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