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