mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 10:14:19 +01:00
XML parser
This commit is contained in:
parent
c7ba7c9a4c
commit
eb87b8a1bd
6 changed files with 522 additions and 2 deletions
|
@ -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 \
|
||||
|
|
59
include/my_xml.h
Normal file
59
include/my_xml.h
Normal file
|
@ -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 */
|
|
@ -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)
|
||||
|
||||
|
|
BIN
mysys/test_xml
Executable file
BIN
mysys/test_xml
Executable file
Binary file not shown.
89
mysys/test_xml.c
Normal file
89
mysys/test_xml.c
Normal file
|
@ -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;
|
||||
}
|
369
mysys/xml.c
Normal file
369
mysys/xml.c
Normal file
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue