#include #include #include #include #include "../http/buffer.h" struct parser_data { object root; object *stack; int stack_top; int stack_size; struct buffer b; }; void collect (struct parser_data *pdata, object x) { object tail = make_cons (x, Cnil); pdata->stack[pdata->stack_top]->c.c_cdr = tail; pdata->stack[pdata->stack_top] = tail; } void end_text (struct parser_data *pdata) { if (pdata->b.index > 0) { collect (pdata, make_simple_string (pdata->b.data)); buffer_reset (&pdata->b); } } void start_element (void *user_data, const char *name, const char **attributes) { object tag = make_keyword (name); object element; const char **att; struct parser_data *pdata = user_data; if (pdata->stack_top >= (pdata->stack_size - 1)) { pdata->stack_size <<= 1; pdata->stack = realloc (pdata->stack, pdata->stack_size * sizeof (object)); } if (*attributes) { tag = make_cons (tag, Cnil); pdata->stack[++pdata->stack_top] = tag; for (att = attributes; *att; att += 2) { collect (pdata, make_keyword (att[0])); collect (pdata, make_simple_string (att[1])); } --pdata->stack_top; } element = make_cons (tag, Cnil); if (pdata->root != Cnil) { end_text (pdata); collect (pdata, element); } else pdata->root = element; pdata->stack[++pdata->stack_top] = element; } void end_element (void *user_data, const char *name) { struct parser_data *pdata = user_data; end_text ((struct parser_data *) user_data); --pdata->stack_top; } void char_data (void *user_data, const XML_Char *s, int len) { struct parser_data *pdata = user_data; buffer_add (&pdata->b, s, len); } object parse_xml_to_sexp (object source, object file_p) { XML_Parser parser; struct parser_data pdata; #ifndef CL_NS_SEP parser = XML_ParserCreate (NULL); #else parser = XML_ParserCreateNS (NULL, CL_NS_SEP); #endif pdata.stack_size = 16; pdata.stack = malloc (pdata.stack_size * sizeof (object)); pdata.stack_top = -1; pdata.root = Cnil; buffer_init (&pdata.b, 1024); XML_SetUserData (parser, &pdata); XML_SetElementHandler (parser, start_element, end_element); XML_SetCharacterDataHandler (parser, char_data); if (file_p == Cnil) { if (!XML_Parse (parser, source->st.st_self, source->st.st_fillp, 1)) { fprintf (stderr, "%s at line %d\n", XML_ErrorString (XML_GetErrorCode (parser)), XML_GetCurrentLineNumber (parser)); return Cnil; } } else { FILE *fp; char buf[BUFSIZ]; int final_p; buffer_add (&pdata.b, source->st.st_self, source->st.st_fillp); fp = fopen (pdata.b.data, "r"); buffer_reset (&pdata.b); if (fp == NULL) return Cnil; do { size_t len = fread (buf, 1, sizeof (buf), fp); final_p = len < sizeof (buf); if (!XML_Parse (parser, buf, len, final_p)) { fprintf (stderr, "%s at line %d\n", XML_ErrorString (XML_GetErrorCode (parser)), XML_GetCurrentLineNumber (parser)); return Cnil; } } while (!final_p); } XML_ParserFree (parser); free (pdata.b.data); return pdata.root; }