1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
43e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * David Korn <dgk@research.att.com> *
18da2e3ebdSchin * *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin * echo [arg...]
23da2e3ebdSchin * print [-nrps] [-f format] [-u filenum] [arg...]
24da2e3ebdSchin * printf format [arg...]
25da2e3ebdSchin *
26da2e3ebdSchin * David Korn
27da2e3ebdSchin * AT&T Labs
28da2e3ebdSchin */
29da2e3ebdSchin
30da2e3ebdSchin #include "defs.h"
31da2e3ebdSchin #include <error.h>
32da2e3ebdSchin #include <stak.h>
33da2e3ebdSchin #include "io.h"
34da2e3ebdSchin #include "name.h"
35da2e3ebdSchin #include "history.h"
36da2e3ebdSchin #include "builtins.h"
37da2e3ebdSchin #include "streval.h"
38da2e3ebdSchin #include <tmx.h>
39da2e3ebdSchin #include <ccode.h>
40da2e3ebdSchin
41da2e3ebdSchin union types_t
42da2e3ebdSchin {
43da2e3ebdSchin unsigned char c;
44da2e3ebdSchin short h;
45da2e3ebdSchin int i;
46da2e3ebdSchin long l;
47da2e3ebdSchin Sflong_t ll;
48da2e3ebdSchin Sfdouble_t ld;
49da2e3ebdSchin double d;
50da2e3ebdSchin float f;
51da2e3ebdSchin char *s;
52da2e3ebdSchin int *ip;
53da2e3ebdSchin char **p;
54da2e3ebdSchin };
55da2e3ebdSchin
56da2e3ebdSchin struct printf
57da2e3ebdSchin {
58da2e3ebdSchin Sffmt_t hdr;
59da2e3ebdSchin int argsize;
60da2e3ebdSchin int intvar;
61da2e3ebdSchin char **nextarg;
627c2fbfb3SApril Chin char *lastarg;
63da2e3ebdSchin char cescape;
64da2e3ebdSchin char err;
65da2e3ebdSchin Shell_t *sh;
66da2e3ebdSchin };
67da2e3ebdSchin
68da2e3ebdSchin static int extend(Sfio_t*,void*, Sffmt_t*);
69da2e3ebdSchin static const char preformat[] = "";
70da2e3ebdSchin static char *genformat(char*);
71da2e3ebdSchin static int fmtvecho(const char*, struct printf*);
727c2fbfb3SApril Chin static ssize_t fmtbase64(Sfio_t*, char*, int);
73da2e3ebdSchin
74da2e3ebdSchin struct print
75da2e3ebdSchin {
76da2e3ebdSchin Shell_t *sh;
77da2e3ebdSchin const char *options;
78da2e3ebdSchin char raw;
79da2e3ebdSchin char echon;
80da2e3ebdSchin };
81da2e3ebdSchin
82da2e3ebdSchin static char* nullarg[] = { 0, 0 };
83da2e3ebdSchin
84da2e3ebdSchin #if !SHOPT_ECHOPRINT
B_echo(int argc,char * argv[],void * extra)85da2e3ebdSchin int B_echo(int argc, char *argv[],void *extra)
86da2e3ebdSchin {
87da2e3ebdSchin static char bsd_univ;
88da2e3ebdSchin struct print prdata;
89da2e3ebdSchin prdata.options = sh_optecho+5;
90da2e3ebdSchin prdata.raw = prdata.echon = 0;
917c2fbfb3SApril Chin prdata.sh = ((Shbltin_t*)extra)->shp;
92da2e3ebdSchin NOT_USED(argc);
93da2e3ebdSchin /* This mess is because /bin/echo on BSD is different */
94da2e3ebdSchin if(!prdata.sh->universe)
95da2e3ebdSchin {
96da2e3ebdSchin register char *universe;
97da2e3ebdSchin if(universe=astconf("UNIVERSE",0,0))
98da2e3ebdSchin bsd_univ = (strcmp(universe,"ucb")==0);
99da2e3ebdSchin prdata.sh->universe = 1;
100da2e3ebdSchin }
101da2e3ebdSchin if(!bsd_univ)
102da2e3ebdSchin return(b_print(0,argv,&prdata));
103da2e3ebdSchin prdata.options = sh_optecho;
104da2e3ebdSchin prdata.raw = 1;
105da2e3ebdSchin while(argv[1] && *argv[1]=='-')
106da2e3ebdSchin {
107da2e3ebdSchin if(strcmp(argv[1],"-n")==0)
108da2e3ebdSchin prdata.echon = 1;
109da2e3ebdSchin #if !SHOPT_ECHOE
110da2e3ebdSchin else if(strcmp(argv[1],"-e")==0)
111da2e3ebdSchin prdata.raw = 0;
112da2e3ebdSchin else if(strcmp(argv[1],"-ne")==0 || strcmp(argv[1],"-en")==0)
113da2e3ebdSchin {
114da2e3ebdSchin prdata.raw = 0;
115da2e3ebdSchin prdata.echon = 1;
116da2e3ebdSchin }
117da2e3ebdSchin #endif /* SHOPT_ECHOE */
118da2e3ebdSchin else
119da2e3ebdSchin break;
120da2e3ebdSchin argv++;
121da2e3ebdSchin }
122da2e3ebdSchin return(b_print(0,argv,&prdata));
123da2e3ebdSchin }
124da2e3ebdSchin #endif /* SHOPT_ECHOPRINT */
125da2e3ebdSchin
b_printf(int argc,char * argv[],void * extra)126da2e3ebdSchin int b_printf(int argc, char *argv[],void *extra)
127da2e3ebdSchin {
128da2e3ebdSchin struct print prdata;
129da2e3ebdSchin NOT_USED(argc);
130da2e3ebdSchin memset(&prdata,0,sizeof(prdata));
1317c2fbfb3SApril Chin prdata.sh = ((Shbltin_t*)extra)->shp;
132da2e3ebdSchin prdata.options = sh_optprintf;
133da2e3ebdSchin return(b_print(-1,argv,&prdata));
134da2e3ebdSchin }
135da2e3ebdSchin
136da2e3ebdSchin /*
137da2e3ebdSchin * argc==0 when called from echo
138da2e3ebdSchin * argc==-1 when called from printf
139da2e3ebdSchin */
140da2e3ebdSchin
b_print(int argc,char * argv[],void * extra)141da2e3ebdSchin int b_print(int argc, char *argv[], void *extra)
142da2e3ebdSchin {
143da2e3ebdSchin register Sfio_t *outfile;
144da2e3ebdSchin register int exitval=0,n, fd = 1;
1457c2fbfb3SApril Chin register Shell_t *shp = ((Shbltin_t*)extra)->shp;
146da2e3ebdSchin const char *options, *msg = e_file+4;
147da2e3ebdSchin char *format = 0;
1487c2fbfb3SApril Chin int sflag = 0, nflag=0, rflag=0, vflag=0;
149da2e3ebdSchin if(argc>0)
150da2e3ebdSchin {
151da2e3ebdSchin options = sh_optprint;
152da2e3ebdSchin nflag = rflag = 0;
153da2e3ebdSchin format = 0;
154da2e3ebdSchin }
155da2e3ebdSchin else
156da2e3ebdSchin {
157da2e3ebdSchin struct print *pp = (struct print*)extra;
158da2e3ebdSchin shp = pp->sh;
159da2e3ebdSchin options = pp->options;
160da2e3ebdSchin if(argc==0)
161da2e3ebdSchin {
162da2e3ebdSchin nflag = pp->echon;
163da2e3ebdSchin rflag = pp->raw;
164da2e3ebdSchin argv++;
165da2e3ebdSchin goto skip;
166da2e3ebdSchin }
167da2e3ebdSchin }
168da2e3ebdSchin while((n = optget(argv,options))) switch(n)
169da2e3ebdSchin {
170da2e3ebdSchin case 'n':
171da2e3ebdSchin nflag++;
172da2e3ebdSchin break;
173da2e3ebdSchin case 'p':
174da2e3ebdSchin fd = shp->coutpipe;
175da2e3ebdSchin msg = e_query;
176da2e3ebdSchin break;
177da2e3ebdSchin case 'f':
178da2e3ebdSchin format = opt_info.arg;
179da2e3ebdSchin break;
180da2e3ebdSchin case 's':
181da2e3ebdSchin /* print to history file */
1827c2fbfb3SApril Chin if(!sh_histinit((void*)shp))
183da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_history);
184da2e3ebdSchin fd = sffileno(shp->hist_ptr->histfp);
185da2e3ebdSchin sh_onstate(SH_HISTORY);
186da2e3ebdSchin sflag++;
187da2e3ebdSchin break;
188da2e3ebdSchin case 'e':
189da2e3ebdSchin rflag = 0;
190da2e3ebdSchin break;
191da2e3ebdSchin case 'r':
192da2e3ebdSchin rflag = 1;
193da2e3ebdSchin break;
194da2e3ebdSchin case 'u':
195da2e3ebdSchin fd = (int)strtol(opt_info.arg,&opt_info.arg,10);
196da2e3ebdSchin if(*opt_info.arg)
197da2e3ebdSchin fd = -1;
198da2e3ebdSchin else if(fd<0 || fd >= shp->lim.open_max)
199da2e3ebdSchin fd = -1;
200da2e3ebdSchin else if(!(sh.inuse_bits&(1<<fd)) && (sh_inuse(fd) || (shp->hist_ptr && fd==sffileno(shp->hist_ptr->histfp))))
201da2e3ebdSchin
202da2e3ebdSchin fd = -1;
203da2e3ebdSchin break;
2047c2fbfb3SApril Chin case 'v':
20534f9b3eeSRoland Mainz vflag='v';
20634f9b3eeSRoland Mainz break;
20734f9b3eeSRoland Mainz case 'C':
20834f9b3eeSRoland Mainz vflag='C';
2097c2fbfb3SApril Chin break;
210da2e3ebdSchin case ':':
211da2e3ebdSchin /* The following is for backward compatibility */
212da2e3ebdSchin #if OPT_VERSION >= 19990123
213da2e3ebdSchin if(strcmp(opt_info.name,"-R")==0)
214da2e3ebdSchin #else
215da2e3ebdSchin if(strcmp(opt_info.option,"-R")==0)
216da2e3ebdSchin #endif
217da2e3ebdSchin {
218da2e3ebdSchin rflag = 1;
219da2e3ebdSchin if(error_info.errors==0)
220da2e3ebdSchin {
221da2e3ebdSchin argv += opt_info.index+1;
222da2e3ebdSchin /* special case test for -Rn */
223da2e3ebdSchin if(strchr(argv[-1],'n'))
224da2e3ebdSchin nflag++;
225da2e3ebdSchin if(*argv && strcmp(*argv,"-n")==0)
226da2e3ebdSchin {
227da2e3ebdSchin
228da2e3ebdSchin nflag++;
229da2e3ebdSchin argv++;
230da2e3ebdSchin }
231da2e3ebdSchin goto skip2;
232da2e3ebdSchin }
233da2e3ebdSchin }
234da2e3ebdSchin else
235da2e3ebdSchin errormsg(SH_DICT,2, "%s", opt_info.arg);
236da2e3ebdSchin break;
237da2e3ebdSchin case '?':
238da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
239da2e3ebdSchin break;
240da2e3ebdSchin }
241da2e3ebdSchin argv += opt_info.index;
242da2e3ebdSchin if(error_info.errors || (argc<0 && !(format = *argv++)))
243da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
2447c2fbfb3SApril Chin if(vflag && format)
24534f9b3eeSRoland Mainz errormsg(SH_DICT,ERROR_usage(2),"-%c and -f are mutually exclusive",vflag);
246da2e3ebdSchin skip:
247da2e3ebdSchin if(format)
248da2e3ebdSchin format = genformat(format);
249da2e3ebdSchin /* handle special case of '-' operand for print */
250da2e3ebdSchin if(argc>0 && *argv && strcmp(*argv,"-")==0 && strcmp(argv[-1],"--"))
251da2e3ebdSchin argv++;
252da2e3ebdSchin skip2:
253da2e3ebdSchin if(fd < 0)
254da2e3ebdSchin {
255da2e3ebdSchin errno = EBADF;
256da2e3ebdSchin n = 0;
257da2e3ebdSchin }
258da2e3ebdSchin else if(!(n=shp->fdstatus[fd]))
2597c2fbfb3SApril Chin n = sh_iocheckfd(shp,fd);
260da2e3ebdSchin if(!(n&IOWRITE))
261da2e3ebdSchin {
262da2e3ebdSchin /* don't print error message for stdout for compatibility */
263da2e3ebdSchin if(fd==1)
264da2e3ebdSchin return(1);
265da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),msg);
266da2e3ebdSchin }
267da2e3ebdSchin if(!(outfile=shp->sftable[fd]))
268da2e3ebdSchin {
269da2e3ebdSchin sh_onstate(SH_NOTRACK);
270da2e3ebdSchin n = SF_WRITE|((n&IOREAD)?SF_READ:0);
271da2e3ebdSchin shp->sftable[fd] = outfile = sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fd,n);
272da2e3ebdSchin sh_offstate(SH_NOTRACK);
273da2e3ebdSchin sfpool(outfile,shp->outpool,SF_WRITE);
274da2e3ebdSchin }
275da2e3ebdSchin /* turn off share to guarantee atomic writes for printf */
276da2e3ebdSchin n = sfset(outfile,SF_SHARE|SF_PUBLIC,0);
277da2e3ebdSchin if(format)
278da2e3ebdSchin {
279da2e3ebdSchin /* printf style print */
280da2e3ebdSchin Sfio_t *pool;
281da2e3ebdSchin struct printf pdata;
282da2e3ebdSchin memset(&pdata, 0, sizeof(pdata));
283da2e3ebdSchin pdata.sh = shp;
284da2e3ebdSchin pdata.hdr.version = SFIO_VERSION;
285da2e3ebdSchin pdata.hdr.extf = extend;
286da2e3ebdSchin pdata.nextarg = argv;
287da2e3ebdSchin sh_offstate(SH_STOPOK);
288da2e3ebdSchin pool=sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE);
289da2e3ebdSchin do
290da2e3ebdSchin {
291da2e3ebdSchin if(shp->trapnote&SH_SIGSET)
292da2e3ebdSchin break;
293da2e3ebdSchin pdata.hdr.form = format;
294da2e3ebdSchin sfprintf(outfile,"%!",&pdata);
295da2e3ebdSchin } while(*pdata.nextarg && pdata.nextarg!=argv);
296da2e3ebdSchin if(pdata.nextarg == nullarg && pdata.argsize>0)
297da2e3ebdSchin sfwrite(outfile,stakptr(staktell()),pdata.argsize);
29834f9b3eeSRoland Mainz if(sffileno(outfile)!=sffileno(sfstderr))
29934f9b3eeSRoland Mainz sfsync(outfile);
300da2e3ebdSchin sfpool(sfstderr,pool,SF_WRITE);
301da2e3ebdSchin exitval = pdata.err;
302da2e3ebdSchin }
3037c2fbfb3SApril Chin else if(vflag)
3047c2fbfb3SApril Chin {
3057c2fbfb3SApril Chin while(*argv)
30634f9b3eeSRoland Mainz {
30734f9b3eeSRoland Mainz fmtbase64(outfile,*argv++,vflag=='C');
30834f9b3eeSRoland Mainz if(!nflag)
30934f9b3eeSRoland Mainz sfputc(outfile,'\n');
31034f9b3eeSRoland Mainz }
3117c2fbfb3SApril Chin }
312da2e3ebdSchin else
313da2e3ebdSchin {
314da2e3ebdSchin /* echo style print */
3157c2fbfb3SApril Chin if(nflag && !argv[0])
3167c2fbfb3SApril Chin sfsync((Sfio_t*)0);
3177c2fbfb3SApril Chin else if(sh_echolist(outfile,rflag,argv) && !nflag)
318da2e3ebdSchin sfputc(outfile,'\n');
319da2e3ebdSchin }
320da2e3ebdSchin if(sflag)
321da2e3ebdSchin {
322da2e3ebdSchin hist_flush(shp->hist_ptr);
323da2e3ebdSchin sh_offstate(SH_HISTORY);
324da2e3ebdSchin }
325da2e3ebdSchin else if(n&SF_SHARE)
326da2e3ebdSchin {
327da2e3ebdSchin sfset(outfile,SF_SHARE|SF_PUBLIC,1);
328da2e3ebdSchin sfsync(outfile);
329da2e3ebdSchin }
330da2e3ebdSchin return(exitval);
331da2e3ebdSchin }
332da2e3ebdSchin
333da2e3ebdSchin /*
334da2e3ebdSchin * echo the argument list onto <outfile>
335da2e3ebdSchin * if <raw> is non-zero then \ is not a special character.
336da2e3ebdSchin * returns 0 for \c otherwise 1.
337da2e3ebdSchin */
338da2e3ebdSchin
sh_echolist(Sfio_t * outfile,int raw,char * argv[])339da2e3ebdSchin int sh_echolist(Sfio_t *outfile, int raw, char *argv[])
340da2e3ebdSchin {
341da2e3ebdSchin register char *cp;
342da2e3ebdSchin register int n;
343da2e3ebdSchin struct printf pdata;
344da2e3ebdSchin pdata.cescape = 0;
345da2e3ebdSchin pdata.err = 0;
346da2e3ebdSchin while(!pdata.cescape && (cp= *argv++))
347da2e3ebdSchin {
348da2e3ebdSchin if(!raw && (n=fmtvecho(cp,&pdata))>=0)
349da2e3ebdSchin {
350da2e3ebdSchin if(n)
351da2e3ebdSchin sfwrite(outfile,stakptr(staktell()),n);
352da2e3ebdSchin }
353da2e3ebdSchin else
354da2e3ebdSchin sfputr(outfile,cp,-1);
355da2e3ebdSchin if(*argv)
356da2e3ebdSchin sfputc(outfile,' ');
357da2e3ebdSchin sh_sigcheck();
358da2e3ebdSchin }
359da2e3ebdSchin return(!pdata.cescape);
360da2e3ebdSchin }
361da2e3ebdSchin
362da2e3ebdSchin /*
363da2e3ebdSchin * modified version of stresc for generating formats
364da2e3ebdSchin */
strformat(char * s)365da2e3ebdSchin static char strformat(char *s)
366da2e3ebdSchin {
367da2e3ebdSchin register char* t;
368da2e3ebdSchin register int c;
369da2e3ebdSchin char* b;
370da2e3ebdSchin char* p;
371da2e3ebdSchin
372da2e3ebdSchin b = t = s;
373da2e3ebdSchin for (;;)
374da2e3ebdSchin {
375da2e3ebdSchin switch (c = *s++)
376da2e3ebdSchin {
377da2e3ebdSchin case '\\':
378da2e3ebdSchin if(*s==0)
379da2e3ebdSchin break;
380da2e3ebdSchin c = chresc(s - 1, &p);
381da2e3ebdSchin s = p;
382da2e3ebdSchin #if SHOPT_MULTIBYTE
383da2e3ebdSchin if(c>UCHAR_MAX && mbwide())
384da2e3ebdSchin {
385da2e3ebdSchin t += wctomb(t, c);
386da2e3ebdSchin continue;
387da2e3ebdSchin }
388da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
389da2e3ebdSchin if(c=='%')
390da2e3ebdSchin *t++ = '%';
391da2e3ebdSchin else if(c==0)
392da2e3ebdSchin {
393da2e3ebdSchin *t++ = '%';
394da2e3ebdSchin c = 'Z';
395da2e3ebdSchin }
396da2e3ebdSchin break;
397da2e3ebdSchin case 0:
398da2e3ebdSchin *t = 0;
399da2e3ebdSchin return(t - b);
400da2e3ebdSchin }
401da2e3ebdSchin *t++ = c;
402da2e3ebdSchin }
403da2e3ebdSchin }
404da2e3ebdSchin
405da2e3ebdSchin
genformat(char * format)406da2e3ebdSchin static char *genformat(char *format)
407da2e3ebdSchin {
408da2e3ebdSchin register char *fp;
409da2e3ebdSchin stakseek(0);
410da2e3ebdSchin stakputs(preformat);
411da2e3ebdSchin stakputs(format);
412da2e3ebdSchin fp = (char*)stakfreeze(1);
413da2e3ebdSchin strformat(fp+sizeof(preformat)-1);
414da2e3ebdSchin return(fp);
415da2e3ebdSchin }
416da2e3ebdSchin
fmthtml(const char * string)417da2e3ebdSchin static char *fmthtml(const char *string)
418da2e3ebdSchin {
419da2e3ebdSchin register const char *cp = string;
420da2e3ebdSchin register int c, offset = staktell();
421da2e3ebdSchin while(c= *(unsigned char*)cp++)
422da2e3ebdSchin {
423da2e3ebdSchin #if SHOPT_MULTIBYTE
424da2e3ebdSchin register int s;
425da2e3ebdSchin if((s=mbsize(cp-1)) > 1)
426da2e3ebdSchin {
427da2e3ebdSchin cp += (s-1);
428da2e3ebdSchin continue;
429da2e3ebdSchin }
430da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
431da2e3ebdSchin if(c=='<')
432da2e3ebdSchin stakputs("<");
433da2e3ebdSchin else if(c=='>')
434da2e3ebdSchin stakputs(">");
435da2e3ebdSchin else if(c=='&')
436da2e3ebdSchin stakputs("&");
437da2e3ebdSchin else if(c=='"')
438da2e3ebdSchin stakputs(""");
439da2e3ebdSchin else if(c=='\'')
440da2e3ebdSchin stakputs("'");
441da2e3ebdSchin else if(c==' ')
442da2e3ebdSchin stakputs(" ");
443da2e3ebdSchin else if(!isprint(c) && c!='\n' && c!='\r')
444da2e3ebdSchin sfprintf(stkstd,"&#%X;",CCMAPC(c,CC_NATIVE,CC_ASCII));
445da2e3ebdSchin else
446da2e3ebdSchin stakputc(c);
447da2e3ebdSchin }
448da2e3ebdSchin stakputc(0);
449da2e3ebdSchin return(stakptr(offset));
450da2e3ebdSchin }
451da2e3ebdSchin
4527c2fbfb3SApril Chin #if 1
fmtbase64(Sfio_t * iop,char * string,int alt)4537c2fbfb3SApril Chin static ssize_t fmtbase64(Sfio_t *iop, char *string, int alt)
4547c2fbfb3SApril Chin #else
4557c2fbfb3SApril Chin static void *fmtbase64(char *string, ssize_t *sz, int alt)
4567c2fbfb3SApril Chin #endif
457da2e3ebdSchin {
458da2e3ebdSchin char *cp;
459da2e3ebdSchin Sfdouble_t d;
4607c2fbfb3SApril Chin ssize_t size;
461da2e3ebdSchin Namval_t *np = nv_open(string, NiL, NV_VARNAME|NV_NOASSIGN|NV_NOADD);
462da2e3ebdSchin static union types_t number;
4637c2fbfb3SApril Chin if(!np || nv_isnull(np))
4647c2fbfb3SApril Chin {
4657c2fbfb3SApril Chin if(sh_isoption(SH_NOUNSET))
4667c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_exit(1),e_notset,string);
4677c2fbfb3SApril Chin return(0);
4687c2fbfb3SApril Chin }
469da2e3ebdSchin if(nv_isattr(np,NV_INTEGER))
470da2e3ebdSchin {
471da2e3ebdSchin d = nv_getnum(np);
472da2e3ebdSchin if(nv_isattr(np,NV_DOUBLE))
473da2e3ebdSchin {
474da2e3ebdSchin if(nv_isattr(np,NV_LONG))
475da2e3ebdSchin {
476da2e3ebdSchin size = sizeof(Sfdouble_t);
477da2e3ebdSchin number.ld = d;
478da2e3ebdSchin }
479da2e3ebdSchin else if(nv_isattr(np,NV_SHORT))
480da2e3ebdSchin {
481da2e3ebdSchin size = sizeof(float);
482da2e3ebdSchin number.f = (float)d;
483da2e3ebdSchin }
484da2e3ebdSchin else
485da2e3ebdSchin {
486da2e3ebdSchin size = sizeof(double);
487da2e3ebdSchin number.d = (double)d;
488da2e3ebdSchin }
489da2e3ebdSchin }
490da2e3ebdSchin else
491da2e3ebdSchin {
492da2e3ebdSchin if(nv_isattr(np,NV_LONG))
493da2e3ebdSchin {
494da2e3ebdSchin size = sizeof(Sflong_t);
495da2e3ebdSchin number.ll = (Sflong_t)d;
496da2e3ebdSchin }
497da2e3ebdSchin else if(nv_isattr(np,NV_SHORT))
498da2e3ebdSchin {
499da2e3ebdSchin size = sizeof(short);
500da2e3ebdSchin number.h = (short)d;
501da2e3ebdSchin }
502da2e3ebdSchin else
503da2e3ebdSchin {
504da2e3ebdSchin size = sizeof(short);
505da2e3ebdSchin number.i = (int)d;
506da2e3ebdSchin }
507da2e3ebdSchin }
5087c2fbfb3SApril Chin #if 1
5097c2fbfb3SApril Chin return(sfwrite(iop, (void*)&number, size));
5107c2fbfb3SApril Chin #else
511da2e3ebdSchin if(sz)
512da2e3ebdSchin *sz = size;
513da2e3ebdSchin return((void*)&number);
5147c2fbfb3SApril Chin #endif
515da2e3ebdSchin }
516da2e3ebdSchin if(nv_isattr(np,NV_BINARY))
5177c2fbfb3SApril Chin #if 1
5187c2fbfb3SApril Chin {
5197c2fbfb3SApril Chin Namfun_t *fp;
5207c2fbfb3SApril Chin for(fp=np->nvfun; fp;fp=fp->next)
5217c2fbfb3SApril Chin {
5227c2fbfb3SApril Chin if(fp->disc && fp->disc->writef)
5237c2fbfb3SApril Chin break;
5247c2fbfb3SApril Chin }
5257c2fbfb3SApril Chin if(fp)
5267c2fbfb3SApril Chin return (*fp->disc->writef)(np, iop, 0, fp);
5277c2fbfb3SApril Chin else
5287c2fbfb3SApril Chin {
5297c2fbfb3SApril Chin int n = nv_size(np);
53034f9b3eeSRoland Mainz if(nv_isarray(np))
53134f9b3eeSRoland Mainz {
53234f9b3eeSRoland Mainz nv_onattr(np,NV_RAW);
53334f9b3eeSRoland Mainz cp = nv_getval(np);
53434f9b3eeSRoland Mainz nv_offattr(np,NV_RAW);
53534f9b3eeSRoland Mainz }
53634f9b3eeSRoland Mainz else
5377c2fbfb3SApril Chin cp = (char*)np->nvalue.cp;
5387c2fbfb3SApril Chin if((size = n)==0)
5397c2fbfb3SApril Chin size = strlen(cp);
5407c2fbfb3SApril Chin size = sfwrite(iop, cp, size);
5417c2fbfb3SApril Chin return(n?n:size);
5427c2fbfb3SApril Chin }
5437c2fbfb3SApril Chin }
5447c2fbfb3SApril Chin else if(nv_isarray(np) && nv_arrayptr(np))
5457c2fbfb3SApril Chin {
5467c2fbfb3SApril Chin nv_outnode(np,iop,(alt?-1:0),0);
5477c2fbfb3SApril Chin sfputc(iop,')');
5487c2fbfb3SApril Chin return(sftell(iop));
5497c2fbfb3SApril Chin }
5507c2fbfb3SApril Chin else
5517c2fbfb3SApril Chin {
5527c2fbfb3SApril Chin if(alt && nv_isvtree(np))
5537c2fbfb3SApril Chin nv_onattr(np,NV_EXPORT);
5547c2fbfb3SApril Chin if(!(cp = nv_getval(np)))
5557c2fbfb3SApril Chin return(0);
5567c2fbfb3SApril Chin size = strlen(cp);
5577c2fbfb3SApril Chin return(sfwrite(iop,cp,size));
5587c2fbfb3SApril Chin }
5597c2fbfb3SApril Chin #else
560da2e3ebdSchin nv_onattr(np,NV_RAW);
561da2e3ebdSchin cp = nv_getval(np);
562da2e3ebdSchin if(nv_isattr(np,NV_BINARY))
563da2e3ebdSchin nv_offattr(np,NV_RAW);
564da2e3ebdSchin if((size = nv_size(np))==0)
565da2e3ebdSchin size = strlen(cp);
566da2e3ebdSchin if(sz)
567da2e3ebdSchin *sz = size;
568da2e3ebdSchin return((void*)cp);
5697c2fbfb3SApril Chin #endif
5707c2fbfb3SApril Chin }
5717c2fbfb3SApril Chin
varname(const char * str,int n)5727c2fbfb3SApril Chin static int varname(const char *str, int n)
5737c2fbfb3SApril Chin {
5747c2fbfb3SApril Chin register int c,dot=1,len=1;
5757c2fbfb3SApril Chin if(n < 0)
5767c2fbfb3SApril Chin {
5777c2fbfb3SApril Chin if(*str=='.')
5787c2fbfb3SApril Chin str++;
5797c2fbfb3SApril Chin n = strlen(str);
5807c2fbfb3SApril Chin }
5817c2fbfb3SApril Chin for(;n > 0; n-=len)
5827c2fbfb3SApril Chin {
5837c2fbfb3SApril Chin #ifdef SHOPT_MULTIBYTE
5847c2fbfb3SApril Chin len = mbsize(str);
5857c2fbfb3SApril Chin c = mbchar(str);
5867c2fbfb3SApril Chin #else
5877c2fbfb3SApril Chin c = *(unsigned char*)str++;
5887c2fbfb3SApril Chin #endif
5897c2fbfb3SApril Chin if(dot && !(isalpha(c)||c=='_'))
5907c2fbfb3SApril Chin break;
5917c2fbfb3SApril Chin else if(dot==0 && !(isalnum(c) || c=='_' || c == '.'))
5927c2fbfb3SApril Chin break;
5937c2fbfb3SApril Chin dot = (c=='.');
5947c2fbfb3SApril Chin }
5957c2fbfb3SApril Chin return(n==0);
596da2e3ebdSchin }
597da2e3ebdSchin
extend(Sfio_t * sp,void * v,Sffmt_t * fe)598da2e3ebdSchin static int extend(Sfio_t* sp, void* v, Sffmt_t* fe)
599da2e3ebdSchin {
600da2e3ebdSchin char* lastchar = "";
601da2e3ebdSchin register int neg = 0;
602da2e3ebdSchin Sfdouble_t d;
603da2e3ebdSchin Sfdouble_t longmin = LDBL_LLONG_MIN;
604da2e3ebdSchin Sfdouble_t longmax = LDBL_LLONG_MAX;
605da2e3ebdSchin int format = fe->fmt;
606da2e3ebdSchin int n;
607da2e3ebdSchin int fold = fe->base;
608da2e3ebdSchin union types_t* value = (union types_t*)v;
609da2e3ebdSchin struct printf* pp = (struct printf*)fe;
610da2e3ebdSchin register char* argp = *pp->nextarg;
61134f9b3eeSRoland Mainz char* w;
612da2e3ebdSchin
6137c2fbfb3SApril Chin if(fe->n_str>0 && varname(fe->t_str,fe->n_str) && (!argp || varname(argp,-1)))
6147c2fbfb3SApril Chin {
6157c2fbfb3SApril Chin if(argp)
6167c2fbfb3SApril Chin pp->lastarg = argp;
6177c2fbfb3SApril Chin else
6187c2fbfb3SApril Chin argp = pp->lastarg;
6197c2fbfb3SApril Chin if(argp)
6207c2fbfb3SApril Chin {
6217c2fbfb3SApril Chin sfprintf(pp->sh->strbuf,"%s.%.*s%c",argp,fe->n_str,fe->t_str,0);
6227c2fbfb3SApril Chin argp = sfstruse(pp->sh->strbuf);
6237c2fbfb3SApril Chin }
6247c2fbfb3SApril Chin }
6257c2fbfb3SApril Chin else
6267c2fbfb3SApril Chin pp->lastarg = 0;
627da2e3ebdSchin fe->flags |= SFFMT_VALUE;
628da2e3ebdSchin if(!argp || format=='Z')
629da2e3ebdSchin {
630da2e3ebdSchin switch(format)
631da2e3ebdSchin {
632da2e3ebdSchin case 'c':
633da2e3ebdSchin value->c = 0;
634da2e3ebdSchin fe->flags &= ~SFFMT_LONG;
635da2e3ebdSchin break;
636da2e3ebdSchin case 'q':
637da2e3ebdSchin format = 's';
638da2e3ebdSchin /* FALL THROUGH */
639da2e3ebdSchin case 's':
640da2e3ebdSchin case 'H':
641da2e3ebdSchin case 'B':
642da2e3ebdSchin case 'P':
643da2e3ebdSchin case 'R':
644da2e3ebdSchin case 'Z':
645da2e3ebdSchin case 'b':
646da2e3ebdSchin fe->fmt = 's';
647da2e3ebdSchin fe->size = -1;
648da2e3ebdSchin fe->base = -1;
649da2e3ebdSchin value->s = "";
650da2e3ebdSchin fe->flags &= ~SFFMT_LONG;
651da2e3ebdSchin break;
652da2e3ebdSchin case 'a':
653da2e3ebdSchin case 'e':
654da2e3ebdSchin case 'f':
655da2e3ebdSchin case 'g':
656da2e3ebdSchin case 'A':
657da2e3ebdSchin case 'E':
658da2e3ebdSchin case 'F':
659da2e3ebdSchin case 'G':
660da2e3ebdSchin if(SFFMT_LDOUBLE)
661da2e3ebdSchin value->ld = 0.;
662da2e3ebdSchin else
663da2e3ebdSchin value->d = 0.;
664da2e3ebdSchin break;
665da2e3ebdSchin case 'n':
666da2e3ebdSchin value->ip = &pp->intvar;
667da2e3ebdSchin break;
668da2e3ebdSchin case 'Q':
669da2e3ebdSchin value->ll = 0;
670da2e3ebdSchin break;
671da2e3ebdSchin case 'T':
672da2e3ebdSchin fe->fmt = 'd';
673da2e3ebdSchin value->ll = tmxgettime();
674da2e3ebdSchin break;
675da2e3ebdSchin default:
676da2e3ebdSchin if(!strchr("DdXxoUu",format))
677da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_formspec,format);
678da2e3ebdSchin fe->fmt = 'd';
679da2e3ebdSchin value->ll = 0;
680da2e3ebdSchin break;
681da2e3ebdSchin }
682da2e3ebdSchin }
683da2e3ebdSchin else
684da2e3ebdSchin {
685da2e3ebdSchin switch(format)
686da2e3ebdSchin {
687da2e3ebdSchin case 'p':
688da2e3ebdSchin value->p = (char**)strtol(argp,&lastchar,10);
689da2e3ebdSchin break;
690da2e3ebdSchin case 'n':
691da2e3ebdSchin {
692da2e3ebdSchin Namval_t *np;
693da2e3ebdSchin np = nv_open(argp,sh.var_tree,NV_VARNAME|NV_NOASSIGN|NV_NOARRAY);
694da2e3ebdSchin nv_unset(np);
695da2e3ebdSchin nv_onattr(np,NV_INTEGER);
696da2e3ebdSchin if (np->nvalue.lp = new_of(int32_t,0))
697da2e3ebdSchin *np->nvalue.lp = 0;
698da2e3ebdSchin nv_setsize(np,10);
699da2e3ebdSchin if(sizeof(int)==sizeof(int32_t))
700da2e3ebdSchin value->ip = (int*)np->nvalue.lp;
701da2e3ebdSchin else
702da2e3ebdSchin {
703da2e3ebdSchin int32_t sl = 1;
704da2e3ebdSchin value->ip = (int*)(((char*)np->nvalue.lp) + (*((char*)&sl) ? 0 : sizeof(int)));
705da2e3ebdSchin }
706da2e3ebdSchin nv_close(np);
707da2e3ebdSchin break;
708da2e3ebdSchin }
709da2e3ebdSchin case 'q':
710da2e3ebdSchin case 'b':
711da2e3ebdSchin case 's':
712da2e3ebdSchin case 'B':
713da2e3ebdSchin case 'H':
714da2e3ebdSchin case 'P':
715da2e3ebdSchin case 'R':
716da2e3ebdSchin fe->fmt = 's';
717da2e3ebdSchin fe->size = -1;
718da2e3ebdSchin if(format=='s' && fe->base>=0)
719da2e3ebdSchin {
720da2e3ebdSchin value->p = pp->nextarg;
721da2e3ebdSchin pp->nextarg = nullarg;
722da2e3ebdSchin }
723da2e3ebdSchin else
724da2e3ebdSchin {
725da2e3ebdSchin fe->base = -1;
726da2e3ebdSchin value->s = argp;
727da2e3ebdSchin }
728da2e3ebdSchin fe->flags &= ~SFFMT_LONG;
729da2e3ebdSchin break;
730da2e3ebdSchin case 'c':
73134f9b3eeSRoland Mainz if(mbwide() && (n = mbsize(argp)) > 1)
73234f9b3eeSRoland Mainz {
73334f9b3eeSRoland Mainz fe->fmt = 's';
73434f9b3eeSRoland Mainz fe->size = n;
73534f9b3eeSRoland Mainz value->s = argp;
73634f9b3eeSRoland Mainz }
73734f9b3eeSRoland Mainz else if(fe->base >=0)
738da2e3ebdSchin value->s = argp;
739da2e3ebdSchin else
740da2e3ebdSchin value->c = *argp;
741da2e3ebdSchin fe->flags &= ~SFFMT_LONG;
742da2e3ebdSchin break;
743da2e3ebdSchin case 'o':
744da2e3ebdSchin case 'x':
745da2e3ebdSchin case 'X':
746da2e3ebdSchin case 'u':
747da2e3ebdSchin case 'U':
748da2e3ebdSchin longmax = LDBL_ULLONG_MAX;
749*3ce7283dSToomas Soome case '.':
750da2e3ebdSchin if(fe->size==2 && strchr("bcsqHPRQTZ",*fe->form))
751da2e3ebdSchin {
752da2e3ebdSchin value->ll = ((unsigned char*)argp)[0];
753da2e3ebdSchin break;
754da2e3ebdSchin }
755da2e3ebdSchin case 'd':
756*3ce7283dSToomas Soome case 'D':
757da2e3ebdSchin case 'i':
758da2e3ebdSchin switch(*argp)
759da2e3ebdSchin {
760da2e3ebdSchin case '\'':
761da2e3ebdSchin case '"':
762da2e3ebdSchin w = argp + 1;
763da2e3ebdSchin if(mbwide() && mbsize(w) > 1)
76434f9b3eeSRoland Mainz value->ll = mbchar(w);
76534f9b3eeSRoland Mainz else
76634f9b3eeSRoland Mainz value->ll = *(unsigned char*)w++;
76734f9b3eeSRoland Mainz if(w[0] && (w[0] != argp[0] || w[1]))
76834f9b3eeSRoland Mainz {
76934f9b3eeSRoland Mainz errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp);
7707c2fbfb3SApril Chin pp->err = 1;
7717c2fbfb3SApril Chin }
7727c2fbfb3SApril Chin break;
7737c2fbfb3SApril Chin default:
774da2e3ebdSchin d = sh_strnum(argp,&lastchar,0);
775da2e3ebdSchin if(d<longmin)
776da2e3ebdSchin {
777da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);
778da2e3ebdSchin pp->err = 1;
779da2e3ebdSchin d = longmin;
780da2e3ebdSchin }
781da2e3ebdSchin else if(d>longmax)
782da2e3ebdSchin {
783da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);
784da2e3ebdSchin pp->err = 1;
785da2e3ebdSchin d = longmax;
786da2e3ebdSchin }
787da2e3ebdSchin value->ll = (Sflong_t)d;
788da2e3ebdSchin if(lastchar == *pp->nextarg)
789da2e3ebdSchin {
790da2e3ebdSchin value->ll = *argp;
791da2e3ebdSchin lastchar = "";
792da2e3ebdSchin }
793da2e3ebdSchin break;
794da2e3ebdSchin }
795da2e3ebdSchin if(neg)
796da2e3ebdSchin value->ll = -value->ll;
797da2e3ebdSchin fe->size = sizeof(value->ll);
798da2e3ebdSchin break;
799da2e3ebdSchin case 'a':
800da2e3ebdSchin case 'e':
801da2e3ebdSchin case 'f':
802da2e3ebdSchin case 'g':
803da2e3ebdSchin case 'A':
804da2e3ebdSchin case 'E':
805da2e3ebdSchin case 'F':
806da2e3ebdSchin case 'G':
807da2e3ebdSchin d = sh_strnum(*pp->nextarg,&lastchar,0);
808da2e3ebdSchin switch(*argp)
809da2e3ebdSchin {
8107c2fbfb3SApril Chin case '\'':
8117c2fbfb3SApril Chin case '"':
8127c2fbfb3SApril Chin d = ((unsigned char*)argp)[1];
8137c2fbfb3SApril Chin if(argp[2] && (argp[2] != argp[0] || argp[3]))
8147c2fbfb3SApril Chin {
8157c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp);
8167c2fbfb3SApril Chin pp->err = 1;
8177c2fbfb3SApril Chin }
8187c2fbfb3SApril Chin break;
8197c2fbfb3SApril Chin default:
8207c2fbfb3SApril Chin d = sh_strnum(*pp->nextarg,&lastchar,0);
8217c2fbfb3SApril Chin break;
8227c2fbfb3SApril Chin }
8237c2fbfb3SApril Chin if(SFFMT_LDOUBLE)
8247c2fbfb3SApril Chin {
825da2e3ebdSchin value->ld = d;
826da2e3ebdSchin fe->size = sizeof(value->ld);
827da2e3ebdSchin }
828da2e3ebdSchin else
829da2e3ebdSchin {
830da2e3ebdSchin value->d = d;
831da2e3ebdSchin fe->size = sizeof(value->d);
832da2e3ebdSchin }
833da2e3ebdSchin break;
834da2e3ebdSchin case 'Q':
835da2e3ebdSchin value->ll = (Sflong_t)strelapsed(*pp->nextarg,&lastchar,1);
836da2e3ebdSchin break;
837da2e3ebdSchin case 'T':
838da2e3ebdSchin value->ll = (Sflong_t)tmxdate(*pp->nextarg,&lastchar,TMX_NOW);
839da2e3ebdSchin break;
840da2e3ebdSchin default:
841da2e3ebdSchin value->ll = 0;
842da2e3ebdSchin fe->fmt = 'd';
843da2e3ebdSchin fe->size = sizeof(value->ll);
844da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_formspec,format);
845da2e3ebdSchin break;
846da2e3ebdSchin }
847da2e3ebdSchin if (format == '.')
848da2e3ebdSchin value->i = value->ll;
849da2e3ebdSchin if(*lastchar)
850da2e3ebdSchin {
851da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_argtype,format);
852da2e3ebdSchin pp->err = 1;
853da2e3ebdSchin }
854da2e3ebdSchin pp->nextarg++;
855da2e3ebdSchin }
856da2e3ebdSchin switch(format)
857da2e3ebdSchin {
858da2e3ebdSchin case 'Z':
859da2e3ebdSchin fe->fmt = 'c';
860da2e3ebdSchin fe->base = -1;
861da2e3ebdSchin value->c = 0;
862da2e3ebdSchin break;
863da2e3ebdSchin case 'b':
864da2e3ebdSchin if((n=fmtvecho(value->s,pp))>=0)
865da2e3ebdSchin {
866da2e3ebdSchin if(pp->nextarg == nullarg)
867da2e3ebdSchin {
868da2e3ebdSchin pp->argsize = n;
869da2e3ebdSchin return -1;
870da2e3ebdSchin }
871da2e3ebdSchin value->s = stakptr(staktell());
872da2e3ebdSchin }
873da2e3ebdSchin break;
874da2e3ebdSchin case 'B':
875da2e3ebdSchin if(!sh.strbuf2)
876da2e3ebdSchin sh.strbuf2 = sfstropen();
8777c2fbfb3SApril Chin fe->size = fmtbase64(sh.strbuf2,value->s, fe->flags&SFFMT_ALTER);
8787c2fbfb3SApril Chin value->s = sfstruse(sh.strbuf2);
8797c2fbfb3SApril Chin fe->flags |= SFFMT_SHORT;
8807c2fbfb3SApril Chin break;
8817c2fbfb3SApril Chin case 'H':
882da2e3ebdSchin value->s = fmthtml(value->s);
883da2e3ebdSchin break;
884da2e3ebdSchin case 'q':
885da2e3ebdSchin value->s = sh_fmtqf(value->s, !!(fe->flags & SFFMT_ALTER), fold);
886da2e3ebdSchin break;
887da2e3ebdSchin case 'P':
888da2e3ebdSchin {
889da2e3ebdSchin char *s = fmtmatch(value->s);
890da2e3ebdSchin if(!s || *s==0)
891da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s);
892da2e3ebdSchin value->s = s;
893da2e3ebdSchin break;
894da2e3ebdSchin }
895da2e3ebdSchin case 'R':
896da2e3ebdSchin value->s = fmtre(value->s);
897da2e3ebdSchin if(*value->s==0)
898da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s);
899da2e3ebdSchin break;
900da2e3ebdSchin case 'Q':
901da2e3ebdSchin if (fe->n_str>0)
902da2e3ebdSchin {
903da2e3ebdSchin fe->fmt = 'd';
904da2e3ebdSchin fe->size = sizeof(value->ll);
905da2e3ebdSchin }
906da2e3ebdSchin else
907da2e3ebdSchin {
908da2e3ebdSchin value->s = fmtelapsed(value->ll, 1);
909da2e3ebdSchin fe->fmt = 's';
910da2e3ebdSchin fe->size = -1;
911da2e3ebdSchin }
912da2e3ebdSchin break;
913da2e3ebdSchin case 'T':
914da2e3ebdSchin if(fe->n_str>0)
915da2e3ebdSchin {
916da2e3ebdSchin n = fe->t_str[fe->n_str];
917da2e3ebdSchin fe->t_str[fe->n_str] = 0;
918da2e3ebdSchin value->s = fmttmx(fe->t_str, value->ll);
919da2e3ebdSchin fe->t_str[fe->n_str] = n;
920da2e3ebdSchin }
921da2e3ebdSchin else value->s = fmttmx(NIL(char*), value->ll);
922da2e3ebdSchin fe->fmt = 's';
923da2e3ebdSchin fe->size = -1;
924da2e3ebdSchin break;
925da2e3ebdSchin }
926da2e3ebdSchin return 0;
927da2e3ebdSchin }
928da2e3ebdSchin
929da2e3ebdSchin /*
930da2e3ebdSchin * construct System V echo string out of <cp>
931da2e3ebdSchin * If there are not escape sequences, returns -1
932da2e3ebdSchin * Otherwise, puts null terminated result on stack, but doesn't freeze it
933da2e3ebdSchin * returns length of output.
934da2e3ebdSchin */
935da2e3ebdSchin
fmtvecho(const char * string,struct printf * pp)936da2e3ebdSchin static int fmtvecho(const char *string, struct printf *pp)
937da2e3ebdSchin {
938da2e3ebdSchin register const char *cp = string, *cpmax;
939da2e3ebdSchin register int c;
940da2e3ebdSchin register int offset = staktell();
941da2e3ebdSchin #if SHOPT_MULTIBYTE
942da2e3ebdSchin int chlen;
943da2e3ebdSchin if(mbwide())
944da2e3ebdSchin {
945da2e3ebdSchin while(1)
946da2e3ebdSchin {
947da2e3ebdSchin if ((chlen = mbsize(cp)) > 1)
948da2e3ebdSchin /* Skip over multibyte characters */
949da2e3ebdSchin cp += chlen;
950da2e3ebdSchin else if((c= *cp++)==0 || c == '\\')
951da2e3ebdSchin break;
952da2e3ebdSchin }
953da2e3ebdSchin }
954da2e3ebdSchin else
955da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
956da2e3ebdSchin while((c= *cp++) && (c!='\\'));
957da2e3ebdSchin if(c==0)
958da2e3ebdSchin return(-1);
959da2e3ebdSchin c = --cp - string;
960da2e3ebdSchin if(c>0)
961da2e3ebdSchin stakwrite((void*)string,c);
962da2e3ebdSchin for(; c= *cp; cp++)
963da2e3ebdSchin {
964da2e3ebdSchin #if SHOPT_MULTIBYTE
965da2e3ebdSchin if (mbwide() && ((chlen = mbsize(cp)) > 1))
966da2e3ebdSchin {
967da2e3ebdSchin stakwrite(cp,chlen);
968da2e3ebdSchin cp += (chlen-1);
969da2e3ebdSchin continue;
970da2e3ebdSchin }
971da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
972da2e3ebdSchin if( c=='\\') switch(*++cp)
973da2e3ebdSchin {
974da2e3ebdSchin case 'E':
975da2e3ebdSchin c = ('a'==97?'\033':39); /* ASCII/EBCDIC */
976da2e3ebdSchin break;
977da2e3ebdSchin case 'a':
978da2e3ebdSchin c = '\a';
979da2e3ebdSchin break;
980da2e3ebdSchin case 'b':
981da2e3ebdSchin c = '\b';
982da2e3ebdSchin break;
983da2e3ebdSchin case 'c':
984da2e3ebdSchin pp->cescape++;
985da2e3ebdSchin pp->nextarg = nullarg;
986da2e3ebdSchin goto done;
987da2e3ebdSchin case 'f':
988da2e3ebdSchin c = '\f';
989da2e3ebdSchin break;
990da2e3ebdSchin case 'n':
991da2e3ebdSchin c = '\n';
992da2e3ebdSchin break;
993da2e3ebdSchin case 'r':
994da2e3ebdSchin c = '\r';
995da2e3ebdSchin break;
996da2e3ebdSchin case 'v':
997da2e3ebdSchin c = '\v';
998da2e3ebdSchin break;
999da2e3ebdSchin case 't':
1000da2e3ebdSchin c = '\t';
1001da2e3ebdSchin break;
1002da2e3ebdSchin case '\\':
1003da2e3ebdSchin c = '\\';
1004da2e3ebdSchin break;
1005da2e3ebdSchin case '0':
1006da2e3ebdSchin c = 0;
1007da2e3ebdSchin cpmax = cp + 4;
1008da2e3ebdSchin while(++cp<cpmax && *cp>='0' && *cp<='7')
1009da2e3ebdSchin {
1010da2e3ebdSchin c <<= 3;
1011da2e3ebdSchin c |= (*cp-'0');
1012da2e3ebdSchin }
1013da2e3ebdSchin default:
1014da2e3ebdSchin cp--;
1015*3ce7283dSToomas Soome }
1016da2e3ebdSchin stakputc(c);
1017da2e3ebdSchin }
1018da2e3ebdSchin done:
1019da2e3ebdSchin c = staktell()-offset;
1020da2e3ebdSchin stakputc(0);
1021da2e3ebdSchin stakseek(offset);
1022da2e3ebdSchin return(c);
1023da2e3ebdSchin }
1024da2e3ebdSchin