1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * echo [arg...]
23 * print [-nrps] [-f format] [-u filenum] [arg...]
24 * printf format [arg...]
25 *
26 * David Korn
27 * AT&T Labs
28 */
29
30 #include "defs.h"
31 #include <error.h>
32 #include <stak.h>
33 #include "io.h"
34 #include "name.h"
35 #include "history.h"
36 #include "builtins.h"
37 #include "streval.h"
38 #include <tmx.h>
39 #include <ccode.h>
40
41 union types_t
42 {
43 unsigned char c;
44 short h;
45 int i;
46 long l;
47 Sflong_t ll;
48 Sfdouble_t ld;
49 double d;
50 float f;
51 char *s;
52 int *ip;
53 char **p;
54 };
55
56 struct printf
57 {
58 Sffmt_t hdr;
59 int argsize;
60 int intvar;
61 char **nextarg;
62 char *lastarg;
63 char cescape;
64 char err;
65 Shell_t *sh;
66 };
67
68 static int extend(Sfio_t*,void*, Sffmt_t*);
69 static const char preformat[] = "";
70 static char *genformat(char*);
71 static int fmtvecho(const char*, struct printf*);
72 static ssize_t fmtbase64(Sfio_t*, char*, int);
73
74 struct print
75 {
76 Shell_t *sh;
77 const char *options;
78 char raw;
79 char echon;
80 };
81
82 static char* nullarg[] = { 0, 0 };
83
84 #if !SHOPT_ECHOPRINT
B_echo(int argc,char * argv[],void * extra)85 int B_echo(int argc, char *argv[],void *extra)
86 {
87 static char bsd_univ;
88 struct print prdata;
89 prdata.options = sh_optecho+5;
90 prdata.raw = prdata.echon = 0;
91 prdata.sh = ((Shbltin_t*)extra)->shp;
92 NOT_USED(argc);
93 /* This mess is because /bin/echo on BSD is different */
94 if(!prdata.sh->universe)
95 {
96 register char *universe;
97 if(universe=astconf("UNIVERSE",0,0))
98 bsd_univ = (strcmp(universe,"ucb")==0);
99 prdata.sh->universe = 1;
100 }
101 if(!bsd_univ)
102 return(b_print(0,argv,&prdata));
103 prdata.options = sh_optecho;
104 prdata.raw = 1;
105 while(argv[1] && *argv[1]=='-')
106 {
107 if(strcmp(argv[1],"-n")==0)
108 prdata.echon = 1;
109 #if !SHOPT_ECHOE
110 else if(strcmp(argv[1],"-e")==0)
111 prdata.raw = 0;
112 else if(strcmp(argv[1],"-ne")==0 || strcmp(argv[1],"-en")==0)
113 {
114 prdata.raw = 0;
115 prdata.echon = 1;
116 }
117 #endif /* SHOPT_ECHOE */
118 else
119 break;
120 argv++;
121 }
122 return(b_print(0,argv,&prdata));
123 }
124 #endif /* SHOPT_ECHOPRINT */
125
b_printf(int argc,char * argv[],void * extra)126 int b_printf(int argc, char *argv[],void *extra)
127 {
128 struct print prdata;
129 NOT_USED(argc);
130 memset(&prdata,0,sizeof(prdata));
131 prdata.sh = ((Shbltin_t*)extra)->shp;
132 prdata.options = sh_optprintf;
133 return(b_print(-1,argv,&prdata));
134 }
135
136 /*
137 * argc==0 when called from echo
138 * argc==-1 when called from printf
139 */
140
b_print(int argc,char * argv[],void * extra)141 int b_print(int argc, char *argv[], void *extra)
142 {
143 register Sfio_t *outfile;
144 register int exitval=0,n, fd = 1;
145 register Shell_t *shp = ((Shbltin_t*)extra)->shp;
146 const char *options, *msg = e_file+4;
147 char *format = 0;
148 int sflag = 0, nflag=0, rflag=0, vflag=0;
149 if(argc>0)
150 {
151 options = sh_optprint;
152 nflag = rflag = 0;
153 format = 0;
154 }
155 else
156 {
157 struct print *pp = (struct print*)extra;
158 shp = pp->sh;
159 options = pp->options;
160 if(argc==0)
161 {
162 nflag = pp->echon;
163 rflag = pp->raw;
164 argv++;
165 goto skip;
166 }
167 }
168 while((n = optget(argv,options))) switch(n)
169 {
170 case 'n':
171 nflag++;
172 break;
173 case 'p':
174 fd = shp->coutpipe;
175 msg = e_query;
176 break;
177 case 'f':
178 format = opt_info.arg;
179 break;
180 case 's':
181 /* print to history file */
182 if(!sh_histinit((void*)shp))
183 errormsg(SH_DICT,ERROR_system(1),e_history);
184 fd = sffileno(shp->hist_ptr->histfp);
185 sh_onstate(SH_HISTORY);
186 sflag++;
187 break;
188 case 'e':
189 rflag = 0;
190 break;
191 case 'r':
192 rflag = 1;
193 break;
194 case 'u':
195 fd = (int)strtol(opt_info.arg,&opt_info.arg,10);
196 if(*opt_info.arg)
197 fd = -1;
198 else if(fd<0 || fd >= shp->lim.open_max)
199 fd = -1;
200 else if(!(sh.inuse_bits&(1<<fd)) && (sh_inuse(fd) || (shp->hist_ptr && fd==sffileno(shp->hist_ptr->histfp))))
201
202 fd = -1;
203 break;
204 case 'v':
205 vflag='v';
206 break;
207 case 'C':
208 vflag='C';
209 break;
210 case ':':
211 /* The following is for backward compatibility */
212 #if OPT_VERSION >= 19990123
213 if(strcmp(opt_info.name,"-R")==0)
214 #else
215 if(strcmp(opt_info.option,"-R")==0)
216 #endif
217 {
218 rflag = 1;
219 if(error_info.errors==0)
220 {
221 argv += opt_info.index+1;
222 /* special case test for -Rn */
223 if(strchr(argv[-1],'n'))
224 nflag++;
225 if(*argv && strcmp(*argv,"-n")==0)
226 {
227
228 nflag++;
229 argv++;
230 }
231 goto skip2;
232 }
233 }
234 else
235 errormsg(SH_DICT,2, "%s", opt_info.arg);
236 break;
237 case '?':
238 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
239 break;
240 }
241 argv += opt_info.index;
242 if(error_info.errors || (argc<0 && !(format = *argv++)))
243 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
244 if(vflag && format)
245 errormsg(SH_DICT,ERROR_usage(2),"-%c and -f are mutually exclusive",vflag);
246 skip:
247 if(format)
248 format = genformat(format);
249 /* handle special case of '-' operand for print */
250 if(argc>0 && *argv && strcmp(*argv,"-")==0 && strcmp(argv[-1],"--"))
251 argv++;
252 skip2:
253 if(fd < 0)
254 {
255 errno = EBADF;
256 n = 0;
257 }
258 else if(!(n=shp->fdstatus[fd]))
259 n = sh_iocheckfd(shp,fd);
260 if(!(n&IOWRITE))
261 {
262 /* don't print error message for stdout for compatibility */
263 if(fd==1)
264 return(1);
265 errormsg(SH_DICT,ERROR_system(1),msg);
266 }
267 if(!(outfile=shp->sftable[fd]))
268 {
269 sh_onstate(SH_NOTRACK);
270 n = SF_WRITE|((n&IOREAD)?SF_READ:0);
271 shp->sftable[fd] = outfile = sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fd,n);
272 sh_offstate(SH_NOTRACK);
273 sfpool(outfile,shp->outpool,SF_WRITE);
274 }
275 /* turn off share to guarantee atomic writes for printf */
276 n = sfset(outfile,SF_SHARE|SF_PUBLIC,0);
277 if(format)
278 {
279 /* printf style print */
280 Sfio_t *pool;
281 struct printf pdata;
282 memset(&pdata, 0, sizeof(pdata));
283 pdata.sh = shp;
284 pdata.hdr.version = SFIO_VERSION;
285 pdata.hdr.extf = extend;
286 pdata.nextarg = argv;
287 sh_offstate(SH_STOPOK);
288 pool=sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE);
289 do
290 {
291 if(shp->trapnote&SH_SIGSET)
292 break;
293 pdata.hdr.form = format;
294 sfprintf(outfile,"%!",&pdata);
295 } while(*pdata.nextarg && pdata.nextarg!=argv);
296 if(pdata.nextarg == nullarg && pdata.argsize>0)
297 sfwrite(outfile,stakptr(staktell()),pdata.argsize);
298 if(sffileno(outfile)!=sffileno(sfstderr))
299 sfsync(outfile);
300 sfpool(sfstderr,pool,SF_WRITE);
301 exitval = pdata.err;
302 }
303 else if(vflag)
304 {
305 while(*argv)
306 {
307 fmtbase64(outfile,*argv++,vflag=='C');
308 if(!nflag)
309 sfputc(outfile,'\n');
310 }
311 }
312 else
313 {
314 /* echo style print */
315 if(nflag && !argv[0])
316 sfsync((Sfio_t*)0);
317 else if(sh_echolist(outfile,rflag,argv) && !nflag)
318 sfputc(outfile,'\n');
319 }
320 if(sflag)
321 {
322 hist_flush(shp->hist_ptr);
323 sh_offstate(SH_HISTORY);
324 }
325 else if(n&SF_SHARE)
326 {
327 sfset(outfile,SF_SHARE|SF_PUBLIC,1);
328 sfsync(outfile);
329 }
330 return(exitval);
331 }
332
333 /*
334 * echo the argument list onto <outfile>
335 * if <raw> is non-zero then \ is not a special character.
336 * returns 0 for \c otherwise 1.
337 */
338
sh_echolist(Sfio_t * outfile,int raw,char * argv[])339 int sh_echolist(Sfio_t *outfile, int raw, char *argv[])
340 {
341 register char *cp;
342 register int n;
343 struct printf pdata;
344 pdata.cescape = 0;
345 pdata.err = 0;
346 while(!pdata.cescape && (cp= *argv++))
347 {
348 if(!raw && (n=fmtvecho(cp,&pdata))>=0)
349 {
350 if(n)
351 sfwrite(outfile,stakptr(staktell()),n);
352 }
353 else
354 sfputr(outfile,cp,-1);
355 if(*argv)
356 sfputc(outfile,' ');
357 sh_sigcheck();
358 }
359 return(!pdata.cescape);
360 }
361
362 /*
363 * modified version of stresc for generating formats
364 */
strformat(char * s)365 static char strformat(char *s)
366 {
367 register char* t;
368 register int c;
369 char* b;
370 char* p;
371
372 b = t = s;
373 for (;;)
374 {
375 switch (c = *s++)
376 {
377 case '\\':
378 if(*s==0)
379 break;
380 c = chresc(s - 1, &p);
381 s = p;
382 #if SHOPT_MULTIBYTE
383 if(c>UCHAR_MAX && mbwide())
384 {
385 t += wctomb(t, c);
386 continue;
387 }
388 #endif /* SHOPT_MULTIBYTE */
389 if(c=='%')
390 *t++ = '%';
391 else if(c==0)
392 {
393 *t++ = '%';
394 c = 'Z';
395 }
396 break;
397 case 0:
398 *t = 0;
399 return(t - b);
400 }
401 *t++ = c;
402 }
403 }
404
405
genformat(char * format)406 static char *genformat(char *format)
407 {
408 register char *fp;
409 stakseek(0);
410 stakputs(preformat);
411 stakputs(format);
412 fp = (char*)stakfreeze(1);
413 strformat(fp+sizeof(preformat)-1);
414 return(fp);
415 }
416
fmthtml(const char * string)417 static char *fmthtml(const char *string)
418 {
419 register const char *cp = string;
420 register int c, offset = staktell();
421 while(c= *(unsigned char*)cp++)
422 {
423 #if SHOPT_MULTIBYTE
424 register int s;
425 if((s=mbsize(cp-1)) > 1)
426 {
427 cp += (s-1);
428 continue;
429 }
430 #endif /* SHOPT_MULTIBYTE */
431 if(c=='<')
432 stakputs("<");
433 else if(c=='>')
434 stakputs(">");
435 else if(c=='&')
436 stakputs("&");
437 else if(c=='"')
438 stakputs(""");
439 else if(c=='\'')
440 stakputs("'");
441 else if(c==' ')
442 stakputs(" ");
443 else if(!isprint(c) && c!='\n' && c!='\r')
444 sfprintf(stkstd,"&#%X;",CCMAPC(c,CC_NATIVE,CC_ASCII));
445 else
446 stakputc(c);
447 }
448 stakputc(0);
449 return(stakptr(offset));
450 }
451
452 #if 1
fmtbase64(Sfio_t * iop,char * string,int alt)453 static ssize_t fmtbase64(Sfio_t *iop, char *string, int alt)
454 #else
455 static void *fmtbase64(char *string, ssize_t *sz, int alt)
456 #endif
457 {
458 char *cp;
459 Sfdouble_t d;
460 ssize_t size;
461 Namval_t *np = nv_open(string, NiL, NV_VARNAME|NV_NOASSIGN|NV_NOADD);
462 static union types_t number;
463 if(!np || nv_isnull(np))
464 {
465 if(sh_isoption(SH_NOUNSET))
466 errormsg(SH_DICT,ERROR_exit(1),e_notset,string);
467 return(0);
468 }
469 if(nv_isattr(np,NV_INTEGER))
470 {
471 d = nv_getnum(np);
472 if(nv_isattr(np,NV_DOUBLE))
473 {
474 if(nv_isattr(np,NV_LONG))
475 {
476 size = sizeof(Sfdouble_t);
477 number.ld = d;
478 }
479 else if(nv_isattr(np,NV_SHORT))
480 {
481 size = sizeof(float);
482 number.f = (float)d;
483 }
484 else
485 {
486 size = sizeof(double);
487 number.d = (double)d;
488 }
489 }
490 else
491 {
492 if(nv_isattr(np,NV_LONG))
493 {
494 size = sizeof(Sflong_t);
495 number.ll = (Sflong_t)d;
496 }
497 else if(nv_isattr(np,NV_SHORT))
498 {
499 size = sizeof(short);
500 number.h = (short)d;
501 }
502 else
503 {
504 size = sizeof(short);
505 number.i = (int)d;
506 }
507 }
508 #if 1
509 return(sfwrite(iop, (void*)&number, size));
510 #else
511 if(sz)
512 *sz = size;
513 return((void*)&number);
514 #endif
515 }
516 if(nv_isattr(np,NV_BINARY))
517 #if 1
518 {
519 Namfun_t *fp;
520 for(fp=np->nvfun; fp;fp=fp->next)
521 {
522 if(fp->disc && fp->disc->writef)
523 break;
524 }
525 if(fp)
526 return (*fp->disc->writef)(np, iop, 0, fp);
527 else
528 {
529 int n = nv_size(np);
530 if(nv_isarray(np))
531 {
532 nv_onattr(np,NV_RAW);
533 cp = nv_getval(np);
534 nv_offattr(np,NV_RAW);
535 }
536 else
537 cp = (char*)np->nvalue.cp;
538 if((size = n)==0)
539 size = strlen(cp);
540 size = sfwrite(iop, cp, size);
541 return(n?n:size);
542 }
543 }
544 else if(nv_isarray(np) && nv_arrayptr(np))
545 {
546 nv_outnode(np,iop,(alt?-1:0),0);
547 sfputc(iop,')');
548 return(sftell(iop));
549 }
550 else
551 {
552 if(alt && nv_isvtree(np))
553 nv_onattr(np,NV_EXPORT);
554 if(!(cp = nv_getval(np)))
555 return(0);
556 size = strlen(cp);
557 return(sfwrite(iop,cp,size));
558 }
559 #else
560 nv_onattr(np,NV_RAW);
561 cp = nv_getval(np);
562 if(nv_isattr(np,NV_BINARY))
563 nv_offattr(np,NV_RAW);
564 if((size = nv_size(np))==0)
565 size = strlen(cp);
566 if(sz)
567 *sz = size;
568 return((void*)cp);
569 #endif
570 }
571
varname(const char * str,int n)572 static int varname(const char *str, int n)
573 {
574 register int c,dot=1,len=1;
575 if(n < 0)
576 {
577 if(*str=='.')
578 str++;
579 n = strlen(str);
580 }
581 for(;n > 0; n-=len)
582 {
583 #ifdef SHOPT_MULTIBYTE
584 len = mbsize(str);
585 c = mbchar(str);
586 #else
587 c = *(unsigned char*)str++;
588 #endif
589 if(dot && !(isalpha(c)||c=='_'))
590 break;
591 else if(dot==0 && !(isalnum(c) || c=='_' || c == '.'))
592 break;
593 dot = (c=='.');
594 }
595 return(n==0);
596 }
597
extend(Sfio_t * sp,void * v,Sffmt_t * fe)598 static int extend(Sfio_t* sp, void* v, Sffmt_t* fe)
599 {
600 char* lastchar = "";
601 register int neg = 0;
602 Sfdouble_t d;
603 Sfdouble_t longmin = LDBL_LLONG_MIN;
604 Sfdouble_t longmax = LDBL_LLONG_MAX;
605 int format = fe->fmt;
606 int n;
607 int fold = fe->base;
608 union types_t* value = (union types_t*)v;
609 struct printf* pp = (struct printf*)fe;
610 register char* argp = *pp->nextarg;
611 char* w;
612
613 if(fe->n_str>0 && varname(fe->t_str,fe->n_str) && (!argp || varname(argp,-1)))
614 {
615 if(argp)
616 pp->lastarg = argp;
617 else
618 argp = pp->lastarg;
619 if(argp)
620 {
621 sfprintf(pp->sh->strbuf,"%s.%.*s%c",argp,fe->n_str,fe->t_str,0);
622 argp = sfstruse(pp->sh->strbuf);
623 }
624 }
625 else
626 pp->lastarg = 0;
627 fe->flags |= SFFMT_VALUE;
628 if(!argp || format=='Z')
629 {
630 switch(format)
631 {
632 case 'c':
633 value->c = 0;
634 fe->flags &= ~SFFMT_LONG;
635 break;
636 case 'q':
637 format = 's';
638 /* FALL THROUGH */
639 case 's':
640 case 'H':
641 case 'B':
642 case 'P':
643 case 'R':
644 case 'Z':
645 case 'b':
646 fe->fmt = 's';
647 fe->size = -1;
648 fe->base = -1;
649 value->s = "";
650 fe->flags &= ~SFFMT_LONG;
651 break;
652 case 'a':
653 case 'e':
654 case 'f':
655 case 'g':
656 case 'A':
657 case 'E':
658 case 'F':
659 case 'G':
660 if(SFFMT_LDOUBLE)
661 value->ld = 0.;
662 else
663 value->d = 0.;
664 break;
665 case 'n':
666 value->ip = &pp->intvar;
667 break;
668 case 'Q':
669 value->ll = 0;
670 break;
671 case 'T':
672 fe->fmt = 'd';
673 value->ll = tmxgettime();
674 break;
675 default:
676 if(!strchr("DdXxoUu",format))
677 errormsg(SH_DICT,ERROR_exit(1),e_formspec,format);
678 fe->fmt = 'd';
679 value->ll = 0;
680 break;
681 }
682 }
683 else
684 {
685 switch(format)
686 {
687 case 'p':
688 value->p = (char**)strtol(argp,&lastchar,10);
689 break;
690 case 'n':
691 {
692 Namval_t *np;
693 np = nv_open(argp,sh.var_tree,NV_VARNAME|NV_NOASSIGN|NV_NOARRAY);
694 nv_unset(np);
695 nv_onattr(np,NV_INTEGER);
696 if (np->nvalue.lp = new_of(int32_t,0))
697 *np->nvalue.lp = 0;
698 nv_setsize(np,10);
699 if(sizeof(int)==sizeof(int32_t))
700 value->ip = (int*)np->nvalue.lp;
701 else
702 {
703 int32_t sl = 1;
704 value->ip = (int*)(((char*)np->nvalue.lp) + (*((char*)&sl) ? 0 : sizeof(int)));
705 }
706 nv_close(np);
707 break;
708 }
709 case 'q':
710 case 'b':
711 case 's':
712 case 'B':
713 case 'H':
714 case 'P':
715 case 'R':
716 fe->fmt = 's';
717 fe->size = -1;
718 if(format=='s' && fe->base>=0)
719 {
720 value->p = pp->nextarg;
721 pp->nextarg = nullarg;
722 }
723 else
724 {
725 fe->base = -1;
726 value->s = argp;
727 }
728 fe->flags &= ~SFFMT_LONG;
729 break;
730 case 'c':
731 if(mbwide() && (n = mbsize(argp)) > 1)
732 {
733 fe->fmt = 's';
734 fe->size = n;
735 value->s = argp;
736 }
737 else if(fe->base >=0)
738 value->s = argp;
739 else
740 value->c = *argp;
741 fe->flags &= ~SFFMT_LONG;
742 break;
743 case 'o':
744 case 'x':
745 case 'X':
746 case 'u':
747 case 'U':
748 longmax = LDBL_ULLONG_MAX;
749 case '.':
750 if(fe->size==2 && strchr("bcsqHPRQTZ",*fe->form))
751 {
752 value->ll = ((unsigned char*)argp)[0];
753 break;
754 }
755 case 'd':
756 case 'D':
757 case 'i':
758 switch(*argp)
759 {
760 case '\'':
761 case '"':
762 w = argp + 1;
763 if(mbwide() && mbsize(w) > 1)
764 value->ll = mbchar(w);
765 else
766 value->ll = *(unsigned char*)w++;
767 if(w[0] && (w[0] != argp[0] || w[1]))
768 {
769 errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp);
770 pp->err = 1;
771 }
772 break;
773 default:
774 d = sh_strnum(argp,&lastchar,0);
775 if(d<longmin)
776 {
777 errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);
778 pp->err = 1;
779 d = longmin;
780 }
781 else if(d>longmax)
782 {
783 errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);
784 pp->err = 1;
785 d = longmax;
786 }
787 value->ll = (Sflong_t)d;
788 if(lastchar == *pp->nextarg)
789 {
790 value->ll = *argp;
791 lastchar = "";
792 }
793 break;
794 }
795 if(neg)
796 value->ll = -value->ll;
797 fe->size = sizeof(value->ll);
798 break;
799 case 'a':
800 case 'e':
801 case 'f':
802 case 'g':
803 case 'A':
804 case 'E':
805 case 'F':
806 case 'G':
807 d = sh_strnum(*pp->nextarg,&lastchar,0);
808 switch(*argp)
809 {
810 case '\'':
811 case '"':
812 d = ((unsigned char*)argp)[1];
813 if(argp[2] && (argp[2] != argp[0] || argp[3]))
814 {
815 errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp);
816 pp->err = 1;
817 }
818 break;
819 default:
820 d = sh_strnum(*pp->nextarg,&lastchar,0);
821 break;
822 }
823 if(SFFMT_LDOUBLE)
824 {
825 value->ld = d;
826 fe->size = sizeof(value->ld);
827 }
828 else
829 {
830 value->d = d;
831 fe->size = sizeof(value->d);
832 }
833 break;
834 case 'Q':
835 value->ll = (Sflong_t)strelapsed(*pp->nextarg,&lastchar,1);
836 break;
837 case 'T':
838 value->ll = (Sflong_t)tmxdate(*pp->nextarg,&lastchar,TMX_NOW);
839 break;
840 default:
841 value->ll = 0;
842 fe->fmt = 'd';
843 fe->size = sizeof(value->ll);
844 errormsg(SH_DICT,ERROR_exit(1),e_formspec,format);
845 break;
846 }
847 if (format == '.')
848 value->i = value->ll;
849 if(*lastchar)
850 {
851 errormsg(SH_DICT,ERROR_warn(0),e_argtype,format);
852 pp->err = 1;
853 }
854 pp->nextarg++;
855 }
856 switch(format)
857 {
858 case 'Z':
859 fe->fmt = 'c';
860 fe->base = -1;
861 value->c = 0;
862 break;
863 case 'b':
864 if((n=fmtvecho(value->s,pp))>=0)
865 {
866 if(pp->nextarg == nullarg)
867 {
868 pp->argsize = n;
869 return -1;
870 }
871 value->s = stakptr(staktell());
872 }
873 break;
874 case 'B':
875 if(!sh.strbuf2)
876 sh.strbuf2 = sfstropen();
877 fe->size = fmtbase64(sh.strbuf2,value->s, fe->flags&SFFMT_ALTER);
878 value->s = sfstruse(sh.strbuf2);
879 fe->flags |= SFFMT_SHORT;
880 break;
881 case 'H':
882 value->s = fmthtml(value->s);
883 break;
884 case 'q':
885 value->s = sh_fmtqf(value->s, !!(fe->flags & SFFMT_ALTER), fold);
886 break;
887 case 'P':
888 {
889 char *s = fmtmatch(value->s);
890 if(!s || *s==0)
891 errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s);
892 value->s = s;
893 break;
894 }
895 case 'R':
896 value->s = fmtre(value->s);
897 if(*value->s==0)
898 errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s);
899 break;
900 case 'Q':
901 if (fe->n_str>0)
902 {
903 fe->fmt = 'd';
904 fe->size = sizeof(value->ll);
905 }
906 else
907 {
908 value->s = fmtelapsed(value->ll, 1);
909 fe->fmt = 's';
910 fe->size = -1;
911 }
912 break;
913 case 'T':
914 if(fe->n_str>0)
915 {
916 n = fe->t_str[fe->n_str];
917 fe->t_str[fe->n_str] = 0;
918 value->s = fmttmx(fe->t_str, value->ll);
919 fe->t_str[fe->n_str] = n;
920 }
921 else value->s = fmttmx(NIL(char*), value->ll);
922 fe->fmt = 's';
923 fe->size = -1;
924 break;
925 }
926 return 0;
927 }
928
929 /*
930 * construct System V echo string out of <cp>
931 * If there are not escape sequences, returns -1
932 * Otherwise, puts null terminated result on stack, but doesn't freeze it
933 * returns length of output.
934 */
935
fmtvecho(const char * string,struct printf * pp)936 static int fmtvecho(const char *string, struct printf *pp)
937 {
938 register const char *cp = string, *cpmax;
939 register int c;
940 register int offset = staktell();
941 #if SHOPT_MULTIBYTE
942 int chlen;
943 if(mbwide())
944 {
945 while(1)
946 {
947 if ((chlen = mbsize(cp)) > 1)
948 /* Skip over multibyte characters */
949 cp += chlen;
950 else if((c= *cp++)==0 || c == '\\')
951 break;
952 }
953 }
954 else
955 #endif /* SHOPT_MULTIBYTE */
956 while((c= *cp++) && (c!='\\'));
957 if(c==0)
958 return(-1);
959 c = --cp - string;
960 if(c>0)
961 stakwrite((void*)string,c);
962 for(; c= *cp; cp++)
963 {
964 #if SHOPT_MULTIBYTE
965 if (mbwide() && ((chlen = mbsize(cp)) > 1))
966 {
967 stakwrite(cp,chlen);
968 cp += (chlen-1);
969 continue;
970 }
971 #endif /* SHOPT_MULTIBYTE */
972 if( c=='\\') switch(*++cp)
973 {
974 case 'E':
975 c = ('a'==97?'\033':39); /* ASCII/EBCDIC */
976 break;
977 case 'a':
978 c = '\a';
979 break;
980 case 'b':
981 c = '\b';
982 break;
983 case 'c':
984 pp->cescape++;
985 pp->nextarg = nullarg;
986 goto done;
987 case 'f':
988 c = '\f';
989 break;
990 case 'n':
991 c = '\n';
992 break;
993 case 'r':
994 c = '\r';
995 break;
996 case 'v':
997 c = '\v';
998 break;
999 case 't':
1000 c = '\t';
1001 break;
1002 case '\\':
1003 c = '\\';
1004 break;
1005 case '0':
1006 c = 0;
1007 cpmax = cp + 4;
1008 while(++cp<cpmax && *cp>='0' && *cp<='7')
1009 {
1010 c <<= 3;
1011 c |= (*cp-'0');
1012 }
1013 default:
1014 cp--;
1015 }
1016 stakputc(c);
1017 }
1018 done:
1019 c = staktell()-offset;
1020 stakputc(0);
1021 stakseek(offset);
1022 return(c);
1023 }
1024