/* [ 10 Feb 1999 ] */ /* rdxml.c,v 1.6 1999/07/31 01:47:03 joe Exp */ /* * KNOWN PROBLEMS: * Doesn't interpret system IDs. * When it does, they will be file names, not URIs. * Check NAMECASE problems. * Add PI, NDATA, etc. handlers. * Add PELs (maybe), REs (maybe). * * ALSO NEED: * ParseXMLProc(), parse XML as a string. */ #include #include #include #include "tcl.h" #include "project.h" #include "esis.h" #include "pile.h" #include "strmap.h" #include "strmgt.h" #include "esisp.h" #include "tclcost.h" #include "expat/xmlparse.h" #define BUFFER_SIZE 4096 /* %%% TODO: insert PELs as needed */ static void StartElementHandler( void *userData, const XML_Char *name, const XML_Char **atts ) { ESISBuilder ep = (ESISBuilder)userData; ESISNode el = esis_open_node(ep,EN_EL); el->name = intern(name); while (atts && *atts) { ESISToken attname = intern(atts[0]); char *attval = pstrdup(ep->datapile, atts[1]); esis_create_attribute(el,attname,attval); atts += 2; } } static void EndElementHandler(void *userData, const XML_Char *name) { ESISBuilder ep = (ESISBuilder)userData; /* ensure not PEL */ esis_close_node(ep); } /* * EXPAT 1.3 passes record-ends as separate CharacterData events. * This is not documented, but we rely on it anyway %%% */ static void CharacterDataHandler( void *userData, const XML_Char *s, int len) { ESISBuilder ep = (ESISBuilder)userData; char *data = palloc(ep->datapile, len + 1); strncpy(data, s, len); data[len] = '\0'; esis_create_datanode(ep, strcmp(data, "\n") ? EN_CDATA : EN_RE, data); } static void ProcessingInstructionHandler( void *userData, const XML_Char *pitarget, const XML_Char *pivalue) { ESISBuilder ep = (ESISBuilder)userData; int len = (pitarget ? strlen(pitarget) : 0) + (pivalue && *pivalue ? 1+strlen(pivalue) : 0); char *content = palloc(ep->datapile, len + 1); if (pitarget) strcpy(content, pitarget); if (pivalue && *pivalue) { strcat(content, " "); strcat(content, pivalue); } esis_create_datanode(ep, EN_PI, content); } /* %%% TO DO: Implement this. */ int ExternalEntityRefHandler( XML_Parser parser, const XML_Char *openEntityNames, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { /* %%% Report error back to caller : incl. sysid, pubid. */ return 0; } /* * Top-level command procedure: * %%% Need: -baseURI argument. * %%% Need: -resolverProc argument (for processing external entity refs.) */ CMDPROC(CostLoadXMLProc) { CostData *cd = (CostData *)clientData; char *handleName; XML_Parser parser; int mode; Tcl_Channel channel; ESISBuilder ep; int done; CHECKNARGS(1, "handle") handleName = argv[1]; /* * Get the input channel: */ channel = Tcl_GetChannel(interp, handleName, &mode); if (!channel) { Tcl_AppendResult(interp,"Invalid channel name ",handleName,NULL); return TCL_ERROR; } if ((mode & TCL_WRITABLE) || !(mode & TCL_READABLE)) { Tcl_AppendResult(interp, handleName, " wrong mode", NULL); return TCL_ERROR; } /* * Create XML parser: */ ep = esis_builder_start(); parser = XML_ParserCreate(NULL); XML_SetUserData(parser, ep); XML_SetElementHandler(parser, StartElementHandler, EndElementHandler); XML_SetCharacterDataHandler(parser, CharacterDataHandler); XML_SetExternalEntityRefHandler(parser,ExternalEntityRefHandler); XML_SetProcessingInstructionHandler(parser, ProcessingInstructionHandler); /* * Parse away. */ do { static char buf[BUFFER_SIZE]; int len = Tcl_Read(channel, buf, BUFFER_SIZE); done = len < BUFFER_SIZE; if (!XML_Parse(parser, buf, len, done)) { const char *errmsg = XML_ErrorString(XML_GetErrorCode(parser)); int lineno = XML_GetCurrentLineNumber(parser); sprintf(buf, " %s line %d", handleName, lineno); Tcl_AppendResult(interp, argv[0], ": ", errmsg, ", ", buf, NULL); XML_ParserFree(parser); esis_free_document(esis_builder_finish(ep)); return TCL_ERROR; } } while (!done); XML_ParserFree(parser); cd->current_document = esis_builder_finish(ep); cd->current_node = esis_rootnode(cd->current_document); CostRegisterDocument(interp, cd, cd->current_document); return TCL_OK; } /*EOF*/