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

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

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