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