diff --git a/os400/make-src.sh b/os400/make-src.sh index 10b66297..9b1076a9 100644 --- a/os400/make-src.sh +++ b/os400/make-src.sh @@ -271,3 +271,30 @@ then mkdir -p "${IFSDIR}/bin" fi rm -f "${IFSDIR}/bin/xmllint" ln -s "${LIBIFSNAME}/XMLLINT.PGM" "${IFSDIR}/bin/xmllint" + +# Prepare the XMLLINT command and its response program. + +if action_needed "${LIBIFSNAME}/XMLLINTCL.PGM" "${SCRIPTDIR}/xmllintcl.c" +then make_module --ebcdic XMLLINTCL "${SCRIPTDIR}/xmllintcl.c" + CMD="CRTPGM PGM(${TARGETLIB}/XMLLINTCL) MODULE(${TARGETLIB}/XMLLINTCL)" + CMD="${CMD} ACTGRP(*NEW) TEXT('XMLLINT command response')" + CMD="${CMD} TGTRLS(${TGTRLS})" + system "${CMD}" + rm -f "${LIBIFSNAME}/XMLLINTCL.MODULE" +fi + +if action_needed "${LIBIFSNAME}/TOOLS.FILE/XMLLINT.MBR" \ + "${SCRIPTDIR}/xmllint.cmd" +then CMD="CPY OBJ('${SCRIPTDIR}/xmllint.cmd')" + CMD="${CMD} TOOBJ('${LIBIFSNAME}/TOOLS.FILE/XMLLINT.MBR')" + CMD="${CMD} TOCCSID(${TGTCCSID}) DTAFMT(*TEXT) REPLACE(*YES)" + system "${CMD}" +fi + +if action_needed "${LIBIFSNAME}/XMLLINT.CMD" \ + "${LIBIFSNAME}/TOOLS.FILE/XMLLINT.MBR" +then CMD="CRTCMD CMD(${TARGETLIB}/XMLLINT) PGM(${TARGETLIB}/XMLLINTCL)" + CMD="${CMD} SRCFILE(${TARGETLIB}/TOOLS) SRCMBR(XMLLINT) THDSAFE(*YES)" + CMD="${CMD} TEXT('XML tool') REPLACE(*YES)" + system "${CMD}" +fi diff --git a/os400/xmllint.cmd b/os400/xmllint.cmd new file mode 100644 index 00000000..1582837f --- /dev/null +++ b/os400/xmllint.cmd @@ -0,0 +1,146 @@ +/* XMLLINT CL command. */ +/* */ +/* See Copyright for the status of this software. */ +/* */ +/* Author: Patrick Monnerat , DATASPHERE S.A. */ + +/* Interface to program XMLLINTCL */ + + CMD PROMPT('XML tool') + + /* XML input file location. */ + + PARM KWD(STMF) TYPE(*PNAME) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) MIN(1) + + CHOICE('Stream file path') + + PROMPT('XML Stream file') + + /* DTD location. */ + + PARM KWD(DTD) TYPE(*PNAME) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) PASSVAL(*NULL) + + CHOICE('ID, URL or stream file path') + + PROMPT('DTD id, URL or file path') + + PARM KWD(DTDLOCATOR) TYPE(*CHAR) LEN(8) DFT(*DTDURL) + + SPCVAL(*DTDURL *DTDFPI) EXPR(*YES) RSTD(*YES) + + PROMPT('DTD locator is URL/FPI') + + /* Schema location. */ + + PARM KWD(SCHEMA) TYPE(*PNAME) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) PASSVAL(*NULL) + + CHOICE('URL or stream file path') + + PROMPT('Schema URL or stream file path') + + PARM KWD(SCHEMAKIND) TYPE(*CHAR) LEN(12) VARY(*YES *INT2) + + RSTD(*YES) DFT(*XSD) + + PROMPT('Validating schema kind') + + CHOICE('Keyword') SPCVAL( + + (*XSD '--schema') + + (*RELAXNG '--relaxng') + + (*SCHEMATRON '--schematron') + + ) + + /* Output location. */ + + PARM KWD(OUTSTMF) TYPE(*PNAME) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) PASSVAL(*NULL) + + CHOICE('Stream file path') + + PROMPT('Output stream file path') + + /* Other parameters with arguments. */ + + PARM KWD(XPATH) TYPE(*CHAR) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) PASSVAL(*NULL) + + CHOICE('XPath expression') + + PROMPT('XPath filter') + + PARM KWD(PATTERN) TYPE(*CHAR) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) PASSVAL(*NULL) + + CHOICE('Reader pattern') + + PROMPT('Reader node filter') + + /* Paths for resources. */ + + PARM KWD(PATH) TYPE(*PNAME) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) MAX(64) + + CHOICE('IFS directory path') + + PROMPT('Path for resources') + + PARM KWD(PRETTY) TYPE(*CHAR) LEN(11) VARY(*YES *INT2) + + RSTD(*YES) DFT(*NONE) + + PROMPT('Pretty-print style') + + CHOICE('Keyword') SPCVAL( + + (*NONE '0') + + (*FORMAT '1') + + (*WHITESPACE '2') + + ) + + PARM KWD(MAXMEM) TYPE(*UINT4) EXPR(*YES) DFT(0) + + CHOICE('Number of bytes') + + PROMPT('Maximum dynamic memory') + + PARM KWD(ENCODING) TYPE(*CHAR) LEN(32) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) PASSVAL(*NULL) + + PMTCTL(ENCODING) CHOICE('Encoding name') + + PROMPT('Output character encoding') +ENCODING: PMTCTL CTL(OUTSTMF) COND(*SPCFD) + + /* Boolean options. */ + /* --shell is not supported from command mode. */ + + PARM KWD(OPTIONS) TYPE(*CHAR) LEN(20) VARY(*YES *INT2) + + MAX(50) RSTD(*YES) PROMPT('Options') + + CHOICE('Keyword') SPCVAL( + + (*VERSION '--version') + + (*DEBUG '--debug') + + (*DEBUGENT '--debugent') + + (*COPY '--copy') + + (*RECOVER '--recover') + + (*HUGE '--huge') + + (*NOENT '--noent') + + (*NOENC '--noenc') + + (*NOOUT '--noout') + + (*LOADTRACE '--load-trace') + + (*NONET '--nonet') + + (*NOCOMPACT '--nocompact') + + (*HTMLOUT '--htmlout') + + (*NOWRAP '--nowrap') + + (*VALID '--valid') + + (*POSTVALID '--postvalid') + + (*TIMING '--timing') + + (*REPEAT '--repeat') + + (*INSERT '--insert') + + (*COMPRESS '--compress') + + (*HTML '--html') + + (*XMLOUT '--xmlout') + + (*NODEFDTD '--nodefdtd') + + (*PUSH '--push') + + (*PUSHSMALL '--pushsmall') + + (*MEMORY '--memory') + + (*NOWARNING '--nowarning') + + (*NOBLANKS '--noblanks') + + (*NOCDATA '--nocdata') + + (*FORMAT '--format') + + (*DROPDTD '--dropdtd') + + (*NSCLEAN '--nsclean') + + (*TESTIO '--testIO') + + (*CATALOGS '--catalogs') + + (*NOCATALOGS '--nocatalogs') + + (*AUTO '--auto') + + (*XINCLUDE '--xinclude') + + (*NOXINCLUDENODE '--noxincludenode') + + (*NOFIXUPBASEURIS '--nofixup-base-uris') + + (*LOADDTD '--loaddtd') + + (*DTDATTR '--dtdattr') + + (*STREAM '--stream') + + (*WALKER '--walker') + + (*CHKREGISTER '--chkregister') + + (*C14N '--c14n') + + (*C14N11 '--c14n11') + + (*EXCC14N '--exc-c14n') + + (*SAX1 '--sax1') + + (*SAX '--sax') + + (*OLDXML10 '--oldxml10') + + ) diff --git a/os400/xmllintcl.c b/os400/xmllintcl.c new file mode 100644 index 00000000..12263853 --- /dev/null +++ b/os400/xmllintcl.c @@ -0,0 +1,216 @@ +/** +*** XMLLINT command response program. +*** +*** See Copyright for the status of this software. +*** +*** Author: Patrick Monnerat , DATASPHERE S.A. +**/ + +#include +#include +#include +#include + + +/* Variable-length string, with 16-bit length. */ +typedef struct { + short len; + char string[5000]; +} vary2; + + +/* Variable-length string, with 32-bit length. */ +typedef struct { + int len; + char string[5000]; +} vary4; + + +/* Multiple occurrence parameter list. */ +#define paramlist(itemsize, itemtype) \ + _Packed struct { \ + short len; \ + union { \ + char _pad[itemsize]; \ + itemtype param; \ + } item[1]; \ + } + + +/* Arguments from CL command. */ +typedef struct { + char * pgm; /* Program name. */ + vary2 * stmf; /* XML file name or URL. */ + vary2 * dtd; /* DTD location or public identifier. */ + char * dtdvalid; /* *DTDURL or *DTDFPI. */ + vary2 * schema; /* Schema file name or URL. */ + vary2 * schemakind; /* --schema/--relaxng/--schematron. */ + vary2 * outstmf; /* Output stream file name. */ + vary2 * xpath; /* XPath filter. */ + vary2 * pattern; /* Reader filter pattern. */ + paramlist(5000 + 2, vary2) * path; /* Path for resources. */ + vary2 * pretty; /* Pretty-print style. */ + unsigned long * maxmem; /* Maximum dynamic memory. */ + vary2 * encoding; /* Output encoding. */ + paramlist(20 + 2, vary2) * options; /* Other options. */ +} arguments; + + +/* Definition of QSHELL program. */ +extern void qshell(vary4 * cmd); +#pragma linkage(qshell, OS) +#pragma map(qshell, "QSHELL/QZSHQSHC") + + +static void +vary4nappend(vary4 * dst, const char * src, size_t len) + +{ + if (len > sizeof(dst->string) - dst->len) + len = sizeof(dst->string) - dst->len; + + if (len) { + memcpy(dst->string + dst->len, src, len); + dst->len += len; + } +} + + +static void +vary4append(vary4 * dst, const char * src) + +{ + vary4nappend(dst, src, strlen(src)); +} + + +static void +vary4arg(vary4 * dst, const char * arg) + +{ + vary4nappend(dst, " ", 1); + vary4append(dst, arg); +} + + +static void +vary4varg(vary4 * dst, vary2 * arg) + +{ + vary4nappend(dst, " ", 1); + vary4nappend(dst, arg->string, arg->len); +} + + +static void +vary4vescape(vary4 * dst, vary2 * arg) + +{ + int i; + + for (i = 0; i < arg->len; i++) + if (arg->string[i] == '\'') + vary4nappend(dst, "'\"'\"'", 5); + else + vary4nappend(dst, arg->string + i, 1); +} + + +static void +vary4vargquote(vary4 * dst, vary2 * arg) + +{ + vary4nappend(dst, " '", 2); + vary4vescape(dst, arg); + vary4nappend(dst, "'", 1); +} + + +int +main(int argsc, arguments * args) + +{ + vary4 cmd; + int i; + char textbuf[20]; + char * lang; + + /* find length of library name. */ + for (i = 0; i < 10 && args->pgm[i] && args->pgm[i] != '/'; i++) + ; + + /* Store program name in command buffer. */ + cmd.len = 0; + vary4append(&cmd, "/QSYS.LIB/"); + vary4nappend(&cmd, args->pgm, i); + vary4append(&cmd, ".LIB/XMLLINT.PGM"); + + /* Map command arguments to standard xmllint argument vector. */ + + if (args->dtd && args->dtd->len) { + if (args->dtdvalid && args->dtdvalid[4] == 'F') + vary4arg(&cmd, "--dtdvalidfpi"); + else + vary4arg(&cmd, "--dtdvalid"); + + vary4vargquote(&cmd, args->dtd); + } + + if (args->schema && args->schema->len) { + vary4varg(&cmd, args->schemakind); + vary4vargquote(&cmd, args->schema); + } + + if (args->outstmf && args->outstmf->len) { + vary4arg(&cmd, "--output"); + vary4vargquote(&cmd, args->outstmf); + + if (args->encoding && args->encoding->len) { + vary4arg(&cmd, "--encoding"); + vary4vargquote(&cmd, args->encoding); + } + } + + if (args->xpath && args->xpath->len) { + vary4arg(&cmd, "--xpath"); + vary4vargquote(&cmd, args->xpath); + } + + if (args->pattern && args->pattern->len) { + vary4arg(&cmd, "--pattern"); + vary4vargquote(&cmd, args->pattern); + } + + if (args->path && args->path->len) { + vary4arg(&cmd, "--path '"); + vary4vescape(&cmd, &args->path->item[0].param); + for (i = 1; i < args->path->len; i++) { + vary4nappend(&cmd, ":", 1); + vary4vescape(&cmd, &args->path->item[i].param); + } + vary4nappend(&cmd, "'", 1); + } + + if (args->pretty && args->pretty->len && + args->pretty->string[0] != '0') { + vary4arg(&cmd, "--pretty"); + vary4varg(&cmd, args->pretty); + } + + if (args->maxmem && *args->maxmem) { + snprintf(textbuf, sizeof textbuf, "%lu", *args->maxmem); + vary4arg(&cmd, "--maxmem"); + vary4arg(&cmd, textbuf); + } + + for (i = 0; i < args->options->len; i++) + vary4varg(&cmd, &args->options->item[i].param); + + vary4vargquote(&cmd, args->stmf); + + /* Execute the shell command. */ + qshell(&cmd); + + /* Terminate. */ + exit(0); +}