1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4b30d1939SAndy Fiddaman * Copyright (c) 1982-2012 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6b30d1939SAndy Fiddaman * Eclipse Public License, Version 1.0 * 77c2fbfb3SApril Chin * by AT&T Intellectual Property * 8da2e3ebdSchin * * 9da2e3ebdSchin * A copy of the License is available at * 10b30d1939SAndy Fiddaman * http://www.eclipse.org/org/documents/epl-v10.html * 11b30d1939SAndy Fiddaman * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12da2e3ebdSchin * * 13da2e3ebdSchin * Information and Software Systems Research * 14da2e3ebdSchin * AT&T Research * 15da2e3ebdSchin * Florham Park NJ * 16da2e3ebdSchin * * 17da2e3ebdSchin * David Korn <dgk@research.att.com> * 18da2e3ebdSchin * * 19da2e3ebdSchin ***********************************************************************/ 20da2e3ebdSchin #pragma prototyped 21da2e3ebdSchin /* 22da2e3ebdSchin * echo [arg...] 23da2e3ebdSchin * print [-nrps] [-f format] [-u filenum] [arg...] 24da2e3ebdSchin * printf format [arg...] 25da2e3ebdSchin * 26da2e3ebdSchin * David Korn 27da2e3ebdSchin * AT&T Labs 28da2e3ebdSchin */ 29da2e3ebdSchin 30da2e3ebdSchin #include "defs.h" 31da2e3ebdSchin #include <error.h> 32da2e3ebdSchin #include <stak.h> 33da2e3ebdSchin #include "io.h" 34da2e3ebdSchin #include "name.h" 35da2e3ebdSchin #include "history.h" 36da2e3ebdSchin #include "builtins.h" 37da2e3ebdSchin #include "streval.h" 38da2e3ebdSchin #include <tmx.h> 39da2e3ebdSchin #include <ccode.h> 40da2e3ebdSchin 41da2e3ebdSchin union types_t 42da2e3ebdSchin { 43da2e3ebdSchin unsigned char c; 44da2e3ebdSchin short h; 45da2e3ebdSchin int i; 46da2e3ebdSchin long l; 47da2e3ebdSchin Sflong_t ll; 48da2e3ebdSchin Sfdouble_t ld; 49da2e3ebdSchin double d; 50da2e3ebdSchin float f; 51da2e3ebdSchin char *s; 52da2e3ebdSchin int *ip; 53da2e3ebdSchin char **p; 54da2e3ebdSchin }; 55da2e3ebdSchin 56da2e3ebdSchin struct printf 57da2e3ebdSchin { 58da2e3ebdSchin Sffmt_t hdr; 59da2e3ebdSchin int argsize; 60da2e3ebdSchin int intvar; 61da2e3ebdSchin char **nextarg; 627c2fbfb3SApril Chin char *lastarg; 63da2e3ebdSchin char cescape; 64da2e3ebdSchin char err; 65da2e3ebdSchin Shell_t *sh; 66da2e3ebdSchin }; 67da2e3ebdSchin 68b30d1939SAndy Fiddaman struct printmap 69b30d1939SAndy Fiddaman { 70b30d1939SAndy Fiddaman size_t size; 71b30d1939SAndy Fiddaman char *name; 72b30d1939SAndy Fiddaman char map[3]; 73b30d1939SAndy Fiddaman const char *description; 74b30d1939SAndy Fiddaman }; 75b30d1939SAndy Fiddaman 76b30d1939SAndy Fiddaman const struct printmap Pmap[] = 77b30d1939SAndy Fiddaman { 78b30d1939SAndy Fiddaman 3, "csv", "q+", "Equivalent to %#q", 79b30d1939SAndy Fiddaman 4, "html", "H", "Equivalent to %H", 80b30d1939SAndy Fiddaman 3, "ere", "R", "Equivalent to %R", 81b30d1939SAndy Fiddaman 7, "pattern","P", "Equivalent to %#P", 82b30d1939SAndy Fiddaman 3, "url", "H+", "Equivalent to %#H", 83b30d1939SAndy Fiddaman 0, 0, 0, 84b30d1939SAndy Fiddaman }; 85b30d1939SAndy Fiddaman 86b30d1939SAndy Fiddaman 87da2e3ebdSchin static int extend(Sfio_t*,void*, Sffmt_t*); 88da2e3ebdSchin static const char preformat[] = ""; 89da2e3ebdSchin static char *genformat(char*); 90da2e3ebdSchin static int fmtvecho(const char*, struct printf*); 917c2fbfb3SApril Chin static ssize_t fmtbase64(Sfio_t*, char*, int); 92da2e3ebdSchin 93da2e3ebdSchin struct print 94da2e3ebdSchin { 95da2e3ebdSchin Shell_t *sh; 96da2e3ebdSchin const char *options; 97da2e3ebdSchin char raw; 98da2e3ebdSchin char echon; 99da2e3ebdSchin }; 100da2e3ebdSchin 101da2e3ebdSchin static char* nullarg[] = { 0, 0 }; 102da2e3ebdSchin 103da2e3ebdSchin #if !SHOPT_ECHOPRINT 104b30d1939SAndy Fiddaman int B_echo(int argc, char *argv[],Shbltin_t *context) 105da2e3ebdSchin { 106da2e3ebdSchin static char bsd_univ; 107da2e3ebdSchin struct print prdata; 108da2e3ebdSchin prdata.options = sh_optecho+5; 109da2e3ebdSchin prdata.raw = prdata.echon = 0; 110b30d1939SAndy Fiddaman prdata.sh = context->shp; 111da2e3ebdSchin NOT_USED(argc); 112da2e3ebdSchin /* This mess is because /bin/echo on BSD is different */ 113da2e3ebdSchin if(!prdata.sh->universe) 114da2e3ebdSchin { 115da2e3ebdSchin register char *universe; 116da2e3ebdSchin if(universe=astconf("UNIVERSE",0,0)) 117da2e3ebdSchin bsd_univ = (strcmp(universe,"ucb")==0); 118da2e3ebdSchin prdata.sh->universe = 1; 119da2e3ebdSchin } 120da2e3ebdSchin if(!bsd_univ) 121b30d1939SAndy Fiddaman return(b_print(0,argv,(Shbltin_t*)&prdata)); 122da2e3ebdSchin prdata.options = sh_optecho; 123da2e3ebdSchin prdata.raw = 1; 124da2e3ebdSchin while(argv[1] && *argv[1]=='-') 125da2e3ebdSchin { 126da2e3ebdSchin if(strcmp(argv[1],"-n")==0) 127da2e3ebdSchin prdata.echon = 1; 128da2e3ebdSchin #if !SHOPT_ECHOE 129da2e3ebdSchin else if(strcmp(argv[1],"-e")==0) 130da2e3ebdSchin prdata.raw = 0; 131da2e3ebdSchin else if(strcmp(argv[1],"-ne")==0 || strcmp(argv[1],"-en")==0) 132da2e3ebdSchin { 133da2e3ebdSchin prdata.raw = 0; 134da2e3ebdSchin prdata.echon = 1; 135da2e3ebdSchin } 136da2e3ebdSchin #endif /* SHOPT_ECHOE */ 137da2e3ebdSchin else 138da2e3ebdSchin break; 139da2e3ebdSchin argv++; 140da2e3ebdSchin } 141b30d1939SAndy Fiddaman return(b_print(0,argv,(Shbltin_t*)&prdata)); 142da2e3ebdSchin } 143da2e3ebdSchin #endif /* SHOPT_ECHOPRINT */ 144da2e3ebdSchin 145b30d1939SAndy Fiddaman int b_printf(int argc, char *argv[],Shbltin_t *context) 146da2e3ebdSchin { 147da2e3ebdSchin struct print prdata; 148da2e3ebdSchin NOT_USED(argc); 149da2e3ebdSchin memset(&prdata,0,sizeof(prdata)); 150b30d1939SAndy Fiddaman prdata.sh = context->shp; 151da2e3ebdSchin prdata.options = sh_optprintf; 152b30d1939SAndy Fiddaman return(b_print(-1,argv,(Shbltin_t*)&prdata)); 153b30d1939SAndy Fiddaman } 154b30d1939SAndy Fiddaman 155b30d1939SAndy Fiddaman static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) 156b30d1939SAndy Fiddaman { 157b30d1939SAndy Fiddaman const struct printmap *pm; 158b30d1939SAndy Fiddaman char c='%'; 159b30d1939SAndy Fiddaman for(pm=Pmap;pm->size>0;pm++) 160b30d1939SAndy Fiddaman { 161b30d1939SAndy Fiddaman sfprintf(sp, "[+%c(%s)q?%s.]",c,pm->name,pm->description); 162b30d1939SAndy Fiddaman } 163b30d1939SAndy Fiddaman return(1); 164da2e3ebdSchin } 165da2e3ebdSchin 166da2e3ebdSchin /* 167da2e3ebdSchin * argc==0 when called from echo 168da2e3ebdSchin * argc==-1 when called from printf 169da2e3ebdSchin */ 170da2e3ebdSchin 171b30d1939SAndy Fiddaman int b_print(int argc, char *argv[], Shbltin_t *context) 172da2e3ebdSchin { 173da2e3ebdSchin register Sfio_t *outfile; 174da2e3ebdSchin register int exitval=0,n, fd = 1; 175b30d1939SAndy Fiddaman register Shell_t *shp = context->shp; 176da2e3ebdSchin const char *options, *msg = e_file+4; 177da2e3ebdSchin char *format = 0; 1787c2fbfb3SApril Chin int sflag = 0, nflag=0, rflag=0, vflag=0; 179b30d1939SAndy Fiddaman Optdisc_t disc; 180b30d1939SAndy Fiddaman disc.version = OPT_VERSION; 181b30d1939SAndy Fiddaman disc.infof = infof; 182b30d1939SAndy Fiddaman opt_info.disc = &disc; 183da2e3ebdSchin if(argc>0) 184da2e3ebdSchin { 185da2e3ebdSchin options = sh_optprint; 186da2e3ebdSchin nflag = rflag = 0; 187da2e3ebdSchin format = 0; 188da2e3ebdSchin } 189da2e3ebdSchin else 190da2e3ebdSchin { 191b30d1939SAndy Fiddaman struct print *pp = (struct print*)context; 192da2e3ebdSchin shp = pp->sh; 193da2e3ebdSchin options = pp->options; 194da2e3ebdSchin if(argc==0) 195da2e3ebdSchin { 196da2e3ebdSchin nflag = pp->echon; 197da2e3ebdSchin rflag = pp->raw; 198da2e3ebdSchin argv++; 199da2e3ebdSchin goto skip; 200da2e3ebdSchin } 201*f9bbf53bSAndy Fiddaman argv++; 202*f9bbf53bSAndy Fiddaman goto printf; 203da2e3ebdSchin } 204da2e3ebdSchin while((n = optget(argv,options))) switch(n) 205da2e3ebdSchin { 206da2e3ebdSchin case 'n': 207da2e3ebdSchin nflag++; 208da2e3ebdSchin break; 209da2e3ebdSchin case 'p': 210da2e3ebdSchin fd = shp->coutpipe; 211da2e3ebdSchin msg = e_query; 212da2e3ebdSchin break; 213da2e3ebdSchin case 'f': 214da2e3ebdSchin format = opt_info.arg; 215da2e3ebdSchin break; 216da2e3ebdSchin case 's': 217da2e3ebdSchin /* print to history file */ 2187c2fbfb3SApril Chin if(!sh_histinit((void*)shp)) 219da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_history); 220b30d1939SAndy Fiddaman fd = sffileno(shp->gd->hist_ptr->histfp); 221da2e3ebdSchin sh_onstate(SH_HISTORY); 222da2e3ebdSchin sflag++; 223da2e3ebdSchin break; 224da2e3ebdSchin case 'e': 225da2e3ebdSchin rflag = 0; 226da2e3ebdSchin break; 227da2e3ebdSchin case 'r': 228da2e3ebdSchin rflag = 1; 229da2e3ebdSchin break; 230da2e3ebdSchin case 'u': 231da2e3ebdSchin fd = (int)strtol(opt_info.arg,&opt_info.arg,10); 232da2e3ebdSchin if(*opt_info.arg) 233da2e3ebdSchin fd = -1; 234b30d1939SAndy Fiddaman else if(!sh_iovalidfd(shp,fd)) 235da2e3ebdSchin fd = -1; 236b30d1939SAndy Fiddaman else if(!(shp->inuse_bits&(1<<fd)) && (sh_inuse(shp,fd) || (shp->gd->hist_ptr && fd==sffileno(shp->gd->hist_ptr->histfp)))) 237da2e3ebdSchin 238da2e3ebdSchin fd = -1; 239da2e3ebdSchin break; 2407c2fbfb3SApril Chin case 'v': 24134f9b3eeSRoland Mainz vflag='v'; 24234f9b3eeSRoland Mainz break; 24334f9b3eeSRoland Mainz case 'C': 24434f9b3eeSRoland Mainz vflag='C'; 2457c2fbfb3SApril Chin break; 246da2e3ebdSchin case ':': 247da2e3ebdSchin /* The following is for backward compatibility */ 248da2e3ebdSchin #if OPT_VERSION >= 19990123 249da2e3ebdSchin if(strcmp(opt_info.name,"-R")==0) 250da2e3ebdSchin #else 251da2e3ebdSchin if(strcmp(opt_info.option,"-R")==0) 252da2e3ebdSchin #endif 253da2e3ebdSchin { 254da2e3ebdSchin rflag = 1; 255da2e3ebdSchin if(error_info.errors==0) 256da2e3ebdSchin { 257da2e3ebdSchin argv += opt_info.index+1; 258da2e3ebdSchin /* special case test for -Rn */ 259da2e3ebdSchin if(strchr(argv[-1],'n')) 260da2e3ebdSchin nflag++; 261da2e3ebdSchin if(*argv && strcmp(*argv,"-n")==0) 262da2e3ebdSchin { 263da2e3ebdSchin 264da2e3ebdSchin nflag++; 265da2e3ebdSchin argv++; 266da2e3ebdSchin } 267da2e3ebdSchin goto skip2; 268da2e3ebdSchin } 269da2e3ebdSchin } 270da2e3ebdSchin else 271da2e3ebdSchin errormsg(SH_DICT,2, "%s", opt_info.arg); 272da2e3ebdSchin break; 273da2e3ebdSchin case '?': 274da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 275da2e3ebdSchin break; 276da2e3ebdSchin } 277da2e3ebdSchin argv += opt_info.index; 278*f9bbf53bSAndy Fiddaman printf: 279da2e3ebdSchin if(error_info.errors || (argc<0 && !(format = *argv++))) 280da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); 2817c2fbfb3SApril Chin if(vflag && format) 28234f9b3eeSRoland Mainz errormsg(SH_DICT,ERROR_usage(2),"-%c and -f are mutually exclusive",vflag); 283da2e3ebdSchin skip: 284da2e3ebdSchin if(format) 285da2e3ebdSchin format = genformat(format); 286da2e3ebdSchin /* handle special case of '-' operand for print */ 287da2e3ebdSchin if(argc>0 && *argv && strcmp(*argv,"-")==0 && strcmp(argv[-1],"--")) 288da2e3ebdSchin argv++; 289da2e3ebdSchin skip2: 290da2e3ebdSchin if(fd < 0) 291da2e3ebdSchin { 292da2e3ebdSchin errno = EBADF; 293da2e3ebdSchin n = 0; 294da2e3ebdSchin } 295da2e3ebdSchin else if(!(n=shp->fdstatus[fd])) 2967c2fbfb3SApril Chin n = sh_iocheckfd(shp,fd); 297da2e3ebdSchin if(!(n&IOWRITE)) 298da2e3ebdSchin { 299da2e3ebdSchin /* don't print error message for stdout for compatibility */ 300da2e3ebdSchin if(fd==1) 301da2e3ebdSchin return(1); 302da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),msg); 303da2e3ebdSchin } 304da2e3ebdSchin if(!(outfile=shp->sftable[fd])) 305da2e3ebdSchin { 306da2e3ebdSchin sh_onstate(SH_NOTRACK); 307da2e3ebdSchin n = SF_WRITE|((n&IOREAD)?SF_READ:0); 308da2e3ebdSchin shp->sftable[fd] = outfile = sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fd,n); 309da2e3ebdSchin sh_offstate(SH_NOTRACK); 310da2e3ebdSchin sfpool(outfile,shp->outpool,SF_WRITE); 311da2e3ebdSchin } 312da2e3ebdSchin /* turn off share to guarantee atomic writes for printf */ 313da2e3ebdSchin n = sfset(outfile,SF_SHARE|SF_PUBLIC,0); 314da2e3ebdSchin if(format) 315da2e3ebdSchin { 316da2e3ebdSchin /* printf style print */ 317da2e3ebdSchin Sfio_t *pool; 318da2e3ebdSchin struct printf pdata; 319da2e3ebdSchin memset(&pdata, 0, sizeof(pdata)); 320da2e3ebdSchin pdata.sh = shp; 321da2e3ebdSchin pdata.hdr.version = SFIO_VERSION; 322da2e3ebdSchin pdata.hdr.extf = extend; 323da2e3ebdSchin pdata.nextarg = argv; 324da2e3ebdSchin sh_offstate(SH_STOPOK); 325da2e3ebdSchin pool=sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE); 326da2e3ebdSchin do 327da2e3ebdSchin { 328da2e3ebdSchin if(shp->trapnote&SH_SIGSET) 329da2e3ebdSchin break; 330da2e3ebdSchin pdata.hdr.form = format; 331da2e3ebdSchin sfprintf(outfile,"%!",&pdata); 332da2e3ebdSchin } while(*pdata.nextarg && pdata.nextarg!=argv); 333da2e3ebdSchin if(pdata.nextarg == nullarg && pdata.argsize>0) 334da2e3ebdSchin sfwrite(outfile,stakptr(staktell()),pdata.argsize); 33534f9b3eeSRoland Mainz if(sffileno(outfile)!=sffileno(sfstderr)) 33634f9b3eeSRoland Mainz sfsync(outfile); 337da2e3ebdSchin sfpool(sfstderr,pool,SF_WRITE); 338da2e3ebdSchin exitval = pdata.err; 339da2e3ebdSchin } 3407c2fbfb3SApril Chin else if(vflag) 3417c2fbfb3SApril Chin { 3427c2fbfb3SApril Chin while(*argv) 34334f9b3eeSRoland Mainz { 34434f9b3eeSRoland Mainz fmtbase64(outfile,*argv++,vflag=='C'); 34534f9b3eeSRoland Mainz if(!nflag) 34634f9b3eeSRoland Mainz sfputc(outfile,'\n'); 34734f9b3eeSRoland Mainz } 3487c2fbfb3SApril Chin } 349da2e3ebdSchin else 350da2e3ebdSchin { 351da2e3ebdSchin /* echo style print */ 3527c2fbfb3SApril Chin if(nflag && !argv[0]) 3537c2fbfb3SApril Chin sfsync((Sfio_t*)0); 354b30d1939SAndy Fiddaman else if(sh_echolist(shp,outfile,rflag,argv) && !nflag) 355da2e3ebdSchin sfputc(outfile,'\n'); 356da2e3ebdSchin } 357da2e3ebdSchin if(sflag) 358da2e3ebdSchin { 359b30d1939SAndy Fiddaman hist_flush(shp->gd->hist_ptr); 360da2e3ebdSchin sh_offstate(SH_HISTORY); 361da2e3ebdSchin } 362da2e3ebdSchin else if(n&SF_SHARE) 363da2e3ebdSchin { 364da2e3ebdSchin sfset(outfile,SF_SHARE|SF_PUBLIC,1); 365da2e3ebdSchin sfsync(outfile); 366da2e3ebdSchin } 367da2e3ebdSchin return(exitval); 368da2e3ebdSchin } 369da2e3ebdSchin 370da2e3ebdSchin /* 371da2e3ebdSchin * echo the argument list onto <outfile> 372da2e3ebdSchin * if <raw> is non-zero then \ is not a special character. 373da2e3ebdSchin * returns 0 for \c otherwise 1. 374da2e3ebdSchin */ 375da2e3ebdSchin 376b30d1939SAndy Fiddaman int sh_echolist(Shell_t *shp,Sfio_t *outfile, int raw, char *argv[]) 377da2e3ebdSchin { 378da2e3ebdSchin register char *cp; 379da2e3ebdSchin register int n; 380da2e3ebdSchin struct printf pdata; 381da2e3ebdSchin pdata.cescape = 0; 382da2e3ebdSchin pdata.err = 0; 383da2e3ebdSchin while(!pdata.cescape && (cp= *argv++)) 384da2e3ebdSchin { 385da2e3ebdSchin if(!raw && (n=fmtvecho(cp,&pdata))>=0) 386da2e3ebdSchin { 387da2e3ebdSchin if(n) 388da2e3ebdSchin sfwrite(outfile,stakptr(staktell()),n); 389da2e3ebdSchin } 390da2e3ebdSchin else 391da2e3ebdSchin sfputr(outfile,cp,-1); 392da2e3ebdSchin if(*argv) 393da2e3ebdSchin sfputc(outfile,' '); 394b30d1939SAndy Fiddaman sh_sigcheck(shp); 395da2e3ebdSchin } 396da2e3ebdSchin return(!pdata.cescape); 397da2e3ebdSchin } 398da2e3ebdSchin 399da2e3ebdSchin /* 400da2e3ebdSchin * modified version of stresc for generating formats 401da2e3ebdSchin */ 402da2e3ebdSchin static char strformat(char *s) 403da2e3ebdSchin { 404da2e3ebdSchin register char* t; 405da2e3ebdSchin register int c; 406da2e3ebdSchin char* b; 407da2e3ebdSchin char* p; 408b30d1939SAndy Fiddaman #if SHOPT_MULTIBYTE && defined(FMT_EXP_WIDE) 409b30d1939SAndy Fiddaman int w; 410b30d1939SAndy Fiddaman #endif 411da2e3ebdSchin 412da2e3ebdSchin b = t = s; 413da2e3ebdSchin for (;;) 414da2e3ebdSchin { 415da2e3ebdSchin switch (c = *s++) 416da2e3ebdSchin { 417da2e3ebdSchin case '\\': 418da2e3ebdSchin if(*s==0) 419da2e3ebdSchin break; 420b30d1939SAndy Fiddaman #if SHOPT_MULTIBYTE && defined(FMT_EXP_WIDE) 421b30d1939SAndy Fiddaman c = chrexp(s - 1, &p, &w, FMT_EXP_CHAR|FMT_EXP_LINE|FMT_EXP_WIDE); 422b30d1939SAndy Fiddaman #else 423da2e3ebdSchin c = chresc(s - 1, &p); 424b30d1939SAndy Fiddaman #endif 425da2e3ebdSchin s = p; 426da2e3ebdSchin #if SHOPT_MULTIBYTE 427b30d1939SAndy Fiddaman #if defined(FMT_EXP_WIDE) 428b30d1939SAndy Fiddaman if(w) 429b30d1939SAndy Fiddaman { 430b30d1939SAndy Fiddaman t += mbwide() ? mbconv(t, c) : wc2utf8(t, c); 431b30d1939SAndy Fiddaman continue; 432b30d1939SAndy Fiddaman } 433b30d1939SAndy Fiddaman #else 434da2e3ebdSchin if(c>UCHAR_MAX && mbwide()) 435da2e3ebdSchin { 436b30d1939SAndy Fiddaman t += mbconv(t, c); 437da2e3ebdSchin continue; 438da2e3ebdSchin } 439b30d1939SAndy Fiddaman #endif /* FMT_EXP_WIDE */ 440da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */ 441da2e3ebdSchin if(c=='%') 442da2e3ebdSchin *t++ = '%'; 443da2e3ebdSchin else if(c==0) 444da2e3ebdSchin { 445da2e3ebdSchin *t++ = '%'; 446da2e3ebdSchin c = 'Z'; 447da2e3ebdSchin } 448da2e3ebdSchin break; 449da2e3ebdSchin case 0: 450da2e3ebdSchin *t = 0; 451da2e3ebdSchin return(t - b); 452da2e3ebdSchin } 453da2e3ebdSchin *t++ = c; 454da2e3ebdSchin } 455da2e3ebdSchin } 456da2e3ebdSchin 457da2e3ebdSchin 458da2e3ebdSchin static char *genformat(char *format) 459da2e3ebdSchin { 460da2e3ebdSchin register char *fp; 461da2e3ebdSchin stakseek(0); 462da2e3ebdSchin stakputs(preformat); 463da2e3ebdSchin stakputs(format); 464da2e3ebdSchin fp = (char*)stakfreeze(1); 465da2e3ebdSchin strformat(fp+sizeof(preformat)-1); 466da2e3ebdSchin return(fp); 467da2e3ebdSchin } 468da2e3ebdSchin 469b30d1939SAndy Fiddaman static char *fmthtml(const char *string, int flags) 470da2e3ebdSchin { 471da2e3ebdSchin register const char *cp = string; 472da2e3ebdSchin register int c, offset = staktell(); 473b30d1939SAndy Fiddaman if(!(flags&SFFMT_ALTER)) 474da2e3ebdSchin { 475b30d1939SAndy Fiddaman while(c= *(unsigned char*)cp++) 476b30d1939SAndy Fiddaman { 477da2e3ebdSchin #if SHOPT_MULTIBYTE 478b30d1939SAndy Fiddaman register int s; 479b30d1939SAndy Fiddaman if((s=mbsize(cp-1)) > 1) 480b30d1939SAndy Fiddaman { 481b30d1939SAndy Fiddaman cp += (s-1); 482b30d1939SAndy Fiddaman continue; 483b30d1939SAndy Fiddaman } 484b30d1939SAndy Fiddaman #endif /* SHOPT_MULTIBYTE */ 485b30d1939SAndy Fiddaman if(c=='<') 486b30d1939SAndy Fiddaman stakputs("<"); 487b30d1939SAndy Fiddaman else if(c=='>') 488b30d1939SAndy Fiddaman stakputs(">"); 489b30d1939SAndy Fiddaman else if(c=='&') 490b30d1939SAndy Fiddaman stakputs("&"); 491b30d1939SAndy Fiddaman else if(c=='"') 492b30d1939SAndy Fiddaman stakputs("""); 493b30d1939SAndy Fiddaman else if(c=='\'') 494b30d1939SAndy Fiddaman stakputs("'"); 495b30d1939SAndy Fiddaman else if(c==' ') 496b30d1939SAndy Fiddaman stakputs(" "); 497b30d1939SAndy Fiddaman else if(!isprint(c) && c!='\n' && c!='\r') 498b30d1939SAndy Fiddaman sfprintf(stkstd,"&#%X;",CCMAPC(c,CC_NATIVE,CC_ASCII)); 499b30d1939SAndy Fiddaman else 500b30d1939SAndy Fiddaman stakputc(c); 501b30d1939SAndy Fiddaman } 502b30d1939SAndy Fiddaman } 503b30d1939SAndy Fiddaman else 504b30d1939SAndy Fiddaman { 505b30d1939SAndy Fiddaman while(c= *(unsigned char*)cp++) 506da2e3ebdSchin { 507b30d1939SAndy Fiddaman if(strchr("!*'();@&+$,#[]<>~.\"{}|\\-`^% ",c) || (!isprint(c) && c!='\n' && c!='\r')) 508b30d1939SAndy Fiddaman sfprintf(stkstd,"%%%02X",CCMAPC(c,CC_NATIVE,CC_ASCII)); 509b30d1939SAndy Fiddaman else 510b30d1939SAndy Fiddaman stakputc(c); 511da2e3ebdSchin } 512da2e3ebdSchin } 513da2e3ebdSchin stakputc(0); 514da2e3ebdSchin return(stakptr(offset)); 515da2e3ebdSchin } 516da2e3ebdSchin 5177c2fbfb3SApril Chin #if 1 5187c2fbfb3SApril Chin static ssize_t fmtbase64(Sfio_t *iop, char *string, int alt) 5197c2fbfb3SApril Chin #else 5207c2fbfb3SApril Chin static void *fmtbase64(char *string, ssize_t *sz, int alt) 5217c2fbfb3SApril Chin #endif 522da2e3ebdSchin { 523da2e3ebdSchin char *cp; 524da2e3ebdSchin Sfdouble_t d; 5257c2fbfb3SApril Chin ssize_t size; 526da2e3ebdSchin Namval_t *np = nv_open(string, NiL, NV_VARNAME|NV_NOASSIGN|NV_NOADD); 527b30d1939SAndy Fiddaman Namarr_t *ap; 528da2e3ebdSchin static union types_t number; 5297c2fbfb3SApril Chin if(!np || nv_isnull(np)) 5307c2fbfb3SApril Chin { 5317c2fbfb3SApril Chin if(sh_isoption(SH_NOUNSET)) 5327c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_exit(1),e_notset,string); 5337c2fbfb3SApril Chin return(0); 5347c2fbfb3SApril Chin } 535da2e3ebdSchin if(nv_isattr(np,NV_INTEGER)) 536da2e3ebdSchin { 537da2e3ebdSchin d = nv_getnum(np); 538da2e3ebdSchin if(nv_isattr(np,NV_DOUBLE)) 539da2e3ebdSchin { 540da2e3ebdSchin if(nv_isattr(np,NV_LONG)) 541da2e3ebdSchin { 542da2e3ebdSchin size = sizeof(Sfdouble_t); 543da2e3ebdSchin number.ld = d; 544da2e3ebdSchin } 545da2e3ebdSchin else if(nv_isattr(np,NV_SHORT)) 546da2e3ebdSchin { 547da2e3ebdSchin size = sizeof(float); 548da2e3ebdSchin number.f = (float)d; 549da2e3ebdSchin } 550da2e3ebdSchin else 551da2e3ebdSchin { 552da2e3ebdSchin size = sizeof(double); 553da2e3ebdSchin number.d = (double)d; 554da2e3ebdSchin } 555da2e3ebdSchin } 556da2e3ebdSchin else 557da2e3ebdSchin { 558da2e3ebdSchin if(nv_isattr(np,NV_LONG)) 559da2e3ebdSchin { 560da2e3ebdSchin size = sizeof(Sflong_t); 561da2e3ebdSchin number.ll = (Sflong_t)d; 562da2e3ebdSchin } 563da2e3ebdSchin else if(nv_isattr(np,NV_SHORT)) 564da2e3ebdSchin { 565da2e3ebdSchin size = sizeof(short); 566da2e3ebdSchin number.h = (short)d; 567da2e3ebdSchin } 568da2e3ebdSchin else 569da2e3ebdSchin { 570da2e3ebdSchin size = sizeof(short); 571da2e3ebdSchin number.i = (int)d; 572da2e3ebdSchin } 573da2e3ebdSchin } 5747c2fbfb3SApril Chin #if 1 5757c2fbfb3SApril Chin return(sfwrite(iop, (void*)&number, size)); 5767c2fbfb3SApril Chin #else 577da2e3ebdSchin if(sz) 578da2e3ebdSchin *sz = size; 579da2e3ebdSchin return((void*)&number); 5807c2fbfb3SApril Chin #endif 581da2e3ebdSchin } 582da2e3ebdSchin if(nv_isattr(np,NV_BINARY)) 5837c2fbfb3SApril Chin #if 1 5847c2fbfb3SApril Chin { 5857c2fbfb3SApril Chin Namfun_t *fp; 5867c2fbfb3SApril Chin for(fp=np->nvfun; fp;fp=fp->next) 5877c2fbfb3SApril Chin { 5887c2fbfb3SApril Chin if(fp->disc && fp->disc->writef) 5897c2fbfb3SApril Chin break; 5907c2fbfb3SApril Chin } 5917c2fbfb3SApril Chin if(fp) 5927c2fbfb3SApril Chin return (*fp->disc->writef)(np, iop, 0, fp); 5937c2fbfb3SApril Chin else 5947c2fbfb3SApril Chin { 5957c2fbfb3SApril Chin int n = nv_size(np); 59634f9b3eeSRoland Mainz if(nv_isarray(np)) 59734f9b3eeSRoland Mainz { 59834f9b3eeSRoland Mainz nv_onattr(np,NV_RAW); 59934f9b3eeSRoland Mainz cp = nv_getval(np); 60034f9b3eeSRoland Mainz nv_offattr(np,NV_RAW); 60134f9b3eeSRoland Mainz } 60234f9b3eeSRoland Mainz else 60334f9b3eeSRoland Mainz cp = (char*)np->nvalue.cp; 6047c2fbfb3SApril Chin if((size = n)==0) 6057c2fbfb3SApril Chin size = strlen(cp); 6067c2fbfb3SApril Chin size = sfwrite(iop, cp, size); 6077c2fbfb3SApril Chin return(n?n:size); 6087c2fbfb3SApril Chin } 6097c2fbfb3SApril Chin } 610b30d1939SAndy Fiddaman else if(nv_isarray(np) && (ap=nv_arrayptr(np)) && array_elem(ap) && (ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN))) 6117c2fbfb3SApril Chin { 6127c2fbfb3SApril Chin nv_outnode(np,iop,(alt?-1:0),0); 6137c2fbfb3SApril Chin sfputc(iop,')'); 6147c2fbfb3SApril Chin return(sftell(iop)); 6157c2fbfb3SApril Chin } 6167c2fbfb3SApril Chin else 6177c2fbfb3SApril Chin { 6187c2fbfb3SApril Chin if(alt && nv_isvtree(np)) 6197c2fbfb3SApril Chin nv_onattr(np,NV_EXPORT); 620b30d1939SAndy Fiddaman else 621b30d1939SAndy Fiddaman alt = 0; 622b30d1939SAndy Fiddaman cp = nv_getval(np); 623b30d1939SAndy Fiddaman if(alt) 624b30d1939SAndy Fiddaman nv_offattr(np,NV_EXPORT); 625b30d1939SAndy Fiddaman if(!cp) 6267c2fbfb3SApril Chin return(0); 6277c2fbfb3SApril Chin size = strlen(cp); 6287c2fbfb3SApril Chin return(sfwrite(iop,cp,size)); 6297c2fbfb3SApril Chin } 6307c2fbfb3SApril Chin #else 631da2e3ebdSchin nv_onattr(np,NV_RAW); 632da2e3ebdSchin cp = nv_getval(np); 633da2e3ebdSchin if(nv_isattr(np,NV_BINARY)) 634da2e3ebdSchin nv_offattr(np,NV_RAW); 635da2e3ebdSchin if((size = nv_size(np))==0) 636da2e3ebdSchin size = strlen(cp); 637da2e3ebdSchin if(sz) 638da2e3ebdSchin *sz = size; 639da2e3ebdSchin return((void*)cp); 6407c2fbfb3SApril Chin #endif 6417c2fbfb3SApril Chin } 6427c2fbfb3SApril Chin 6437c2fbfb3SApril Chin static int varname(const char *str, int n) 6447c2fbfb3SApril Chin { 6457c2fbfb3SApril Chin register int c,dot=1,len=1; 6467c2fbfb3SApril Chin if(n < 0) 6477c2fbfb3SApril Chin { 6487c2fbfb3SApril Chin if(*str=='.') 6497c2fbfb3SApril Chin str++; 6507c2fbfb3SApril Chin n = strlen(str); 6517c2fbfb3SApril Chin } 6527c2fbfb3SApril Chin for(;n > 0; n-=len) 6537c2fbfb3SApril Chin { 6547c2fbfb3SApril Chin #ifdef SHOPT_MULTIBYTE 6557c2fbfb3SApril Chin len = mbsize(str); 6567c2fbfb3SApril Chin c = mbchar(str); 6577c2fbfb3SApril Chin #else 6587c2fbfb3SApril Chin c = *(unsigned char*)str++; 6597c2fbfb3SApril Chin #endif 6607c2fbfb3SApril Chin if(dot && !(isalpha(c)||c=='_')) 6617c2fbfb3SApril Chin break; 6627c2fbfb3SApril Chin else if(dot==0 && !(isalnum(c) || c=='_' || c == '.')) 6637c2fbfb3SApril Chin break; 6647c2fbfb3SApril Chin dot = (c=='.'); 6657c2fbfb3SApril Chin } 6667c2fbfb3SApril Chin return(n==0); 667da2e3ebdSchin } 668da2e3ebdSchin 669b30d1939SAndy Fiddaman static const char *mapformat(Sffmt_t *fe) 670b30d1939SAndy Fiddaman { 671b30d1939SAndy Fiddaman const struct printmap *pm = Pmap; 672b30d1939SAndy Fiddaman while(pm->size>0) 673b30d1939SAndy Fiddaman { 674b30d1939SAndy Fiddaman if(pm->size==fe->n_str && memcmp(pm->name,fe->t_str,fe->n_str)==0) 675b30d1939SAndy Fiddaman return(pm->map); 676b30d1939SAndy Fiddaman pm++; 677b30d1939SAndy Fiddaman } 678b30d1939SAndy Fiddaman return(0); 679b30d1939SAndy Fiddaman } 680b30d1939SAndy Fiddaman 681da2e3ebdSchin static int extend(Sfio_t* sp, void* v, Sffmt_t* fe) 682da2e3ebdSchin { 683da2e3ebdSchin char* lastchar = ""; 684da2e3ebdSchin register int neg = 0; 685da2e3ebdSchin Sfdouble_t d; 686da2e3ebdSchin Sfdouble_t longmin = LDBL_LLONG_MIN; 687da2e3ebdSchin Sfdouble_t longmax = LDBL_LLONG_MAX; 688da2e3ebdSchin int format = fe->fmt; 689da2e3ebdSchin int n; 690da2e3ebdSchin int fold = fe->base; 691da2e3ebdSchin union types_t* value = (union types_t*)v; 692da2e3ebdSchin struct printf* pp = (struct printf*)fe; 693b30d1939SAndy Fiddaman Shell_t *shp = pp->sh; 694da2e3ebdSchin register char* argp = *pp->nextarg; 695b30d1939SAndy Fiddaman char *w,*s; 696da2e3ebdSchin 697b30d1939SAndy Fiddaman if(fe->n_str>0 && (format=='T'||format=='Q') && varname(fe->t_str,fe->n_str) && (!argp || varname(argp,-1))) 6987c2fbfb3SApril Chin { 6997c2fbfb3SApril Chin if(argp) 7007c2fbfb3SApril Chin pp->lastarg = argp; 7017c2fbfb3SApril Chin else 7027c2fbfb3SApril Chin argp = pp->lastarg; 7037c2fbfb3SApril Chin if(argp) 7047c2fbfb3SApril Chin { 7057c2fbfb3SApril Chin sfprintf(pp->sh->strbuf,"%s.%.*s%c",argp,fe->n_str,fe->t_str,0); 7067c2fbfb3SApril Chin argp = sfstruse(pp->sh->strbuf); 7077c2fbfb3SApril Chin } 7087c2fbfb3SApril Chin } 7097c2fbfb3SApril Chin else 7107c2fbfb3SApril Chin pp->lastarg = 0; 711da2e3ebdSchin fe->flags |= SFFMT_VALUE; 712da2e3ebdSchin if(!argp || format=='Z') 713da2e3ebdSchin { 714da2e3ebdSchin switch(format) 715da2e3ebdSchin { 716da2e3ebdSchin case 'c': 717da2e3ebdSchin value->c = 0; 718da2e3ebdSchin fe->flags &= ~SFFMT_LONG; 719da2e3ebdSchin break; 720da2e3ebdSchin case 'q': 721da2e3ebdSchin format = 's'; 722da2e3ebdSchin /* FALL THROUGH */ 723da2e3ebdSchin case 's': 724da2e3ebdSchin case 'H': 725da2e3ebdSchin case 'B': 726da2e3ebdSchin case 'P': 727da2e3ebdSchin case 'R': 728da2e3ebdSchin case 'Z': 729da2e3ebdSchin case 'b': 730da2e3ebdSchin fe->fmt = 's'; 731da2e3ebdSchin fe->size = -1; 732da2e3ebdSchin fe->base = -1; 733da2e3ebdSchin value->s = ""; 734da2e3ebdSchin fe->flags &= ~SFFMT_LONG; 735da2e3ebdSchin break; 736da2e3ebdSchin case 'a': 737da2e3ebdSchin case 'e': 738da2e3ebdSchin case 'f': 739da2e3ebdSchin case 'g': 740da2e3ebdSchin case 'A': 741da2e3ebdSchin case 'E': 742da2e3ebdSchin case 'F': 743da2e3ebdSchin case 'G': 744da2e3ebdSchin if(SFFMT_LDOUBLE) 745da2e3ebdSchin value->ld = 0.; 746da2e3ebdSchin else 747da2e3ebdSchin value->d = 0.; 748da2e3ebdSchin break; 749da2e3ebdSchin case 'n': 750da2e3ebdSchin value->ip = &pp->intvar; 751da2e3ebdSchin break; 752da2e3ebdSchin case 'Q': 753da2e3ebdSchin value->ll = 0; 754da2e3ebdSchin break; 755da2e3ebdSchin case 'T': 756da2e3ebdSchin fe->fmt = 'd'; 757da2e3ebdSchin value->ll = tmxgettime(); 758da2e3ebdSchin break; 759da2e3ebdSchin default: 760da2e3ebdSchin if(!strchr("DdXxoUu",format)) 761da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_formspec,format); 762da2e3ebdSchin fe->fmt = 'd'; 763da2e3ebdSchin value->ll = 0; 764da2e3ebdSchin break; 765da2e3ebdSchin } 766da2e3ebdSchin } 767da2e3ebdSchin else 768da2e3ebdSchin { 769da2e3ebdSchin switch(format) 770da2e3ebdSchin { 771da2e3ebdSchin case 'p': 772da2e3ebdSchin value->p = (char**)strtol(argp,&lastchar,10); 773da2e3ebdSchin break; 774da2e3ebdSchin case 'n': 775da2e3ebdSchin { 776da2e3ebdSchin Namval_t *np; 777b30d1939SAndy Fiddaman np = nv_open(argp,shp->var_tree,NV_VARNAME|NV_NOASSIGN|NV_NOARRAY); 778b30d1939SAndy Fiddaman _nv_unset(np,0); 779da2e3ebdSchin nv_onattr(np,NV_INTEGER); 780da2e3ebdSchin if (np->nvalue.lp = new_of(int32_t,0)) 781da2e3ebdSchin *np->nvalue.lp = 0; 782da2e3ebdSchin nv_setsize(np,10); 783da2e3ebdSchin if(sizeof(int)==sizeof(int32_t)) 784da2e3ebdSchin value->ip = (int*)np->nvalue.lp; 785da2e3ebdSchin else 786da2e3ebdSchin { 787da2e3ebdSchin int32_t sl = 1; 788da2e3ebdSchin value->ip = (int*)(((char*)np->nvalue.lp) + (*((char*)&sl) ? 0 : sizeof(int))); 789da2e3ebdSchin } 790da2e3ebdSchin nv_close(np); 791da2e3ebdSchin break; 792da2e3ebdSchin } 793da2e3ebdSchin case 'q': 794b30d1939SAndy Fiddaman if(fe->n_str) 795b30d1939SAndy Fiddaman { 796b30d1939SAndy Fiddaman const char *fp = mapformat(fe); 797b30d1939SAndy Fiddaman if(fp) 798b30d1939SAndy Fiddaman { 799b30d1939SAndy Fiddaman format = *fp; 800b30d1939SAndy Fiddaman if(fp[1]) 801b30d1939SAndy Fiddaman fe->flags |=SFFMT_ALTER; 802b30d1939SAndy Fiddaman } 803b30d1939SAndy Fiddaman } 804b30d1939SAndy Fiddaman /* FALLTHROUGH */ 805da2e3ebdSchin case 'b': 806da2e3ebdSchin case 's': 807da2e3ebdSchin case 'B': 808da2e3ebdSchin case 'H': 809da2e3ebdSchin case 'P': 810da2e3ebdSchin case 'R': 811da2e3ebdSchin fe->fmt = 's'; 812da2e3ebdSchin fe->size = -1; 813da2e3ebdSchin if(format=='s' && fe->base>=0) 814da2e3ebdSchin { 815da2e3ebdSchin value->p = pp->nextarg; 816da2e3ebdSchin pp->nextarg = nullarg; 817da2e3ebdSchin } 818da2e3ebdSchin else 819da2e3ebdSchin { 820da2e3ebdSchin fe->base = -1; 821da2e3ebdSchin value->s = argp; 822da2e3ebdSchin } 823da2e3ebdSchin fe->flags &= ~SFFMT_LONG; 824da2e3ebdSchin break; 825da2e3ebdSchin case 'c': 82634f9b3eeSRoland Mainz if(mbwide() && (n = mbsize(argp)) > 1) 82734f9b3eeSRoland Mainz { 82834f9b3eeSRoland Mainz fe->fmt = 's'; 82934f9b3eeSRoland Mainz fe->size = n; 83034f9b3eeSRoland Mainz value->s = argp; 83134f9b3eeSRoland Mainz } 83234f9b3eeSRoland Mainz else if(fe->base >=0) 833da2e3ebdSchin value->s = argp; 834da2e3ebdSchin else 835da2e3ebdSchin value->c = *argp; 836da2e3ebdSchin fe->flags &= ~SFFMT_LONG; 837da2e3ebdSchin break; 838da2e3ebdSchin case 'o': 839da2e3ebdSchin case 'x': 840da2e3ebdSchin case 'X': 841da2e3ebdSchin case 'u': 842da2e3ebdSchin case 'U': 843da2e3ebdSchin longmax = LDBL_ULLONG_MAX; 8445ae8bd53SToomas Soome /* FALLTHROUGH */ 845da2e3ebdSchin case '.': 846da2e3ebdSchin if(fe->size==2 && strchr("bcsqHPRQTZ",*fe->form)) 847da2e3ebdSchin { 848da2e3ebdSchin value->ll = ((unsigned char*)argp)[0]; 849da2e3ebdSchin break; 850da2e3ebdSchin } 8515ae8bd53SToomas Soome /* FALLTHROUGH */ 852da2e3ebdSchin case 'd': 853da2e3ebdSchin case 'D': 854da2e3ebdSchin case 'i': 855da2e3ebdSchin switch(*argp) 856da2e3ebdSchin { 857da2e3ebdSchin case '\'': 858da2e3ebdSchin case '"': 85934f9b3eeSRoland Mainz w = argp + 1; 86034f9b3eeSRoland Mainz if(mbwide() && mbsize(w) > 1) 86134f9b3eeSRoland Mainz value->ll = mbchar(w); 86234f9b3eeSRoland Mainz else 86334f9b3eeSRoland Mainz value->ll = *(unsigned char*)w++; 86434f9b3eeSRoland Mainz if(w[0] && (w[0] != argp[0] || w[1])) 8657c2fbfb3SApril Chin { 8667c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp); 8677c2fbfb3SApril Chin pp->err = 1; 8687c2fbfb3SApril Chin } 869da2e3ebdSchin break; 870da2e3ebdSchin default: 871da2e3ebdSchin d = sh_strnum(argp,&lastchar,0); 872da2e3ebdSchin if(d<longmin) 873da2e3ebdSchin { 874da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp); 875da2e3ebdSchin pp->err = 1; 876da2e3ebdSchin d = longmin; 877da2e3ebdSchin } 878da2e3ebdSchin else if(d>longmax) 879da2e3ebdSchin { 880da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp); 881da2e3ebdSchin pp->err = 1; 882da2e3ebdSchin d = longmax; 883da2e3ebdSchin } 884da2e3ebdSchin value->ll = (Sflong_t)d; 885da2e3ebdSchin if(lastchar == *pp->nextarg) 886da2e3ebdSchin { 887da2e3ebdSchin value->ll = *argp; 888da2e3ebdSchin lastchar = ""; 889da2e3ebdSchin } 890da2e3ebdSchin break; 891da2e3ebdSchin } 892da2e3ebdSchin if(neg) 893da2e3ebdSchin value->ll = -value->ll; 894da2e3ebdSchin fe->size = sizeof(value->ll); 895da2e3ebdSchin break; 896da2e3ebdSchin case 'a': 897da2e3ebdSchin case 'e': 898da2e3ebdSchin case 'f': 899da2e3ebdSchin case 'g': 900da2e3ebdSchin case 'A': 901da2e3ebdSchin case 'E': 902da2e3ebdSchin case 'F': 903da2e3ebdSchin case 'G': 904da2e3ebdSchin d = sh_strnum(*pp->nextarg,&lastchar,0); 9057c2fbfb3SApril Chin switch(*argp) 9067c2fbfb3SApril Chin { 9077c2fbfb3SApril Chin case '\'': 9087c2fbfb3SApril Chin case '"': 9097c2fbfb3SApril Chin d = ((unsigned char*)argp)[1]; 9107c2fbfb3SApril Chin if(argp[2] && (argp[2] != argp[0] || argp[3])) 9117c2fbfb3SApril Chin { 9127c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp); 9137c2fbfb3SApril Chin pp->err = 1; 9147c2fbfb3SApril Chin } 9157c2fbfb3SApril Chin break; 9167c2fbfb3SApril Chin default: 9177c2fbfb3SApril Chin d = sh_strnum(*pp->nextarg,&lastchar,0); 9187c2fbfb3SApril Chin break; 9197c2fbfb3SApril Chin } 920da2e3ebdSchin if(SFFMT_LDOUBLE) 921da2e3ebdSchin { 922da2e3ebdSchin value->ld = d; 923da2e3ebdSchin fe->size = sizeof(value->ld); 924da2e3ebdSchin } 925da2e3ebdSchin else 926da2e3ebdSchin { 927da2e3ebdSchin value->d = d; 928da2e3ebdSchin fe->size = sizeof(value->d); 929da2e3ebdSchin } 930da2e3ebdSchin break; 931da2e3ebdSchin case 'Q': 932da2e3ebdSchin value->ll = (Sflong_t)strelapsed(*pp->nextarg,&lastchar,1); 933da2e3ebdSchin break; 934da2e3ebdSchin case 'T': 935da2e3ebdSchin value->ll = (Sflong_t)tmxdate(*pp->nextarg,&lastchar,TMX_NOW); 936da2e3ebdSchin break; 937da2e3ebdSchin default: 938da2e3ebdSchin value->ll = 0; 939da2e3ebdSchin fe->fmt = 'd'; 940da2e3ebdSchin fe->size = sizeof(value->ll); 941da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_formspec,format); 942da2e3ebdSchin break; 943da2e3ebdSchin } 944da2e3ebdSchin if (format == '.') 945da2e3ebdSchin value->i = value->ll; 946da2e3ebdSchin if(*lastchar) 947da2e3ebdSchin { 948da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_argtype,format); 949da2e3ebdSchin pp->err = 1; 950da2e3ebdSchin } 951da2e3ebdSchin pp->nextarg++; 952da2e3ebdSchin } 953da2e3ebdSchin switch(format) 954da2e3ebdSchin { 955da2e3ebdSchin case 'Z': 956da2e3ebdSchin fe->fmt = 'c'; 957da2e3ebdSchin fe->base = -1; 958da2e3ebdSchin value->c = 0; 959da2e3ebdSchin break; 960da2e3ebdSchin case 'b': 961da2e3ebdSchin if((n=fmtvecho(value->s,pp))>=0) 962da2e3ebdSchin { 963da2e3ebdSchin if(pp->nextarg == nullarg) 964da2e3ebdSchin { 965da2e3ebdSchin pp->argsize = n; 966da2e3ebdSchin return -1; 967da2e3ebdSchin } 968da2e3ebdSchin value->s = stakptr(staktell()); 969b30d1939SAndy Fiddaman fe->size = n; 970da2e3ebdSchin } 971da2e3ebdSchin break; 972da2e3ebdSchin case 'B': 973b30d1939SAndy Fiddaman if(!shp->strbuf2) 974b30d1939SAndy Fiddaman shp->strbuf2 = sfstropen(); 975b30d1939SAndy Fiddaman fe->size = fmtbase64(shp->strbuf2,value->s, fe->flags&SFFMT_ALTER); 976b30d1939SAndy Fiddaman value->s = sfstruse(shp->strbuf2); 9777c2fbfb3SApril Chin fe->flags |= SFFMT_SHORT; 978da2e3ebdSchin break; 979da2e3ebdSchin case 'H': 980b30d1939SAndy Fiddaman value->s = fmthtml(value->s, fe->flags); 981da2e3ebdSchin break; 982da2e3ebdSchin case 'q': 983da2e3ebdSchin value->s = sh_fmtqf(value->s, !!(fe->flags & SFFMT_ALTER), fold); 984da2e3ebdSchin break; 985da2e3ebdSchin case 'P': 986b30d1939SAndy Fiddaman s = fmtmatch(value->s); 987da2e3ebdSchin if(!s || *s==0) 988da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s); 989da2e3ebdSchin value->s = s; 990da2e3ebdSchin break; 991da2e3ebdSchin case 'R': 992b30d1939SAndy Fiddaman s = fmtre(value->s); 993b30d1939SAndy Fiddaman if(!s || *s==0) 994da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s); 995b30d1939SAndy Fiddaman value->s = s; 996da2e3ebdSchin break; 997da2e3ebdSchin case 'Q': 998da2e3ebdSchin if (fe->n_str>0) 999da2e3ebdSchin { 1000da2e3ebdSchin fe->fmt = 'd'; 1001da2e3ebdSchin fe->size = sizeof(value->ll); 1002da2e3ebdSchin } 1003da2e3ebdSchin else 1004da2e3ebdSchin { 1005da2e3ebdSchin value->s = fmtelapsed(value->ll, 1); 1006da2e3ebdSchin fe->fmt = 's'; 1007da2e3ebdSchin fe->size = -1; 1008da2e3ebdSchin } 1009da2e3ebdSchin break; 1010da2e3ebdSchin case 'T': 1011da2e3ebdSchin if(fe->n_str>0) 1012da2e3ebdSchin { 1013da2e3ebdSchin n = fe->t_str[fe->n_str]; 1014da2e3ebdSchin fe->t_str[fe->n_str] = 0; 1015da2e3ebdSchin value->s = fmttmx(fe->t_str, value->ll); 1016da2e3ebdSchin fe->t_str[fe->n_str] = n; 1017da2e3ebdSchin } 1018da2e3ebdSchin else value->s = fmttmx(NIL(char*), value->ll); 1019da2e3ebdSchin fe->fmt = 's'; 1020da2e3ebdSchin fe->size = -1; 1021da2e3ebdSchin break; 1022da2e3ebdSchin } 1023da2e3ebdSchin return 0; 1024da2e3ebdSchin } 1025da2e3ebdSchin 1026da2e3ebdSchin /* 1027da2e3ebdSchin * construct System V echo string out of <cp> 1028da2e3ebdSchin * If there are not escape sequences, returns -1 1029da2e3ebdSchin * Otherwise, puts null terminated result on stack, but doesn't freeze it 1030da2e3ebdSchin * returns length of output. 1031da2e3ebdSchin */ 1032da2e3ebdSchin 1033da2e3ebdSchin static int fmtvecho(const char *string, struct printf *pp) 1034da2e3ebdSchin { 1035da2e3ebdSchin register const char *cp = string, *cpmax; 1036da2e3ebdSchin register int c; 1037da2e3ebdSchin register int offset = staktell(); 1038da2e3ebdSchin #if SHOPT_MULTIBYTE 1039da2e3ebdSchin int chlen; 1040da2e3ebdSchin if(mbwide()) 1041da2e3ebdSchin { 1042da2e3ebdSchin while(1) 1043da2e3ebdSchin { 1044da2e3ebdSchin if ((chlen = mbsize(cp)) > 1) 1045da2e3ebdSchin /* Skip over multibyte characters */ 1046da2e3ebdSchin cp += chlen; 1047da2e3ebdSchin else if((c= *cp++)==0 || c == '\\') 1048da2e3ebdSchin break; 1049da2e3ebdSchin } 1050da2e3ebdSchin } 1051da2e3ebdSchin else 1052da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */ 1053da2e3ebdSchin while((c= *cp++) && (c!='\\')); 1054da2e3ebdSchin if(c==0) 1055da2e3ebdSchin return(-1); 1056da2e3ebdSchin c = --cp - string; 1057da2e3ebdSchin if(c>0) 1058da2e3ebdSchin stakwrite((void*)string,c); 1059da2e3ebdSchin for(; c= *cp; cp++) 1060da2e3ebdSchin { 1061da2e3ebdSchin #if SHOPT_MULTIBYTE 1062da2e3ebdSchin if (mbwide() && ((chlen = mbsize(cp)) > 1)) 1063da2e3ebdSchin { 1064da2e3ebdSchin stakwrite(cp,chlen); 1065da2e3ebdSchin cp += (chlen-1); 1066da2e3ebdSchin continue; 1067da2e3ebdSchin } 1068da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */ 1069da2e3ebdSchin if( c=='\\') switch(*++cp) 1070da2e3ebdSchin { 1071da2e3ebdSchin case 'E': 1072da2e3ebdSchin c = ('a'==97?'\033':39); /* ASCII/EBCDIC */ 1073da2e3ebdSchin break; 1074da2e3ebdSchin case 'a': 1075da2e3ebdSchin c = '\a'; 1076da2e3ebdSchin break; 1077da2e3ebdSchin case 'b': 1078da2e3ebdSchin c = '\b'; 1079da2e3ebdSchin break; 1080da2e3ebdSchin case 'c': 1081da2e3ebdSchin pp->cescape++; 1082da2e3ebdSchin pp->nextarg = nullarg; 1083da2e3ebdSchin goto done; 1084da2e3ebdSchin case 'f': 1085da2e3ebdSchin c = '\f'; 1086da2e3ebdSchin break; 1087da2e3ebdSchin case 'n': 1088da2e3ebdSchin c = '\n'; 1089da2e3ebdSchin break; 1090da2e3ebdSchin case 'r': 1091da2e3ebdSchin c = '\r'; 1092da2e3ebdSchin break; 1093da2e3ebdSchin case 'v': 1094da2e3ebdSchin c = '\v'; 1095da2e3ebdSchin break; 1096da2e3ebdSchin case 't': 1097da2e3ebdSchin c = '\t'; 1098da2e3ebdSchin break; 1099da2e3ebdSchin case '\\': 1100da2e3ebdSchin c = '\\'; 1101da2e3ebdSchin break; 1102da2e3ebdSchin case '0': 1103da2e3ebdSchin c = 0; 1104da2e3ebdSchin cpmax = cp + 4; 1105da2e3ebdSchin while(++cp<cpmax && *cp>='0' && *cp<='7') 1106da2e3ebdSchin { 1107da2e3ebdSchin c <<= 3; 1108da2e3ebdSchin c |= (*cp-'0'); 1109da2e3ebdSchin } 11105ae8bd53SToomas Soome /* FALLTHROUGH */ 1111da2e3ebdSchin default: 1112da2e3ebdSchin cp--; 1113da2e3ebdSchin } 1114da2e3ebdSchin stakputc(c); 1115da2e3ebdSchin } 1116da2e3ebdSchin done: 1117da2e3ebdSchin c = staktell()-offset; 1118da2e3ebdSchin stakputc(0); 1119da2e3ebdSchin stakseek(offset); 1120da2e3ebdSchin return(c); 1121da2e3ebdSchin } 1122