/home/dko/projects/mobilec/trunk/src/mxml-2.2.2/testmxml.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: testmxml.c,v 1.1 2007/05/23 20:43:28 david_ko Exp $"
00003  *
00004  * Test program for Mini-XML, a small XML-like file parsing library.
00005  *
00006  * Copyright 2003-2005 by Michael Sweet.
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * Contents:
00019  *
00020  *   main()          - Main entry for test program.
00021  *   type_cb()       - XML data type callback for mxmlLoadFile()...
00022  *   whitespace_cb() - Let the mxmlSaveFile() function know when to insert
00023  *                     newlines and tabs...
00024  */
00025 
00026 /*
00027  * Include necessary headers...
00028  */
00029 
00030 #include "config.h"
00031 #include "mxml.h"
00032 #ifdef WIN32
00033 #  include <io.h>
00034 #else
00035 #  include <unistd.h>
00036 #endif /* WIN32 */
00037 #include <fcntl.h>
00038 #ifndef O_BINARY
00039 #  define O_BINARY 0
00040 #endif /* !O_BINARY */
00041 
00042 
00043 /*
00044  * Local functions...
00045  */
00046 
00047 mxml_type_t     type_cb(mxml_node_t *node);
00048 const char      *whitespace_cb(mxml_node_t *node, int where);
00049 
00050 
00051 /*
00052  * 'main()' - Main entry for test program.
00053  */
00054 
00055 int                                     /* O - Exit status */
00056 main(int  argc,                         /* I - Number of command-line args */
00057      char *argv[])                      /* I - Command-line args */
00058 {
00059   int                   i;              /* Looping var */
00060   FILE                  *fp;            /* File to read */
00061   int                   fd;             /* File descriptor */
00062   mxml_node_t           *tree,          /* XML tree */
00063                         *node;          /* Node which should be in test.xml */
00064   mxml_index_t          *ind;           /* XML index */
00065   char                  buffer[16384];  /* Save string */
00066   static const char     *types[] =      /* Strings for node types */
00067                         {
00068                           "MXML_ELEMENT",
00069                           "MXML_INTEGER",
00070                           "MXML_OPAQUE",
00071                           "MXML_REAL",
00072                           "MXML_TEXT"
00073                         };
00074 
00075 
00076  /*
00077   * Check arguments...
00078   */
00079 
00080   if (argc != 2)
00081   {
00082     fputs("Usage: testmxml filename.xml\n", stderr);
00083     return (1);
00084   }
00085 
00086  /*
00087   * Test the basic functionality...
00088   */
00089 
00090   tree = mxmlNewElement(MXML_NO_PARENT, "element");
00091 
00092   if (!tree)
00093   {
00094     fputs("ERROR: No parent node in basic test!\n", stderr);
00095     return (1);
00096   }
00097 
00098   if (tree->type != MXML_ELEMENT)
00099   {
00100     fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_ELEMENT!\n",
00101             tree->type < MXML_ELEMENT || tree->type > MXML_TEXT ?
00102                 "UNKNOWN" : types[tree->type], tree->type);
00103     mxmlDelete(tree);
00104     return (1);
00105   }
00106 
00107   if (strcmp(tree->value.element.name, "element"))
00108   {
00109     fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\"!\n",
00110             tree->value.element.name);
00111     mxmlDelete(tree);
00112     return (1);
00113   }
00114 
00115   mxmlNewInteger(tree, 123);
00116   mxmlNewOpaque(tree, "opaque");
00117   mxmlNewReal(tree, 123.4f);
00118   mxmlNewText(tree, 1, "text");
00119 
00120   mxmlLoadString(tree, "<group type='string'>string string string</group>",
00121                  MXML_NO_CALLBACK);
00122   mxmlLoadString(tree, "<group type='integer'>1 2 3</group>",
00123                  MXML_INTEGER_CALLBACK);
00124   mxmlLoadString(tree, "<group type='real'>1.0 2.0 3.0</group>",
00125                  MXML_REAL_CALLBACK);
00126   mxmlLoadString(tree, "<group>opaque opaque opaque</group>",
00127                  MXML_OPAQUE_CALLBACK);
00128 
00129   node = tree->child;
00130 
00131   if (!node)
00132   {
00133     fputs("ERROR: No first child node in basic test!\n", stderr);
00134     mxmlDelete(tree);
00135     return (1);
00136   }
00137 
00138   if (node->type != MXML_INTEGER)
00139   {
00140     fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_INTEGER!\n",
00141             node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
00142                 "UNKNOWN" : types[node->type], node->type);
00143     mxmlDelete(tree);
00144     return (1);
00145   }
00146 
00147   if (node->value.integer != 123)
00148   {
00149     fprintf(stderr, "ERROR: First child value is %d, expected 123!\n",
00150             node->value.integer);
00151     mxmlDelete(tree);
00152     return (1);
00153   }
00154 
00155   node = node->next;
00156 
00157   if (!node)
00158   {
00159     fputs("ERROR: No second child node in basic test!\n", stderr);
00160     mxmlDelete(tree);
00161     return (1);
00162   }
00163 
00164   if (node->type != MXML_OPAQUE)
00165   {
00166     fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_OPAQUE!\n",
00167             node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
00168                 "UNKNOWN" : types[node->type], node->type);
00169     mxmlDelete(tree);
00170     return (1);
00171   }
00172 
00173   if (!node->value.opaque || strcmp(node->value.opaque, "opaque"))
00174   {
00175     fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\"!\n",
00176             node->value.opaque ? node->value.opaque : "(null)");
00177     mxmlDelete(tree);
00178     return (1);
00179   }
00180 
00181   node = node->next;
00182 
00183   if (!node)
00184   {
00185     fputs("ERROR: No third child node in basic test!\n", stderr);
00186     mxmlDelete(tree);
00187     return (1);
00188   }
00189 
00190   if (node->type != MXML_REAL)
00191   {
00192     fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_REAL!\n",
00193             node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
00194                 "UNKNOWN" : types[node->type], node->type);
00195     mxmlDelete(tree);
00196     return (1);
00197   }
00198 
00199   if (node->value.real != 123.4f)
00200   {
00201     fprintf(stderr, "ERROR: Third child value is %f, expected 123.4!\n",
00202             node->value.real);
00203     mxmlDelete(tree);
00204     return (1);
00205   }
00206 
00207   node = node->next;
00208 
00209   if (!node)
00210   {
00211     fputs("ERROR: No fourth child node in basic test!\n", stderr);
00212     mxmlDelete(tree);
00213     return (1);
00214   }
00215 
00216   if (node->type != MXML_TEXT)
00217   {
00218     fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TEXT!\n",
00219             node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
00220                 "UNKNOWN" : types[node->type], node->type);
00221     mxmlDelete(tree);
00222     return (1);
00223   }
00224 
00225   if (!node->value.text.whitespace ||
00226       !node->value.text.string || strcmp(node->value.text.string, "text"))
00227   {
00228     fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\"!\n",
00229             node->value.text.whitespace,
00230             node->value.text.string ? node->value.text.string : "(null)");
00231     mxmlDelete(tree);
00232     return (1);
00233   }
00234 
00235   for (i = 0; i < 4; i ++)
00236   {
00237     node = node->next;
00238 
00239     if (!node)
00240     {
00241       fprintf(stderr, "ERROR: No group #%d child node in basic test!\n", i + 1);
00242       mxmlDelete(tree);
00243       return (1);
00244     }
00245 
00246     if (node->type != MXML_ELEMENT)
00247     {
00248       fprintf(stderr, "ERROR: Group child #%d has type %s (%d), expected MXML_ELEMENT!\n",
00249               i + 1, node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
00250                          "UNKNOWN" : types[node->type], node->type);
00251       mxmlDelete(tree);
00252       return (1);
00253     }
00254   }
00255 
00256  /*
00257   * Test indices...
00258   */
00259 
00260   ind = mxmlIndexNew(tree, NULL, NULL);
00261   if (!ind)
00262   {
00263     fputs("ERROR: Unable to create index of all nodes!\n", stderr);
00264     mxmlDelete(tree);
00265     return (1);
00266   }
00267 
00268   if (ind->num_nodes != 5)
00269   {
00270     fprintf(stderr, "ERROR: Index of all nodes contains %d "
00271                     "nodes; expected 5!\n", ind->num_nodes);
00272     mxmlIndexDelete(ind);
00273     mxmlDelete(tree);
00274     return (1);
00275   }
00276 
00277   mxmlIndexReset(ind);
00278   if (!mxmlIndexFind(ind, "group", NULL))
00279   {
00280     fputs("ERROR: mxmlIndexFind for \"group\" failed!\n", stderr);
00281     mxmlIndexDelete(ind);
00282     mxmlDelete(tree);
00283     return (1);
00284   }
00285 
00286   mxmlIndexDelete(ind);
00287 
00288   ind = mxmlIndexNew(tree, "group", NULL);
00289   if (!ind)
00290   {
00291     fputs("ERROR: Unable to create index of groups!\n", stderr);
00292     mxmlDelete(tree);
00293     return (1);
00294   }
00295 
00296   if (ind->num_nodes != 4)
00297   {
00298     fprintf(stderr, "ERROR: Index of groups contains %d "
00299                     "nodes; expected 4!\n", ind->num_nodes);
00300     mxmlIndexDelete(ind);
00301     mxmlDelete(tree);
00302     return (1);
00303   }
00304 
00305   mxmlIndexReset(ind);
00306   if (!mxmlIndexEnum(ind))
00307   {
00308     fputs("ERROR: mxmlIndexEnum failed!\n", stderr);
00309     mxmlIndexDelete(ind);
00310     mxmlDelete(tree);
00311     return (1);
00312   }
00313 
00314   mxmlIndexDelete(ind);
00315 
00316   ind = mxmlIndexNew(tree, NULL, "type");
00317   if (!ind)
00318   {
00319     fputs("ERROR: Unable to create index of type attributes!\n", stderr);
00320     mxmlDelete(tree);
00321     return (1);
00322   }
00323 
00324   if (ind->num_nodes != 3)
00325   {
00326     fprintf(stderr, "ERROR: Index of type attributes contains %d "
00327                     "nodes; expected 3!\n", ind->num_nodes);
00328     mxmlIndexDelete(ind);
00329     mxmlDelete(tree);
00330     return (1);
00331   }
00332 
00333   mxmlIndexReset(ind);
00334   if (!mxmlIndexFind(ind, NULL, "string"))
00335   {
00336     fputs("ERROR: mxmlIndexFind for \"string\" failed!\n", stderr);
00337     mxmlIndexDelete(ind);
00338     mxmlDelete(tree);
00339     return (1);
00340   }
00341 
00342   mxmlIndexDelete(ind);
00343 
00344   ind = mxmlIndexNew(tree, "group", "type");
00345   if (!ind)
00346   {
00347     fputs("ERROR: Unable to create index of elements and attributes!\n", stderr);
00348     mxmlDelete(tree);
00349     return (1);
00350   }
00351 
00352   if (ind->num_nodes != 3)
00353   {
00354     fprintf(stderr, "ERROR: Index of elements and attributes contains %d "
00355                     "nodes; expected 3!\n", ind->num_nodes);
00356     mxmlIndexDelete(ind);
00357     mxmlDelete(tree);
00358     return (1);
00359   }
00360 
00361   mxmlIndexReset(ind);
00362   if (!mxmlIndexFind(ind, "group", "string"))
00363   {
00364     fputs("ERROR: mxmlIndexFind for \"string\" failed!\n", stderr);
00365     mxmlIndexDelete(ind);
00366     mxmlDelete(tree);
00367     return (1);
00368   }
00369 
00370   mxmlIndexDelete(ind);
00371 
00372  /*
00373   * Check the mxmlDelete() works properly...
00374   */
00375 
00376   for (i = 0; i < 8; i ++)
00377   {
00378     if (tree->child)
00379       mxmlDelete(tree->child);
00380     else
00381     {
00382       fprintf(stderr, "ERROR: Child pointer prematurely NULL on child #%d\n",
00383               i + 1);
00384       mxmlDelete(tree);
00385       return (1);
00386     }
00387   }
00388 
00389   if (tree->child)
00390   {
00391     fputs("ERROR: Child pointer not NULL after deleting all children!\n", stderr);
00392     return (1);
00393   }
00394 
00395   if (tree->last_child)
00396   {
00397     fputs("ERROR: Last child pointer not NULL after deleting all children!\n", stderr);
00398     return (1);
00399   }
00400 
00401   mxmlDelete(tree);
00402 
00403  /*
00404   * Open the file...
00405   */
00406 
00407   if (argv[1][0] == '<')
00408     tree = mxmlLoadString(NULL, argv[1], type_cb);
00409   else if ((fp = fopen(argv[1], "rb")) == NULL)
00410   {
00411     perror(argv[1]);
00412     return (1);
00413   }
00414   else
00415   {
00416    /*
00417     * Read the file...
00418     */
00419 
00420     tree = mxmlLoadFile(NULL, fp, type_cb);
00421 
00422     fclose(fp);
00423   }
00424 
00425   if (!tree)
00426   {
00427     fputs("Unable to read XML file!\n", stderr);
00428     return (1);
00429   }
00430 
00431   if (!strcmp(argv[1], "test.xml"))
00432   {
00433    /*
00434     * Verify that mxmlFindElement() and indirectly mxmlWalkNext() work
00435     * properly...
00436     */
00437 
00438     if ((node = mxmlFindElement(tree, tree, "choice", NULL, NULL,
00439                                 MXML_DESCEND)) == NULL)
00440     {
00441       fputs("Unable to find first <choice> element in XML tree!\n", stderr);
00442       mxmlDelete(tree);
00443       return (1);
00444     }
00445 
00446     if ((node = mxmlFindElement(node, tree, "choice", NULL, NULL,
00447                                 MXML_NO_DESCEND)) == NULL)
00448     {
00449       fputs("Unable to find second <choice> element in XML tree!\n", stderr);
00450       mxmlDelete(tree);
00451       return (1);
00452     }
00453   }
00454 
00455  /*
00456   * Print the XML tree...
00457   */
00458 
00459   mxmlSaveFile(tree, stdout, whitespace_cb);
00460 
00461  /*
00462   * Save the XML tree to a string and print it...
00463   */
00464 
00465   if (mxmlSaveString(tree, buffer, sizeof(buffer), whitespace_cb) > 0)
00466     fputs(buffer, stderr);
00467 
00468  /*
00469   * Delete the tree...
00470   */
00471 
00472   mxmlDelete(tree);
00473 
00474  /*
00475   * Read from/write to file descriptors...
00476   */
00477 
00478   if (argv[1][0] != '<')
00479   {
00480    /*
00481     * Open the file again...
00482     */
00483 
00484     if ((fd = open(argv[1], O_RDONLY | O_BINARY)) < 0)
00485     {
00486       perror(argv[1]);
00487       return (1);
00488     }
00489 
00490    /*
00491     * Read the file...
00492     */
00493 
00494     tree = mxmlLoadFd(NULL, fd, type_cb);
00495 
00496     close(fd);
00497 
00498    /*
00499     * Create filename.xmlfd...
00500     */
00501 
00502     snprintf(buffer, sizeof(buffer), "%sfd", argv[1]);
00503 
00504     if ((fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) < 0)
00505     {
00506       perror(buffer);
00507       mxmlDelete(tree);
00508       return (1);
00509     }
00510 
00511    /*
00512     * Write the file...
00513     */
00514 
00515     mxmlSaveFd(tree, fd, whitespace_cb);
00516 
00517     close(fd);
00518 
00519    /*
00520     * Delete the tree...
00521     */
00522 
00523     mxmlDelete(tree);
00524   }
00525 
00526  /*
00527   * Return...
00528   */
00529 
00530   return (0);
00531 }
00532 
00533 
00534 /*
00535  * 'type_cb()' - XML data type callback for mxmlLoadFile()...
00536  */
00537 
00538 mxml_type_t                             /* O - Data type */
00539 type_cb(mxml_node_t *node)              /* I - Element node */
00540 {
00541   const char    *type;                  /* Type string */
00542 
00543 
00544  /*
00545   * You can lookup attributes and/or use the element name, hierarchy, etc...
00546   */
00547 
00548   if ((type = mxmlElementGetAttr(node, "type")) == NULL)
00549     type = node->value.element.name;
00550 
00551   if (!strcmp(type, "integer"))
00552     return (MXML_INTEGER);
00553   else if (!strcmp(type, "opaque") || !strcmp(type, "pre"))
00554     return (MXML_OPAQUE);
00555   else if (!strcmp(type, "real"))
00556     return (MXML_REAL);
00557   else
00558     return (MXML_TEXT);
00559 }
00560 
00561 
00562 /*
00563  * 'whitespace_cb()' - Let the mxmlSaveFile() function know when to insert
00564  *                     newlines and tabs...
00565  */
00566 
00567 const char *                            /* O - Whitespace string or NULL */
00568 whitespace_cb(mxml_node_t *node,        /* I - Element node */
00569               int         where)        /* I - Open or close tag? */
00570 {
00571   mxml_node_t   *parent;                /* Parent node */
00572   int           level;                  /* Indentation level */
00573   const char    *name;                  /* Name of element */
00574   static const char *tabs = "\t\t\t\t\t\t\t\t";
00575                                         /* Tabs for indentation */
00576 
00577 
00578  /*
00579   * We can conditionally break to a new line before or after any element.
00580   * These are just common HTML elements...
00581   */
00582 
00583   name = node->value.element.name;
00584 
00585   if (!strcmp(name, "html") || !strcmp(name, "head") || !strcmp(name, "body") ||
00586       !strcmp(name, "pre") || !strcmp(name, "p") ||
00587       !strcmp(name, "h1") || !strcmp(name, "h2") || !strcmp(name, "h3") ||
00588       !strcmp(name, "h4") || !strcmp(name, "h5") || !strcmp(name, "h6"))
00589   {
00590    /*
00591     * Newlines before open and after close...
00592     */
00593 
00594     if (where == MXML_WS_BEFORE_OPEN || where == MXML_WS_AFTER_CLOSE)
00595       return ("\n");
00596   }
00597   else if (!strcmp(name, "dl") || !strcmp(name, "ol") || !strcmp(name, "ul"))
00598   {
00599    /*
00600     * Put a newline before and after list elements...
00601     */
00602 
00603     return ("\n");
00604   }
00605   else if (!strcmp(name, "dd") || !strcmp(name, "dt") || !strcmp(name, "li"))
00606   {
00607    /*
00608     * Put a tab before <li>'s, <dd>'s, and <dt>'s, and a newline after them...
00609     */
00610 
00611     if (where == MXML_WS_BEFORE_OPEN)
00612       return ("\t");
00613     else if (where == MXML_WS_AFTER_CLOSE)
00614       return ("\n");
00615   }
00616   else if (!strcmp(name, "?xml"))
00617   {
00618     return (NULL);
00619   }
00620   else if (where == MXML_WS_BEFORE_OPEN ||
00621            ((!strcmp(name, "choice") || !strcmp(name, "option")) &&
00622             where == MXML_WS_BEFORE_CLOSE))
00623   {
00624     for (level = -1, parent = node->parent;
00625          parent;
00626          level ++, parent = parent->parent);
00627 
00628     if (level > 8)
00629       level = 8;
00630     else if (level < 0)
00631       level = 0;
00632 
00633     return (tabs + 8 - level);
00634   }
00635   else if (where == MXML_WS_AFTER_CLOSE ||
00636            ((!strcmp(name, "group") || !strcmp(name, "option") ||
00637              !strcmp(name, "choice")) &&
00638             where == MXML_WS_AFTER_OPEN))
00639     return ("\n");
00640   else if (where == MXML_WS_AFTER_OPEN && !node->child)
00641     return ("\n");
00642 
00643  /*
00644   * Return NULL for no added whitespace...
00645   */
00646 
00647   return (NULL);
00648 }
00649 
00650 
00651 /*
00652  * End of "$Id: testmxml.c,v 1.1 2007/05/23 20:43:28 david_ko Exp $".
00653  */

Generated on Fri May 16 14:49:55 2008 for Mobile-C by  doxygen 1.5.4