mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			401 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			401 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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 (!bcmp(p->cur,"<!--",4))
 | 
						|
  {
 | 
						|
    for( ; (p->cur < p->end) && 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 ((uint) (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_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 ; 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;
 | 
						|
}
 |