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);