#include #include #include #include #include #include #include #include #include #include #include #include #include #include "templates.h" #include "s1kd_tools.h" #define PROG_NAME "s1kd-newdml" #define VERSION "2.2.0" #define ERR_PREFIX PROG_NAME ": ERROR: " #define EXIT_DML_EXISTS 1 #define EXIT_BAD_INPUT 2 #define EXIT_BAD_CODE 3 #define EXIT_BAD_BREX_DMC 4 #define EXIT_BAD_DATE 5 #define EXIT_BAD_ISSUE 6 #define EXIT_BAD_TEMPLATE 7 #define EXIT_BAD_TEMPL_DIR 8 #define EXIT_OS_ERROR 9 #define EXIT_BAD_SNS 10 #define E_BAD_TEMPL_DIR ERR_PREFIX "Cannot dump template in directory: %s\n" #define E_BAD_SNS ERR_PREFIX "Specified BREX DM could not be read: %s\n" #define E_BAD_LIST ERR_PREFIX "Could not read list: %s\n" #define MAX_MODEL_IDENT_CODE 14 + 2 #define MAX_SYSTEM_DIFF_CODE 4 + 2 #define MAX_SYSTEM_CODE 3 + 2 #define MAX_SUB_SYSTEM_CODE 1 + 2 #define MAX_SUB_SUB_SYSTEM_CODE 1 + 2 #define MAX_ASSY_CODE 4 + 2 #define MAX_DISASSY_CODE 2 + 2 #define MAX_DISASSY_CODE_VARIANT 1 + 2 #define MAX_INFO_CODE 3 + 2 #define MAX_INFO_CODE_VARIANT 1 + 2 #define MAX_ITEM_LOCATION_CODE 1 + 2 #define MAX_LEARN_CODE 3 + 2 #define MAX_LEARN_EVENT_CODE 1 + 2 #define MAX_ISSUE_NUMBER 5 + 2 #define MAX_IN_WORK 2 + 2 static char model_ident_code[MAX_MODEL_IDENT_CODE] = ""; static char sender_ident[7] = ""; static char dml_type[3] = ""; static char year_of_data_issue[6] = ""; static char seq_number[7] = ""; static char security_classification[4] = ""; static char issue_number[MAX_ISSUE_NUMBER] = ""; static char in_work[MAX_IN_WORK] = ""; static char brex_dmcode[256] = ""; static char issue_date[16] = ""; static xmlChar *issue_type = NULL; static xmlChar *remarks = NULL; #define DEFAULT_S1000D_ISSUE ISS_50 #define ISS_22_DEFAULT_BREX "AE-A-04-10-0301-00A-022A-D" #define ISS_23_DEFAULT_BREX "AE-A-04-10-0301-00A-022A-D" #define ISS_30_DEFAULT_BREX "AE-A-04-10-0301-00A-022A-D" #define ISS_40_DEFAULT_BREX "S1000D-A-04-10-0301-00A-022A-D" #define ISS_41_DEFAULT_BREX "S1000D-E-04-10-0301-00A-022A-D" #define ISS_42_DEFAULT_BREX "S1000D-F-04-10-0301-00A-022A-D" static enum issue { NO_ISS, ISS_20, ISS_21, ISS_22, ISS_23, ISS_30, ISS_40, ISS_41, ISS_42, ISS_50 } issue = NO_ISS; static char *defaultRpcName = NULL; static char *defaultRpcCode = NULL; static char *template_dir = NULL; static xmlDocPtr xml_skeleton(void) { if (template_dir) { char src[PATH_MAX]; sprintf(src, "%s/dml.xml", template_dir); if (access(src, F_OK) == -1) { fprintf(stderr, ERR_PREFIX "No schema dml found in template directory \"%s\".\n", template_dir); exit(EXIT_BAD_TEMPLATE); } return read_xml_doc(src); } else { return read_xml_mem((const char *) dml_xml, dml_xml_len); } } static enum issue get_issue(const char *iss) { if (strcmp(iss, "5.0") == 0) return ISS_50; else if (strcmp(iss, "4.2") == 0) return ISS_42; else if (strcmp(iss, "4.1") == 0) return ISS_41; else if (strcmp(iss, "4.0") == 0) return ISS_40; else if (strcmp(iss, "3.0") == 0) return ISS_30; else if (strcmp(iss, "2.3") == 0) return ISS_23; else if (strcmp(iss, "2.2") == 0) return ISS_22; else if (strcmp(iss, "2.1") == 0) return ISS_21; else if (strcmp(iss, "2.0") == 0) return ISS_20; fprintf(stderr, ERR_PREFIX "Unsupported issue: %s\n", iss); exit(EXIT_BAD_ISSUE); return NO_ISS; } static void transform_doc(xmlDocPtr doc, unsigned char *xsl, unsigned int len, const char **params) { xmlDocPtr styledoc, src, res; xsltStylesheetPtr style; xmlNodePtr old; src = xmlCopyDoc(doc, 1); styledoc = read_xml_mem((const char *) xsl, len); style = xsltParseStylesheetDoc(styledoc); res = xsltApplyStylesheet(style, src, params); old = xmlDocSetRootElement(doc, xmlCopyNode(xmlDocGetRootElement(res), 1)); xmlFreeNode(old); xmlFreeDoc(src); xmlFreeDoc(res); xsltFreeStylesheet(style); } static xmlDocPtr toissue(xmlDocPtr doc, enum issue iss) { xmlDocPtr orig; unsigned char *xml = NULL; unsigned int len; switch (iss) { case ISS_42: xml = ___common_to42_xsl; len = ___common_to42_xsl_len; break; case ISS_41: xml = ___common_to41_xsl; len = ___common_to41_xsl_len; break; case ISS_40: xml = ___common_to40_xsl; len = ___common_to40_xsl_len; break; case ISS_30: xml = ___common_to30_xsl; len = ___common_to30_xsl_len; break; case ISS_23: xml = ___common_to23_xsl; len = ___common_to23_xsl_len; break; case ISS_22: xml = ___common_to22_xsl; len = ___common_to22_xsl_len; break; case ISS_21: xml = ___common_to21_xsl; len = ___common_to21_xsl_len; break; case ISS_20: xml = ___common_to20_xsl; len = ___common_to20_xsl_len; break; default: return NULL; } orig = xmlCopyDoc(doc, 1); transform_doc(orig, xml, len, NULL); xmlFreeDoc(doc); return orig; } static void prompt(const char *prompt, char *str, int n) { if (strcmp(str, "") == 0) { printf("%s: ", prompt); while (!strchr(fgets(str, n, stdin), '\n')) { fprintf(stderr, ERR_PREFIX "Bad input for \"%s\".\n", prompt); while (getchar() != '\n'); printf("%s: ", prompt); } *(strchr(str, '\n')) = '\0'; } else { char temp[512] = ""; printf("%s [%s]: ", prompt, str); while (!strchr(fgets(temp, n, stdin), '\n')) { fprintf(stderr, ERR_PREFIX "Bad input for \"%s\".\n", prompt); while (getchar() != '\n'); printf("%s [%s]: ", prompt, str); } *(strchr(temp, '\n')) = '\0'; if (strcmp(temp, "") != 0) { memcpy(str, temp, n - 1); } } } static xmlNodePtr firstXPathNode(const char *xpath, xmlDocPtr doc) { xmlXPathContextPtr ctx; xmlXPathObjectPtr obj; xmlNodePtr node; ctx = xmlXPathNewContext(doc); obj = xmlXPathEvalExpression(BAD_CAST xpath, ctx); if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) { node = NULL; } else { node = obj->nodesetval->nodeTab[0]; } xmlXPathFreeObject(obj); xmlXPathFreeContext(ctx); return node; } static bool isdm(xmlDocPtr doc) { return xmlStrcmp(xmlDocGetRootElement(doc)->name, BAD_CAST "dmodule") == 0; } static bool ispm(xmlDocPtr doc) { return xmlStrcmp(xmlDocGetRootElement(doc)->name, BAD_CAST "pm") == 0; } static bool isicn(const char *name) { return strncmp(name, "ICN-", 4) == 0; } static bool isimf(xmlDocPtr doc) { return xmlStrcmp(xmlDocGetRootElement(doc)->name, BAD_CAST "icnMetadataFile") == 0; } static bool iscom(xmlDocPtr doc) { return xmlStrcmp(xmlDocGetRootElement(doc)->name, BAD_CAST "comment") == 0; } static bool isdml(xmlDocPtr doc) { return xmlStrcmp(xmlDocGetRootElement(doc)->name, BAD_CAST "dml") == 0; } static void addDmRef(xmlDocPtr dm, xmlNodePtr dmlContent, bool csl) { xmlNodePtr dmRef, dmRefIdent, dmRefAddressItems, dmlEntry; dmlEntry = xmlNewChild(dmlContent, NULL, BAD_CAST "dmlEntry", NULL); if (csl) { xmlChar *issueType; issueType = xmlGetProp(firstXPathNode("//dmStatus", dm), BAD_CAST "issueType"); if (issueType) { xmlSetProp(dmlEntry, BAD_CAST "issueType", issueType); } xmlFree(issueType); } dmRef = xmlNewChild(dmlEntry, NULL, BAD_CAST "dmRef", NULL); dmRefIdent = xmlNewChild(dmRef, NULL, BAD_CAST "dmRefIdent", NULL); xmlAddChild(dmRefIdent, xmlCopyNode(firstXPathNode("//dmIdent/identExtension", dm), 1)); xmlAddChild(dmRefIdent, xmlCopyNode(firstXPathNode("//dmIdent/dmCode", dm), 1)); if (csl) { xmlAddChild(dmRefIdent, xmlCopyNode(firstXPathNode("//dmIdent/issueInfo", dm), 1)); } xmlAddChild(dmRefIdent, xmlCopyNode(firstXPathNode("//dmIdent/language", dm), 1)); dmRefAddressItems = xmlNewChild(dmRef, NULL, BAD_CAST "dmRefAddressItems", NULL); xmlAddChild(dmRefAddressItems, xmlCopyNode(firstXPathNode("//dmAddressItems/dmTitle", dm), 1)); if (csl) { xmlAddChild(dmRefAddressItems, xmlCopyNode(firstXPathNode("//dmAddressItems/issueDate", dm), 1)); } xmlAddChild(dmlEntry, xmlCopyNode(firstXPathNode("//dmStatus/security", dm), 1)); xmlAddChild(dmlEntry, xmlCopyNode(firstXPathNode("//dmStatus/responsiblePartnerCompany", dm), 1)); } static void addPmRef(xmlDocPtr pm, xmlNodePtr dmlContent, bool csl) { xmlNodePtr pmRef, pmRefIdent, pmRefAddressItems, dmlEntry; dmlEntry = xmlNewChild(dmlContent, NULL, BAD_CAST "dmlEntry", NULL); if (csl) { xmlChar *issueType; issueType = xmlGetProp(firstXPathNode("//pmStatus", pm), BAD_CAST "issueType"); if (issueType) { xmlSetProp(dmlEntry, BAD_CAST "issueType", issueType); } xmlFree(issueType); } pmRef = xmlNewChild(dmlEntry, NULL, BAD_CAST "pmRef", NULL); pmRefIdent = xmlNewChild(pmRef, NULL, BAD_CAST "pmRefIdent", NULL); xmlAddChild(pmRefIdent, xmlCopyNode(firstXPathNode("//pmIdent/identExtension", pm), 1)); xmlAddChild(pmRefIdent, xmlCopyNode(firstXPathNode("//pmIdent/pmCode", pm), 1)); if (csl) { xmlAddChild(pmRefIdent, xmlCopyNode(firstXPathNode("//pmIdent/issueInfo", pm), 1)); } xmlAddChild(pmRefIdent, xmlCopyNode(firstXPathNode("//pmIdent/language", pm), 1)); pmRefAddressItems = xmlNewChild(pmRef, NULL, BAD_CAST "pmRefAddressItems", NULL); xmlAddChild(pmRefAddressItems, xmlCopyNode(firstXPathNode("//pmAddressItems/pmTitle", pm), 1)); if (csl) { xmlAddChild(pmRefAddressItems, xmlCopyNode(firstXPathNode("//pmAddressItems/issueDate", pm), 1)); } xmlAddChild(pmRefAddressItems, xmlCopyNode(firstXPathNode("//pmAddressItems/shortPmTitle", pm), 1)); xmlAddChild(dmlEntry, xmlCopyNode(firstXPathNode("//pmStatus/security", pm), 1)); xmlAddChild(dmlEntry, xmlCopyNode(firstXPathNode("//pmStatus/responsiblePartnerCompany", pm), 1)); } static void addIcnRef(const char *str, xmlNodePtr dmlContent) { xmlNodePtr dmlEntry, infoEntityRef, responsiblePartnerCompany, security; char *icn; char *sec; dmlEntry = xmlNewChild(dmlContent, NULL, BAD_CAST "dmlEntry", NULL); infoEntityRef = xmlNewChild(dmlEntry, NULL, BAD_CAST "infoEntityRef", NULL); icn = strdup(str); strtok(icn, "."); sec = strrchr(icn, '-') + 1; xmlSetProp(infoEntityRef, BAD_CAST "infoEntityRefIdent", BAD_CAST icn); security = xmlNewChild(dmlEntry, NULL, BAD_CAST "security", NULL); xmlSetProp(security, BAD_CAST "securityClassification", BAD_CAST sec); responsiblePartnerCompany = xmlNewChild(dmlEntry, NULL, BAD_CAST "responsiblePartnerCompany", NULL); if (defaultRpcCode) { xmlSetProp(responsiblePartnerCompany, BAD_CAST "enterpriseCode", BAD_CAST defaultRpcCode); } if (defaultRpcName) { xmlNewChild(responsiblePartnerCompany, NULL, BAD_CAST "enterpriseName", BAD_CAST defaultRpcName); } free(icn); } static void addImfRef(xmlDocPtr imf, xmlNodePtr dmlContent) { xmlChar *imfIdentIcn; char *icn; imfIdentIcn = xmlGetProp(firstXPathNode("//imfIdent/imfCode", imf), BAD_CAST "imfIdentIcn"); icn = malloc(xmlStrlen(imfIdentIcn) + 5); sprintf(icn, "ICN-%s", imfIdentIcn); addIcnRef(icn, dmlContent); free(icn); xmlFree(imfIdentIcn); } static void addComRef(xmlDocPtr com, xmlNodePtr dmlContent) { xmlNodePtr dmlEntry, commentRef, commentRefIdent, responsiblePartnerCompany; dmlEntry = xmlNewChild(dmlContent, NULL, BAD_CAST "dmlEntry", NULL); commentRef = xmlNewChild(dmlEntry, NULL, BAD_CAST "commentRef", NULL); commentRefIdent = xmlNewChild(commentRef, NULL, BAD_CAST "commentRefIdent", NULL); xmlAddChild(commentRefIdent, xmlCopyNode(firstXPathNode("//commentIdent/commentCode", com), 1)); xmlAddChild(commentRefIdent, xmlCopyNode(firstXPathNode("//commentIdent/language", com), 1)); xmlAddChild(dmlEntry, xmlCopyNode(firstXPathNode("//commentStatus/security", com), 1)); responsiblePartnerCompany = xmlNewChild(dmlEntry, NULL, BAD_CAST "responsiblePartnerCompany", NULL); if (defaultRpcCode) { xmlSetProp(responsiblePartnerCompany, BAD_CAST "enterpriseCode", BAD_CAST defaultRpcCode); } if (defaultRpcName) { xmlNewChild(responsiblePartnerCompany, NULL, BAD_CAST "enterpriseName", BAD_CAST defaultRpcName); } } static void addDmlRef(xmlDocPtr dml, xmlNodePtr dmlContent, bool csl) { xmlNodePtr dmlEntry, dmlRef, dmlRefIdent, responsiblePartnerCompany; dmlEntry = xmlNewChild(dmlContent, NULL, BAD_CAST "dmlEntry", NULL); dmlRef = xmlNewChild(dmlEntry, NULL, BAD_CAST "dmlRef", NULL); dmlRefIdent = xmlNewChild(dmlRef, NULL, BAD_CAST "dmlRefIdent", NULL); xmlAddChild(dmlRefIdent, xmlCopyNode(firstXPathNode("//dmlIdent/dmlCode", dml), 1)); if (csl) { xmlAddChild(dmlRefIdent, xmlCopyNode(firstXPathNode("//dmlIdent/issueInfo", dml), 1)); } xmlAddChild(dmlEntry, xmlCopyNode(firstXPathNode("//dmlStatus/security", dml), 1)); responsiblePartnerCompany = xmlNewChild(dmlEntry, NULL, BAD_CAST "responsiblePartnerCompany", NULL); if (defaultRpcCode) { xmlSetProp(responsiblePartnerCompany, BAD_CAST "enterpriseCode", BAD_CAST defaultRpcCode); } if (defaultRpcName) { xmlNewChild(responsiblePartnerCompany, NULL, BAD_CAST "enterpriseName", BAD_CAST defaultRpcName); } } static void copy_default_value(const char *def_key, const char *def_val) { if (strcmp(def_key, "modelIdentCode") == 0 && strcmp(model_ident_code, "") == 0) strcpy(model_ident_code, def_val); else if (strcmp(def_key, "senderIdent") == 0 && strcmp(sender_ident, "") == 0) strcpy(sender_ident, def_val); else if (strcmp(def_key, "dmlType") == 0 && strcmp(dml_type, "") == 0) strcpy(dml_type, def_val); else if (strcmp(def_key, "yearOfDataIssue") == 0 && strcmp(year_of_data_issue, "") == 0) strcpy(year_of_data_issue, def_val); else if (strcmp(def_key, "seqNumber") == 0 && strcmp(seq_number, "") == 0) strcpy(seq_number, def_val); else if (strcmp(def_key, "issueNumber") == 0 && strcmp(issue_number, "") == 0) strcpy(issue_number, def_val); else if (strcmp(def_key, "inWork") == 0 && strcmp(in_work, "") == 0) strcpy(in_work, def_val); else if (strcmp(def_key, "securityClassification") == 0 && strcmp(security_classification, "") == 0) strcpy(security_classification, def_val); else if (strcmp(def_key, "brex") == 0 && strcmp(brex_dmcode, "") == 0) strcpy(brex_dmcode, def_val); else if (strcmp(def_key, "responsiblePartnerCompany") == 0 && !defaultRpcName) defaultRpcName = strdup(def_val); else if (strcmp(def_key, "responsiblePartnerCompanyCode") == 0 && !defaultRpcCode) defaultRpcCode = strdup(def_val); else if (strcmp(def_key, "templates") == 0 && !template_dir) template_dir = strdup(def_val); else if (strcmp(def_key, "remarks") == 0 && !remarks) remarks = xmlStrdup(BAD_CAST def_val); else if (strcmp(def_key, "issue") == 0 && issue == NO_ISS) issue = get_issue(def_val); else if (strcmp(def_key, "issueType") == 0 && !issue_type) issue_type = xmlStrdup(BAD_CAST def_val); } static void add_sns(xmlNodePtr content, const char *path, const char *incode) { xmlDocPtr doc; xmlNodePtr new_content, cur; const char *params[9]; char infocode[4], variant[2], itemloc[2]; int n, i = 0; char *is = NULL, *vs = NULL, *ls = NULL, *rc = NULL, *rn = NULL; if (!(doc = read_xml_doc(path))) { fprintf(stderr, E_BAD_SNS, path); exit(EXIT_BAD_SNS); } params[i++] = "infoCode"; if ((n = sscanf(incode, "%3s%1s-%1s", infocode, variant, itemloc)) < 1) { fprintf(stderr, ERR_PREFIX "Bad info code: %s\n", incode); exit(EXIT_BAD_INPUT); } is = malloc(7); sprintf(is, "\"%s\"", infocode); params[i++] = is; if (n > 1) { params[i++] = "infoCodeVariant"; vs = malloc(4); sprintf(vs, "\"%s\"", variant); params[i++] = vs; if (n > 2) { params[i++] = "itemLocationCode"; ls = malloc(4); sprintf(ls, "\"%s\"", itemloc); params[i++] = ls; } } if (defaultRpcCode) { params[i++] = "RPCcode"; rc = malloc(strlen(defaultRpcCode) + 3); sprintf(rc, "\"%s\"", defaultRpcCode); params[i++] = rc; } if (defaultRpcName) { params[i++] = "RPCname"; rn = malloc(strlen(defaultRpcName) + 3); sprintf(rn, "\"%s\"", defaultRpcName); params[i++] = rn; } params[i++] = NULL; transform_doc(doc, sns2dmrl_xsl, sns2dmrl_xsl_len, params); free(is); free(vs); free(ls); free(rc); free(rn); new_content = xmlDocGetRootElement(doc); for (cur = new_content->children; cur; cur = cur->next) { if (cur->type != XML_ELEMENT_NODE) { continue; } xmlAddChild(content, xmlCopyNode(cur, 1)); } xmlFreeDoc(doc); } static void sort_entries(xmlDocPtr doc) { transform_doc(doc, sort_xsl, sort_xsl_len, NULL); } static void dump_template(const char *path) { FILE *f; if (access(path, W_OK) == -1 || chdir(path)) { fprintf(stderr, E_BAD_TEMPL_DIR, path); exit(EXIT_BAD_TEMPL_DIR); } f = fopen("dml.xml", "w"); fprintf(f, "%.*s", dml_xml_len, dml_xml); fclose(f); } static void show_help(void) { puts("Usage: " PROG_NAME " [options] [...]"); puts(""); puts("Options:"); puts(" -$, --issue Specify which S1000d issue to use."); puts(" -@, --out Output to specified file or directory."); puts(" -%, --templates Use template in specified directory."); puts(" -~, --dump-templates Dump built-in template to directory."); puts(" -d, --defaults Specify .defaults file name."); puts(" -f, --overwrite Overwrite existing file."); puts(" -h, -?, --help Show usage message."); puts(" -i, --info-code Specify info code for SNS-generated DMRL."); puts(" -l, --list Treat input as a list of objects to add to the new list."); puts(" -N, --omit-issue Omit issue/inwork from filename."); puts(" -p, --prompt Prompt the user for each value."); puts(" -q, --quiet Don't report an error if file exists."); puts(" -S, --sns Create a DMRL from SNS rules."); puts(" -v, --verbose Print file name of DML."); puts(" --version Show version information."); puts(" ... CSDB object(s) to add to the new list."); puts(""); puts("In addition, the following pieces of metadata can be set:"); puts(" -#, --code DML code"); puts(" -b, --brex BREX data module code"); puts(" -c, --security Security classification"); puts(" -I, --date Issue date"); puts(" -m, --remarks Remarks"); puts(" -n, --issno Issue number"); puts(" -R, --rpccode Default RPC code"); puts(" -r, --rpcname Default RPC name"); puts(" -w, --inwork Inwork issue"); puts(" -z, --issue-type Issue type"); LIBXML2_PARSE_LONGOPT_HELP } static void show_version(void) { printf("%s (s1kd-tools) %s\n", PROG_NAME, VERSION); printf("Using libxml %s and libxslt %s\n", xmlParserVersion, xsltEngineVersion); } static void set_brex(xmlDocPtr doc, const char *code) { xmlNodePtr dmCode; int n; char modelIdentCode[MAX_MODEL_IDENT_CODE] = ""; char systemDiffCode[MAX_SYSTEM_DIFF_CODE] = ""; char systemCode[MAX_SYSTEM_CODE] = ""; char subSystemCode[MAX_SUB_SYSTEM_CODE] = ""; char subSubSystemCode[MAX_SUB_SUB_SYSTEM_CODE] = ""; char assyCode[MAX_ASSY_CODE] = ""; char disassyCode[MAX_DISASSY_CODE] = ""; char disassyCodeVariant[MAX_DISASSY_CODE_VARIANT] = ""; char infoCode[MAX_INFO_CODE] = ""; char infoCodeVariant[MAX_INFO_CODE_VARIANT] = ""; char itemLocationCode[MAX_ITEM_LOCATION_CODE] = ""; char learnCode[MAX_LEARN_CODE] = ""; char learnEventCode[MAX_LEARN_EVENT_CODE] = ""; dmCode = firstXPathNode("//brexDmRef/dmRef/dmRefIdent/dmCode", doc); n = sscanf(code, "%14[^-]-%4[^-]-%3[^-]-%c%c-%4[^-]-%2s%3[^-]-%3s%c-%c-%3s%1s", modelIdentCode, systemDiffCode, systemCode, subSystemCode, subSubSystemCode, assyCode, disassyCode, disassyCodeVariant, infoCode, infoCodeVariant, itemLocationCode, learnCode, learnEventCode); if (n != 11 && n != 13) { fprintf(stderr, ERR_PREFIX "Bad BREX data module code.\n"); exit(EXIT_BAD_BREX_DMC); } xmlSetProp(dmCode, BAD_CAST "modelIdentCode", BAD_CAST modelIdentCode); xmlSetProp(dmCode, BAD_CAST "systemDiffCode", BAD_CAST systemDiffCode); xmlSetProp(dmCode, BAD_CAST "systemCode", BAD_CAST systemCode); xmlSetProp(dmCode, BAD_CAST "subSystemCode", BAD_CAST subSystemCode); xmlSetProp(dmCode, BAD_CAST "subSubSystemCode", BAD_CAST subSubSystemCode); xmlSetProp(dmCode, BAD_CAST "assyCode", BAD_CAST assyCode); xmlSetProp(dmCode, BAD_CAST "disassyCode", BAD_CAST disassyCode); xmlSetProp(dmCode, BAD_CAST "disassyCodeVariant", BAD_CAST disassyCodeVariant); xmlSetProp(dmCode, BAD_CAST "infoCode", BAD_CAST infoCode); xmlSetProp(dmCode, BAD_CAST "infoCodeVariant", BAD_CAST infoCodeVariant); xmlSetProp(dmCode, BAD_CAST "itemLocationCode", BAD_CAST itemLocationCode); if (strcmp(learnCode, "") != 0) xmlSetProp(dmCode, BAD_CAST "learnCode", BAD_CAST learnCode); if (strcmp(learnEventCode, "") != 0) xmlSetProp(dmCode, BAD_CAST "learnEventCode", BAD_CAST learnEventCode); } static void set_issue_date(xmlNodePtr issueDate) { char year_s[5], month_s[3], day_s[3]; if (strcmp(issue_date, "") == 0) { time_t now; struct tm *local; unsigned short year, month, day; time(&now); local = localtime(&now); year = local->tm_year + 1900; month = local->tm_mon + 1; day = local->tm_mday; if (snprintf(year_s, 5, "%u", year) < 0 || snprintf(month_s, 3, "%.2u", month) < 0 || snprintf(day_s, 3, "%.2u", day) < 0) exit(EXIT_BAD_DATE); } else { if (sscanf(issue_date, "%4s-%2s-%2s", year_s, month_s, day_s) != 3) { fprintf(stderr, ERR_PREFIX "Bad issue date: %s\n", issue_date); exit(EXIT_BAD_DATE); } } xmlSetProp(issueDate, BAD_CAST "year", BAD_CAST year_s); xmlSetProp(issueDate, BAD_CAST "month", BAD_CAST month_s); xmlSetProp(issueDate, BAD_CAST "day", BAD_CAST day_s); } static void set_remarks(xmlDocPtr doc, xmlChar *text) { xmlNodePtr remarks; remarks = firstXPathNode("//remarks", doc); if (text) { xmlNewChild(remarks, NULL, BAD_CAST "simplePara", text); } else { xmlUnlinkNode(remarks); xmlFreeNode(remarks); } } static void add_ref(xmlNodePtr dmlContent, char *path) { xmlDocPtr doc = read_xml_doc(path); if (doc) { if (isdm(doc)) { addDmRef(doc, dmlContent, strcmp(dml_type, "S") == 0); } else if (ispm(doc)) { addPmRef(doc, dmlContent, strcmp(dml_type, "S") == 0); } else if (isimf(doc)) { addImfRef(doc, dmlContent); } else if (iscom(doc)) { addComRef(doc, dmlContent); } else if (isdml(doc)) { addDmlRef(doc, dmlContent, strcmp(dml_type, "S") == 0); } xmlFreeDoc(doc); } else { char *base = basename(path); if (isicn(base)) { addIcnRef(base, dmlContent); } } } static void add_ref_list(xmlNodePtr dmlContent, const char *fname) { FILE *f; char path[PATH_MAX]; if (fname) { if (!(f = fopen(fname, "r"))) { fprintf(stderr, E_BAD_LIST, fname); return; } } else { f = stdin; } while (fgets(path, PATH_MAX, f)) { strtok(path, "\t\r\n"); add_ref(dmlContent, path); } if (fname) { fclose(f); } } int main(int argc, char **argv) { xmlDocPtr dml_doc; xmlNodePtr dmlCode, issueInfo, security, issueDate, dmlContent, dmlStatus, sns_incodes; xmlXPathContextPtr ctxt; xmlXPathObjectPtr results; char defaults_fname[PATH_MAX]; bool custom_defaults = false; bool showprompts = false; char code[256] = ""; bool skipcode = false; bool noissue = false; bool verbose = false; bool overwrite = false; bool no_overwrite_error = false; char *sns = NULL; bool islist = false; int c; xmlDocPtr defaults_xml; char *out = NULL; char *outdir = NULL; const char *sopts = "pd:#:n:w:c:Nb:I:vf$:@:r:R:%:qS:i:m:~:z:lh?"; struct option lopts[] = { {"version" , no_argument , 0, 0}, {"help" , no_argument , 0, 'h'}, {"prompt" , no_argument , 0, 'p'}, {"defaults" , required_argument, 0, 'd'}, {"code" , required_argument, 0, '#'}, {"issno" , required_argument, 0, 'n'}, {"inwork" , required_argument, 0, 'w'}, {"security" , required_argument, 0, 'c'}, {"omit-issue" , no_argument , 0, 'N'}, {"brex" , required_argument, 0, 'b'}, {"date" , required_argument, 0, 'I'}, {"verbose" , no_argument , 0, 'v'}, {"overwrite" , no_argument , 0, 'f'}, {"issue" , required_argument, 0, '$'}, {"out" , required_argument, 0, '@'}, {"rpcname" , required_argument, 0, 'r'}, {"rpccode" , required_argument, 0, 'R'}, {"templates" , required_argument, 0, '%'}, {"quiet" , no_argument , 0, 'q'}, {"sns" , required_argument, 0, 'S'}, {"info-code" , required_argument, 0, 'i'}, {"remarks" , required_argument, 0, 'm'}, {"dump-templates", required_argument, 0, '~'}, {"issue-type" , required_argument, 0, 'z'}, {"list" , no_argument , 0, 'l'}, LIBXML2_PARSE_LONGOPT_DEFS {0, 0, 0, 0} }; int loptind = 0; sns_incodes = xmlNewNode(NULL, BAD_CAST "incodes"); while ((c = getopt_long(argc, argv, sopts, lopts, &loptind)) != -1) { switch (c) { case 0: if (strcmp(lopts[loptind].name, "version") == 0) { show_version(); return 0; } LIBXML2_PARSE_LONGOPT_HANDLE(lopts, loptind, optarg) break; case 'p': showprompts = true; break; case 'd': strcpy(defaults_fname, optarg); custom_defaults = true; break; case '#': strcpy(code, optarg); skipcode = true; break; case 'n': strcpy(issue_number, optarg); break; case 'w': strcpy(in_work, optarg); break; case 'c': strcpy(security_classification, optarg); break; case 'N': noissue = true; break; case 'b': strncpy(brex_dmcode, optarg, 255); break; case 'I': strncpy(issue_date, optarg, 15); break; case 'v': verbose = true; break; case 'f': overwrite = true; break; case '$': issue = get_issue(optarg); break; case '@': out = strdup(optarg); break; case 'r': defaultRpcName = strdup(optarg); break; case 'R': defaultRpcCode = strdup(optarg); break; case '%': template_dir = strdup(optarg); break; case 'q': no_overwrite_error = true; break; case 'S': sns = strdup(optarg); break; case 'i': xmlNewChild(sns_incodes, NULL, BAD_CAST "incode", BAD_CAST optarg); break; case 'm': remarks = xmlStrdup(BAD_CAST optarg); break; case '~': dump_template(optarg); return 0; case 'z': issue_type = xmlStrdup(BAD_CAST optarg); break; case 'l': islist = true; break; case 'h': case '?': show_help(); return 0; } } if (!custom_defaults) { find_config(defaults_fname, DEFAULT_DEFAULTS_FNAME); } if (!sns_incodes->children) { xmlNewChild(sns_incodes, NULL, BAD_CAST "incode", BAD_CAST "000"); } if ((defaults_xml = read_xml_doc(defaults_fname))) { xmlNodePtr cur; for (cur = xmlDocGetRootElement(defaults_xml)->children; cur; cur = cur->next) { char *def_key, *def_val; if (cur->type != XML_ELEMENT_NODE) continue; if (!xmlHasProp(cur, BAD_CAST "ident")) continue; if (!xmlHasProp(cur, BAD_CAST "value")) continue; def_key = (char *) xmlGetProp(cur, BAD_CAST "ident"); def_val = (char *) xmlGetProp(cur, BAD_CAST "value"); copy_default_value(def_key, def_val); xmlFree(def_key); xmlFree(def_val); } xmlFreeDoc(defaults_xml); } else { FILE *defaults; defaults = fopen(defaults_fname, "r"); if (defaults) { char default_line[1024]; while (fgets(default_line, 1024, defaults)) { char def_key[32], def_val[256]; if (sscanf(default_line, "%31s %255[^\n]", def_key, def_val) != 2) continue; copy_default_value(def_key, def_val); } fclose(defaults); } } if (strcmp(code, "") != 0) { int n, offset; offset = strncmp(code, "DML-", 4) == 0 ? 4 : 0; n = sscanf(code + offset, "%14[^-]-%5[^-]-%c-%4[^-]-%5[^-]", model_ident_code, sender_ident, dml_type, year_of_data_issue, seq_number); if (n != 5) { fprintf(stderr, ERR_PREFIX "Bad DML code.\n"); exit(EXIT_BAD_CODE); } } if (showprompts) { if (!skipcode) { prompt("Model ident code", model_ident_code, 16); prompt("Sender ident", sender_ident, 7); prompt("DML type", dml_type, 3); prompt("Year of data issue", year_of_data_issue, 6); prompt("Sequence number", seq_number, 7); } prompt("Issue number", issue_number, 5); prompt("In-work issue", in_work, 4); prompt("Security classification", security_classification, 4); } if (strcmp(model_ident_code, "") == 0 || strcmp(sender_ident, "") == 0 || strcmp(dml_type, "") == 0 || strcmp(year_of_data_issue, "") == 0 || strcmp(seq_number, "") == 0) { fprintf(stderr, ERR_PREFIX "Missing required DML code components: "); fprintf(stderr, "DML-%s-%s-%s-%s-%s\n", strcmp(model_ident_code, "") == 0 ? "???" : model_ident_code, strcmp(sender_ident, "") == 0 ? "???" : sender_ident, strcmp(dml_type, "") == 0 ? "???" : dml_type, strcmp(year_of_data_issue, "") == 0 ? "???" : year_of_data_issue, strcmp(seq_number, "") == 0 ? "???" : seq_number); exit(EXIT_BAD_CODE); } if (issue == NO_ISS) issue = DEFAULT_S1000D_ISSUE; if (strcmp(issue_number, "") == 0) strcpy(issue_number, "000"); if (strcmp(in_work, "") == 0) strcpy(in_work, "01"); if (strcmp(security_classification, "") == 0) strcpy(security_classification, "01"); dml_doc = xml_skeleton(); ctxt = xmlXPathNewContext(dml_doc); results = xmlXPathEvalExpression(BAD_CAST "//dmlIdent/dmlCode", ctxt); dmlCode = results->nodesetval->nodeTab[0]; xmlXPathFreeObject(results); results = xmlXPathEvalExpression(BAD_CAST "//dmlIdent/issueInfo", ctxt); issueInfo = results->nodesetval->nodeTab[0]; xmlXPathFreeObject(results); results = xmlXPathEvalExpression(BAD_CAST "//dmlStatus/security", ctxt); security = results->nodesetval->nodeTab[0]; xmlXPathFreeObject(results); results = xmlXPathEvalExpression(BAD_CAST "//dmlAddressItems/issueDate", ctxt); issueDate = results->nodesetval->nodeTab[0]; xmlXPathFreeObject(results); dml_type[0] = tolower(dml_type[0]); xmlSetProp(dmlCode, BAD_CAST "modelIdentCode", BAD_CAST model_ident_code); xmlSetProp(dmlCode, BAD_CAST "senderIdent", BAD_CAST sender_ident); xmlSetProp(dmlCode, BAD_CAST "dmlType", BAD_CAST dml_type); xmlSetProp(dmlCode, BAD_CAST "yearOfDataIssue", BAD_CAST year_of_data_issue); xmlSetProp(dmlCode, BAD_CAST "seqNumber", BAD_CAST seq_number); xmlSetProp(issueInfo, BAD_CAST "issueNumber", BAD_CAST issue_number); xmlSetProp(issueInfo, BAD_CAST "inWork", BAD_CAST in_work); xmlSetProp(security, BAD_CAST "securityClassification", BAD_CAST security_classification); set_issue_date(issueDate); dmlStatus = firstXPathNode("//dmlStatus", dml_doc); if (issue_type) xmlSetProp(dmlStatus, BAD_CAST "issueType", issue_type); xmlXPathFreeContext(ctxt); if (strcmp(brex_dmcode, "") != 0) set_brex(dml_doc, brex_dmcode); set_remarks(dml_doc, remarks); dml_type[0] = toupper(dml_type[0]); dmlContent = firstXPathNode("//dmlContent", dml_doc); if (sns) { xmlNodePtr incode; for (incode = sns_incodes->children; incode; incode = incode->next) { char *inc; inc = (char *) xmlNodeGetContent(incode); add_sns(dmlContent, sns, inc); xmlFree(inc); } } if (optind < argc) { for (c = optind; c < argc; ++c) { if (islist) { add_ref_list(dmlContent, argv[c]); } else { add_ref(dmlContent, argv[c]); } } } else if (islist) { add_ref_list(dmlContent, NULL); } sort_entries(dml_doc); if (issue < ISS_50) { if (strcmp(brex_dmcode, "") == 0) { switch (issue) { case ISS_22: set_brex(dml_doc, ISS_22_DEFAULT_BREX); break; case ISS_23: set_brex(dml_doc, ISS_23_DEFAULT_BREX); break; case ISS_30: set_brex(dml_doc, ISS_30_DEFAULT_BREX); break; case ISS_40: set_brex(dml_doc, ISS_40_DEFAULT_BREX); break; case ISS_41: set_brex(dml_doc, ISS_41_DEFAULT_BREX); break; case ISS_42: set_brex(dml_doc, ISS_42_DEFAULT_BREX); break; default: break; } } dml_doc = toissue(dml_doc, issue); } if (out && isdir(out, false)) { outdir = out; out = NULL; } if (!out) { char dml_fname[PATH_MAX]; if (noissue) { snprintf(dml_fname, PATH_MAX, "DML-%s-%s-%s-%s-%s.XML", model_ident_code, sender_ident, dml_type, year_of_data_issue, seq_number); } else { snprintf(dml_fname, PATH_MAX, "DML-%s-%s-%s-%s-%s_%s-%s.XML", model_ident_code, sender_ident, dml_type, year_of_data_issue, seq_number, issue_number, in_work); } out = strdup(dml_fname); } if (outdir) { if (chdir(outdir) != 0) { fprintf(stderr, ERR_PREFIX "Could not change to directory %s: %s\n", outdir, strerror(errno)); exit(EXIT_OS_ERROR); } } if (!overwrite && access(out, F_OK) != -1) { if (no_overwrite_error) return 0; if (outdir) { fprintf(stderr, ERR_PREFIX "%s/%s already exists. Use -f to overwrite.\n", outdir, out); } else { fprintf(stderr, ERR_PREFIX "%s already exists. Use -f to overwrite.\n", out); } exit(EXIT_DML_EXISTS); } save_xml_doc(dml_doc, out); if (verbose) { if (outdir) { printf("%s/%s\n", outdir, out); } else { puts(out); } } free(out); free(outdir); free(defaultRpcName); free(defaultRpcCode); free(template_dir); xmlFree(remarks); xmlFree(issue_type); free(sns); xmlFreeDoc(dml_doc); xmlFreeNode(sns_incodes); xmlCleanupParser(); xsltCleanupGlobals(); return 0; }