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