diff options
-rw-r--r-- | include/Makefile.am | 2 | ||||
-rw-r--r-- | include/my_xml.h | 59 | ||||
-rw-r--r-- | mysys/Makefile.am | 5 | ||||
-rwxr-xr-x | mysys/test_xml | bin | 0 -> 35493 bytes | |||
-rw-r--r-- | mysys/test_xml.c | 89 | ||||
-rw-r--r-- | mysys/xml.c | 369 |
6 files changed, 522 insertions, 2 deletions
diff --git a/include/Makefile.am b/include/Makefile.am index c88e1ee1e40..652278e8a80 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -16,7 +16,7 @@ # MA 02111-1307, USA BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h -pkginclude_HEADERS = dbug.h m_string.h my_sys.h my_list.h \ +pkginclude_HEADERS = dbug.h m_string.h my_sys.h my_list.h my_xml.h \ mysql.h mysql_com.h mysqld_error.h mysql_embed.h \ my_semaphore.h my_pthread.h my_no_pthread.h raid.h \ errmsg.h my_global.h my_net.h my_alloc.h \ diff --git a/include/my_xml.h b/include/my_xml.h new file mode 100644 index 00000000000..25db161715a --- /dev/null +++ b/include/my_xml.h @@ -0,0 +1,59 @@ +/* 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 */ + + +#ifndef _my_xml_h +#define _my_xml_h + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MY_XML_OK 0 +#define MY_XML_ERROR 1 + +typedef struct xml_stack_st +{ + char errstr[128]; + char attr[128]; + char *attrend; + const char *beg; + const char *cur; + const char *end; + int (*enter)(struct xml_stack_st *st,const char *val, uint len); + int (*value)(struct xml_stack_st *st,const char *val, uint len); + int (*leave)(struct xml_stack_st *st,const char *val, uint len); +} MY_XML_PARSER; + +void my_xml_parser_create(MY_XML_PARSER *st); +void my_xml_parser_free(MY_XML_PARSER *st); +int my_xml_parse(MY_XML_PARSER *st,const char *str, uint len); + +void my_xml_set_value_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, uint len)); +void my_xml_set_enter_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, uint len)); +void my_xml_set_leave_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, uint len)); + +uint my_xml_error_pos(MY_XML_PARSER *st); +uint my_xml_error_lineno(MY_XML_PARSER *st); + +const char *my_xml_error_string(MY_XML_PARSER *st); + +#ifdef __cplusplus +} +#endif + +#endif /* _my_xml_h */ diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 330e1d6e59d..cc72bfae7cf 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -50,7 +50,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ my_getopt.c my_mkdir.c \ default.c my_compress.c checksum.c raid.cc \ my_net.c my_semaphore.c my_port.c \ - my_vsnprintf.c charset.c my_bitmap.c my_bit.c md5.c \ + my_vsnprintf.c charset.c xml.c my_bitmap.c my_bit.c md5.c \ my_gethostbyname.c rijndael.c my_aes.c sha1.c \ my_handler.c EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ @@ -104,6 +104,9 @@ test_dir: test_dir.c $(LIBRARIES) test_charset$(EXEEXT): test_charset.c $(LIBRARIES) $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_charset.c $(LDADD) $(LIBS) +test_xml$(EXEEXT): test_xml.c $(LIBRARIES) + $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_xml.c $(LDADD) $(LIBS) + charset2html$(EXEEXT): charset2html.c $(LIBRARIES) $(LINK) $(FLAGS) -DMAIN $(srcdir)/charset2html.c $(LDADD) $(LIBS) diff --git a/mysys/test_xml b/mysys/test_xml Binary files differnew file mode 100755 index 00000000000..6b8b0b3b83c --- /dev/null +++ b/mysys/test_xml diff --git a/mysys/test_xml.c b/mysys/test_xml.c new file mode 100644 index 00000000000..d97d6561681 --- /dev/null +++ b/mysys/test_xml.c @@ -0,0 +1,89 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include "my_xml.h" + +static void mstr(char *str,const char *src,uint l1,uint l2) +{ + l1 = l1<l2 ? l1 : l2; + memcpy(str,src,l1); + str[l1]='\0'; +} + +static int dstr(MY_XML_PARSER *st,const char *attr, uint len) +{ + char str[1024]; + + mstr(str,attr,len,sizeof(str)-1); + printf("VALUE '%s'\n",str); + return MY_XML_OK; +} + +static int bstr(MY_XML_PARSER *st,const char *attr, uint len) +{ + char str[1024]; + + mstr(str,attr,len,sizeof(str)-1); + printf("ENTER %s\n",str); + return MY_XML_OK; +} + + +static int estr(MY_XML_PARSER *st,const char *attr, uint len) +{ + char str[1024]; + + mstr(str,attr,len,sizeof(str)-1); + printf("LEAVE %s\n",str); + return MY_XML_OK; +} + +static void usage(const char *prog) +{ + printf("Usage:\n"); + printf("%s xmlfile\n",prog); +} + +int main(int ac, char **av) +{ + char str[1024*64]=""; + const char *fn; + int f; + uint len; + MY_XML_PARSER p; + + if (ac<2) + { + usage(av[0]); + return 0; + } + + fn=av[1]?av[1]:"test.xml"; + if ((f=open(fn,O_RDONLY))<0) + { + fprintf(stderr,"Err '%s'\n",fn); + return 1; + } + + len=read(f,str,sizeof(str)-1); + str[len]='\0'; + + my_xml_parser_create(&p); + + my_xml_set_enter_handler(&p,bstr); + my_xml_set_value_handler(&p,dstr); + my_xml_set_leave_handler(&p,estr); + + if (MY_XML_OK!=(f=my_xml_parse(&p,str,len))) + { + printf("ERROR at line %d pos %d '%s'\n", + my_xml_error_lineno(&p)+1, + my_xml_error_pos(&p), + my_xml_error_string(&p)); + } + + my_xml_parser_free(&p); + + return 0; +} diff --git a/mysys/xml.c b/mysys/xml.c new file mode 100644 index 00000000000..049eb05b19c --- /dev/null +++ b/mysys/xml.c @@ -0,0 +1,369 @@ +/* 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 (!memcmp(p->cur,"<!--",4)) + { + for( ; (p->cur < p->end) && memcmp(p->cur, "-->", 3); p->cur++); + if(!memcmp(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 = l1<l2 ? l1 : l2; + memcpy(s,src,l1); + s[l1]='\0'; +} + +static int my_xml_leave(MY_XML_PARSER *p, const char *str, uint slen) +{ + char *e; + uint glen; + char s[32]; + char g[32]; + int rc; + + /* Find previous '.' or beginning */ + for( e=p->attrend; (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,"'</%s>' unexpected ('</%s>' wanted)",s,g); + return MY_XML_ERROR; + } + + rc = p->leave ? p->leave(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=action; +} + +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 ; s<p->cur; 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 ; s<p->cur; s++) + if (s[0]=='\n') + res++; + return res; +} |