8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libshell / common / bltins / print.c
blob41db7b3e465e7e2703549c2cf8bb3ae7c1e2ebcd
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
22 * echo [arg...]
23 * print [-nrps] [-f format] [-u filenum] [arg...]
24 * printf format [arg...]
26 * David Korn
27 * AT&T Labs
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>
41 union types_t
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;
56 struct printf
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;
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);
74 struct print
76 Shell_t *sh;
77 const char *options;
78 char raw;
79 char echon;
82 static char* nullarg[] = { 0, 0 };
84 #if !SHOPT_ECHOPRINT
85 int B_echo(int argc, char *argv[],void *extra)
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)
96 register char *universe;
97 if(universe=astconf("UNIVERSE",0,0))
98 bsd_univ = (strcmp(universe,"ucb")==0);
99 prdata.sh->universe = 1;
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]=='-')
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)
114 prdata.raw = 0;
115 prdata.echon = 1;
117 #endif /* SHOPT_ECHOE */
118 else
119 break;
120 argv++;
122 return(b_print(0,argv,&prdata));
124 #endif /* SHOPT_ECHOPRINT */
126 int b_printf(int argc, char *argv[],void *extra)
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));
137 * argc==0 when called from echo
138 * argc==-1 when called from printf
141 int b_print(int argc, char *argv[], void *extra)
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)
151 options = sh_optprint;
152 nflag = rflag = 0;
153 format = 0;
155 else
157 struct print *pp = (struct print*)extra;
158 shp = pp->sh;
159 options = pp->options;
160 if(argc==0)
162 nflag = pp->echon;
163 rflag = pp->raw;
164 argv++;
165 goto skip;
168 while((n = optget(argv,options))) switch(n)
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))))
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
218 rflag = 1;
219 if(error_info.errors==0)
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)
228 nflag++;
229 argv++;
231 goto skip2;
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;
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)
255 errno = EBADF;
256 n = 0;
258 else if(!(n=shp->fdstatus[fd]))
259 n = sh_iocheckfd(shp,fd);
260 if(!(n&IOWRITE))
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);
267 if(!(outfile=shp->sftable[fd]))
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);
275 /* turn off share to guarantee atomic writes for printf */
276 n = sfset(outfile,SF_SHARE|SF_PUBLIC,0);
277 if(format)
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);
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;
303 else if(vflag)
305 while(*argv)
307 fmtbase64(outfile,*argv++,vflag=='C');
308 if(!nflag)
309 sfputc(outfile,'\n');
312 else
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');
320 if(sflag)
322 hist_flush(shp->hist_ptr);
323 sh_offstate(SH_HISTORY);
325 else if(n&SF_SHARE)
327 sfset(outfile,SF_SHARE|SF_PUBLIC,1);
328 sfsync(outfile);
330 return(exitval);
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.
339 int sh_echolist(Sfio_t *outfile, int raw, char *argv[])
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++))
348 if(!raw && (n=fmtvecho(cp,&pdata))>=0)
350 if(n)
351 sfwrite(outfile,stakptr(staktell()),n);
353 else
354 sfputr(outfile,cp,-1);
355 if(*argv)
356 sfputc(outfile,' ');
357 sh_sigcheck();
359 return(!pdata.cescape);
363 * modified version of stresc for generating formats
365 static char strformat(char *s)
367 register char* t;
368 register int c;
369 char* b;
370 char* p;
372 b = t = s;
373 for (;;)
375 switch (c = *s++)
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())
385 t += wctomb(t, c);
386 continue;
388 #endif /* SHOPT_MULTIBYTE */
389 if(c=='%')
390 *t++ = '%';
391 else if(c==0)
393 *t++ = '%';
394 c = 'Z';
396 break;
397 case 0:
398 *t = 0;
399 return(t - b);
401 *t++ = c;
406 static char *genformat(char *format)
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);
417 static char *fmthtml(const char *string)
419 register const char *cp = string;
420 register int c, offset = staktell();
421 while(c= *(unsigned char*)cp++)
423 #if SHOPT_MULTIBYTE
424 register int s;
425 if((s=mbsize(cp-1)) > 1)
427 cp += (s-1);
428 continue;
430 #endif /* SHOPT_MULTIBYTE */
431 if(c=='<')
432 stakputs("&lt;");
433 else if(c=='>')
434 stakputs("&gt;");
435 else if(c=='&')
436 stakputs("&amp;");
437 else if(c=='"')
438 stakputs("&quot;");
439 else if(c=='\'')
440 stakputs("&apos;");
441 else if(c==' ')
442 stakputs("&nbsp;");
443 else if(!isprint(c) && c!='\n' && c!='\r')
444 sfprintf(stkstd,"&#%X;",CCMAPC(c,CC_NATIVE,CC_ASCII));
445 else
446 stakputc(c);
448 stakputc(0);
449 return(stakptr(offset));
452 #if 1
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
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))
465 if(sh_isoption(SH_NOUNSET))
466 errormsg(SH_DICT,ERROR_exit(1),e_notset,string);
467 return(0);
469 if(nv_isattr(np,NV_INTEGER))
471 d = nv_getnum(np);
472 if(nv_isattr(np,NV_DOUBLE))
474 if(nv_isattr(np,NV_LONG))
476 size = sizeof(Sfdouble_t);
477 number.ld = d;
479 else if(nv_isattr(np,NV_SHORT))
481 size = sizeof(float);
482 number.f = (float)d;
484 else
486 size = sizeof(double);
487 number.d = (double)d;
490 else
492 if(nv_isattr(np,NV_LONG))
494 size = sizeof(Sflong_t);
495 number.ll = (Sflong_t)d;
497 else if(nv_isattr(np,NV_SHORT))
499 size = sizeof(short);
500 number.h = (short)d;
502 else
504 size = sizeof(short);
505 number.i = (int)d;
508 #if 1
509 return(sfwrite(iop, (void*)&number, size));
510 #else
511 if(sz)
512 *sz = size;
513 return((void*)&number);
514 #endif
516 if(nv_isattr(np,NV_BINARY))
517 #if 1
519 Namfun_t *fp;
520 for(fp=np->nvfun; fp;fp=fp->next)
522 if(fp->disc && fp->disc->writef)
523 break;
525 if(fp)
526 return (*fp->disc->writef)(np, iop, 0, fp);
527 else
529 int n = nv_size(np);
530 if(nv_isarray(np))
532 nv_onattr(np,NV_RAW);
533 cp = nv_getval(np);
534 nv_offattr(np,NV_RAW);
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);
544 else if(nv_isarray(np) && nv_arrayptr(np))
546 nv_outnode(np,iop,(alt?-1:0),0);
547 sfputc(iop,')');
548 return(sftell(iop));
550 else
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));
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
572 static int varname(const char *str, int n)
574 register int c,dot=1,len=1;
575 if(n < 0)
577 if(*str=='.')
578 str++;
579 n = strlen(str);
581 for(;n > 0; n-=len)
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=='.');
595 return(n==0);
598 static int extend(Sfio_t* sp, void* v, Sffmt_t* fe)
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;
613 if(fe->n_str>0 && varname(fe->t_str,fe->n_str) && (!argp || varname(argp,-1)))
615 if(argp)
616 pp->lastarg = argp;
617 else
618 argp = pp->lastarg;
619 if(argp)
621 sfprintf(pp->sh->strbuf,"%s.%.*s%c",argp,fe->n_str,fe->t_str,0);
622 argp = sfstruse(pp->sh->strbuf);
625 else
626 pp->lastarg = 0;
627 fe->flags |= SFFMT_VALUE;
628 if(!argp || format=='Z')
630 switch(format)
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;
683 else
685 switch(format)
687 case 'p':
688 value->p = (char**)strtol(argp,&lastchar,10);
689 break;
690 case 'n':
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
703 int32_t sl = 1;
704 value->ip = (int*)(((char*)np->nvalue.lp) + (*((char*)&sl) ? 0 : sizeof(int)));
706 nv_close(np);
707 break;
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)
720 value->p = pp->nextarg;
721 pp->nextarg = nullarg;
723 else
725 fe->base = -1;
726 value->s = argp;
728 fe->flags &= ~SFFMT_LONG;
729 break;
730 case 'c':
731 if(mbwide() && (n = mbsize(argp)) > 1)
733 fe->fmt = 's';
734 fe->size = n;
735 value->s = argp;
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))
752 value->ll = ((unsigned char*)argp)[0];
753 break;
755 case 'd':
756 case 'D':
757 case 'i':
758 switch(*argp)
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]))
769 errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp);
770 pp->err = 1;
772 break;
773 default:
774 d = sh_strnum(argp,&lastchar,0);
775 if(d<longmin)
777 errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);
778 pp->err = 1;
779 d = longmin;
781 else if(d>longmax)
783 errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);
784 pp->err = 1;
785 d = longmax;
787 value->ll = (Sflong_t)d;
788 if(lastchar == *pp->nextarg)
790 value->ll = *argp;
791 lastchar = "";
793 break;
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)
810 case '\'':
811 case '"':
812 d = ((unsigned char*)argp)[1];
813 if(argp[2] && (argp[2] != argp[0] || argp[3]))
815 errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp);
816 pp->err = 1;
818 break;
819 default:
820 d = sh_strnum(*pp->nextarg,&lastchar,0);
821 break;
823 if(SFFMT_LDOUBLE)
825 value->ld = d;
826 fe->size = sizeof(value->ld);
828 else
830 value->d = d;
831 fe->size = sizeof(value->d);
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;
847 if (format == '.')
848 value->i = value->ll;
849 if(*lastchar)
851 errormsg(SH_DICT,ERROR_warn(0),e_argtype,format);
852 pp->err = 1;
854 pp->nextarg++;
856 switch(format)
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)
866 if(pp->nextarg == nullarg)
868 pp->argsize = n;
869 return -1;
871 value->s = stakptr(staktell());
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':
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;
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)
903 fe->fmt = 'd';
904 fe->size = sizeof(value->ll);
906 else
908 value->s = fmtelapsed(value->ll, 1);
909 fe->fmt = 's';
910 fe->size = -1;
912 break;
913 case 'T':
914 if(fe->n_str>0)
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;
921 else value->s = fmttmx(NIL(char*), value->ll);
922 fe->fmt = 's';
923 fe->size = -1;
924 break;
926 return 0;
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.
936 static int fmtvecho(const char *string, struct printf *pp)
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())
945 while(1)
947 if ((chlen = mbsize(cp)) > 1)
948 /* Skip over multibyte characters */
949 cp += chlen;
950 else if((c= *cp++)==0 || c == '\\')
951 break;
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++)
964 #if SHOPT_MULTIBYTE
965 if (mbwide() && ((chlen = mbsize(cp)) > 1))
967 stakwrite(cp,chlen);
968 cp += (chlen-1);
969 continue;
971 #endif /* SHOPT_MULTIBYTE */
972 if( c=='\\') switch(*++cp)
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')
1010 c <<= 3;
1011 c |= (*cp-'0');
1013 default:
1014 cp--;
1016 stakputc(c);
1018 done:
1019 c = staktell()-offset;
1020 stakputc(0);
1021 stakseek(offset);
1022 return(c);