Annotation of embedaddon/libxml2/testrecurse.c, revision 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>