Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

xml.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: xml.c,v 1.33 2004/09/17 18:38:27 rleigh Exp $"
00003  *
00004  *   XML parser - process Gutenprint XML data with mxml.
00005  *
00006  *   Copyright 2002-2003 Roger Leigh (rleigh@debian.org)
00007  *
00008  *   This program is free software; you can redistribute it and/or modify it
00009  *   under the terms of the GNU General Public License as published by the Free
00010  *   Software Foundation; either version 2 of the License, or (at your option)
00011  *   any later version.
00012  *
00013  *   This program is distributed in the hope that it will be useful, but
00014  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00015  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016  *   for more details.
00017  *
00018  *   You should have received a copy of the GNU General Public License
00019  *   along with this program; if not, write to the Free Software
00020  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 #include <gutenprint/gutenprint.h>
00028 #include "gutenprint-internal.h"
00029 #include <gutenprint/gutenprint-intl-internal.h>
00030 #include <assert.h>
00031 #include <ctype.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <math.h>
00036 #include <errno.h>
00037 #ifdef HAVE_LIMITS_H
00038 #include <limits.h>
00039 #endif
00040 #if defined(HAVE_VARARGS_H) && !defined(HAVE_STDARG_H)
00041 #include <varargs.h>
00042 #else
00043 #include <stdarg.h>
00044 #endif
00045 
00046 typedef struct
00047 {
00048   char *name;
00049   stp_xml_parse_func parse_func;
00050 } stpi_xml_parse_registry;
00051 
00052 static stp_list_t *stpi_xml_registry;
00053 
00054 static stp_list_t *stpi_xml_preloads;
00055 
00056 static const char *
00057 xml_registry_namefunc(const void *item)
00058 {
00059   const stpi_xml_parse_registry *xmlp = (const stpi_xml_parse_registry *) item;
00060   return xmlp->name;
00061 }
00062 
00063 static void
00064 xml_registry_freefunc(void *item)
00065 {
00066   stpi_xml_parse_registry *xmlp = (stpi_xml_parse_registry *) item;
00067   stp_free(xmlp->name);
00068   stp_free(xmlp);
00069 }
00070 
00071 static const char *
00072 xml_preload_namefunc(const void *item)
00073 {
00074   return (const char *) item;
00075 }
00076 
00077 static void
00078 xml_preload_freefunc(void *item)
00079 {
00080   stp_free(item);
00081 }
00082 
00083 void
00084 stp_register_xml_parser(const char *name, stp_xml_parse_func parse_func)
00085 {
00086   stpi_xml_parse_registry *xmlp;
00087   stp_list_item_t *item = stp_list_get_item_by_name(stpi_xml_registry, name);
00088   if (item)
00089     xmlp = (stpi_xml_parse_registry *) stp_list_item_get_data(item);
00090   else
00091     {
00092       xmlp = stp_malloc(sizeof(stpi_xml_parse_registry));
00093       xmlp->name = stp_strdup(name);
00094       stp_list_item_create(stpi_xml_registry, NULL, xmlp);
00095     }
00096   xmlp->parse_func = parse_func;
00097 }
00098 
00099 void
00100 stp_unregister_xml_parser(const char *name)
00101 {
00102   stp_list_item_t *item = stp_list_get_item_by_name(stpi_xml_registry, name);
00103   if (item)
00104     stp_list_item_destroy(stpi_xml_registry, item);
00105 }
00106 
00107 void
00108 stp_register_xml_preload(const char *filename)
00109 {
00110   stp_list_item_t *item = stp_list_get_item_by_name(stpi_xml_preloads, filename);
00111   if (!item)
00112     {
00113       char *the_filename = stp_strdup(filename);
00114       stp_list_item_create(stpi_xml_preloads, NULL, the_filename);
00115     }
00116 }
00117 
00118 void
00119 stp_unregister_xml_preload(const char *name)
00120 {
00121   stp_list_item_t *item = stp_list_get_item_by_name(stpi_xml_preloads, name);
00122   if (item)
00123     stp_list_item_destroy(stpi_xml_preloads, item);
00124 }
00125 
00126 
00127 static void stpi_xml_process_gutenprint(stp_mxml_node_t *gutenprint, const char *file);
00128 
00129 static char *saved_lc_collate;                 /* Saved LC_COLLATE */
00130 static char *saved_lc_ctype;                   /* Saved LC_CTYPE */
00131 static char *saved_lc_numeric;                 /* Saved LC_NUMERIC */
00132 static int xml_is_initialised;                 /* Flag for init */
00133 
00134 void
00135 stp_xml_preinit(void)
00136 {
00137   static int xml_is_preinitialized = 0;
00138   if (!xml_is_preinitialized)
00139     {
00140       stpi_xml_registry = stp_list_create();
00141       stp_list_set_freefunc(stpi_xml_registry, xml_registry_freefunc);
00142       stp_list_set_namefunc(stpi_xml_registry, xml_registry_namefunc);
00143       stpi_xml_preloads = stp_list_create();
00144       stp_list_set_freefunc(stpi_xml_preloads, xml_preload_freefunc);
00145       stp_list_set_namefunc(stpi_xml_preloads, xml_preload_namefunc);
00146     }
00147 }    
00148 
00149 /*
00150  * Call before using any of the static functions in this file.  All
00151  * public functions should call this before using any mxml
00152  * functions.
00153  */
00154 void
00155 stp_xml_init(void)
00156 {
00157   if (xml_is_initialised >= 1)
00158     {
00159       xml_is_initialised++;
00160       return;
00161     }
00162 
00163   /* Set some locale facets to "C" */
00164   saved_lc_collate = setlocale(LC_COLLATE, "C");
00165   saved_lc_ctype = setlocale(LC_CTYPE, "C");
00166   saved_lc_numeric = setlocale(LC_NUMERIC, "C");
00167 
00168   xml_is_initialised = 1;
00169 }
00170 
00171 /*
00172  * Call after using any of the static functions in this file.  All
00173  * public functions should call this after using any mxml functions.
00174  */
00175 void
00176 stp_xml_exit(void)
00177 {
00178   if (xml_is_initialised > 1) /* don't restore original state */
00179     {
00180       xml_is_initialised--;
00181       return;
00182     }
00183   else if (xml_is_initialised < 1)
00184     return;
00185 
00186   /* Restore locale */
00187   setlocale(LC_COLLATE, saved_lc_collate);
00188   setlocale(LC_CTYPE, saved_lc_ctype);
00189   setlocale(LC_NUMERIC, saved_lc_numeric);
00190   xml_is_initialised = 0;
00191 }
00192 
00193 void
00194 stp_xml_parse_file_named(const char *name)
00195 {
00196   stp_list_t *dir_list;                  /* List of directories to scan */
00197   stp_list_t *file_list;                 /* List of XML files */
00198   stp_list_item_t *item;                 /* Pointer to current list item */
00199   if (!(dir_list = stp_list_create()))
00200     return;
00201   stp_list_set_freefunc(dir_list, stp_list_node_free_data);
00202   if (getenv("STP_DATA_PATH"))
00203     stp_path_split(dir_list, getenv("STP_DATA_PATH"));
00204   else
00205     stp_path_split(dir_list, PKGXMLDATADIR);
00206   file_list = stp_path_search(dir_list, name);
00207   stp_list_destroy(dir_list);
00208   item = stp_list_get_start(file_list);
00209   while (item)
00210     {
00211       stp_deprintf(STP_DBG_XML,
00212                    "stp_xml_parse_file_named: source file: %s\n",
00213                    (const char *) stp_list_item_get_data(item));
00214       stp_xml_parse_file((const char *) stp_list_item_get_data(item));
00215       item = stp_list_item_next(item);
00216     }
00217   stp_list_destroy(file_list);
00218 }
00219   
00220 
00221 /*
00222  * Read all available XML files.
00223  */
00224 int
00225 stp_xml_init_defaults(void)
00226 {
00227   stp_list_item_t *item;                 /* Pointer to current list item */
00228 
00229   stp_xml_init();
00230 
00231   /* Parse each XML file */
00232   item = stp_list_get_start(stpi_xml_preloads);
00233   while (item)
00234     {
00235       stp_deprintf(STP_DBG_XML, "stp_xml_init_defaults: source file: %s\n",
00236                    (const char *) stp_list_item_get_data(item));
00237       stp_xml_parse_file_named((const char *) stp_list_item_get_data(item));
00238       item = stp_list_item_next(item);
00239     }
00240   stp_list_destroy(stpi_xml_preloads);
00241 
00242   stp_xml_exit();
00243 
00244   return 0;
00245 }
00246 
00247 
00248 /*
00249  * Parse a single XML file.
00250  */
00251 int
00252 stp_xml_parse_file(const char *file) /* File to parse */
00253 {
00254   stp_mxml_node_t *doc;
00255   stp_mxml_node_t *cur;
00256   FILE *fp;
00257 
00258   stp_deprintf(STP_DBG_XML, "stp_xml_parse_file: reading  `%s'...\n", file);
00259 
00260   fp = fopen(file, "r");
00261   if (!fp)
00262     {
00263       stp_erprintf("stp_xml_parse_file: unable to open %s: %s\n", file,
00264                    strerror(errno));
00265       return 1;
00266     }
00267 
00268   stp_xml_init();
00269 
00270   doc = stp_mxmlLoadFile(NULL, fp, STP_MXML_NO_CALLBACK);
00271   fclose(fp);
00272 
00273   cur = doc->child;
00274   while (cur &&
00275          (cur->type != STP_MXML_ELEMENT ||
00276           (strcmp(cur->value.element.name, "gutenprint") != 0 &&
00277            strcmp(cur->value.element.name, "gimp-print") != 0)))
00278     cur = cur->next;
00279 
00280   if (cur == NULL || cur->type != STP_MXML_ELEMENT)
00281     {
00282       stp_erprintf("stp_xml_parse_file: %s: parse error\n", file);
00283       stp_mxmlDelete(doc);
00284       return 1;
00285     }
00286 
00287   if (strcmp(cur->value.element.name, "gutenprint") != 0 &&
00288       strcmp(cur->value.element.name, "gimp-print") != 0)
00289     {
00290       stp_erprintf
00291         ("XML file of the wrong type, root node is %s != (gutenprint || gimp-print)",
00292          cur->value.element.name);
00293       stp_mxmlDelete(doc);
00294       return 1;
00295     }
00296 
00297   /* The XML file was read and is the right format */
00298 
00299   stpi_xml_process_gutenprint(cur, file);
00300   stp_mxmlDelete(doc);
00301 
00302   stp_xml_exit();
00303 
00304   return 0;
00305 }
00306 
00307 /*
00308  * Convert a text string into an integer.
00309  */
00310 long
00311 stp_xmlstrtol(const char *textval)
00312 {
00313   long val; /* The value to return */
00314   val = strtol(textval, (char **)NULL, 10);
00315 
00316   return val;
00317 }
00318 
00319 /*
00320  * Convert a text string into an unsigned int.
00321  */
00322 unsigned long
00323 stp_xmlstrtoul(const char *textval)
00324 {
00325   unsigned long val; /* The value to return */
00326   val = strtoul(textval, (char **)NULL, 10);
00327 
00328   return val;
00329 }
00330 
00331 /*
00332  * Convert a text string into a double.
00333  */
00334 double
00335 stp_xmlstrtod(const char *textval)
00336 {
00337   double val; /* The value to return */
00338   val = strtod(textval, (char **)NULL);
00339 
00340   return val;
00341 }
00342 
00343 
00344 /*
00345  * Find a node in an XML tree.  This function takes an xmlNodePtr,
00346  * followed by a NULL-terminated list of nodes which are required.
00347  * For example stp_xml_get_node(myroot, "gutenprint", "dither") will
00348  * return the first dither node in the tree.  Additional dither nodes
00349  * cannot be accessed with this function.
00350  */
00351 stp_mxml_node_t *
00352 stp_xml_get_node(stp_mxml_node_t *xmlroot, ...)
00353 {
00354   stp_mxml_node_t *child;
00355   va_list ap;
00356   const char *target = NULL;
00357 
00358   va_start(ap, xmlroot);
00359 
00360   child = xmlroot;
00361   target = va_arg(ap, const char *);
00362 
00363   while (target && child)
00364     {
00365       child = stp_mxmlFindElement(child, child, target, NULL, NULL, STP_MXML_DESCEND);
00366       target = va_arg(ap, const char *);
00367     }
00368   va_end(ap);
00369   return child;
00370 }
00371 
00372 static void
00373 stpi_xml_process_node(stp_mxml_node_t *node, const char *file)
00374 {
00375   stp_list_item_t *item =
00376     stp_list_get_item_by_name(stpi_xml_registry, node->value.element.name);
00377   if (item)
00378     {
00379       stpi_xml_parse_registry *xmlp =
00380         (stpi_xml_parse_registry *) stp_list_item_get_data(item);
00381       (xmlp->parse_func)(node, file);
00382     }
00383 }
00384 
00385 /*
00386  * Parse the <gutenprint> root node.
00387  */
00388 static void
00389 stpi_xml_process_gutenprint(stp_mxml_node_t *cur, const char *file) /* The node to parse */
00390 {
00391   stp_mxml_node_t *child;                       /* Child node pointer */
00392 
00393   child = cur->child;
00394   while (child)
00395     {
00396       /* process nodes with corresponding parser */
00397       if (child->type == STP_MXML_ELEMENT)
00398         stpi_xml_process_node(child, file);
00399       child = child->next;
00400     }
00401 }
00402 
00403 /*
00404  * Create a basic gutenprint XML document tree root
00405  */
00406 stp_mxml_node_t *
00407 stp_xmldoc_create_generic(void)
00408 {
00409   stp_mxml_node_t *doc;
00410   stp_mxml_node_t *rootnode;
00411 
00412   /* Create the XML tree */
00413   doc = stp_mxmlNewElement(NULL, "?xml");
00414   stp_mxmlElementSetAttr(doc, "version", "1.0");
00415 
00416   rootnode = stp_mxmlNewElement(doc, "gutenprint");
00417   stp_mxmlElementSetAttr
00418     (rootnode, "xmlns", "http://gimp-print.sourceforge.net/xsd/gp.xsd-1.0");
00419   stp_mxmlElementSetAttr
00420     (rootnode, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
00421   stp_mxmlElementSetAttr
00422     (rootnode, "xsi:schemaLocation",
00423      "http://gimp-print.sourceforge.net/xsd/gp.xsd-1.0 gutenprint.xsd");
00424 
00425   return doc;
00426 }
00427 
00428 
00429 

Generated on Thu Feb 10 19:29:31 2005 for libgutenprint API Reference by  doxygen 1.4.1