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