Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libdss/dssprintf.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2002-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
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* dss printf implementation
23
*/
24
25
#include "dsshdr.h"
26
27
#include <ast_float.h>
28
29
struct Arg_s; typedef struct Arg_s Arg_t;
30
31
struct Arg_s
32
{
33
Cxvariable_t* variable;
34
Cxexpr_t* expr;
35
Cxtype_t* cast;
36
Cxedit_t* edit;
37
char* details;
38
char* qb;
39
char* qe;
40
unsigned short type;
41
unsigned short fmt;
42
unsigned char flags;
43
};
44
45
struct Format_s
46
{
47
Format_t* next;
48
char* oformat;
49
char* nformat;
50
Arg_t arg[1];
51
};
52
53
typedef struct Fmt_s
54
{
55
Sffmt_t fmt;
56
Cx_t* cx;
57
void* data;
58
int errors;
59
Arg_t* ap;
60
} Fmt_t;
61
62
typedef union
63
{
64
char** p;
65
char* s;
66
Sflong_t q;
67
long l;
68
int i;
69
short h;
70
char c;
71
double f;
72
} Value_t;
73
74
#define DSS_FORMAT_char 1
75
#define DSS_FORMAT_float 2
76
#define DSS_FORMAT_int 3
77
#define DSS_FORMAT_long 4
78
#define DSS_FORMAT_string 5
79
80
#define DSS_FORMAT_quote 0x01
81
82
/*
83
* sfio %! extension function
84
*/
85
86
static int
87
getfmt(Sfio_t* sp, void* vp, Sffmt_t* dp)
88
{
89
register Fmt_t* fp = (Fmt_t*)dp;
90
register Arg_t* ap = fp->ap++;
91
Value_t* value = (Value_t*)vp;
92
Cxoperand_t ret;
93
94
if (ap->expr && cxeval(fp->cx, ap->expr, fp->data, &ret) < 0 || cxcast(fp->cx, &ret, ap->variable, ap->cast, fp->data, ap->details))
95
{
96
fp->errors++;
97
return -1;
98
}
99
fp->fmt.flags |= SFFMT_VALUE;
100
switch (ap->type)
101
{
102
case DSS_FORMAT_char:
103
fp->fmt.size = sizeof(int);
104
if (ret.value.number < 1)
105
value->c = 0;
106
else if (ret.value.number > UCHAR_MAX)
107
value->c = UCHAR_MAX;
108
else
109
value->c = (unsigned char)ret.value.number;
110
break;
111
case DSS_FORMAT_float:
112
fp->fmt.size = sizeof(double);
113
value->f = ret.value.number;
114
break;
115
case DSS_FORMAT_int:
116
#if 0
117
/*
118
* this code is technically correct but overly
119
* complicates script portability between architectures
120
* with differing sizeof(int) and/or sizeof(long)
121
*/
122
123
fp->fmt.size = sizeof(int);
124
if (((ret.value.number >= 0) ? ret.value.number : -ret.value.number) < 1)
125
value->i = 0;
126
else if (ret.value.number > UINT_MAX)
127
value->i = INT_MAX;
128
else if (ret.value.number < INT_MIN)
129
value->i = INT_MAX;
130
else
131
value->i = (unsigned int)ret.value.number;
132
break;
133
#endif
134
case DSS_FORMAT_long:
135
fp->fmt.size = sizeof(Sflong_t);
136
if (((ret.value.number >= 0) ? ret.value.number : -ret.value.number) < 1)
137
value->q = 0;
138
else if (ret.value.number > FLTMAX_UINTMAX_MAX)
139
value->q = FLTMAX_INTMAX_MAX;
140
else if (ret.value.number < FLTMAX_INTMAX_MIN)
141
value->q = FLTMAX_INTMAX_MAX;
142
else
143
value->q = (Sfulong_t)((Sflong_t)ret.value.number);
144
break;
145
case DSS_FORMAT_string:
146
if (ap->fmt & (FMT_EXP_CHAR|FMT_EXP_LINE|FMT_EXP_NOCR|FMT_EXP_NONL|FMT_EXP_WIDE))
147
ret.value.string.size = strexp(ret.value.string.data, ap->fmt);
148
if (ap->edit)
149
cxsub(fp->cx, ap->edit, &ret);
150
if (ap->flags & DSS_FORMAT_quote)
151
ret.value.string.size = strlen(ret.value.string.data = fmtquote(ret.value.string.data, ap->qb, ap->qe, ret.value.string.size, ap->fmt));
152
value->s = ret.value.string.data;
153
fp->fmt.size = ret.value.string.size;
154
break;
155
}
156
return 0;
157
}
158
159
/*
160
* printf
161
*/
162
163
int
164
dssprintf(Dss_t* dss, Cx_t* cx, Sfio_t* sp, const char* format, Dssrecord_t* record)
165
{
166
register char* s;
167
register char* t;
168
register char* d;
169
register char* v;
170
register int n;
171
register int q;
172
register Arg_t* ap;
173
int l;
174
int x;
175
char* f;
176
char* o;
177
char* w;
178
Format_t* fp;
179
Fmt_t fmt;
180
181
if (!cx)
182
cx = dss->cx;
183
for (fp = dss->print; fp && fp->oformat != (char*)format; fp = fp->next);
184
if (!fp)
185
{
186
if (f = s = (char*)format)
187
{
188
char* details['z' - 'a' + 1];
189
190
memset(details, 0, sizeof(details));
191
d = 0;
192
l = 0;
193
n = 0;
194
q = 0;
195
w = 0;
196
for (;;)
197
{
198
switch (*s++)
199
{
200
case 0:
201
if (q)
202
{
203
if (dss->disc->errorf)
204
(*dss->disc->errorf)(NiL, dss->disc, 2, "%s: format character omitted", f);
205
return -1;
206
}
207
break;
208
case '%':
209
if (*s != '%')
210
{
211
q = 1;
212
n++;
213
f = s - 1;
214
}
215
continue;
216
case '(':
217
if (q == 1)
218
{
219
q++;
220
for (;;)
221
{
222
switch (*s++)
223
{
224
case 0:
225
s--;
226
break;
227
case '(':
228
q++;
229
continue;
230
case ')':
231
if (--q == 1)
232
break;
233
continue;
234
case ':':
235
if (*s == ':')
236
s++;
237
else if (!d)
238
d = s;
239
continue;
240
default:
241
continue;
242
}
243
break;
244
}
245
if (d)
246
{
247
l += s - d + 1;
248
d = 0;
249
}
250
}
251
continue;
252
case 'c':
253
case 'd':
254
case 'e':
255
case 'f':
256
case 'g':
257
case 'o':
258
case 's':
259
case 'u':
260
case 'x':
261
if (q == 1)
262
q = 0;
263
continue;
264
default:
265
continue;
266
}
267
break;
268
}
269
if (!(fp = vmnewof(dss->vm, 0, Format_t, 1, (n - 1) * sizeof(Arg_t) + strlen(format) + 2 * n + l + 2)))
270
{
271
if (dss->disc->errorf)
272
(*dss->disc->errorf)(NiL, dss->disc, ERROR_SYSTEM|2, "out of space");
273
return -1;
274
}
275
fp->oformat = (char*)format;
276
fp->next = dss->print;
277
dss->print = fp;
278
ap = &fp->arg[0];
279
s = t = fp->nformat = (char*)(&fp->arg[n]);
280
strcpy(t, format);
281
f = t + strlen(format) + 2 * n + 1;
282
q = 0;
283
d = 0;
284
l = 0;
285
for (;;)
286
{
287
switch (*t++ = *s++)
288
{
289
case 0:
290
*(t - 1) = '\n';
291
*t = 0;
292
break;
293
case '%':
294
if (*s == '%')
295
*t++ = *s++;
296
else
297
q = 1;
298
continue;
299
case '(':
300
if (q == 1)
301
{
302
q++;
303
t--;
304
x = 0;
305
v = s;
306
for (;;)
307
{
308
switch (*s++)
309
{
310
case 0:
311
if (dss->disc->errorf)
312
(*dss->disc->errorf)(NiL, dss->disc, 2, "%s: %(...) imbalance", fp->oformat);
313
return -1;
314
case '(':
315
if (!d)
316
x = 1;
317
q++;
318
continue;
319
case ')':
320
if (--q == 1)
321
break;
322
continue;
323
case ':':
324
if (*s == ':')
325
s++;
326
else if (!d && q == 2)
327
d = s;
328
continue;
329
case ',':
330
if (!d)
331
x = 1;
332
continue;
333
default:
334
if (!d && cx->table->opcode[*(unsigned char*)(s - 1)])
335
x = 1;
336
continue;
337
}
338
break;
339
}
340
if (d)
341
*(d - 1) = 0;
342
*(s - 1) = 0;
343
if (*v)
344
{
345
if (x)
346
{
347
void* pop;
348
349
if (!(pop = cxpush(cx, NiL, NiL, v, (d ? d : s) - v, 0)))
350
return -1;
351
ap->expr = cxcomp(cx);
352
cxpop(cx, pop);
353
if (!ap->expr)
354
return -1;
355
}
356
else if (cx->referencef)
357
{
358
Cxoperand_t a;
359
Cxoperand_t b;
360
Cxoperand_t r;
361
362
a.type = cx->state->type_string;
363
a.value.string.size = s - v - 1;
364
a.value.string.data = v;
365
b.type = a.type;
366
if ((*cx->referencef)(cx, NiL, &r, &b, &a, NiL, cx->disc))
367
return -1;
368
ap->variable = r.value.variable;
369
}
370
else if (!(ap->variable = cxvariable(cx, v, NiL, cx->disc)))
371
return -1;
372
}
373
else if (d)
374
{
375
w = d;
376
d = 0;
377
}
378
}
379
continue;
380
case 'c':
381
if (q == 1)
382
{
383
ap->type = DSS_FORMAT_char;
384
ap->cast = cx->state->type_number;
385
goto set;
386
}
387
continue;
388
case 'd':
389
case 'o':
390
case 'u':
391
case 'x':
392
if (q == 1)
393
{
394
if (l > 1 || ap->variable && (ap->variable->format.width == 8 || ap->variable->type->format.width == 8))
395
{
396
n = *(t - 1);
397
*(t - 1) = 'l';
398
*t++ = 'l';
399
*t++ = n;
400
ap->type = DSS_FORMAT_long;
401
}
402
else
403
ap->type = DSS_FORMAT_int;
404
ap->cast = cx->state->type_number;
405
goto set;
406
}
407
continue;
408
case 'e':
409
case 'f':
410
case 'g':
411
if (q == 1)
412
{
413
ap->type = DSS_FORMAT_float;
414
ap->cast = cx->state->type_number;
415
goto set;
416
}
417
continue;
418
case 'h':
419
if (q == 1)
420
t--;
421
continue;
422
case 'l':
423
if (q == 1)
424
{
425
t--;
426
l++;
427
}
428
continue;
429
case 's':
430
if (q == 1)
431
{
432
ap->type = DSS_FORMAT_string;
433
ap->cast = cx->state->type_string;
434
set:
435
if (w)
436
{
437
details[*(s-1) - 'a'] = w;
438
w = 0;
439
fp->nformat = t = s;
440
continue;
441
}
442
if (!ap->variable && !ap->expr)
443
{
444
if (dss->disc->errorf)
445
{
446
*t = 0;
447
(*dss->disc->errorf)(NiL, dss->disc, 2, "%s: (variable) omitted in format", fp->nformat);
448
}
449
return -1;
450
}
451
l = 0;
452
q = 0;
453
if (d || (d = details[*(s-1) - 'a']) || (d = cx->state->type_string->format.details))
454
{
455
ap->fmt = FMT_ALWAYS|FMT_ESCAPED;
456
while (*d)
457
{
458
o = 0;
459
v = d;
460
while (*d)
461
if (*d++ == ':')
462
{
463
*(o = d - 1) = 0;
464
break;
465
}
466
if (strneq(v, "edit=", 5))
467
{
468
if (o)
469
*o = ':';
470
if (ap->edit = cxedit(cx, v + 5, dss->disc))
471
{
472
d = v + 5 + ap->edit->re.re_npat;
473
if (d == o)
474
d++;
475
}
476
}
477
else if (strneq(v, "endquote=", 8))
478
{
479
ap->qe = v += 8;
480
while (*f++ = *v++);
481
}
482
else if (streq(v, "expand"))
483
{
484
ap->fmt |= FMT_EXP_CHAR|FMT_EXP_LINE|FMT_EXP_WIDE;
485
continue;
486
}
487
else if (strneq(v, "expand=", 7))
488
{
489
v += 7;
490
while (*v)
491
{
492
if (*v == '|' || *v == ',')
493
{
494
v++;
495
continue;
496
}
497
if (strneq(v, "all", 3))
498
{
499
ap->fmt |= FMT_EXP_CHAR|FMT_EXP_LINE|FMT_EXP_WIDE;
500
break;
501
}
502
else if (strneq(v, "char", 4))
503
{
504
v += 4;
505
ap->fmt |= FMT_EXP_CHAR;
506
}
507
else if (strneq(v, "line", 4))
508
{
509
v += 4;
510
ap->fmt |= FMT_EXP_LINE;
511
}
512
else if (strneq(v, "nocr", 4))
513
{
514
v += 4;
515
ap->fmt |= FMT_EXP_NOCR;
516
}
517
else if (strneq(v, "nonl", 4))
518
{
519
v += 4;
520
ap->fmt |= FMT_EXP_NONL;
521
}
522
else if (strneq(v, "wide", 4))
523
{
524
v += 4;
525
ap->fmt |= FMT_EXP_WIDE;
526
}
527
else
528
while (*v && *v != '|' && *v != ',')
529
v++;
530
}
531
continue;
532
}
533
else if (streq(v, "escape"))
534
ap->fmt &= ~FMT_ESCAPED;
535
else if (strneq(v, "opt", 3))
536
ap->fmt &= ~FMT_ALWAYS;
537
else if (streq(v, "quote") || strneq(v, "quote=", 6))
538
{
539
if (v[5])
540
{
541
ap->qb = v += 6;
542
while (*f++ = *v++);
543
}
544
else
545
ap->qb = "\"";
546
if (!ap->qe)
547
ap->qe = ap->qb;
548
}
549
else if (streq(v, "shell") || strneq(v, "shell=", 6))
550
{
551
ap->fmt |= FMT_SHELL;
552
if (v[5])
553
{
554
ap->qb = v += 6;
555
while (*f++ = *v++);
556
}
557
else
558
ap->qb = "$'";
559
if (!ap->qe)
560
ap->qe = "'";
561
}
562
else if (streq(v, "wide"))
563
ap->fmt |= FMT_WIDE;
564
else
565
{
566
if (*d)
567
*(d - 1) = ':';
568
d = v;
569
break;
570
}
571
ap->flags |= DSS_FORMAT_quote;
572
}
573
ap->details = f;
574
while (*f++ = *d++);
575
d = 0;
576
}
577
if (ap->variable && !ap->edit && cxisstring(ap->variable->type) && ap->variable->format.map && ap->variable->format.map->part && ap->variable->format.map->part->edit)
578
ap->edit = ap->variable->format.map->part->edit;
579
ap++;
580
}
581
continue;
582
case 'L':
583
if (q == 1)
584
{
585
t--;
586
l += 2;
587
}
588
continue;
589
default:
590
continue;
591
}
592
break;
593
}
594
}
595
else
596
{
597
Cxvariable_t* vp;
598
599
n = q = 0;
600
if (dss->meth->cx->fields)
601
{
602
for (vp = (Cxvariable_t*)dtfirst(dss->meth->cx->fields); vp; vp = (Cxvariable_t*)dtnext(dss->meth->cx->fields, vp), n++)
603
if (!(vp->header.flags & CX_DEPRECATED) && q < (l = strlen(vp->name)))
604
q = l;
605
}
606
else if (dss->meth->data)
607
{
608
for (vp = (Cxvariable_t*)dss->meth->data; vp->name; vp++, n++)
609
if (!(vp->header.flags & CX_DEPRECATED) && q < (l = strlen(vp->name)))
610
q = l;
611
}
612
q += 2;
613
if (!(fp = vmnewof(dss->vm, 0, Format_t, 1, n * sizeof(Arg_t) + n * (q + 3) + 2)))
614
{
615
if (dss->disc->errorf)
616
(*dss->disc->errorf)(NiL, dss->disc, ERROR_SYSTEM|2, "out of space");
617
return -1;
618
}
619
fp->oformat = 0;
620
fp->next = dss->print;
621
dss->print = fp;
622
ap = &fp->arg[0];
623
s = fp->nformat = (char*)(&fp->arg[n]);
624
*s++ = '\n';
625
vp = dss->meth->cx->fields ? (Cxvariable_t*)dtfirst(dss->meth->cx->fields) : dss->meth->data ? (Cxvariable_t*)dss->meth->data : 0;
626
if (vp)
627
for (;;)
628
{
629
if (dss->meth->cx->fields)
630
{
631
if (!vp)
632
break;
633
}
634
else if (!vp->name)
635
break;
636
if (!(vp->header.flags & CX_DEPRECATED))
637
{
638
s += sfsprintf(s, q + 4, "%-*s%%s\n", q, vp->name);
639
ap->variable = vp;
640
ap->type = DSS_FORMAT_string;
641
ap->cast = cx->state->type_string;
642
if (cxisstring(vp->type) && vp->format.map && vp->format.map->part && vp->format.map->part->edit)
643
ap->edit = vp->format.map->part->edit;
644
ap++;
645
}
646
if (dss->meth->cx->fields)
647
vp = (Cxvariable_t*)dtnext(dss->meth->cx->fields, vp);
648
else
649
vp++;
650
}
651
*s = 0;
652
}
653
if (!sp)
654
return 0;
655
}
656
memset(&fmt, 0, sizeof(fmt));
657
fmt.fmt.version = SFIO_VERSION;
658
fmt.fmt.form = fp->nformat;
659
fmt.fmt.extf = getfmt;
660
fmt.cx = cx;
661
fmt.data = record;
662
fmt.ap = &fp->arg[0];
663
n = sfprintf(sp, "%!", &fmt);
664
return !sp ? 0 : (fmt.errors || n <= 0 && sp && sferror(sp)) ? -1 : n;
665
}
666
667