/* * $Id: mi_parser.c 1404 2006-12-14 14:40:45Z bogdan_iancu $ * * Copyright (C) 2006 Voice Sistem SRL * * This file is part of openser, a free SIP server. * * openser 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. * * openser 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. * * * History: * --------- * 2006-09-25 first version (bogdan) */ #include #include #include #include "../../str.h" #include "../../dprint.h" #include "../../mi/tree.h" #include "../../mem/mem.h" #include "fifo_fnc.h" #include "mi_fifo.h" #include "mi_parser.h" static char *mi_parse_buffer = 0; static unsigned int mi_parse_buffer_len = 0; int mi_parser_init( unsigned int size ) { mi_parse_buffer_len = size; mi_parse_buffer = pkg_malloc(size); if(!mi_parse_buffer){ LOG(L_ERR, "ERROR:mi_fifo:mi_parser_init: pkg_malloc cannot " "allocate any more memory!\n"); return -1; } return 0; } /* returns -1 = error * 0 = ok * 1 = end of stream */ static inline int mi_parse_node( FILE *stream, str *buf, str *name, str *value) { char *p, *pmax; char *start; char *mark_nsp; int line_len; /* read one line */ do { if (mi_read_line( buf->s, buf->len, stream, &line_len)<0) { LOG(L_ERR,"ERROR:mi_fifo:mi_parse_tree: failed to read from " "fifo\n"); return -1; } if (line_len == 1){ DBG("DEBUG:mi_fifo:mi_parse_tree: end of input tree\n"); return 1; } start = buf->s; pmax = buf->s + line_len - 1; /* remove leading spaces */ for( ; starts = value->s = 0; name->len = value->len = 0; mark_nsp = 0; /* start parsing */ if (*start!='"') { /* look for the atribute name */ p = mark_nsp = start; while ( p!=pmax && ( (p[0]!=MI_ATTR_VAL_SEP1) || (p+1==pmax) || p[1]!=MI_ATTR_VAL_SEP2) ) { if (!isspace((int)*p)) { if (*p=='"') goto parse_err; mark_nsp = p; } p++; } if (p!=pmax) { /* we have found the separator */ if (p==start) { /* empty attr name */ } else { name->s = start; name->len = mark_nsp - start + 1; } p += 2; /* for separator */ DBG("DEBUG:mi_fifo:mi_parse_node: attr name <%.*s> found\n", name->len, name->s); /* consume the trailing spaces */ for( ; p!=pmax && isspace((int)*p) ; p++); if (p==pmax) { /* empty value.....we are done */ goto done; } /* value (only if not quoted ) */ if (*p!='"') { for( start=p ; p!=pmax ; p++ ) { if (!isspace((int)*p)) { if (*p=='"') goto parse_err; mark_nsp = p; } } value->s = start; value->len = mark_nsp + 1 - start; goto done; } /* quoted value....continue */ } else { /* we have an empty name ... and we read a non-quoted value */ value->s = start; value->len = mark_nsp + 1 - start; goto done; } } else { p = start; } start = p+1; value->s = start; do { p = start; /* parse the buffer and look for " */ while (plen = p - value->s; /* is the line ending propely (only spaces) ? */ for( p++ ; p!=pmax && isspace((int)*p) ; p++); if (p!=pmax) goto parse_err; /* found! */ goto done; } } else { p++; } } /* adjust input buffer */ p++; buf->len -= p - buf->s; buf->s = p; /*read one more line */ if (mi_read_line( buf->s, buf->len, stream, &line_len)<0) { LOG(L_ERR,"ERROR:mi_fifo:mi_parse_tree: failed to re-read from " "fifo\n"); return -1; } if (line_len == 1) { DBG("DEBUG:mi_fifo:mi_parse_tree: end of input tree\n"); return -2; } start = buf->s; pmax = buf->s + line_len - 1; } while(1); done: buf->len -= p - buf->s; buf->s = p; return 0; parse_err: LOG(L_ERR,"ERROR:mi_fifo:mi_parse_node: parse error around %c\n",*p); return -1; } struct mi_root * mi_parse_tree(FILE *stream) { struct mi_root *root; struct mi_node *node; str name; str value; str buf; int ret; buf.s = mi_parse_buffer; buf.len= mi_parse_buffer_len; root = init_mi_tree(0,0,0); if (!root) { LOG(L_ERR, "ERROR:mi_fifo:mi_parse_tree: the MI tree cannot be " "initialized!\n"); goto error; } node = &root->node; name.s = value.s = 0; name.len = value.len = 0; /* every tree for a command ends with a \n that is alone on its line */ while ( (ret=mi_parse_node(stream, &buf, &name, &value))>=0 ) { if (ret==1) return root; DBG("DEBUG:mi_fifo:mi_parse_tree: adding node <%.*s> ; val <%.*s>\n", name.len,name.s, value.len,value.s); if(!add_mi_node_child(node,0,name.s,name.len,value.s,value.len)){ LOG(L_ERR, "ERROR:mi_fifo:mi_parse_tree: cannot add the child " "node to the tree\n"); goto error; } } LOG(L_ERR, "ERROR:mi_fifo:mi_parse_tree: Parse error!\n"); if (ret==-1) { /* consume the rest of the fifo request */ do { mi_read_line(mi_parse_buffer,mi_parse_buffer_len,stream,&ret); }while(ret>1); } error: if (root) free_mi_tree(root); return 0; }