loadlwipv6 inlined
[vde.git] / vde-2 / src / common / cmdparse.c
blobee1eb66c8cd61ddf0c3625fbf14c0f3e3c13a63b
1 /*
2 * Copyright (C) 2007 - Renzo Davoli, Luca Bigliardi
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #include <config.h>
19 #include <vde.h>
20 #include <vdecommon.h>
22 #define _GNU_SOURCE
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <errno.h>
31 #define BUFSIZE 256
32 #define TIMEOUT 10000
34 enum command {ERR, IN, THROW, SEND, SHIFT, IF, GOTO, COPY, EXIT, EXITRV, SKIP, IFARG, RVATOI, OUTSHIFT, OUTTAG};
36 char *commandname[]= {
37 "",
38 "IN",
39 "THROW",
40 "SEND",
41 "SHIFT",
42 "IF",
43 "GOTO",
44 "COPY",
45 "EXIT",
46 "EXITRV",
47 "SKIP",
48 "IFARG",
49 "RVATOI",
50 "OUTSHIFT",
51 "OUTTAG"
54 #define NUMCOMMANDS (sizeof(commandname)/sizeof(char *))
56 static const char *nullstring="";
58 struct utmstate {
59 int num;
60 enum command command;
61 const char *string;
62 #define value nextnum;
63 int nextnum;
64 struct utmstate *next;
67 static struct utmstate *utmsadd(struct utmstate *head, struct utmstate *this)
69 if (!head || head->num > this->num) {
70 this->next=head;
71 return this;
72 } else {
73 head->next=utmsadd(head->next,this);
74 return head;
78 static enum command searchcommand(char *name)
80 int i;
81 for (i=0; i<NUMCOMMANDS && strcmp(name,commandname[i]) != 0; i++)
83 if (i<NUMCOMMANDS)
84 return i;
85 else
86 return ERR;
89 static inline char *blankskip(char *s)
91 while (*s && (*s==' ' || *s=='\t'))
92 s++;
93 return s;
96 static inline char *fieldskip(char *s)
98 while (*s && *s!=' ' && *s!='\t' && *s!='\n')
99 s++;
100 return s;
103 static int readchar(int fd, struct utm_buf *inbuf, char *out, int timeout)
105 if (!inbuf->buf) {
106 inbuf->buf=(char *)malloc(sizeof(char)*BUFSIZE);
107 if(!inbuf->buf) { perror("readchar"); exit(-1); }
108 inbuf->len=inbuf->pos=0;
110 if (inbuf->len <= inbuf->pos)
112 struct pollfd pfd={fd, POLLIN, 0};
113 if (poll(&pfd,1,timeout) <= 0) {
114 return -1;
116 inbuf->len=read(fd,inbuf->buf,BUFSIZE);
117 if (inbuf->len==0)
118 return -1;
119 else
120 inbuf->pos=0;
122 *out = (inbuf->buf[(inbuf->pos)++]);
123 return 0;
126 struct utmstate *sgoto(struct utmstate *head,int nextnum)
128 if (head) {
129 if (nextnum == head->num)
130 return head;
131 else
132 return sgoto(head->next,nextnum);
133 } else {
134 //fprintf(stderr,"Error Label not found: %d\n",nextnum);
135 return NULL;
139 void utm_freestate(struct utmstate *head)
141 struct utmstate* rest = head->next;
142 free(head);
143 utm_freestate(rest);
146 struct utm *utm_alloc(char *conf)
148 FILE *f;
149 struct utm *utm=NULL;
150 int line=0;
151 char buf[BUFSIZE];
152 if ((f=fopen(conf,"r")) == NULL) {
153 //fprintf(stderr,"Configuration file error %s\n",conf);
154 errno=ENOENT;
155 return NULL;
157 utm=(struct utm*)malloc(sizeof(struct utm));
158 if(!utm) {perror("utm_alloc"); exit(-1); }
159 utm->timeout=TIMEOUT ; utm->head = NULL;
160 while (fgets(buf,BUFSIZE,f) != NULL) {
161 char *s=buf;
162 int num;
163 line++;
164 s=blankskip(s);
165 num=atoi(s);
166 if (num>0) {
167 /* create new automata state */
168 enum command cmd;
169 char *currfield;
170 char c;
171 s=fieldskip(s);
172 s=blankskip(s);
173 currfield=s;
174 s=fieldskip(s);
175 c=*s;*s=0;
176 if ((cmd=searchcommand(currfield)) != ERR) {
177 struct utmstate *new=malloc(sizeof(struct utmstate));
178 if(!new) {perror("utm_alloc"); exit(-1); }
179 new->num = num;
180 new->command = cmd;
181 *s=c;
182 s=blankskip(s);
183 currfield=s;
184 if (*currfield=='\'') { /* first argument is a string */
185 char *t;
186 char skip=0; /*not escaped*/
187 t=currfield=++s; /* skip ' */
188 while (*s && (skip || *s != '\'')) {
189 if (*s == '\\' && *(s+1) != 0) {
190 s++; /* skip \ */
191 switch (*s) {
192 case 'n': *s='\n'; break;
193 case 't': *s='\t'; break;
194 case 'f': *s='\f'; break;
197 *t++ = *s++;
199 c=*s;*t=0;
200 new->string=strdup(currfield);
201 if (c) s++;
202 s=blankskip(s);
203 currfield=s;
204 } else {
205 new->string=nullstring;
207 new->nextnum=atoi(currfield);
208 utm->head=utmsadd(utm->head,new);
210 } else {
211 /* add constant definition */
212 if (strncmp("TIMEOUT",s,7)==0)
213 utm->timeout=atoi(s+8);
216 fclose(f);
217 return(utm);
220 void utm_free(struct utm *utm)
222 if(utm){
223 if(utm->head) utm_freestate(utm->head);
224 free(utm);
228 int utm_run(struct utm *utm, struct utm_buf *buf, int fd, int argc, char **argv, struct utm_out *out, int debug)
230 struct utmstate *status = utm->head;
231 int len=0, curr=0, linebufsize=0, rv=-1;
232 char *linebuf=NULL;
234 if(debug) {int i; printf("c: %d\n", argc); for(i=0; i <=argc ; i++) printf("a[%d]: %s\n", i, argv[i]); }
236 while (1) {
237 int patlen=strlen(status->string);
238 if (debug) printf("NOW %d parsing %s\n",status->num,linebuf?(linebuf+curr):NULL);
239 switch (status -> command) {
240 case ERR: /* error, return */
241 if(linebuf) free(linebuf);
242 return -1;
243 break;
244 case IN: /* eat from inbuf while timeout or pattern found */
246 int ltimeout=0;
247 do {
248 if (len==linebufsize) {
249 linebufsize += BUFSIZE;
250 linebuf=realloc(linebuf,sizeof(char)*(linebufsize+1));
251 if(!linebuf){ perror("utm_run"); exit(-1); }
253 if (readchar(fd, buf, &linebuf[len], utm->timeout) < 0)
254 ltimeout=1;
255 else
256 len++;
257 } while (!ltimeout && (len < patlen || strncmp(status->string,linebuf+(len-patlen),patlen) != 0));
258 linebuf[len]=0;
259 if(ltimeout)
260 status=sgoto(utm->head,status->nextnum);
261 else
262 status=status->next;
264 break;
265 case THROW: /* drop current linebuf */
266 curr=0;
267 if(linebuf) *linebuf=0;
268 len=0;
269 status=status->next;
270 break;
271 case SEND: /* write command to fd */
273 const char *t=status->string;
274 char *ptr;
275 size_t size;
276 FILE *mf=open_memstream(&ptr,&size);
277 while (*t) { /* create the string */
278 if (*t == '$' && (t==status->string || *(t-1) != '\\')) {
279 t++;
280 if (*t == '*' || *t == '0') { /*all parms*/
281 int i;
282 for (i=0;i<argc;i++) {
283 if (i) fprintf(mf," ");
284 fprintf(mf,argv[i]);
286 } else {
287 int num=atoi(t);
288 while (*t >='0' && *t <= '9') t++;
289 if (num < argc)
290 fprintf(mf,argv[num]);
292 } else
293 fprintf(mf,"%c",*t);
294 t++;
296 fclose(mf);
297 write (fd,ptr,size);
298 free(ptr);
300 status=status->next;
301 break;
302 case SHIFT: /* eat first argument */
303 argc--; argv++;
304 status=status->next;
305 break;
306 case IF: /* goto nextnum if pattern match */
307 if (linebuf && (strncmp(linebuf+curr,status->string,patlen) == 0) )
308 status=sgoto(utm->head,status->nextnum);
309 else
310 status=status->next;
311 break;
312 case GOTO: /* simple goto */
313 status=sgoto(utm->head,status->nextnum);
314 break;
315 case COPY: /* copy current linebuf to current outbuf */
316 if(linebuf){
317 int tocpy=strlen(linebuf+curr)+1;
318 out->buf=realloc(out->buf, out->sz+tocpy);
319 if(!out->buf){ perror("utm_run"); exit(-1); }
320 memcpy(out->buf+out->sz, linebuf+curr, tocpy);
321 out->sz+=tocpy;
323 status=status->next;
324 break;
325 case EXIT: /* exit with value */
326 rv = status->nextnum;
327 case EXITRV: /* exit with retval */
328 if(linebuf) free(linebuf);
329 return rv;
330 break;
331 case SKIP: /* skip after the first occurence of string or N chars */
332 if(linebuf){
333 char *skip=NULL;
334 if(strlen(status->string)) skip=strstr(linebuf, status->string);
335 if(skip) curr=(status->string+strlen(status->string))-linebuf;
336 else curr+=status->nextnum;
337 if(curr>len) curr=len; /* normalize */
339 status=status->next;
340 break;
341 case IFARG: /* goto if there are still arguments */
342 if (argc>=0)
343 status=sgoto(utm->head,status->nextnum);
344 else
345 status=status->next;
346 break;
347 case RVATOI: /* remember current number as return value the
348 optional argument is the base to convert from*/
349 if(!linebuf){
350 rv = -1;
351 }else if( status->nextnum <= 0 ){
352 rv = strtol(linebuf+curr, NULL, 10);
353 }else if( status->nextnum >= 2 && status->nextnum <= 36 ){
354 rv = strtol(linebuf+curr, NULL, status->nextnum);
355 }else{
356 rv = -1;
358 status=status->next;
359 break;
360 case OUTSHIFT: /* alloc another output buffer and use it */
361 out->next=utmout_alloc();
362 out=out->next;
363 status=status->next;
364 break;
365 case OUTTAG: /* set tag of current output buffer */
366 out->tag=status->nextnum;
367 status=status->next;
368 break;
369 default:
370 if(linebuf) free(linebuf);
371 return -1;
372 break;
377 struct utm_out *utmout_alloc(void)
379 struct utm_out *out = NULL;
380 out = (struct utm_out*)malloc(sizeof(struct utm_out));
381 if(!out) { perror(__func__); exit(-1);}
382 memset(out, 0, sizeof(struct utm_out));
383 return out;
386 void utmout_free(struct utm_out *out)
388 while(out) {
389 if(out->buf) free(out->buf);
390 out = out->next;