Annotation of embedaddon/libxml2/testrecurse.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * testrecurse.c: C program to run libxml2 regression tests checking entities
                      3:  *            recursions
                      4:  *
                      5:  * To compile on Unixes:
                      6:  * cc -o testrecurse `xml2-config --cflags` testrecurse.c `xml2-config --libs` -lpthread
                      7:  *
                      8:  * See Copyright for the status of this software.
                      9:  *
                     10:  * daniel@veillard.com
                     11:  */
                     12: 
                     13: #ifdef HAVE_CONFIG_H
                     14: #include "libxml.h"
                     15: #else
                     16: #include <stdio.h>
                     17: #endif
                     18: 
                     19: #if !defined(_WIN32) || defined(__CYGWIN__)
                     20: #include <unistd.h>
                     21: #endif
                     22: #include <string.h>
                     23: #include <sys/types.h>
                     24: #include <sys/stat.h>
                     25: #include <fcntl.h>
                     26: 
                     27: #include <libxml/parser.h>
                     28: #include <libxml/tree.h>
                     29: #include <libxml/uri.h>
                     30: #ifdef LIBXML_READER_ENABLED
                     31: #include <libxml/xmlreader.h>
                     32: #endif
                     33: 
                     34: /*
                     35:  * O_BINARY is just for Windows compatibility - if it isn't defined
                     36:  * on this system, avoid any compilation error
                     37:  */
                     38: #ifdef O_BINARY
                     39: #define RD_FLAGS       O_RDONLY | O_BINARY
                     40: #else
                     41: #define        RD_FLAGS        O_RDONLY
                     42: #endif
                     43: 
                     44: typedef int (*functest) (const char *filename, const char *result,
                     45:                          const char *error, int options);
                     46: 
                     47: typedef struct testDesc testDesc;
                     48: typedef testDesc *testDescPtr;
                     49: struct testDesc {
                     50:     const char *desc; /* descripton of the test */
                     51:     functest    func; /* function implementing the test */
                     52:     const char *in;   /* glob to path for input files */
                     53:     const char *out;  /* output directory */
                     54:     const char *suffix;/* suffix for output files */
                     55:     const char *err;  /* suffix for error output files */
                     56:     int     options;  /* parser options for the test */
                     57: };
                     58: 
                     59: static int checkTestFile(const char *filename);
                     60: 
                     61: 
                     62: #if defined(_WIN32) && !defined(__CYGWIN__)
                     63: 
                     64: #include <windows.h>
                     65: #include <io.h>
                     66: 
                     67: typedef struct
                     68: {
                     69:       size_t gl_pathc;    /* Count of paths matched so far  */
                     70:       char **gl_pathv;    /* List of matched pathnames.  */
                     71:       size_t gl_offs;     /* Slots to reserve in 'gl_pathv'.  */
                     72: } glob_t;
                     73: 
                     74: #define GLOB_DOOFFS 0
                     75: static int glob(const char *pattern, int flags,
                     76:                 int errfunc(const char *epath, int eerrno),
                     77:                 glob_t *pglob) {
                     78:     glob_t *ret;
                     79:     WIN32_FIND_DATA FindFileData;
                     80:     HANDLE hFind;
                     81:     unsigned int nb_paths = 0;
                     82:     char directory[500];
                     83:     int len;
                     84: 
                     85:     if ((pattern == NULL) || (pglob == NULL)) return(-1);
                     86: 
                     87:     strncpy(directory, pattern, 499);
                     88:     for (len = strlen(directory);len >= 0;len--) {
                     89:         if (directory[len] == '/') {
                     90:            len++;
                     91:            directory[len] = 0;
                     92:            break;
                     93:        }
                     94:     }
                     95:     if (len <= 0)
                     96:         len = 0;
                     97: 
                     98: 
                     99:     ret = pglob;
                    100:     memset(ret, 0, sizeof(glob_t));
                    101: 
                    102:     hFind = FindFirstFileA(pattern, &FindFileData);
                    103:     if (hFind == INVALID_HANDLE_VALUE)
                    104:         return(0);
                    105:     nb_paths = 20;
                    106:     ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
                    107:     if (ret->gl_pathv == NULL) {
                    108:        FindClose(hFind);
                    109:         return(-1);
                    110:     }
                    111:     strncpy(directory + len, FindFileData.cFileName, 499 - len);
                    112:     ret->gl_pathv[ret->gl_pathc] = strdup(directory);
                    113:     if (ret->gl_pathv[ret->gl_pathc] == NULL)
                    114:         goto done;
                    115:     ret->gl_pathc++;
                    116:     while(FindNextFileA(hFind, &FindFileData)) {
                    117:         if (FindFileData.cFileName[0] == '.')
                    118:            continue;
                    119:         if (ret->gl_pathc + 2 > nb_paths) {
                    120:             char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
                    121:             if (tmp == NULL)
                    122:                 break;
                    123:             ret->gl_pathv = tmp;
                    124:             nb_paths *= 2;
                    125:        }
                    126:        strncpy(directory + len, FindFileData.cFileName, 499 - len);
                    127:        ret->gl_pathv[ret->gl_pathc] = strdup(directory);
                    128:         if (ret->gl_pathv[ret->gl_pathc] == NULL)
                    129:             break;
                    130:         ret->gl_pathc++;
                    131:     }
                    132:     ret->gl_pathv[ret->gl_pathc] = NULL;
                    133: 
                    134: done:
                    135:     FindClose(hFind);
                    136:     return(0);
                    137: }
                    138: 
                    139: 
                    140: 
                    141: static void globfree(glob_t *pglob) {
                    142:     unsigned int i;
                    143:     if (pglob == NULL)
                    144:         return;
                    145: 
                    146:     for (i = 0;i < pglob->gl_pathc;i++) {
                    147:          if (pglob->gl_pathv[i] != NULL)
                    148:              free(pglob->gl_pathv[i]);
                    149:     }
                    150: }
                    151: #define vsnprintf _vsnprintf
                    152: #define snprintf _snprintf
                    153: #else
                    154: #include <glob.h>
                    155: #endif
                    156: 
                    157: /************************************************************************
                    158:  *                                                                     *
                    159:  *             Huge document generator                                 *
                    160:  *                                                                     *
                    161:  ************************************************************************/
                    162: 
                    163: #include <libxml/xmlIO.h>
                    164: 
                    165: 
                    166: static const char *start = "<!DOCTYPE foo [\
                    167: <!ENTITY f 'some internal data'> \
                    168: <!ENTITY e '&f;&f;'> \
                    169: <!ENTITY d '&e;&e;'> \
                    170: ]> \
                    171: <foo>";
                    172: 
                    173: static const char *segment = "  <bar>&e; &f; &d;</bar>\n";
                    174: static const char *finish = "</foo>";
                    175: 
                    176: static int curseg = 0;
                    177: static const char *current;
                    178: static int rlen;
                    179: 
                    180: /**
                    181:  * hugeMatch:
                    182:  * @URI: an URI to test
                    183:  *
                    184:  * Check for an huge: query
                    185:  *
                    186:  * Returns 1 if yes and 0 if another Input module should be used
                    187:  */
                    188: static int
                    189: hugeMatch(const char * URI) {
                    190:     if ((URI != NULL) && (!strncmp(URI, "huge:", 4)))
                    191:         return(1);
                    192:     return(0);
                    193: }
                    194: 
                    195: /**
                    196:  * hugeOpen:
                    197:  * @URI: an URI to test
                    198:  *
                    199:  * Return a pointer to the huge: query handler, in this example simply
                    200:  * the current pointer...
                    201:  *
                    202:  * Returns an Input context or NULL in case or error
                    203:  */
                    204: static void *
                    205: hugeOpen(const char * URI) {
                    206:     if ((URI == NULL) || (strncmp(URI, "huge:", 4)))
                    207:         return(NULL);
                    208:     rlen = strlen(start);
                    209:     current = start;
                    210:     return((void *) current);
                    211: }
                    212: 
                    213: /**
                    214:  * hugeClose:
                    215:  * @context: the read context
                    216:  *
                    217:  * Close the huge: query handler
                    218:  *
                    219:  * Returns 0 or -1 in case of error
                    220:  */
                    221: static int
                    222: hugeClose(void * context) {
                    223:     if (context == NULL) return(-1);
                    224:     return(0);
                    225: }
                    226: 
                    227: #define MAX_NODES 1000000
                    228: 
                    229: /**
                    230:  * hugeRead:
                    231:  * @context: the read context
                    232:  * @buffer: where to store data
                    233:  * @len: number of bytes to read
                    234:  *
                    235:  * Implement an huge: query read.
                    236:  *
                    237:  * Returns the number of bytes read or -1 in case of error
                    238:  */
                    239: static int
                    240: hugeRead(void *context, char *buffer, int len)
                    241: {
                    242:     if ((context == NULL) || (buffer == NULL) || (len < 0))
                    243:         return (-1);
                    244: 
                    245:     if (len >= rlen) {
                    246:         if (curseg >= MAX_NODES + 1) {
                    247:             rlen = 0;
                    248:             return(0);
                    249:         }
                    250:         len = rlen;
                    251:         rlen = 0;
                    252:        memcpy(buffer, current, len);
                    253:         curseg ++;
                    254:         if (curseg == MAX_NODES) {
                    255:            fprintf(stderr, "\n");
                    256:             rlen = strlen(finish);
                    257:             current = finish;
                    258:        } else {
                    259:            if (curseg % (MAX_NODES / 10) == 0)
                    260:                fprintf(stderr, ".");
                    261:             rlen = strlen(segment);
                    262:             current = segment;
                    263:        }
                    264:     } else {
                    265:        memcpy(buffer, current, len);
                    266:        rlen -= len;
                    267:         current += len;
                    268:     }
                    269:     return (len);
                    270: }
                    271: 
                    272: /************************************************************************
                    273:  *                                                                     *
                    274:  *             Libxml2 specific routines                               *
                    275:  *                                                                     *
                    276:  ************************************************************************/
                    277: 
                    278: static int nb_tests = 0;
                    279: static int nb_errors = 0;
                    280: static int nb_leaks = 0;
                    281: static int extraMemoryFromResolver = 0;
                    282: 
                    283: static int
                    284: fatalError(void) {
                    285:     fprintf(stderr, "Exitting tests on fatal error\n");
                    286:     exit(1);
                    287: }
                    288: 
                    289: /*
                    290:  * We need to trap calls to the resolver to not account memory for the catalog
                    291:  * which is shared to the current running test. We also don't want to have
                    292:  * network downloads modifying tests.
                    293:  */
                    294: static xmlParserInputPtr
                    295: testExternalEntityLoader(const char *URL, const char *ID,
                    296:                         xmlParserCtxtPtr ctxt) {
                    297:     xmlParserInputPtr ret;
                    298: 
                    299:     if (checkTestFile(URL)) {
                    300:        ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
                    301:     } else {
                    302:        int memused = xmlMemUsed();
                    303:        ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
                    304:        extraMemoryFromResolver += xmlMemUsed() - memused;
                    305:     }
                    306: 
                    307:     return(ret);
                    308: }
                    309: 
                    310: /*
                    311:  * Trapping the error messages at the generic level to grab the equivalent of
                    312:  * stderr messages on CLI tools.
                    313:  */
                    314: static char testErrors[32769];
                    315: static int testErrorsSize = 0;
                    316: 
                    317: static void XMLCDECL
                    318: channel(void *ctx  ATTRIBUTE_UNUSED, const char *msg, ...) {
                    319:     va_list args;
                    320:     int res;
                    321: 
                    322:     if (testErrorsSize >= 32768)
                    323:         return;
                    324:     va_start(args, msg);
                    325:     res = vsnprintf(&testErrors[testErrorsSize],
                    326:                     32768 - testErrorsSize,
                    327:                    msg, args);
                    328:     va_end(args);
                    329:     if (testErrorsSize + res >= 32768) {
                    330:         /* buffer is full */
                    331:        testErrorsSize = 32768;
                    332:        testErrors[testErrorsSize] = 0;
                    333:     } else {
                    334:         testErrorsSize += res;
                    335:     }
                    336:     testErrors[testErrorsSize] = 0;
                    337: }
                    338: 
                    339: /**
                    340:  * xmlParserPrintFileContext:
                    341:  * @input:  an xmlParserInputPtr input
                    342:  *
                    343:  * Displays current context within the input content for error tracking
                    344:  */
                    345: 
                    346: static void
                    347: xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
                    348:                xmlGenericErrorFunc chanl, void *data ) {
                    349:     const xmlChar *cur, *base;
                    350:     unsigned int n, col;       /* GCC warns if signed, because compared with sizeof() */
                    351:     xmlChar  content[81]; /* space for 80 chars + line terminator */
                    352:     xmlChar *ctnt;
                    353: 
                    354:     if (input == NULL) return;
                    355:     cur = input->cur;
                    356:     base = input->base;
                    357:     /* skip backwards over any end-of-lines */
                    358:     while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
                    359:        cur--;
                    360:     }
                    361:     n = 0;
                    362:     /* search backwards for beginning-of-line (to max buff size) */
                    363:     while ((n++ < (sizeof(content)-1)) && (cur > base) &&
                    364:    (*(cur) != '\n') && (*(cur) != '\r'))
                    365:         cur--;
                    366:     if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
                    367:     /* calculate the error position in terms of the current position */
                    368:     col = input->cur - cur;
                    369:     /* search forward for end-of-line (to max buff size) */
                    370:     n = 0;
                    371:     ctnt = content;
                    372:     /* copy selected text to our buffer */
                    373:     while ((*cur != 0) && (*(cur) != '\n') &&
                    374:    (*(cur) != '\r') && (n < sizeof(content)-1)) {
                    375:                *ctnt++ = *cur++;
                    376:        n++;
                    377:     }
                    378:     *ctnt = 0;
                    379:     /* print out the selected text */
                    380:     chanl(data ,"%s\n", content);
                    381:     /* create blank line with problem pointer */
                    382:     n = 0;
                    383:     ctnt = content;
                    384:     /* (leave buffer space for pointer + line terminator) */
                    385:     while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
                    386:        if (*(ctnt) != '\t')
                    387:            *(ctnt) = ' ';
                    388:        ctnt++;
                    389:     }
                    390:     *ctnt++ = '^';
                    391:     *ctnt = 0;
                    392:     chanl(data ,"%s\n", content);
                    393: }
                    394: 
                    395: static void
                    396: testStructuredErrorHandler(void *ctx  ATTRIBUTE_UNUSED, xmlErrorPtr err) {
                    397:     char *file = NULL;
                    398:     int line = 0;
                    399:     int code = -1;
                    400:     int domain;
                    401:     void *data = NULL;
                    402:     const char *str;
                    403:     const xmlChar *name = NULL;
                    404:     xmlNodePtr node;
                    405:     xmlErrorLevel level;
                    406:     xmlParserInputPtr input = NULL;
                    407:     xmlParserInputPtr cur = NULL;
                    408:     xmlParserCtxtPtr ctxt = NULL;
                    409: 
                    410:     if (err == NULL)
                    411:         return;
                    412: 
                    413:     file = err->file;
                    414:     line = err->line;
                    415:     code = err->code;
                    416:     domain = err->domain;
                    417:     level = err->level;
                    418:     node = err->node;
                    419:     if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
                    420:         (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
                    421:        (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
                    422:        ctxt = err->ctxt;
                    423:     }
                    424:     str = err->message;
                    425: 
                    426:     if (code == XML_ERR_OK)
                    427:         return;
                    428: 
                    429:     if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
                    430:         name = node->name;
                    431: 
                    432:     /*
                    433:      * Maintain the compatibility with the legacy error handling
                    434:      */
                    435:     if (ctxt != NULL) {
                    436:         input = ctxt->input;
                    437:         if ((input != NULL) && (input->filename == NULL) &&
                    438:             (ctxt->inputNr > 1)) {
                    439:             cur = input;
                    440:             input = ctxt->inputTab[ctxt->inputNr - 2];
                    441:         }
                    442:         if (input != NULL) {
                    443:             if (input->filename)
                    444:                 channel(data, "%s:%d: ", input->filename, input->line);
                    445:             else if ((line != 0) && (domain == XML_FROM_PARSER))
                    446:                 channel(data, "Entity: line %d: ", input->line);
                    447:         }
                    448:     } else {
                    449:         if (file != NULL)
                    450:             channel(data, "%s:%d: ", file, line);
                    451:         else if ((line != 0) && (domain == XML_FROM_PARSER))
                    452:             channel(data, "Entity: line %d: ", line);
                    453:     }
                    454:     if (name != NULL) {
                    455:         channel(data, "element %s: ", name);
                    456:     }
                    457:     if (code == XML_ERR_OK)
                    458:         return;
                    459:     switch (domain) {
                    460:         case XML_FROM_PARSER:
                    461:             channel(data, "parser ");
                    462:             break;
                    463:         case XML_FROM_NAMESPACE:
                    464:             channel(data, "namespace ");
                    465:             break;
                    466:         case XML_FROM_DTD:
                    467:         case XML_FROM_VALID:
                    468:             channel(data, "validity ");
                    469:             break;
                    470:         case XML_FROM_HTML:
                    471:             channel(data, "HTML parser ");
                    472:             break;
                    473:         case XML_FROM_MEMORY:
                    474:             channel(data, "memory ");
                    475:             break;
                    476:         case XML_FROM_OUTPUT:
                    477:             channel(data, "output ");
                    478:             break;
                    479:         case XML_FROM_IO:
                    480:             channel(data, "I/O ");
                    481:             break;
                    482:         case XML_FROM_XINCLUDE:
                    483:             channel(data, "XInclude ");
                    484:             break;
                    485:         case XML_FROM_XPATH:
                    486:             channel(data, "XPath ");
                    487:             break;
                    488:         case XML_FROM_XPOINTER:
                    489:             channel(data, "parser ");
                    490:             break;
                    491:         case XML_FROM_REGEXP:
                    492:             channel(data, "regexp ");
                    493:             break;
                    494:         case XML_FROM_MODULE:
                    495:             channel(data, "module ");
                    496:             break;
                    497:         case XML_FROM_SCHEMASV:
                    498:             channel(data, "Schemas validity ");
                    499:             break;
                    500:         case XML_FROM_SCHEMASP:
                    501:             channel(data, "Schemas parser ");
                    502:             break;
                    503:         case XML_FROM_RELAXNGP:
                    504:             channel(data, "Relax-NG parser ");
                    505:             break;
                    506:         case XML_FROM_RELAXNGV:
                    507:             channel(data, "Relax-NG validity ");
                    508:             break;
                    509:         case XML_FROM_CATALOG:
                    510:             channel(data, "Catalog ");
                    511:             break;
                    512:         case XML_FROM_C14N:
                    513:             channel(data, "C14N ");
                    514:             break;
                    515:         case XML_FROM_XSLT:
                    516:             channel(data, "XSLT ");
                    517:             break;
                    518:         default:
                    519:             break;
                    520:     }
                    521:     if (code == XML_ERR_OK)
                    522:         return;
                    523:     switch (level) {
                    524:         case XML_ERR_NONE:
                    525:             channel(data, ": ");
                    526:             break;
                    527:         case XML_ERR_WARNING:
                    528:             channel(data, "warning : ");
                    529:             break;
                    530:         case XML_ERR_ERROR:
                    531:             channel(data, "error : ");
                    532:             break;
                    533:         case XML_ERR_FATAL:
                    534:             channel(data, "error : ");
                    535:             break;
                    536:     }
                    537:     if (code == XML_ERR_OK)
                    538:         return;
                    539:     if (str != NULL) {
                    540:         int len;
                    541:        len = xmlStrlen((const xmlChar *)str);
                    542:        if ((len > 0) && (str[len - 1] != '\n'))
                    543:            channel(data, "%s\n", str);
                    544:        else
                    545:            channel(data, "%s", str);
                    546:     } else {
                    547:         channel(data, "%s\n", "out of memory error");
                    548:     }
                    549:     if (code == XML_ERR_OK)
                    550:         return;
                    551: 
                    552:     if (ctxt != NULL) {
                    553:         xmlParserPrintFileContextInternal(input, channel, data);
                    554:         if (cur != NULL) {
                    555:             if (cur->filename)
                    556:                 channel(data, "%s:%d: \n", cur->filename, cur->line);
                    557:             else if ((line != 0) && (domain == XML_FROM_PARSER))
                    558:                 channel(data, "Entity: line %d: \n", cur->line);
                    559:             xmlParserPrintFileContextInternal(cur, channel, data);
                    560:         }
                    561:     }
                    562:     if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
                    563:         (err->int1 < 100) &&
                    564:        (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
                    565:        xmlChar buf[150];
                    566:        int i;
                    567: 
                    568:        channel(data, "%s\n", err->str1);
                    569:        for (i=0;i < err->int1;i++)
                    570:             buf[i] = ' ';
                    571:        buf[i++] = '^';
                    572:        buf[i] = 0;
                    573:        channel(data, "%s\n", buf);
                    574:     }
                    575: }
                    576: 
                    577: static void
                    578: initializeLibxml2(void) {
                    579:     xmlGetWarningsDefaultValue = 0;
                    580:     xmlPedanticParserDefault(0);
                    581: 
                    582:     xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
                    583:     xmlInitParser();
                    584:     xmlSetExternalEntityLoader(testExternalEntityLoader);
                    585:     xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
                    586:     /*
                    587:      * register the new I/O handlers
                    588:      */
                    589:     if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen,
                    590:                                   hugeRead, hugeClose) < 0) {
                    591:         fprintf(stderr, "failed to register Huge handler\n");
                    592:        exit(1);
                    593:     }
                    594: }
                    595: 
                    596: /************************************************************************
                    597:  *                                                                     *
                    598:  *             File name and path utilities                            *
                    599:  *                                                                     *
                    600:  ************************************************************************/
                    601: 
                    602: static const char *baseFilename(const char *filename) {
                    603:     const char *cur;
                    604:     if (filename == NULL)
                    605:         return(NULL);
                    606:     cur = &filename[strlen(filename)];
                    607:     while ((cur > filename) && (*cur != '/'))
                    608:         cur--;
                    609:     if (*cur == '/')
                    610:         return(cur + 1);
                    611:     return(cur);
                    612: }
                    613: 
                    614: static char *resultFilename(const char *filename, const char *out,
                    615:                             const char *suffix) {
                    616:     const char *base;
                    617:     char res[500];
                    618:     char suffixbuff[500];
                    619: 
                    620: /*************
                    621:     if ((filename[0] == 't') && (filename[1] == 'e') &&
                    622:         (filename[2] == 's') && (filename[3] == 't') &&
                    623:        (filename[4] == '/'))
                    624:        filename = &filename[5];
                    625:  *************/
                    626: 
                    627:     base = baseFilename(filename);
                    628:     if (suffix == NULL)
                    629:         suffix = ".tmp";
                    630:     if (out == NULL)
                    631:         out = "";
                    632: 
                    633:     strncpy(suffixbuff,suffix,499);
                    634: #ifdef VMS
                    635:     if(strstr(base,".") && suffixbuff[0]=='.')
                    636:       suffixbuff[0]='_';
                    637: #endif
                    638: 
                    639:     snprintf(res, 499, "%s%s%s", out, base, suffixbuff);
                    640:     res[499] = 0;
                    641:     return(strdup(res));
                    642: }
                    643: 
                    644: static int checkTestFile(const char *filename) {
                    645:     struct stat buf;
                    646: 
                    647:     if (stat(filename, &buf) == -1)
                    648:         return(0);
                    649: 
                    650: #if defined(_WIN32) && !defined(__CYGWIN__)
                    651:     if (!(buf.st_mode & _S_IFREG))
                    652:         return(0);
                    653: #else
                    654:     if (!S_ISREG(buf.st_mode))
                    655:         return(0);
                    656: #endif
                    657: 
                    658:     return(1);
                    659: }
                    660: 
                    661: 
                    662: 
                    663: /************************************************************************
                    664:  *                                                                     *
                    665:  *             Test to detect or not recursive entities                *
                    666:  *                                                                     *
                    667:  ************************************************************************/
                    668: /**
                    669:  * recursiveDetectTest:
                    670:  * @filename: the file to parse
                    671:  * @result: the file with expected result
                    672:  * @err: the file with error messages: unused
                    673:  *
                    674:  * Parse a file loading DTD and replacing entities check it fails for
                    675:  * lol cases
                    676:  *
                    677:  * Returns 0 in case of success, an error code otherwise
                    678:  */
                    679: static int
                    680: recursiveDetectTest(const char *filename,
                    681:              const char *result ATTRIBUTE_UNUSED,
                    682:              const char *err ATTRIBUTE_UNUSED,
                    683:             int options ATTRIBUTE_UNUSED) {
                    684:     xmlDocPtr doc;
                    685:     xmlParserCtxtPtr ctxt;
                    686:     int res = 0;
                    687:     int mem;
                    688: 
                    689:     nb_tests++;
                    690: 
                    691:     ctxt = xmlNewParserCtxt();
                    692:     mem = xmlMemUsed();
                    693:     /*
                    694:      * base of the test, parse with the old API
                    695:      */
                    696:     doc = xmlCtxtReadFile(ctxt, filename, NULL,
                    697:                           XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
                    698:     if ((doc != NULL) || (ctxt->lastError.code != XML_ERR_ENTITY_LOOP)) {
                    699:         fprintf(stderr, "Failed to detect recursion in %s\n", filename);
                    700:        xmlFreeParserCtxt(ctxt);
                    701:        xmlFreeDoc(doc);
                    702:         return(1);
                    703:     }
                    704:     xmlFreeParserCtxt(ctxt);
                    705: 
                    706:     return(res);
                    707: }
                    708: 
                    709: /**
                    710:  * notRecursiveDetectTest:
                    711:  * @filename: the file to parse
                    712:  * @result: the file with expected result
                    713:  * @err: the file with error messages: unused
                    714:  *
                    715:  * Parse a file loading DTD and replacing entities check it works for
                    716:  * good cases
                    717:  *
                    718:  * Returns 0 in case of success, an error code otherwise
                    719:  */
                    720: static int
                    721: notRecursiveDetectTest(const char *filename,
                    722:              const char *result ATTRIBUTE_UNUSED,
                    723:              const char *err ATTRIBUTE_UNUSED,
                    724:             int options ATTRIBUTE_UNUSED) {
                    725:     xmlDocPtr doc;
                    726:     xmlParserCtxtPtr ctxt;
                    727:     int res = 0;
                    728:     int mem;
                    729: 
                    730:     nb_tests++;
                    731: 
                    732:     ctxt = xmlNewParserCtxt();
                    733:     mem = xmlMemUsed();
                    734:     /*
                    735:      * base of the test, parse with the old API
                    736:      */
                    737:     doc = xmlCtxtReadFile(ctxt, filename, NULL,
                    738:                           XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
                    739:     if (doc == NULL) {
                    740:         fprintf(stderr, "Failed to parse correct file %s\n", filename);
                    741:        xmlFreeParserCtxt(ctxt);
                    742:         return(1);
                    743:     }
                    744:     xmlFreeDoc(doc);
                    745:     xmlFreeParserCtxt(ctxt);
                    746: 
                    747:     return(res);
                    748: }
                    749: 
                    750: #ifdef LIBXML_READER_ENABLED
                    751: /**
                    752:  * notRecursiveHugeTest:
                    753:  * @filename: the file to parse
                    754:  * @result: the file with expected result
                    755:  * @err: the file with error messages: unused
                    756:  *
                    757:  * Parse a memory generated file
                    758:  * good cases
                    759:  *
                    760:  * Returns 0 in case of success, an error code otherwise
                    761:  */
                    762: static int
                    763: notRecursiveHugeTest(const char *filename ATTRIBUTE_UNUSED,
                    764:              const char *result ATTRIBUTE_UNUSED,
                    765:              const char *err ATTRIBUTE_UNUSED,
                    766:             int options ATTRIBUTE_UNUSED) {
                    767:     xmlTextReaderPtr reader;
                    768:     int res = 0;
                    769:     int ret;
                    770: 
                    771:     nb_tests++;
                    772: 
                    773:     reader = xmlReaderForFile("huge:test" , NULL,
                    774:                               XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
                    775:     if (reader == NULL) {
                    776:         fprintf(stderr, "Failed to open huge:test\n");
                    777:        return(1);
                    778:     }
                    779:     ret = xmlTextReaderRead(reader);
                    780:     while (ret == 1) {
                    781:         ret = xmlTextReaderRead(reader);
                    782:     }
                    783:     if (ret != 0) {
                    784:         fprintf(stderr, "Failed to parser huge:test with entities\n");
                    785:        res = 1;
                    786:     }
                    787:     xmlFreeTextReader(reader);
                    788: 
                    789:     return(res);
                    790: }
                    791: #endif
                    792: 
                    793: /************************************************************************
                    794:  *                                                                     *
                    795:  *                     Tests Descriptions                              *
                    796:  *                                                                     *
                    797:  ************************************************************************/
                    798: 
                    799: static
                    800: testDesc testDescriptions[] = {
                    801:     { "Parsing recursive test cases" ,
                    802:       recursiveDetectTest, "./test/recurse/lol*.xml", NULL, NULL, NULL,
                    803:       0 },
                    804:     { "Parsing non-recursive test cases" ,
                    805:       notRecursiveDetectTest, "./test/recurse/good*.xml", NULL, NULL, NULL,
                    806:       0 },
                    807: #ifdef LIBXML_READER_ENABLED
                    808:     { "Parsing non-recursive huge case" ,
                    809:       notRecursiveHugeTest, NULL, NULL, NULL, NULL,
                    810:       0 },
                    811: #endif
                    812:     {NULL, NULL, NULL, NULL, NULL, NULL, 0}
                    813: };
                    814: 
                    815: /************************************************************************
                    816:  *                                                                     *
                    817:  *             The main code driving the tests                         *
                    818:  *                                                                     *
                    819:  ************************************************************************/
                    820: 
                    821: static int
                    822: launchTests(testDescPtr tst) {
                    823:     int res = 0, err = 0;
                    824:     size_t i;
                    825:     char *result;
                    826:     char *error;
                    827:     int mem;
                    828: 
                    829:     if (tst == NULL) return(-1);
                    830:     if (tst->in != NULL) {
                    831:        glob_t globbuf;
                    832: 
                    833:        globbuf.gl_offs = 0;
                    834:        glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
                    835:        for (i = 0;i < globbuf.gl_pathc;i++) {
                    836:            if (!checkTestFile(globbuf.gl_pathv[i]))
                    837:                continue;
                    838:            if (tst->suffix != NULL) {
                    839:                result = resultFilename(globbuf.gl_pathv[i], tst->out,
                    840:                                        tst->suffix);
                    841:                if (result == NULL) {
                    842:                    fprintf(stderr, "Out of memory !\n");
                    843:                    fatalError();
                    844:                }
                    845:            } else {
                    846:                result = NULL;
                    847:            }
                    848:            if (tst->err != NULL) {
                    849:                error = resultFilename(globbuf.gl_pathv[i], tst->out,
                    850:                                        tst->err);
                    851:                if (error == NULL) {
                    852:                    fprintf(stderr, "Out of memory !\n");
                    853:                    fatalError();
                    854:                }
                    855:            } else {
                    856:                error = NULL;
                    857:            }
                    858:            if ((result) &&(!checkTestFile(result))) {
                    859:                fprintf(stderr, "Missing result file %s\n", result);
                    860:            } else if ((error) &&(!checkTestFile(error))) {
                    861:                fprintf(stderr, "Missing error file %s\n", error);
                    862:            } else {
                    863:                mem = xmlMemUsed();
                    864:                extraMemoryFromResolver = 0;
                    865:                testErrorsSize = 0;
                    866:                testErrors[0] = 0;
                    867:                res = tst->func(globbuf.gl_pathv[i], result, error,
                    868:                                tst->options | XML_PARSE_COMPACT);
                    869:                xmlResetLastError();
                    870:                if (res != 0) {
                    871:                    fprintf(stderr, "File %s generated an error\n",
                    872:                            globbuf.gl_pathv[i]);
                    873:                    nb_errors++;
                    874:                    err++;
                    875:                }
                    876:                else if (xmlMemUsed() != mem) {
                    877:                    if ((xmlMemUsed() != mem) &&
                    878:                        (extraMemoryFromResolver == 0)) {
                    879:                        fprintf(stderr, "File %s leaked %d bytes\n",
                    880:                                globbuf.gl_pathv[i], xmlMemUsed() - mem);
                    881:                        nb_leaks++;
                    882:                        err++;
                    883:                    }
                    884:                }
                    885:                testErrorsSize = 0;
                    886:            }
                    887:            if (result)
                    888:                free(result);
                    889:            if (error)
                    890:                free(error);
                    891:        }
                    892:        globfree(&globbuf);
                    893:     } else {
                    894:         testErrorsSize = 0;
                    895:        testErrors[0] = 0;
                    896:        extraMemoryFromResolver = 0;
                    897:         res = tst->func(NULL, NULL, NULL, tst->options);
                    898:        if (res != 0) {
                    899:            nb_errors++;
                    900:            err++;
                    901:        }
                    902:     }
                    903:     return(err);
                    904: }
                    905: 
                    906: static int verbose = 0;
                    907: static int tests_quiet = 0;
                    908: 
                    909: static int
                    910: runtest(int i) {
                    911:     int ret = 0, res;
                    912:     int old_errors, old_tests, old_leaks;
                    913: 
                    914:     old_errors = nb_errors;
                    915:     old_tests = nb_tests;
                    916:     old_leaks = nb_leaks;
                    917:     if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
                    918:        printf("## %s\n", testDescriptions[i].desc);
                    919:     res = launchTests(&testDescriptions[i]);
                    920:     if (res != 0)
                    921:        ret++;
                    922:     if (verbose) {
                    923:        if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
                    924:            printf("Ran %d tests, no errors\n", nb_tests - old_tests);
                    925:        else
                    926:            printf("Ran %d tests, %d errors, %d leaks\n",
                    927:                   nb_tests - old_tests,
                    928:                   nb_errors - old_errors,
                    929:                   nb_leaks - old_leaks);
                    930:     }
                    931:     return(ret);
                    932: }
                    933: 
                    934: int
                    935: main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
                    936:     int i, a, ret = 0;
                    937:     int subset = 0;
                    938: 
                    939:     initializeLibxml2();
                    940: 
                    941:     for (a = 1; a < argc;a++) {
                    942:         if (!strcmp(argv[a], "-v"))
                    943:            verbose = 1;
                    944:         else if (!strcmp(argv[a], "-quiet"))
                    945:            tests_quiet = 1;
                    946:        else {
                    947:            for (i = 0; testDescriptions[i].func != NULL; i++) {
                    948:                if (strstr(testDescriptions[i].desc, argv[a])) {
                    949:                    ret += runtest(i);
                    950:                    subset++;
                    951:                }
                    952:            }
                    953:        }
                    954:     }
                    955:     if (subset == 0) {
                    956:        for (i = 0; testDescriptions[i].func != NULL; i++) {
                    957:            ret += runtest(i);
                    958:        }
                    959:     }
                    960:     if ((nb_errors == 0) && (nb_leaks == 0)) {
                    961:         ret = 0;
                    962:        printf("Total %d tests, no errors\n",
                    963:               nb_tests);
                    964:     } else {
                    965:         ret = 1;
                    966:        printf("Total %d tests, %d errors, %d leaks\n",
                    967:               nb_tests, nb_errors, nb_leaks);
                    968:     }
                    969:     xmlCleanupParser();
                    970:     xmlMemoryDump();
                    971: 
                    972:     return(ret);
                    973: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>