mi_parser.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2006 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00021  *
00022  *
00023  * History:
00024  * ---------
00025  *  2006-09-25  first version (bogdan)
00026  */
00027 
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <ctype.h>
00038 
00039 #include "../../str.h"
00040 #include "../../dprint.h"
00041 #include "../../lib/kmi/mi.h"
00042 #include "../../mem/mem.h"
00043 #include "fifo_fnc.h"
00044 #include "mi_fifo.h"
00045 #include "mi_parser.h"
00046 
00047 static char *mi_parse_buffer = 0;
00048 static unsigned int mi_parse_buffer_len = 0;
00049 
00050 
00051 int mi_parser_init( unsigned int size )
00052 {
00053         mi_parse_buffer_len = size;
00054         mi_parse_buffer = pkg_malloc(size);
00055 
00056         if(!mi_parse_buffer){
00057                 LM_ERR("pkg_malloc cannot allocate any more memory!\n");
00058                 return -1;
00059         }
00060 
00061         return 0;
00062 }
00063 
00064 
00065 
00066 /* returns -1 = error
00067  *          0 = ok
00068  *          1 = end of stream
00069  */
00070 static inline int mi_parse_node( FILE *stream, str *buf, str *name, str *value)
00071 {
00072         char *p, *pmax;
00073         char *start;
00074         char *mark_nsp;
00075         int line_len;
00076 
00077         /* read one line */
00078         do {
00079                 if (mi_read_line( buf->s, buf->len, stream, &line_len)<0) {
00080                         LM_ERR("failed to read from fifo\n");
00081                         return -1;
00082                 }
00083                 if (line_len == 1){
00084                         LM_DBG("end of fifo input tree\n");
00085                         return 1;
00086                 }
00087 
00088                 start = buf->s;
00089                 pmax = buf->s + line_len - 1;
00090 
00091                 /* remove leading spaces */
00092                 for( ; start<pmax && isspace((int)*start) ; start++ );
00093         } while ( start==pmax );
00094 
00095         /* init */
00096         name->s = value->s = 0;
00097         name->len = value->len = 0;
00098 
00099         mark_nsp = 0;
00100 
00101         /* start parsing */
00102         if (*start!='"') {
00103                 /* look for the atribute name */
00104                 p = mark_nsp = start;
00105                 while ( p!=pmax && ( (p[0]!=MI_ATTR_VAL_SEP1) || (p+1==pmax)
00106                 || p[1]!=MI_ATTR_VAL_SEP2) ) {
00107                         if (!isspace((int)*p)) {
00108                                 if (*p=='"')
00109                                         goto parse_err;
00110                                 mark_nsp = p;
00111                         }
00112                         p++;
00113                 }
00114 
00115                 if (p!=pmax) {
00116                         /* we have found the separator */
00117                         if (p==start) {
00118                                 /* empty attr name */
00119                         } else {
00120                                 name->s = start;
00121                                 name->len = mark_nsp - start + 1;
00122                         }
00123 
00124                         p += 2; /* for separator */
00125 
00126                         LM_DBG("attr name <%.*s> found\n",
00127                                 name->len, name->s);
00128 
00129                         /* consume the trailing spaces */
00130                         for( ; p!=pmax && isspace((int)*p) ; p++);
00131 
00132                         if (p==pmax) {
00133                                 /* empty value.....we are done */
00134                                 goto done;
00135                         }
00136 
00137                         /* value (only if not quoted ) */
00138                         if (*p!='"') {
00139                                 for( start=p ; p!=pmax ; p++ ) {
00140                                         if (!isspace((int)*p)) {
00141                                                 if (*p=='"')
00142                                                         goto parse_err;
00143                                                 mark_nsp = p;
00144                                         }
00145                                 }
00146                                 value->s = start;
00147                                 value->len = mark_nsp + 1  - start;
00148                                 goto done;
00149                         }
00150                         /* quoted value....continue */
00151                 } else {
00152                         /* we have an empty name ... and we read a non-quoted value */
00153                         value->s = start;
00154                         value->len = mark_nsp + 1 - start;
00155                         goto done;
00156                 }
00157         } else {
00158                 p = start;
00159         }
00160 
00161         start = p+1;
00162         value->s = start;
00163 
00164         do {
00165                 p = start;
00166                 /* parse the buffer and look for " */
00167                 while (p<pmax) {
00168                         if (*p=='"') {
00169                                 if (start+1!=p && *(p-1)=='\\') {
00170                                         /* skip current char */
00171                                         memmove( p-1, p, pmax-p);
00172                                         pmax--;
00173                                 } else {
00174                                         /* end of value */
00175                                         value->len = p - value->s;
00176                                         /* is the line ending propely (only spaces) ? */
00177                                         for( p++ ; p!=pmax && isspace((int)*p) ; p++);
00178                                         if (p!=pmax)
00179                                                 goto parse_err;
00180                                         /* found! */
00181                                         goto done;
00182                                 }
00183                         } else {
00184                                 p++;
00185                         }
00186                 }
00187 
00188                 /* adjust input buffer */
00189                 p++;
00190                 buf->len -= p - buf->s;
00191                 buf->s = p;
00192 
00193                 /*read one more line */
00194                 if (mi_read_line( buf->s, buf->len, stream, &line_len)<0) {
00195                         LM_ERR("failed to re-read from fifo\n");
00196                         return -1;
00197                 }
00198                 if (line_len == 1) {
00199                         LM_DBG("end of fifo input tree\n");
00200                         return -2;
00201                 }
00202 
00203                 start = buf->s;
00204                 pmax = buf->s + line_len - 1;
00205         } while(1);
00206 
00207 done:
00208         buf->len -= p - buf->s;
00209         buf->s = p;
00210         return 0;
00211 parse_err:
00212         LM_ERR("parse error around %c\n",*p);
00213         return -1;
00214 }
00215 
00216 
00217 
00218 struct mi_root * mi_parse_tree(FILE *stream) {
00219         struct mi_root *root;
00220         struct mi_node *node;
00221         str name;
00222         str value;
00223         str buf;
00224         int ret;
00225 
00226         buf.s = mi_parse_buffer;
00227         buf.len= mi_parse_buffer_len;
00228 
00229         root = init_mi_tree(0,0,0);
00230         if (!root) {
00231                 LM_ERR("the MI tree cannot be initialized!\n");
00232                 goto error;
00233         }
00234         node = &root->node;
00235 
00236         name.s = value.s = 0;
00237         name.len = value.len = 0;
00238 
00239         /* every tree for a command ends with a \n that is alone on its line */
00240         while ( (ret=mi_parse_node(stream, &buf, &name, &value))>=0 ) {
00241                 if (ret==1)
00242                         return root;
00243 
00244                 LM_DBG("adding node <%.*s> ; val <%.*s>\n",
00245                         name.len,name.s, value.len,value.s);
00246 
00247                 if(!add_mi_node_child(node,0,name.s,name.len,value.s,value.len)){
00248                         LM_ERR("cannot add the child node to the MI tree\n");
00249                         goto error;
00250                 }
00251         }
00252 
00253         LM_ERR("Parse error!\n");
00254         if (ret==-1) {
00255                 /* consume the rest of the fifo request */
00256                 do {
00257                         mi_read_line(mi_parse_buffer,mi_parse_buffer_len,stream,&ret);
00258                 }while(ret>1);
00259         }
00260 
00261 error:
00262         if (root)
00263                 free_mi_tree(root);
00264         return 0;
00265 }
00266 
00267