#ifdef RCS
static char rcsid[]=
"$Id: goodies.c,v 1.74 2001/08/04 07:17:44 guenther Exp $";
#endif
#include "procmail.h"
#include "sublib.h"
#include "robust.h"
#include "shell.h"
#include "misc.h"
#include "pipes.h"
#include "common.h"
#include "acommon.h"
#include "cstdio.h"
#include "variables.h"
#include "goodies.h"
const char test[]="test";
const char*Tmnate,*All_args;
static const char*evalenv(skipping)
int skipping;
{ int j=buf2[0]-'0';
return skipping?(const char*)0:
(unsigned)j>9?getenv(buf2):
!j?argv0:
j<=crestarg?restargv[j-1]:(const char*)0;
}
#define NOTHING_YET (-1)
#define SKIPPING_SPACE 0
#define NORMAL_TEXT 1
#define DOUBLE_QUOTED 2
#define SINGLE_QUOTED 3
#define fgetc() (*fpgetc)()
#define CHECKINC() (fencepost<p?(skipping|=1,p=fencepost):0)
int readparse(p,fpgetc,sarg,skipping)register char*p;int(*const fpgetc)();
const int sarg;int skipping;
{ static int i,skipbracelev,bracegot;int got,bracelev,qbracelev;
charNUM(num,long),*startb,*const fencepost=buf+linebuf,
*const fencepost2=buf2+linebuf;
static char*skipback;static const char*oldstartb;
bracelev=qbracelev=0;All_args=0;
if(skipping)skipping=2;
for(got=NOTHING_YET;;)
loop:
{ i=fgetc();
newchar:
fencepost[1]='\0';CHECKINC();
switch(i)
{ case EOF:
if(sarg<2&&got>NORMAL_TEXT)
early_eof: nlog(unexpeof);
ready: if(got!=SKIPPING_SPACE||sarg)
*p++='\0';
Tmnate=p;
if(skipping&1)
{ nlog(exceededlb);setoverflow();
}
return skipping&1;
case '\\':
if(got==SINGLE_QUOTED)
break;
i=fgetc();
Quoted: switch(i)
{ case EOF:
goto early_eof;
case '\n':
continue;
case '#':
if(got>SKIPPING_SPACE)
goto noesc;
case ' ':case '\t':case '\'':
if(got==DOUBLE_QUOTED)
goto noesc;
case '"':case '\\':case '$':case '`':
goto nodelim;
case '}':
if(got<=NORMAL_TEXT&&bracelev||
got==DOUBLE_QUOTED&&bracelev>qbracelev)
goto nodelim;
}
if(got>NORMAL_TEXT)
noesc: *p++='\\';
break;
case '`':
if(got==SINGLE_QUOTED)
goto nodelim;
for(startb=p;;)
{ switch(i=fgetc())
{ case '"':
if(got!=DOUBLE_QUOTED)
break;
forcebquote: case EOF:case '`':
if(skipping)
*(p=startb)='\0';
else
{ int osh=sh;
*p='\0';
if(!(sh=!!strpbrk(startb,shellmetas)))
{ const char*save=sgetcp,*sAll_args;
sgetcp=p=tstrdup(startb);sAll_args=All_args;
if(readparse(startb,sgetc,0,0)
#ifndef GOT_bin_test
||!strcmp(test,startb)
#endif
)strcpy(startb,p),sh=1;
All_args=sAll_args;
free(p);sgetcp=save;
}
startb=fromprog(
p=startb,startb,(size_t)(buf-startb+linebuf-3));
sh=osh;
}
if(got!=DOUBLE_QUOTED)
{ i=0;startb=p;
goto simplsplit;
}
if(i=='"'||got<=SKIPPING_SPACE)
got=NORMAL_TEXT;
p=startb;
goto loop;
case '\\':
switch(i=fgetc())
{ case EOF:nlog(unexpeof);
goto forcebquote;
case '\n':
continue;
case '"':
if(got!=DOUBLE_QUOTED)
break;
case '\\':case '$':case '`':
goto escaped;
}
*p++='\\';
}
escaped: CHECKINC();*p++=i;
}
case '"':
switch(got)
{ case DOUBLE_QUOTED:
if(qbracelev<bracelev)
case SINGLE_QUOTED:
goto nodelim;
got=NORMAL_TEXT;
continue;
}
qbracelev=bracelev;got=DOUBLE_QUOTED;
continue;
case '\'':
switch(got)
{ case DOUBLE_QUOTED:
goto nodelim;
case SINGLE_QUOTED:got=NORMAL_TEXT;
continue;
}
got=SINGLE_QUOTED;
continue;
case '}':
if(got<=NORMAL_TEXT&&bracelev||
got==DOUBLE_QUOTED&&bracelev>qbracelev)
{ bracelev--;
if(skipback&&bracelev==skipbracelev)
{ skipping-=2;p=skipback;skipback=0;startb=(char*)oldstartb;
got=bracegot;
goto closebrace;
}
continue;
}
goto nodelim;
case '#':
if(got>SKIPPING_SPACE)
break;
while((i=fgetc())!=EOF&&i!='\n');
goto ready;
case '$':
if(got==SINGLE_QUOTED)
break;
startb=buf2;
switch(i=fgetc())
{ case EOF:*p++='$';got=NORMAL_TEXT;
goto ready;
case '@':
if(got!=DOUBLE_QUOTED)
goto normchar;
if(!skipping)
All_args=p;
continue;
case '{':
while(EOF!=(i=fgetc())&&alphanum(i))
{ if(startb>=fencepost2)
startb=buf2+2,skipping|=1;
*startb++=i;
}
*startb='\0';
if(numeric(*buf2)&&buf2[1])
goto badsub;
startb=(char*)evalenv(skipping);
switch(i)
{ default:
goto badsub;
case ':':
switch(i=fgetc())
{ case '-':
if(startb&&*startb)
goto noalt;
goto doalt;
case '+':
if(startb&&*startb)
goto doalt;
goto noalt;
default:
badsub: nlog("Bad substitution of");logqnl(buf2);
continue;
}
case '+':
if(startb)
goto doalt;
goto noalt;
case '-':
if(startb)
noalt: if(!skipping)
{ skipping+=2;skipback=p;skipbracelev=bracelev;
oldstartb=startb;bracegot=got;
}
doalt: bracelev++;
continue;
#if 0
case '%':
case '#':
#endif
case '}':
closebrace: if(!startb)
startb=(char*)empty;
break;
}
goto ibreak;
case '$':ultstr(0,(unsigned long)thepid,startb=num);
goto ieofstr;
case '?':ltstr(0,(long)lexitcode,startb=num);
goto ieofstr;
case '#':ultstr(0,(unsigned long)crestarg,startb=num);
goto ieofstr;
case '=':ltstr(0,lastscore,startb=num);
ieofstr: i='\0';
goto copyit;
case '_':startb=incnamed?incnamed->ename:(char*)empty;
goto ibreak;
case '-':startb=(char*)tgetenv(lastfolder);
ibreak: i='\0';
break;
default:
{ int quoted=0;
if(numeric(i))
{ *startb++=i;i='\0';
goto finsb;
}
if(i=='\\')
quoted=1,i=fgetc();
if(alphanum(i))
{ do
{ if(startb>=fencepost2)
startb=buf2+2,skipping|=1;
*startb++=i;
}
while(EOF!=(i=fgetc())&&alphanum(i));
if(i==EOF)
i='\0';
finsb: *startb='\0';
if(!(startb=(char*)evalenv(skipping)))
startb=(char*)empty;
if(quoted)
{ *p++='(';CHECKINC();
*p++=')';
for(;CHECKINC(),*startb;*p++= *startb++)
if(strchr("(|)*?+.^$[\\",*startb))
*p++='\\';
normchar: quoted=0;
}
else
break;
}
else
*p++='$';
if(got<=SKIPPING_SPACE)
got=NORMAL_TEXT;
if(quoted)
goto Quoted;
goto eeofstr;
}
}
if(got!=DOUBLE_QUOTED)
simplsplit: { char*q;
if(sarg)
goto copyit;
if(q=simplesplit(p,startb,fencepost,&got))
p=q;
else
skipping|=1,p=fencepost;
}
else
copyit: { size_t len=fencepost-p+1;
if(strlcpy(p,startb,len)>=len)
skipping|=1;
if(got<=SKIPPING_SPACE)
got=NORMAL_TEXT;
p=strchr(p,'\0');
}
eeofstr: if(i)
goto newchar;
continue;
#if 0
case '~':
if(got==NORMAL_TEXT&&p[-1]!='='&&p[-1]!=':')
break;
case '&':case '|':case '<':case '>':case ';':
case '?':case '*':case '[':
if(got<=NORMAL_TEXT)
sh=1;
break;
#endif
case ' ':case '\t':
switch(got)
{ case NORMAL_TEXT:
if(sarg==1)
goto ready;
got=SKIPPING_SPACE;*p++=sarg?' ':'\0';
case NOTHING_YET:case SKIPPING_SPACE:
continue;
}
case '\n':
if(got<=NORMAL_TEXT)
goto ready;
}
nodelim:
*p++=i;
if(got<=SKIPPING_SPACE)
got=NORMAL_TEXT;
}
}
char*simplesplit(to,from,fencepost,gotp)char*to;const char*from,*fencepost;
int*gotp;
{ register int got= *gotp;
for(;to<=fencepost;from++)
{ switch(*from)
{ case ' ':case '\t':case '\n':
if(got>SKIPPING_SPACE)
*to++='\0',got=SKIPPING_SPACE;
continue;
case '\0':
goto ret;
}
*to++= *from;got=NORMAL_TEXT;
}
to=0;
ret:
*gotp=got;
return to;
}
void concatenate(p)register char*p;
{ while(p!=Tmnate)
{ while(*p)
p++;
*p++=' ';
}
*p=p[-1]='\0';
}
void metaparse(p)const char*p;
{ if(sh=!!strpbrk(p,shellmetas))
strcpy(buf,p);
else
{ sgetcp=p=tstrdup(p);
if(readparse(buf,sgetc,0,0)
#ifndef GOT_bin_test
||!strcmp(test,buf)
#endif
)
strcpy(buf,p),sh=1;
free((char*)p);
}
}
void ltstr(minwidth,val,dest)const int minwidth;const long val;char*dest;
{ if(val<0)
{ *dest=' ';ultstr(minwidth-1,-val,dest+1);
while(*++dest==' ');
dest[-1]='-';
}
else
ultstr(minwidth,val,dest);
}
#ifdef NOstrtod
double strtod(str,ptr)const char*str;char**const ptr;
{ int sign,any;unsigned i;char*chp;double acc,fracc;
fracc=1;acc=any=sign=0;
switch(*(chp=skpspace(str)))
{ case '-':sign=1;
case '+':chp++;
}
while((i=(unsigned)*chp++-'0')<=9)
acc=acc*10+i,any=1;
switch(i)
{ case (unsigned)'.'-'0':case (unsigned)','-'0':
while(fracc/=10,(i=(unsigned)*chp++-'0')<=9)
acc+=fracc*i,any=1;
}
if(ptr)
*ptr=any?chp-1:(char**)str;
return sign?-acc:acc;
}
#endif