Scippy

SCIP

Solving Constraint Integer Programs

xmlparse.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file xmldef.h
17  * @brief declarations for XML parsing
18  * @author Thorsten Koch
19  * @author Marc Pfetsch
20  *
21  * If SPEC_LIKE_SPACE_HANDLING is not defined, all LF,CR will be changed into spaces and from a
22  * sequence of spaces only one will be used.
23  *
24  * @todo Implement possibility to avoid the construction of parsing information for certain tags
25  * (and their children). For solution files this would avoid parsing the constraints section.
26  */
27 
28 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
29 
30 #include <blockmemshell/memory.h>
31 
32 #include "xml.h"
33 #include "xmldef.h"
34 
35 
36 #include <sys/types.h>
37 #ifdef WITH_ZLIB
38 #include <unistd.h>
39 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <assert.h>
43 #include <ctype.h>
44 #include <string.h>
45 
46 
47 #define NAME_EXT_SIZE 128
48 #define ATTR_EXT_SIZE 4096
49 #define DATA_EXT_SIZE 4096
50 #define LINE_BUF_SIZE 8192
51 
52 #define xmlError(a, b) xmlErrmsg(a, b, FALSE, __FILE__, __LINE__)
53 
54 
55 /* forward declarations */
56 typedef struct parse_stack_struct PSTACK;
57 typedef struct parse_pos_struct PPOS;
58 
59 /** state of the parser */
61 {
67 };
68 typedef enum parse_state_enum PSTATE;
69 
70 /** Stack as a (singly) linked list. The top element is the current node. */
72 {
75 };
76 
77 /** Store the current position in the file and the state of the parser. */
79 {
80  const char* filename;
83  int pos;
84  int lineno;
85  int nextsym;
86  int lastsym;
89 };
90 
91 
92 /** output error message with corresponding line and position */
93 static void xmlErrmsg(
94  PPOS* ppos,
95  const char* msg,
96  XML_Bool msg_only,
97  const char* file,
98  int line
99  )
100 {
101 #ifndef NDEBUG
102  int ret;
103  assert( ppos != NULL );
104 
105  if ( ! msg_only )
106  {
107  ret = fprintf(stderr, "%s(%d) Error in file %s line %d\n", file, line, ppos->filename, ppos->lineno);
108  assert(ret >= 0);
109 
110  ret = fprintf(stderr, "%s", ppos->buf);
111  assert(ret >= 0);
112 
113  if ( strchr(ppos->buf, '\n') == NULL )
114  {
115  int retc;
116 
117  retc = fputc('\n', stderr);
118  assert(retc != EOF);
119  }
120 
121  ret = fprintf(stderr, "%*s\n", ppos->pos, "^");
122  assert(ret >= 0);
123  }
124  ret = fprintf(stderr, "%s\n\n", msg);
125  assert(ret >= 0);
126 
127 #else
128 
129  if ( ! msg_only )
130  {
131  (void) fprintf(stderr, "%s(%d) Error in file %s line %d\n", file, line, ppos->filename, ppos->lineno);
132 
133  (void) fprintf(stderr, "%s", ppos->buf);
134 
135  if ( strchr(ppos->buf, '\n') == NULL )
136  {
137  (void) fputc('\n', stderr);
138  }
139 
140  (void) fprintf(stderr, "%*s\n", ppos->pos, "^");
141  }
142  (void) fprintf(stderr, "%s\n\n", msg);
143 #endif
144 }
145 
146 
147 /** Push new element on the parse stack.
148  *
149  * TRUE if it worked, FAILURE otherwise.
150  */
151 static
153  PPOS* ppos,
154  XML_NODE* node
155  )
156 {
157  PSTACK* p;
158 
159  assert(ppos != NULL);
160  assert(node != NULL);
161 
162  debugMessage("Pushing %s\n", node->name);
163 
165  assert(p != NULL);
166 
167  p->node = node;
168  p->next = ppos->top;
169  ppos->top = p;
170 
171  return TRUE;
172 }
173 
174 /** returns top element on stack (which has to be present) */
176  const PPOS* ppos
177  )
178 {
179  assert(ppos != NULL);
180  assert(ppos->top != NULL);
181 
182  return ppos->top->node;
183 }
184 
185 /** remove top element from stack and deletes it
186  *
187  * TRUE if ok, FALSE otherwise
188  */
189 static
191  PPOS* ppos /**< input stream position */
192  )
193 {
194  PSTACK* p;
195  XML_Bool result;
196 
197  assert(ppos != NULL);
198 
199  if ( ppos->top == NULL )
200  {
201  xmlError(ppos, "Stack underflow");
202  result = FALSE;
203  }
204  else
205  {
206  result = TRUE;
207  p = ppos->top;
208  ppos->top = p->next;
209 
210  debugMessage("Poping %s\n", p->node->name);
211  BMSfreeMemory(&p);
212  }
213  return result;
214 }
215 
216 /** remove complete stack */
217 static
219  PPOS* ppos
220  )
221 {
222  assert(ppos != NULL);
223 
224  while ( ppos->top != NULL )
225  (void) popPstack(ppos);
226 }
227 
228 /** Returns the next character from the input buffer and fills the buffer if it is empty (similar to
229  * fgetc()).
230  */
231 static
232 int mygetc(
233  PPOS* ppos
234  )
235 {
236  assert(ppos != NULL);
237  assert(ppos->fp != NULL);
238  assert(ppos->pos < LINE_BUF_SIZE);
239 
240  if ( ppos->buf[ppos->pos] == '\0' )
241  {
242 #if 0
243  if ( NULL == FGETS(ppos->buf, sizeof(ppos->buf), ppos->fp) )
244  return EOF;
245 #else
246  size_t len = (size_t) FREAD(ppos->buf, sizeof(ppos->buf) - 1, ppos->fp);
247 
248  if( len == 0 || len > sizeof(ppos->buf) - 1 )
249  return EOF;
250 
251  ppos->buf[len] = '\0';
252 #endif
253  ppos->pos = 0;
254  }
255  return (unsigned char)ppos->buf[ppos->pos++];
256 }
257 
258 
259 #ifdef SPEC_LIKE_SPACE_HANDLING
260 /** Read input from fp_in.
261  *
262  * If there is a LF, CR, CR/LF, or LF/CR it returns exactly on LF. Also counts the number of
263  * characters.
264  */
265 static
266 int getsymbol(
267  PPOS* ppos
268  )
269 {
270  int c;
271 
272  assert(ppos != NULL);
273 
274  if ( ppos->nextsym == 0 )
275  c = mygetc(ppos);
276  else
277  {
278  c = ppos->nextsym;
279  ppos->nextsym = 0;
280  }
281  assert(ppos->nextsym == 0);
282 
283  if (((c == '\n') && (ppos->lastsym == '\r')) || ((c == '\r') && (ppos->lastsym == '\n')))
284  c = mygetc(ppos);
285 
286  ppos->lastsym = c;
287 
288  if ( c == '\r' )
289  c = '\n';
290 
291  if ( c == '\n' )
292  ++ppos->lineno;
293 
294  return c;
295 }
296 #else
297 /** Read input from fp_in (variant).
298  *
299  * Here we convert all LF or CR into SPACE and return maximally one SPACE after the other.
300  *
301  * @note This function counts lines differently. On systems that have only one '\\r' as line feed
302  * (MAC) it does not count correctly.
303  */
304 static
306  PPOS* ppos
307  )
308 {
309  int c;
310 
311  assert(ppos != NULL);
312 
313  do
314  {
315  if ( ppos->nextsym == 0 )
316  c = mygetc(ppos);
317  else
318  {
319  c = ppos->nextsym;
320  ppos->nextsym = 0;
321  }
322  assert(ppos->nextsym == 0);
323 
324  if ( c == '\n' )
325  ++ppos->lineno;
326 
327  if ((c == '\n') || (c == '\r'))
328  c = ' ';
329  } while((c == ' ') && (ppos->lastsym == c));
330 
331  ppos->lastsym = c;
332 
333  debugMessage("[%c]\n", c);
334 
335  return c;
336 }
337 #endif
338 
339 /** Reinserts a character into the input stream */
340 static
342  PPOS* ppos,
343  int c
344  )
345 {
346  assert(ppos != NULL);
347  assert(ppos->nextsym == 0);
348 
349  ppos->nextsym = c;
350 }
351 
352 /** Skip all spaces and return the next non-space character or EOF */
353 static
355  PPOS* ppos
356  )
357 {
358  int c;
359 
360  assert(ppos != NULL);
361 
362  do
363  {
364  c = getsymbol(ppos);
365  }
366  while(isspace(c));
367 
368  return c;
369 }
370 
371 /** Get name of a TAG or attribute from the input stream.
372  *
373  * Either it returns a pointer to allocated memory which contains the name or it returns NULL if
374  * there is some error.
375  */
376 static
377 char* getName(
378  PPOS* ppos
379  )
380 {
381  char* name = NULL;
382  size_t size = 0;
383  size_t len = 0;
384  int c;
385 
386  assert(ppos != NULL);
387 
388  c = getsymbol(ppos);
389 
390  if ( ! isalpha(c) && (c != '_') && (c != ':') )
391  {
392  xmlError(ppos, "Name starting with illegal charater");
393  return NULL;
394  }
395 
396  /* The following is wrong: Here almost all characters that we casted to unicode are feasible */
397  while ( isalnum(c) || (c == '_') || (c == ':') || (c == '.') || (c == '-') )
398  {
399  if ( len + 1 >= size )
400  {
401  size += NAME_EXT_SIZE;
402 
403  if ( name == NULL )
404  {
405  ALLOC_ABORT( BMSallocMemoryArray(&name, size) );
406  }
407  else
408  {
409  ALLOC_ABORT( BMSreallocMemoryArray(&name, size) );
410  }
411  }
412  assert(name != NULL);
413  assert(size > len);
414 
415  name[len++] = (char)c;
416 
417  c = getsymbol(ppos);
418  }
419  if ( c != EOF )
420  ungetsymbol(ppos, c);
421 
422  assert(name != NULL);
423 
424  if ( len == 0 )
425  {
426  BMSfreeMemoryArray(&name);
427  name = NULL;
428  }
429  else
430  name[len] = '\0';
431 
432  return name;
433 }
434 
435 /** Read the value of an attribute from the input stream.
436  *
437  * The value has to be between two " or ' (the other character is then valid as well). The function
438  * returns a pointer to allocated memory containing the value or it returns NULL in case of an
439  * error.
440  */
441 static
443  PPOS* ppos
444  )
445 {
446  char* attr = NULL;
447  int c;
448  int stop;
449  size_t len = 0;
450  size_t size = 0;
451 
452  assert(ppos != NULL);
453 
454  /* The following is not allowed according to the specification (the value has to be directly
455  * after the equation sign). */
456  c = skipSpace(ppos);
457 
458  if ( (c != '"') && (c != '\'') )
459  {
460  xmlError(ppos, "Atribute value does not start with \" or \'");
461  return NULL;
462  }
463  stop = c;
464 
465  for(;;)
466  {
467  if ( len == size )
468  {
469  size += ATTR_EXT_SIZE;
470 
471  if ( attr == NULL )
472  {
473  ALLOC_ABORT( BMSallocMemoryArray(&attr, size) );
474  }
475  else
476  {
477  ALLOC_ABORT( BMSreallocMemoryArray(&attr, size) );
478  }
479  }
480  assert(attr != NULL);
481  assert(size > len);
482 
483  c = getsymbol(ppos);
484 
485  if ( (c == stop) || (c == EOF) )
486  break;
487 
488  attr[len++] = (char)c;
489  }
490 
491  if ( c != EOF )
492  attr[len] = '\0';
493  else
494  {
495  BMSfreeMemoryArray(&attr);
496  attr = NULL;
497  }
498  return attr;
499 }
500 
501 /** Skip comment
502  *
503  * Return FALSE if an error occurs.
504  */
505 static
507  PPOS* ppos
508  )
509 {
510  XML_Bool result = TRUE;
511  int c;
512  int state = 0;
513 
514  assert(ppos != NULL);
515 
516  for(;;)
517  {
518  c = getsymbol(ppos);
519 
520  if ( c == EOF )
521  break;
522 
523  if ( (c == '>') && (state >= 2) )
524  break;
525 
526  state = (c == '-') ? state + 1 : 0;
527  }
528  if ( c == EOF )
529  {
530  xmlError(ppos, "Unexpected EOF in comment");
531  result = FALSE;
532  }
533  return result;
534 }
535 
536 /** Handles a CDATA section.
537  *
538  * Returns a pointer to allocated memory containing the data of this section or NULL in case of an
539  * error.
540  */
541 static
542 char* doCdata(
543  PPOS* ppos
544  )
545 {
546  char* data = NULL;
547  size_t size = 0;
548  size_t len = 0;
549  int state = 0;
550  int c;
551 
552  assert(ppos != NULL);
553 
554  for(;;)
555  {
556  c = getsymbol(ppos);
557 
558  if ( c == EOF )
559  break;
560 
561  if ( c == ']' )
562  state++;
563  else
564  if ( (c == '>') && (state >= 2) )
565  break;
566  else
567  state = 0;
568 
569  if ( len == size )
570  {
571  size += DATA_EXT_SIZE;
572 
573  if ( data == NULL )
574  {
575  ALLOC_ABORT( BMSallocMemoryArray(&data, size) );
576  }
577  else
578  {
579  ALLOC_ABORT( BMSreallocMemoryArray(&data, size) );
580  }
581  }
582  assert(data != NULL);
583  assert(size > len);
584 
585  data[len++] = (char)c;
586  }
587  assert(data != NULL);
588 
589  /*lint --e{527}*/
590  if ( c != EOF )
591  {
592  assert(len >= 2);
593  assert(data != NULL);
594 
595  data[len - 2] = '\0'; /*lint !e413*/
596  }
597  else
598  {
599  BMSfreeMemoryArray(&data);
600  data = NULL;
601  xmlError(ppos, "Unexpected EOF in CDATA");
602  }
603  return data;
604 }
605 
606 /** Handle processing instructions (skipping) */
607 static
608 void handlePi(
609  PPOS* ppos
610  )
611 {
612  int c;
613 
614  assert(ppos != NULL);
615  assert(ppos->state == XML_STATE_BEFORE);
616 
617  do
618  {
619  c = getsymbol(ppos);
620  }
621  while ( (c != EOF) && (c != '>') );
622 
623  if ( c != EOF )
624  ppos->state = XML_STATE_PCDATA;
625  else
626  {
627  xmlError(ppos, "Unexpected EOF in PI");
628  ppos->state = XML_STATE_ERROR;
629  }
630 }
631 
632 /** Handles declarations that start with a <!.
633  *
634  * This includes comments. Does currenlty not work very well, because of DTDs.
635  */
636 static
638  PPOS* ppos
639  )
640 {
641  enum XmlSection
642  {
643  IS_COMMENT,
644  IS_ATTLIST,
645  IS_DOCTYPE,
646  IS_ELEMENT,
647  IS_ENTITY,
648  IS_NOTATION,
649  IS_CDATA
650  };
651  typedef enum XmlSection XMLSECTION;
652 
653  static struct
654  {
655  const char* name;
656  XMLSECTION what;
657  } key[] =
658  {
659  { "--", IS_COMMENT },
660  { "ATTLIST", IS_ATTLIST },
661  { "DOCTYPE", IS_DOCTYPE },
662  { "ELEMENT", IS_ELEMENT },
663  { "ENTITY", IS_ENTITY },
664  { "NOTATION", IS_NOTATION },
665  { "[CDATA[", IS_CDATA }
666  };
667  XML_NODE* node;
668  char* data;
669  int c;
670  int k = 0;
671  int beg = 0;
672  int end;
673 
674  assert(ppos != NULL);
675  assert(ppos->state == XML_STATE_BEFORE);
676 
677  end = (int) (sizeof(key) / sizeof(key[0])) - 1;
678  do
679  {
680  c = getsymbol(ppos);
681 
682  for(; (beg <= end) && (c != key[beg].name[k]); beg++)
683  ;
684  for(; (end >= beg) && (c != key[end].name[k]); end--)
685  ;
686  k++;
687  } while(beg < end);
688 
689  if ( beg != end )
690  {
691  xmlError(ppos, "Unknown declaration");
692 
693  while ( (c != EOF) && (c != '>') )
694  c = getsymbol(ppos);
695  }
696  else
697  {
698  assert(beg == end);
699  assert(beg < (int)(sizeof(key) / sizeof(*key)));
700 
701  switch(key[beg].what)
702  {
703  case IS_COMMENT :
704  if ( doComment(ppos) )
705  ppos->state = XML_STATE_ERROR;
706  break;
707  case IS_CDATA :
708  if ( (data = doCdata(ppos)) == NULL )
709  ppos->state = XML_STATE_ERROR;
710  else
711  {
712  if ( NULL == (node = xmlNewNode("#CDATA", ppos->lineno)) )
713  {
714  xmlError(ppos, "Can't create new node");
715  ppos->state = XML_STATE_ERROR;
716  }
717  else
718  {
719  BMSduplicateMemoryArray(&node->data, data, strlen(data)+1);
720  BMSfreeMemoryArray(&data);
721  xmlAppendChild(topPstack(ppos), node);
722  }
723  }
724  break;
725  case IS_ATTLIST :
726  case IS_ELEMENT :
727  case IS_NOTATION :
728  case IS_ENTITY :
729  case IS_DOCTYPE :
730  break;
731  default :
732  abort();
733  }
734  }
735 }
736 
737 /** Handle end tag */
738 static
740  PPOS* ppos
741  )
742 {
743  char* name;
744  int c;
745 
746  assert(ppos != NULL);
747 
748  if ( (name = getName(ppos)) == NULL )
749  xmlError(ppos, "Missing name in endtag");
750  else
751  {
752  c = skipSpace(ppos);
753 
754  if ( c != '>' )
755  {
756  xmlError(ppos, "Missing '>' in endtag");
757  ppos->state = XML_STATE_ERROR;
758  }
759  else
760  {
761  if ( strcmp(name, topPstack(ppos)->name) )
762  {
763  xmlError(ppos, "Name of endtag does not match starttag");
764  ppos->state = XML_STATE_ERROR;
765  }
766  else
767  {
768  if ( popPstack(ppos) )
769  ppos->state = XML_STATE_PCDATA;
770  else
771  ppos->state = XML_STATE_ERROR;
772  }
773  BMSfreeMemoryArray(&name);
774  }
775  }
776 }
777 
778 /** Handle start tag */
779 static
781  PPOS* ppos
782  )
783 {
784  XML_NODE* node;
785  char* name;
786 
787  assert(ppos != NULL);
788 
789  name = getName(ppos);
790  if ( name == NULL )
791  {
792  xmlError(ppos, "Missing name in tagstart");
793  ppos->state = XML_STATE_ERROR;
794  }
795  else
796  {
797  node = xmlNewNode(name, ppos->lineno);
798  if ( node == NULL )
799  {
800  xmlError(ppos, "Can't create new node");
801  ppos->state = XML_STATE_ERROR;
802  }
803  else
804  {
805  xmlAppendChild(topPstack(ppos), node);
806 
807  if ( pushPstack(ppos, node) )
808  ppos->state = XML_STATE_IN_TAG;
809  else
810  ppos->state = XML_STATE_ERROR;
811  }
812  BMSfreeMemoryArray(&name);
813  }
814 }
815 
816 /** Checks for next tag */
817 static
819  PPOS* ppos /**< input stream position */
820  )
821 {
822  int c;
823 
824  assert(ppos != NULL);
825  assert(ppos->state == XML_STATE_BEFORE);
826 
827  c = skipSpace(ppos);
828 
829  if ( c != '<' )
830  {
831  xmlError(ppos, "Expecting '<'");
832  ppos->state = XML_STATE_ERROR;
833  }
834  else
835  {
836  c = getsymbol(ppos);
837 
838  switch(c)
839  {
840  case EOF :
841  xmlError(ppos, "Unexpected EOF");
842  ppos->state = XML_STATE_ERROR;
843  break;
844  case '!' :
845  handleDecl(ppos);
846  break;
847  case '?' :
848  handlePi(ppos);
849  break;
850  case '/' :
851  handleEndtag(ppos);
852  break;
853  default :
854  ungetsymbol(ppos, c);
855  handleStarttag(ppos);
856  break;
857  }
858  }
859 }
860 
861 /** Process tag */
862 static
864  PPOS* ppos /**< input stream position */
865  )
866 {
867  XML_ATTR* attr;
868  int c;
869  XML_Bool empty = FALSE;
870  char* name;
871  char* value;
872 
873  assert(ppos != NULL);
874  assert(ppos->state == XML_STATE_IN_TAG);
875 
876  c = skipSpace(ppos);
877 
878  if ( (c == '/') || (c == '>') || (c == EOF) )
879  {
880  if ( c == '/' )
881  {
882  empty = TRUE;
883  c = getsymbol(ppos);
884  }
885 
886  if ( c == EOF )
887  {
888  xmlError(ppos, "Unexpected EOF while in a tag");
889  ppos->state = XML_STATE_ERROR;
890  }
891 
892  if ( c == '>' )
893  {
894  ppos->state = XML_STATE_PCDATA;
895 
896  if (empty && ! popPstack(ppos))
897  ppos->state = XML_STATE_ERROR;
898  }
899  else
900  {
901  xmlError(ppos, "Expected tag end marker '>'");
902  ppos->state = XML_STATE_ERROR;
903  }
904  }
905  else
906  {
907  ungetsymbol(ppos, c);
908 
909  name = getName(ppos);
910  if ( name == NULL )
911  {
912  xmlError(ppos, "No name for attribute");
913  ppos->state = XML_STATE_ERROR;
914  }
915  else
916  {
917  c = skipSpace(ppos);
918 
919  if ( (c != '=') || ((value = getAttrval(ppos)) == NULL) )
920  {
921  xmlError(ppos, "Missing attribute value");
922  ppos->state = XML_STATE_ERROR;
923  BMSfreeMemoryArray(&name);
924  }
925  else
926  {
927  attr = xmlNewAttr(name, value);
928  if ( attr == NULL )
929  {
930  xmlError(ppos, "Can't create new attribute");
931  ppos->state = XML_STATE_ERROR;
932  }
933  else
934  {
935  xmlAddAttr(topPstack(ppos), attr);
936  }
937  BMSfreeMemoryArray(&name);
938  BMSfreeMemoryArray(&value);
939  }
940  }
941  }
942 }
943 
944 /* Handles PCDATA */
945 static
947  PPOS* ppos /**< input stream position */
948  )
949 {
950  XML_NODE* node;
951  char* data = NULL;
952  size_t size = 0;
953  size_t len = 0;
954  int c;
955 
956  assert(ppos != NULL);
957  assert(ppos->state == XML_STATE_PCDATA);
958 
959 #ifndef SPEC_LIKE_SPACE_HANDLING
960  c = skipSpace(ppos);
961  if ( c != EOF )
962  ungetsymbol(ppos, c);
963 #endif
964  c = getsymbol(ppos);
965 
966  while ( (c != EOF) && (c != '<') )
967  {
968  if ( len + 1 >= size ) /* leave space for terminating '\0' */
969  {
970  size += DATA_EXT_SIZE;
971 
972  if ( data == NULL )
973  {
974  ALLOC_ABORT( BMSallocMemoryArray(&data, size) );
975  }
976  else
977  {
978  ALLOC_ABORT( BMSreallocMemoryArray(&data, size) );
979  }
980  }
981  assert(data != NULL);
982  assert(size > len + 1);
983 
984  data[len++] = (char)c;
985 
986  c = getsymbol(ppos);
987  }
988  if ( data == NULL )
989  {
990  if ( c == EOF )
991  ppos->state = XML_STATE_EOF;
992  else if ( c == '<' )
993  {
994  ppos->state = XML_STATE_BEFORE;
995  ungetsymbol(ppos, c);
996  }
997  else
998  {
999  ppos->state = XML_STATE_ERROR;
1000  }
1001  }
1002  else
1003  {
1004  assert(len < size);
1005  data[len] = '\0';
1006 
1007  if ( c == EOF )
1008  ppos->state = XML_STATE_ERROR;
1009  else
1010  {
1011  ungetsymbol(ppos, c);
1012 
1013  node = xmlNewNode("#PCDATA", ppos->lineno);
1014  if ( node == NULL )
1015  {
1016  xmlError(ppos, "Can't create new node");
1017  ppos->state = XML_STATE_ERROR;
1018  }
1019  else
1020  {
1021  BMSduplicateMemoryArray(&node->data, data, strlen(data)+1);
1022  xmlAppendChild(topPstack(ppos), node);
1023  ppos->state = XML_STATE_BEFORE;
1024  }
1025  BMSfreeMemoryArray(&data);
1026  }
1027  }
1028 }
1029 
1030 /** Parse input stream */
1031 static
1033  PPOS* ppos /**< input stream position */
1034  )
1035 {
1036  XML_Bool ok = TRUE;
1037 
1038  while (ok)
1039  {
1040  debugMessage("state=%d\n", ppos->state);
1041 
1042  switch (ppos->state)
1043  {
1044  case XML_STATE_BEFORE :
1045  procBefore(ppos);
1046  break;
1047  case XML_STATE_IN_TAG :
1048  procInTag(ppos);
1049  break;
1050  case XML_STATE_PCDATA :
1051  procPcdata(ppos);
1052  break;
1053  case XML_STATE_EOF :
1054  ok = FALSE;
1055  break;
1056  case XML_STATE_ERROR :
1057  ok = FALSE;
1058  break;
1059  default :
1060  xmlError(ppos, "Internal Error, illegal state");
1061  ok = FALSE;
1062  }
1063  }
1064  return (ppos->state == XML_STATE_EOF);
1065 }
1066 
1067 /** Parse file */
1069  const char* filename /**< XML file name */
1070  )
1071 {
1072  PPOS ppos;
1073  XML_NODE* node = NULL;
1074  XML_ATTR* attr;
1075  XML_Bool result = FALSE;
1076  char* myfilename;
1077  size_t filenamelen;
1078 
1079  /* allocate space and copy filename (possibly modified below) in two steps in order to satisfy valgrind */
1080  assert( filename != NULL );
1081  filenamelen = strlen(filename);
1082  if ( BMSallocMemoryArray(&myfilename, filenamelen + 5) == NULL )
1083  return NULL;
1084  BMScopyMemoryArray(myfilename, filename, filenamelen + 1);
1085 
1086 #ifdef WITH_ZLIB
1087  if ( access(filename, R_OK) != 0 )
1088  {
1089  strcat(myfilename, ".gz");
1090 
1091  /* If .gz also does not work, revert to the old name
1092  * to get a better error message.
1093  */
1094  if ( access(myfilename, R_OK) != 0 )
1095  strcpy(myfilename, filename);
1096  }
1097 #endif
1098  ppos.fp = FOPEN(myfilename, "r");
1099  if ( ppos.fp == NULL )
1100  perror(myfilename);
1101  else
1102  {
1103  ppos.filename = myfilename;
1104  ppos.buf[0] = '\0';
1105  ppos.pos = 0;
1106  ppos.lineno = 1;
1107  ppos.nextsym = 0;
1108  ppos.lastsym = 0;
1109  ppos.state = XML_STATE_BEFORE;
1110  ppos.top = NULL;
1111 
1112  node = xmlNewNode("#ROOT", ppos.lineno);
1113  if ( node == NULL )
1114  {
1115  xmlError(&ppos, "Can't create new node");
1116  }
1117  else
1118  {
1119  attr = xmlNewAttr("filename", myfilename);
1120  if ( attr == NULL )
1121  xmlError(&ppos, "Can't create new attribute");
1122  else
1123  {
1124  xmlAddAttr(node, attr);
1125 
1126  /* push root node on stack and start to process */
1127  if ( pushPstack(&ppos, node) )
1128  {
1129  result = xmlParse(&ppos);
1130 
1131  clearPstack(&ppos);
1132  }
1133  }
1134  }
1135 
1136  if ( ! result && (node != NULL) )
1137  {
1138  xmlErrmsg(&ppos, "Parsing error, processing stopped", TRUE, __FILE__, __LINE__);
1139  xmlFreeNode(node);
1140  node = NULL;
1141  }
1142  if ( FCLOSE(ppos.fp) )
1143  perror(myfilename);
1144  }
1145  BMSfreeMemoryArray(&myfilename);
1146 
1147  return node;
1148 }
1149 
1150 
1151 
1152 
1153 
1154 
1155 /*----------------------------------------------------------------------------------------------*/
1156 
1157 
1158 /** create new node */
1160  const char* name,
1161  int lineno
1162  )
1163 {
1164  XML_NODE* n = NULL;
1165 
1166  assert(name != NULL);
1167 
1168  if ( BMSallocMemory(&n) != NULL )
1169  {
1170  BMSclearMemory(n);
1171  BMSduplicateMemoryArray(&n->name, name, strlen(name)+1);
1172  n->lineno = lineno;
1173  }
1174  return n;
1175 }
1176 
1177 /** create new attribute */
1179  const char* name,
1180  const char* value
1181  )
1182 {
1183  XML_ATTR* a = NULL;
1184 
1185  assert(name != NULL);
1186  assert(value != NULL);
1187 
1188  if ( BMSallocMemory(&a) != NULL )
1189  {
1190  BMSclearMemory(a);
1191  BMSduplicateMemoryArray(&a->name, name, strlen(name)+1);
1192  BMSduplicateMemoryArray(&a->value, value, strlen(value)+1);
1193  }
1194  return a;
1195 }
1196 
1197 /** add attribute */
1199  XML_NODE* n,
1200  XML_ATTR* a
1201  )
1202 {
1203  assert(n != NULL);
1204  assert(a != NULL);
1205 
1206  a->next = n->attrlist;
1207  n->attrlist = a;
1208 }
1209 
1210 /** append child node */
1212  XML_NODE* parent,
1213  XML_NODE* child
1214  )
1215 {
1216  assert(parent != NULL);
1217  assert(child != NULL);
1218 
1219  child->parent = parent;
1220  child->prevsibl = parent->lastchild;
1221  child->nextsibl = NULL;
1222  parent->lastchild = child;
1223 
1224  if ( child->prevsibl != NULL )
1225  child->prevsibl->nextsibl = child;
1226 
1227  if ( parent->firstchild == NULL )
1228  parent->firstchild = child;
1229 }
1230 
1231 /** free attribute */
1232 static
1234  XML_ATTR* attr
1235  )
1236 {
1237  XML_ATTR* a;
1238 
1239  a = attr;
1240  while (a != NULL)
1241  {
1242  XML_ATTR* b;
1243  b = a->next;
1244 
1245  assert(a->name != NULL);
1246  assert(a->value != NULL);
1247 
1248  BMSfreeMemoryArray(&a->name);
1249  BMSfreeMemoryArray(&a->value);
1250  BMSfreeMemory(&a);
1251  a = b;
1252  }
1253 
1254 #if 0
1255  if (a != NULL)
1256  {
1257  xmlFreeAttr(a->next);
1258 
1259  assert(a->name != NULL);
1260  assert(a->value != NULL);
1261 
1262  BMSfreeMemoryArray(&a->name);
1263  BMSfreeMemoryArray(&a->value);
1264  BMSfreeMemory(&a);
1265  }
1266 #endif
1267 }
1268 
1269 /** free node */
1271  XML_NODE* node
1272  )
1273 {
1274  XML_NODE* n;
1275 
1276  if ( node == NULL )
1277  return;
1278 
1279  /* free data from back to front (because free is faster this way) */
1280  n = node->lastchild;
1281  while ( n != NULL )
1282  {
1283  XML_NODE* m;
1284  m = n->prevsibl;
1285  xmlFreeNode(n);
1286  n = m;
1287  }
1288 
1289  xmlFreeAttr(node->attrlist);
1290 
1291  if ( node->data != NULL )
1292  {
1293  BMSfreeMemoryArray(&node->data);
1294  }
1295  assert(node->name != NULL);
1296 
1297  BMSfreeMemoryArray(&node->name);
1298  BMSfreeMemory(&node);
1299 
1300 #if 0
1301  if ( n != NULL )
1302  {
1303  xmlFreeNode(n->firstchild);
1304  xmlFreeNode(n->nextsibl);
1305  xmlFreeAttr(n->attrlist);
1306 
1307  if ( n->data != NULL )
1308  {
1309  BMSfreeMemoryArray(&n->data);
1310  }
1311  assert(n->name != NULL);
1312 
1313  BMSfreeMemoryArray(&n->name);
1314  BMSfreeMemory(&n);
1315  }
1316 #endif
1317 }
1318 
1319 /** output node */
1321  const XML_NODE* root
1322  )
1323 {
1324  const XML_NODE* n;
1325  const XML_ATTR* a;
1326 
1327  assert(root != NULL);
1328 
1329  for (n = root; n != NULL; n = n->nextsibl)
1330  {
1331  infoMessage("Name: %s\n", n->name);
1332  infoMessage("Line: %d\n", n->lineno);
1333  infoMessage("Data: %s\n", (n->data != NULL) ? n->data : "***");
1334 
1335  for (a = n->attrlist; a != NULL; a = a->next)
1336  infoMessage("Attr: %s = [%s]\n", a->name, a->value);
1337 
1338  if ( n->firstchild != NULL )
1339  {
1340  infoMessage("->\n");
1341  xmlShowNode(n->firstchild);
1342  infoMessage("<-\n");
1343  }
1344  }
1345 }
1346 
1347 /** get attribute value */
1348 const char* xmlGetAttrval(
1349  const XML_NODE* node,
1350  const char* name
1351  )
1352 {
1353  XML_ATTR* a;
1354 
1355  assert(node != NULL);
1356  assert(name != NULL);
1357 
1358  for (a = node->attrlist; a != NULL; a = a->next)
1359  {
1360  if ( ! strcmp(name, a->name) )
1361  break;
1362  }
1363 
1364 #if 0
1365  if (a == NULL)
1366  infoMessage("Error: Attribute %s in TAG <%s> not found\n",
1367  name, node->name);
1368 #endif
1369 
1370  return (a == NULL) ? NULL : a->value;
1371 }
1372 
1373 /** return first node */
1375  const XML_NODE* node,
1376  const char* name
1377  )
1378 {
1379  const XML_NODE* n;
1380 
1381  assert(node != NULL);
1382  assert(name != NULL);
1383 
1384  for (n = node; n != NULL; n = n->nextsibl)
1385  {
1386  if ( ! strcmp(name, n->name) )
1387  break;
1388  }
1389 
1390  return n;
1391 }
1392 
1393 /** return next node */
1395  const XML_NODE* node,
1396  const char* name
1397  )
1398 {
1399  assert(node != NULL);
1400  assert(name != NULL);
1401 
1402  return (node->nextsibl == NULL) ? NULL : xmlFirstNode(node->nextsibl, name);
1403 }
1404 
1405 /** find node */
1407  const XML_NODE* node,
1408  const char* name
1409  )
1410 {
1411  const XML_NODE* n;
1412  const XML_NODE* r;
1413 
1414  assert(node != NULL);
1415  assert(name != NULL);
1416 
1417  if ( ! strcmp(name, node->name) )
1418  return node;
1419 
1420  for (n = node->firstchild; n != NULL; n = n->nextsibl)
1421  {
1422  r = xmlFindNode(n, name);
1423  if ( r != NULL )
1424  return r;
1425  }
1426 
1427 #if 0
1428  if ( node->firstchild != NULL )
1429  {
1430  if (NULL != (n = xmlFindNode(node->firstchild, name)))
1431  return n;
1432  }
1433 
1434  if ( node->nextsibl != NULL )
1435  {
1436  if (NULL != (n = xmlFindNode(node->nextsibl, name)))
1437  return n;
1438  }
1439 #endif
1440 
1441  return NULL;
1442 }
1443 
1444 /** find node with bound on the depth */
1446  const XML_NODE* node, /**< current node - use start node to begin */
1447  const char* name, /**< name of tag to search for */
1448  int depth, /**< current depth - start with 0 for root */
1449  int maxdepth /**< maximal depth */
1450  )
1451 {
1452  const XML_NODE* n;
1453  const XML_NODE* r;
1454 
1455  assert(node != NULL);
1456  assert(name != NULL);
1457 
1458  if ( ! strcmp(name, node->name) )
1459  return node;
1460 
1461  if ( depth < maxdepth )
1462  {
1463  for (n = node->firstchild; n != NULL; n = n->nextsibl)
1464  {
1465  r = xmlFindNodeMaxdepth(n, name, depth+1, maxdepth);
1466  if ( r != NULL )
1467  return r;
1468  }
1469  }
1470 
1471  return NULL;
1472 }
1473 
1474 /** return next sibling */
1476  const XML_NODE* node
1477  )
1478 {
1479  assert(node != NULL);
1480 
1481  return node->nextsibl;
1482 }
1483 
1484 /** return previous sibling */
1486  const XML_NODE* node
1487  )
1488 {
1489  assert(node != NULL);
1490 
1491  return node->prevsibl;
1492 }
1493 
1494 /** return first child */
1496  const XML_NODE* node
1497  )
1498 {
1499  assert(node != NULL);
1500 
1501  return node->firstchild;
1502 }
1503 
1504 /** return last child */
1506  const XML_NODE* node
1507  )
1508 {
1509  assert(node != NULL);
1510 
1511  return node->lastchild;
1512 }
1513 
1514 /** return name of node */
1515 const char* xmlGetName(
1516  const XML_NODE* node
1517  )
1518 {
1519  assert(node != NULL);
1520 
1521  return node->name;
1522 }
1523 
1524 /** get line number */
1526  const XML_NODE* node
1527  )
1528 {
1529  assert(node != NULL);
1530 
1531  return node->lineno;
1532 }
1533 
1534 /** get data */
1535 const char* xmlGetData(
1536  const XML_NODE* node
1537  )
1538 {
1539  assert(node != NULL);
1540 
1541  return node->data;
1542 }
1543 
1544 /** find PCDATA */
1545 const char* xmlFindPcdata(
1546  const XML_NODE* node,
1547  const char* name
1548  )
1549 {
1550  const XML_NODE* n;
1551 
1552  assert(node != NULL);
1553  assert(name != NULL);
1554 
1555  n = xmlFindNode(node, name);
1556  if ( n == NULL )
1557  return NULL;
1558 
1559  if ( ! strcmp(n->firstchild->name, "#PCDATA") )
1560  return n->firstchild->data;
1561 
1562  return NULL;
1563 }
1564