Annotation of XML/debugXML.c, revision 1.47

1.1       daniel      1: /*
                      2:  * debugXML.c : This is a set of routines used for debugging the tree
                      3:  *              produced by the XML parser.
                      4:  *
1.2       daniel      5:  * See Copyright for the status of this software.
                      6:  *
1.1       daniel      7:  * Daniel Veillard <Daniel.Veillard@w3.org>
                      8:  */
                      9: 
1.11      daniel     10: #ifdef WIN32
                     11: #include "win32config.h"
                     12: #else
                     13: #include "config.h"
                     14: #endif
1.23      daniel     15: 
1.41      veillard   16: #include <libxml/xmlversion.h>
1.23      daniel     17: #ifdef LIBXML_DEBUG_ENABLED
                     18: 
1.1       daniel     19: #include <stdio.h>
1.26      veillard   20: #include <string.h>
1.12      daniel     21: #ifdef HAVE_STDLIB_H
                     22: #include <stdlib.h>
                     23: #endif
1.14      daniel     24: #ifdef HAVE_STRING_H
                     25: #include <string.h>
                     26: #endif
1.23      daniel     27: #include <libxml/xmlmemory.h>
                     28: #include <libxml/tree.h>
                     29: #include <libxml/parser.h>
                     30: #include <libxml/valid.h>
                     31: #include <libxml/debugXML.h>
                     32: #include <libxml/HTMLtree.h>
                     33: #include <libxml/HTMLparser.h>
1.44      veillard   34: #include <libxml/xmlerror.h>
1.1       daniel     35: 
                     36: #define IS_BLANK(c)                                                    \
                     37:   (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
                     38: 
1.6       daniel     39: void xmlDebugDumpString(FILE *output, const xmlChar *str) {
1.1       daniel     40:     int i;
1.29      veillard   41:     if (str == NULL) {
                     42:        fprintf(output, "(NULL)");
                     43:        return;
                     44:     }
1.1       daniel     45:     for (i = 0;i < 40;i++)
                     46:         if (str[i] == 0) return;
                     47:        else if (IS_BLANK(str[i])) fputc(' ', output);
1.27      veillard   48:        else if (str[i] >= 0x80)
                     49:             fprintf(output, "#%X", str[i]);
1.1       daniel     50:        else fputc(str[i], output);
                     51:     fprintf(output, "...");
                     52: }
                     53: 
1.18      daniel     54: void xmlDebugDumpDtd(FILE *output, xmlDtdPtr dtd, int depth) {
                     55:     int i;
                     56:     char shift[100];
                     57: 
                     58:     for (i = 0;((i < depth) && (i < 25));i++)
                     59:         shift[2 * i] = shift[2 * i + 1] = ' ';
                     60:     shift[2 * i] = shift[2 * i + 1] = 0;
                     61: 
                     62:     fprintf(output, shift);
                     63: 
                     64:     if (dtd->type != XML_DTD_NODE) {
                     65:        fprintf(output, "PBM: not a DTD\n");
                     66:        return;
                     67:     }
                     68:     if (dtd->name != NULL)
                     69:        fprintf(output, "DTD(%s)", dtd->name);
                     70:     else
                     71:        fprintf(output, "DTD");
                     72:     if (dtd->ExternalID != NULL)
                     73:        fprintf(output, ", PUBLIC %s", dtd->ExternalID);
                     74:     if (dtd->SystemID != NULL)
                     75:        fprintf(output, ", SYSTEM %s", dtd->SystemID);
                     76:     fprintf(output, "\n");
                     77:     /*
                     78:      * Do a bit of checking
                     79:      */
                     80:     if (dtd->parent == NULL)
                     81:        fprintf(output, "PBM: Dtd has no parent\n");
                     82:     if (dtd->doc == NULL)
                     83:        fprintf(output, "PBM: Dtd has no doc\n");
                     84:     if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
                     85:        fprintf(output, "PBM: Dtd doc differs from parent's one\n");
                     86:     if (dtd->prev == NULL) {
                     87:        if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
                     88:            fprintf(output, "PBM: Dtd has no prev and not first of list\n");
                     89:     } else {
                     90:        if (dtd->prev->next != (xmlNodePtr) dtd)
                     91:            fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
                     92:     }
                     93:     if (dtd->next == NULL) {
                     94:        if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
                     95:            fprintf(output, "PBM: Dtd has no next and not last of list\n");
                     96:     } else {
                     97:        if (dtd->next->prev != (xmlNodePtr) dtd)
                     98:            fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
                     99:     }
                    100: }
                    101: 
                    102: void xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) {
                    103:     int i;
                    104:     char shift[100];
                    105: 
                    106:     for (i = 0;((i < depth) && (i < 25));i++)
                    107:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    108:     shift[2 * i] = shift[2 * i + 1] = 0;
                    109: 
                    110:     fprintf(output, shift);
                    111: 
                    112:     if (attr->type != XML_ATTRIBUTE_DECL) {
                    113:        fprintf(output, "PBM: not a Attr\n");
                    114:        return;
                    115:     }
                    116:     if (attr->name != NULL)
                    117:        fprintf(output, "ATTRDECL(%s)", attr->name);
                    118:     else
                    119:        fprintf(output, "PBM ATTRDECL noname!!!");
                    120:     if (attr->elem != NULL)
                    121:        fprintf(output, " for %s", attr->elem);
                    122:     else
                    123:        fprintf(output, " PBM noelem!!!");
                    124:     switch (attr->atype) {
                    125:         case XML_ATTRIBUTE_CDATA:
                    126:            fprintf(output, " CDATA");
                    127:            break;
                    128:         case XML_ATTRIBUTE_ID:
                    129:            fprintf(output, " ID");
                    130:            break;
                    131:         case XML_ATTRIBUTE_IDREF:
                    132:            fprintf(output, " IDREF");
                    133:            break;
                    134:         case XML_ATTRIBUTE_IDREFS:
                    135:            fprintf(output, " IDREFS");
                    136:            break;
                    137:         case XML_ATTRIBUTE_ENTITY:
                    138:            fprintf(output, " ENTITY");
                    139:            break;
                    140:         case XML_ATTRIBUTE_ENTITIES:
                    141:            fprintf(output, " ENTITIES");
                    142:            break;
                    143:         case XML_ATTRIBUTE_NMTOKEN:
                    144:            fprintf(output, " NMTOKEN");
                    145:            break;
                    146:         case XML_ATTRIBUTE_NMTOKENS:
                    147:            fprintf(output, " NMTOKENS");
                    148:            break;
                    149:         case XML_ATTRIBUTE_ENUMERATION:
                    150:            fprintf(output, " ENUMERATION");
                    151:            break;
                    152:         case XML_ATTRIBUTE_NOTATION:
                    153:            fprintf(output, " NOTATION ");
                    154:            break;
                    155:     }
                    156:     if (attr->tree != NULL) {
                    157:        int i;
                    158:        xmlEnumerationPtr cur = attr->tree;
                    159: 
                    160:        for (i = 0;i < 5; i++) {
                    161:            if (i != 0)
                    162:                fprintf(output, "|%s", cur->name);
                    163:            else
                    164:                fprintf(output, " (%s", cur->name);
                    165:            cur = cur->next;
                    166:            if (cur == NULL) break;
                    167:        }
                    168:        if (cur == NULL)
                    169:            fprintf(output, ")");
                    170:        else
                    171:            fprintf(output, "...)");
                    172:     }
                    173:     switch (attr->def) {
                    174:         case XML_ATTRIBUTE_NONE:
                    175:            break;
                    176:         case XML_ATTRIBUTE_REQUIRED:
                    177:            fprintf(output, " REQUIRED");
                    178:            break;
                    179:         case XML_ATTRIBUTE_IMPLIED:
                    180:            fprintf(output, " IMPLIED");
                    181:            break;
                    182:         case XML_ATTRIBUTE_FIXED:
                    183:            fprintf(output, " FIXED");
                    184:            break;
                    185:     }
                    186:     if (attr->defaultValue != NULL) {
                    187:        fprintf(output, "\"");
                    188:        xmlDebugDumpString(output, attr->defaultValue);
                    189:        fprintf(output, "\"");
                    190:     }
                    191:     printf("\n");
                    192: 
                    193:     /*
                    194:      * Do a bit of checking
                    195:      */
                    196:     if (attr->parent == NULL)
                    197:        fprintf(output, "PBM: Attr has no parent\n");
                    198:     if (attr->doc == NULL)
                    199:        fprintf(output, "PBM: Attr has no doc\n");
                    200:     if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
                    201:        fprintf(output, "PBM: Attr doc differs from parent's one\n");
                    202:     if (attr->prev == NULL) {
                    203:        if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr))
                    204:            fprintf(output, "PBM: Attr has no prev and not first of list\n");
                    205:     } else {
                    206:        if (attr->prev->next != (xmlNodePtr) attr)
                    207:            fprintf(output, "PBM: Attr prev->next : back link wrong\n");
                    208:     }
                    209:     if (attr->next == NULL) {
                    210:        if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr))
                    211:            fprintf(output, "PBM: Attr has no next and not last of list\n");
                    212:     } else {
                    213:        if (attr->next->prev != (xmlNodePtr) attr)
                    214:            fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
                    215:     }
                    216: }
                    217: 
                    218: void xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) {
                    219:     int i;
                    220:     char shift[100];
                    221: 
                    222:     for (i = 0;((i < depth) && (i < 25));i++)
                    223:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    224:     shift[2 * i] = shift[2 * i + 1] = 0;
                    225: 
                    226:     fprintf(output, shift);
                    227: 
                    228:     if (elem->type != XML_ELEMENT_DECL) {
                    229:        fprintf(output, "PBM: not a Elem\n");
                    230:        return;
                    231:     }
1.27      veillard  232:     if (elem->name != NULL) {
                    233:        fprintf(output, "ELEMDECL(");
                    234:        xmlDebugDumpString(output, elem->name);
                    235:        fprintf(output, ")");
                    236:     } else
1.18      daniel    237:        fprintf(output, "PBM ELEMDECL noname!!!");
                    238:     switch (elem->etype) {
                    239:        case XML_ELEMENT_TYPE_EMPTY: 
                    240:            fprintf(output, ", EMPTY");
                    241:            break;
                    242:        case XML_ELEMENT_TYPE_ANY: 
                    243:            fprintf(output, ", ANY");
                    244:            break;
                    245:        case XML_ELEMENT_TYPE_MIXED: 
                    246:            fprintf(output, ", MIXED ");
                    247:            break;
                    248:        case XML_ELEMENT_TYPE_ELEMENT: 
                    249:            fprintf(output, ", MIXED ");
                    250:            break;
                    251:     }
                    252:     if (elem->content != NULL) {
1.30      veillard  253:        char buf[5001];
1.18      daniel    254: 
                    255:        buf[0] = 0;
                    256:        xmlSprintfElementContent(buf, elem->content, 1);
1.30      veillard  257:        buf[5000] = 0;
1.18      daniel    258:        fprintf(output, "%s", buf);
                    259:     }
                    260:     printf("\n");
                    261: 
                    262:     /*
                    263:      * Do a bit of checking
                    264:      */
                    265:     if (elem->parent == NULL)
                    266:        fprintf(output, "PBM: Elem has no parent\n");
                    267:     if (elem->doc == NULL)
                    268:        fprintf(output, "PBM: Elem has no doc\n");
                    269:     if ((elem->parent != NULL) && (elem->doc != elem->parent->doc))
                    270:        fprintf(output, "PBM: Elem doc differs from parent's one\n");
                    271:     if (elem->prev == NULL) {
                    272:        if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem))
                    273:            fprintf(output, "PBM: Elem has no prev and not first of list\n");
                    274:     } else {
                    275:        if (elem->prev->next != (xmlNodePtr) elem)
                    276:            fprintf(output, "PBM: Elem prev->next : back link wrong\n");
                    277:     }
                    278:     if (elem->next == NULL) {
                    279:        if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem))
                    280:            fprintf(output, "PBM: Elem has no next and not last of list\n");
                    281:     } else {
                    282:        if (elem->next->prev != (xmlNodePtr) elem)
                    283:            fprintf(output, "PBM: Elem next->prev : forward link wrong\n");
                    284:     }
                    285: }
                    286: 
1.20      daniel    287: void xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) {
                    288:     int i;
                    289:     char shift[100];
                    290: 
                    291:     for (i = 0;((i < depth) && (i < 25));i++)
                    292:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    293:     shift[2 * i] = shift[2 * i + 1] = 0;
                    294: 
                    295:     fprintf(output, shift);
                    296: 
                    297:     if (ent->type != XML_ENTITY_DECL) {
                    298:        fprintf(output, "PBM: not a Entity decl\n");
                    299:        return;
                    300:     }
1.27      veillard  301:     if (ent->name != NULL) {
                    302:        fprintf(output, "ENTITYDECL(");
                    303:        xmlDebugDumpString(output, ent->name);
                    304:        fprintf(output, ")");
                    305:     } else
1.20      daniel    306:        fprintf(output, "PBM ENTITYDECL noname!!!");
                    307:     switch (ent->etype) {
                    308:        case XML_INTERNAL_GENERAL_ENTITY: 
                    309:            fprintf(output, ", internal\n");
                    310:            break;
                    311:        case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 
                    312:            fprintf(output, ", external parsed\n");
                    313:            break;
                    314:        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 
                    315:            fprintf(output, ", unparsed\n");
                    316:            break;
                    317:        case XML_INTERNAL_PARAMETER_ENTITY: 
                    318:            fprintf(output, ", parameter\n");
                    319:            break;
                    320:        case XML_EXTERNAL_PARAMETER_ENTITY: 
                    321:            fprintf(output, ", external parameter\n");
                    322:            break;
                    323:        case XML_INTERNAL_PREDEFINED_ENTITY: 
                    324:            fprintf(output, ", predefined\n");
                    325:            break;
                    326:     }
                    327:     if (ent->ExternalID) {
                    328:         fprintf(output, shift);
1.32      veillard  329:         fprintf(output, " ExternalID=%s\n", ent->ExternalID);
1.20      daniel    330:     }
                    331:     if (ent->SystemID) {
                    332:         fprintf(output, shift);
1.32      veillard  333:         fprintf(output, " SystemID=%s\n", ent->SystemID);
                    334:     }
                    335:     if (ent->URI != NULL) {
                    336:         fprintf(output, shift);
                    337:         fprintf(output, " URI=%s\n", ent->URI);
1.20      daniel    338:     }
                    339:     if (ent->content) {
                    340:         fprintf(output, shift);
1.32      veillard  341:        fprintf(output, " content=");
1.20      daniel    342:        xmlDebugDumpString(output, ent->content);
                    343:        fprintf(output, "\n");
                    344:     }
                    345: 
                    346:     /*
                    347:      * Do a bit of checking
                    348:      */
                    349:     if (ent->parent == NULL)
                    350:        fprintf(output, "PBM: Ent has no parent\n");
                    351:     if (ent->doc == NULL)
                    352:        fprintf(output, "PBM: Ent has no doc\n");
                    353:     if ((ent->parent != NULL) && (ent->doc != ent->parent->doc))
                    354:        fprintf(output, "PBM: Ent doc differs from parent's one\n");
                    355:     if (ent->prev == NULL) {
                    356:        if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent))
                    357:            fprintf(output, "PBM: Ent has no prev and not first of list\n");
                    358:     } else {
                    359:        if (ent->prev->next != (xmlNodePtr) ent)
                    360:            fprintf(output, "PBM: Ent prev->next : back link wrong\n");
                    361:     }
                    362:     if (ent->next == NULL) {
                    363:        if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent))
                    364:            fprintf(output, "PBM: Ent has no next and not last of list\n");
                    365:     } else {
                    366:        if (ent->next->prev != (xmlNodePtr) ent)
                    367:            fprintf(output, "PBM: Ent next->prev : forward link wrong\n");
                    368:     }
                    369: }
                    370: 
1.1       daniel    371: void xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
                    372:     int i;
                    373:     char shift[100];
                    374: 
                    375:     for (i = 0;((i < depth) && (i < 25));i++)
                    376:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    377:     shift[2 * i] = shift[2 * i + 1] = 0;
                    378: 
                    379:     fprintf(output, shift);
1.45      veillard  380:     if (ns->type != XML_NAMESPACE_DECL) {
                    381:         fprintf(output, "invalid namespace node %d\n", ns->type);
                    382:        return;
                    383:     }
1.29      veillard  384:     if (ns->href == NULL) {
                    385:        if (ns->prefix != NULL)
                    386:            fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix);
                    387:        else
                    388:            fprintf(output, "incomplete default namespace href=NULL\n");
                    389:     } else {
                    390:        if (ns->prefix != NULL)
                    391:            fprintf(output, "namespace %s href=", ns->prefix);
                    392:        else
                    393:            fprintf(output, "default namespace href=");
1.10      daniel    394: 
1.29      veillard  395:        xmlDebugDumpString(output, ns->href);
                    396:        fprintf(output, "\n");
                    397:     }
1.1       daniel    398: }
                    399: 
                    400: void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
                    401:     while (ns != NULL) {
                    402:         xmlDebugDumpNamespace(output, ns, depth);
                    403:        ns = ns->next;
                    404:     }
                    405: }
                    406: 
                    407: void xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
                    408:     int i;
                    409:     char shift[100];
                    410: 
                    411:     for (i = 0;((i < depth) && (i < 25));i++)
                    412:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    413:     shift[2 * i] = shift[2 * i + 1] = 0;
                    414: 
                    415:     fprintf(output, shift);
1.19      daniel    416:     switch (ent->etype) {
1.1       daniel    417:         case XML_INTERNAL_GENERAL_ENTITY:
                    418:            fprintf(output, "INTERNAL_GENERAL_ENTITY ");
                    419:            break;
                    420:         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
                    421:            fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
                    422:            break;
                    423:         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
                    424:            fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
                    425:            break;
                    426:         case XML_INTERNAL_PARAMETER_ENTITY:
                    427:            fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
                    428:            break;
                    429:         case XML_EXTERNAL_PARAMETER_ENTITY:
                    430:            fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
                    431:            break;
                    432:        default:
1.19      daniel    433:            fprintf(output, "ENTITY_%d ! ", ent->etype);
1.1       daniel    434:     }
                    435:     fprintf(output, "%s\n", ent->name);
                    436:     if (ent->ExternalID) {
                    437:         fprintf(output, shift);
                    438:         fprintf(output, "ExternalID=%s\n", ent->ExternalID);
                    439:     }
                    440:     if (ent->SystemID) {
                    441:         fprintf(output, shift);
                    442:         fprintf(output, "SystemID=%s\n", ent->SystemID);
                    443:     }
1.32      veillard  444:     if (ent->URI) {
                    445:         fprintf(output, shift);
                    446:         fprintf(output, "URI=%s\n", ent->URI);
                    447:     }
1.1       daniel    448:     if (ent->content) {
                    449:         fprintf(output, shift);
                    450:        fprintf(output, "content=");
                    451:        xmlDebugDumpString(output, ent->content);
                    452:        fprintf(output, "\n");
                    453:     }
                    454: }
                    455: 
                    456: void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
                    457:     int i;
                    458:     char shift[100];
                    459: 
                    460:     for (i = 0;((i < depth) && (i < 25));i++)
                    461:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    462:     shift[2 * i] = shift[2 * i + 1] = 0;
                    463: 
                    464:     fprintf(output, shift);
1.18      daniel    465: 
1.27      veillard  466:     fprintf(output, "ATTRIBUTE ");
                    467:     xmlDebugDumpString(output, attr->name);
                    468:     fprintf(output, "\n");
1.16      daniel    469:     if (attr->children != NULL) 
                    470:         xmlDebugDumpNodeList(output, attr->children, depth + 1);
1.18      daniel    471: 
                    472:     /*
                    473:      * Do a bit of checking
                    474:      */
                    475:     if (attr->parent == NULL)
                    476:        fprintf(output, "PBM: Attr has no parent\n");
                    477:     if (attr->doc == NULL)
                    478:        fprintf(output, "PBM: Attr has no doc\n");
                    479:     if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
                    480:        fprintf(output, "PBM: Attr doc differs from parent's one\n");
                    481:     if (attr->prev == NULL) {
                    482:        if ((attr->parent != NULL) && (attr->parent->properties != attr))
                    483:            fprintf(output, "PBM: Attr has no prev and not first of list\n");
                    484:     } else {
                    485:        if (attr->prev->next != attr)
                    486:            fprintf(output, "PBM: Attr prev->next : back link wrong\n");
                    487:     }
                    488:     if (attr->next != NULL) {
                    489:        if (attr->next->prev != attr)
                    490:            fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
                    491:     }
1.1       daniel    492: }
                    493: 
                    494: void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) {
                    495:     while (attr != NULL) {
                    496:         xmlDebugDumpAttr(output, attr, depth);
                    497:        attr = attr->next;
                    498:     }
                    499: }
                    500: 
1.3       daniel    501: void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) {
1.1       daniel    502:     int i;
                    503:     char shift[100];
                    504: 
                    505:     for (i = 0;((i < depth) && (i < 25));i++)
                    506:         shift[2 * i] = shift[2 * i + 1] = ' ';
                    507:     shift[2 * i] = shift[2 * i + 1] = 0;
                    508: 
                    509:     switch (node->type) {
                    510:        case XML_ELEMENT_NODE:
1.21      daniel    511:            fprintf(output, shift);
1.1       daniel    512:            fprintf(output, "ELEMENT ");
1.27      veillard  513:            if (node->ns != NULL) {
                    514:                xmlDebugDumpString(output, node->ns->prefix);
                    515:                fprintf(output, ":");
                    516:            }
                    517:            xmlDebugDumpString(output, node->name);
                    518:            fprintf(output, "\n");
1.1       daniel    519:            break;
                    520:        case XML_ATTRIBUTE_NODE:
1.21      daniel    521:            fprintf(output, shift);
1.1       daniel    522:            fprintf(output, "Error, ATTRIBUTE found here\n");
                    523:            break;
                    524:        case XML_TEXT_NODE:
1.21      daniel    525:            fprintf(output, shift);
1.1       daniel    526:            fprintf(output, "TEXT\n");
                    527:            break;
                    528:        case XML_CDATA_SECTION_NODE:
1.21      daniel    529:            fprintf(output, shift);
1.1       daniel    530:            fprintf(output, "CDATA_SECTION\n");
                    531:            break;
                    532:        case XML_ENTITY_REF_NODE:
1.21      daniel    533:            fprintf(output, shift);
1.15      daniel    534:            fprintf(output, "ENTITY_REF(%s)\n", node->name);
1.1       daniel    535:            break;
                    536:        case XML_ENTITY_NODE:
1.21      daniel    537:            fprintf(output, shift);
1.1       daniel    538:            fprintf(output, "ENTITY\n");
                    539:            break;
                    540:        case XML_PI_NODE:
1.21      daniel    541:            fprintf(output, shift);
1.4       daniel    542:            fprintf(output, "PI %s\n", node->name);
1.1       daniel    543:            break;
                    544:        case XML_COMMENT_NODE:
1.21      daniel    545:            fprintf(output, shift);
1.1       daniel    546:            fprintf(output, "COMMENT\n");
                    547:            break;
                    548:        case XML_DOCUMENT_NODE:
1.7       daniel    549:        case XML_HTML_DOCUMENT_NODE:
1.21      daniel    550:            fprintf(output, shift);
1.1       daniel    551:            fprintf(output, "Error, DOCUMENT found here\n");
                    552:            break;
                    553:        case XML_DOCUMENT_TYPE_NODE:
1.21      daniel    554:            fprintf(output, shift);
1.1       daniel    555:            fprintf(output, "DOCUMENT_TYPE\n");
                    556:            break;
                    557:        case XML_DOCUMENT_FRAG_NODE:
1.21      daniel    558:            fprintf(output, shift);
1.1       daniel    559:            fprintf(output, "DOCUMENT_FRAG\n");
                    560:            break;
                    561:        case XML_NOTATION_NODE:
1.47    ! veillard  562:            fprintf(output, shift);
1.1       daniel    563:            fprintf(output, "NOTATION\n");
                    564:            break;
1.18      daniel    565:        case XML_DTD_NODE:
1.21      daniel    566:            xmlDebugDumpDtd(output, (xmlDtdPtr) node, depth);
1.18      daniel    567:            return;
                    568:        case XML_ELEMENT_DECL:
1.21      daniel    569:            xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
1.18      daniel    570:            return;
                    571:        case XML_ATTRIBUTE_DECL:
1.21      daniel    572:            xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
1.18      daniel    573:            return;
1.20      daniel    574:         case XML_ENTITY_DECL:
1.21      daniel    575:            xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
1.20      daniel    576:            return;
1.45      veillard  577:         case XML_NAMESPACE_DECL:
                    578:            xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth);
1.47    ! veillard  579:            return;
        !           580:         case XML_XINCLUDE_START:
        !           581:            fprintf(output, shift);
        !           582:            fprintf(output, "INCLUDE START\n");
        !           583:            return;
        !           584:         case XML_XINCLUDE_END:
        !           585:            fprintf(output, shift);
        !           586:            fprintf(output, "INCLUDE END\n");
1.45      veillard  587:            return;
1.1       daniel    588:        default:
1.21      daniel    589:            fprintf(output, shift);
1.40      veillard  590:            fprintf(output, "NODE_%d !!!\n", node->type);
                    591:            return;
1.1       daniel    592:     }
                    593:     if (node->doc == NULL) {
                    594:         fprintf(output, shift);
                    595:        fprintf(output, "doc == NULL !!!\n");
                    596:     }
                    597:     if (node->nsDef != NULL) 
                    598:         xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
                    599:     if (node->properties != NULL)
                    600:        xmlDebugDumpAttrList(output, node->properties, depth + 1);
                    601:     if (node->type != XML_ENTITY_REF_NODE) {
                    602:        if (node->content != NULL) {
1.38      veillard  603:             shift[2 * i] = shift[2 * i + 1] = ' ' ;
                    604:             shift[2 * i + 2] = shift[2 * i + 3] = 0 ;
1.1       daniel    605:            fprintf(output, shift);
                    606:            fprintf(output, "content=");
1.8       daniel    607: #ifndef XML_USE_BUFFER_CONTENT     
1.1       daniel    608:            xmlDebugDumpString(output, node->content);
1.8       daniel    609: #else
                    610:            xmlDebugDumpString(output, xmlBufferContent(node->content));
                    611: #endif
1.1       daniel    612:            fprintf(output, "\n");
                    613:        }
                    614:     } else {
                    615:         xmlEntityPtr ent;
                    616:        ent = xmlGetDocEntity(node->doc, node->name);
                    617:        if (ent != NULL)
                    618:            xmlDebugDumpEntity(output, ent, depth + 1);
1.18      daniel    619:     }
                    620:     /*
                    621:      * Do a bit of checking
                    622:      */
                    623:     if (node->parent == NULL)
                    624:        fprintf(output, "PBM: Node has no parent\n");
                    625:     if (node->doc == NULL)
                    626:        fprintf(output, "PBM: Node has no doc\n");
                    627:     if ((node->parent != NULL) && (node->doc != node->parent->doc))
                    628:        fprintf(output, "PBM: Node doc differs from parent's one\n");
                    629:     if (node->prev == NULL) {
                    630:        if ((node->parent != NULL) && (node->parent->children != node))
                    631:            fprintf(output, "PBM: Node has no prev and not first of list\n");
                    632:     } else {
                    633:        if (node->prev->next != node)
                    634:            fprintf(output, "PBM: Node prev->next : back link wrong\n");
                    635:     }
                    636:     if (node->next == NULL) {
                    637:        if ((node->parent != NULL) && (node->parent->last != node))
                    638:            fprintf(output, "PBM: Node has no next and not last of list\n");
                    639:     } else {
                    640:        if (node->next->prev != node)
                    641:            fprintf(output, "PBM: Node next->prev : forward link wrong\n");
1.1       daniel    642:     }
1.3       daniel    643: }
                    644: 
                    645: void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) {
                    646:     xmlDebugDumpOneNode(output, node, depth);
1.32      veillard  647:     if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
1.16      daniel    648:        xmlDebugDumpNodeList(output, node->children, depth + 1);
1.1       daniel    649: }
                    650: 
                    651: void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
                    652:     while (node != NULL) {
                    653:         xmlDebugDumpNode(output, node, depth);
                    654:        node = node->next;
                    655:     }
                    656: }
                    657: 
                    658: 
1.12      daniel    659: void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
1.1       daniel    660:     if (output == NULL) output = stdout;
                    661:     if (doc == NULL) {
                    662:         fprintf(output, "DOCUMENT == NULL !\n");
                    663:        return;
                    664:     }
                    665: 
                    666:     switch (doc->type) {
                    667:        case XML_ELEMENT_NODE:
                    668:            fprintf(output, "Error, ELEMENT found here ");
                    669:            break;
                    670:        case XML_ATTRIBUTE_NODE:
                    671:            fprintf(output, "Error, ATTRIBUTE found here\n");
                    672:            break;
                    673:        case XML_TEXT_NODE:
                    674:            fprintf(output, "Error, TEXT\n");
                    675:            break;
                    676:        case XML_CDATA_SECTION_NODE:
                    677:            fprintf(output, "Error, CDATA_SECTION\n");
                    678:            break;
                    679:        case XML_ENTITY_REF_NODE:
                    680:            fprintf(output, "Error, ENTITY_REF\n");
                    681:            break;
                    682:        case XML_ENTITY_NODE:
                    683:            fprintf(output, "Error, ENTITY\n");
                    684:            break;
                    685:        case XML_PI_NODE:
                    686:            fprintf(output, "Error, PI\n");
                    687:            break;
                    688:        case XML_COMMENT_NODE:
                    689:            fprintf(output, "Error, COMMENT\n");
                    690:            break;
                    691:        case XML_DOCUMENT_NODE:
                    692:            fprintf(output, "DOCUMENT\n");
1.7       daniel    693:            break;
                    694:        case XML_HTML_DOCUMENT_NODE:
                    695:            fprintf(output, "HTML DOCUMENT\n");
1.1       daniel    696:            break;
                    697:        case XML_DOCUMENT_TYPE_NODE:
                    698:            fprintf(output, "Error, DOCUMENT_TYPE\n");
                    699:            break;
                    700:        case XML_DOCUMENT_FRAG_NODE:
                    701:            fprintf(output, "Error, DOCUMENT_FRAG\n");
                    702:            break;
                    703:        case XML_NOTATION_NODE:
                    704:            fprintf(output, "Error, NOTATION\n");
                    705:            break;
                    706:        default:
                    707:            fprintf(output, "NODE_%d\n", doc->type);
                    708:     }
                    709:     if (doc->name != NULL) {
                    710:        fprintf(output, "name=");
1.5       daniel    711:         xmlDebugDumpString(output, BAD_CAST doc->name);
1.1       daniel    712:        fprintf(output, "\n");
                    713:     }
                    714:     if (doc->version != NULL) {
                    715:        fprintf(output, "version=");
                    716:         xmlDebugDumpString(output, doc->version);
                    717:        fprintf(output, "\n");
                    718:     }
                    719:     if (doc->encoding != NULL) {
                    720:        fprintf(output, "encoding=");
                    721:         xmlDebugDumpString(output, doc->encoding);
1.32      veillard  722:        fprintf(output, "\n");
                    723:     }
                    724:     if (doc->URL != NULL) {
                    725:        fprintf(output, "URL=");
                    726:         xmlDebugDumpString(output, doc->URL);
1.1       daniel    727:        fprintf(output, "\n");
                    728:     }
                    729:     if (doc->standalone)
                    730:         fprintf(output, "standalone=true\n");
                    731:     if (doc->oldNs != NULL) 
                    732:         xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
1.12      daniel    733: }
                    734: 
                    735: void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
                    736:     if (output == NULL) output = stdout;
                    737:     if (doc == NULL) {
                    738:         fprintf(output, "DOCUMENT == NULL !\n");
                    739:        return;
                    740:     }
                    741:     xmlDebugDumpDocumentHead(output, doc);
                    742:     if (((doc->type == XML_DOCUMENT_NODE) ||
                    743:          (doc->type == XML_HTML_DOCUMENT_NODE)) &&
1.16      daniel    744:         (doc->children != NULL))
                    745:         xmlDebugDumpNodeList(output, doc->children, 1);
1.12      daniel    746: }    
1.30      veillard  747: 
                    748: void xmlDebugDumpDTD(FILE *output, xmlDtdPtr dtd) {
                    749:     if (dtd == NULL)
                    750:        return;
                    751:     if (dtd->type != XML_DTD_NODE) {
                    752:        fprintf(output, "PBM: not a DTD\n");
                    753:        return;
                    754:     }
                    755:     if (dtd->name != NULL)
                    756:        fprintf(output, "DTD(%s)", dtd->name);
                    757:     else
                    758:        fprintf(output, "DTD");
                    759:     if (dtd->ExternalID != NULL)
                    760:        fprintf(output, ", PUBLIC %s", dtd->ExternalID);
                    761:     if (dtd->SystemID != NULL)
                    762:        fprintf(output, ", SYSTEM %s", dtd->SystemID);
                    763:     fprintf(output, "\n");
                    764:     /*
                    765:      * Do a bit of checking
                    766:      */
                    767:     if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
                    768:        fprintf(output, "PBM: Dtd doc differs from parent's one\n");
                    769:     if (dtd->prev == NULL) {
                    770:        if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
                    771:            fprintf(output, "PBM: Dtd has no prev and not first of list\n");
                    772:     } else {
                    773:        if (dtd->prev->next != (xmlNodePtr) dtd)
                    774:            fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
                    775:     }
                    776:     if (dtd->next == NULL) {
                    777:        if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
                    778:            fprintf(output, "PBM: Dtd has no next and not last of list\n");
                    779:     } else {
                    780:        if (dtd->next->prev != (xmlNodePtr) dtd)
                    781:            fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
                    782:     }
                    783:     if (dtd->children == NULL)
                    784:        fprintf(output, "    DTD is empty\n");
                    785:     else
                    786:         xmlDebugDumpNodeList(output, dtd->children, 1);
                    787: }
1.9       daniel    788: 
1.43      veillard  789: void xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output,
                    790:                                const xmlChar *name) {
                    791:     fprintf(output, "%s : ", cur->name);
                    792:     switch (cur->etype) {
                    793:        case XML_INTERNAL_GENERAL_ENTITY:
                    794:            fprintf(output, "INTERNAL GENERAL, ");
                    795:            break;
                    796:        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
                    797:            fprintf(output, "EXTERNAL PARSED, ");
                    798:            break;
                    799:        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
                    800:            fprintf(output, "EXTERNAL UNPARSED, ");
                    801:            break;
                    802:        case XML_INTERNAL_PARAMETER_ENTITY:
                    803:            fprintf(output, "INTERNAL PARAMETER, ");
                    804:            break;
                    805:        case XML_EXTERNAL_PARAMETER_ENTITY:
                    806:            fprintf(output, "EXTERNAL PARAMETER, ");
                    807:            break;
                    808:        default:
                    809:            fprintf(output, "UNKNOWN TYPE %d",
                    810:                    cur->etype);
                    811:     }
                    812:     if (cur->ExternalID != NULL) 
                    813:        fprintf(output, "ID \"%s\"", cur->ExternalID);
                    814:     if (cur->SystemID != NULL)
                    815:        fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
                    816:     if (cur->orig != NULL)
                    817:        fprintf(output, "\n orig \"%s\"", cur->orig);
                    818:     if (cur->content != NULL)
                    819:        fprintf(output, "\n content \"%s\"", cur->content);
                    820:     fprintf(output, "\n");     
                    821: }
                    822: 
1.9       daniel    823: void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
                    824:     if (output == NULL) output = stdout;
                    825:     if (doc == NULL) {
                    826:         fprintf(output, "DOCUMENT == NULL !\n");
                    827:        return;
                    828:     }
                    829: 
                    830:     switch (doc->type) {
                    831:        case XML_ELEMENT_NODE:
                    832:            fprintf(output, "Error, ELEMENT found here ");
                    833:            break;
                    834:        case XML_ATTRIBUTE_NODE:
                    835:            fprintf(output, "Error, ATTRIBUTE found here\n");
                    836:            break;
                    837:        case XML_TEXT_NODE:
                    838:            fprintf(output, "Error, TEXT\n");
                    839:            break;
                    840:        case XML_CDATA_SECTION_NODE:
                    841:            fprintf(output, "Error, CDATA_SECTION\n");
                    842:            break;
                    843:        case XML_ENTITY_REF_NODE:
                    844:            fprintf(output, "Error, ENTITY_REF\n");
                    845:            break;
                    846:        case XML_ENTITY_NODE:
                    847:            fprintf(output, "Error, ENTITY\n");
                    848:            break;
                    849:        case XML_PI_NODE:
                    850:            fprintf(output, "Error, PI\n");
                    851:            break;
                    852:        case XML_COMMENT_NODE:
                    853:            fprintf(output, "Error, COMMENT\n");
                    854:            break;
                    855:        case XML_DOCUMENT_NODE:
                    856:            fprintf(output, "DOCUMENT\n");
                    857:            break;
                    858:        case XML_HTML_DOCUMENT_NODE:
                    859:            fprintf(output, "HTML DOCUMENT\n");
                    860:            break;
                    861:        case XML_DOCUMENT_TYPE_NODE:
                    862:            fprintf(output, "Error, DOCUMENT_TYPE\n");
                    863:            break;
                    864:        case XML_DOCUMENT_FRAG_NODE:
                    865:            fprintf(output, "Error, DOCUMENT_FRAG\n");
                    866:            break;
                    867:        case XML_NOTATION_NODE:
                    868:            fprintf(output, "Error, NOTATION\n");
                    869:            break;
                    870:        default:
                    871:            fprintf(output, "NODE_%d\n", doc->type);
                    872:     }
                    873:     if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
                    874:         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 
                    875:                                    doc->intSubset->entities;
                    876:        fprintf(output, "Entities in internal subset\n");
1.43      veillard  877:        xmlHashScan(table, (xmlHashScanner)xmlDebugDumpEntityCallback, output);
1.9       daniel    878:     } else
                    879:        fprintf(output, "No entities in internal subset\n");
                    880:     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
                    881:         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 
                    882:                                    doc->extSubset->entities;
                    883:        fprintf(output, "Entities in external subset\n");
1.43      veillard  884:        xmlHashScan(table, (xmlHashScanner)xmlDebugDumpEntityCallback, output);
1.9       daniel    885:     } else
                    886:        fprintf(output, "No entities in external subset\n");
                    887: }
1.12      daniel    888: 
                    889: static int xmlLsCountNode(xmlNodePtr node) {
                    890:     int ret = 0;
                    891:     xmlNodePtr list = NULL;
                    892: 
                    893:     switch (node->type) {
                    894:        case XML_ELEMENT_NODE:
1.16      daniel    895:            list = node->children;
1.12      daniel    896:            break;
                    897:        case XML_DOCUMENT_NODE:
                    898:        case XML_HTML_DOCUMENT_NODE:
1.33      veillard  899: #ifdef LIBXML_SGML_ENABLED
                    900:        case XML_SGML_DOCUMENT_NODE:
                    901: #endif
1.16      daniel    902:            list = ((xmlDocPtr) node)->children;
1.12      daniel    903:            break;
                    904:        case XML_ATTRIBUTE_NODE:
1.16      daniel    905:            list = ((xmlAttrPtr) node)->children;
1.12      daniel    906:            break;
                    907:        case XML_TEXT_NODE:
                    908:        case XML_CDATA_SECTION_NODE:
                    909:        case XML_PI_NODE:
                    910:        case XML_COMMENT_NODE:
                    911:            if (node->content != NULL) {
                    912: #ifndef XML_USE_BUFFER_CONTENT     
                    913:                ret = xmlStrlen(node->content);
                    914: #else
                    915:                ret = xmlBufferLength(node->content);
                    916: #endif
                    917:             }
                    918:            break;
                    919:        case XML_ENTITY_REF_NODE:
                    920:        case XML_DOCUMENT_TYPE_NODE:
                    921:        case XML_ENTITY_NODE:
                    922:        case XML_DOCUMENT_FRAG_NODE:
                    923:        case XML_NOTATION_NODE:
1.16      daniel    924:        case XML_DTD_NODE:
1.17      daniel    925:         case XML_ELEMENT_DECL:
                    926:         case XML_ATTRIBUTE_DECL:
1.20      daniel    927:         case XML_ENTITY_DECL:
1.45      veillard  928:        case XML_NAMESPACE_DECL:
1.46      veillard  929:        case XML_XINCLUDE_START:
                    930:        case XML_XINCLUDE_END:
1.12      daniel    931:            ret = 1;
                    932:            break;
                    933:     }
                    934:     for (;list != NULL;ret++) 
                    935:         list = list->next;
                    936:     return(ret);
                    937: }
                    938: 
                    939: void xmlLsOneNode(FILE *output, xmlNodePtr node) {
                    940:     switch (node->type) {
                    941:        case XML_ELEMENT_NODE:
                    942:            fprintf(output, "-");
                    943:            break;
                    944:        case XML_ATTRIBUTE_NODE:
                    945:            fprintf(output, "a");
                    946:            break;
                    947:        case XML_TEXT_NODE:
                    948:            fprintf(output, "t");
                    949:            break;
                    950:        case XML_CDATA_SECTION_NODE:
                    951:            fprintf(output, "c");
                    952:            break;
                    953:        case XML_ENTITY_REF_NODE:
                    954:            fprintf(output, "e");
                    955:            break;
                    956:        case XML_ENTITY_NODE:
                    957:            fprintf(output, "E");
                    958:            break;
                    959:        case XML_PI_NODE:
                    960:            fprintf(output, "p");
                    961:            break;
                    962:        case XML_COMMENT_NODE:
                    963:            fprintf(output, "c");
                    964:            break;
                    965:        case XML_DOCUMENT_NODE:
                    966:            fprintf(output, "d");
                    967:            break;
                    968:        case XML_HTML_DOCUMENT_NODE:
                    969:            fprintf(output, "h");
                    970:            break;
                    971:        case XML_DOCUMENT_TYPE_NODE:
                    972:            fprintf(output, "T");
                    973:            break;
                    974:        case XML_DOCUMENT_FRAG_NODE:
                    975:            fprintf(output, "F");
                    976:            break;
                    977:        case XML_NOTATION_NODE:
                    978:            fprintf(output, "N");
                    979:            break;
                    980:        default:
                    981:            fprintf(output, "?");
                    982:     }
                    983:     if (node->properties != NULL)
                    984:        fprintf(output, "a");
                    985:     else       
                    986:        fprintf(output, "-");
                    987:     if (node->nsDef != NULL) 
                    988:        fprintf(output, "n");
                    989:     else       
                    990:        fprintf(output, "-");
                    991: 
                    992:     fprintf(output, " %8d ", xmlLsCountNode(node));
                    993: 
                    994:     switch (node->type) {
                    995:        case XML_ELEMENT_NODE:
                    996:            if (node->name != NULL)
                    997:                fprintf(output, "%s", node->name);
                    998:            break;
                    999:        case XML_ATTRIBUTE_NODE:
                   1000:            if (node->name != NULL)
                   1001:                fprintf(output, "%s", node->name);
                   1002:            break;
                   1003:        case XML_TEXT_NODE:
                   1004:            if (node->content != NULL) {
                   1005: #ifndef XML_USE_BUFFER_CONTENT     
                   1006:                xmlDebugDumpString(output, node->content);
                   1007: #else
                   1008:                xmlDebugDumpString(output, xmlBufferContent(node->content));
                   1009: #endif
                   1010:             }
                   1011:            break;
                   1012:        case XML_CDATA_SECTION_NODE:
                   1013:            break;
                   1014:        case XML_ENTITY_REF_NODE:
                   1015:            if (node->name != NULL)
                   1016:                fprintf(output, "%s", node->name);
                   1017:            break;
                   1018:        case XML_ENTITY_NODE:
                   1019:            if (node->name != NULL)
                   1020:                fprintf(output, "%s", node->name);
                   1021:            break;
                   1022:        case XML_PI_NODE:
                   1023:            if (node->name != NULL)
                   1024:                fprintf(output, "%s", node->name);
                   1025:            break;
                   1026:        case XML_COMMENT_NODE:
                   1027:            break;
                   1028:        case XML_DOCUMENT_NODE:
                   1029:            break;
                   1030:        case XML_HTML_DOCUMENT_NODE:
                   1031:            break;
                   1032:        case XML_DOCUMENT_TYPE_NODE:
                   1033:            break;
                   1034:        case XML_DOCUMENT_FRAG_NODE:
                   1035:            break;
                   1036:        case XML_NOTATION_NODE:
                   1037:            break;
                   1038:        default:
                   1039:            if (node->name != NULL)
                   1040:                fprintf(output, "%s", node->name);
                   1041:     }
                   1042:     fprintf(output, "\n");
                   1043: }
                   1044: 
                   1045: /****************************************************************
                   1046:  *                                                             *
                   1047:  *             The XML shell related functions                 *
                   1048:  *                                                             *
                   1049:  ****************************************************************/
                   1050: 
                   1051: /*
                   1052:  * TODO: Improvement/cleanups for the XML shell
                   1053:  *     - allow to shell out an editor on a subpart
                   1054:  *     - cleanup function registrations (with help) and calling
                   1055:  *     - provide registration routines
                   1056:  */
                   1057: 
                   1058: /**
                   1059:  * xmlShellList:
                   1060:  * @ctxt:  the shell context
                   1061:  * @arg:  unused
                   1062:  * @node:  a node
                   1063:  * @node2:  unused
                   1064:  *
                   1065:  * Implements the XML shell function "ls"
                   1066:  * Does an Unix like listing of the given node (like a directory)
                   1067:  *
                   1068:  * Returns 0
                   1069:  */
                   1070: int
                   1071: xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
                   1072:                   xmlNodePtr node2) {
                   1073:     xmlNodePtr cur;
                   1074: 
                   1075:     if ((node->type == XML_DOCUMENT_NODE) ||
                   1076:         (node->type == XML_HTML_DOCUMENT_NODE)) {
1.16      daniel   1077:         cur = ((xmlDocPtr) node)->children;
                   1078:     } else if (node->children != NULL) {
                   1079:         cur = node->children;
1.12      daniel   1080:     } else {
                   1081:        xmlLsOneNode(stdout, node);
                   1082:         return(0);
                   1083:     }
                   1084:     while (cur != NULL) {
                   1085:        xmlLsOneNode(stdout, cur);
                   1086:        cur = cur->next;
                   1087:     }
                   1088:     return(0);
                   1089: }
                   1090: 
                   1091: /**
                   1092:  * xmlShellDir:
                   1093:  * @ctxt:  the shell context
                   1094:  * @arg:  unused
                   1095:  * @node:  a node
                   1096:  * @node2:  unused
                   1097:  *
                   1098:  * Implements the XML shell function "dir"
                   1099:  * dumps informations about the node (namespace, attributes, content).
                   1100:  *
                   1101:  * Returns 0
                   1102:  */
                   1103: int
                   1104: xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
                   1105:                   xmlNodePtr node2) {
                   1106:     if ((node->type == XML_DOCUMENT_NODE) ||
                   1107:         (node->type == XML_HTML_DOCUMENT_NODE)) {
                   1108:        xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
                   1109:     } else if (node->type == XML_ATTRIBUTE_NODE) {
                   1110:        xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
                   1111:     } else {
                   1112:        xmlDebugDumpOneNode(stdout, node, 0);
                   1113:     }
                   1114:     return(0);
                   1115: }
                   1116: 
                   1117: /**
                   1118:  * xmlShellCat:
                   1119:  * @ctxt:  the shell context
                   1120:  * @arg:  unused
                   1121:  * @node:  a node
                   1122:  * @node2:  unused
                   1123:  *
                   1124:  * Implements the XML shell function "cat"
                   1125:  * dumps the serialization node content (XML or HTML).
                   1126:  *
                   1127:  * Returns 0
                   1128:  */
                   1129: int
                   1130: xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
                   1131:                   xmlNodePtr node2) {
1.13      daniel   1132:     if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
1.23      daniel   1133: #ifdef LIBXML_HTML_ENABLED
1.13      daniel   1134:        if (node->type == XML_HTML_DOCUMENT_NODE)
                   1135:            htmlDocDump(stdout, (htmlDocPtr) node);
                   1136:        else
1.14      daniel   1137:            htmlNodeDumpFile(stdout, ctxt->doc, node);
1.23      daniel   1138: #else
                   1139:        if (node->type == XML_DOCUMENT_NODE)
                   1140:            xmlDocDump(stdout, (xmlDocPtr) node);
                   1141:        else
                   1142:            xmlElemDump(stdout, ctxt->doc, node);
                   1143: #endif /* LIBXML_HTML_ENABLED */
1.13      daniel   1144:     } else {
                   1145:        if (node->type == XML_DOCUMENT_NODE)
                   1146:            xmlDocDump(stdout, (xmlDocPtr) node);
                   1147:        else
                   1148:            xmlElemDump(stdout, ctxt->doc, node);
                   1149:     }
1.12      daniel   1150:     printf("\n");
                   1151:     return(0);
                   1152: }
                   1153: 
                   1154: /**
                   1155:  * xmlShellLoad:
                   1156:  * @ctxt:  the shell context
                   1157:  * @filename:  the file name
                   1158:  * @node:  unused
                   1159:  * @node2:  unused
                   1160:  *
                   1161:  * Implements the XML shell function "load"
                   1162:  * loads a new document specified by the filename
                   1163:  *
                   1164:  * Returns 0 or -1 if loading failed
                   1165:  */
                   1166: int
                   1167: xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
                   1168:              xmlNodePtr node2) {
                   1169:     xmlDocPtr doc;
                   1170:     int html = 0;
                   1171: 
                   1172:     if (ctxt->doc != NULL)
                   1173:        html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
                   1174: 
                   1175:     if (html) {
1.23      daniel   1176: #ifdef LIBXML_HTML_ENABLED
1.12      daniel   1177:        doc = htmlParseFile(filename, NULL);
1.23      daniel   1178: #else  
                   1179:        printf("HTML support not compiled in\n");
                   1180:        doc = NULL;
                   1181: #endif /* LIBXML_HTML_ENABLED */
1.12      daniel   1182:     } else {
                   1183:        doc = xmlParseFile(filename);
                   1184:     }
                   1185:     if (doc != NULL) {
                   1186:         if (ctxt->loaded == 1) {
                   1187:            xmlFreeDoc(ctxt->doc);
                   1188:        }
                   1189:        ctxt->loaded = 1;
1.23      daniel   1190: #ifdef LIBXML_XPATH_ENABLED
1.12      daniel   1191:        xmlXPathFreeContext(ctxt->pctxt);
1.23      daniel   1192: #endif /* LIBXML_XPATH_ENABLED */
1.12      daniel   1193:        xmlFree(ctxt->filename);
                   1194:        ctxt->doc = doc;
                   1195:        ctxt->node = (xmlNodePtr) doc;   
1.23      daniel   1196: #ifdef LIBXML_XPATH_ENABLED
1.12      daniel   1197:        ctxt->pctxt = xmlXPathNewContext(doc);
1.23      daniel   1198: #endif /* LIBXML_XPATH_ENABLED */
1.12      daniel   1199:        ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
                   1200:     } else
                   1201:         return(-1);
                   1202:     return(0);
                   1203: }
                   1204: 
                   1205: /**
                   1206:  * xmlShellWrite:
                   1207:  * @ctxt:  the shell context
                   1208:  * @filename:  the file name
                   1209:  * @node:  a node in the tree
                   1210:  * @node2:  unused
                   1211:  *
                   1212:  * Implements the XML shell function "write"
                   1213:  * Write the current node to the filename, it saves the serailization
                   1214:  * of the subtree under the @node specified
                   1215:  *
                   1216:  * Returns 0 or -1 in case of error
                   1217:  */
                   1218: int
                   1219: xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
                   1220:                   xmlNodePtr node2) {
                   1221:     if (node == NULL)
                   1222:         return(-1);
                   1223:     if ((filename == NULL) || (filename[0] == 0)) {
1.44      veillard 1224:         xmlGenericError(xmlGenericErrorContext,
                   1225:                "Write command requires a filename argument\n");
1.12      daniel   1226:        return(-1);
                   1227:     }
                   1228: #ifdef W_OK
                   1229:     if (access((char *) filename, W_OK)) {
1.44      veillard 1230:         xmlGenericError(xmlGenericErrorContext,
                   1231:                "Cannot write to %s\n", filename);
1.12      daniel   1232:        return(-1);
                   1233:     }
                   1234: #endif    
                   1235:     switch(node->type) {
                   1236:         case XML_DOCUMENT_NODE:
                   1237:            if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1.44      veillard 1238:                xmlGenericError(xmlGenericErrorContext,
                   1239:                        "Failed to write to %s\n", filename);
1.12      daniel   1240:                return(-1);
                   1241:            }
                   1242:            break;
                   1243:         case XML_HTML_DOCUMENT_NODE:
1.23      daniel   1244: #ifdef LIBXML_HTML_ENABLED
1.12      daniel   1245:            if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1.44      veillard 1246:                xmlGenericError(xmlGenericErrorContext,
                   1247:                        "Failed to write to %s\n", filename);
1.12      daniel   1248:                return(-1);
                   1249:            }
1.23      daniel   1250: #else
                   1251:            if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1.44      veillard 1252:                xmlGenericError(xmlGenericErrorContext,
                   1253:                        "Failed to write to %s\n", filename);
1.23      daniel   1254:                return(-1);
                   1255:            }
                   1256: #endif /* LIBXML_HTML_ENABLED */
1.12      daniel   1257:            break;
                   1258:        default: {
                   1259:            FILE *f;
                   1260: 
                   1261:            f = fopen((char *) filename, "w");
                   1262:            if (f == NULL) {
1.44      veillard 1263:                xmlGenericError(xmlGenericErrorContext,
                   1264:                        "Failed to write to %s\n", filename);
1.12      daniel   1265:                return(-1);
                   1266:            }
                   1267:            xmlElemDump(f, ctxt->doc, node);
                   1268:            fclose(f);
                   1269:        }
                   1270:     }
                   1271:     return(0);
                   1272: }
                   1273: 
                   1274: /**
                   1275:  * xmlShellSave:
                   1276:  * @ctxt:  the shell context
                   1277:  * @filename:  the file name (optionnal)
                   1278:  * @node:  unused
                   1279:  * @node2:  unused
                   1280:  *
                   1281:  * Implements the XML shell function "save"
                   1282:  * Write the current document to the filename, or it's original name
                   1283:  *
                   1284:  * Returns 0 or -1 in case of error
                   1285:  */
                   1286: int 
                   1287: xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
                   1288:              xmlNodePtr node2) {
                   1289:     if (ctxt->doc == NULL)
                   1290:        return(-1);
                   1291:     if ((filename == NULL) || (filename[0] == 0))
                   1292:         filename = ctxt->filename;
                   1293: #ifdef W_OK
                   1294:     if (access((char *) filename, W_OK)) {
1.44      veillard 1295:         xmlGenericError(xmlGenericErrorContext,
                   1296:                "Cannot save to %s\n", filename);
1.12      daniel   1297:        return(-1);
                   1298:     }
                   1299: #endif
                   1300:     switch(ctxt->doc->type) {
                   1301:         case XML_DOCUMENT_NODE:
                   1302:            if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1.44      veillard 1303:                xmlGenericError(xmlGenericErrorContext,
                   1304:                        "Failed to save to %s\n", filename);
1.12      daniel   1305:            }
                   1306:            break;
                   1307:         case XML_HTML_DOCUMENT_NODE:
1.23      daniel   1308: #ifdef LIBXML_HTML_ENABLED
1.12      daniel   1309:            if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1.44      veillard 1310:                xmlGenericError(xmlGenericErrorContext,
                   1311:                        "Failed to save to %s\n", filename);
1.12      daniel   1312:            }
1.23      daniel   1313: #else
                   1314:            if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1.44      veillard 1315:                xmlGenericError(xmlGenericErrorContext,
                   1316:                        "Failed to save to %s\n", filename);
1.23      daniel   1317:            }
                   1318: #endif /* LIBXML_HTML_ENABLED */
1.12      daniel   1319:            break;
                   1320:        default:
1.44      veillard 1321:            xmlGenericError(xmlGenericErrorContext, 
1.12      daniel   1322:              "To save to subparts of a document use the 'write' command\n");
                   1323:            return(-1);
                   1324:            
                   1325:     }
                   1326:     return(0);
                   1327: }
                   1328: 
                   1329: /**
                   1330:  * xmlShellValidate:
                   1331:  * @ctxt:  the shell context
                   1332:  * @dtd:  the DTD URI (optionnal)
                   1333:  * @node:  unused
                   1334:  * @node2:  unused
                   1335:  *
                   1336:  * Implements the XML shell function "validate"
                   1337:  * Validate the document, if a DTD path is provided, then the validation
                   1338:  * is done against the given DTD.
                   1339:  *
                   1340:  * Returns 0 or -1 in case of error
                   1341:  */
                   1342: int 
                   1343: xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
                   1344:                  xmlNodePtr node2) {
                   1345:     xmlValidCtxt vctxt;
                   1346:     int res = -1;
                   1347: 
                   1348:     vctxt.userData = stderr;
                   1349:     vctxt.error = (xmlValidityErrorFunc) fprintf;
                   1350:     vctxt.warning = (xmlValidityWarningFunc) fprintf;
                   1351: 
                   1352:     if ((dtd == NULL) || (dtd[0] == 0)) {
                   1353:         res = xmlValidateDocument(&vctxt, ctxt->doc);
                   1354:     } else {
                   1355:         xmlDtdPtr subset;
                   1356: 
                   1357:        subset = xmlParseDTD(NULL, (xmlChar *) dtd);
                   1358:        if (subset != NULL) {
                   1359:             res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
                   1360: 
                   1361:            xmlFreeDtd(subset);
                   1362:        }
                   1363:     }
                   1364:     return(res);
                   1365: }
                   1366: 
                   1367: /**
                   1368:  * xmlShellDu:
                   1369:  * @ctxt:  the shell context
                   1370:  * @arg:  unused
                   1371:  * @tree:  a node defining a subtree
                   1372:  * @node2:  unused
                   1373:  *
                   1374:  * Implements the XML shell function "du"
                   1375:  * show the structure of the subtree under node @tree
                   1376:  * If @tree is null, the command works on the current node.
                   1377:  *
                   1378:  * Returns 0 or -1 in case of error
                   1379:  */
                   1380: int 
                   1381: xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
                   1382:                   xmlNodePtr node2) {
                   1383:     xmlNodePtr node;
                   1384:     int indent = 0,i;
                   1385: 
                   1386:     if (tree == NULL) return(-1);
                   1387:     node = tree;
                   1388:     while (node != NULL) {
                   1389:         if ((node->type == XML_DOCUMENT_NODE) ||
                   1390:             (node->type == XML_HTML_DOCUMENT_NODE)) {
                   1391:            printf("/\n");
                   1392:        } else if (node->type == XML_ELEMENT_NODE) {
                   1393:            for (i = 0;i < indent;i++)
                   1394:                printf("  ");
                   1395:            printf("%s\n", node->name);
                   1396:        } else {
                   1397:        }
                   1398: 
                   1399:        /*
                   1400:         * Browse the full subtree, deep first
                   1401:         */
                   1402: 
                   1403:         if ((node->type == XML_DOCUMENT_NODE) ||
                   1404:             (node->type == XML_HTML_DOCUMENT_NODE)) {
1.16      daniel   1405:            node = ((xmlDocPtr) node)->children;
1.25      daniel   1406:         } else if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1.12      daniel   1407:            /* deep first */
1.16      daniel   1408:            node = node->children;
1.12      daniel   1409:            indent++;
                   1410:        } else if ((node != tree) && (node->next != NULL)) {
                   1411:            /* then siblings */
                   1412:            node = node->next;
                   1413:        } else if (node != tree) {
                   1414:            /* go up to parents->next if needed */
                   1415:            while (node != tree) {
                   1416:                if (node->parent != NULL) {
                   1417:                    node = node->parent;
                   1418:                    indent--;
                   1419:                }
                   1420:                if ((node != tree) && (node->next != NULL)) {
                   1421:                    node = node->next;
                   1422:                    break;
                   1423:                }
                   1424:                if (node->parent == NULL) {
                   1425:                    node = NULL;
                   1426:                    break;
                   1427:                }
                   1428:                if (node == tree) {
                   1429:                    node = NULL;
                   1430:                    break;
                   1431:                }
                   1432:            }
                   1433:            /* exit condition */
                   1434:            if (node == tree) 
                   1435:                node = NULL;
                   1436:        } else
                   1437:            node = NULL;
                   1438:     }
                   1439:     return(0);
                   1440: }
                   1441: 
                   1442: /**
                   1443:  * xmlShellPwd:
                   1444:  * @ctxt:  the shell context
                   1445:  * @buffer:  the output buffer
                   1446:  * @tree:  a node 
                   1447:  * @node2:  unused
                   1448:  *
                   1449:  * Implements the XML shell function "pwd"
                   1450:  * Show the full path from the root to the node, if needed building
                   1451:  * thumblers when similar elements exists at a given ancestor level.
                   1452:  * The output is compatible with XPath commands.
                   1453:  *
                   1454:  * Returns 0 or -1 in case of error
                   1455:  */
                   1456: int 
                   1457: xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
                   1458:                   xmlNodePtr node2) {
                   1459:     xmlNodePtr cur, tmp, next;
                   1460:     char buf[500];
                   1461:     char sep;
                   1462:     const char *name;
                   1463:     int occur = 0;
                   1464: 
                   1465:     buffer[0] = 0;
                   1466:     if (node == NULL) return(-1);
                   1467:     cur = node;
                   1468:     do {
                   1469:        name = "";
                   1470:        sep= '?';
                   1471:        occur = 0;
                   1472:        if ((cur->type == XML_DOCUMENT_NODE) ||
                   1473:            (cur->type == XML_HTML_DOCUMENT_NODE)) {
                   1474:            sep = '/';
                   1475:            next = NULL;
                   1476:        } else if (cur->type == XML_ELEMENT_NODE) {
                   1477:            sep = '/';
                   1478:            name = (const char *)cur->name;
                   1479:            next = cur->parent;
                   1480: 
                   1481:            /*
                   1482:             * Thumbler index computation
                   1483:             */
                   1484:            tmp = cur->prev;
                   1485:             while (tmp != NULL) {
1.35      veillard 1486:                if (xmlStrEqual(cur->name, tmp->name))
1.12      daniel   1487:                    occur++;
                   1488:                tmp = tmp->prev;
                   1489:            }
                   1490:            if (occur == 0) {
                   1491:                tmp = cur->next;
                   1492:                while (tmp != NULL) {
1.35      veillard 1493:                    if (xmlStrEqual(cur->name, tmp->name))
1.12      daniel   1494:                        occur++;
                   1495:                    tmp = tmp->next;
                   1496:                }
                   1497:                if (occur != 0) occur = 1;
                   1498:            } else
                   1499:                occur++;
                   1500:        } else if (cur->type == XML_ATTRIBUTE_NODE) {
                   1501:            sep = '@';
                   1502:            name = (const char *) (((xmlAttrPtr) cur)->name);
1.16      daniel   1503:            next = ((xmlAttrPtr) cur)->parent;
1.12      daniel   1504:        } else {
                   1505:            next = cur->parent;
                   1506:        }
                   1507:        if (occur == 0)
1.31      veillard 1508: #ifdef HAVE_SNPRINTF
                   1509:            snprintf(buf, sizeof(buf), "%c%s%s", sep, name, buffer);
                   1510: #else
1.12      daniel   1511:            sprintf(buf, "%c%s%s", sep, name, buffer);
1.31      veillard 1512: #endif
                   1513:         else
                   1514: #ifdef HAVE_SNPRINTF
                   1515:            snprintf(buf, sizeof(buf), "%c%s[%d]%s",
                   1516:                     sep, name, occur, buffer);
                   1517: #else
1.12      daniel   1518:            sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
1.31      veillard 1519: #endif
                   1520:         buf[sizeof(buf) - 1] = 0;
                   1521:         /*
                   1522:          * This test prevents buffer overflow, because this routine
                   1523:          * is only called by xmlShell, in which the second argument is
                   1524:          * 500 chars long.
                   1525:          * It is a dirty hack before a cleaner solution is found.
                   1526:          * Documentation should mention that the second argument must
                   1527:          * be at least 500 chars long, and could be stripped if too long.
                   1528:          */
                   1529:         if (strlen(buffer) + strlen(buf) > 499)
                   1530:            break;
1.12      daniel   1531:        strcpy(buffer, buf);
                   1532:         cur = next;
                   1533:     } while (cur != NULL);
                   1534:     return(0);
                   1535: }
                   1536: 
                   1537: /**
                   1538:  * xmlShell
                   1539:  * @doc:  the initial document
                   1540:  * @filename:  the output buffer
                   1541:  * @input:  the line reading function
                   1542:  * @output:  the output FILE*
                   1543:  *
                   1544:  * Implements the XML shell 
                   1545:  * This allow to load, validate, view, modify and save a document
                   1546:  * using a environment similar to a UNIX commandline.
                   1547:  */
                   1548: void
                   1549: xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
                   1550:          FILE *output) {
                   1551:     char prompt[500] = "/ > ";
1.39      veillard 1552:     char *cmdline = NULL, *cur;
1.12      daniel   1553:     int nbargs;
                   1554:     char command[100];
                   1555:     char arg[400];
1.39      veillard 1556:     int i;
1.12      daniel   1557:     xmlShellCtxtPtr ctxt;
                   1558:     xmlXPathObjectPtr list;
                   1559: 
                   1560:     if (doc == NULL)
                   1561:         return;
                   1562:     if (filename == NULL)
                   1563:         return;
                   1564:     if (input == NULL)
                   1565:         return;
                   1566:     if (output == NULL)
                   1567:         return;
                   1568:     ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
                   1569:     if (ctxt == NULL) 
                   1570:         return;
                   1571:     ctxt->loaded = 0;
                   1572:     ctxt->doc = doc;
                   1573:     ctxt->input = input;
                   1574:     ctxt->output = output;
                   1575:     ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
                   1576:     ctxt->node = (xmlNodePtr) ctxt->doc;        
                   1577: 
1.23      daniel   1578: #ifdef LIBXML_XPATH_ENABLED
1.12      daniel   1579:     ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
                   1580:     if (ctxt->pctxt == NULL) {
                   1581:        xmlFree(ctxt);
                   1582:        return;
                   1583:     }
1.23      daniel   1584: #endif /* LIBXML_XPATH_ENABLED */
1.12      daniel   1585:     while (1) {
                   1586:         if (ctxt->node == (xmlNodePtr) ctxt->doc)
                   1587:            sprintf(prompt, "%s > ", "/");
                   1588:        else if (ctxt->node->name)
1.31      veillard 1589: #ifdef HAVE_SNPRINTF
                   1590:            snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
                   1591: #else
1.34      veillard 1592:            sprintf(prompt, "%s > ", ctxt->node->name);
1.31      veillard 1593: #endif
                   1594:         else
1.12      daniel   1595:            sprintf(prompt, "? > ");
1.31      veillard 1596:         prompt[sizeof(prompt) - 1] = 0;
1.12      daniel   1597: 
1.39      veillard 1598:        /*
                   1599:         * Get a new command line
                   1600:         */
1.12      daniel   1601:         cmdline = ctxt->input(prompt);
                   1602:         if (cmdline == NULL) break;
                   1603: 
1.39      veillard 1604:        /*
                   1605:         * Parse the command itself
                   1606:         */
                   1607:        cur = cmdline;
                   1608:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                   1609:        i = 0;
                   1610:        while ((*cur != ' ') && (*cur != '\t') &&
                   1611:               (*cur != '\n') && (*cur != '\r')) {
                   1612:            if (*cur == 0)
                   1613:                break;
                   1614:            command[i++] = *cur++;
                   1615:        }
                   1616:        command[i] = 0;
                   1617:        if (i == 0) continue;
                   1618:        nbargs++;
1.12      daniel   1619: 
1.39      veillard 1620:        /*
                   1621:         * Parse the argument
                   1622:         */
                   1623:        while ((*cur == ' ') || (*cur == '\t')) cur++;
                   1624:        i = 0;
                   1625:        while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
                   1626:            if (*cur == 0)
                   1627:                break;
                   1628:            arg[i++] = *cur++;
                   1629:        }
                   1630:        arg[i] = 0;
                   1631:        if (i != 0) 
                   1632:            nbargs++;
                   1633: 
                   1634:        /*
                   1635:         * start interpreting the command
                   1636:         */
1.12      daniel   1637:         if (!strcmp(command, "exit"))
                   1638:            break;
                   1639:         if (!strcmp(command, "quit"))
                   1640:            break;
                   1641:         if (!strcmp(command, "bye"))
                   1642:            break;
                   1643:        if (!strcmp(command, "validate")) {
                   1644:            xmlShellValidate(ctxt, arg, NULL, NULL);
                   1645:        } else if (!strcmp(command, "load")) {
                   1646:            xmlShellLoad(ctxt, arg, NULL, NULL);
                   1647:        } else if (!strcmp(command, "save")) {
                   1648:            xmlShellSave(ctxt, arg, NULL, NULL);
                   1649:        } else if (!strcmp(command, "write")) {
                   1650:            xmlShellWrite(ctxt, arg, NULL, NULL);
                   1651:        } else if (!strcmp(command, "free")) {
                   1652:            if (arg[0] == 0) {
                   1653:                xmlMemShow(stdout, 0);
                   1654:            } else {
                   1655:                int len = 0;
                   1656:                sscanf(arg, "%d", &len);
                   1657:                xmlMemShow(stdout, len);
                   1658:            }
                   1659:        } else if (!strcmp(command, "pwd")) {
                   1660:            char dir[500];
                   1661:            if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
                   1662:                printf("%s\n", dir);
                   1663:        } else  if (!strcmp(command, "du")) {
                   1664:            xmlShellDu(ctxt, NULL, ctxt->node, NULL);
                   1665:        } else  if ((!strcmp(command, "ls")) ||
                   1666:              (!strcmp(command, "dir"))) {
                   1667:            int dir = (!strcmp(command, "dir"));
                   1668:            if (arg[0] == 0) {
                   1669:                if (dir)
                   1670:                    xmlShellDir(ctxt, NULL, ctxt->node, NULL);
                   1671:                else
                   1672:                    xmlShellList(ctxt, NULL, ctxt->node, NULL);
                   1673:            } else {
                   1674:                ctxt->pctxt->node = ctxt->node;
1.23      daniel   1675: #ifdef LIBXML_XPATH_ENABLED
1.36      veillard 1676:                ctxt->pctxt->node = ctxt->node;
1.12      daniel   1677:                list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23      daniel   1678: #else
                   1679:                list = NULL;
                   1680: #endif /* LIBXML_XPATH_ENABLED */
1.12      daniel   1681:                if (list != NULL) {
                   1682:                    switch (list->type) {
                   1683:                        case XPATH_UNDEFINED:
1.44      veillard 1684:                            xmlGenericError(xmlGenericErrorContext,
                   1685:                                    "%s: no such node\n", arg);
1.12      daniel   1686:                            break;
                   1687:                        case XPATH_NODESET: {
                   1688:                            int i;
                   1689: 
                   1690:                            for (i = 0;i < list->nodesetval->nodeNr;i++) {
                   1691:                                if (dir)
                   1692:                                    xmlShellDir(ctxt, NULL,
                   1693:                                       list->nodesetval->nodeTab[i], NULL);
                   1694:                                else
                   1695:                                    xmlShellList(ctxt, NULL,
                   1696:                                       list->nodesetval->nodeTab[i], NULL);
                   1697:                            }
                   1698:                            break;
                   1699:                        }
                   1700:                        case XPATH_BOOLEAN:
1.44      veillard 1701:                            xmlGenericError(xmlGenericErrorContext,
                   1702:                                    "%s is a Boolean\n", arg);
1.12      daniel   1703:                            break;
                   1704:                        case XPATH_NUMBER:
1.44      veillard 1705:                            xmlGenericError(xmlGenericErrorContext,
                   1706:                                    "%s is a number\n", arg);
1.12      daniel   1707:                            break;
                   1708:                        case XPATH_STRING:
1.44      veillard 1709:                            xmlGenericError(xmlGenericErrorContext,
                   1710:                                    "%s is a string\n", arg);
1.12      daniel   1711:                            break;
1.37      veillard 1712:                        case XPATH_POINT:
1.44      veillard 1713:                            xmlGenericError(xmlGenericErrorContext,
                   1714:                                    "%s is a point\n", arg);
1.37      veillard 1715:                            break;
                   1716:                        case XPATH_RANGE:
1.44      veillard 1717:                            xmlGenericError(xmlGenericErrorContext,
                   1718:                                    "%s is a range\n", arg);
1.37      veillard 1719:                            break;
1.38      veillard 1720:                        case XPATH_LOCATIONSET:
1.44      veillard 1721:                            xmlGenericError(xmlGenericErrorContext,
                   1722:                                    "%s is a range\n", arg);
1.37      veillard 1723:                            break;
                   1724:                        case XPATH_USERS:
1.44      veillard 1725:                            xmlGenericError(xmlGenericErrorContext,
                   1726:                                    "%s is user-defined\n", arg);
1.37      veillard 1727:                            break;
1.12      daniel   1728:                    }
                   1729:                    xmlXPathFreeNodeSetList(list);
                   1730:                } else {
1.44      veillard 1731:                    xmlGenericError(xmlGenericErrorContext,
                   1732:                            "%s: no such node\n", arg);
1.12      daniel   1733:                }
1.36      veillard 1734:                ctxt->pctxt->node = NULL;
1.12      daniel   1735:            }
                   1736:        } else if (!strcmp(command, "cd")) {
                   1737:            if (arg[0] == 0) {
                   1738:                ctxt->node = (xmlNodePtr) ctxt->doc;
                   1739:            } else {
1.36      veillard 1740: #ifdef LIBXML_XPATH_ENABLED
1.12      daniel   1741:                ctxt->pctxt->node = ctxt->node;
                   1742:                list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23      daniel   1743: #else
                   1744:                list = NULL;
                   1745: #endif /* LIBXML_XPATH_ENABLED */
1.12      daniel   1746:                if (list != NULL) {
                   1747:                    switch (list->type) {
                   1748:                        case XPATH_UNDEFINED:
1.44      veillard 1749:                            xmlGenericError(xmlGenericErrorContext,
                   1750:                                    "%s: no such node\n", arg);
1.12      daniel   1751:                            break;
                   1752:                        case XPATH_NODESET:
                   1753:                            if (list->nodesetval->nodeNr == 1) {
                   1754:                                ctxt->node = list->nodesetval->nodeTab[0];
                   1755:                            } else 
1.44      veillard 1756:                                xmlGenericError(xmlGenericErrorContext,
                   1757:                                        "%s is a %d Node Set\n",
1.12      daniel   1758:                                        arg, list->nodesetval->nodeNr);
                   1759:                            break;
                   1760:                        case XPATH_BOOLEAN:
1.44      veillard 1761:                            xmlGenericError(xmlGenericErrorContext,
                   1762:                                    "%s is a Boolean\n", arg);
1.12      daniel   1763:                            break;
                   1764:                        case XPATH_NUMBER:
1.44      veillard 1765:                            xmlGenericError(xmlGenericErrorContext,
                   1766:                                    "%s is a number\n", arg);
1.12      daniel   1767:                            break;
                   1768:                        case XPATH_STRING:
1.44      veillard 1769:                            xmlGenericError(xmlGenericErrorContext,
                   1770:                                    "%s is a string\n", arg);
1.12      daniel   1771:                            break;
1.37      veillard 1772:                        case XPATH_POINT:
1.44      veillard 1773:                            xmlGenericError(xmlGenericErrorContext,
                   1774:                                    "%s is a point\n", arg);
1.37      veillard 1775:                            break;
                   1776:                        case XPATH_RANGE:
1.44      veillard 1777:                            xmlGenericError(xmlGenericErrorContext,
                   1778:                                    "%s is a range\n", arg);
1.37      veillard 1779:                            break;
1.38      veillard 1780:                        case XPATH_LOCATIONSET:
1.44      veillard 1781:                            xmlGenericError(xmlGenericErrorContext,
                   1782:                                    "%s is a range\n", arg);
1.37      veillard 1783:                            break;
                   1784:                        case XPATH_USERS:
1.44      veillard 1785:                            xmlGenericError(xmlGenericErrorContext,
                   1786:                                    "%s is user-defined\n", arg);
1.37      veillard 1787:                            break;
1.12      daniel   1788:                    }
                   1789:                    xmlXPathFreeNodeSetList(list);
                   1790:                } else {
1.44      veillard 1791:                    xmlGenericError(xmlGenericErrorContext,
                   1792:                            "%s: no such node\n", arg);
1.12      daniel   1793:                }
1.36      veillard 1794:                ctxt->pctxt->node = NULL;
1.12      daniel   1795:            }
                   1796:        } else if (!strcmp(command, "cat")) {
                   1797:            if (arg[0] == 0) {
                   1798:                xmlShellCat(ctxt, NULL, ctxt->node, NULL);
                   1799:            } else {
                   1800:                ctxt->pctxt->node = ctxt->node;
1.23      daniel   1801: #ifdef LIBXML_XPATH_ENABLED
1.36      veillard 1802:                ctxt->pctxt->node = ctxt->node;
1.12      daniel   1803:                list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23      daniel   1804: #else
                   1805:                list = NULL;
                   1806: #endif /* LIBXML_XPATH_ENABLED */
1.12      daniel   1807:                if (list != NULL) {
                   1808:                    switch (list->type) {
                   1809:                        case XPATH_UNDEFINED:
1.44      veillard 1810:                            xmlGenericError(xmlGenericErrorContext,
                   1811:                                    "%s: no such node\n", arg);
1.12      daniel   1812:                            break;
                   1813:                        case XPATH_NODESET: {
                   1814:                            int i;
                   1815: 
                   1816:                            for (i = 0;i < list->nodesetval->nodeNr;i++) {
                   1817:                                if (i > 0) printf(" -------\n");
                   1818:                                xmlShellCat(ctxt, NULL,
                   1819:                                    list->nodesetval->nodeTab[i], NULL);
                   1820:                            }
                   1821:                            break;
                   1822:                        }
                   1823:                        case XPATH_BOOLEAN:
1.44      veillard 1824:                            xmlGenericError(xmlGenericErrorContext,
                   1825:                                    "%s is a Boolean\n", arg);
1.12      daniel   1826:                            break;
                   1827:                        case XPATH_NUMBER:
1.44      veillard 1828:                            xmlGenericError(xmlGenericErrorContext,
                   1829:                                    "%s is a number\n", arg);
1.12      daniel   1830:                            break;
                   1831:                        case XPATH_STRING:
1.44      veillard 1832:                            xmlGenericError(xmlGenericErrorContext,
                   1833:                                    "%s is a string\n", arg);
1.37      veillard 1834:                            break;
                   1835:                        case XPATH_POINT:
1.44      veillard 1836:                            xmlGenericError(xmlGenericErrorContext,
                   1837:                                    "%s is a point\n", arg);
1.37      veillard 1838:                            break;
                   1839:                        case XPATH_RANGE:
1.44      veillard 1840:                            xmlGenericError(xmlGenericErrorContext,
                   1841:                                    "%s is a range\n", arg);
1.37      veillard 1842:                            break;
1.38      veillard 1843:                        case XPATH_LOCATIONSET:
1.44      veillard 1844:                            xmlGenericError(xmlGenericErrorContext,
                   1845:                                    "%s is a range\n", arg);
1.37      veillard 1846:                            break;
                   1847:                        case XPATH_USERS:
1.44      veillard 1848:                            xmlGenericError(xmlGenericErrorContext,
                   1849:                                    "%s is user-defined\n", arg);
1.12      daniel   1850:                            break;
                   1851:                    }
                   1852:                    xmlXPathFreeNodeSetList(list);
                   1853:                } else {
1.44      veillard 1854:                    xmlGenericError(xmlGenericErrorContext,
                   1855:                            "%s: no such node\n", arg);
1.12      daniel   1856:                }
1.36      veillard 1857:                ctxt->pctxt->node = NULL;
1.12      daniel   1858:            }
                   1859:        } else {
1.44      veillard 1860:            xmlGenericError(xmlGenericErrorContext,
                   1861:                    "Unknown command %s\n", command);
1.12      daniel   1862:        }
                   1863:        free(cmdline); /* not xmlFree here ! */
                   1864:     }
1.23      daniel   1865: #ifdef LIBXML_XPATH_ENABLED
1.12      daniel   1866:     xmlXPathFreeContext(ctxt->pctxt);
1.23      daniel   1867: #endif /* LIBXML_XPATH_ENABLED */
1.12      daniel   1868:     if (ctxt->loaded) {
                   1869:         xmlFreeDoc(ctxt->doc);
                   1870:     }
                   1871:     xmlFree(ctxt);
                   1872:     if (cmdline != NULL)
                   1873:         free(cmdline); /* not xmlFree here ! */
                   1874: }
                   1875: 
1.23      daniel   1876: #endif /* LIBXML_DEBUG_ENABLED */

Webmaster