Overview of the program and main()

Previous: xmltools index ] [ Top: xmltools index ] [ Next: Data structures: frames and tags ]

The overall layout of the file is pretty much like any single-file C program: includes at the top, followed by type and struct definitions, then globals, then functions, and finally the main function.

The structure of this code is a little weird, because it's generating four executables instead of one. The four are:
xmlsnip#define XMLSNIPexcerpts a named section
xmlreplace#define XMLREPLACE replaces a named section
xmlset#define XMLSET sets an attribute, otherwise not touching the file
xmlinsert#define XMLINSERT inserts stdin somewhere in the tree
All these write to stdout; snip and set can read the source from stdin, but replace and insert need stdin for the thing to be inserted, so a file must be given explicitly.

And now that I notice, none of these defines is used in the main function; they're all out in the handlers, which is appropriate. The main function is short and sweet; it reads the command line (which initializes the global state variables), figures out where the input is coming from, then enters the regular expat loop, as I explain in my expat tutorial. All the real work is done in the handlers.
 
#include <stdio.h>
#include <malloc.h>
#include "xmlparse.h"


See Data structures: frames and tags
See Global variables (state)

See Freeing frames and the stack
See Printing the current stack as a locator
See Handling elements: startElement
See Handling elements: endElement
See Handling non-element data: charData
See Reading the command line


int main(int argc, char * argv[])
{
   char buf[BUFSIZ];
   FILE * in;
   XML_Parser parser;

   init(argc, argv);

   if (!stack.locator) {
     See Print usage description
   }

   if (!infile) {
      in = stdin;
   } else if (!(in = fopen (infile, "r"))) {
      printf ("Unable to open input file %s\n", infile);
      exit (2);
   }
  
   parser = XML_ParserCreate(NULL);

   XML_SetElementHandler(parser, startElement, endElement);
   if (emit_content) XML_SetCharacterDataHandler(parser, charData);

   done = 0;
   finished = 0;

   do {
      size_t len = fread(buf, 1, sizeof(buf), in);
      done = len < sizeof(buf);
      if (!XML_Parse(parser, buf, len, done)) {
         fprintf(stderr,
            "%s at line %d\n",
            XML_ErrorString(XML_GetErrorCode(parser)),
            XML_GetCurrentLineNumber(parser));
         return 1;
      }
   } while (!done && !finished);
   XML_ParserFree(parser);

   free_stack();

   if (emit_tags) printf ("\n");

   if (in != stdin) fclose (in);
   return 0;
}


Print usage description
To print usage, we just print some stuff. In the original version of this program, I made this a separate function print_usage() for readability. In the literate presentation, there's no reason to do that, so I save a whole function call. Ha. You may scoff at that, and in this case of course one piddling function call is trivial -- but the whole concept of breaking functions into smaller functions for readability is obviated by a literate style. OK, end of soapbox.
 
#ifdef XMLSNIP
   printf ("usage: xmlsnip <flags> <location> [<file>]\n");
#endif
#ifdef XMLREPLACE
   printf ("usage: xmlreplace <flags> <location> <file>\n  - Replacement on stdin\n");
#endif
#ifdef XMLSET
   printf ("usage: xmlset <flags> <location> <attr> <new value> [<file>]\n");
#endif
#ifdef XMLINSERT
   printf ("usage: xmlsnip <flags> <insertwhere> <location> <file>\n  - Insert on stdin\n");
#endif
   printf ("  Flags: (not all may make sense for this program; xmltools share the flags.\n");
   printf ("  -c : include comments\n");
   printf ("  -o : exclude elements\n");
   printf ("  -t : exclude nonelement content\n");
   printf ("  -m : exclude the matching tag\n");
   printf ("  -p : include processing instructions (PIs)\n");
   printf ("  -l : include locator when match occurs\n");
Previous: xmltools index ] [ Top: xmltools index ] [ Next: Data structures: frames and tags ]


This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2000, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license.