Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/dsslib/text/text.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2002-2011 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
* text method
23
*
24
* Glenn Fowler
25
* AT&T Research
26
*/
27
28
static const char usage[] =
29
"[+DESCRIPTION?The \bdss\b text method describes newline-terminated"
30
" field-delimited text file data. The method schema is a \bscanf\b(3)"
31
" style format string with embedded field names of the form"
32
" \b%(\b\afield\a\b)\b\aformat-char\a \adelimiter\a ...]"
33
"[+?Use the \bdss\b \bflat\b method for generic record-oriented flat "
34
"file data.]"
35
"[+EXAMPLES]{"
36
" [+dss -x text::::\b\"%(name)s::%(passwd::Encrypted\\ password.)s::%(uid)d::%(gid)d::%(comment)s::%(home)s::%(shell)s\"\\ 'passwd==\"\"&&uid==0'\\ "
37
" /etc/passwd?Prints \b/etc/passwd\b entries with uid==0 and no"
38
" password.]"
39
"}"
40
"\n"
41
"\n--method=text[,option...]\n"
42
"\n"
43
;
44
45
#include <dsslib.h>
46
#include <tm.h>
47
48
typedef uint32_t Ipaddr_t;
49
50
struct Text_s; typedef struct Text_s Text_t;
51
52
struct Text_s /* Dssmeth_t.data */
53
{
54
char* format;
55
Dt_t* dict;
56
int vars;
57
char name[1];
58
};
59
60
static char null[1];
61
62
extern Dsslib_t dss_lib_text;
63
64
/*
65
* text identf
66
*/
67
68
static int
69
textident(Dssfile_t* file, void* buf, size_t n, Dssdisc_t* disc)
70
{
71
return 1;
72
}
73
74
/*
75
* text fopenf
76
*/
77
78
static int
79
textfopen(Dssfile_t* file, Dssdisc_t* disc)
80
{
81
if (!(file->data = vmnewof(file->dss->vm, 0, Cxvalue_t, ((Text_t*)file->dss->meth->data)->vars, 0)))
82
{
83
if (disc->errorf)
84
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
85
return -1;
86
}
87
return 0;
88
}
89
90
/*
91
* text fclosef
92
*/
93
94
static int
95
textfclose(Dssfile_t* file, Dssdisc_t* disc)
96
{
97
if (!file || !file->data)
98
return -1;
99
vmfree(file->dss->vm, file->data);
100
return 0;
101
}
102
103
/*
104
* get one string token into p
105
*/
106
107
static char*
108
lextok(register char* s, register int c, Cxstring_t* p)
109
{
110
register char* t;
111
register int q;
112
char* b;
113
char* u;
114
115
b = s;
116
q = 0;
117
t = 0;
118
for (;;)
119
{
120
if (!*s)
121
{
122
if (!q)
123
{
124
if (c && c != ' ')
125
{
126
s = b;
127
b = null;
128
break;
129
}
130
}
131
if (t)
132
*t = 0;
133
break;
134
}
135
else if (*s == '\\')
136
{
137
u = s;
138
if (!*++s)
139
continue;
140
if (b == u)
141
b = s;
142
else if (!t)
143
t = u;
144
}
145
else if (q)
146
{
147
if (*s == q)
148
{
149
q = 0;
150
if (!t)
151
t = s;
152
s++;
153
continue;
154
}
155
else if (*s == '\r')
156
*s = 0;
157
}
158
else if (*s == '"' || *s == '\'')
159
{
160
q = *s++;
161
if (b == (s - 1))
162
b = s;
163
else if (!t)
164
t = s - 1;
165
continue;
166
}
167
else if (*s == c || c == ' ' && *s == '\t')
168
{
169
*s++ = 0;
170
if (t)
171
*t = 0;
172
if (c == ' ')
173
while (*s == ' ' || *s == '\t')
174
s++;
175
break;
176
}
177
if (t)
178
*t++ = *s;
179
s++;
180
}
181
p->data = b;
182
p->size = *b ? (s - b) : 0;
183
return s;
184
}
185
186
/*
187
* text readf
188
*/
189
190
static int
191
textread(register Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
192
{
193
register Cxvalue_t* data = (Cxvalue_t*)file->data;
194
register Text_t* text = (Text_t*)file->dss->meth->data;
195
register char* s;
196
register char* f;
197
register int c;
198
char* t;
199
int num;
200
int q;
201
Ipaddr_t a;
202
203
if (!(s = sfgetr(file->io, '\n', 1)))
204
return 0;
205
num = 0;
206
f = text->format;
207
for (;;)
208
{
209
switch (c = *f++)
210
{
211
case 0:
212
break;
213
case ' ':
214
while (*s == ' ' || *s == '\t')
215
s++;
216
break;
217
case '%':
218
switch (c = *f++)
219
{
220
case 'h':
221
case 'l':
222
q = c;
223
c = *f++;
224
break;
225
default:
226
q = 0;
227
break;
228
}
229
switch (c)
230
{
231
case 0:
232
f--;
233
continue;
234
case '%':
235
if (*s++ != c)
236
s = null;
237
continue;
238
case 'c':
239
if (data[num].number = *s)
240
s++;
241
num++;
242
break;
243
case 'd':
244
c = 10;
245
goto number;
246
case 'i':
247
if (!*s)
248
data[num].number = 0;
249
else
250
{
251
strtoip4(s, &t, &a, NiL);
252
data[num].number = a;
253
s = t;
254
}
255
num++;
256
break;
257
case 'n':
258
case 'u':
259
c = 0;
260
goto number;
261
case 'o':
262
c = 8;
263
goto number;
264
case 'x':
265
c = 16;
266
number:
267
if (!*s)
268
data[num].number = 0;
269
else
270
{
271
data[num].number = strtol(s, &t, c);
272
s = t;
273
}
274
num++;
275
break;
276
case 'f':
277
case 'g':
278
if (!*s)
279
data[num].number = 0;
280
else
281
{
282
data[num].number = strtod(s, &t);
283
s = t;
284
}
285
num++;
286
break;
287
case 's':
288
if (q = *f)
289
f++;
290
if (!*s)
291
{
292
data[num].string.data = null;
293
data[num].string.size = 0;
294
}
295
else
296
s = lextok(s, q, &data[num].string);
297
num++;
298
break;
299
case 't':
300
if (!*s)
301
data[num].number = 0;
302
else
303
{
304
data[num].number = tmdate(s, &t, NiL);
305
if (*t && *t != *f && *t != '\n')
306
data[num].number = strtol(s, &t, 0);
307
s = t;
308
}
309
num++;
310
break;
311
}
312
continue;
313
case '\n':
314
break;
315
default:
316
if (*s++ != c)
317
s = null;
318
continue;
319
}
320
break;
321
}
322
record->data = data;
323
return 1;
324
}
325
326
/*
327
* text writef
328
*/
329
330
static int
331
textwrite(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
332
{
333
register Text_t* text = (Text_t*)file->dss->meth->data;
334
Cxvalue_t* data = (Cxvalue_t*)record->data;
335
register char* f;
336
register int c;
337
int num;
338
339
num = 0;
340
f = text->format;
341
for (;;)
342
{
343
switch (c = *f++)
344
{
345
case 0:
346
break;
347
case ' ':
348
sfputc(file->io, ' ');
349
break;
350
case '%':
351
switch (c = *f++)
352
{
353
case 'h':
354
case 'l':
355
c = *f++;
356
break;
357
}
358
switch (c)
359
{
360
case 0:
361
f--;
362
continue;
363
case '%':
364
sfputc(file->io, '%');
365
continue;
366
case 'c':
367
sfputc(file->io, (int)data[num].number);
368
num++;
369
break;
370
case 'd':
371
case 'n':
372
case 'u':
373
sfprintf(file->io, "%d", (long)data[num].number);
374
num++;
375
break;
376
case 'i':
377
sfprintf(file->io, "%s", fmtip4((Ipaddr_t)data[num].number, -1));
378
num++;
379
break;
380
case 'f':
381
case 'g':
382
sfprintf(file->io, "%Lg", data[num].number);
383
num++;
384
break;
385
case 'o':
386
sfprintf(file->io, "%o", (long)data[num].number);
387
num++;
388
break;
389
case 'x':
390
sfprintf(file->io, "%x", (long)data[num].number);
391
num++;
392
break;
393
case 's':
394
sfprintf(file->io, "%-.*s", data[num].string.size, data[num].string.data);
395
num++;
396
break;
397
case 't':
398
sfprintf(file->io, "%s", fmttime("%K", (time_t)data[num].number));
399
num++;
400
break;
401
}
402
continue;
403
case '\n':
404
break;
405
default:
406
sfputc(file->io, c);
407
continue;
408
}
409
break;
410
}
411
sfputc(file->io, '\n');
412
return 0;
413
}
414
415
static Dssformat_t text_format =
416
{
417
"text",
418
"text format (2010-05-28)",
419
CXH,
420
textident,
421
textfopen,
422
textread,
423
textwrite,
424
0,
425
textfclose,
426
0,
427
0,
428
0
429
};
430
431
static int
432
op_get(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
433
{
434
r->value = ((Cxvalue_t*)DSSDATA(data))[((Cxvariable_t*)pc->data.variable)->index];
435
return 0;
436
}
437
438
static Cxcallout_t local_callouts[] =
439
{
440
CXC(CX_GET, "void", "void", op_get, 0)
441
};
442
443
/*
444
* methf
445
*/
446
447
static Dssmeth_t*
448
textmeth(const char* name, const char* options, const char* schema, Dssdisc_t* disc, Dssmeth_t* ometh)
449
{
450
register Text_t* text;
451
register Dssmeth_t* meth;
452
register Cxvariable_t* var;
453
register char* s;
454
register char* t;
455
register char* f;
456
register int c;
457
char* d;
458
int p;
459
int index;
460
461
if (options)
462
{
463
if (dssoptlib(ometh->cx->buf, &dss_lib_text, usage, disc))
464
goto drop;
465
s = sfstruse(ometh->cx->buf);
466
for (;;)
467
{
468
switch (optstr(options, s))
469
{
470
case '?':
471
if (disc->errorf)
472
(*disc->errorf)(NiL, disc, ERROR_USAGE|4, "%s", opt_info.arg);
473
goto drop;
474
case ':':
475
if (disc->errorf)
476
(*disc->errorf)(NiL, disc, 2, "%s", opt_info.arg);
477
goto drop;
478
}
479
break;
480
}
481
}
482
if (!schema || !*schema)
483
return ometh;
484
if (!(meth = newof(0, Dssmeth_t, 1, sizeof(Text_t) + strlen(name) + 2 * strlen(schema) + 2)))
485
{
486
free(meth);
487
if (disc->errorf)
488
(*disc->errorf)(NiL, disc, 2, "out of space");
489
return 0;
490
}
491
*meth = *ometh;
492
meth->data = text = (Text_t*)(meth + 1);
493
text->format = strcopy(text->name, name) + 1;
494
index = 0;
495
s = (char*)schema;
496
f = text->format;
497
for (;;)
498
{
499
switch (c = *s++)
500
{
501
case 0:
502
break;
503
case '%':
504
*f++ = '%';
505
var = 0;
506
switch (c = *s++)
507
{
508
case 0:
509
goto invalid;
510
case 'h': case 'l': case 'L':
511
case '+': case '-': case '.': case '_':
512
case '0': case '1': case '2': case '3': case '4':
513
case '5': case '6': case '7': case '8': case '9':
514
continue;
515
case '%':
516
*f++ = '%';
517
continue;
518
case '(':
519
t = f;
520
d = 0;
521
p = 1;
522
for (;;)
523
{
524
switch (c = *s++)
525
{
526
case 0:
527
goto invalid;
528
case '(':
529
p++;
530
*t++ = c;
531
continue;
532
case ')':
533
if (!--p)
534
break;
535
*t++ = c;
536
continue;
537
case ':':
538
if (d)
539
*t++ = c;
540
else
541
{
542
*t++ = 0;
543
d = t;
544
}
545
continue;
546
default:
547
*t++ = c;
548
continue;
549
}
550
break;
551
}
552
*t = 0;
553
if (dtmatch(meth->cx->variables, f))
554
{
555
if (disc->errorf)
556
(*disc->errorf)(NiL, disc, 2, "%s: duplicate field", f);
557
goto drop;
558
}
559
if (!(var = newof(0, Cxvariable_t, 1, t - f + 1)))
560
{
561
if (disc->errorf)
562
(*disc->errorf)(NiL, disc, 2, "out of space");
563
goto drop;
564
}
565
var->index = index;
566
t = strcopy((char*)(var->name = (char*)(var + 1)), f);
567
if (d)
568
var->description = strcpy(t + 1, d);
569
break;
570
}
571
for (;;)
572
{
573
switch (c = *s++)
574
{
575
case 0:
576
goto invalid;
577
case 'h': case 'l': case 'L':
578
case '+': case '-': case '.': case '_':
579
case '0': case '1': case '2': case '3': case '4':
580
case '5': case '6': case '7': case '8': case '9':
581
continue;
582
}
583
break;
584
}
585
if (var)
586
{
587
switch (c)
588
{
589
case 'd':
590
case 'f':
591
case 'g':
592
case 'n':
593
case 'o':
594
case 'u':
595
case 'x':
596
var->type = (Cxtype_t*)"number";
597
break;
598
case 'i':
599
var->type = (Cxtype_t*)"ipaddr_t";
600
break;
601
case 's':
602
var->type = (Cxtype_t*)"string";
603
break;
604
case 't':
605
var->type = (Cxtype_t*)"time_t";
606
break;
607
default:
608
if (disc->errorf)
609
(*disc->errorf)(NiL, disc, 2, "%c: invalid field format >>>%s", c, s - 1);
610
goto drop;
611
}
612
if (cxaddvariable(meth->cx, var, disc))
613
goto drop;
614
}
615
index++;
616
*f++ = c;
617
continue;
618
case ' ':
619
case '\t':
620
case '\n':
621
if (f == text->format || *(f - 1) != ' ')
622
*f++ = ' ';
623
continue;
624
default:
625
*f++ = c;
626
continue;
627
}
628
break;
629
}
630
if (!(text->vars = index))
631
goto invalid;
632
*f = 0;
633
dtinsert(meth->formats, &text_format);
634
for (c = 0; c < elementsof(local_callouts); c++)
635
if (cxaddcallout(meth->cx, &local_callouts[c], disc))
636
return 0;
637
return meth;
638
invalid:
639
if (disc->errorf)
640
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: invalid schema", schema);
641
drop:
642
free(meth);
643
return 0;
644
}
645
646
/*
647
* openf
648
*/
649
650
static int
651
textopen(Dss_t* dss, Dssdisc_t* disc)
652
{
653
return dss->meth->data ? 0 : -1;
654
}
655
656
static Dssmeth_t method =
657
{
658
"text",
659
"Newline-terminated field-delimited text file; the method schema is"
660
" a scanf(3) like format string with embedded field names of the form:"
661
" %(field1)format-char delimiter ...",
662
CXH,
663
textmeth,
664
textopen,
665
0,
666
0
667
};
668
669
Dsslib_t dss_lib_text =
670
{
671
"text",
672
"text method"
673
"[-1ls5Pp0?\n@(#)$Id: dss text method (AT&T Research) 2002-12-17 $\n]"
674
USAGE_LICENSE,
675
CXH,
676
0,
677
&method,
678
};
679
680