d8feabb353b3c2650facea4afd08c86bb56e5549 kent Fri Apr 6 16:51:54 2012 -0700 Moving autoSql and autoDtd and autoXml back to just under hg. A little autoSql -django fix. diff --git src/hg/autoXml/autoXml.c src/hg/autoXml/autoXml.c new file mode 100644 index 0000000..cf05e8b --- /dev/null +++ src/hg/autoXml/autoXml.c @@ -0,0 +1,724 @@ +/* autoXml - Generate structures code and parser for XML file from DTD-like spec. */ +#include "common.h" +#include "linefile.h" +#include "hash.h" +#include "dystring.h" +#include "cheapcgi.h" +#include "obscure.h" +#include "portable.h" +#include "dtdParse.h" + + +/* Variables that can be over-ridden from command line. */ +char *textField = "text"; +char *fileComment = "autoXml generated file"; +boolean picky; /* Generate a parser that is afraid of the unknown. */ +boolean makeMain; /* Generate main() routine as test shell. */ +boolean positiveOnly; /* Don't write out negative numbers. */ +char prefix[128]; /* Added to start of output file and structure names. */ + +void usage() +/* Explain usage and exit. */ +{ +errAbort( + "autoXml - Generate structures code and parser for XML file from DTD-like spec\n" + "usage:\n" + " autoXml file.dtdx root\n" + "This will generate root.c, root.h\n" + "options:\n" + " -textField=xxx what to name text between start/end tags. Default 'text'\n" + " -comment=xxx Comment to appear at top of generated code files\n" + " -picky Generate parser that rejects stuff it doesn't understand\n" + " -main Put in a main routine that's a test harness\n" + " -prefix=xxx Prefix to add to structure names. By default same as root\n" + " -positive Don't write out optional attributes with negative values\n" + ); +} + +char *cAttType(char *type) +/* Return C declaration corresponding to type. */ +{ +if (sameWord(type, "INT")) + return "int "; +else if (sameWord(type, "FLOAT")) + return "double "; +else + return "char *"; +} + +char fAttType(char *type) +/* Return printf %code to type. */ +{ +if (sameWord(type, "INT")) + return 'd'; +else if (sameWord(type, "FLOAT")) + return 'f'; +else + return 's'; +} + +boolean childMatch(struct dtdElChild *children, struct dtdElement *el) +/* Return TRUE if any of children are el. */ +{ +struct dtdElChild *ec; +for (ec = children; ec != NULL; ec = ec->next) + { + if (ec->el == el) + return TRUE; + } +return FALSE; +} + +boolean anyParent(struct dtdElement *elList, struct dtdElement *child) +/* Return TRUE if anybody in elList could be a parent to child. */ +{ +struct dtdElement *el; +for (el = elList; el != NULL; el = el->next) + { + if (childMatch(el->children, child)) + return TRUE; + } +return FALSE; +} + +void freeFunctionPrototype(struct dtdElement *el, FILE *f, char *addSemi) +/* Put up function prototype for elFree function. */ +{ +char *name = el->mixedCaseName; +fprintf(f, "void %sFree(struct %s **pObj)%s", name, name, addSemi); +fprintf(f, "\n"); +fprintf(f, "/* Free up %s. */\n", name); +} + +void freeListFunctionPrototype(struct dtdElement *el, FILE *f, char *addSemi) +/* Put up function prototype for elFreeList function. */ +{ +char *name = el->mixedCaseName; +fprintf(f, "void %sFreeList(struct %s **pList)%s", name, name, addSemi); +fprintf(f, "\n"); +fprintf(f, "/* Free up list of %s. */\n", name); +} + + +void saveFunctionPrototype(struct dtdElement *el, FILE *f, char *addSemi) +/* Put up function prototype for elSave function. */ +{ +char *name = el->mixedCaseName; +fprintf(f, "void %sSave(struct %s *obj, int indent, FILE *f)%s", name, name, addSemi); +fprintf(f, "\n"); +fprintf(f, "/* Save %s to file. */\n", name); +} + +void loadFunctionPrototype(struct dtdElement *el, FILE *f, char *addSemi) +/* Put up function prototype for elLoad function. */ +{ +char *name = el->mixedCaseName; +fprintf(f, "struct %s *%sLoad(char *fileName)%s\n", name, name, addSemi); +fprintf(f, "/* Load %s from XML file where it is root element. */\n", name); +} + +void loadFunctionBody(struct dtdElement *el, FILE *f) +/* Write body of elLoad function. */ +{ +fprintf(f, "{\n"); +fprintf(f, "struct %s *obj;\n", el->mixedCaseName); +fprintf(f, "xapParseAny(fileName, \"%s\", %sStartHandler, %sEndHandler, NULL, &obj);\n", + el->name, prefix, prefix); +fprintf(f, "return obj;\n"); +fprintf(f, "}\n"); +fprintf(f, "\n"); +} + +void loadNextFunctionPrototype(struct dtdElement *el, FILE *f, char *addSemi) +/* Put up function prototype for elLoad function. */ +{ +char *name = el->mixedCaseName; +fprintf(f, "struct %s *%sLoadNext(struct xap *xap)%s\n", name, name, addSemi); +fprintf(f, "/* Load next %s element. Use xapOpen to get xap. */\n", name); +} + +void loadNextFunctionBody(struct dtdElement *el, FILE *f) +/* Write body of elLoad function. */ +{ +fprintf(f, "{\n"); +fprintf(f, "return xapNext(xap, \"%s\");\n", el->name); +fprintf(f, "}\n"); +fprintf(f, "\n"); +} + + +void startHandlerPrototype(FILE *f, char *addSemi) +/* Print function prototype for startHandler. */ +{ +fprintf(f, "void *%sStartHandler(struct xap *xp, char *name, char **atts)%s\n", prefix, addSemi); +fprintf(f, "/* Called by xap with start tag. Does most of the parsing work. */\n"); +} + +void makeStartHandler(struct dtdElement *elList, FILE *f) +/* Create function that gets called by expat at start of tag. */ +{ +struct dtdElement *el; +struct dtdAttribute *att; + +startHandlerPrototype(f, ""); +fprintf(f, "{\n"); +fprintf(f, "struct xapStack *st = xp->stack+1;\n"); +fprintf(f, "int depth = xp->stackDepth;\n"); +fprintf(f, "int i;\n"); +fprintf(f, "\n"); +for (el = elList; el != NULL; el = el->next) + { + fprintf(f, "%sif (sameString(name, \"%s\"))\n", (el == elList ? "" : "else "), el->name); + fprintf(f, " {\n"); + fprintf(f, " struct %s *obj;\n", el->mixedCaseName); + fprintf(f, " AllocVar(obj);\n"); + if (el->attributes != NULL) + { + boolean first = TRUE; + for (att = el->attributes; att != NULL; att = att->next) + { + if (att->usual != NULL) + { + char *quote = "\""; + if (sameString(att->type, "INT") || sameString(att->type, "FLOAT")) + quote = ""; + fprintf(f, " obj->%s = %s%s%s;\n", att->name, quote, att->usual, quote); + } + } + fprintf(f, " for (i=0; atts[i] != NULL; i += 2)\n"); + fprintf(f, " {\n"); + fprintf(f, " char *name = atts[i], *val = atts[i+1];\n"); + for (att = el->attributes; att != NULL; att = att->next) + { + fprintf(f, " %s (sameString(name, \"%s\"))\n", + (first ? "if " : "else if"), att->name); + if (sameWord(att->type, "INT")) + fprintf(f, " obj->%s = atoi(val);\n", att->name); + else if (sameWord(att->type, "FLOAT")) + fprintf(f, " obj->%s = atof(val);\n", att->name); + else + fprintf(f, " obj->%s = cloneString(val);\n", att->name); + first = FALSE; + } + if (picky) + { + fprintf(f, " else\n"); + fprintf(f, " xapError(xp, \"Unknown attribute %%s\", name);\n"); + } + fprintf(f, " }\n"); + for (att = el->attributes; att != NULL; att = att->next) + { + if (att->required) + { + if (sameWord(att->type, "INT") || sameWord(att->type, "FLOAT")) + { + /* For the moment can't check these. */ + } + else + { + fprintf(f, " if (obj->%s == NULL)\n", att->name); + fprintf(f, " xapError(xp, \"missing %s\");\n", att->name); + } + } + } + } + if (anyParent(elList, el)) + { + struct dtdElement *parent; + boolean first = TRUE; + fprintf(f, " if (depth > 1)\n"); + fprintf(f, " {\n"); + for (parent = elList; parent != NULL; parent = parent->next) + { + if (childMatch(parent->children, el)) + { + fprintf(f, " %s (sameString(st->elName, \"%s\"))\n", + (first ? "if " : "else if"), parent->name); + fprintf(f, " {\n"); + fprintf(f, " struct %s *parent = st->object;\n", parent->mixedCaseName); + fprintf(f, " slAddHead(&parent->%s, obj);\n", el->mixedCaseName); + fprintf(f, " }\n"); + first = FALSE; + } + } + if (picky) + { + fprintf(f, " else\n"); + fprintf(f, " xapError(xp, \"%%s misplaced\", name);\n"); + } + fprintf(f, " }\n"); + } + fprintf(f, " return obj;\n"); + fprintf(f, " }\n"); + } +fprintf(f, "else\n"); +fprintf(f, " {\n"); +if (picky) + fprintf(f, " xapError(xp, \"Unknown element %%s\", name);\n"); +else + fprintf(f, " xapSkip(xp);\n"); +fprintf(f, " return NULL;\n"); +fprintf(f, " }\n"); +fprintf(f, "}\n"); +fprintf(f, "\n"); +} + + +void endHandlerPrototype(FILE *f, char *addSemi) +/* Print function prototype for endHandler. */ +{ +fprintf(f, "void %sEndHandler(struct xap *xp, char *name)%s\n", prefix, addSemi); +fprintf(f, "/* Called by xap with end tag. Checks all required children are loaded. */\n"); +} + +void makeEndHandler(struct dtdElement *elList, FILE *f) +/* Create function that gets called by expat at end of tag. */ +{ +struct dtdElement *el; +struct dtdElChild *ec; +boolean first = TRUE; + +endHandlerPrototype(f, ""); +fprintf(f, "{\n"); +fprintf(f, "struct xapStack *stack = xp->stack;\n"); +for (el = elList; el != NULL; el = el->next) + { + if (el->children || el->textType) + { + fprintf(f, "%sif (sameString(name, \"%s\"))\n", + (first ? "" : "else "), el->name); + fprintf(f, " {\n"); + fprintf(f, " struct %s *obj = stack->object;\n", el->mixedCaseName); + for (ec = el->children; ec != NULL; ec = ec->next) + { + char *cBIG = ec->el->name; + char *cSmall = ec->el->mixedCaseName; + if (ec->copyCode == '1') + { + fprintf(f, " if (obj->%s == NULL)\n", cSmall); + fprintf(f, " xapError(xp, \"Missing %s\");\n", cBIG); + fprintf(f, " if (obj->%s->next != NULL)\n", cSmall); + fprintf(f, " xapError(xp, \"Multiple %s\");\n", cBIG); + } + else if (ec->copyCode == '+') + { + if (! ec->isOr) + { + /* bypassing this is not the Right thing to do -- + * really we should make sure that somebody in the Or list + * was present */ + fprintf(f, " if (obj->%s == NULL)\n", cSmall); + fprintf(f, " xapError(xp, \"Missing %s\");\n",cBIG); + } + fprintf(f, " slReverse(&obj->%s);\n", cSmall); + } + else if (ec->copyCode == '*') + { + fprintf(f, " slReverse(&obj->%s);\n", cSmall); + } + else if (ec->copyCode == '?') + { + fprintf(f, " if (obj->%s != NULL && obj->%s->next != NULL)\n", cSmall, cSmall); + fprintf(f, " xapError(xp, \"Multiple %s\");\n", cBIG); + } + } + if (el->textType) + { + if (sameString(el->textType, "#INT")) + fprintf(f, " obj->%s = atoi(stack->%s->string);\n", textField, textField); + else if (sameString(el->textType, "#FLOAT")) + fprintf(f, " obj->%s = atof(stack->%s->string);\n", textField, textField); + else + fprintf(f, " obj->%s = cloneString(stack->%s->string);\n", textField, textField); + } + fprintf(f, " }\n"); + first = FALSE; + } + } +fprintf(f, "}\n"); +fprintf(f, "\n"); +} + +void makeH(struct dtdElement *elList, char *fileName) +/* Produce C header file. */ +{ +FILE *f = mustOpen(fileName, "w"); +struct dtdElement *el; +struct dtdAttribute *att; +struct dtdElChild *ec; +char upcPrefix[128]; + +fprintf(f, "/* %s.h %s */\n", prefix, fileComment); +strcpy(upcPrefix, prefix); +touppers(upcPrefix); +fprintf(f, "#ifndef %s_H\n", upcPrefix); +fprintf(f, "#define %s_H\n", upcPrefix); +fprintf(f, "\n"); +fprintf(f, "#ifndef XAP_H\n"); +fprintf(f, "#include \"xap.h\"\n"); +fprintf(f, "#endif\n"); +fprintf(f, "\n"); + +fprintf(f, + "/* The start and end handlers here are used with routines defined in xap.h.\n" + " * In particular if you want to read just parts of the XML file into memory\n" + " * call xapOpen() with these, and then xapNext() with the name of the tag\n" + " * you want to load. */\n\n"); +startHandlerPrototype(f, ";"); +fprintf(f, "\n"); +endHandlerPrototype(f, ";"); +fprintf(f, "\n"); +fprintf(f, "\n"); + +for (el = elList; el != NULL; el = el->next) + { + fprintf(f, "struct %s\n", el->mixedCaseName); + fprintf(f, " {\n"); + fprintf(f, " struct %s *next;\n", el->mixedCaseName); + if (el->textType != NULL) + { + if (sameString(el->textType, "#INT")) + fprintf(f, " int %s;\n", textField); + else if (sameString(el->textType, "#FLOAT")) + fprintf(f, " float %s;\n", textField); + else + fprintf(f, " char *%s;\n", textField); + } + for (att = el->attributes; att != NULL; att = att->next) + { + fprintf(f, " %s%s;", cAttType(att->type), att->name); + if (att->required) + fprintf(f, "\t/* Required */"); + else + { + if (att->usual != NULL) + fprintf(f, "\t/* Defaults to %s */", att->usual); + else + fprintf(f, "\t/* Optional */"); + } + fprintf(f, "\n"); + } + for (ec = el->children; ec != NULL; ec = ec->next) + { + fprintf(f, " struct %s *%s;", ec->el->mixedCaseName, ec->el->mixedCaseName); + if (ec->copyCode == '1') + fprintf(f, "\t/** Single instance required. **/"); + else if (ec->copyCode == '+') + fprintf(f, "\t/** Non-empty list required. **/"); + else if (ec->copyCode == '*') + fprintf(f, "\t/** Possibly empty list. **/"); + else if (ec->copyCode == '?') + fprintf(f, "\t/** Optional (may be NULL). **/"); + fprintf(f, "\n"); + } + fprintf(f, " };\n"); + fprintf(f, "\n"); + freeFunctionPrototype(el, f, ";"); + fprintf(f, "\n"); + freeListFunctionPrototype(el, f, ";"); + fprintf(f, "\n"); + saveFunctionPrototype(el, f, ";"); + fprintf(f, "\n"); + loadFunctionPrototype(el, f, ";"); + fprintf(f, "\n"); + loadNextFunctionPrototype(el, f, ";"); + fprintf(f, "\n"); + } + +fprintf(f, "#endif /* %s_H */\n", upcPrefix); +fprintf(f, "\n"); +} + +boolean optionalChildren(struct dtdElement *el) +/* Return TRUE if not sure whether you have children. */ +{ +struct dtdElChild *ec; +boolean required = FALSE, optional = FALSE; +for (ec = el->children; ec != NULL; ec = ec->next) + { + if (ec->copyCode == '*' || ec->copyCode == '?') + optional = TRUE; + else + required = TRUE; + } +return !required && optional; +} + +boolean isAtomic(struct dtdElement *el) +/* Return TRUE if by definition no children. */ +{ +return el->textType == NULL && el->children == NULL; +} + +void saveFunctionBody(struct dtdElement *el, FILE *f) +/* Write out save function body. */ +{ +struct dtdElChild *ec; +struct dtdAttribute *att; +boolean optKids = optionalChildren(el); +boolean isAtom = isAtomic(el); + +fprintf(f, "{\n"); + +/* Declare variables to walk through list if need be. */ +for (ec = el->children; ec != NULL; ec = ec->next) + { + if (ec->copyCode == '*' || ec->copyCode == '+') + { + char *name = ec->el->mixedCaseName; + fprintf(f, "struct %s *%s;\n", name, name); + } + } +if (optKids) + fprintf(f, "boolean isNode = TRUE;\n"); + +fprintf(f, "if (obj == NULL) return;\n"); +fprintf(f, "xapIndent(indent, f);\n"); +if (el->attributes == NULL) + { + if (isAtom) + fprintf(f, "fprintf(f, \" ->\\n\");\n"); + else + fprintf(f, "fprintf(f, \"<%s>\");\n", el->name); + } +else + { + fprintf(f, "fprintf(f, \"<%s\");\n", el->name); + for (att = el->attributes; att != NULL; att = att->next) + { + if (att->required ) + fprintf(f, "fprintf(f, \" %s=\\\"%%%c\\\"\", obj->%s);\n", att->name, fAttType(att->type), att->name); + else + { + if (sameString(att->type, "INT") || sameString(att->type, "FLOAT")) + { + if (positiveOnly) + { + fprintf(f, "if (obj->%s >= 0)\n ", att->name); + } + fprintf(f, "fprintf(f, \" %s=\\\"%%%c\\\"\", obj->%s);\n", att->name, fAttType(att->type), att->name); + } + else + { + fprintf(f, "if (obj->%s != NULL)\n", att->name); + fprintf(f, " fprintf(f, \" %s=\\\"%%%c\\\"\", obj->%s);\n", att->name, fAttType(att->type), att->name); + } + } + } + if (isAtom) + fprintf(f, "fprintf(f, \"/>\\n\");\n"); + else + fprintf(f, "fprintf(f, \">\");\n"); + } +if (el->textType != NULL) + { + if (sameString(el->textType, "#INT")) + fprintf(f, "fprintf(f, \"%%d\", obj->%s);\n", textField); + else if (sameString(el->textType, "#FLOAT")) + fprintf(f, "fprintf(f, \"%%f\", obj->%s);\n", textField); + else + fprintf(f, "fprintf(f, \"%%s\", obj->%s);\n", textField); + } +if (isAtom) + { + } +else if (el->children == NULL) + { + fprintf(f, "fprintf(f, \"\\n\");\n", el->name); + } +else + { + if (!optKids) + fprintf(f, "fprintf(f, \"\\n\");\n"); + for (ec = el->children; ec != NULL; ec = ec->next) + { + char *name = ec->el->mixedCaseName; + if (ec->copyCode == '*' || ec->copyCode == '+') + { + fprintf(f, "for (%s = obj->%s; %s != NULL; %s = %s->next)\n", name, name, name, name, name); + fprintf(f, " {\n"); + if (optKids) + { + fprintf(f, " if (isNode)\n"); + fprintf(f, " {\n"); + fprintf(f, " fprintf(f, \"\\n\");\n"); + fprintf(f, " isNode = FALSE;\n"); + fprintf(f, " }\n"); + } + fprintf(f, " %sSave(%s, indent+2, f);\n", name, name); + fprintf(f, " }\n"); + } + else + { + if (optKids) + { + fprintf(f, "if (obj->%s != NULL)\n", name); + fprintf(f, " {\n"); + fprintf(f, " if (isNode)\n"); + fprintf(f, " {\n"); + fprintf(f, " fprintf(f, \"\\n\");\n"); + fprintf(f, " isNode = FALSE;\n"); + fprintf(f, " }\n"); + fprintf(f, " %sSave(obj->%s, indent+2, f);\n", name, name); + fprintf(f, " }\n"); + } + else + fprintf(f, "%sSave(obj->%s, indent+2, f);\n", name, name); + } + } + if (optKids) + { + fprintf(f, "if (!isNode)\n"); + fprintf(f, " xapIndent(indent, f);\n"); + } + else + { + fprintf(f, "xapIndent(indent, f);\n"); + } + fprintf(f, "fprintf(f, \"\\n\");\n", el->name); + } +fprintf(f, "}\n"); +fprintf(f, "\n"); +} + +void freeFunctionBody(struct dtdElement *el, FILE *f) +/* Write out free function body. */ +{ +struct dtdElChild *ec; +struct dtdAttribute *att; + +fprintf(f, "{\n"); +fprintf(f, "struct %s *obj = *pObj;\n", el->mixedCaseName); + +/* Declare variables to walk through list if need be. */ +fprintf(f, "if (obj == NULL) return;\n"); +for (att = el->attributes; att != NULL; att = att->next) + { + if (!sameString(att->type, "INT") && !sameString(att->type, "FLOAT")) + fprintf(f, "freeMem(obj->%s);\n", att->name); + } +if (el->textType != NULL) + { + if (!sameString(el->textType, "#INT") && + !sameString(el->textType, "#FLOAT")) + fprintf(f, "freeMem(obj->text);\n"); + } +for (ec = el->children; ec != NULL; ec = ec->next) + { + char *name = ec->el->mixedCaseName; + if (ec->copyCode == '*' || ec->copyCode == '+') + fprintf(f, "%sFreeList(&obj->%s);\n", name, name); + else + fprintf(f, "%sFree(&obj->%s);\n", name, name); + } +fprintf(f, "freez(pObj);\n"); +fprintf(f, "}\n"); +fprintf(f, "\n"); +} + +void freeListFunctionBody(struct dtdElement *el, FILE *f) +/* Write out free function body. */ +{ +fprintf(f, "{\n"); +fprintf(f, "struct %s *el, *next;\n", el->mixedCaseName); +fprintf(f, "for (el = *pList; el != NULL; el = next)\n"); +fprintf(f, " {\n"); +fprintf(f, " next = el->next;\n"); +fprintf(f, " %sFree(&el);\n", el->mixedCaseName); +fprintf(f, " el = next;\n"); +fprintf(f, " }\n"); +fprintf(f, "}\n"); +fprintf(f, "\n"); +} + + +void makeTestDriver(struct dtdElement *rootEl, FILE *f) +/* Make main routine. */ +{ +char *symName = rootEl->mixedCaseName; +fprintf(f, "int main(int argc, char *argv[])\n"); +fprintf(f, "/* Test driver for %s routines */\n", prefix); +fprintf(f, "{\n"); +fprintf(f, "struct %s *obj;\n", symName); +fprintf(f, "if (argc != 2)\n"); +fprintf(f, " errAbort(\"Please run again with a xml filename.\");\n"); +fprintf(f, "obj = %sLoad(argv[1]);\n", symName); +fprintf(f, "%sSave(obj, 0, stdout);\n", symName); +fprintf(f, "%sFree(&obj);\n", symName); +fprintf(f, "return 0;\n"); +fprintf(f, "}\n"); +} + + +void makeC(struct dtdElement *elList, char *fileName, char *incName) +/* Produce C code file. */ +{ +FILE *f = mustOpen(fileName, "w"); +struct dtdElement *el; +char incFile[128], incExt[64]; + +splitPath(incName, NULL, incFile, incExt); + +fprintf(f, "/* %s.c %s */\n", prefix, fileComment); +fprintf(f, "\n"); +fprintf(f, "#include \"common.h\"\n"); +fprintf(f, "#include \"xap.h\"\n"); +fprintf(f, "#include \"%s%s\"\n", incFile, incExt); +fprintf(f, "\n"); + +fprintf(f, "\n"); +for (el = elList; el != NULL; el = el->next) + { + freeFunctionPrototype(el, f, ""); + freeFunctionBody(el, f); + freeListFunctionPrototype(el, f, ""); + freeListFunctionBody(el, f); + saveFunctionPrototype(el, f, ""); + saveFunctionBody(el, f); + loadFunctionPrototype(el, f, ""); + loadFunctionBody(el, f); + loadNextFunctionPrototype(el, f, ""); + loadNextFunctionBody(el, f); + } +makeStartHandler(elList, f); +makeEndHandler(elList, f); +if (makeMain) + makeTestDriver(elList, f); +} + +void autoXml(char *dtdxFile, char *outRoot) +/* autoXml - Generate structures code and parser for XML file from DTD-like spec. */ +{ +struct dtdElement *elList = NULL; +struct hash *elHash = NULL; +char hName[512], cName[512]; +char outDir[256]; + +splitPath(outRoot, outDir, prefix, NULL); +if (cgiVarExists("prefix")) + strcpy(prefix, cgiString("prefix")); +if (outDir[0] != 0) + makeDir(outDir); +dtdParse(dtdxFile, prefix, textField, &elList, &elHash); +printf("Parsed %d elements in %s\n", slCount(elList), dtdxFile); +sprintf(hName, "%s.h", outRoot); +makeH(elList, hName); +sprintf(cName, "%s.c", outRoot); +makeC(elList, cName, hName); +printf("Generated code in %s\n", cName); +} + +int main(int argc, char *argv[]) +/* Process command line. */ +{ +cgiSpoof(&argc, argv); +textField = cgiUsualString("textField", textField); +fileComment = cgiUsualString("comment", fileComment); +picky = cgiBoolean("picky"); +makeMain = cgiBoolean("main"); +positiveOnly = cgiBoolean("positive"); +if (argc != 3) + usage(); +autoXml(argv[1], argv[2]); +return 0; +}