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