xref: /onnv-gate/usr/src/lib/libshell/common/bltins/print.c (revision 12068:08a39a083754)
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("&lt;");
4334887Schin 		else if(c=='>')
4344887Schin 			stakputs("&gt;");
4354887Schin 		else if(c=='&')
4364887Schin 			stakputs("&amp;");
4374887Schin 		else if(c=='"')
4384887Schin 			stakputs("&quot;");
4394887Schin 		else if(c=='\'')
4404887Schin 			stakputs("&apos;");
4414887Schin 		else if(c==' ')
4424887Schin 			stakputs("&nbsp;");
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