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.
26 #ifndef HAVE_OPEN_MEMSTREAM
27 #include <utils/open_memstream.h>
30 #include <utils/cmdparse.h>
35 enum command
{ERR
, IN
, THROW
, SEND
, SHIFT
, IF
, GOTO
, COPY
, EXIT
, EXITRV
, SKIP
, IFARG
, RVATOI
, OUTSHIFT
, OUTTAG
};
37 char *commandname
[]= {
55 #define NUMCOMMANDS (sizeof(commandname)/sizeof(char *))
57 static const char *nullstring
="";
63 #define value nextnum;
65 struct utmstate
*next
;
68 static struct utmstate
*utmsadd(struct utmstate
*head
, struct utmstate
*this)
70 if (!head
|| head
->num
> this->num
) {
74 head
->next
=utmsadd(head
->next
,this);
79 static enum command
searchcommand(char *name
)
82 for (i
=0; i
<NUMCOMMANDS
&& strcmp(name
,commandname
[i
]) != 0; i
++)
90 static inline char *blankskip(char *s
)
92 while (*s
&& (*s
==' ' || *s
=='\t'))
97 static inline char *fieldskip(char *s
)
99 while (*s
&& *s
!=' ' && *s
!='\t' && *s
!='\n')
104 static int readchar(int fd
, struct utm_buf
*inbuf
, char *out
, int timeout
)
107 inbuf
->buf
=(char *)malloc(sizeof(char)*BUFSIZE
);
108 if(!inbuf
->buf
) { perror("readchar"); exit(-1); }
109 inbuf
->len
=inbuf
->pos
=0;
111 if (inbuf
->len
<= inbuf
->pos
)
113 struct pollfd pfd
={fd
, POLLIN
, 0};
114 if (poll(&pfd
,1,timeout
) <= 0) {
117 inbuf
->len
=read(fd
,inbuf
->buf
,BUFSIZE
);
123 *out
= (inbuf
->buf
[(inbuf
->pos
)++]);
127 struct utmstate
*sgoto(struct utmstate
*head
,int nextnum
)
130 if (nextnum
== head
->num
)
133 return sgoto(head
->next
,nextnum
);
135 //fprintf(stderr,"Error Label not found: %d\n",nextnum);
140 void utm_freestate(struct utmstate
*head
)
142 struct utmstate
* rest
= head
->next
;
147 struct utm
*utm_alloc(char *conf
)
150 struct utm
*utm
=NULL
;
153 if ((f
=fopen(conf
,"r")) == NULL
) {
154 //fprintf(stderr,"Configuration file error %s\n",conf);
158 utm
=(struct utm
*)malloc(sizeof(struct utm
));
159 if(!utm
) {perror("utm_alloc"); exit(-1); }
160 utm
->timeout
=TIMEOUT
; utm
->head
= NULL
;
161 while (fgets(buf
,BUFSIZE
,f
) != NULL
) {
168 /* create new automata state */
177 if ((cmd
=searchcommand(currfield
)) != ERR
) {
178 struct utmstate
*new=malloc(sizeof(struct utmstate
));
179 if(!new) {perror("utm_alloc"); exit(-1); }
185 if (*currfield
=='\'') { /* first argument is a string */
187 char skip
=0; /*not escaped*/
188 t
=currfield
=++s
; /* skip ' */
189 while (*s
&& (skip
|| *s
!= '\'')) {
190 if (*s
== '\\' && *(s
+1) != 0) {
193 case 'n': *s
='\n'; break;
194 case 't': *s
='\t'; break;
195 case 'f': *s
='\f'; break;
201 new->string
=strdup(currfield
);
206 new->string
=nullstring
;
208 new->nextnum
=atoi(currfield
);
209 utm
->head
=utmsadd(utm
->head
,new);
212 /* add constant definition */
213 if (strncmp("TIMEOUT",s
,7)==0)
214 utm
->timeout
=atoi(s
+8);
221 void utm_free(struct utm
*utm
)
224 if(utm
->head
) utm_freestate(utm
->head
);
229 int utm_run(struct utm
*utm
, struct utm_buf
*buf
, int fd
, int argc
, char **argv
, struct utm_out
*out
, int debug
)
231 struct utmstate
*status
= utm
->head
;
232 int len
=0, curr
=0, linebufsize
=0, rv
=-1;
235 if(debug
) {int i
; printf("c: %d\n", argc
); for(i
=0; i
<=argc
; i
++) printf("a[%d]: %s\n", i
, argv
[i
]); }
238 int patlen
=strlen(status
->string
);
239 if (debug
) printf("NOW %d parsing %s\n",status
->num
,linebuf
?(linebuf
+curr
):NULL
);
240 switch (status
-> command
) {
241 case ERR
: /* error, return */
242 if(linebuf
) free(linebuf
);
245 case IN
: /* eat from inbuf while timeout or pattern found */
249 if (len
==linebufsize
) {
250 linebufsize
+= BUFSIZE
;
251 linebuf
=realloc(linebuf
,sizeof(char)*(linebufsize
+1));
252 if(!linebuf
){ perror("utm_run"); exit(-1); }
254 if (readchar(fd
, buf
, &linebuf
[len
], utm
->timeout
) < 0)
258 } while (!ltimeout
&& (len
< patlen
|| strncmp(status
->string
,linebuf
+(len
-patlen
),patlen
) != 0));
261 status
=sgoto(utm
->head
,status
->nextnum
);
266 case THROW
: /* drop current linebuf */
268 if(linebuf
) *linebuf
=0;
272 case SEND
: /* write command to fd */
274 const char *t
=status
->string
;
277 FILE *mf
=open_memstream(&ptr
,&size
);
278 while (*t
) { /* create the string */
279 if (*t
== '$' && (t
==status
->string
|| *(t
-1) != '\\')) {
281 if (*t
== '*' || *t
== '0') { /*all parms*/
283 for (i
=0;i
<argc
;i
++) {
284 if (i
) fprintf(mf
," ");
289 while (*t
>='0' && *t
<= '9') t
++;
291 fprintf(mf
,argv
[num
]);
303 case SHIFT
: /* eat first argument */
307 case IF
: /* goto nextnum if pattern match */
308 if (linebuf
&& (strncmp(linebuf
+curr
,status
->string
,patlen
) == 0) )
309 status
=sgoto(utm
->head
,status
->nextnum
);
313 case GOTO
: /* simple goto */
314 status
=sgoto(utm
->head
,status
->nextnum
);
316 case COPY
: /* copy current linebuf to current outbuf */
318 int tocpy
=strlen(linebuf
+curr
)+1;
319 out
->buf
=realloc(out
->buf
, out
->sz
+tocpy
);
320 if(!out
->buf
){ perror("utm_run"); exit(-1); }
321 memcpy(out
->buf
+out
->sz
, linebuf
+curr
, tocpy
);
326 case EXIT
: /* exit with value */
327 rv
= status
->nextnum
;
328 case EXITRV
: /* exit with retval */
329 if(linebuf
) free(linebuf
);
332 case SKIP
: /* skip after the first occurence of string or N chars */
335 if(strlen(status
->string
)) skip
=strstr(linebuf
, status
->string
);
336 if(skip
) curr
=(status
->string
+strlen(status
->string
))-linebuf
;
337 else curr
+=status
->nextnum
;
338 if(curr
>len
) curr
=len
; /* normalize */
342 case IFARG
: /* goto if there are still arguments */
344 status
=sgoto(utm
->head
,status
->nextnum
);
348 case RVATOI
: /* remember current number as return value the
349 optional argument is the base to convert from*/
352 }else if( status
->nextnum
<= 0 ){
353 rv
= strtol(linebuf
+curr
, NULL
, 10);
354 }else if( status
->nextnum
>= 2 && status
->nextnum
<= 36 ){
355 rv
= strtol(linebuf
+curr
, NULL
, status
->nextnum
);
361 case OUTSHIFT
: /* alloc another output buffer and use it */
362 out
->next
=utmout_alloc();
366 case OUTTAG
: /* set tag of current output buffer */
367 out
->tag
=status
->nextnum
;
371 if(linebuf
) free(linebuf
);
378 struct utm_out
*utmout_alloc(void)
380 struct utm_out
*out
= NULL
;
381 out
= (struct utm_out
*)malloc(sizeof(struct utm_out
));
382 if(!out
) { perror(__func__
); exit(-1);}
383 memset(out
, 0, sizeof(struct utm_out
));
387 void utmout_free(struct utm_out
*out
)
390 if(out
->buf
) free(out
->buf
);