/* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "my_global.h" #include "m_string.h" #include "my_xml.h" #define MY_XML_EOF 'E' #define MY_XML_STRING 'S' #define MY_XML_IDENT 'I' #define MY_XML_EQ '=' #define MY_XML_LT '<' #define MY_XML_GT '>' #define MY_XML_SLASH '/' #define MY_XML_COMMENT 'C' #define MY_XML_TEXT 'T' #define MY_XML_QUESTION '?' #define MY_XML_EXCLAM '!' typedef struct xml_attr_st { const char *beg; const char *end; } MY_XML_ATTR; static const char *lex2str(int lex) { switch(lex) { case MY_XML_EOF: return "EOF"; case MY_XML_STRING: return "STRING"; case MY_XML_IDENT: return "IDENT"; case MY_XML_EQ: return "'='"; case MY_XML_LT: return "'<'"; case MY_XML_GT: return "'>'"; case MY_XML_SLASH: return "'/'"; case MY_XML_COMMENT: return "COMMENT"; case MY_XML_TEXT: return "TEXT"; case MY_XML_QUESTION: return "'?'"; case MY_XML_EXCLAM: return "'!'"; } return "UNKNOWN"; } static void my_xml_norm_text(MY_XML_ATTR *a) { for ( ; (a->beg < a->end) && strchr(" \t\r\n",a->beg[0]) ; a->beg++ ); for ( ; (a->beg < a->end) && strchr(" \t\r\n",a->end[-1]) ; a->end-- ); } static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a) { int lex; for( ; ( p->cur < p->end) && strchr(" \t\r\n",p->cur[0]) ; p->cur++); if (p->cur >= p->end) { a->beg=p->end; a->end=p->end; lex=MY_XML_EOF; goto ret; } a->beg=p->cur; a->end=p->cur; if ((p->end - p->cur > 3) && !bcmp(p->cur,"", 3); p->cur++) {} if (!bcmp(p->cur, "-->", 3)) p->cur+=3; a->end=p->cur; lex=MY_XML_COMMENT; } else if (strchr("?=/<>!",p->cur[0])) { p->cur++; a->end=p->cur; lex=a->beg[0]; } else if ( (p->cur[0]=='"') || (p->cur[0]=='\'') ) { p->cur++; for( ; ( p->cur < p->end ) && (p->cur[0] != a->beg[0]); p->cur++) {} a->end=p->cur; if (a->beg[0]==p->cur[0])p->cur++; a->beg++; my_xml_norm_text(a); lex=MY_XML_STRING; } else { for(; (p->cur < p->end) && !strchr("?'\"=/<> \t\r\n", p->cur[0]); p->cur++) {} a->end=p->cur; my_xml_norm_text(a); lex=MY_XML_IDENT; } #if 0 printf("LEX=%s[%d]\n",lex2str(lex),a->end-a->beg); #endif ret: return lex; } static int my_xml_value(MY_XML_PARSER *st, const char *str, uint len) { return (st->value) ? (st->value)(st,str,len) : MY_XML_OK; } static int my_xml_enter(MY_XML_PARSER *st, const char *str, uint len) { if ( (st->attrend-st->attr+len+1)>sizeof(st->attr)) { sprintf(st->errstr,"To deep XML"); return MY_XML_ERROR; } if (st->attrend > st->attr) { st->attrend[0]='.'; st->attrend++; } memcpy(st->attrend,str,len); st->attrend+=len; st->attrend[0]='\0'; return st->enter ? st->enter(st,st->attr,st->attrend-st->attr) : MY_XML_OK; } static void mstr(char *s,const char *src,uint l1, uint l2) { l1 = l1attrend; (e>p->attr) && (e[0]!='.') ; e--); glen = (e[0]=='.') ? (p->attrend-e-1) : p->attrend-e; if (str && (slen != glen)) { mstr(s,str,sizeof(s)-1,slen); mstr(g,e+1,sizeof(g)-1,glen), sprintf(p->errstr,"'' unexpected ('' wanted)",s,g); return MY_XML_ERROR; } rc = p->leave_xml ? p->leave_xml(p,p->attr,p->attrend-p->attr) : MY_XML_OK; *e='\0'; p->attrend=e; return rc; } int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) { p->attrend=p->attr; p->beg=str; p->cur=str; p->end=str+len; while ( p->cur < p->end ) { MY_XML_ATTR a; if(p->cur[0]=='<') { int lex; int question=0; int exclam=0; lex=my_xml_scan(p,&a); if (MY_XML_COMMENT==lex) { continue; } lex=my_xml_scan(p,&a); if (MY_XML_SLASH==lex) { if(MY_XML_IDENT!=(lex=my_xml_scan(p,&a))) { sprintf(p->errstr,"1: %s unexpected (ident wanted)",lex2str(lex)); return MY_XML_ERROR; } if(MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg)) return MY_XML_ERROR; lex=my_xml_scan(p,&a); goto gt; } if (MY_XML_EXCLAM==lex) { lex=my_xml_scan(p,&a); exclam=1; } else if (MY_XML_QUESTION==lex) { lex=my_xml_scan(p,&a); question=1; } if (MY_XML_IDENT==lex) { if(MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) return MY_XML_ERROR; } else { sprintf(p->errstr,"3: %s unexpected (ident or '/' wanted)", lex2str(lex)); return MY_XML_ERROR; } while ((MY_XML_IDENT==(lex=my_xml_scan(p,&a))) || (MY_XML_STRING==lex)) { MY_XML_ATTR b; if(MY_XML_EQ==(lex=my_xml_scan(p,&b))) { lex=my_xml_scan(p,&b); if ( (lex==MY_XML_IDENT) || (lex==MY_XML_STRING) ) { if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) || (MY_XML_OK!=my_xml_value(p,b.beg,b.end-b.beg)) || (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg))) return MY_XML_ERROR; } else { sprintf(p->errstr,"4: %s unexpected (ident or string wanted)", lex2str(lex)); return MY_XML_ERROR; } } else if ( (MY_XML_STRING==lex) || (MY_XML_IDENT==lex) ) { if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) || (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg))) return MY_XML_ERROR; } else break; } if (lex==MY_XML_SLASH) { if(MY_XML_OK!=my_xml_leave(p,NULL,0)) return MY_XML_ERROR; lex=my_xml_scan(p,&a); } gt: if (question) { if (lex!=MY_XML_QUESTION) { sprintf(p->errstr,"6: %s unexpected ('?' wanted)",lex2str(lex)); return MY_XML_ERROR; } if(MY_XML_OK!=my_xml_leave(p,NULL,0)) return MY_XML_ERROR; lex=my_xml_scan(p,&a); } if (exclam) { if(MY_XML_OK!=my_xml_leave(p,NULL,0)) return MY_XML_ERROR; } if (lex!=MY_XML_GT) { sprintf(p->errstr,"5: %s unexpected ('>' wanted)",lex2str(lex)); return MY_XML_ERROR; } } else { a.beg=p->cur; for ( ; (p->cur < p->end) && (p->cur[0]!='<') ; p->cur++); a.end=p->cur; my_xml_norm_text(&a); if (a.beg!=a.end) { my_xml_value(p,a.beg,a.end-a.beg); } } } return MY_XML_OK; } void my_xml_parser_create(MY_XML_PARSER *p) { bzero((void*)p,sizeof(p[0])); } void my_xml_parser_free(MY_XML_PARSER *p __attribute__((unused))) { } void my_xml_set_value_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) { p->value=action; } void my_xml_set_enter_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) { p->enter=action; } void my_xml_set_leave_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) { p->leave_xml=action; } void my_xml_set_user_data(MY_XML_PARSER *p, void *user_data) { p->user_data=user_data; } const char *my_xml_error_string(MY_XML_PARSER *p) { return p->errstr; } uint my_xml_error_pos(MY_XML_PARSER *p) { const char *beg=p->beg; const char *s; for ( s=p->beg ; scur; s++) { if (s[0]=='\n') beg=s; } return p->cur-beg; } uint my_xml_error_lineno(MY_XML_PARSER *p) { uint res=0; const char *s; for ( s=p->beg ; scur; s++) { if (s[0]=='\n') res++; } return res; }