#include #include #include #include #include #include #include #include #include #include "s1kd_tools.h" #include "resources.h" #define PROG_NAME "s1kd-aspp" #define VERSION "5.0.1" #define ERR_PREFIX PROG_NAME ": ERROR: " #define WRN_PREFIX PROG_NAME ": WARNING: " #define INF_PREFIX PROG_NAME ": INFO: " #define E_BAD_LIST ERR_PREFIX "Could not read list: %s\n" #define W_MISSING_REF WRN_PREFIX "Could not read referenced object: %s\n" #define I_PROCESS INF_PREFIX "Processing %s...\n" /* ID for the inline element representing the whole data module's * applicability. */ #define DEFAULT_DM_APPLIC_ID BAD_CAST "app-0000" static xmlChar *dmApplicId; /* XPath to select all elements which may have applicability annotations. * * Read from elements_list.h*/ static xmlChar *applicElemsXPath; /* Search for ACTs/CCTs recursively. */ static bool recursive_search = false; /* Directory to start search for ACTs/CCTs in. */ static char *search_dir; /* Overwrite existing display text in annotations. */ static bool overwriteDispText = true; /* Verbose output. */ static enum verbosity { QUIET, NORMAL, VERBOSE } verbosity = NORMAL; /* Assume objects were created with -N. */ static bool no_issue = false; /* Delimiter for format strings. */ #define FMTSTR_DELIM '%' /* Return the first node matching an XPath expression. */ static xmlNodePtr firstXPathNode(xmlDocPtr doc, xmlNodePtr node, const char *xpath) { xmlXPathContextPtr ctx; xmlXPathObjectPtr obj; xmlNodePtr first; if (doc) { ctx = xmlXPathNewContext(doc); } else if (node) { ctx = xmlXPathNewContext(node->doc); } else { return NULL; } ctx->node = node; obj = xmlXPathEvalExpression(BAD_CAST xpath, ctx); if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) { first = NULL; } else { first = obj->nodesetval->nodeTab[0]; } xmlXPathFreeObject(obj); xmlXPathFreeContext(ctx); return first; } /* Return the last node matching an XPath expression. */ static xmlNodePtr lastXPathNode(xmlDocPtr doc, xmlNodePtr node, const char *xpath) { xmlXPathContextPtr ctx; xmlXPathObjectPtr obj; xmlNodePtr last; if (doc) { ctx = xmlXPathNewContext(doc); } else if (node) { ctx = xmlXPathNewContext(node->doc); } else { return NULL; } ctx->node = node; obj = xmlXPathEvalExpression(BAD_CAST xpath, ctx); if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) { last = NULL; } else { last = obj->nodesetval->nodeTab[obj->nodesetval->nodeNr - 1]; } xmlXPathFreeObject(obj); xmlXPathFreeContext(ctx); return last; } /* Return the value of the first node matching an XPath expression. */ static xmlChar *first_xpath_value(xmlDocPtr doc, xmlNodePtr node, const char *xpath) { return xmlNodeGetContent(firstXPathNode(doc, node, xpath)); } /* Set an explicit applicability annotation on a node. * * Nodes with the attribute @applicRefId already have an explicit annotation. * * Nodes without @applicRefId have an implicit annotation inherited from their * parent/ancestor which does have an explicit annotation, or ultimately from * the applicability of the whole data module. */ static void processNode(xmlNodePtr node) { xmlNodePtr attr; attr = firstXPathNode(NULL, node, "@applicRefId|@refapplic"); if (!attr) { /* Inherit applicability from * - an ancestor, or * - the whole data module level */ xmlNodePtr ancestor; xmlChar *name; ancestor = lastXPathNode(NULL, node, "ancestor::*[@applicRefId]|ancestor::*[@refapplic]"); name = BAD_CAST (firstXPathNode(NULL, node, "//idstatus") ? "refapplic" : "applicRefId"); if (!ancestor) { xmlSetProp(node, name, dmApplicId); } else { xmlChar *ancestorApplic = xmlGetProp(ancestor, name); xmlSetProp(node, name, ancestorApplic); xmlFree(ancestorApplic); } } } /* Set explicit applicability on all nodes in a nodeset. */ static void processNodeSet(xmlNodeSetPtr nodes) { int i; for (i = 0; i < nodes->nodeNr; ++i) { processNode(nodes->nodeTab[i]); } } /* Remove duplicate applicability annotations in document-order so that an * annotation is only shown when applicability changes. */ static void removeDuplicates(xmlNodeSetPtr nodes) { int i; xmlChar *applic = xmlStrdup(dmApplicId); for (i = 0; i < nodes->nodeNr; ++i) { xmlNodePtr attr; xmlChar *applicRefId; attr = firstXPathNode(NULL, nodes->nodeTab[i], "@applicRefId|@refapplic"); applicRefId = xmlNodeGetContent(attr); if (xmlStrcmp(applicRefId, applic) == 0) { xmlUnsetProp(nodes->nodeTab[i], attr->name); } else { xmlFree(applic); applic = xmlStrdup(applicRefId); } xmlFree(applicRefId); } xmlFree(applic); } /* Insert a new inline element representing the applicability of the * whole data module, based on the dmStatus/applic element. */ static void addDmApplic(xmlNodePtr dmodule) { xmlNodePtr referencedApplicGroup; if ((referencedApplicGroup = firstXPathNode(NULL, dmodule, ".//referencedApplicGroup|.//inlineapplics"))) { xmlNodePtr applic; xmlNodePtr wholeDmApplic; wholeDmApplic = firstXPathNode(NULL, dmodule, ".//dmStatus/applic|.//status/applic"); applic = xmlAddChild(referencedApplicGroup, xmlCopyNode(wholeDmApplic, 1)); xmlSetProp(applic, BAD_CAST "id", dmApplicId); } } static xmlDocPtr parse_disptext(xmlDocPtr config) { xmlDocPtr doc1, doc2, res; xsltStylesheetPtr style; doc1 = read_xml_mem((const char *) disptext_xsl, disptext_xsl_len); style = xsltParseStylesheetDoc(doc1); doc2 = xsltApplyStylesheet(style, config, NULL); xsltFreeStylesheet(style); res = xmlCopyDoc(doc2, 1); xmlFreeDoc(doc2); return res; } static void dumpGenDispTextXsl(void) { xmlDocPtr doc1, doc2; doc1 = read_xml_mem((const char *) disptext_xml, disptext_xml_len); doc2 = parse_disptext(doc1); xmlFreeDoc(doc1); save_xml_doc(doc2, "-"); xmlFreeDoc(doc2); } static void dumpDispText(void) { printf("%.*s", disptext_xml_len, disptext_xml); } /* Customize the display text based on a format string. */ static void apply_format_str(xmlDocPtr doc, const char *fmt) { xmlNodePtr t, c; int i; /* Get the assert text template. */ t = firstXPathNode(doc, NULL, "//*[@match='assert' and @mode='text']"); if (!t) { return; } /* Clear the template. */ c = t->children; while (c) { xmlNodePtr n; n = c->next; xmlUnlinkNode(c); xmlFreeNode(c); c = n; } /* Parse the format string and generate the new template. */ for (i = 0; fmt[i]; ++i) { xmlChar s[2] = {0}; if (fmt[i] == FMTSTR_DELIM) { if (fmt[i + 1] == FMTSTR_DELIM) { s[0] = FMTSTR_DELIM; xmlNewChild(t, t->nsDef, BAD_CAST "text", s); ++i; } else { const char *k, *e; int n; k = fmt + i + 1; e = strchr(k, FMTSTR_DELIM); if (!e) break; n = e - k; if (strncmp(k, "name", n) == 0) { c = xmlNewChild(t, t->nsDef, BAD_CAST "call-template", NULL); xmlSetProp(c, BAD_CAST "name", BAD_CAST "applicPropertyName"); } else if (strncmp(k, "values", n) == 0) { c = xmlNewChild(t, t->nsDef, BAD_CAST "call-template", NULL); xmlSetProp(c, BAD_CAST "name", BAD_CAST "applicPropertyVal"); } i += n + 1; } } else { if (fmt[i] == '\\') { switch (fmt[i + 1]) { case 'n': s[0] = '\n'; ++i; break; case 't': s[0] = '\t'; ++i; break; default: s[0] = fmt[i]; break; } } else { s[0] = fmt[i]; } xmlNewChild(t, t->nsDef, BAD_CAST "text", s); } } } static void generateDisplayText(xmlDocPtr doc, xmlNodePtr acts, xmlNodePtr ccts, xsltStylesheetPtr style) { xmlDocPtr res, muxdoc; xmlNodePtr mux, cur, muxacts, muxccts, new, old; const char *params[3]; muxdoc = xmlNewDoc(BAD_CAST "1.0"); mux = xmlNewNode(NULL, BAD_CAST "mux"); xmlDocSetRootElement(muxdoc, mux); xmlAddChild(mux, xmlCopyNode(xmlDocGetRootElement(doc), 1)); muxacts = xmlNewChild(mux, NULL, BAD_CAST "acts", NULL); muxccts = xmlNewChild(mux, NULL, BAD_CAST "ccts", NULL); for (cur = acts->children; cur; cur = cur->next) { xmlDocPtr act; xmlChar *path; path = xmlNodeGetContent(cur); act = read_xml_doc((char *) path); xmlAddChild(muxacts, xmlCopyNode(xmlDocGetRootElement(act), 1)); xmlFreeDoc(act); xmlFree(path); } for (cur = ccts->children; cur; cur = cur->next) { xmlDocPtr cct; xmlChar *path; path = xmlNodeGetContent(cur); cct = read_xml_doc((char *) path); xmlAddChild(muxccts, xmlCopyNode(xmlDocGetRootElement(cct), 1)); xmlFreeDoc(cct); xmlFree(path); } params[0] = "overwrite-display-text"; params[1] = overwriteDispText ? "true()" : "false()"; params[2] = NULL; res = xsltApplyStylesheet(style, muxdoc, params); new = xmlCopyNode(firstXPathNode(res, NULL, "/mux/dmodule"), 1); old = xmlDocSetRootElement(doc, new); xmlFreeNode(old); xmlFreeDoc(res); xmlFreeDoc(muxdoc); } static void processDmodule(xmlNodePtr dmodule) { xmlXPathContextPtr ctx; xmlXPathObjectPtr obj; ctx = xmlXPathNewContext(dmodule->doc); ctx->node = dmodule; obj = xmlXPathEvalExpression(applicElemsXPath, ctx); processNodeSet(obj->nodesetval); removeDuplicates(obj->nodesetval); addDmApplic(dmodule); xmlXPathFreeObject(obj); xmlXPathFreeContext(ctx); } static void processDmodules(xmlNodeSetPtr dmodules) { int i; for (i = 0; i < dmodules->nodeNr; ++i) { processDmodule(dmodules->nodeTab[i]); } } /* Find a data module filename in the current directory based on the dmRefIdent * element. */ static bool find_dmod_fname(char *dst, xmlNodePtr dmRefIdent) { char *model_ident_code; char *system_diff_code; char *system_code; char *sub_system_code; char *sub_sub_system_code; char *assy_code; char *disassy_code; char *disassy_code_variant; char *info_code; char *info_code_variant; char *item_location_code; char *learn_code; char *learn_event_code; char code[64]; xmlNodePtr dmCode, issueInfo, language; dmCode = firstXPathNode(NULL, dmRefIdent, "dmCode|avee"); issueInfo = firstXPathNode(NULL, dmRefIdent, "issueInfo|issno"); language = firstXPathNode(NULL, dmRefIdent, "language"); model_ident_code = (char *) first_xpath_value(NULL, dmCode, "modelic|@modelIdentCode"); system_diff_code = (char *) first_xpath_value(NULL, dmCode, "sdc|@systemDiffCode"); system_code = (char *) first_xpath_value(NULL, dmCode, "chapnum|@systemCode"); sub_system_code = (char *) first_xpath_value(NULL, dmCode, "section|@subSystemCode"); sub_sub_system_code = (char *) first_xpath_value(NULL, dmCode, "subsect|@subSubSystemCode"); assy_code = (char *) first_xpath_value(NULL, dmCode, "subject|@assyCode"); disassy_code = (char *) first_xpath_value(NULL, dmCode, "discode|@disassyCode"); disassy_code_variant = (char *) first_xpath_value(NULL, dmCode, "discodev|@disassyCodeVariant"); info_code = (char *) first_xpath_value(NULL, dmCode, "incode|@infoCode"); info_code_variant = (char *) first_xpath_value(NULL, dmCode, "incodev|@infoCodeVariant"); item_location_code = (char *) first_xpath_value(NULL, dmCode, "itemloc|@itemLocationCode"); learn_code = (char *) first_xpath_value(NULL, dmCode, "@learnCode"); learn_event_code = (char *) first_xpath_value(NULL, dmCode, "@learnEventCode"); snprintf(code, 64, "DMC-%s-%s-%s-%s%s-%s-%s%s-%s%s-%s", model_ident_code, system_diff_code, system_code, sub_system_code, sub_sub_system_code, assy_code, disassy_code, disassy_code_variant, info_code, info_code_variant, item_location_code); xmlFree(model_ident_code); xmlFree(system_diff_code); xmlFree(system_code); xmlFree(sub_system_code); xmlFree(sub_sub_system_code); xmlFree(assy_code); xmlFree(disassy_code); xmlFree(disassy_code_variant); xmlFree(info_code); xmlFree(info_code_variant); xmlFree(item_location_code); if (learn_code) { char learn[8]; snprintf(learn, 8, "-%s%s", learn_code, learn_event_code); strcat(code, learn); } xmlFree(learn_code); xmlFree(learn_event_code); if (!no_issue) { if (issueInfo) { char *issue_number; char *in_work; char iss[8]; issue_number = (char *) first_xpath_value(NULL, issueInfo, "@issno|@issueNumber"); in_work = (char *) first_xpath_value(NULL, issueInfo, "@inwork|@inWork"); snprintf(iss, 8, "_%s-%s", issue_number, in_work ? in_work : "00"); strcat(code, iss); xmlFree(issue_number); xmlFree(in_work); } else if (language) { strcat(code, "_\?\?\?-\?\?"); } } if (language) { char *language_iso_code; char *country_iso_code; char lang[8]; language_iso_code = (char *) first_xpath_value(NULL, language, "@language|@languageIsoCode"); country_iso_code = (char *) first_xpath_value(NULL, language, "@country|@countryIsoCode"); snprintf(lang, 8, "_%s-%s", language_iso_code, country_iso_code); strcat(code, lang); xmlFree(language_iso_code); xmlFree(country_iso_code); } if (find_csdb_object(dst, search_dir, code, is_dm, recursive_search)) { return true; } if (verbosity >= NORMAL) { fprintf(stderr, W_MISSING_REF, code); } return false; } /* Find the filename of a referenced ACT data module. */ static bool find_act_fname(char *dst, xmlDocPtr doc) { xmlNodePtr actref; actref = firstXPathNode(doc, NULL, "//applicCrossRefTableRef/dmRef/dmRefIdent|//actref/refdm"); return actref && find_dmod_fname(dst, actref); } /* Find the filename of a referenced PCT data module via the ACT. */ static bool find_cct_fname(char *dst, xmlDocPtr act) { xmlNodePtr pctref; bool found; pctref = firstXPathNode(act, NULL, "//condCrossRefTableRef/dmRef/dmRefIdent|//cctref/refdm"); found = pctref && find_dmod_fname(dst, pctref); return found; } /* Add cross-reference tables by searching for them in the current directory. */ static void find_cross_ref_tables(xmlDocPtr doc, xmlNodePtr acts, xmlNodePtr ccts) { char act_fname[PATH_MAX]; xmlDocPtr act = NULL; if (find_act_fname(act_fname, doc) && (act = read_xml_doc(act_fname))) { char cct_fname[PATH_MAX]; xmlNewChild(acts, NULL, BAD_CAST "act", BAD_CAST act_fname); if (find_cct_fname(cct_fname, act)) { xmlNewChild(ccts, NULL, BAD_CAST "cct", BAD_CAST cct_fname); } xmlFreeDoc(act); } } /* Add tags containing the display text of the referenecd applic annotation. */ static void addTags(xmlDocPtr doc, const char *tags) { xmlDocPtr styledoc, src, res; xsltStylesheetPtr style; const char *params[3]; xmlNodePtr old; styledoc = read_xml_mem((const char *) addTags_xsl, addTags_xsl_len); style = xsltParseStylesheetDoc(styledoc); params[0] = "mode"; if (strcmp(tags, "comment") == 0) { params[1] = "'comment'"; } else if (strcmp(tags, "pi") == 0) { params[1] = "'pi'"; } else { params[1] = "'remove'"; } params[2] = NULL; src = xmlCopyDoc(doc, 1); res = xsltApplyStylesheet(style, src, params); xmlFreeDoc(src); old = xmlDocSetRootElement(doc, xmlCopyNode(xmlDocGetRootElement(res), 1)); xmlFreeNode(old); xmlFreeDoc(res); xsltFreeStylesheet(style); } /* Recursively delete display text nodes. */ static void deleteDisplayTextNode(xmlNodePtr node) { xmlNodePtr cur; /* 3.0-: displaytext * 4.0+: displayText * * Ignore display text nodes without any siblings. */ if ((xmlStrcmp(node->name, BAD_CAST "displayText") == 0 || xmlStrcmp(node->name, BAD_CAST "displaytext") == 0) && xmlChildElementCount(node->parent) > 1) { xmlUnlinkNode(node); xmlFreeNode(node); return; } /* Call recursively on all children. */ cur = node->children; while (cur) { xmlNodePtr next = cur->next; deleteDisplayTextNode(cur); cur = next; } } /* Delete all display text nodes in a document. */ static void deleteDisplayText(xmlDocPtr doc) { deleteDisplayTextNode(xmlDocGetRootElement(doc)); } static void processFile(const char *in, const char *out, bool process, bool genDispText, bool delDispText, xmlNodePtr acts, xmlNodePtr ccts, bool findcts, xsltStylesheetPtr style, const char *tags) { xmlDocPtr doc; xmlXPathContextPtr ctx; xmlXPathObjectPtr obj; xmlNodePtr all_acts, all_ccts; if (verbosity >= VERBOSE) { fprintf(stderr, I_PROCESS, in); } doc = read_xml_doc(in); if (findcts) { /* Copy the user-defined ACTs/CCTs. */ all_acts = xmlCopyNode(acts, 1); all_ccts = xmlCopyNode(ccts, 1); /* Find the ACT/CCT referenced by the current DM. */ find_cross_ref_tables(doc, all_acts, all_ccts); } else { /* Only use the user-defined ACTs/CCTs. */ all_acts = acts; all_ccts = ccts; } if (process) { ctx = xmlXPathNewContext(doc); obj = xmlXPathEvalExpression(BAD_CAST "//dmodule", ctx); processDmodules(obj->nodesetval); xmlXPathFreeObject(obj); xmlXPathFreeContext(ctx); } if (delDispText) { deleteDisplayText(doc); } else if (genDispText) { generateDisplayText(doc, all_acts, all_ccts, style); } if (tags) { addTags(doc, tags); } save_xml_doc(doc, out); /* The next data module could reference a different ACT/CCT, so * the list must be cleared. */ if (findcts) { xmlFreeNode(all_acts); xmlFreeNode(all_ccts); } xmlFreeDoc(doc); } static void process_list(const char *path, bool overwrite, bool process, bool genDispText, bool delDispText, xmlNodePtr acts, xmlNodePtr ccts, bool findcts, xsltStylesheetPtr style, const char *tags) { FILE *f; char line[PATH_MAX]; if (path) { if (!(f = fopen(path, "r"))) { if (verbosity >= NORMAL) { fprintf(stderr, E_BAD_LIST, path); } return; } } else { f = stdin; } while (fgets(line, PATH_MAX, f)) { strtok(line, "\t\r\n"); processFile(line, overwrite ? line : "-", process, genDispText, delDispText, acts, ccts, findcts, style, tags); } if (path) { fclose(f); } } static void show_help(void) { puts("Usage:"); puts(" " PROG_NAME " [options] [ ...]"); puts(""); puts("Options:"); puts(" -., --dump-disptext Dump the built-in .disptext file."); puts(" -,, --dump-xsl Dump the built-in XSLT for generating display text."); puts(" -A, --act Use when generating display text."); puts(" -a, --id Use for DM-level applic."); puts(" -C, --cct Use when generating display text."); puts(" -c, --search Search for ACT/CCT data modules."); puts(" -D, --delete Remove all display text."); puts(" -d, --dir Directory to start search for ACT/CCT in."); puts(" -F, --format Use a custom format string for generating display text."); puts(" -f, --overwrite Overwrite input file(s)."); puts(" -G, --disptext Specify .disptext file."); puts(" -g, --generate Generate display text for applicability annotations."); puts(" -k, --keep Do not overwrite existing display text."); puts(" -l, --list Treat input as list of modules."); puts(" -N, --omit-issue Assume issue/inwork number are omitted."); puts(" -p, --presentation Convert semantic applicability to presentation applicability."); puts(" -q, --quiet Quiet mode."); puts(" -r, --recursive Search for ACT/CCT recursively."); puts(" -t, --tags Add display text tags before elements with applicability."); puts(" -v, --verbose Verbose output."); puts(" -x, --xsl Use custom XSLT script to generate display text."); puts(" -h, -?, --help Show help/usage message."); puts(" --version Show version information."); puts(" ... CSDB objects to process."); LIBXML2_PARSE_LONGOPT_HELP } static void show_version(void) { printf("%s (s1kd-tools) %s\n", PROG_NAME, VERSION); printf("Using libxml %s, libxslt %s and libexslt %s\n", xmlParserVersion, xsltEngineVersion, exsltLibraryVersion); } int main(int argc, char **argv) { int i; bool overwrite = false; bool genDispText = false; bool process = false; bool delDispText = false; bool findcts = false; bool islist = false; char *format = NULL; char *tags = NULL; char *customGenDispTextFile = NULL; xmlDocPtr disptext = NULL; xmlDocPtr styledoc; xsltStylesheetPtr style; xmlNodePtr acts, ccts; const char *sopts = ".,A:a:C:cDd:F:fG:gklNpqrt:vx:h?"; struct option lopts[] = { {"version" , no_argument , 0, 0}, {"help" , no_argument , 0, 'h'}, {"dump-disptext", no_argument , 0, '.'}, {"dump-xsl" , no_argument , 0, ','}, {"act" , required_argument, 0, 'A'}, {"id" , required_argument, 0, 'a'}, {"cct" , required_argument, 0, 'C'}, {"search" , no_argument , 0, 'c'}, {"delete" , no_argument , 0, 'D'}, {"dir" , required_argument, 0, 'd'}, {"format" , required_argument, 0, 'F'}, {"overwrite" , no_argument , 0, 'f'}, {"disptext" , required_argument, 0, 'G'}, {"generate" , no_argument , 0, 'g'}, {"keep" , no_argument , 0, 'k'}, {"list" , no_argument , 0, 'l'}, {"omit-issue" , no_argument , 0, 'N'}, {"presentation" , no_argument , 0, 'p'}, {"quiet" , no_argument , 0, 'q'}, {"recursive" , no_argument , 0, 'r'}, {"tags" , required_argument, 0, 't'}, {"verbose" , no_argument , 0, 'v'}, {"xsl" , required_argument, 0, 'x'}, LIBXML2_PARSE_LONGOPT_DEFS {0, 0, 0, 0} }; int loptind = 0; exsltRegisterAll(); dmApplicId = xmlStrdup(DEFAULT_DM_APPLIC_ID); applicElemsXPath = xmlStrndup(elements_list, elements_list_len); acts = xmlNewNode(NULL, BAD_CAST "acts"); ccts = xmlNewNode(NULL, BAD_CAST "ccts"); search_dir = strdup("."); while ((i = getopt_long(argc, argv, sopts, lopts, &loptind)) != -1) { switch (i) { case 0: if (strcmp(lopts[loptind].name, "version") == 0) { show_version(); return 0; } LIBXML2_PARSE_LONGOPT_HANDLE(lopts, loptind, optarg) break; case '.': dumpDispText(); return 0; case ',': dumpGenDispTextXsl(); return 0; case 'A': xmlNewChild(acts, NULL, BAD_CAST "act", BAD_CAST optarg); findcts = false; break; case 'a': xmlFree(dmApplicId); dmApplicId = xmlStrdup(BAD_CAST optarg); break; case 'C': xmlNewChild(ccts, NULL, BAD_CAST "cct", BAD_CAST optarg); findcts = false; break; case 'c': findcts = true; break; case 'D': delDispText = true; break; case 'd': free(search_dir); search_dir = strdup(optarg); break; case 'F': genDispText = true; free(format); format = strdup(optarg); break; case 'f': overwrite = true; break; case 'G': genDispText = true; xmlFreeDoc(disptext); disptext = read_xml_doc(optarg); break; case 'g': genDispText = true; break; case 'k': overwriteDispText = false; break; case 'l': islist = true; break; case 'N': no_issue = true; break; case 'p': process = true; break; case 'q': --verbosity; break; case 'r': recursive_search = true; break; case 't': free(tags); tags = strdup(optarg); break; case 'v': ++verbosity; break; case 'x': genDispText = true; free(customGenDispTextFile); customGenDispTextFile = strdup(optarg); break; case 'h': case '?': show_help(); return 0; } } if (customGenDispTextFile == NULL) { if (disptext == NULL) { char disptext_fname[PATH_MAX]; if (find_config(disptext_fname, DEFAULT_DISPTEXT_FNAME)) { disptext = read_xml_doc(disptext_fname); } else { disptext = read_xml_mem((const char *) disptext_xml, disptext_xml_len); } } styledoc = parse_disptext(disptext); } else { styledoc = read_xml_doc(customGenDispTextFile); } if (format) { apply_format_str(styledoc, format); } style = xsltParseStylesheetDoc(styledoc); if (optind >= argc) { if (islist) { process_list(NULL, overwrite, process, genDispText, delDispText, acts, ccts, findcts, style, tags); } else { processFile("-", "-", process, genDispText, delDispText, acts, ccts, findcts, style, tags); } } else { for (i = optind; i < argc; ++i) { if (islist) { process_list(argv[i], overwrite, process, genDispText, delDispText, acts, ccts, findcts, style, tags); } else { processFile(argv[i], overwrite ? argv[i] : "-", process, genDispText, delDispText, acts, ccts, findcts, style, tags); } } } xmlFree(dmApplicId); xmlFree(applicElemsXPath); xmlFreeNode(acts); xmlFreeNode(ccts); free(customGenDispTextFile); free(search_dir); free(format); free(tags); xmlFreeDoc(disptext); xsltFreeStylesheet(style); xsltCleanupGlobals(); xmlCleanupParser(); return 0; }