..
/
download
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/debugXML.h>
#include <libxslt/transform.h>
#include "templates.h"
#include "s1kd_tools.h"
#define PROG_NAME "s1kd-newupf"
#define VERSION "2.2.0"
#define ERR_PREFIX PROG_NAME ": ERROR: "
#define EXIT_UPF_EXISTS 1
#define EXIT_MISSING_ARGS 2
#define EXIT_INVALID_ARGS 3
#define EXIT_BAD_ISSUE 4
#define EXIT_BAD_TEMPLATE 5
#define EXIT_BAD_TEMPL_DIR 6
#define EXIT_OS_ERROR 7
#define E_BAD_TEMPL_DIR ERR_PREFIX "Cannot dump template in directory: %s\n"
#define DEFAULT_S1000D_ISSUE ISS_50
static enum issue { NO_ISS, ISS_41, ISS_42, ISS_50 } issue = NO_ISS;
#define CIR_OBJECT_XPATH \
"//accessPointSpec|" \
"//applicSpec|" \
"//cautionSpec|" \
"//circuitBreakerSpec|" \
"//controlIndicatorSpec|" \
"//enterpriseSpec|" \
"//functionalItemSpec|" \
"//partSpec|" \
"//supplySpec|" \
"//toolSpec|" \
"//warningSpec"
typedef enum {
NON_REPOSITORY,
ACCESS_POINT_REPOSITORY,
APPLIC_REPOSITORY,
CAUTION_REPOSITORY,
CIRCUIT_BREAKER_REPOSITORY,
CONTROL_INDICATOR_REPOSITORY,
ENTERPRISE_REPOSITORY,
FUNCTIONAL_ITEM_REPOSITORY,
PART_REPOSITORY,
SUPPLY_REPOSITORY,
TOOL_REPOSITORY,
WARNING_REPOSITORY
} cirType;
static char *templateDir = NULL;
static enum issue getIssue(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;
}
fprintf(stderr, ERR_PREFIX "Unsupported issue: %s\n", iss);
exit(EXIT_BAD_ISSUE);
return NO_ISS;
}
static xmlNodePtr nodeExists(const char *xpath, xmlXPathContextPtr ctx)
{
xmlXPathObjectPtr obj;
xmlNodePtr node;
obj = xmlXPathEvalExpression(BAD_CAST xpath, ctx);
if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
node = NULL;
} else {
node = obj->nodesetval->nodeTab[0];
}
xmlXPathFreeObject(obj);
return node;
}
static xmlNodePtr firstXPathNode(const char *xpath, xmlXPathContextPtr ctx)
{
xmlXPathObjectPtr obj;
xmlNodePtr node;
obj = xmlXPathEvalExpression(BAD_CAST xpath, ctx);
if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
node = NULL;
} else {
node = obj->nodesetval->nodeTab[0];
}
xmlXPathFreeObject(obj);
return node;
}
static cirType typeOfCir(xmlXPathContextPtr ctx)
{
xmlNodePtr type;
type = firstXPathNode("//content/commonRepository/*", ctx);
if (xmlStrcmp(type->name, BAD_CAST "accessPointRepository") == 0) {
return ACCESS_POINT_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "applicRepository") == 0) {
return APPLIC_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "cautionRepository") == 0) {
return CAUTION_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "circuitBreakerRepository") == 0) {
return CIRCUIT_BREAKER_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "controlIndicatorRepository") == 0) {
return CONTROL_INDICATOR_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "enterpriseRepository") == 0) {
return ENTERPRISE_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "functionalItemRepository") == 0) {
return FUNCTIONAL_ITEM_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "partRepository") == 0) {
return PART_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "supplyRepository") == 0) {
return SUPPLY_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "toolRepository") == 0) {
return TOOL_REPOSITORY;
} else if (xmlStrcmp(type->name, BAD_CAST "warningRepository") == 0) {
return WARNING_REPOSITORY;
} else {
return NON_REPOSITORY;
}
}
/* XPath for specs which are distinguished by a single unique attribute */
static xmlNodePtr xpathForBasicSpec(char *xpath, xmlNodePtr object, const char *attr)
{
xmlNodePtr ident;
xmlChar *value;
ident = xmlFirstElementChild(object);
value = xmlGetProp(ident, BAD_CAST attr);
snprintf(xpath, 256, "//%s[%s/@%s='%s']",
(char *) object->name,
(char *) ident->name,
attr,
(char *) value);
xmlFree(value);
return ident;
}
static xmlNodePtr xpathForPartSpec(char *xpath, xmlNodePtr object)
{
xmlNodePtr ident;
xmlChar *partNumberValue, *manufacturerCodeValue;
ident = xmlFirstElementChild(object);
partNumberValue = xmlGetProp(ident, BAD_CAST "partNumberValue");
manufacturerCodeValue = xmlGetProp(ident, BAD_CAST "manufacturerCodeValue");
snprintf(xpath, 256, "//partSpec[partIdent/@partNumberValue='%s' and partIdent/@manufacturerCodeValue='%s']",
(char *) partNumberValue,
(char *) manufacturerCodeValue);
xmlFree(partNumberValue);
xmlFree(manufacturerCodeValue);
return ident;
}
static xmlNodePtr xpathForToolSpec(char *xpath, xmlNodePtr object)
{
xmlNodePtr ident;
xmlChar *toolNumber, *manufacturerCodeValue;
ident = xmlFirstElementChild(object);
toolNumber = xmlGetProp(ident, BAD_CAST "toolNumber");
manufacturerCodeValue = xmlGetProp(ident, BAD_CAST "manufacturerCodeValue");
snprintf(xpath, 256, "//toolSpec[toolIdent/@toolNumber='%s' and toolIdent/@manufacturerCodeValue='%s']",
(char *) toolNumber,
(char *) manufacturerCodeValue);
xmlFree(toolNumber);
xmlFree(manufacturerCodeValue);
return ident;
}
static xmlNodePtr xpathForControlIndicatorSpec(char *xpath, xmlNodePtr object)
{
xmlChar *controlIndicatorNumber;
xmlNodePtr ident;
controlIndicatorNumber = xmlGetProp(object, BAD_CAST "controlIndicatorNumber");
snprintf(xpath, 256, "//controlIndicatorSpec[@controlIndicatorNumber='%s']",
(char *) controlIndicatorNumber);
ident = xmlNewNode(NULL, BAD_CAST "controlIndicatorIdent");
xmlAddNextSibling(object, ident);
xmlSetProp(ident, BAD_CAST "controlIndicatorNumber", controlIndicatorNumber);
xmlFree(controlIndicatorNumber);
return ident;
}
static xmlNodePtr getNodeXPath(char *xpath, xmlNodePtr object)
{
xmlNodePtr ident;
xmlChar *id;
if ((id = xmlGetProp(object, BAD_CAST "id"))) {
snprintf(xpath, 256, "//%s[@id='%s']", (char *) object->name, (char *) id);
ident = xmlFirstElementChild(object);
} else if (xmlStrcmp(object->name, BAD_CAST "accessPointSpec") == 0) {
ident = xpathForBasicSpec(xpath, object, "accessPointNumber");
} else if (xmlStrcmp(object->name, BAD_CAST "applicSpec") == 0) {
ident = xpathForBasicSpec(xpath, object, "applicIdentValue");
} else if (xmlStrcmp(object->name, BAD_CAST "cautionSpec") == 0) {
ident = xpathForBasicSpec(xpath, object, "cautionIdentNumber");
} else if (xmlStrcmp(object->name, BAD_CAST "circuitBreakerSpec") == 0) {
ident = xpathForBasicSpec(xpath, object, "circuitBreakerNumber");
} else if (xmlStrcmp(object->name, BAD_CAST "controlIndicatorSpec") == 0) {
ident = xpathForControlIndicatorSpec(xpath, object);
} else if (xmlStrcmp(object->name, BAD_CAST "enterpriseSpec") == 0) {
ident = xpathForBasicSpec(xpath, object, "manufacturerCodeValue");
} else if (xmlStrcmp(object->name, BAD_CAST "functionalItemSpec") == 0) {
ident = xpathForBasicSpec(xpath, object, "functionalItemNumber");
} else if (xmlStrcmp(object->name, BAD_CAST "partSpec") == 0) {
ident = xpathForPartSpec(xpath, object);
} else if (xmlStrcmp(object->name, BAD_CAST "supplySpec") == 0) {
ident = xpathForBasicSpec(xpath, object, "supplyNumber");
} else if (xmlStrcmp(object->name, BAD_CAST "toolSpec") == 0) {
ident = xpathForToolSpec(xpath, object);
} else if (xmlStrcmp(object->name, BAD_CAST "warningSpec") == 0) {
ident = xpathForBasicSpec(xpath, object, "warningIdentNumber");
} else {
ident = NULL;
}
return ident;
}
static xmlNodePtr deleteObjects(xmlXPathContextPtr src, xmlXPathContextPtr tgt)
{
xmlNodePtr group;
xmlXPathObjectPtr results;
xmlNodeSetPtr objects;
group = xmlNewNode(NULL, BAD_CAST "deleteObjectGroup");
results = xmlXPathEvalExpression(BAD_CAST CIR_OBJECT_XPATH, src);
objects = results->nodesetval;
if (!xmlXPathNodeSetIsEmpty(objects)) {
int i;
for (i = 0; i < objects->nodeNr; ++i) {
char xpath[256];
xmlNodePtr ident;
ident = getNodeXPath(xpath, objects->nodeTab[i]);
if (!nodeExists(xpath, tgt)) {
xmlNodePtr deleteObject;
deleteObject = xmlNewChild(group, NULL, BAD_CAST "deleteObject", NULL);
xmlAddChild(deleteObject, xmlCopyNode(ident, 1));
}
}
}
xmlXPathFreeObject(results);
if (group->children) {
return group;
}
xmlFreeNode(group);
return NULL;
}
static xmlNodePtr insertObjects(xmlXPathContextPtr src, xmlXPathContextPtr tgt)
{
xmlNodePtr group;
xmlXPathObjectPtr results;
xmlNodeSetPtr objects;
group = xmlNewNode(NULL, BAD_CAST "insertObjectGroup");
results = xmlXPathEvalExpression(BAD_CAST CIR_OBJECT_XPATH, tgt);
objects = results->nodesetval;
if (!xmlXPathNodeSetIsEmpty(objects)) {
int i;
for (i = 0; i < objects->nodeNr; ++i) {
char xpath[256];
getNodeXPath(xpath, objects->nodeTab[i]);
if (!nodeExists(xpath, src)) {
xmlNodePtr insertObject, before, after;
insertObject = xmlNewChild(group, NULL, BAD_CAST "insertObject", NULL);
before = xmlPreviousElementSibling(objects->nodeTab[i]);
after = xmlNextElementSibling(objects->nodeTab[i]);
if (before) {
getNodeXPath(xpath, before);
xmlSetProp(insertObject, BAD_CAST "targetPath", BAD_CAST xpath);
xmlSetProp(insertObject, BAD_CAST "insertionOrder", BAD_CAST "after");
} else if (after) {
getNodeXPath(xpath, after);
xmlSetProp(insertObject, BAD_CAST "targetPath", BAD_CAST xpath);
xmlSetProp(insertObject, BAD_CAST "insertionOrder", BAD_CAST "before");
}
xmlAddChild(insertObject, xmlCopyNode(objects->nodeTab[i], 1));
}
}
}
xmlXPathFreeObject(results);
if (group->children) {
return group;
}
xmlFreeNode(group);
return NULL;
}
static bool sameNodes(xmlNodePtr a, xmlNodePtr b)
{
xmlBufferPtr bufA, bufB;
bool equal;
bufA = xmlBufferCreate();
bufB = xmlBufferCreate();
xmlNodeDump(bufA, a->doc, a, 0, 0);
xmlNodeDump(bufB, b->doc, b, 0, 0);
equal = xmlStrcmp(bufA->content, bufB->content) == 0;
xmlBufferFree(bufA);
xmlBufferFree(bufB);
return equal;
}
static xmlNodePtr replaceObjects(xmlXPathContextPtr src, xmlXPathContextPtr tgt)
{
xmlNodePtr group;
xmlXPathObjectPtr results;
xmlNodeSetPtr objects;
group = xmlNewNode(NULL, BAD_CAST "replaceObjectGroup");
results = xmlXPathEvalExpression(BAD_CAST CIR_OBJECT_XPATH, src);
objects = results->nodesetval;
if (!xmlXPathNodeSetIsEmpty(objects)) {
int i;
for (i = 0; i < objects->nodeNr; ++i) {
char xpath[256];
xmlNodePtr node;
getNodeXPath(xpath, objects->nodeTab[i]);
if ((node = nodeExists(xpath, tgt)) && !sameNodes(objects->nodeTab[i], node)) {
xmlNodePtr replaceObject;
replaceObject = xmlNewChild(group, NULL, BAD_CAST "replaceObject", NULL);
xmlAddChild(replaceObject, xmlCopyNode(node, 1));
}
}
}
xmlXPathFreeObject(results);
if (group->children) {
return group;
}
return NULL;
}
/* Copy metadata from source and target CIRs */
static void setMetadata(xmlXPathContextPtr update, xmlXPathContextPtr source, xmlXPathContextPtr target)
{
xmlNodePtr updateAddress, updateIdent, updateCode, sourceDmIdent,
updateStatus, targetDmIssueInfo, updateIdentAndStatusSection,
targetDmStatus;
updateAddress = firstXPathNode("//updateAddress", update);
updateIdent = xmlAddChild(updateAddress, xmlCopyNode(firstXPathNode("//dmIdent", source), 1));
xmlNodeSetName(updateIdent, BAD_CAST "updateIdent");
updateCode = firstXPathNode("//updateIdent/dmCode", update);
xmlNodeSetName(updateCode, BAD_CAST "updateCode");
xmlSetProp(updateCode, BAD_CAST "objectIdentCode", BAD_CAST "UPF");
updateStatus = firstXPathNode("//updateStatus", update);
xmlAddChild(updateAddress, xmlCopyNode(firstXPathNode("//dmAddressItems/issueDate", target), 1));
sourceDmIdent = xmlAddChild(updateStatus, xmlCopyNode(firstXPathNode("//dmIdent", source), 1));
xmlNodeSetName(sourceDmIdent, BAD_CAST "sourceDmIdent");
targetDmIssueInfo = xmlAddChild(updateStatus, xmlCopyNode(firstXPathNode("//dmIdent/issueInfo", target), 1));
xmlNodeSetName(targetDmIssueInfo, BAD_CAST "targetDmIssueInfo");
xmlAddChild(updateStatus, xmlCopyNode(firstXPathNode("//dmStatus/responsiblePartnerCompany", target), 1));
xmlAddChild(updateStatus, xmlCopyNode(firstXPathNode("//dmStatus/originator", target), 1));
xmlAddChild(updateStatus, xmlCopyNode(firstXPathNode("//dmStatus/brexDmRef", target), 1));
xmlAddChild(updateStatus, xmlCopyNode(firstXPathNode("//dmStatus/qualityAssurance", target), 1));
updateIdentAndStatusSection = firstXPathNode("//updateIdentAndStatusSection", update);
targetDmStatus = xmlAddChild(updateIdentAndStatusSection, xmlCopyNode(firstXPathNode("//dmStatus", target), 1));
xmlNodeSetName(targetDmStatus, BAD_CAST "targetDmStatus");
}
static void autoName(char *dst, xmlXPathContextPtr update)
{
xmlNodePtr updateCode, issueInfo, language;
char *modelIdentCode;
char *systemDiffCode;
char *systemCode;
char *subSystemCode;
char *subSubSystemCode;
char *assyCode;
char *disassyCode;
char *disassyCodeVariant;
char *infoCode;
char *infoCodeVariant;
char *itemLocationCode;
char *issueNumber;
char *inWork;
char *languageIsoCode;
char *countryIsoCode;
int i;
updateCode = firstXPathNode("//updateIdent/updateCode", update);
issueInfo = firstXPathNode("//updateIdent/issueInfo", update);
language = firstXPathNode("//updateIdent/language", update);
modelIdentCode = (char *) xmlGetProp(updateCode, BAD_CAST "modelIdentCode");
systemDiffCode = (char *) xmlGetProp(updateCode, BAD_CAST "systemDiffCode");
systemCode = (char *) xmlGetProp(updateCode, BAD_CAST "systemCode");
subSystemCode = (char *) xmlGetProp(updateCode, BAD_CAST "subSystemCode");
subSubSystemCode = (char *) xmlGetProp(updateCode, BAD_CAST "subSubSystemCode");
assyCode = (char *) xmlGetProp(updateCode, BAD_CAST "assyCode");
disassyCode = (char *) xmlGetProp(updateCode, BAD_CAST "disassyCode");
disassyCodeVariant = (char *) xmlGetProp(updateCode, BAD_CAST "disassyCodeVariant");
infoCode = (char *) xmlGetProp(updateCode, BAD_CAST "infoCode");
infoCodeVariant = (char *) xmlGetProp(updateCode, BAD_CAST "infoCodeVariant");
itemLocationCode = (char *) xmlGetProp(updateCode, BAD_CAST "itemLocationCode");
issueNumber = (char *) xmlGetProp(issueInfo, BAD_CAST "issueNumber");
inWork = (char *) xmlGetProp(issueInfo, BAD_CAST "inWork");
languageIsoCode = (char *) xmlGetProp(language, BAD_CAST "languageIsoCode");
countryIsoCode = (char *) xmlGetProp(language, BAD_CAST "countryIsoCode");
for (i = 0; languageIsoCode[i]; ++i) languageIsoCode[i] = toupper(languageIsoCode[i]);
sprintf(dst, "UPF-%s-%s-%s-%s%s-%s-%s%s-%s%s-%s_%s-%s_%s-%s.XML",
modelIdentCode,
systemDiffCode,
systemCode,
subSystemCode,
subSubSystemCode,
assyCode,
disassyCode,
disassyCodeVariant,
infoCode,
infoCodeVariant,
itemLocationCode,
issueNumber,
inWork,
languageIsoCode,
countryIsoCode);
xmlFree(modelIdentCode);
xmlFree(systemDiffCode);
xmlFree(systemCode);
xmlFree(subSystemCode);
xmlFree(subSubSystemCode);
xmlFree(assyCode);
xmlFree(disassyCode);
xmlFree(disassyCodeVariant);
xmlFree(infoCode);
xmlFree(infoCodeVariant);
xmlFree(itemLocationCode);
xmlFree(issueNumber);
xmlFree(inWork);
xmlFree(languageIsoCode);
xmlFree(countryIsoCode);
}
static xmlDocPtr toIssue(xmlDocPtr doc, enum issue iss)
{
xsltStylesheetPtr style;
xmlDocPtr styledoc, res, 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;
default:
return NULL;
}
orig = xmlCopyDoc(doc, 1);
styledoc = read_xml_mem((const char *) xml, len);
style = xsltParseStylesheetDoc(styledoc);
res = xsltApplyStylesheet(style, doc, NULL);
xmlFreeDoc(doc);
xsltFreeStylesheet(style);
xmlDocSetRootElement(orig, xmlCopyNode(xmlDocGetRootElement(res), 1));
xmlFreeDoc(res);
return orig;
}
static xmlDocPtr xmlSkeleton(const char *templateDir)
{
if (templateDir) {
char src[PATH_MAX];
sprintf(src, "%s/update.xml", templateDir);
if (access(src, F_OK) == -1) {
fprintf(stderr, ERR_PREFIX "No schema update in template directory \"%s\".\n", templateDir);
exit(EXIT_BAD_TEMPLATE);
}
return read_xml_doc(src);
} else {
return read_xml_mem((const char *) update_xml, update_xml_len);
}
}
static void copyDefaultValue(const char *key, const char *val)
{
if (strcmp(key, "issue") == 0 && issue == NO_ISS) {
issue = getIssue(val);
} else if (strcmp(key, "templates") == 0 && !templateDir) {
templateDir = strdup(val);
}
}
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("update.xml", "w");
fprintf(f, "%.*s", update_xml_len, update_xml);
fclose(f);
}
static void show_help(void)
{
puts("Usage: " PROG_NAME " [options] <SOURCE> <TARGET>");
puts("");
puts("Options:");
puts(" -$, --issue <issue> Specify which S1000D issue to use.");
puts(" -@, --out <path> Output to specified file or directory.");
puts(" -%, --templates <dir> Use templates in specified directory.");
puts(" -~, --dump-templates <dir> Dump built-in template to directory.");
puts(" -d, --defaults <file> Specify the .defaults file name.");
puts(" -f, --overwrite Overwrite existing file.");
puts(" -h, -?, --help Show help/usage message.");
puts(" -q, --quiet Don't report an error if file exists.");
puts(" -v, --verbose Print file name of new update file.");
puts(" --version Show version information.");
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);
}
int main(int argc, char **argv)
{
const char *source, *target;
xmlDocPtr sourceDoc, targetDoc, updateFile;
xmlXPathContextPtr sourceContext, targetContext, updateFileContext;
xmlNodePtr update;
xmlNodePtr deleteObjectGroup, insertObjectGroup, replaceObjectGroup;
int c;
bool overwrite = false;
bool no_overwrite_error = false;
bool verbose = false;
char *out = NULL;
char *outdir = NULL;
char defaultsFname[PATH_MAX];
bool custom_defaults = false;
xmlDocPtr defaultsXml;
const char *sopts = "@:$:%:d:fqv~:h?";
struct option lopts[] = {
{"version" , no_argument , 0, 0},
{"help" , no_argument , 0, 'h'},
{"out" , required_argument, 0, '@'},
{"issue" , required_argument, 0, '$'},
{"templates" , required_argument, 0, '%'},
{"defaults" , required_argument, 0, 'd'},
{"overwrite" , no_argument , 0, 'f'},
{"quiet" , no_argument , 0, 'q'},
{"verbose" , no_argument , 0, 'v'},
{"dump-templates", required_argument, 0, '~'},
LIBXML2_PARSE_LONGOPT_DEFS
{0, 0, 0, 0}
};
int loptind = 0;
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 '@':
out = strdup(optarg);
break;
case '$':
issue = getIssue(optarg);
break;
case '%':
templateDir = strdup(optarg);
break;
case 'd':
strncpy(defaultsFname, optarg, PATH_MAX - 1);
custom_defaults = true;
break;
case 'f':
overwrite = true;
break;
case 'q':
no_overwrite_error = true;
break;
case 'v':
verbose = true;
break;
case '~':
dump_template(optarg);
return 0;
case 'h':
case '?':
show_help();
return 0;
}
}
if (argc - optind < 2) {
exit(EXIT_MISSING_ARGS);
}
source = argv[optind];
target = argv[optind + 1];
sourceDoc = read_xml_doc(source);
targetDoc = read_xml_doc(target);
if (!custom_defaults) {
find_config(defaultsFname, DEFAULT_DEFAULTS_FNAME);
}
if ((defaultsXml = read_xml_doc(defaultsFname))) {
xmlNodePtr cur;
for (cur = xmlDocGetRootElement(defaultsXml)->children; cur; cur = cur->next) {
char *key, *val;
if (cur->type != XML_ELEMENT_NODE) continue;
if (!xmlHasProp(cur, BAD_CAST "ident")) continue;
if (!xmlHasProp(cur, BAD_CAST "value")) continue;
key = (char *) xmlGetProp(cur, BAD_CAST "ident");
val = (char *) xmlGetProp(cur, BAD_CAST "value");
copyDefaultValue(key, val);
xmlFree(key);
xmlFree(val);
}
xmlFreeDoc(defaultsXml);
} else {
FILE *defaults;
if ((defaults = fopen(defaultsFname, "r"))) {
char line[1024];
while (fgets(line, 1024, defaults)) {
char key[32];
char val[256];
if (sscanf(line, "%31s %255[^\n]", key, val) != 2)
continue;
copyDefaultValue(key, val);
}
fclose(defaults);
}
}
if (issue == NO_ISS) issue = DEFAULT_S1000D_ISSUE;
updateFile = xmlSkeleton(templateDir);
sourceContext = xmlXPathNewContext(sourceDoc);
targetContext = xmlXPathNewContext(targetDoc);
updateFileContext = xmlXPathNewContext(updateFile);
if (typeOfCir(sourceContext) != typeOfCir(targetContext)) {
fprintf(stderr, ERR_PREFIX "Source CIR and target CIR are of different types.\n");
exit(EXIT_INVALID_ARGS);
}
setMetadata(updateFileContext, sourceContext, targetContext);
update = firstXPathNode("//content/update", updateFileContext);
if ((deleteObjectGroup = deleteObjects(sourceContext, targetContext))) {
xmlAddChild(update, deleteObjectGroup);
}
if ((insertObjectGroup = insertObjects(sourceContext, targetContext))) {
xmlAddChild(update, insertObjectGroup);
}
if ((replaceObjectGroup = replaceObjects(sourceContext, targetContext))) {
xmlAddChild(update, replaceObjectGroup);
}
if (issue < ISS_50) {
xmlXPathFreeContext(updateFileContext);
updateFile = toIssue(updateFile, issue);
updateFileContext = xmlXPathNewContext(updateFile);
}
if (out && isdir(out, false)) {
outdir = out;
out = NULL;
}
if (!out) {
out = malloc(PATH_MAX);
autoName(out, updateFileContext);
}
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_UPF_EXISTS);
}
save_xml_doc(updateFile, out);
if (verbose) {
if (outdir) {
printf("%s/%s\n", outdir, out);
} else {
puts(out);
}
}
free(out);
free(outdir);
free(templateDir);
xmlXPathFreeContext(updateFileContext);
xmlXPathFreeContext(sourceContext);
xmlXPathFreeContext(targetContext);
xmlFreeDoc(sourceDoc);
xmlFreeDoc(targetDoc);
xmlFreeDoc(updateFile);
xmlCleanupParser();
return 0;
}
gopher://khzae.net/0/s1000d/s1kd-tools/src/tools/s1kd-newupf/s1kd-newupf.c