..
/
download
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <regex.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include "s1kd_tools.h"
#define PROG_NAME "s1kd-metadata"
#define VERSION "4.5.0"
#define ERR_PREFIX PROG_NAME ": ERROR: "
#define EXIT_INVALID_METADATA 1
#define EXIT_INVALID_VALUE 2
#define EXIT_NO_WRITE 3
#define EXIT_MISSING_METADATA 4
#define EXIT_NO_EDIT 5
#define EXIT_INVALID_CREATE 6
#define EXIT_NO_FILE 7
#define EXIT_CONDITION_UNMET 8
#define KEY_COLUMN_WIDTH 31
#define FMTSTR_DELIM '%'
#define DEFAULT_TIMEFMT "%Y-%m-%d"
enum verbosity {SILENT, NORMAL};
struct opts {
xmlNodePtr conds;
int endl;
char *execstr;
char *fmtstr;
int format_all;
xmlNodePtr keys;
char *metadata_fname;
int only_editable;
int overwrite;
char *timefmt;
enum verbosity verbosity;
};
struct metadata {
char *key;
char *path;
xmlChar *(*get)(xmlNodePtr, struct opts *);
void (*show)(xmlNodePtr, struct opts *);
int (*edit)(xmlNodePtr, const char *);
int (*create)(xmlXPathContextPtr, const char *);
char *descr;
};
struct icn_metadata {
char *key;
xmlChar *(*get)(const char *, struct opts *);
void (*show)(const char *, struct opts *);
};
static xmlNodePtr first_xpath_node(char *expr, xmlXPathContextPtr ctxt)
{
xmlXPathObjectPtr results;
xmlNodePtr node;
results = xmlXPathEvalExpression(BAD_CAST expr, ctxt);
if (xmlXPathNodeSetIsEmpty(results->nodesetval)) {
node = NULL;
} else {
node = results->nodesetval->nodeTab[0];
}
xmlXPathFreeObject(results);
return node;
}
static xmlNodePtr first_xpath_node_local(xmlNodePtr node, const xmlChar *expr)
{
xmlXPathContextPtr ctx;
xmlXPathObjectPtr obj;
xmlNodePtr first;
ctx = xmlXPathNewContext(node->doc);
ctx->node = node;
obj = xmlXPathEvalExpression(BAD_CAST expr, ctx);
if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
first = NULL;
} else {
first = obj->nodesetval->nodeTab[0];
}
xmlXPathFreeObject(obj);
xmlXPathFreeContext(ctx);
return first;
}
static xmlChar *first_xpath_string(xmlNodePtr node, const xmlChar *expr)
{
return xmlNodeGetContent(first_xpath_node_local(node, expr));
}
static xmlChar *get_issue_date(xmlNodePtr node, struct opts *opts)
{
xmlChar *year, *month, *day, *date;
int y, m, d;
struct tm t = {0};
year = xmlGetProp(node, BAD_CAST "year");
month = xmlGetProp(node, BAD_CAST "month");
day = xmlGetProp(node, BAD_CAST "day");
y = atoi((char *) year);
m = atoi((char *) month);
d = atoi((char *) day);
t.tm_mday = d;
t.tm_mon = m - 1;
t.tm_year = y - 1900;
date = malloc(256);
strftime((char *) date, 256, opts->timefmt, &t);
xmlFree(year);
xmlFree(month);
xmlFree(day);
return date;
}
static void show_issue_date(xmlNodePtr issue_date, struct opts *opts)
{
xmlChar *date;
date = get_issue_date(issue_date, opts);
if (date) {
printf("%s", (char *) date);
}
xmlFree(date);
}
static int edit_issue_date(xmlNodePtr issue_date, const char *val)
{
char year[5], month[3], day[3];
if (sscanf(val, "%4s-%2s-%2s", year, month, day) != 3) {
return EXIT_INVALID_VALUE;
}
xmlSetProp(issue_date, BAD_CAST "year", BAD_CAST year);
xmlSetProp(issue_date, BAD_CAST "month", BAD_CAST month);
xmlSetProp(issue_date, BAD_CAST "day", BAD_CAST day);
return 0;
}
static void show_simple_node(xmlNodePtr node, struct opts *opts)
{
xmlChar *content = xmlNodeGetContent(node);
if (content) {
printf("%s", (char *) content);
}
xmlFree(content);
}
static int edit_simple_node(xmlNodePtr node, const char *val)
{
xmlNodeSetContent(node, BAD_CAST val);
return 0;
}
static int create_info_name(xmlXPathContextPtr ctxt, const char *val)
{
xmlNodePtr tech_name, info_name;
tech_name = first_xpath_node("//techName|//techname", ctxt);
if (xmlStrcmp(tech_name->name, BAD_CAST "techName") == 0) {
info_name = xmlNewNode(NULL, BAD_CAST "infoName");
} else {
info_name = xmlNewNode(NULL, BAD_CAST "infoname");
}
info_name = xmlAddNextSibling(tech_name, info_name);
xmlNodeSetContent(info_name, BAD_CAST val);
return 0;
}
static int create_info_name_variant(xmlXPathContextPtr ctxt, const char *val)
{
xmlNodePtr info_name, info_name_variant;
if (!(info_name = first_xpath_node("//infoName", ctxt))) {
return 1;
}
info_name_variant = xmlNewNode(NULL, BAD_CAST "infoNameVariant");
info_name_variant = xmlAddNextSibling(info_name, info_name_variant);
xmlNodeSetContent(info_name_variant, BAD_CAST val);
return 0;
}
static void show_simple_attr(xmlNodePtr node, const char *attr, struct opts *opts)
{
xmlChar *text = xmlGetProp(node, BAD_CAST attr);
if (text) {
printf("%s", (char *) text);
}
xmlFree(text);
}
static int edit_simple_attr(xmlNodePtr node, const char *attr, const char *val)
{
xmlSetProp(node, BAD_CAST attr, BAD_CAST val);
return 0;
}
static void show_rpc_name(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "rpc") == 0) {
show_simple_attr(node, "rpcname", opts);
} else {
show_simple_node(node, opts);
}
}
static int edit_rpc_name(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "rpc") == 0) {
return edit_simple_attr(node, "rpcname", val);
} else {
return edit_simple_node(node, val);
}
}
static void show_orig_name(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "orig") == 0) {
show_simple_attr(node, "origname", opts);
} else {
show_simple_node(node, opts);
}
}
static int edit_orig_name(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "orig") == 0) {
return edit_simple_attr(node, "origname", val);
} else {
return edit_simple_node(node, val);
}
}
static void show_ent_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "orig") == 0 || xmlStrcmp(node->name, BAD_CAST "rpc") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "enterpriseCode", opts);
}
}
static int edit_ent_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "orig") == 0 || xmlStrcmp(node->name, BAD_CAST "rpc") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "enterpriseCode", val);
}
}
static int create_rpc_ent_code(xmlXPathContextPtr ctxt, const char *val)
{
xmlNodePtr node;
node = first_xpath_node("//rpc|//responsiblePartnerCompany", ctxt);
if (xmlStrcmp(node->name, BAD_CAST "rpc") == 0) {
edit_simple_node(node, val);
} else {
edit_simple_attr(node, "enterpriseCode", val);
}
return 0;
}
static int create_orig_ent_code(xmlXPathContextPtr ctxt, const char *val)
{
xmlNodePtr node;
node = first_xpath_node("//orig|//originator", ctxt);
if (xmlStrcmp(node->name, BAD_CAST "orig") == 0) {
edit_simple_node(node, val);
} else {
edit_simple_attr(node, "enterpriseCode", val);
}
return 0;
}
static void show_sec_class(xmlNodePtr node, struct opts *opts)
{
if (xmlHasProp(node, BAD_CAST "securityClassification")) {
show_simple_attr(node, "securityClassification", opts);
} else {
show_simple_attr(node, "class", opts);
}
}
static int edit_sec_class(xmlNodePtr node, const char *val)
{
if (xmlHasProp(node, BAD_CAST "securityClassification")) {
return edit_simple_attr(node, "securityClassification", val);
} else {
return edit_simple_attr(node, "class", val);
}
}
static xmlChar *get_issue(xmlNodePtr node, struct opts *opts)
{
xmlChar *url;
regex_t re;
regmatch_t pmatch[3];
xmlChar *iss;
regcomp(&re, "S1000D_([0-9]+)-([0-9]+)", REG_EXTENDED);
url = xmlGetNsProp(node, BAD_CAST "noNamespaceSchemaLocation", BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
if (url && regexec(&re, (char *) url, 3, pmatch, 0) == 0) {
int len1, len2, n;
len1 = pmatch[1].rm_eo - pmatch[1].rm_so;
len2 = pmatch[2].rm_eo - pmatch[2].rm_so;
n = len1 + len2 + 2;
iss = malloc(n);
xmlStrPrintf(iss, n, "%.*s.%.*s",
len1, url + pmatch[1].rm_so,
len2, url + pmatch[2].rm_so);
xmlFree(url);
} else {
iss = NULL;
}
regfree(&re);
return iss;
}
static void show_issue(xmlNodePtr node, struct opts *opts)
{
xmlChar *iss;
iss = get_issue(node, opts);
if (iss) {
printf("%s", (char *) iss);
}
free(iss);
}
static int edit_issue(xmlNodePtr node, const char *val)
{
xmlAttrPtr attr;
char *url;
regex_t re;
regmatch_t pmatch[1];
int err = 0;
regcomp(&re, "[^/]+\\.xsd$", REG_EXTENDED);
attr = xmlHasNsProp(node, BAD_CAST "noNamespaceSchemaLocation", BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
url = (char *) xmlNodeGetContent((xmlNodePtr) attr);
if (regexec(&re, url, 1, pmatch, 0) == 0) {
xmlChar *schema, *xsi;
schema = xmlCharStrndup(url + pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so);
xsi = xmlStrdup(BAD_CAST "http://www.s1000d.org/S1000D_");
if (strcmp(val, "2.0") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "2-0");
} else if (strcmp(val, "2.1") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "2-1");
} else if (strcmp(val, "2.2") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "2-2");
} else if (strcmp(val, "2.3") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "2-3");
} else if (strcmp(val, "3.0") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "3-0");
} else if (strcmp(val, "4.0") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "4-0");
} else if (strcmp(val, "4.1") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "4-1");
} else if (strcmp(val, "4.2") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "4-2");
} else if (strcmp(val, "5.0") == 0) {
xsi = xmlStrcat(xsi, BAD_CAST "5-0");
} else {
err = EXIT_INVALID_VALUE;
}
if (!err) {
xsi = xmlStrcat(xsi, BAD_CAST "/xml_schema_flat/");
xsi = xmlStrcat(xsi, schema);
xmlSetNsProp(node, attr->ns, BAD_CAST "noNamespaceSchemaLocation", xsi);
}
xmlFree(schema);
xmlFree(xsi);
} else {
err = EXIT_MISSING_METADATA;
}
regfree(&re);
xmlFree(url);
return err;
}
static void show_schema_url(xmlNodePtr node, struct opts *opts)
{
show_simple_attr(node, "noNamespaceSchemaLocation", opts);
}
static int edit_schema_url(xmlNodePtr node, const char *val)
{
return edit_simple_attr(node, "xsi:noNamespaceSchemaLocation", val);
}
static xmlChar *get_schema(xmlNodePtr node, struct opts *opts)
{
char *url, *s;
xmlChar *r;
url = (char *) xmlGetProp(node, BAD_CAST "noNamespaceSchemaLocation");
if (url) {
char *e;
s = strrchr(url, '/');
s = s ? s + 1 : url;
e = strrchr(s, '.');
if (e) *e = '\0';
r = xmlCharStrdup(s);
xmlFree(url);
} else {
r = NULL;
}
return r;
}
static void show_schema(xmlNodePtr node, struct opts *opts)
{
xmlChar *s;
s = get_schema(node, opts);
if (s) {
printf("%s", (char *) s);
}
free(s);
}
static int edit_info_name(xmlNodePtr node, const char *val)
{
if (strcmp(val, "") == 0) {
xmlUnlinkNode(node);
xmlFreeNode(node);
return 0;
} else {
return edit_simple_node(node, val);
}
}
static void show_type(xmlNodePtr node, struct opts *opts)
{
printf("%s", node->name);
}
static xmlChar *get_dmcode(xmlNodePtr node, struct opts *opts)
{
xmlChar *model_ident_code;
xmlChar *system_diff_code;
xmlChar *system_code;
xmlChar *sub_system_code;
xmlChar *sub_sub_system_code;
xmlChar *assy_code;
xmlChar *disassy_code;
xmlChar *disassy_code_variant;
xmlChar *info_code;
xmlChar *info_code_variant;
xmlChar *item_location_code;
xmlChar *learn_code;
xmlChar *learn_event_code;
xmlChar learn[6] = "";
xmlChar *code;
if (xmlStrcmp(node->name, BAD_CAST "dmCode") == 0) {
model_ident_code = xmlGetProp(node, BAD_CAST "modelIdentCode");
system_diff_code = xmlGetProp(node, BAD_CAST "systemDiffCode");
system_code = xmlGetProp(node, BAD_CAST "systemCode");
sub_system_code = xmlGetProp(node, BAD_CAST "subSystemCode");
sub_sub_system_code = xmlGetProp(node, BAD_CAST "subSubSystemCode");
assy_code = xmlGetProp(node, BAD_CAST "assyCode");
disassy_code = xmlGetProp(node, BAD_CAST "disassyCode");
disassy_code_variant = xmlGetProp(node, BAD_CAST "disassyCodeVariant");
info_code = xmlGetProp(node, BAD_CAST "infoCode");
info_code_variant = xmlGetProp(node, BAD_CAST "infoCodeVariant");
item_location_code = xmlGetProp(node, BAD_CAST "itemLocationCode");
learn_code = xmlGetProp(node, BAD_CAST "learnCode");
learn_event_code = xmlGetProp(node, BAD_CAST "learnEventCode");
if (learn_code && learn_event_code) xmlStrPrintf(learn, 6, "-%s%s", learn_code, learn_event_code);
} else {
model_ident_code = first_xpath_string(node, BAD_CAST "modelic");
system_diff_code = first_xpath_string(node, BAD_CAST "sdc");
system_code = first_xpath_string(node, BAD_CAST "chapnum");
sub_system_code = first_xpath_string(node, BAD_CAST "section");
sub_sub_system_code = first_xpath_string(node, BAD_CAST "subsect");
assy_code = first_xpath_string(node, BAD_CAST "subject");
disassy_code = first_xpath_string(node, BAD_CAST "discode");
disassy_code_variant = first_xpath_string(node, BAD_CAST "discodev");
info_code = first_xpath_string(node, BAD_CAST "incode");
info_code_variant = first_xpath_string(node, BAD_CAST "incodev");
item_location_code = first_xpath_string(node, BAD_CAST "itemloc");
learn_code = NULL;
learn_event_code = NULL;
}
if (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)
{
code = malloc(256);
xmlStrPrintf(code, 256, "%s-%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,
learn);
} else {
code = NULL;
}
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);
xmlFree(learn_code);
xmlFree(learn_event_code);
return code;
}
static void show_dmcode(xmlNodePtr node, struct opts *opts)
{
xmlChar *code;
code = get_dmcode(node, opts);
if (code) {
printf("%s", (char *) code);
}
xmlFree(code);
}
static int edit_dmcode(xmlNodePtr node, const char *val)
{
char model_ident_code[15];
char system_diff_code[5];
char system_code[4];
char sub_system_code[2];
char sub_sub_system_code[2];
char assy_code[5];
char disassy_code[3];
char disassy_code_variant[4];
char info_code[4];
char info_code_variant[2];
char item_location_code[2];
char learn_code[4];
char learn_event_code[2];
int n, offset;
offset = strncmp(val, "DMC-", 4) == 0 ? 4 : 0;
n = sscanf(val + offset, "%14[^-]-%4[^-]-%3[^-]-%1s%1s-%4[^-]-%2s%3[^-]-%3s%1s-%1s-%3s%1s",
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,
learn_code,
learn_event_code);
if (n != 11 && n != 13) {
return EXIT_INVALID_VALUE;
}
if (xmlStrcmp(node->name, BAD_CAST "dmCode") == 0) {
edit_simple_attr(node, "modelIdentCode", model_ident_code);
edit_simple_attr(node, "systemDiffCode", system_diff_code);
edit_simple_attr(node, "systemCode", system_code);
edit_simple_attr(node, "subSystemCode", sub_system_code);
edit_simple_attr(node, "subSubSystemCode", sub_sub_system_code);
edit_simple_attr(node, "assyCode", assy_code);
edit_simple_attr(node, "disassyCode", disassy_code);
edit_simple_attr(node, "disassyCodeVariant", disassy_code_variant);
edit_simple_attr(node, "infoCode", info_code);
edit_simple_attr(node, "infoCodeVariant", info_code_variant);
edit_simple_attr(node, "itemLocationCode", item_location_code);
if (n == 13) {
edit_simple_attr(node, "learnCode", learn_code);
edit_simple_attr(node, "learnEventCode", learn_event_code);
}
} else {
edit_simple_node(first_xpath_node_local(node, BAD_CAST "modelic"), model_ident_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "sdc"), system_diff_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "chapnum"), system_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "section"), sub_system_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "subsect"), sub_sub_system_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "subject"), assy_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "discode"), disassy_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "discodev"), disassy_code_variant);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "incode"), info_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "incodev"), info_code_variant);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "itemloc"), item_location_code);
}
return 0;
}
static xmlChar *get_ddncode(xmlNodePtr node, struct opts *opts)
{
xmlChar *modelic, *sendid, *recvid, *diyear, *seqnum, *code;
modelic = first_xpath_string(node, BAD_CAST "@modelIdentCode|modelic");
sendid = first_xpath_string(node, BAD_CAST "@senderIdent|sendid");
recvid = first_xpath_string(node, BAD_CAST "@receiverIdent|recvid");
diyear = first_xpath_string(node, BAD_CAST "@yearOfDataIssue|diyear");
seqnum = first_xpath_string(node, BAD_CAST "@seqNumber|seqnum");
if (modelic && sendid && recvid && diyear && seqnum) {
code = malloc(256);
xmlStrPrintf(code, 256, "%s-%s-%s-%s-%s",
modelic,
sendid,
recvid,
diyear,
seqnum);
} else {
code = NULL;
}
xmlFree(modelic);
xmlFree(sendid);
xmlFree(recvid);
xmlFree(diyear);
xmlFree(seqnum);
return code;
}
static void show_ddncode(xmlNodePtr node, struct opts *opts)
{
xmlChar *code = get_ddncode(node, opts);
if (code) printf("%s", (char *) code);
xmlFree(code);
}
static xmlChar *get_dmlcode(xmlNodePtr node, struct opts *opts)
{
xmlChar *modelic, *sendid, *dmltype, *diyear, *seqnum, *code;
modelic = first_xpath_string(node, BAD_CAST "@modelIdentCode|modelic");
sendid = first_xpath_string(node, BAD_CAST "@senderIdent|sendid");
dmltype = first_xpath_string(node, BAD_CAST "@dmlType|dmltype/@type");
diyear = first_xpath_string(node, BAD_CAST "@yearOfDataIssue|diyear");
seqnum = first_xpath_string(node, BAD_CAST "@seqNumber|seqnum");
if (modelic && sendid && dmltype && diyear && seqnum) {
code = malloc(256);
xmlStrPrintf(code, 256, "%s-%s-%s-%s-%s",
modelic,
sendid,
dmltype,
diyear,
seqnum);
} else {
code = NULL;
}
xmlFree(modelic);
xmlFree(sendid);
xmlFree(dmltype);
xmlFree(diyear);
xmlFree(seqnum);
return code;
}
static void show_dmlcode(xmlNodePtr node, struct opts *opts)
{
xmlChar *code = get_dmlcode(node, opts);
if (code) printf("%s", (char *) code);
xmlFree(code);
}
static xmlChar *get_pmcode(xmlNodePtr node, struct opts *opts)
{
xmlChar *modelic, *pmissuer, *pmnumber, *pmvolume, *code;
modelic = first_xpath_string(node, BAD_CAST "@modelIdentCode|modelic");
pmissuer = first_xpath_string(node, BAD_CAST "@pmIssuer|pmissuer");
pmnumber = first_xpath_string(node, BAD_CAST "@pmNumber|pmnumber");
pmvolume = first_xpath_string(node, BAD_CAST "@pmVolume|pmvolume");
if (modelic && pmissuer && pmnumber && pmvolume) {
code = malloc(256);
xmlStrPrintf(code, 256, "%s-%s-%s-%s",
modelic,
pmissuer,
pmnumber,
pmvolume);
} else {
code = NULL;
}
xmlFree(modelic);
xmlFree(pmissuer);
xmlFree(pmnumber);
xmlFree(pmvolume);
return code;
}
static void show_pmcode(xmlNodePtr node, struct opts *opts)
{
xmlChar *code = get_pmcode(node, opts);
if (code) printf("%s", (char *) code);
xmlFree(code);
}
static int edit_pmcode(xmlNodePtr node, const char *val)
{
char model_ident_code[15];
char pm_issuer[6];
char pm_number[6];
char pm_volume[3];
int n, offset;
offset = strncmp(val, "PMC-", 4) == 0 ? 4 : 0;
n = sscanf(val + offset, "%14[^-]-%5[^-]-%5[^-]-%2s",
model_ident_code,
pm_issuer,
pm_number,
pm_volume);
if (n != 4) {
return EXIT_INVALID_VALUE;
}
if (xmlStrcmp(node->name, BAD_CAST "pmCode") == 0) {
edit_simple_attr(node, "modelIdentCode", model_ident_code);
edit_simple_attr(node, "pmIssuer", pm_issuer);
edit_simple_attr(node, "pmNumber", pm_number);
edit_simple_attr(node, "pmVolume", pm_volume);
} else {
edit_simple_node(first_xpath_node_local(node, BAD_CAST "modelic"), model_ident_code);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "pmissuer"), pm_issuer);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "pmnumber"), pm_number);
edit_simple_node(first_xpath_node_local(node, BAD_CAST "pmvolume"), pm_volume);
}
return 0;
}
static void show_pm_issuer(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "pmissuer") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "pmIssuer", opts);
}
}
static int edit_pm_issuer(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "pmissuer") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "pmIssuer", val);
}
}
static void show_pm_number(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "pmnumber") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "pmNumber", opts);
}
}
static int edit_pm_number(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "pmnumber") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "pmNumber", val);
}
}
static void show_pm_volume(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "pmvolume") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "pmVolume", opts);
}
}
static int edit_pm_volume(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "pmvolume") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "pmVolume", val);
}
}
static xmlChar *get_comment_code(xmlNodePtr node, struct opts *opts)
{
xmlChar *model_ident_code;
xmlChar *sender_ident;
xmlChar *year_of_data_issue;
xmlChar *seq_number;
xmlChar *comment_type;
xmlChar *code;
if (xmlStrcmp(node->name, BAD_CAST "commentCode") == 0) {
model_ident_code = xmlGetProp(node, BAD_CAST "modelIdentCode");
sender_ident = xmlGetProp(node, BAD_CAST "senderIdent");
year_of_data_issue = xmlGetProp(node, BAD_CAST "yearOfDataIssue");
seq_number = xmlGetProp(node, BAD_CAST "seqNumber");
comment_type = xmlGetProp(node, BAD_CAST "commentType");
} else {
model_ident_code = first_xpath_string(node, BAD_CAST "modelic");
sender_ident = first_xpath_string(node, BAD_CAST "sendid");
year_of_data_issue = first_xpath_string(node, BAD_CAST "diyear");
seq_number = first_xpath_string(node, BAD_CAST "seqnum");
comment_type = first_xpath_string(node, BAD_CAST "ctype/@type");
}
if (model_ident_code && sender_ident && year_of_data_issue && seq_number && comment_type) {
code = malloc(256);
xmlStrPrintf(code, 256, "%s-%s-%s-%s-%s",
model_ident_code,
sender_ident,
year_of_data_issue,
seq_number,
comment_type);
} else {
code = NULL;
}
xmlFree(model_ident_code);
xmlFree(sender_ident);
xmlFree(year_of_data_issue);
xmlFree(seq_number);
xmlFree(comment_type);
return code;
}
static void show_comment_code(xmlNodePtr node, struct opts *opts)
{
xmlChar *code = get_comment_code(node, opts);
if (code) printf("%s", (char *) code);
xmlFree(code);
}
static xmlChar *get_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "dmCode") == 0 || xmlStrcmp(node->name, BAD_CAST "avee") == 0) {
return get_dmcode(node, opts);
} else if (xmlStrcmp(node->name, BAD_CAST "pmCode") == 0 || xmlStrcmp(node->name, BAD_CAST "pmc") == 0) {
return get_pmcode(node, opts);
} else if (xmlStrcmp(node->name, BAD_CAST "commentCode") == 0 || xmlStrcmp(node->name, BAD_CAST "ccode") == 0) {
return get_comment_code(node, opts);
} else if (xmlStrcmp(node->name, BAD_CAST "ddnCode") == 0 || xmlStrcmp(node->name, BAD_CAST "ddnc") == 0) {
return get_ddncode(node, opts);
} else if (xmlStrcmp(node->name, BAD_CAST "dmlCode") == 0 || xmlStrcmp(node->name, BAD_CAST "dmlc") == 0) {
return get_dmlcode(node, opts);
}
return NULL;
}
static void show_code(xmlNodePtr node, struct opts *opts)
{
xmlChar *code = get_code(node, opts);
if (code) printf("%s", (char *) code);
xmlFree(code);
}
static int edit_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "dmCode") == 0 || xmlStrcmp(node->name, BAD_CAST "avee") == 0) {
return edit_dmcode(node, val);
} else if (xmlStrcmp(node->name, BAD_CAST "pmCode") == 0 || xmlStrcmp(node->name, BAD_CAST "pmc") == 0) {
return edit_pmcode(node, val);
} else {
return EXIT_NO_EDIT;
}
}
static void show_issue_type(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "issno") == 0) {
show_simple_attr(node, "type", opts);
} else {
show_simple_attr(node, "issueType", opts);
}
}
static int edit_issue_type(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "issno") == 0) {
return edit_simple_attr(node, "type", val);
} else {
return edit_simple_attr(node, "issueType", val);
}
}
static void show_language_iso_code(xmlNodePtr node, struct opts *opts)
{
if (xmlHasProp(node, BAD_CAST "languageIsoCode")) {
show_simple_attr(node, "languageIsoCode", opts);
} else {
show_simple_attr(node, "language", opts);
}
}
static int edit_language_iso_code(xmlNodePtr node, const char *val)
{
if (xmlHasProp(node, BAD_CAST "languageIsoCode")) {
return edit_simple_attr(node, "languageIsoCode", val);
} else {
return edit_simple_attr(node, "language", val);
}
}
static void show_country_iso_code(xmlNodePtr node, struct opts *opts)
{
if (xmlHasProp(node, BAD_CAST "countryIsoCode")) {
show_simple_attr(node, "countryIsoCode", opts);
} else {
show_simple_attr(node, "country", opts);
}
}
static int edit_country_iso_code(xmlNodePtr node, const char *val)
{
if (xmlHasProp(node, BAD_CAST "countryIsoCode")) {
return edit_simple_attr(node, "countryIsoCode", val);
} else {
return edit_simple_attr(node, "country", val);
}
}
static void show_issue_number(xmlNodePtr node, struct opts *opts)
{
if (xmlHasProp(node, BAD_CAST "issueNumber")) {
show_simple_attr(node, "issueNumber", opts);
} else {
show_simple_attr(node, "issno", opts);
}
}
static int edit_issue_number(xmlNodePtr node, const char *val)
{
return edit_simple_attr(node, "issueNumber", val);
}
static void show_in_work(xmlNodePtr node, struct opts *opts)
{
if (xmlHasProp(node, BAD_CAST "inWork")) {
show_simple_attr(node, "inWork", opts);
} else if (xmlHasProp(node, BAD_CAST "inwork")) {
show_simple_attr(node, "inwork", opts);
} else {
printf("00");
}
}
static int edit_in_work(xmlNodePtr node, const char *val)
{
return edit_simple_attr(node, "inWork", val);
}
static xmlChar *get_issue_info(xmlNodePtr node, struct opts *opts)
{
xmlChar *i, *w;
i = first_xpath_string(node, BAD_CAST "@issueNumber|@issno");
w = first_xpath_string(node, BAD_CAST "@inWork|@inwork");
i = xmlStrcat(i, BAD_CAST "-");
i = xmlStrcat(i, w ? w : BAD_CAST "00");
xmlFree(w);
return i;
}
static void show_issue_info(xmlNodePtr node, struct opts *opts)
{
xmlChar *s;
s = get_issue_info(node, opts);
if (s) {
printf("%s", (char *) s);
}
xmlFree(s);
}
static int create_act_ref(xmlXPathContextPtr ctxt, const char *val)
{
xmlNodePtr node;
node = first_xpath_node("//dmStatus/originator", ctxt);
node = xmlAddNextSibling(node, xmlNewNode(NULL, BAD_CAST "applicCrossRefTableRef"));
node = xmlNewChild(node, NULL, BAD_CAST "dmRef", NULL);
node = xmlNewChild(node, NULL, BAD_CAST "dmRefIdent", NULL);
node = xmlNewChild(node, NULL, BAD_CAST "dmCode", NULL);
return edit_dmcode(node, val);
}
static int create_comment_title(xmlXPathContextPtr ctxt, const char *val)
{
xmlNodePtr node;
node = first_xpath_node("//commentAddressItems/issueDate", ctxt);
if (!node) return EXIT_INVALID_CREATE;
node = xmlAddNextSibling(node, xmlNewNode(NULL, BAD_CAST "commentTitle"));
return edit_simple_node(node, val);
}
static void show_comment_priority(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "priority") == 0) {
show_simple_attr(node, "cprio", opts);
} else {
show_simple_attr(node, "commentPriorityCode", opts);
}
}
static int edit_comment_priority(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "priority") == 0) {
return edit_simple_attr(node, "cprio", val);
} else {
return edit_simple_attr(node, "commentPriorityCode", val);
}
}
static void show_comment_response(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "response") == 0) {
show_simple_attr(node, "rsptype", opts);
} else {
show_simple_attr(node, "responseType", opts);
}
}
static int edit_comment_response(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "response") == 0) {
return edit_simple_attr(node, "rsptype", val);
} else {
return edit_simple_attr(node, "responseType", val);
}
}
static int create_ent_name(xmlNodePtr node, const char *val)
{
return xmlNewChild(node, NULL, BAD_CAST "enterpriseName", BAD_CAST val) == NULL;
}
static int create_rpc_name(xmlXPathContextPtr ctxt, const char *val)
{
xmlNodePtr node;
node = first_xpath_node("//responsiblePartnerCompany|//rpc", ctxt);
if (!node) {
return EXIT_INVALID_CREATE;
} else if (xmlStrcmp(node->name, BAD_CAST "rpc") == 0) {
return edit_simple_attr(node, "rpcname", val);
} else {
return create_ent_name(node, val);
}
}
static int create_orig_name(xmlXPathContextPtr ctxt, const char *val)
{
xmlNodePtr node;
node = first_xpath_node("//originator|//orig", ctxt);
if (!node) {
return EXIT_INVALID_CREATE;
} else if (xmlStrcmp(node->name, BAD_CAST "orig") == 0) {
return edit_simple_attr(node, "origname", val);
} else {
return create_ent_name(node, val);
}
}
static void show_url(xmlNodePtr node, struct opts *opts)
{
printf("%s", node->doc->URL);
}
static void show_title(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "dmTitle") == 0 || xmlStrcmp(node->name, BAD_CAST "dmtitle") == 0) {
xmlNodePtr tech, info, vari;
xmlChar *tech_content;
tech = first_xpath_node_local(node, BAD_CAST "techName|techname");
info = first_xpath_node_local(node, BAD_CAST "infoName|infoname");
vari = first_xpath_node_local(node, BAD_CAST "infoNameVariant");
tech_content = xmlNodeGetContent(tech);
printf("%s", (char *) tech_content);
xmlFree(tech_content);
if (info) {
xmlChar *info_content;
info_content = xmlNodeGetContent(info);
printf(" - %s", info_content);
xmlFree(info_content);
if (vari) {
xmlChar *vari_content;
vari_content = xmlNodeGetContent(vari);
printf(", %s", vari_content);
xmlFree(vari_content);
}
}
} else {
show_simple_node(node, opts);
}
}
static void show_model_ident_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "modelic") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "modelIdentCode", opts);
}
}
static int edit_model_ident_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "modelic") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "modelIdentCode", val);
}
}
static void show_system_diff_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "sdc") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "systemDiffCode", opts);
}
}
static int edit_system_diff_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "sdc") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "systemDiffCode", val);
}
}
static void show_system_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "chapnum") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "systemCode", opts);
}
}
static int edit_system_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "chapnum") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "systemCode", val);
}
}
static void show_sub_system_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "section") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "subSystemCode", opts);
}
}
static int edit_sub_system_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "section") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "subSystemCode", val);
}
}
static void show_sub_sub_system_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "subsect") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "subSubSystemCode", opts);
}
}
static int edit_sub_sub_system_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "subsect") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "subSubSystemCode", val);
}
}
static void show_assy_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "subject") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "assyCode", opts);
}
}
static int edit_assy_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "subject") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "assyCode", val);
}
}
static void show_disassy_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "discode") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "disassyCode", opts);
}
}
static int edit_disassy_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "discode") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "disassyCode", val);
}
}
static void show_disassy_code_variant(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "discodev") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "disassyCodeVariant", opts);
}
}
static int edit_disassy_code_variant(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "discodev") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "disassyCodeVariant", val);
}
}
static void show_info_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "incode") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "infoCode", opts);
}
}
static int edit_info_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "incode") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "infoCode", val);
}
}
static void show_info_code_variant(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "incodev") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "infoCodeVariant", opts);
}
}
static int edit_info_code_variant(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "incodev") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "infoCodeVariant", val);
}
}
static void show_item_location_code(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "itemloc") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "itemLocationCode", opts);
}
}
static int edit_item_location_code(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "itemloc") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "itemLocationCode", val);
}
}
static void show_learn_code(xmlNodePtr node, struct opts *opts)
{
show_simple_attr(node, "learnCode", opts);
}
static int edit_learn_code(xmlNodePtr node, const char *val)
{
return edit_simple_attr(node, "learnCode", val);
}
static void show_learn_event_code(xmlNodePtr node, struct opts *opts)
{
show_simple_attr(node, "learnEventCode", opts);
}
static int edit_learn_event_code(xmlNodePtr node, const char *val)
{
return edit_simple_attr(node, "learnEventCode", val);
}
static void show_skill_level(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "skill") == 0) {
show_simple_attr(node, "skill", opts);
} else {
show_simple_attr(node, "skillLevelCode", opts);
}
}
static int edit_skill_level(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "skill") == 0) {
return edit_simple_attr(node, "skill", val);
} else {
return edit_simple_attr(node, "skillLevelCode", val);
}
}
static int create_skill_level(xmlXPathContextPtr ctx, const char *val)
{
xmlNodePtr node, skill_level;
int iss30;
node = first_xpath_node(
"(//qualityAssurance|//qa|"
"//systemBreakdownCode|//sbc|"
"//functionalItemCode|//fic|"
"//dmStatus/functionalItemRef|//status/ein"
")[last()]", ctx);
iss30 = xmlStrcmp(node->parent->name, BAD_CAST "status") == 0;
skill_level = xmlNewNode(NULL, BAD_CAST (iss30 ? "skill" : "skillLevel"));
xmlAddNextSibling(node, skill_level);
xmlSetProp(skill_level, BAD_CAST (iss30 ? "skill" : "skillLevelCode"), BAD_CAST val);
return 0;
}
static void show_comment_type(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "ctype") == 0) {
show_simple_attr(node, "type", opts);
} else {
show_simple_attr(node, "commentType", opts);
}
}
static int edit_comment_type(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "ctype") == 0) {
return edit_simple_attr(node, "type", val);
} else {
return edit_simple_attr(node, "commentType", val);
}
}
static void show_seq_number(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "seqnum") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "seqNumber", opts);
}
}
static int edit_seq_number(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "seqnum") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "seqNumber", val);
}
}
static void show_year_of_data_issue(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "diyear") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "yearOfDataIssue", opts);
}
}
static int edit_year_of_data_issue(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "diyear") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "yearOfDataIssue", val);
}
}
static void show_sender_ident(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "sendid") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "senderIdent", opts);
}
}
static int edit_sender_ident(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "sendid") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "senderIdent", val);
}
}
static void show_receiver_ident(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "recvid") == 0) {
show_simple_node(node, opts);
} else {
show_simple_attr(node, "receiverIdent", opts);
}
}
static int edit_receiver_ident(xmlNodePtr node, const char *val)
{
if (xmlStrcmp(node->name, BAD_CAST "recvid") == 0) {
return edit_simple_node(node, val);
} else {
return edit_simple_attr(node, "receiverIdent", val);
}
}
static void show_source(xmlNodePtr node, struct opts *opts)
{
xmlNodePtr dmc, issno, lang;
dmc = first_xpath_node_local(node, BAD_CAST "dmCode|pmCode|dmc/avee");
issno = first_xpath_node_local(node, BAD_CAST "issueInfo|issno");
lang = first_xpath_node_local(node, BAD_CAST "language");
if (xmlStrcmp(dmc->name, BAD_CAST "pmCode") == 0) {
printf("PMC-");
show_pmcode(dmc, opts);
} else {
printf("DMC-");
show_dmcode(dmc, opts);
}
putchar('_');
show_issue_number(issno, opts);
putchar('-');
show_in_work(issno, opts);
putchar('_');
show_language_iso_code(lang, opts);
putchar('-');
show_country_iso_code(lang, opts);
}
static xmlChar *get_qa(xmlNodePtr node, struct opts *opts)
{
xmlNodePtr first, sec;
first = first_xpath_node_local(node, BAD_CAST "firstVerification|firstver");
sec = first_xpath_node_local(node, BAD_CAST "secondVerification|secver");
if (sec) {
return xmlStrdup(BAD_CAST "secondVerification");
}
if (first) {
return xmlStrdup(BAD_CAST "firstVerification");
}
return xmlStrdup(BAD_CAST "unverified");
}
static void show_qa(xmlNodePtr node, struct opts *opts)
{
xmlChar *qa;
qa = get_qa(node, opts);
if (qa) {
printf("%s", (char *) qa);
}
xmlFree(qa);
}
static void show_verification_type(xmlNodePtr node, struct opts *opts)
{
if (xmlStrcmp(node->name, BAD_CAST "firstVerification") == 0 ||
xmlStrcmp(node->name, BAD_CAST "secondVerification") == 0)
{
show_simple_attr(node, "verificationType", opts);
} else {
show_simple_attr(node, "type", opts);
}
}
static int edit_first_verification_type(xmlNodePtr node, const char *val)
{
if (strcmp(val, "unverified") == 0) {
xmlNodePtr qa, cur;
qa = node->parent;
cur = qa->children;
while (cur) {
xmlNodePtr next;
next = cur->next;
xmlUnlinkNode(cur);
xmlFreeNode(cur);
cur = next;
}
if (xmlStrcmp(node->name, BAD_CAST "firstVerification") == 0) {
xmlNewChild(qa, qa->ns, BAD_CAST "unverified", NULL);
} else {
xmlNewChild(qa, qa->ns, BAD_CAST "unverif", NULL);
}
return 0;
}
if (xmlStrcmp(node->name, BAD_CAST "firstVerification") == 0) {
return edit_simple_attr(node, "verificationType", val);
} else {
return edit_simple_attr(node, "type", val);
}
}
static int edit_second_verification_type(xmlNodePtr node, const char *val)
{
if (strcmp(val, "unverified") == 0) {
xmlUnlinkNode(node);
xmlFreeNode(node);
return 0;
}
if (xmlStrcmp(node->name, BAD_CAST "secondVerification") == 0) {
return edit_simple_attr(node, "verificationType", val);
} else {
return edit_simple_attr(node, "type", val);
}
}
static int create_first_verification(xmlXPathContextPtr ctx, const char *val)
{
xmlNodePtr unverif, first;
if (!(strcmp(val, "tabtop") == 0 || strcmp(val, "onobject") == 0 || strcmp(val, "ttandoo") == 0)) {
return 0;
}
if (!(unverif = first_xpath_node("//unverified|//unverif", ctx))) {
return EXIT_INVALID_CREATE;
}
if (xmlStrcmp(unverif->name, BAD_CAST "unverified") == 0) {
first = xmlNewNode(unverif->ns, BAD_CAST "firstVerification");
xmlSetProp(first, BAD_CAST "verificationType", BAD_CAST val);
} else {
first = xmlNewNode(unverif->ns, BAD_CAST "firstver");
xmlSetProp(first, BAD_CAST "type", BAD_CAST val);
}
xmlAddNextSibling(unverif, first);
xmlUnlinkNode(unverif);
xmlFreeNode(unverif);
return 0;
}
static int create_second_verification(xmlXPathContextPtr ctx, const char *val)
{
xmlNodePtr first, sec;
if (!(strcmp(val, "tabtop") == 0 || strcmp(val, "onobject") == 0 || strcmp(val, "ttandoo") == 0)) {
return 0;
}
if (!(first = first_xpath_node("//firstVerification|//firstver", ctx))) {
return EXIT_INVALID_CREATE;
}
if (xmlStrcmp(first->name, BAD_CAST "firstVerification") == 0) {
sec = xmlNewNode(first->ns, BAD_CAST "secondVerification");
xmlSetProp(sec, BAD_CAST "verificationType", BAD_CAST val);
} else {
sec = xmlNewNode(first->ns, BAD_CAST "secver");
xmlSetProp(sec, BAD_CAST "type", BAD_CAST val);
}
xmlAddNextSibling(first, sec);
return 0;
}
static xmlChar *get_remarks_or_rfu(xmlNodePtr node, struct opts *opts)
{
return xmlNodeGetContent(first_xpath_node_local(node, BAD_CAST "simplePara|p"));
}
static void show_remarks_or_rfu(xmlNodePtr node, struct opts *opts)
{
xmlChar *s = get_remarks_or_rfu(node, opts);
if (s) {
printf("%s", (char *) s);
}
xmlFree(s);
}
static int edit_remarks_or_rfu(xmlNodePtr node, const char *val)
{
xmlNodePtr p = first_xpath_node_local(node, BAD_CAST "simplePara|p");
return edit_simple_node(p, val);
}
static int create_remarks(xmlXPathContextPtr ctx, const char *val)
{
xmlNodePtr node, remarks;
bool iss30;
node = first_xpath_node(
"("
"//dmStatus/*|//status/*|"
"//pmStatus/*|//pmstatus/*|"
"//commentStatus/*|"
"//ddnStatus/*|"
"//dmlStatus/*|"
"//scormContentPackageStatus/*"
")[last()]", ctx);
if (!node) {
return EXIT_INVALID_CREATE;
}
iss30 = xmlStrcmp(node->parent->name, BAD_CAST "status") == 0 || xmlStrcmp(node->parent->name, BAD_CAST "pmstatus") == 0;
remarks = xmlNewNode(NULL, BAD_CAST "remarks");
xmlAddNextSibling(node, remarks);
xmlNewTextChild(remarks, NULL, BAD_CAST (iss30 ? "p" : "simplePara"), BAD_CAST val);
return 0;
}
static int create_rfu(xmlXPathContextPtr ctx, const char *val)
{
xmlNodePtr node, rfu;
bool iss30;
node = first_xpath_node(
"("
"//dmStatus/*|//status/*|"
"//pmStatus/*|//pmstatus/*|"
"//commentStatus/*|"
"//ddnStatus/*|"
"//dmlStatus/*|"
"//scormContentPackageStatus/*"
")[not(self::productSafety or self::remarks)][last()]", ctx);
if (!node) {
return EXIT_INVALID_CREATE;
}
iss30 = xmlStrcmp(node->parent->name, BAD_CAST "status") == 0 || xmlStrcmp(node->parent->name, BAD_CAST "pmstatus") == 0;
rfu = xmlNewNode(NULL, BAD_CAST (iss30 ? "rfu" : "reasonForUpdate"));
xmlAddNextSibling(node, rfu);
xmlNewTextChild(rfu, NULL, BAD_CAST (iss30 ? "p" : "simplePara"), BAD_CAST val);
return 0;
}
static struct metadata metadata[] = {
{"act",
"//applicCrossRefTableRef/dmRef/dmRefIdent/dmCode",
get_dmcode,
show_dmcode,
edit_dmcode,
create_act_ref,
"ACT data module code"},
{"applic",
"//applic/displayText/simplePara|//applic/displaytext/p",
NULL,
show_simple_node,
edit_simple_node,
NULL,
"Whole data module applicability"},
{"assyCode",
"//@assyCode|//avee/subject",
NULL,
show_assy_code,
edit_assy_code,
NULL,
"Assembly code"},
{"authorization",
"//authorization|//authrtn",
NULL,
show_simple_node,
edit_simple_node,
NULL,
"Authorization for a DDN"},
{"brex",
"//brexDmRef/dmRef/dmRefIdent/dmCode|//brexref/refdm/avee",
get_dmcode,
show_dmcode,
edit_dmcode,
NULL,
"BREX data module code"},
{"code",
"//dmCode|//avee|//pmCode|//pmc|//commentCode|//ccode|//ddnCode|//ddnc|//dmlCode|//dmlc",
get_code,
show_code,
edit_code,
NULL,
"CSDB object code"},
{"commentCode",
"//commentCode|//ccode",
get_comment_code,
show_comment_code,
NULL,
NULL,
"Comment code"},
{"commentPriority",
"//commentPriority/@commentPriorityCode|//priority/@cprio",
NULL,
show_comment_priority,
edit_comment_priority,
NULL,
"Priority code of a comment"},
{"commentResponse",
"//commentResponse/@responseType|//response/@rsptype",
NULL,
show_comment_response,
edit_comment_response,
NULL,
"Response type of a comment"},
{"commentTitle",
"//commentTitle|//ctitle",
NULL,
show_simple_node,
edit_simple_node,
create_comment_title,
"Title of a comment"},
{"commentType",
"//@commentType|//ctype/@type",
NULL,
show_comment_type,
edit_comment_type,
NULL,
"Type of a comment"},
{"countryIsoCode",
"//language/@countryIsoCode|//language/@country",
NULL,
show_country_iso_code,
edit_country_iso_code,
NULL,
"Country ISO code (CA, US, GB...)"},
{"ddnCode",
"//ddnCode|//ddnc",
get_ddncode,
show_ddncode,
NULL,
NULL,
"Data dispatch note code"},
{"disassyCode",
"//@disassyCode|//discode",
NULL,
show_disassy_code,
edit_disassy_code,
NULL,
"Disassembly code"},
{"disassyCodeVariant",
"//@disassyCodeVariant|//discodev",
NULL,
show_disassy_code_variant,
edit_disassy_code_variant,
NULL,
"Disassembly code variant"},
{"dmCode",
"//dmCode|//avee",
get_dmcode,
show_dmcode,
edit_dmcode,
NULL,
"Data module code"},
{"dmlCode",
"//dmlCode|//dmlc",
get_dmlcode,
show_dmlcode,
NULL,
NULL,
"Data management list code"},
{"firstVerificationType",
"//firstVerification/@verificationType|//firstver/@type",
NULL,
show_verification_type,
edit_first_verification_type,
create_first_verification,
"First verification type"},
{"format",
"false()",
NULL,
NULL,
NULL,
NULL,
"File format of the object"},
{"icnTitle",
"//imfAddressItems/icnTitle",
NULL,
show_simple_node,
edit_simple_node,
NULL,
"Title of an IMF"},
{"infoCode",
"//@infoCode|//incode",
NULL,
show_info_code,
edit_info_code,
NULL,
"Information code"},
{"infoCodeVariant",
"//@infoCodeVariant|//incodev",
NULL,
show_info_code_variant,
edit_info_code_variant,
NULL,
"Information code variant"},
{"infoName",
"//infoName|//infoname",
NULL,
show_simple_node,
edit_info_name,
create_info_name,
"Information name of a data module"},
{"infoNameVariant",
"//infoNameVariant",
NULL,
show_simple_node,
edit_info_name,
create_info_name_variant,
"Information name variant of a data module"},
{"inWork",
"//issueInfo/@inWork|//issno",
NULL,
show_in_work,
edit_in_work,
NULL,
"Inwork issue number (NN)"},
{"issue",
"//*",
get_issue,
show_issue,
edit_issue,
NULL,
"Issue of S1000D"},
{"issueDate",
"//issueDate|//issdate",
get_issue_date,
show_issue_date,
edit_issue_date,
NULL,
"Issue date of the CSDB object"},
{"issueInfo",
"//issueInfo|//issno",
get_issue_info,
show_issue_info,
NULL,
NULL,
"Issue info (NNN-NN)"},
{"issueNumber",
"//issueInfo/@issueNumber|//issno/@issno",
NULL,
show_issue_number,
edit_issue_number,
NULL,
"Issue number (NNN)"},
{"issueType",
"//dmStatus/@issueType|//pmStatus/@issueType|//issno/@type",
NULL,
show_issue_type,
edit_issue_type,
NULL,
"Issue type (new, changed, deleted...)"},
{"itemLocationCode",
"//@itemLocationCode|//itemloc",
NULL,
show_item_location_code,
edit_item_location_code,
NULL,
"Item location code"},
{"languageIsoCode",
"//language/@languageIsoCode|//language/@language",
NULL,
show_language_iso_code,
edit_language_iso_code,
NULL,
"Language ISO code (en, fr, es...)"},
{"learnCode",
"//@learnCode",
NULL,
show_learn_code,
edit_learn_code,
NULL,
"Learn code"},
{"learnEventCode",
"//@learnEventCode",
NULL,
show_learn_event_code,
edit_learn_event_code,
NULL,
"Learn event code"},
{"modelIdentCode",
"//@modelIdentCode|//modelic",
NULL,
show_model_ident_code,
edit_model_ident_code,
NULL,
"Model identification code"},
{"modified",
"false()",
NULL,
NULL,
NULL,
NULL,
"File modification time"},
{"originator",
"//originator/enterpriseName|//orig/@origname",
NULL,
show_orig_name,
edit_orig_name,
create_orig_name,
"Name of the originator"},
{"originatorCode",
"//originator/@enterpriseCode|//orig[. != '']",
NULL,
show_ent_code,
edit_ent_code,
create_orig_ent_code,
"NCAGE code of the originator"},
{"path",
"false()",
NULL,
NULL,
NULL,
NULL,
"Filesystem path of object"},
{"pmCode",
"//pmCode|//pmc",
get_pmcode,
show_pmcode,
edit_pmcode,
NULL,
"Publication module code"},
{"pmIssuer",
"//@pmIssuer|//pmissuer",
NULL,
show_pm_issuer,
edit_pm_issuer,
NULL,
"Issuing authority of the PM"},
{"pmNumber",
"//@pmNumber|//pmnumber",
NULL,
show_pm_number,
edit_pm_number,
NULL,
"PM number"},
{"pmTitle",
"//pmTitle|//pmtitle",
NULL,
show_simple_node,
edit_simple_node,
NULL,
"Title of a publication module"},
{"pmVolume",
"//@pmVolume|//pmvolume",
NULL,
show_pm_volume,
edit_pm_volume,
NULL,
"Volume of the PM"},
{"qualityAssurance",
"//qualityAssurance|//qa",
get_qa,
show_qa,
NULL,
NULL,
"Quality assurance status"},
{"reasonForUpdate",
"//reasonForUpdate|//rfu",
get_remarks_or_rfu,
show_remarks_or_rfu,
edit_remarks_or_rfu,
create_rfu,
"Reason for update"},
{"receiverIdent",
"//@receiverIdent|//recvid",
NULL,
show_receiver_ident,
edit_receiver_ident,
NULL,
"Receiving authority"},
{"remarks",
"//dmStatus/remarks|//status/remarks|//pmStatus/remarks|//pmstatus/remarks|//commentStatus/remarks|//dmlStatus/remarks|//ddnStatus/remarks|//scormContentPackageStatus/remarks|//imfStatus/remarks",
get_remarks_or_rfu,
show_remarks_or_rfu,
edit_remarks_or_rfu,
create_remarks,
"General remarks"},
{"responsiblePartnerCompany",
"//responsiblePartnerCompany/enterpriseName|//rpc/@rpcname",
NULL,
show_rpc_name,
edit_rpc_name,
create_rpc_name,
"Name of the RPC"},
{"responsiblePartnerCompanyCode",
"//responsiblePartnerCompany/@enterpriseCode|//rpc[. != '']",
NULL,
show_ent_code,
edit_ent_code,
create_rpc_ent_code,
"NCAGE code of the RPC"},
{"schema",
"/*",
get_schema,
show_schema,
NULL,
NULL,
"S1000D schema name"},
{"schemaUrl",
"/*",
NULL,
show_schema_url,
edit_schema_url,
NULL,
"XML schema URL"},
{"secondVerificationType",
"//secondVerification/@verificationType|//secver/@type",
NULL,
show_verification_type,
edit_second_verification_type,
create_second_verification,
"Second verification type"},
{"securityClassification",
"//security/@securityClassification|//security/@class",
NULL,
show_sec_class,
edit_sec_class,
NULL,
"Security classification (01, 02...)"},
{"senderIdent",
"//@senderIdent|//sendid",
NULL,
show_sender_ident,
edit_sender_ident,
NULL,
"Issuing authority"},
{"seqNumber",
"//@seqNumber|//seqnum",
NULL,
show_seq_number,
edit_seq_number,
NULL,
"Sequence number"},
{"shortPmTitle",
"//shortPmTitle",
NULL,
show_simple_node,
edit_simple_node,
NULL,
"Short title of a publication module"},
{"skillLevelCode",
"//dmStatus/skillLevel/@skillLevelCode|//status/skill/@skill",
NULL,
show_skill_level,
edit_skill_level,
create_skill_level,
"Skill level code of the data module"},
{"source",
"//sourceDmIdent|//sourcePmIdent|//srcdmaddres",
NULL,
show_source,
NULL,
NULL,
"Full source DM or PM identification"},
{"sourceDmCode",
"//sourceDmIdent/dmCode|//srcdmaddres/dmc/avee",
get_dmcode,
show_dmcode,
edit_dmcode,
NULL,
"Source DM code"},
{"sourcePmCode",
"//sourcePmIdent/pmCode",
get_pmcode,
show_pmcode,
edit_pmcode,
NULL,
"Source PM code"},
{"sourceIssueNumber",
"//sourceDmIdent/issueInfo/@issueNumber|//sourcePmIdent/issueInfo/@issueNumber|//srcdmaddres/issno/@issno",
NULL,
show_issue_number,
edit_issue_number,
NULL,
"Source DM or PM issue number"},
{"sourceInWork",
"//sourceDmIdent/issueInfo/@inWork|//sourcePmIdent/issueInfo/@inWork|//srcdmaddres/issno",
NULL,
show_in_work,
edit_in_work,
NULL,
"Source DM or PM inwork issue number"},
{"sourceLanguageIsoCode",
"//sourceDmIdent/language/@languageIsoCode|//sourcePmIdent/language/@languageIsoCode|//srcdmaddres/language/@language",
NULL,
show_language_iso_code,
edit_language_iso_code,
NULL,
"Source DM or PM language ISO code"},
{"sourceCountryIsoCode",
"//sourceDmIdent/language/@countryIsoCode|//sourcePmIdent/language/@countryIsoCode|//srcdmaddres/language/@country",
NULL,
show_country_iso_code,
edit_country_iso_code,
NULL,
"Source DM or PM country ISO code"},
{"subSubSystemCode",
"//@subSubSystemCode|//subsect",
NULL,
show_sub_sub_system_code,
edit_sub_sub_system_code,
NULL,
"Subsubsystem code"},
{"subSystemCode",
"//@subSystemCode|//section",
NULL,
show_sub_system_code,
edit_sub_system_code,
NULL,
"Subsystem code"},
{"systemCode",
"//@systemCode|//chapnum",
NULL,
show_system_code,
edit_system_code,
NULL,
"System code"},
{"systemDiffCode",
"//@systemDiffCode|//sdc",
NULL,
show_system_diff_code,
edit_system_diff_code,
NULL,
"System difference code"},
{"techName",
"//techName|//techname",
NULL,
show_simple_node,
edit_simple_node,
NULL,
"Technical name of a data module"},
{"title",
"//dmTitle|//dmtitle|//pmTitle|//pmtitle|//commentTitle|//ctitle|//icnTitle",
NULL,
show_title,
NULL,
NULL,
"Title of a CSDB object"},
{"type",
"/*",
NULL,
show_type,
NULL,
NULL,
"Name of the root element of the document"},
{"url",
"/",
NULL,
show_url,
NULL,
NULL,
"URL of the document"},
{"yearOfDataIssue",
"//@yearOfDataIssue|//diyear",
NULL,
show_year_of_data_issue,
edit_year_of_data_issue,
NULL,
"Year of data issue"},
{NULL}
};
static xmlChar *get_icn_code(const char *bname, struct opts *opts)
{
int n;
n = strchr(bname, '.') - bname;
return xmlCharStrndup(bname, n);
}
static void show_icn_code(const char *bname, struct opts *opts)
{
xmlChar *s;
s = get_icn_code(bname, opts);
printf("%s", (char *) s);
free(s);
}
static xmlChar *get_icn_sec(const char *bname, struct opts *opts)
{
char *s, *e;
int n;
s = strrchr(bname, '-');
++s;
e = strchr(s, '.');
n = e - s;
return xmlCharStrndup(s, n);
}
static void show_icn_sec(const char *bname, struct opts *opts)
{
xmlChar *s;
s = get_icn_sec(bname, opts);
printf("%s", (char *) s);
free(s);
}
static xmlChar *get_icn_iss(const char *bname, struct opts *opts)
{
char *s, *e;
int n;
s = strrchr(bname, '-');
s = s - 3;
e = strchr(s, '-');
n = e - s;
return xmlCharStrndup(s, n);
}
static void show_icn_iss(const char *bname, struct opts *opts)
{
xmlChar *s;
s = get_icn_iss(bname, opts);
printf("%s", (char *) s);
free(s);
}
static xmlChar *get_icn_type(const char *bname, struct opts *opts)
{
return xmlCharStrdup("icn");
}
static void show_icn_type(const char *bname, struct opts *opts)
{
printf("icn");
}
static struct icn_metadata icn_metadata[] = {
{"code", get_icn_code, show_icn_code},
{"issueNumber", get_icn_iss, show_icn_iss},
{"securityClassification", get_icn_sec, show_icn_sec},
{"type", get_icn_type, show_icn_type},
{NULL}
};
static int show_metadata(xmlXPathContextPtr ctxt, const char *key, struct opts *opts)
{
int i;
for (i = 0; metadata[i].key; ++i) {
if (strcmp(key, metadata[i].key) == 0) {
xmlNodePtr node;
if (!(node = first_xpath_node(metadata[i].path, ctxt))) {
if (opts->endl > -1) putchar(opts->endl);
return EXIT_MISSING_METADATA;
}
if (node->type == XML_ATTRIBUTE_NODE) node = node->parent;
metadata[i].show(node, opts);
return EXIT_SUCCESS;
}
}
if (opts->endl > -1) putchar(opts->endl);
return EXIT_INVALID_METADATA;
}
static int edit_metadata(xmlXPathContextPtr ctxt, const char *key, const char *val)
{
int i;
for (i = 0; metadata[i].key; ++i) {
if (strcmp(key, metadata[i].key) == 0) {
xmlNodePtr node;
if (!(node = first_xpath_node(metadata[i].path, ctxt))) {
if (metadata[i].create) {
return metadata[i].create(ctxt, val);
} else {
return EXIT_NO_EDIT;
}
} else {
if (node->type == XML_ATTRIBUTE_NODE) node = node->parent;
if (metadata[i].edit) {
return metadata[i].edit(node, val);
} else {
return EXIT_NO_EDIT;
}
}
}
}
return EXIT_INVALID_METADATA;
}
static int show_all_metadata(xmlXPathContextPtr ctxt, struct opts *opts)
{
int i;
for (i = 0; metadata[i].key; ++i) {
xmlNodePtr node;
if (opts->only_editable && !metadata[i].edit) continue;
if ((node = first_xpath_node(metadata[i].path, ctxt))) {
if (node->type == XML_ATTRIBUTE_NODE) node = node->parent;
if (opts->endl == '\n') {
printf("%s", metadata[i].key);
if (opts->format_all) {
int n = KEY_COLUMN_WIDTH - strlen(metadata[i].key);
int j;
for (j = 0; j < n; ++j) putchar(' ');
} else {
putchar('\t');
}
}
metadata[i].show(node, opts);
if (opts->endl > -1) putchar(opts->endl);
}
}
return 0;
}
static int edit_all_metadata(FILE *input, xmlXPathContextPtr ctxt)
{
char key[256], val[256];
while (fscanf(input, "%255s %255[^\n]", key, val) == 2) {
edit_metadata(ctxt, key, val);
}
return 0;
}
static void list_metadata_key(const char *key, const char *descr, struct opts *opts)
{
int n = KEY_COLUMN_WIDTH - strlen(key);
printf("%s", key);
if (opts->format_all) {
int j;
for (j = 0; j < n; ++j) putchar(' ');
} else {
putchar('\t');
}
printf("%s", descr);
putchar('\n');
}
static int has_key(xmlNodePtr keys, const char *key)
{
if (keys->children) {
xmlNodePtr cur;
for (cur = keys->children; cur; cur = cur->next) {
xmlChar *name;
int match;
name = xmlGetProp(cur, BAD_CAST "name");
match = xmlStrcmp(name, BAD_CAST key) == 0;
xmlFree(name);
if (match) return 1;
}
return 0;
}
return 1;
}
static void list_metadata_keys(struct opts *opts)
{
int i;
for (i = 0; metadata[i].key; ++i) {
if (has_key(opts->keys, metadata[i].key) && (!opts->only_editable || metadata[i].edit)) {
list_metadata_key(metadata[i].key, metadata[i].descr, opts);
}
}
}
static int show_err(int err, const char *key, const char *val, const char *fname, struct opts *opts)
{
if (opts->verbosity < NORMAL) return err;
switch (err) {
case EXIT_INVALID_METADATA:
if (val) {
fprintf(stderr, ERR_PREFIX "Cannot edit metadata: %s\n", key);
} else {
fprintf(stderr, ERR_PREFIX "Invalid metadata name: %s\n", key);
}
break;
case EXIT_INVALID_VALUE:
fprintf(stderr, ERR_PREFIX "Invalid value for %s: %s\n", key, val);
break;
case EXIT_MISSING_METADATA:
fprintf(stderr, ERR_PREFIX "Data has no metadata: %s\n", key);
break;
case EXIT_NO_EDIT:
fprintf(stderr, ERR_PREFIX "Cannot edit metadata: %s\n", key);
break;
case EXIT_INVALID_CREATE:
fprintf(stderr, ERR_PREFIX "%s is not valid metadata for %s\n", key, fname);
break;
}
return err;
}
static int show_path(const char *fname, struct opts *opts)
{
printf("%s", fname);
return 0;
}
static char *get_format(const char *bname, struct opts *opts)
{
char *s;
if ((s = strchr(bname, '.'))) {
return s + 1;
} else {
return "";
}
}
static int show_format(const char *bname, struct opts *opts)
{
printf("%s", get_format(bname, opts));
return 0;
}
static char *get_modtime(const char *fname, struct opts *opts)
{
struct stat st;
char *buf;
stat(fname, &st);
buf = malloc(256);
strftime(buf, 256, opts->timefmt, localtime(&st.st_mtime));
return buf;
}
static int show_modtime(const char *fname, struct opts *opts)
{
char *s;
s = get_modtime(fname, opts);
printf("%s", s);
free(s);
return 0;
}
static int show_metadata_fmtstr_key(xmlXPathContextPtr ctx, const char *k, int n, struct opts *opts)
{
int i;
char *key;
key = malloc(n + 1);
sprintf(key, "%.*s", n, k);
for (i = 0; metadata[i].key; ++i) {
if (strcmp(metadata[i].key, key) == 0) {
xmlNodePtr node;
if (!(node = first_xpath_node(metadata[i].path, ctx))) {
show_err(EXIT_MISSING_METADATA, key, NULL, NULL, opts);
free(key);
return EXIT_MISSING_METADATA;
}
if (node->type == XML_ATTRIBUTE_NODE) node = node->parent;
metadata[i].show(node, opts);
free(key);
return EXIT_SUCCESS;
}
}
show_err(EXIT_INVALID_METADATA, key, NULL, NULL, opts);
free(key);
return EXIT_INVALID_METADATA;
}
static int show_icn_metadata_fmtstr_key(const char *bname, const char *k, int n, struct opts *opts)
{
int i;
char *key;
key = malloc(n + 1);
sprintf(key, "%.*s", n, k);
for (i = 0; icn_metadata[i].key; ++i) {
if (strcmp(icn_metadata[i].key, key) == 0) {
icn_metadata[i].show(bname, opts);
free(key);
return EXIT_SUCCESS;
}
}
show_err(EXIT_INVALID_METADATA, key, NULL, NULL, opts);
free(key);
return EXIT_INVALID_METADATA;
}
static int show_metadata_fmtstr(const char *fname, xmlXPathContextPtr ctx, struct opts *opts)
{
int i;
for (i = 0; opts->fmtstr[i]; ++i) {
if (opts->fmtstr[i] == FMTSTR_DELIM) {
if (opts->fmtstr[i + 1] == FMTSTR_DELIM) {
putchar(FMTSTR_DELIM);
++i;
} else {
const char *k, *e;
int n;
char *s, *bname;
k = opts->fmtstr + i + 1;
e = strchr(k, FMTSTR_DELIM);
if (!e) break;
n = e - k;
s = strdup(fname);
bname = basename(s);
if (strncmp(k, "path", n) == 0) {
show_path(fname, opts);
} else if (strncmp(k, "format", n) == 0) {
show_format(bname, opts);
} else if (strncmp(k, "modified", n) == 0) {
show_modtime(fname, opts);
} else if (is_icn(bname)) {
show_icn_metadata_fmtstr_key(bname, k, n, opts);
} else {
show_metadata_fmtstr_key(ctx, k, n, opts);
}
free(s);
i += n + 1;
}
} else if (opts->fmtstr[i] == '\\') {
switch (opts->fmtstr[i + 1]) {
case 'n': putchar('\n'); ++i; break;
case 't': putchar('\t'); ++i; break;
case '0': putchar('\0'); ++i; break;
default: putchar(opts->fmtstr[i]);
}
} else {
putchar(opts->fmtstr[i]);
}
}
return 0;
}
static xmlChar *get_cond_content(int i, xmlXPathContextPtr ctx, const char *fname, struct opts *opts)
{
xmlNodePtr node;
if (strcmp(metadata[i].key, "path") == 0) {
return xmlCharStrdup(fname);
} else if (strcmp(metadata[i].key, "format") == 0) {
return xmlCharStrdup(get_format(fname, opts));
} else if (strcmp(metadata[i].key, "modified") == 0) {
return xmlCharStrdup(get_modtime(fname, opts));
} else if ((node = first_xpath_node(metadata[i].path, ctx))) {
if (metadata[i].get) {
return BAD_CAST metadata[i].get(node, opts);
} else {
return xmlNodeGetContent(node);
}
}
return NULL;
}
static int condition_cmp(const xmlChar *op, const xmlChar *content, const xmlChar *val, const xmlChar *regex)
{
int cmp;
if (regex) {
switch (op[0]) {
case '=': cmp = val == NULL ? content != NULL : match_pattern(content, val); break;
case '~': cmp = val == NULL ? content == NULL : !match_pattern(content, val); break;
default: cmp = 0; break;
}
} else {
switch (op[0]) {
case '=': cmp = val == NULL ? content != NULL : xmlStrcmp(content, val) == 0; break;
case '~': cmp = val == NULL ? content == NULL : xmlStrcmp(content, val) != 0; break;
default: cmp = 0; break;
}
}
return cmp;
}
static int condition_met(xmlXPathContextPtr ctx, xmlNodePtr cond, const char *fname, const char *bname, struct opts *opts)
{
xmlChar *key, *val, *op, *regex;
int i, cmp = 0;
key = xmlGetProp(cond, BAD_CAST "key");
val = xmlGetProp(cond, BAD_CAST "val");
op = xmlGetProp(cond, BAD_CAST "op");
regex = xmlGetProp(cond, BAD_CAST "regex");
if (is_icn(bname)) {
for (i = 0; icn_metadata[i].key; ++i) {
if (xmlStrcmp(key, BAD_CAST icn_metadata[i].key) == 0) {
xmlChar *content;
content = icn_metadata[i].get(bname, opts);
cmp = condition_cmp(op, content, val, regex);
xmlFree(content);
break;
}
}
} else {
for (i = 0; metadata[i].key; ++i) {
if (xmlStrcmp(key, BAD_CAST metadata[i].key) == 0) {
xmlChar *content;
content = get_cond_content(i, ctx, fname, opts);
cmp = condition_cmp(op, content, val, regex);
xmlFree(content);
break;
}
}
}
xmlFree(key);
xmlFree(val);
xmlFree(op);
xmlFree(regex);
return cmp;
}
static int show_icn_metadata(const char *bname, const char *key, struct opts *opts)
{
int i;
for (i = 0; icn_metadata[i].key; ++i) {
if (strcmp(key, icn_metadata[i].key) == 0) {
icn_metadata[i].show(bname, opts);
return EXIT_SUCCESS;
}
}
if (opts->endl > -1) putchar(opts->endl);
return EXIT_INVALID_METADATA;
}
static int show_all_icn_metadata(const char *fname, struct opts *opts)
{
int i;
for (i = 0; icn_metadata[i].key; ++i) {
if (opts->endl == '\n') {
printf("%s", icn_metadata[i].key);
if (opts->format_all) {
int n = KEY_COLUMN_WIDTH - strlen(icn_metadata[i].key);
int j;
for (j = 0; j < n; ++j) putchar(' ');
} else {
putchar('\t');
}
}
icn_metadata[i].show(fname, opts);
if (opts->endl > -1) putchar(opts->endl);
}
return 0;
}
static int show_or_edit_metadata(const char *fname, struct opts *opts)
{
int err = 0;
xmlDocPtr doc;
xmlXPathContextPtr ctxt;
int edit = 0;
xmlNodePtr cond;
char *s, *bname;
doc = read_xml_doc(fname);
ctxt = xmlXPathNewContext(doc);
s = strdup(fname);
bname = basename(s);
for (cond = opts->conds->children; cond; cond = cond->next) {
if (!condition_met(ctxt, cond, fname, bname, opts)) {
err = EXIT_CONDITION_UNMET;
}
}
if (!err) {
if (opts->execstr) {
err = execfile(opts->execstr, fname) != 0;
} else if (opts->fmtstr) {
err = show_metadata_fmtstr(fname, ctxt, opts);
} else if (opts->keys->children) {
xmlNodePtr cur;
for (cur = opts->keys->children; cur; cur = cur->next) {
char *key = NULL, *val = NULL;
key = (char *) xmlGetProp(cur, BAD_CAST "name");
val = (char *) xmlGetProp(cur, BAD_CAST "value");
if (val) {
edit = 1;
err = edit_metadata(ctxt, key, val);
} else if (strcmp(key, "path") == 0) {
err = show_path(fname, opts);
} else if (strcmp(key, "format") == 0) {
err = show_format(bname, opts);
} else if (strcmp(key, "modified") == 0) {
err = show_modtime(fname, opts);
} else if (is_icn(bname)) {
err = show_icn_metadata(bname, key, opts);
} else {
err = show_metadata(ctxt, key, opts);
}
if (!edit) {
putchar(opts->endl);
}
show_err(err, key, val, fname, opts);
xmlFree(key);
xmlFree(val);
}
} else if (opts->metadata_fname) {
FILE *input;
edit = 1;
if (strcmp(opts->metadata_fname, "-") == 0) {
input = stdin;
} else {
input = fopen(opts->metadata_fname, "r");
}
err = edit_all_metadata(input, ctxt);
fclose(input);
} else if (is_icn(bname)) {
err = show_all_icn_metadata(bname, opts);
} else {
err = show_all_metadata(ctxt, opts);
}
}
xmlXPathFreeContext(ctxt);
if (edit && !err) {
if (opts->overwrite) {
if (access(fname, W_OK) != -1) {
save_xml_doc(doc, fname);
} else {
fprintf(stderr, ERR_PREFIX "%s does not have write permission.\n", fname);
exit(EXIT_NO_WRITE);
}
} else {
save_xml_doc(doc, "-");
}
} else if (opts->endl != '\n' && err != EXIT_CONDITION_UNMET) {
putchar('\n');
}
free(s);
xmlFreeDoc(doc);
return err;
}
static void add_key(xmlNodePtr keys, const char *name)
{
xmlNodePtr key;
key = xmlNewChild(keys, NULL, BAD_CAST "key", NULL);
xmlSetProp(key, BAD_CAST "name", BAD_CAST name);
}
static void add_val(xmlNodePtr keys, const char *val)
{
xmlNodePtr key;
key = keys->last;
xmlSetProp(key, BAD_CAST "value", BAD_CAST val);
}
static void add_cond(xmlNodePtr conds, const char *k, const char *o)
{
xmlNodePtr cond;
cond = xmlNewChild(conds, NULL, BAD_CAST "cond", NULL);
xmlSetProp(cond, BAD_CAST "key", BAD_CAST k);
xmlSetProp(cond, BAD_CAST "op", BAD_CAST o);
}
static void add_cond_val(xmlNodePtr conds, const char *v, bool regex)
{
xmlNodePtr cond;
cond = conds->last;
if (regex) {
xmlSetProp(cond, BAD_CAST "regex", BAD_CAST "yes");
}
xmlSetProp(cond, BAD_CAST "val", BAD_CAST v);
}
static int show_or_edit_metadata_list(const char *fname, struct opts *opts)
{
FILE *f;
char path[PATH_MAX];
int err = 0;
if (fname) {
if (!(f = fopen(fname, "r"))) {
fprintf(stderr, ERR_PREFIX "Could not read list file '%s'.\n", fname);
exit(EXIT_NO_FILE);
}
} else {
f = stdin;
}
while (fgets(path, PATH_MAX, f)) {
strtok(path, "\t\r\n");
err += show_or_edit_metadata(path, opts);
}
if (fname) {
fclose(f);
}
return err;
}
#ifdef LIBS1KD
xmlChar *s1kdDocGetMetadata(xmlDocPtr doc, const xmlChar *name)
{
int i;
xmlChar *value = NULL;
struct opts opts;
/* Initialize option defaults. */
opts.conds = NULL;
opts.endl = '\n';
opts.execstr = NULL;
opts.fmtstr = NULL;
opts.format_all = 1;
opts.keys = NULL;
opts.metadata_fname = NULL;
opts.only_editable = 0;
opts.overwrite = 0;
opts.timefmt = strdup(DEFAULT_TIMEFMT);
opts.verbosity = NORMAL;
for (i = 0; metadata[i].key && !value; ++i) {
if (strcmp(metadata[i].key, name) == 0) {
xmlXPathContextPtr ctx;
xmlNodePtr node;
ctx = xmlXPathNewContext(doc);
if ((node = first_xpath_node(metadata[i].path, ctx))) {
if (metadata[i].get) {
value = metadata[i].get(node, &opts);
} else {
value = xmlNodeGetContent(node);
}
}
xmlXPathFreeContext(ctx);
break;
}
}
free(opts.timefmt);
return value;
}
char *s1kdGetMetadata(const char *object_xml, int object_size, const char *name)
{
xmlDocPtr doc;
char *val;
doc = read_xml_mem(object_xml, object_size);
val = (char *) s1kdDocGetMetadata(doc, BAD_CAST name);
xmlFreeDoc(doc);
return val;
}
int s1kdDocSetMetadata(xmlDocPtr doc, const xmlChar *name, const xmlChar *value)
{
xmlXPathContextPtr ctx;
int err;
ctx = xmlXPathNewContext(doc);
err = edit_metadata(ctx, (char *) name, (char *) value);
xmlXPathFreeContext(ctx);
return err;
}
int s1kdSetMetadata(const char *object_xml, int object_size, const char *name, const char *value, char **result_xml, int *result_size)
{
xmlDocPtr doc;
int err;
doc = read_xml_mem(object_xml, object_size);
err = s1kdDocSetMetadata(doc, BAD_CAST name, BAD_CAST value);
if (result_xml && result_size) {
xmlDocDumpMemory(doc, (xmlChar **) result_xml, result_size);
}
xmlFreeDoc(doc);
return err;
}
#else
static void show_help(void)
{
puts("Usage: " PROG_NAME " [options] [<object>...]");
puts("");
puts("Options:");
puts(" -0, --null Use null-delimited fields.");
puts(" -c, --set <file> Set metadata using definitions in <file> (- for stdin).");
puts(" -d, --date-format <fmt> Format to use for printing dates.");
puts(" -E, --editable Include only editable metadata when showing all.");
puts(" -e, --exec <cmd> Execute <cmd> for each CSDB object.");
puts(" -F, --format <fmt> Print a formatted line for each CSDB object.");
puts(" -f, --overwrite Overwrite modules when editing metadata.");
puts(" -H, --info List information on available metadata.");
puts(" -l, --list Input is a list of filenames.");
puts(" -m, --matches <regex> Use a pattern instead of a literal value (-v) with -w/-W.");
puts(" -n, --name <name> Specific metadata name to view/edit.");
puts(" -q, --quiet Quiet mode, do not show non-fatal errors.");
puts(" -T, --raw Do not format columns in output.");
puts(" -t, --tab Use tab-delimited fields.");
puts(" -v, --value <value> The value to set or match.");
puts(" -W, --where-not <name> Only list/edit objects where metadata <name> does not equal a value.");
puts(" -w, --where <name> Only list/edit objects where metadata <name> equals a value.");
puts(" --version Show version information.");
puts(" <object> CSDB object(s) to view/edit metadata on.");
LIBXML2_PARSE_LONGOPT_HELP
}
static void show_version(void)
{
printf("%s (s1kd-tools) %s\n", PROG_NAME, VERSION);
printf("Using libxml %s\n", xmlParserVersion);
}
int main(int argc, char **argv)
{
xmlNodePtr last = NULL;
int err = 0;
int i;
int list_keys = 0;
int islist = 0;
struct opts opts;
const char *sopts = "0d:c:Ee:F:fHlm:n:Ttv:qW:w:h?";
struct option lopts[] = {
{"version" , no_argument , 0, 0},
{"help" , no_argument , 0, 'h'},
{"null" , no_argument , 0, '0'},
{"set" , required_argument, 0, 'c'},
{"date-format", required_argument, 0, 'd'},
{"editable" , no_argument , 0, 'E'},
{"exec" , required_argument, 0, 'e'},
{"format" , required_argument, 0, 'F'},
{"overwrite" , no_argument , 0, 'f'},
{"info" , no_argument , 0, 'H'},
{"list" , no_argument , 0, 'l'},
{"matches" , required_argument, 0, 'm'},
{"name" , required_argument, 0, 'n'},
{"raw" , no_argument , 0, 'T'},
{"tab" , no_argument , 0, 't'},
{"value" , required_argument, 0, 'v'},
{"quiet" , no_argument , 0, 'q'},
{"where" , required_argument, 0, 'w'},
{"where-not" , required_argument, 0, 'W'},
LIBXML2_PARSE_LONGOPT_DEFS
{0, 0, 0, 0}
};
int loptind = 0;
/* Initialize program option defaults. */
opts.conds = xmlNewNode(NULL, BAD_CAST "conds");
opts.endl = '\n';
opts.execstr = NULL;
opts.fmtstr = NULL;
opts.format_all = 1;
opts.keys = xmlNewNode(NULL, BAD_CAST "keys");
opts.metadata_fname = NULL;
opts.only_editable = 0;
opts.overwrite = 0;
opts.timefmt = strdup(DEFAULT_TIMEFMT);
opts.verbosity = NORMAL;
while ((i = getopt_long(argc, argv, sopts, lopts, &loptind)) != -1) {
switch (i) {
case 0:
if (strcmp(lopts[loptind].name, "version") == 0) {
show_version();
goto cleanup;
}
LIBXML2_PARSE_LONGOPT_HANDLE(lopts, loptind, optarg)
break;
case '0': opts.endl = '\0'; break;
case 'c': opts.metadata_fname = strdup(optarg); break;
case 'd': free(opts.timefmt); opts.timefmt = strdup(optarg); break;
case 'E': opts.only_editable = 1; break;
case 'e': opts.execstr = strdup(optarg); break;
case 'F': opts.fmtstr = strdup(optarg); opts.endl = -1; break;
case 'f': opts.overwrite = 1; break;
case 'H': list_keys = 1; break;
case 'l': islist = 1; break;
case 'm':
if (last == opts.conds) {
add_cond_val(opts.conds, optarg, true);
}
break;
case 'n': add_key(opts.keys, optarg); last = opts.keys; break;
case 'T': opts.format_all = 0; break;
case 't': opts.endl = '\t'; break;
case 'v':
if (last == opts.keys)
add_val(opts.keys, optarg);
else if (last == opts.conds)
add_cond_val(opts.conds, optarg, false);
break;
case 'q': opts.verbosity = SILENT; break;
case 'w': add_cond(opts.conds, optarg, "="); last = opts.conds; break;
case 'W': add_cond(opts.conds, optarg, "~"); last = opts.conds; break;
case 'h':
case '?': show_help(); goto cleanup;
}
}
if (list_keys) {
list_metadata_keys(&opts);
} else if (optind < argc) {
for (i = optind; i < argc; ++i) {
if (islist) {
err += show_or_edit_metadata_list(argv[i], &opts);
} else {
err += show_or_edit_metadata(argv[i], &opts);
}
}
} else if (islist) {
err = show_or_edit_metadata_list(NULL, &opts);
} else {
err = show_or_edit_metadata("-", &opts);
}
cleanup:
free(opts.metadata_fname);
free(opts.fmtstr);
free(opts.execstr);
free(opts.timefmt);
xmlFreeNode(opts.keys);
xmlFreeNode(opts.conds);
xmlCleanupParser();
return err;
}
#endif
gopher://khzae.net/0/s1kd/s1kd-tools/src/tools/s1kd-metadata/s1kd-metadata.c