1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1982-2011 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 41union 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 56struct 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 68static int extend(Sfio_t*,void*, Sffmt_t*); 69static const char preformat[] = ""; 70static char *genformat(char*); 71static int fmtvecho(const char*, struct printf*); 72static ssize_t fmtbase64(Sfio_t*, char*, int); 73 74struct print 75{ 76 Shell_t *sh; 77 const char *options; 78 char raw; 79 char echon; 80}; 81 82static char* nullarg[] = { 0, 0 }; 83 84#if !SHOPT_ECHOPRINT 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 126int 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 141int 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->gd->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(!sh_iovalidfd(shp,fd)) 199 fd = -1; 200 else if(!(shp->inuse_bits&(1<<fd)) && (sh_inuse(shp,fd) || (shp->gd->hist_ptr && fd==sffileno(shp->gd->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); 246skip: 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++; 252skip2: 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(shp,outfile,rflag,argv) && !nflag) 318 sfputc(outfile,'\n'); 319 } 320 if(sflag) 321 { 322 hist_flush(shp->gd->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 339int sh_echolist(Shell_t *shp,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(shp); 358 } 359 return(!pdata.cescape); 360} 361 362/* 363 * modified version of stresc for generating formats 364 */ 365static char strformat(char *s) 366{ 367 register char* t; 368 register int c; 369 char* b; 370 char* p; 371#if SHOPT_MULTIBYTE && defined(FMT_EXP_WIDE) 372 int w; 373#endif 374 375 b = t = s; 376 for (;;) 377 { 378 switch (c = *s++) 379 { 380 case '\\': 381 if(*s==0) 382 break; 383#if SHOPT_MULTIBYTE && defined(FMT_EXP_WIDE) 384 c = chrexp(s - 1, &p, &w, FMT_EXP_CHAR|FMT_EXP_LINE|FMT_EXP_WIDE); 385#else 386 c = chresc(s - 1, &p); 387#endif 388 s = p; 389#if SHOPT_MULTIBYTE 390#if defined(FMT_EXP_WIDE) 391 if(w) 392 { 393 t += mbwide() ? mbconv(t, c) : wc2utf8(t, c); 394 continue; 395 } 396#else 397 if(c>UCHAR_MAX && mbwide()) 398 { 399 t += mbconv(t, c); 400 continue; 401 } 402#endif /* FMT_EXP_WIDE */ 403#endif /* SHOPT_MULTIBYTE */ 404 if(c=='%') 405 *t++ = '%'; 406 else if(c==0) 407 { 408 *t++ = '%'; 409 c = 'Z'; 410 } 411 break; 412 case 0: 413 *t = 0; 414 return(t - b); 415 } 416 *t++ = c; 417 } 418} 419 420 421static char *genformat(char *format) 422{ 423 register char *fp; 424 stakseek(0); 425 stakputs(preformat); 426 stakputs(format); 427 fp = (char*)stakfreeze(1); 428 strformat(fp+sizeof(preformat)-1); 429 return(fp); 430} 431 432static char *fmthtml(const char *string) 433{ 434 register const char *cp = string; 435 register int c, offset = staktell(); 436 while(c= *(unsigned char*)cp++) 437 { 438#if SHOPT_MULTIBYTE 439 register int s; 440 if((s=mbsize(cp-1)) > 1) 441 { 442 cp += (s-1); 443 continue; 444 } 445#endif /* SHOPT_MULTIBYTE */ 446 if(c=='<') 447 stakputs("<"); 448 else if(c=='>') 449 stakputs(">"); 450 else if(c=='&') 451 stakputs("&"); 452 else if(c=='"') 453 stakputs("""); 454 else if(c=='\'') 455 stakputs("'"); 456 else if(c==' ') 457 stakputs(" "); 458 else if(!isprint(c) && c!='\n' && c!='\r') 459 sfprintf(stkstd,"&#%X;",CCMAPC(c,CC_NATIVE,CC_ASCII)); 460 else 461 stakputc(c); 462 } 463 stakputc(0); 464 return(stakptr(offset)); 465} 466 467#if 1 468static ssize_t fmtbase64(Sfio_t *iop, char *string, int alt) 469#else 470static void *fmtbase64(char *string, ssize_t *sz, int alt) 471#endif 472{ 473 char *cp; 474 Sfdouble_t d; 475 ssize_t size; 476 Namval_t *np = nv_open(string, NiL, NV_VARNAME|NV_NOASSIGN|NV_NOADD); 477 Namarr_t *ap; 478 static union types_t number; 479 if(!np || nv_isnull(np)) 480 { 481 if(sh_isoption(SH_NOUNSET)) 482 errormsg(SH_DICT,ERROR_exit(1),e_notset,string); 483 return(0); 484 } 485 if(nv_isattr(np,NV_INTEGER)) 486 { 487 d = nv_getnum(np); 488 if(nv_isattr(np,NV_DOUBLE)) 489 { 490 if(nv_isattr(np,NV_LONG)) 491 { 492 size = sizeof(Sfdouble_t); 493 number.ld = d; 494 } 495 else if(nv_isattr(np,NV_SHORT)) 496 { 497 size = sizeof(float); 498 number.f = (float)d; 499 } 500 else 501 { 502 size = sizeof(double); 503 number.d = (double)d; 504 } 505 } 506 else 507 { 508 if(nv_isattr(np,NV_LONG)) 509 { 510 size = sizeof(Sflong_t); 511 number.ll = (Sflong_t)d; 512 } 513 else if(nv_isattr(np,NV_SHORT)) 514 { 515 size = sizeof(short); 516 number.h = (short)d; 517 } 518 else 519 { 520 size = sizeof(short); 521 number.i = (int)d; 522 } 523 } 524#if 1 525 return(sfwrite(iop, (void*)&number, size)); 526#else 527 if(sz) 528 *sz = size; 529 return((void*)&number); 530#endif 531 } 532 if(nv_isattr(np,NV_BINARY)) 533#if 1 534 { 535 Namfun_t *fp; 536 for(fp=np->nvfun; fp;fp=fp->next) 537 { 538 if(fp->disc && fp->disc->writef) 539 break; 540 } 541 if(fp) 542 return (*fp->disc->writef)(np, iop, 0, fp); 543 else 544 { 545 int n = nv_size(np); 546 if(nv_isarray(np)) 547 { 548 nv_onattr(np,NV_RAW); 549 cp = nv_getval(np); 550 nv_offattr(np,NV_RAW); 551 } 552 else 553 cp = (char*)np->nvalue.cp; 554 if((size = n)==0) 555 size = strlen(cp); 556 size = sfwrite(iop, cp, size); 557 return(n?n:size); 558 } 559 } 560 else if(nv_isarray(np) && (ap=nv_arrayptr(np)) && (ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN))) 561 { 562 nv_outnode(np,iop,(alt?-1:0),0); 563 sfputc(iop,')'); 564 return(sftell(iop)); 565 } 566 else 567 { 568 if(alt && nv_isvtree(np)) 569 nv_onattr(np,NV_EXPORT); 570 else 571 alt = 0; 572 cp = nv_getval(np); 573 if(alt) 574 nv_offattr(np,NV_EXPORT); 575 if(!cp) 576 return(0); 577 size = strlen(cp); 578 return(sfwrite(iop,cp,size)); 579 } 580#else 581 nv_onattr(np,NV_RAW); 582 cp = nv_getval(np); 583 if(nv_isattr(np,NV_BINARY)) 584 nv_offattr(np,NV_RAW); 585 if((size = nv_size(np))==0) 586 size = strlen(cp); 587 if(sz) 588 *sz = size; 589 return((void*)cp); 590#endif 591} 592 593static int varname(const char *str, int n) 594{ 595 register int c,dot=1,len=1; 596 if(n < 0) 597 { 598 if(*str=='.') 599 str++; 600 n = strlen(str); 601 } 602 for(;n > 0; n-=len) 603 { 604#ifdef SHOPT_MULTIBYTE 605 len = mbsize(str); 606 c = mbchar(str); 607#else 608 c = *(unsigned char*)str++; 609#endif 610 if(dot && !(isalpha(c)||c=='_')) 611 break; 612 else if(dot==0 && !(isalnum(c) || c=='_' || c == '.')) 613 break; 614 dot = (c=='.'); 615 } 616 return(n==0); 617} 618 619static int extend(Sfio_t* sp, void* v, Sffmt_t* fe) 620{ 621 char* lastchar = ""; 622 register int neg = 0; 623 Sfdouble_t d; 624 Sfdouble_t longmin = LDBL_LLONG_MIN; 625 Sfdouble_t longmax = LDBL_LLONG_MAX; 626 int format = fe->fmt; 627 int n; 628 int fold = fe->base; 629 union types_t* value = (union types_t*)v; 630 struct printf* pp = (struct printf*)fe; 631 Shell_t *shp = pp->sh; 632 register char* argp = *pp->nextarg; 633 char* w; 634 635 if(fe->n_str>0 && varname(fe->t_str,fe->n_str) && (!argp || varname(argp,-1))) 636 { 637 if(argp) 638 pp->lastarg = argp; 639 else 640 argp = pp->lastarg; 641 if(argp) 642 { 643 sfprintf(pp->sh->strbuf,"%s.%.*s%c",argp,fe->n_str,fe->t_str,0); 644 argp = sfstruse(pp->sh->strbuf); 645 } 646 } 647 else 648 pp->lastarg = 0; 649 fe->flags |= SFFMT_VALUE; 650 if(!argp || format=='Z') 651 { 652 switch(format) 653 { 654 case 'c': 655 value->c = 0; 656 fe->flags &= ~SFFMT_LONG; 657 break; 658 case 'q': 659 format = 's'; 660 /* FALL THROUGH */ 661 case 's': 662 case 'H': 663 case 'B': 664 case 'P': 665 case 'R': 666 case 'Z': 667 case 'b': 668 fe->fmt = 's'; 669 fe->size = -1; 670 fe->base = -1; 671 value->s = ""; 672 fe->flags &= ~SFFMT_LONG; 673 break; 674 case 'a': 675 case 'e': 676 case 'f': 677 case 'g': 678 case 'A': 679 case 'E': 680 case 'F': 681 case 'G': 682 if(SFFMT_LDOUBLE) 683 value->ld = 0.; 684 else 685 value->d = 0.; 686 break; 687 case 'n': 688 value->ip = &pp->intvar; 689 break; 690 case 'Q': 691 value->ll = 0; 692 break; 693 case 'T': 694 fe->fmt = 'd'; 695 value->ll = tmxgettime(); 696 break; 697 default: 698 if(!strchr("DdXxoUu",format)) 699 errormsg(SH_DICT,ERROR_exit(1),e_formspec,format); 700 fe->fmt = 'd'; 701 value->ll = 0; 702 break; 703 } 704 } 705 else 706 { 707 switch(format) 708 { 709 case 'p': 710 value->p = (char**)strtol(argp,&lastchar,10); 711 break; 712 case 'n': 713 { 714 Namval_t *np; 715 np = nv_open(argp,shp->var_tree,NV_VARNAME|NV_NOASSIGN|NV_NOARRAY); 716 _nv_unset(np,0); 717 nv_onattr(np,NV_INTEGER); 718 if (np->nvalue.lp = new_of(int32_t,0)) 719 *np->nvalue.lp = 0; 720 nv_setsize(np,10); 721 if(sizeof(int)==sizeof(int32_t)) 722 value->ip = (int*)np->nvalue.lp; 723 else 724 { 725 int32_t sl = 1; 726 value->ip = (int*)(((char*)np->nvalue.lp) + (*((char*)&sl) ? 0 : sizeof(int))); 727 } 728 nv_close(np); 729 break; 730 } 731 case 'q': 732 case 'b': 733 case 's': 734 case 'B': 735 case 'H': 736 case 'P': 737 case 'R': 738 fe->fmt = 's'; 739 fe->size = -1; 740 if(format=='s' && fe->base>=0) 741 { 742 value->p = pp->nextarg; 743 pp->nextarg = nullarg; 744 } 745 else 746 { 747 fe->base = -1; 748 value->s = argp; 749 } 750 fe->flags &= ~SFFMT_LONG; 751 break; 752 case 'c': 753 if(mbwide() && (n = mbsize(argp)) > 1) 754 { 755 fe->fmt = 's'; 756 fe->size = n; 757 value->s = argp; 758 } 759 else if(fe->base >=0) 760 value->s = argp; 761 else 762 value->c = *argp; 763 fe->flags &= ~SFFMT_LONG; 764 break; 765 case 'o': 766 case 'x': 767 case 'X': 768 case 'u': 769 case 'U': 770 longmax = LDBL_ULLONG_MAX; 771 case '.': 772 if(fe->size==2 && strchr("bcsqHPRQTZ",*fe->form)) 773 { 774 value->ll = ((unsigned char*)argp)[0]; 775 break; 776 } 777 case 'd': 778 case 'D': 779 case 'i': 780 switch(*argp) 781 { 782 case '\'': 783 case '"': 784 w = argp + 1; 785 if(mbwide() && mbsize(w) > 1) 786 value->ll = mbchar(w); 787 else 788 value->ll = *(unsigned char*)w++; 789 if(w[0] && (w[0] != argp[0] || w[1])) 790 { 791 errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp); 792 pp->err = 1; 793 } 794 break; 795 default: 796 d = sh_strnum(argp,&lastchar,0); 797 if(d<longmin) 798 { 799 errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp); 800 pp->err = 1; 801 d = longmin; 802 } 803 else if(d>longmax) 804 { 805 errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp); 806 pp->err = 1; 807 d = longmax; 808 } 809 value->ll = (Sflong_t)d; 810 if(lastchar == *pp->nextarg) 811 { 812 value->ll = *argp; 813 lastchar = ""; 814 } 815 break; 816 } 817 if(neg) 818 value->ll = -value->ll; 819 fe->size = sizeof(value->ll); 820 break; 821 case 'a': 822 case 'e': 823 case 'f': 824 case 'g': 825 case 'A': 826 case 'E': 827 case 'F': 828 case 'G': 829 d = sh_strnum(*pp->nextarg,&lastchar,0); 830 switch(*argp) 831 { 832 case '\'': 833 case '"': 834 d = ((unsigned char*)argp)[1]; 835 if(argp[2] && (argp[2] != argp[0] || argp[3])) 836 { 837 errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp); 838 pp->err = 1; 839 } 840 break; 841 default: 842 d = sh_strnum(*pp->nextarg,&lastchar,0); 843 break; 844 } 845 if(SFFMT_LDOUBLE) 846 { 847 value->ld = d; 848 fe->size = sizeof(value->ld); 849 } 850 else 851 { 852 value->d = d; 853 fe->size = sizeof(value->d); 854 } 855 break; 856 case 'Q': 857 value->ll = (Sflong_t)strelapsed(*pp->nextarg,&lastchar,1); 858 break; 859 case 'T': 860 value->ll = (Sflong_t)tmxdate(*pp->nextarg,&lastchar,TMX_NOW); 861 break; 862 default: 863 value->ll = 0; 864 fe->fmt = 'd'; 865 fe->size = sizeof(value->ll); 866 errormsg(SH_DICT,ERROR_exit(1),e_formspec,format); 867 break; 868 } 869 if (format == '.') 870 value->i = value->ll; 871 if(*lastchar) 872 { 873 errormsg(SH_DICT,ERROR_warn(0),e_argtype,format); 874 pp->err = 1; 875 } 876 pp->nextarg++; 877 } 878 switch(format) 879 { 880 case 'Z': 881 fe->fmt = 'c'; 882 fe->base = -1; 883 value->c = 0; 884 break; 885 case 'b': 886 if((n=fmtvecho(value->s,pp))>=0) 887 { 888 if(pp->nextarg == nullarg) 889 { 890 pp->argsize = n; 891 return -1; 892 } 893 value->s = stakptr(staktell()); 894 fe->size = n; 895 } 896 break; 897 case 'B': 898 if(!shp->strbuf2) 899 shp->strbuf2 = sfstropen(); 900 fe->size = fmtbase64(shp->strbuf2,value->s, fe->flags&SFFMT_ALTER); 901 value->s = sfstruse(shp->strbuf2); 902 fe->flags |= SFFMT_SHORT; 903 break; 904 case 'H': 905 value->s = fmthtml(value->s); 906 break; 907 case 'q': 908 value->s = sh_fmtqf(value->s, !!(fe->flags & SFFMT_ALTER), fold); 909 break; 910 case 'P': 911 { 912 char *s = fmtmatch(value->s); 913 if(!s || *s==0) 914 errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s); 915 value->s = s; 916 break; 917 } 918 case 'R': 919 value->s = fmtre(value->s); 920 if(*value->s==0) 921 errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s); 922 break; 923 case 'Q': 924 if (fe->n_str>0) 925 { 926 fe->fmt = 'd'; 927 fe->size = sizeof(value->ll); 928 } 929 else 930 { 931 value->s = fmtelapsed(value->ll, 1); 932 fe->fmt = 's'; 933 fe->size = -1; 934 } 935 break; 936 case 'T': 937 if(fe->n_str>0) 938 { 939 n = fe->t_str[fe->n_str]; 940 fe->t_str[fe->n_str] = 0; 941 value->s = fmttmx(fe->t_str, value->ll); 942 fe->t_str[fe->n_str] = n; 943 } 944 else value->s = fmttmx(NIL(char*), value->ll); 945 fe->fmt = 's'; 946 fe->size = -1; 947 break; 948 } 949 return 0; 950} 951 952/* 953 * construct System V echo string out of <cp> 954 * If there are not escape sequences, returns -1 955 * Otherwise, puts null terminated result on stack, but doesn't freeze it 956 * returns length of output. 957 */ 958 959static int fmtvecho(const char *string, struct printf *pp) 960{ 961 register const char *cp = string, *cpmax; 962 register int c; 963 register int offset = staktell(); 964#if SHOPT_MULTIBYTE 965 int chlen; 966 if(mbwide()) 967 { 968 while(1) 969 { 970 if ((chlen = mbsize(cp)) > 1) 971 /* Skip over multibyte characters */ 972 cp += chlen; 973 else if((c= *cp++)==0 || c == '\\') 974 break; 975 } 976 } 977 else 978#endif /* SHOPT_MULTIBYTE */ 979 while((c= *cp++) && (c!='\\')); 980 if(c==0) 981 return(-1); 982 c = --cp - string; 983 if(c>0) 984 stakwrite((void*)string,c); 985 for(; c= *cp; cp++) 986 { 987#if SHOPT_MULTIBYTE 988 if (mbwide() && ((chlen = mbsize(cp)) > 1)) 989 { 990 stakwrite(cp,chlen); 991 cp += (chlen-1); 992 continue; 993 } 994#endif /* SHOPT_MULTIBYTE */ 995 if( c=='\\') switch(*++cp) 996 { 997 case 'E': 998 c = ('a'==97?'\033':39); /* ASCII/EBCDIC */ 999 break; 1000 case 'a': 1001 c = '\a'; 1002 break; 1003 case 'b': 1004 c = '\b'; 1005 break; 1006 case 'c': 1007 pp->cescape++; 1008 pp->nextarg = nullarg; 1009 goto done; 1010 case 'f': 1011 c = '\f'; 1012 break; 1013 case 'n': 1014 c = '\n'; 1015 break; 1016 case 'r': 1017 c = '\r'; 1018 break; 1019 case 'v': 1020 c = '\v'; 1021 break; 1022 case 't': 1023 c = '\t'; 1024 break; 1025 case '\\': 1026 c = '\\'; 1027 break; 1028 case '0': 1029 c = 0; 1030 cpmax = cp + 4; 1031 while(++cp<cpmax && *cp>='0' && *cp<='7') 1032 { 1033 c <<= 3; 1034 c |= (*cp-'0'); 1035 } 1036 default: 1037 cp--; 1038 } 1039 stakputc(c); 1040 } 1041done: 1042 c = staktell()-offset; 1043 stakputc(0); 1044 stakseek(offset); 1045 return(c); 1046} 1047