14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * echo [arg...]
234887Schin * print [-nrps] [-f format] [-u filenum] [arg...]
244887Schin * printf format [arg...]
254887Schin *
264887Schin * David Korn
274887Schin * AT&T Labs
284887Schin */
294887Schin
304887Schin #include "defs.h"
314887Schin #include <error.h>
324887Schin #include <stak.h>
334887Schin #include "io.h"
344887Schin #include "name.h"
354887Schin #include "history.h"
364887Schin #include "builtins.h"
374887Schin #include "streval.h"
384887Schin #include <tmx.h>
394887Schin #include <ccode.h>
404887Schin
414887Schin union types_t
424887Schin {
434887Schin unsigned char c;
444887Schin short h;
454887Schin int i;
464887Schin long l;
474887Schin Sflong_t ll;
484887Schin Sfdouble_t ld;
494887Schin double d;
504887Schin float f;
514887Schin char *s;
524887Schin int *ip;
534887Schin char **p;
544887Schin };
554887Schin
564887Schin struct printf
574887Schin {
584887Schin Sffmt_t hdr;
594887Schin int argsize;
604887Schin int intvar;
614887Schin char **nextarg;
628462SApril.Chin@Sun.COM char *lastarg;
634887Schin char cescape;
644887Schin char err;
654887Schin Shell_t *sh;
664887Schin };
674887Schin
684887Schin static int extend(Sfio_t*,void*, Sffmt_t*);
694887Schin static const char preformat[] = "";
704887Schin static char *genformat(char*);
714887Schin static int fmtvecho(const char*, struct printf*);
728462SApril.Chin@Sun.COM static ssize_t fmtbase64(Sfio_t*, char*, int);
734887Schin
744887Schin struct print
754887Schin {
764887Schin Shell_t *sh;
774887Schin const char *options;
784887Schin char raw;
794887Schin char echon;
804887Schin };
814887Schin
824887Schin static char* nullarg[] = { 0, 0 };
834887Schin
844887Schin #if !SHOPT_ECHOPRINT
B_echo(int argc,char * argv[],void * extra)854887Schin int B_echo(int argc, char *argv[],void *extra)
864887Schin {
874887Schin static char bsd_univ;
884887Schin struct print prdata;
894887Schin prdata.options = sh_optecho+5;
904887Schin prdata.raw = prdata.echon = 0;
918462SApril.Chin@Sun.COM prdata.sh = ((Shbltin_t*)extra)->shp;
924887Schin NOT_USED(argc);
934887Schin /* This mess is because /bin/echo on BSD is different */
944887Schin if(!prdata.sh->universe)
954887Schin {
964887Schin register char *universe;
974887Schin if(universe=astconf("UNIVERSE",0,0))
984887Schin bsd_univ = (strcmp(universe,"ucb")==0);
994887Schin prdata.sh->universe = 1;
1004887Schin }
1014887Schin if(!bsd_univ)
1024887Schin return(b_print(0,argv,&prdata));
1034887Schin prdata.options = sh_optecho;
1044887Schin prdata.raw = 1;
1054887Schin while(argv[1] && *argv[1]=='-')
1064887Schin {
1074887Schin if(strcmp(argv[1],"-n")==0)
1084887Schin prdata.echon = 1;
1094887Schin #if !SHOPT_ECHOE
1104887Schin else if(strcmp(argv[1],"-e")==0)
1114887Schin prdata.raw = 0;
1124887Schin else if(strcmp(argv[1],"-ne")==0 || strcmp(argv[1],"-en")==0)
1134887Schin {
1144887Schin prdata.raw = 0;
1154887Schin prdata.echon = 1;
1164887Schin }
1174887Schin #endif /* SHOPT_ECHOE */
1184887Schin else
1194887Schin break;
1204887Schin argv++;
1214887Schin }
1224887Schin return(b_print(0,argv,&prdata));
1234887Schin }
1244887Schin #endif /* SHOPT_ECHOPRINT */
1254887Schin
b_printf(int argc,char * argv[],void * extra)1264887Schin int b_printf(int argc, char *argv[],void *extra)
1274887Schin {
1284887Schin struct print prdata;
1294887Schin NOT_USED(argc);
1304887Schin memset(&prdata,0,sizeof(prdata));
1318462SApril.Chin@Sun.COM prdata.sh = ((Shbltin_t*)extra)->shp;
1324887Schin prdata.options = sh_optprintf;
1334887Schin return(b_print(-1,argv,&prdata));
1344887Schin }
1354887Schin
1364887Schin /*
1374887Schin * argc==0 when called from echo
1384887Schin * argc==-1 when called from printf
1394887Schin */
1404887Schin
b_print(int argc,char * argv[],void * extra)1414887Schin int b_print(int argc, char *argv[], void *extra)
1424887Schin {
1434887Schin register Sfio_t *outfile;
1444887Schin register int exitval=0,n, fd = 1;
1458462SApril.Chin@Sun.COM register Shell_t *shp = ((Shbltin_t*)extra)->shp;
1464887Schin const char *options, *msg = e_file+4;
1474887Schin char *format = 0;
1488462SApril.Chin@Sun.COM int sflag = 0, nflag=0, rflag=0, vflag=0;
1494887Schin if(argc>0)
1504887Schin {
1514887Schin options = sh_optprint;
1524887Schin nflag = rflag = 0;
1534887Schin format = 0;
1544887Schin }
1554887Schin else
1564887Schin {
1574887Schin struct print *pp = (struct print*)extra;
1584887Schin shp = pp->sh;
1594887Schin options = pp->options;
1604887Schin if(argc==0)
1614887Schin {
1624887Schin nflag = pp->echon;
1634887Schin rflag = pp->raw;
1644887Schin argv++;
1654887Schin goto skip;
1664887Schin }
1674887Schin }
1684887Schin while((n = optget(argv,options))) switch(n)
1694887Schin {
1704887Schin case 'n':
1714887Schin nflag++;
1724887Schin break;
1734887Schin case 'p':
1744887Schin fd = shp->coutpipe;
1754887Schin msg = e_query;
1764887Schin break;
1774887Schin case 'f':
1784887Schin format = opt_info.arg;
1794887Schin break;
1804887Schin case 's':
1814887Schin /* print to history file */
1828462SApril.Chin@Sun.COM if(!sh_histinit((void*)shp))
1834887Schin errormsg(SH_DICT,ERROR_system(1),e_history);
1844887Schin fd = sffileno(shp->hist_ptr->histfp);
1854887Schin sh_onstate(SH_HISTORY);
1864887Schin sflag++;
1874887Schin break;
1884887Schin case 'e':
1894887Schin rflag = 0;
1904887Schin break;
1914887Schin case 'r':
1924887Schin rflag = 1;
1934887Schin break;
1944887Schin case 'u':
1954887Schin fd = (int)strtol(opt_info.arg,&opt_info.arg,10);
1964887Schin if(*opt_info.arg)
1974887Schin fd = -1;
1984887Schin else if(fd<0 || fd >= shp->lim.open_max)
1994887Schin fd = -1;
2004887Schin else if(!(sh.inuse_bits&(1<<fd)) && (sh_inuse(fd) || (shp->hist_ptr && fd==sffileno(shp->hist_ptr->histfp))))
2014887Schin
2024887Schin fd = -1;
2034887Schin break;
2048462SApril.Chin@Sun.COM case 'v':
20510898Sroland.mainz@nrubsig.org vflag='v';
20610898Sroland.mainz@nrubsig.org break;
20710898Sroland.mainz@nrubsig.org case 'C':
20810898Sroland.mainz@nrubsig.org vflag='C';
2098462SApril.Chin@Sun.COM break;
2104887Schin case ':':
2114887Schin /* The following is for backward compatibility */
2124887Schin #if OPT_VERSION >= 19990123
2134887Schin if(strcmp(opt_info.name,"-R")==0)
2144887Schin #else
2154887Schin if(strcmp(opt_info.option,"-R")==0)
2164887Schin #endif
2174887Schin {
2184887Schin rflag = 1;
2194887Schin if(error_info.errors==0)
2204887Schin {
2214887Schin argv += opt_info.index+1;
2224887Schin /* special case test for -Rn */
2234887Schin if(strchr(argv[-1],'n'))
2244887Schin nflag++;
2254887Schin if(*argv && strcmp(*argv,"-n")==0)
2264887Schin {
2274887Schin
2284887Schin nflag++;
2294887Schin argv++;
2304887Schin }
2314887Schin goto skip2;
2324887Schin }
2334887Schin }
2344887Schin else
2354887Schin errormsg(SH_DICT,2, "%s", opt_info.arg);
2364887Schin break;
2374887Schin case '?':
2384887Schin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
2394887Schin break;
2404887Schin }
2414887Schin argv += opt_info.index;
2424887Schin if(error_info.errors || (argc<0 && !(format = *argv++)))
2434887Schin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
2448462SApril.Chin@Sun.COM if(vflag && format)
24510898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_usage(2),"-%c and -f are mutually exclusive",vflag);
2464887Schin skip:
2474887Schin if(format)
2484887Schin format = genformat(format);
2494887Schin /* handle special case of '-' operand for print */
2504887Schin if(argc>0 && *argv && strcmp(*argv,"-")==0 && strcmp(argv[-1],"--"))
2514887Schin argv++;
2524887Schin skip2:
2534887Schin if(fd < 0)
2544887Schin {
2554887Schin errno = EBADF;
2564887Schin n = 0;
2574887Schin }
2584887Schin else if(!(n=shp->fdstatus[fd]))
2598462SApril.Chin@Sun.COM n = sh_iocheckfd(shp,fd);
2604887Schin if(!(n&IOWRITE))
2614887Schin {
2624887Schin /* don't print error message for stdout for compatibility */
2634887Schin if(fd==1)
2644887Schin return(1);
2654887Schin errormsg(SH_DICT,ERROR_system(1),msg);
2664887Schin }
2674887Schin if(!(outfile=shp->sftable[fd]))
2684887Schin {
2694887Schin sh_onstate(SH_NOTRACK);
2704887Schin n = SF_WRITE|((n&IOREAD)?SF_READ:0);
2714887Schin shp->sftable[fd] = outfile = sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fd,n);
2724887Schin sh_offstate(SH_NOTRACK);
2734887Schin sfpool(outfile,shp->outpool,SF_WRITE);
2744887Schin }
2754887Schin /* turn off share to guarantee atomic writes for printf */
2764887Schin n = sfset(outfile,SF_SHARE|SF_PUBLIC,0);
2774887Schin if(format)
2784887Schin {
2794887Schin /* printf style print */
2804887Schin Sfio_t *pool;
2814887Schin struct printf pdata;
2824887Schin memset(&pdata, 0, sizeof(pdata));
2834887Schin pdata.sh = shp;
2844887Schin pdata.hdr.version = SFIO_VERSION;
2854887Schin pdata.hdr.extf = extend;
2864887Schin pdata.nextarg = argv;
2874887Schin sh_offstate(SH_STOPOK);
2884887Schin pool=sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE);
2894887Schin do
2904887Schin {
2914887Schin if(shp->trapnote&SH_SIGSET)
2924887Schin break;
2934887Schin pdata.hdr.form = format;
2944887Schin sfprintf(outfile,"%!",&pdata);
2954887Schin } while(*pdata.nextarg && pdata.nextarg!=argv);
2964887Schin if(pdata.nextarg == nullarg && pdata.argsize>0)
2974887Schin sfwrite(outfile,stakptr(staktell()),pdata.argsize);
29810898Sroland.mainz@nrubsig.org if(sffileno(outfile)!=sffileno(sfstderr))
29910898Sroland.mainz@nrubsig.org sfsync(outfile);
3004887Schin sfpool(sfstderr,pool,SF_WRITE);
3014887Schin exitval = pdata.err;
3024887Schin }
3038462SApril.Chin@Sun.COM else if(vflag)
3048462SApril.Chin@Sun.COM {
3058462SApril.Chin@Sun.COM while(*argv)
30610898Sroland.mainz@nrubsig.org {
30710898Sroland.mainz@nrubsig.org fmtbase64(outfile,*argv++,vflag=='C');
30810898Sroland.mainz@nrubsig.org if(!nflag)
30910898Sroland.mainz@nrubsig.org sfputc(outfile,'\n');
31010898Sroland.mainz@nrubsig.org }
3118462SApril.Chin@Sun.COM }
3124887Schin else
3134887Schin {
3144887Schin /* echo style print */
3158462SApril.Chin@Sun.COM if(nflag && !argv[0])
3168462SApril.Chin@Sun.COM sfsync((Sfio_t*)0);
3178462SApril.Chin@Sun.COM else if(sh_echolist(outfile,rflag,argv) && !nflag)
3184887Schin sfputc(outfile,'\n');
3194887Schin }
3204887Schin if(sflag)
3214887Schin {
3224887Schin hist_flush(shp->hist_ptr);
3234887Schin sh_offstate(SH_HISTORY);
3244887Schin }
3254887Schin else if(n&SF_SHARE)
3264887Schin {
3274887Schin sfset(outfile,SF_SHARE|SF_PUBLIC,1);
3284887Schin sfsync(outfile);
3294887Schin }
3304887Schin return(exitval);
3314887Schin }
3324887Schin
3334887Schin /*
3344887Schin * echo the argument list onto <outfile>
3354887Schin * if <raw> is non-zero then \ is not a special character.
3364887Schin * returns 0 for \c otherwise 1.
3374887Schin */
3384887Schin
sh_echolist(Sfio_t * outfile,int raw,char * argv[])3394887Schin int sh_echolist(Sfio_t *outfile, int raw, char *argv[])
3404887Schin {
3414887Schin register char *cp;
3424887Schin register int n;
3434887Schin struct printf pdata;
3444887Schin pdata.cescape = 0;
3454887Schin pdata.err = 0;
3464887Schin while(!pdata.cescape && (cp= *argv++))
3474887Schin {
3484887Schin if(!raw && (n=fmtvecho(cp,&pdata))>=0)
3494887Schin {
3504887Schin if(n)
3514887Schin sfwrite(outfile,stakptr(staktell()),n);
3524887Schin }
3534887Schin else
3544887Schin sfputr(outfile,cp,-1);
3554887Schin if(*argv)
3564887Schin sfputc(outfile,' ');
3574887Schin sh_sigcheck();
3584887Schin }
3594887Schin return(!pdata.cescape);
3604887Schin }
3614887Schin
3624887Schin /*
3634887Schin * modified version of stresc for generating formats
3644887Schin */
strformat(char * s)3654887Schin static char strformat(char *s)
3664887Schin {
3674887Schin register char* t;
3684887Schin register int c;
3694887Schin char* b;
3704887Schin char* p;
3714887Schin
3724887Schin b = t = s;
3734887Schin for (;;)
3744887Schin {
3754887Schin switch (c = *s++)
3764887Schin {
3774887Schin case '\\':
3784887Schin if(*s==0)
3794887Schin break;
3804887Schin c = chresc(s - 1, &p);
3814887Schin s = p;
3824887Schin #if SHOPT_MULTIBYTE
3834887Schin if(c>UCHAR_MAX && mbwide())
3844887Schin {
3854887Schin t += wctomb(t, c);
3864887Schin continue;
3874887Schin }
3884887Schin #endif /* SHOPT_MULTIBYTE */
3894887Schin if(c=='%')
3904887Schin *t++ = '%';
3914887Schin else if(c==0)
3924887Schin {
3934887Schin *t++ = '%';
3944887Schin c = 'Z';
3954887Schin }
3964887Schin break;
3974887Schin case 0:
3984887Schin *t = 0;
3994887Schin return(t - b);
4004887Schin }
4014887Schin *t++ = c;
4024887Schin }
4034887Schin }
4044887Schin
4054887Schin
genformat(char * format)4064887Schin static char *genformat(char *format)
4074887Schin {
4084887Schin register char *fp;
4094887Schin stakseek(0);
4104887Schin stakputs(preformat);
4114887Schin stakputs(format);
4124887Schin fp = (char*)stakfreeze(1);
4134887Schin strformat(fp+sizeof(preformat)-1);
4144887Schin return(fp);
4154887Schin }
4164887Schin
fmthtml(const char * string)4174887Schin static char *fmthtml(const char *string)
4184887Schin {
4194887Schin register const char *cp = string;
4204887Schin register int c, offset = staktell();
4214887Schin while(c= *(unsigned char*)cp++)
4224887Schin {
4234887Schin #if SHOPT_MULTIBYTE
4244887Schin register int s;
4254887Schin if((s=mbsize(cp-1)) > 1)
4264887Schin {
4274887Schin cp += (s-1);
4284887Schin continue;
4294887Schin }
4304887Schin #endif /* SHOPT_MULTIBYTE */
4314887Schin if(c=='<')
4324887Schin stakputs("<");
4334887Schin else if(c=='>')
4344887Schin stakputs(">");
4354887Schin else if(c=='&')
4364887Schin stakputs("&");
4374887Schin else if(c=='"')
4384887Schin stakputs(""");
4394887Schin else if(c=='\'')
4404887Schin stakputs("'");
4414887Schin else if(c==' ')
4424887Schin stakputs(" ");
4434887Schin else if(!isprint(c) && c!='\n' && c!='\r')
4444887Schin sfprintf(stkstd,"&#%X;",CCMAPC(c,CC_NATIVE,CC_ASCII));
4454887Schin else
4464887Schin stakputc(c);
4474887Schin }
4484887Schin stakputc(0);
4494887Schin return(stakptr(offset));
4504887Schin }
4514887Schin
4528462SApril.Chin@Sun.COM #if 1
fmtbase64(Sfio_t * iop,char * string,int alt)4538462SApril.Chin@Sun.COM static ssize_t fmtbase64(Sfio_t *iop, char *string, int alt)
4548462SApril.Chin@Sun.COM #else
4558462SApril.Chin@Sun.COM static void *fmtbase64(char *string, ssize_t *sz, int alt)
4568462SApril.Chin@Sun.COM #endif
4574887Schin {
4584887Schin char *cp;
4594887Schin Sfdouble_t d;
4608462SApril.Chin@Sun.COM ssize_t size;
4614887Schin Namval_t *np = nv_open(string, NiL, NV_VARNAME|NV_NOASSIGN|NV_NOADD);
4624887Schin static union types_t number;
4638462SApril.Chin@Sun.COM if(!np || nv_isnull(np))
4648462SApril.Chin@Sun.COM {
4658462SApril.Chin@Sun.COM if(sh_isoption(SH_NOUNSET))
4668462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_exit(1),e_notset,string);
4678462SApril.Chin@Sun.COM return(0);
4688462SApril.Chin@Sun.COM }
4694887Schin if(nv_isattr(np,NV_INTEGER))
4704887Schin {
4714887Schin d = nv_getnum(np);
4724887Schin if(nv_isattr(np,NV_DOUBLE))
4734887Schin {
4744887Schin if(nv_isattr(np,NV_LONG))
4754887Schin {
4764887Schin size = sizeof(Sfdouble_t);
4774887Schin number.ld = d;
4784887Schin }
4794887Schin else if(nv_isattr(np,NV_SHORT))
4804887Schin {
4814887Schin size = sizeof(float);
4824887Schin number.f = (float)d;
4834887Schin }
4844887Schin else
4854887Schin {
4864887Schin size = sizeof(double);
4874887Schin number.d = (double)d;
4884887Schin }
4894887Schin }
4904887Schin else
4914887Schin {
4924887Schin if(nv_isattr(np,NV_LONG))
4934887Schin {
4944887Schin size = sizeof(Sflong_t);
4954887Schin number.ll = (Sflong_t)d;
4964887Schin }
4974887Schin else if(nv_isattr(np,NV_SHORT))
4984887Schin {
4994887Schin size = sizeof(short);
5004887Schin number.h = (short)d;
5014887Schin }
5024887Schin else
5034887Schin {
5044887Schin size = sizeof(short);
5054887Schin number.i = (int)d;
5064887Schin }
5074887Schin }
5088462SApril.Chin@Sun.COM #if 1
5098462SApril.Chin@Sun.COM return(sfwrite(iop, (void*)&number, size));
5108462SApril.Chin@Sun.COM #else
5114887Schin if(sz)
5124887Schin *sz = size;
5134887Schin return((void*)&number);
5148462SApril.Chin@Sun.COM #endif
5154887Schin }
5164887Schin if(nv_isattr(np,NV_BINARY))
5178462SApril.Chin@Sun.COM #if 1
5188462SApril.Chin@Sun.COM {
5198462SApril.Chin@Sun.COM Namfun_t *fp;
5208462SApril.Chin@Sun.COM for(fp=np->nvfun; fp;fp=fp->next)
5218462SApril.Chin@Sun.COM {
5228462SApril.Chin@Sun.COM if(fp->disc && fp->disc->writef)
5238462SApril.Chin@Sun.COM break;
5248462SApril.Chin@Sun.COM }
5258462SApril.Chin@Sun.COM if(fp)
5268462SApril.Chin@Sun.COM return (*fp->disc->writef)(np, iop, 0, fp);
5278462SApril.Chin@Sun.COM else
5288462SApril.Chin@Sun.COM {
5298462SApril.Chin@Sun.COM int n = nv_size(np);
53010898Sroland.mainz@nrubsig.org if(nv_isarray(np))
53110898Sroland.mainz@nrubsig.org {
53210898Sroland.mainz@nrubsig.org nv_onattr(np,NV_RAW);
53310898Sroland.mainz@nrubsig.org cp = nv_getval(np);
53410898Sroland.mainz@nrubsig.org nv_offattr(np,NV_RAW);
53510898Sroland.mainz@nrubsig.org }
53610898Sroland.mainz@nrubsig.org else
53710898Sroland.mainz@nrubsig.org cp = (char*)np->nvalue.cp;
5388462SApril.Chin@Sun.COM if((size = n)==0)
5398462SApril.Chin@Sun.COM size = strlen(cp);
5408462SApril.Chin@Sun.COM size = sfwrite(iop, cp, size);
5418462SApril.Chin@Sun.COM return(n?n:size);
5428462SApril.Chin@Sun.COM }
5438462SApril.Chin@Sun.COM }
5448462SApril.Chin@Sun.COM else if(nv_isarray(np) && nv_arrayptr(np))
5458462SApril.Chin@Sun.COM {
5468462SApril.Chin@Sun.COM nv_outnode(np,iop,(alt?-1:0),0);
5478462SApril.Chin@Sun.COM sfputc(iop,')');
5488462SApril.Chin@Sun.COM return(sftell(iop));
5498462SApril.Chin@Sun.COM }
5508462SApril.Chin@Sun.COM else
5518462SApril.Chin@Sun.COM {
5528462SApril.Chin@Sun.COM if(alt && nv_isvtree(np))
5538462SApril.Chin@Sun.COM nv_onattr(np,NV_EXPORT);
5548462SApril.Chin@Sun.COM if(!(cp = nv_getval(np)))
5558462SApril.Chin@Sun.COM return(0);
5568462SApril.Chin@Sun.COM size = strlen(cp);
5578462SApril.Chin@Sun.COM return(sfwrite(iop,cp,size));
5588462SApril.Chin@Sun.COM }
5598462SApril.Chin@Sun.COM #else
5604887Schin nv_onattr(np,NV_RAW);
5614887Schin cp = nv_getval(np);
5624887Schin if(nv_isattr(np,NV_BINARY))
5634887Schin nv_offattr(np,NV_RAW);
5644887Schin if((size = nv_size(np))==0)
5654887Schin size = strlen(cp);
5664887Schin if(sz)
5674887Schin *sz = size;
5684887Schin return((void*)cp);
5698462SApril.Chin@Sun.COM #endif
5708462SApril.Chin@Sun.COM }
5718462SApril.Chin@Sun.COM
varname(const char * str,int n)5728462SApril.Chin@Sun.COM static int varname(const char *str, int n)
5738462SApril.Chin@Sun.COM {
5748462SApril.Chin@Sun.COM register int c,dot=1,len=1;
5758462SApril.Chin@Sun.COM if(n < 0)
5768462SApril.Chin@Sun.COM {
5778462SApril.Chin@Sun.COM if(*str=='.')
5788462SApril.Chin@Sun.COM str++;
5798462SApril.Chin@Sun.COM n = strlen(str);
5808462SApril.Chin@Sun.COM }
5818462SApril.Chin@Sun.COM for(;n > 0; n-=len)
5828462SApril.Chin@Sun.COM {
5838462SApril.Chin@Sun.COM #ifdef SHOPT_MULTIBYTE
5848462SApril.Chin@Sun.COM len = mbsize(str);
5858462SApril.Chin@Sun.COM c = mbchar(str);
5868462SApril.Chin@Sun.COM #else
5878462SApril.Chin@Sun.COM c = *(unsigned char*)str++;
5888462SApril.Chin@Sun.COM #endif
5898462SApril.Chin@Sun.COM if(dot && !(isalpha(c)||c=='_'))
5908462SApril.Chin@Sun.COM break;
5918462SApril.Chin@Sun.COM else if(dot==0 && !(isalnum(c) || c=='_' || c == '.'))
5928462SApril.Chin@Sun.COM break;
5938462SApril.Chin@Sun.COM dot = (c=='.');
5948462SApril.Chin@Sun.COM }
5958462SApril.Chin@Sun.COM return(n==0);
5964887Schin }
5974887Schin
extend(Sfio_t * sp,void * v,Sffmt_t * fe)5984887Schin static int extend(Sfio_t* sp, void* v, Sffmt_t* fe)
5994887Schin {
6004887Schin char* lastchar = "";
6014887Schin register int neg = 0;
6024887Schin Sfdouble_t d;
6034887Schin Sfdouble_t longmin = LDBL_LLONG_MIN;
6044887Schin Sfdouble_t longmax = LDBL_LLONG_MAX;
6054887Schin int format = fe->fmt;
6064887Schin int n;
6074887Schin int fold = fe->base;
6084887Schin union types_t* value = (union types_t*)v;
6094887Schin struct printf* pp = (struct printf*)fe;
6104887Schin register char* argp = *pp->nextarg;
61110898Sroland.mainz@nrubsig.org char* w;
6124887Schin
6138462SApril.Chin@Sun.COM if(fe->n_str>0 && varname(fe->t_str,fe->n_str) && (!argp || varname(argp,-1)))
6148462SApril.Chin@Sun.COM {
6158462SApril.Chin@Sun.COM if(argp)
6168462SApril.Chin@Sun.COM pp->lastarg = argp;
6178462SApril.Chin@Sun.COM else
6188462SApril.Chin@Sun.COM argp = pp->lastarg;
6198462SApril.Chin@Sun.COM if(argp)
6208462SApril.Chin@Sun.COM {
6218462SApril.Chin@Sun.COM sfprintf(pp->sh->strbuf,"%s.%.*s%c",argp,fe->n_str,fe->t_str,0);
6228462SApril.Chin@Sun.COM argp = sfstruse(pp->sh->strbuf);
6238462SApril.Chin@Sun.COM }
6248462SApril.Chin@Sun.COM }
6258462SApril.Chin@Sun.COM else
6268462SApril.Chin@Sun.COM pp->lastarg = 0;
6274887Schin fe->flags |= SFFMT_VALUE;
6284887Schin if(!argp || format=='Z')
6294887Schin {
6304887Schin switch(format)
6314887Schin {
6324887Schin case 'c':
6334887Schin value->c = 0;
6344887Schin fe->flags &= ~SFFMT_LONG;
6354887Schin break;
6364887Schin case 'q':
6374887Schin format = 's';
6384887Schin /* FALL THROUGH */
6394887Schin case 's':
6404887Schin case 'H':
6414887Schin case 'B':
6424887Schin case 'P':
6434887Schin case 'R':
6444887Schin case 'Z':
6454887Schin case 'b':
6464887Schin fe->fmt = 's';
6474887Schin fe->size = -1;
6484887Schin fe->base = -1;
6494887Schin value->s = "";
6504887Schin fe->flags &= ~SFFMT_LONG;
6514887Schin break;
6524887Schin case 'a':
6534887Schin case 'e':
6544887Schin case 'f':
6554887Schin case 'g':
6564887Schin case 'A':
6574887Schin case 'E':
6584887Schin case 'F':
6594887Schin case 'G':
6604887Schin if(SFFMT_LDOUBLE)
6614887Schin value->ld = 0.;
6624887Schin else
6634887Schin value->d = 0.;
6644887Schin break;
6654887Schin case 'n':
6664887Schin value->ip = &pp->intvar;
6674887Schin break;
6684887Schin case 'Q':
6694887Schin value->ll = 0;
6704887Schin break;
6714887Schin case 'T':
6724887Schin fe->fmt = 'd';
6734887Schin value->ll = tmxgettime();
6744887Schin break;
6754887Schin default:
6764887Schin if(!strchr("DdXxoUu",format))
6774887Schin errormsg(SH_DICT,ERROR_exit(1),e_formspec,format);
6784887Schin fe->fmt = 'd';
6794887Schin value->ll = 0;
6804887Schin break;
6814887Schin }
6824887Schin }
6834887Schin else
6844887Schin {
6854887Schin switch(format)
6864887Schin {
6874887Schin case 'p':
6884887Schin value->p = (char**)strtol(argp,&lastchar,10);
6894887Schin break;
6904887Schin case 'n':
6914887Schin {
6924887Schin Namval_t *np;
6934887Schin np = nv_open(argp,sh.var_tree,NV_VARNAME|NV_NOASSIGN|NV_NOARRAY);
6944887Schin nv_unset(np);
6954887Schin nv_onattr(np,NV_INTEGER);
6964887Schin if (np->nvalue.lp = new_of(int32_t,0))
6974887Schin *np->nvalue.lp = 0;
6984887Schin nv_setsize(np,10);
6994887Schin if(sizeof(int)==sizeof(int32_t))
7004887Schin value->ip = (int*)np->nvalue.lp;
7014887Schin else
7024887Schin {
7034887Schin int32_t sl = 1;
7044887Schin value->ip = (int*)(((char*)np->nvalue.lp) + (*((char*)&sl) ? 0 : sizeof(int)));
7054887Schin }
7064887Schin nv_close(np);
7074887Schin break;
7084887Schin }
7094887Schin case 'q':
7104887Schin case 'b':
7114887Schin case 's':
7124887Schin case 'B':
7134887Schin case 'H':
7144887Schin case 'P':
7154887Schin case 'R':
7164887Schin fe->fmt = 's';
7174887Schin fe->size = -1;
7184887Schin if(format=='s' && fe->base>=0)
7194887Schin {
7204887Schin value->p = pp->nextarg;
7214887Schin pp->nextarg = nullarg;
7224887Schin }
7234887Schin else
7244887Schin {
7254887Schin fe->base = -1;
7264887Schin value->s = argp;
7274887Schin }
7284887Schin fe->flags &= ~SFFMT_LONG;
7294887Schin break;
7304887Schin case 'c':
73110898Sroland.mainz@nrubsig.org if(mbwide() && (n = mbsize(argp)) > 1)
73210898Sroland.mainz@nrubsig.org {
73310898Sroland.mainz@nrubsig.org fe->fmt = 's';
73410898Sroland.mainz@nrubsig.org fe->size = n;
73510898Sroland.mainz@nrubsig.org value->s = argp;
73610898Sroland.mainz@nrubsig.org }
73710898Sroland.mainz@nrubsig.org else if(fe->base >=0)
7384887Schin value->s = argp;
7394887Schin else
7404887Schin value->c = *argp;
7414887Schin fe->flags &= ~SFFMT_LONG;
7424887Schin break;
7434887Schin case 'o':
7444887Schin case 'x':
7454887Schin case 'X':
7464887Schin case 'u':
7474887Schin case 'U':
7484887Schin longmax = LDBL_ULLONG_MAX;
7494887Schin case '.':
7504887Schin if(fe->size==2 && strchr("bcsqHPRQTZ",*fe->form))
7514887Schin {
7524887Schin value->ll = ((unsigned char*)argp)[0];
7534887Schin break;
7544887Schin }
7554887Schin case 'd':
7564887Schin case 'D':
7574887Schin case 'i':
7584887Schin switch(*argp)
7594887Schin {
7604887Schin case '\'':
7614887Schin case '"':
76210898Sroland.mainz@nrubsig.org w = argp + 1;
76310898Sroland.mainz@nrubsig.org if(mbwide() && mbsize(w) > 1)
76410898Sroland.mainz@nrubsig.org value->ll = mbchar(w);
76510898Sroland.mainz@nrubsig.org else
76610898Sroland.mainz@nrubsig.org value->ll = *(unsigned char*)w++;
76710898Sroland.mainz@nrubsig.org if(w[0] && (w[0] != argp[0] || w[1]))
7688462SApril.Chin@Sun.COM {
7698462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp);
7708462SApril.Chin@Sun.COM pp->err = 1;
7718462SApril.Chin@Sun.COM }
7724887Schin break;
7734887Schin default:
7744887Schin d = sh_strnum(argp,&lastchar,0);
7754887Schin if(d<longmin)
7764887Schin {
7774887Schin errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);
7784887Schin pp->err = 1;
7794887Schin d = longmin;
7804887Schin }
7814887Schin else if(d>longmax)
7824887Schin {
7834887Schin errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);
7844887Schin pp->err = 1;
7854887Schin d = longmax;
7864887Schin }
7874887Schin value->ll = (Sflong_t)d;
7884887Schin if(lastchar == *pp->nextarg)
7894887Schin {
7904887Schin value->ll = *argp;
7914887Schin lastchar = "";
7924887Schin }
7934887Schin break;
7944887Schin }
7954887Schin if(neg)
7964887Schin value->ll = -value->ll;
7974887Schin fe->size = sizeof(value->ll);
7984887Schin break;
7994887Schin case 'a':
8004887Schin case 'e':
8014887Schin case 'f':
8024887Schin case 'g':
8034887Schin case 'A':
8044887Schin case 'E':
8054887Schin case 'F':
8064887Schin case 'G':
8074887Schin d = sh_strnum(*pp->nextarg,&lastchar,0);
8088462SApril.Chin@Sun.COM switch(*argp)
8098462SApril.Chin@Sun.COM {
8108462SApril.Chin@Sun.COM case '\'':
8118462SApril.Chin@Sun.COM case '"':
8128462SApril.Chin@Sun.COM d = ((unsigned char*)argp)[1];
8138462SApril.Chin@Sun.COM if(argp[2] && (argp[2] != argp[0] || argp[3]))
8148462SApril.Chin@Sun.COM {
8158462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp);
8168462SApril.Chin@Sun.COM pp->err = 1;
8178462SApril.Chin@Sun.COM }
8188462SApril.Chin@Sun.COM break;
8198462SApril.Chin@Sun.COM default:
8208462SApril.Chin@Sun.COM d = sh_strnum(*pp->nextarg,&lastchar,0);
8218462SApril.Chin@Sun.COM break;
8228462SApril.Chin@Sun.COM }
8234887Schin if(SFFMT_LDOUBLE)
8244887Schin {
8254887Schin value->ld = d;
8264887Schin fe->size = sizeof(value->ld);
8274887Schin }
8284887Schin else
8294887Schin {
8304887Schin value->d = d;
8314887Schin fe->size = sizeof(value->d);
8324887Schin }
8334887Schin break;
8344887Schin case 'Q':
8354887Schin value->ll = (Sflong_t)strelapsed(*pp->nextarg,&lastchar,1);
8364887Schin break;
8374887Schin case 'T':
8384887Schin value->ll = (Sflong_t)tmxdate(*pp->nextarg,&lastchar,TMX_NOW);
8394887Schin break;
8404887Schin default:
8414887Schin value->ll = 0;
8424887Schin fe->fmt = 'd';
8434887Schin fe->size = sizeof(value->ll);
8444887Schin errormsg(SH_DICT,ERROR_exit(1),e_formspec,format);
8454887Schin break;
8464887Schin }
8474887Schin if (format == '.')
8484887Schin value->i = value->ll;
8494887Schin if(*lastchar)
8504887Schin {
8514887Schin errormsg(SH_DICT,ERROR_warn(0),e_argtype,format);
8524887Schin pp->err = 1;
8534887Schin }
8544887Schin pp->nextarg++;
8554887Schin }
8564887Schin switch(format)
8574887Schin {
8584887Schin case 'Z':
8594887Schin fe->fmt = 'c';
8604887Schin fe->base = -1;
8614887Schin value->c = 0;
8624887Schin break;
8634887Schin case 'b':
8644887Schin if((n=fmtvecho(value->s,pp))>=0)
8654887Schin {
8664887Schin if(pp->nextarg == nullarg)
8674887Schin {
8684887Schin pp->argsize = n;
8694887Schin return -1;
8704887Schin }
8714887Schin value->s = stakptr(staktell());
8724887Schin }
8734887Schin break;
8744887Schin case 'B':
8758462SApril.Chin@Sun.COM if(!sh.strbuf2)
8768462SApril.Chin@Sun.COM sh.strbuf2 = sfstropen();
8778462SApril.Chin@Sun.COM fe->size = fmtbase64(sh.strbuf2,value->s, fe->flags&SFFMT_ALTER);
8788462SApril.Chin@Sun.COM value->s = sfstruse(sh.strbuf2);
8798462SApril.Chin@Sun.COM fe->flags |= SFFMT_SHORT;
8804887Schin break;
8814887Schin case 'H':
8824887Schin value->s = fmthtml(value->s);
8834887Schin break;
8844887Schin case 'q':
8854887Schin value->s = sh_fmtqf(value->s, !!(fe->flags & SFFMT_ALTER), fold);
8864887Schin break;
8874887Schin case 'P':
8884887Schin {
8894887Schin char *s = fmtmatch(value->s);
8904887Schin if(!s || *s==0)
8914887Schin errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s);
8924887Schin value->s = s;
8934887Schin break;
8944887Schin }
8954887Schin case 'R':
8964887Schin value->s = fmtre(value->s);
8974887Schin if(*value->s==0)
8984887Schin errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s);
8994887Schin break;
9004887Schin case 'Q':
9014887Schin if (fe->n_str>0)
9024887Schin {
9034887Schin fe->fmt = 'd';
9044887Schin fe->size = sizeof(value->ll);
9054887Schin }
9064887Schin else
9074887Schin {
9084887Schin value->s = fmtelapsed(value->ll, 1);
9094887Schin fe->fmt = 's';
9104887Schin fe->size = -1;
9114887Schin }
9124887Schin break;
9134887Schin case 'T':
9144887Schin if(fe->n_str>0)
9154887Schin {
9164887Schin n = fe->t_str[fe->n_str];
9174887Schin fe->t_str[fe->n_str] = 0;
9184887Schin value->s = fmttmx(fe->t_str, value->ll);
9194887Schin fe->t_str[fe->n_str] = n;
9204887Schin }
9214887Schin else value->s = fmttmx(NIL(char*), value->ll);
9224887Schin fe->fmt = 's';
9234887Schin fe->size = -1;
9244887Schin break;
9254887Schin }
9264887Schin return 0;
9274887Schin }
9284887Schin
9294887Schin /*
9304887Schin * construct System V echo string out of <cp>
9314887Schin * If there are not escape sequences, returns -1
9324887Schin * Otherwise, puts null terminated result on stack, but doesn't freeze it
9334887Schin * returns length of output.
9344887Schin */
9354887Schin
fmtvecho(const char * string,struct printf * pp)9364887Schin static int fmtvecho(const char *string, struct printf *pp)
9374887Schin {
9384887Schin register const char *cp = string, *cpmax;
9394887Schin register int c;
9404887Schin register int offset = staktell();
9414887Schin #if SHOPT_MULTIBYTE
9424887Schin int chlen;
9434887Schin if(mbwide())
9444887Schin {
9454887Schin while(1)
9464887Schin {
9474887Schin if ((chlen = mbsize(cp)) > 1)
9484887Schin /* Skip over multibyte characters */
9494887Schin cp += chlen;
9504887Schin else if((c= *cp++)==0 || c == '\\')
9514887Schin break;
9524887Schin }
9534887Schin }
9544887Schin else
9554887Schin #endif /* SHOPT_MULTIBYTE */
9564887Schin while((c= *cp++) && (c!='\\'));
9574887Schin if(c==0)
9584887Schin return(-1);
9594887Schin c = --cp - string;
9604887Schin if(c>0)
9614887Schin stakwrite((void*)string,c);
9624887Schin for(; c= *cp; cp++)
9634887Schin {
9644887Schin #if SHOPT_MULTIBYTE
9654887Schin if (mbwide() && ((chlen = mbsize(cp)) > 1))
9664887Schin {
9674887Schin stakwrite(cp,chlen);
9684887Schin cp += (chlen-1);
9694887Schin continue;
9704887Schin }
9714887Schin #endif /* SHOPT_MULTIBYTE */
9724887Schin if( c=='\\') switch(*++cp)
9734887Schin {
9744887Schin case 'E':
9754887Schin c = ('a'==97?'\033':39); /* ASCII/EBCDIC */
9764887Schin break;
9774887Schin case 'a':
9784887Schin c = '\a';
9794887Schin break;
9804887Schin case 'b':
9814887Schin c = '\b';
9824887Schin break;
9834887Schin case 'c':
9844887Schin pp->cescape++;
9854887Schin pp->nextarg = nullarg;
9864887Schin goto done;
9874887Schin case 'f':
9884887Schin c = '\f';
9894887Schin break;
9904887Schin case 'n':
9914887Schin c = '\n';
9924887Schin break;
9934887Schin case 'r':
9944887Schin c = '\r';
9954887Schin break;
9964887Schin case 'v':
9974887Schin c = '\v';
9984887Schin break;
9994887Schin case 't':
10004887Schin c = '\t';
10014887Schin break;
10024887Schin case '\\':
10034887Schin c = '\\';
10044887Schin break;
10054887Schin case '0':
10064887Schin c = 0;
10074887Schin cpmax = cp + 4;
10084887Schin while(++cp<cpmax && *cp>='0' && *cp<='7')
10094887Schin {
10104887Schin c <<= 3;
10114887Schin c |= (*cp-'0');
10124887Schin }
10134887Schin default:
10144887Schin cp--;
10154887Schin }
10164887Schin stakputc(c);
10174887Schin }
10184887Schin done:
10194887Schin c = staktell()-offset;
10204887Schin stakputc(0);
10214887Schin stakseek(offset);
10224887Schin return(c);
10234887Schin }
1024