Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/dsslib/flat/flat.c
1810 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
* flat method
23
*
24
* Glenn Fowler
25
* AT&T Research
26
*/
27
28
static const char usage[] =
29
"[+DESCRIPTION?The \bdss\b flat method schema is the name of an XML file "
30
"that describes fixed-width and/or field-delimited flat files. Public "
31
"schemas are usually placed in a \b../lib/dss\b sibling directory on "
32
"\b$PATH\b.]"
33
"[b!:binary?Enable the fixed binary record field optimization.]"
34
"[e:emptyspace?Write empty field values as one \bspace\b character.]"
35
"[h:header?Print a C header for schema member access on the standard"
36
" output and exit. The \bFLAT\b(\adata\a) macro returns a pointer"
37
" to the flat record \bstruct\b given the \bDssrecord_t\b pointer"
38
" \adata\a. This macro cannot be evaluated in a declaration"
39
" assignment. The member names are prefixed by \ashema\a_ to"
40
" avoid C identifier conflicts.]"
41
"[o:offsets?Print the name, offset, size, number of elements and type"
42
" of each member, one per line, on the standard output, and exit."
43
" Scalar fields have 0 elements.]"
44
"[p:prototype?Print a prototype flat record with the field data replaced by"
45
" the field name on the standard output and exit.]"
46
"[s:struct?Print the fixed width record schema C \bstruct\b on the standard"
47
" output and exit.]"
48
"[T:test?Enable implementation-specific tests and tracing.]#[mask]"
49
"[+TAGS?The supported tags are:]{"
50
;
51
52
#include <dsslib.h>
53
#include <ccode.h>
54
#include <magicid.h>
55
#include <regex.h>
56
57
struct Flatten_s; typedef struct Flatten_s Flatten_t;
58
struct Field_s; typedef struct Field_s Field_t;
59
struct Flat_s; typedef struct Flat_s Flat_t;
60
struct Format_s; typedef struct Format_s Format_t;
61
struct Key_s; typedef struct Key_s Key_t;
62
struct Library_s; typedef struct Library_s Library_t;
63
struct Magic_s; typedef struct Magic_s Magic_t;
64
struct Member_s; typedef struct Member_s Member_t;
65
struct Physical_s; typedef struct Physical_s Physical_t;
66
struct Record_s; typedef struct Record_s Record_t;
67
struct Section_s; typedef struct Section_s Section_t;
68
struct Size_s; typedef struct Size_s Size_t;
69
struct Table_s; typedef struct Table_s Table_t;
70
struct Value_s; typedef struct Value_s Value_t;
71
72
typedef Cxvalue_t* (*Flattenget_f)(Flatten_t*, Cxvariable_t*, void*);
73
typedef Cxoperand_t* (*Flatget_f)(Record_t*, int);
74
75
struct Value_s
76
{
77
const char* name;
78
long value;
79
};
80
81
struct Physical_s /* physical field info */
82
{
83
Cxtype_t* type; /* type */
84
Cxformat_t format; /* format details */
85
Cxarray_t* array; /* physical array info */
86
};
87
88
struct Flatten_s
89
{
90
Dss_t* dss; /* output method stream */
91
Dssfile_t* file; /* output file */
92
Cx_t* cx; /* dss->cx */
93
Flat_t* flat; /* dss->meth->data */
94
Vmalloc_t* vm; /* vm region */
95
Cxcallout_f getf; /* dss->cx->getf */
96
Cxoperand_t value; /* flattenget() value */
97
int emptyspace; /* empty field value => space */
98
};
99
100
struct Table_s /* key table info */
101
{
102
Dtdisc_t disc; /* dict discipline */
103
Sfio_t* oob; /* out of band stream */
104
Dt_t* dict; /* dictionary */
105
int span; /* key value span char */
106
unsigned char identified; /* id table initialized */
107
unsigned char qualified; /* qualification check done */
108
unsigned char unknown; /* span unknown keys */
109
char id[UCHAR_MAX+1];/* identifier test map */
110
};
111
112
struct Field_s /* field info */
113
{
114
Cxvariable_t variable; /* logical field variable */
115
Physical_t physical; /* physical field info */
116
Field_t* next; /* next in list */
117
Cxexpr_t* width; /* variable size */
118
Cxvariable_t* flatten; /* flatten source variable */
119
Flattenget_f flattengetf; /* flatten flatget() */
120
Flatget_f flatgetf; /* flat flatget() */
121
Cxstructure_t structure; /* structure info */
122
Record_t* record; /* sub-record context */
123
Table_t* table; /* parse time table holder */
124
size_t truncate; /* fixed width before truncation*/
125
unsigned char* map; /* physical.format.code map */
126
unsigned char* pam; /* conversion map */
127
unsigned char keyed; /* name=value key */
128
unsigned char structref; /* struct w/ member values only */
129
};
130
131
struct Key_s /* field key */
132
{
133
Dtlink_t link; /* dictionary link */
134
Key_t* next; /* ambiguous key link */
135
Field_t* field; /* field for this key */
136
char* qualification; /* key qualification */
137
Cxexpr_t* expr; /* key qualification expression */
138
char name[1]; /* key name */
139
};
140
141
struct Member_s /* record member */
142
{
143
Cxoperand_t ret; /* value (first for dynamic Q) */
144
Field_t* field; /* static field info */
145
Cxtype_t* type; /* dynamic record data type */
146
size_t off; /* record data offset */
147
size_t siz; /* record data size */
148
unsigned int serial; /* read serial number */
149
unsigned int keyed; /* keyed serial number */
150
};
151
152
struct Record_s /* current record info */
153
{
154
Member_t* fields; /* fields (first for dynamic Q) */
155
Flatget_f getf; /* getf (second for dynamic Q) */
156
Dss_t* dss; /* dss handle */
157
Flat_t* flat; /* flat handle */
158
Dssrecord_t* record; /* dss record handle */
159
Cx_t* cx; /* cx handle */
160
Sfio_t* io; /* io stream */
161
Table_t* table; /* key table */
162
char* image; /* original record data buffer */
163
char* buf; /* record data buffer */
164
char* cur; /* current position in buf */
165
size_t siz; /* record data buffer size */
166
size_t offset; /* subrecord field offset */
167
size_t nfields; /* #fields per record */
168
size_t kfields; /* first keyed field index */
169
size_t serial; /* record serial */
170
size_t copy; /* record copy serial */
171
int index; /* next field index */
172
};
173
174
struct Section_s /* section info */
175
{
176
Section_t* next; /* next in list */
177
regex_t* re; /* section line pattern */
178
int delimiter; /* section record delimiter */
179
size_t count; /* pattern/delimiter count */
180
size_t size; /* section size */
181
};
182
183
struct Magic_s /* magic info */
184
{
185
const char* string; /* magic string */
186
unsigned long number; /* magic number */
187
size_t size; /* magic header size */
188
size_t length; /* magic number/string length */
189
unsigned long version; /* version stamp */
190
int swap; /* swap op */
191
};
192
193
struct Library_s /* library list */
194
{
195
Library_t* next; /* next in list */
196
char name[1]; /* library name */
197
};
198
199
struct Size_s /* block/record size field info */
200
{
201
size_t fixed; /* fixed size */
202
int type; /* field type */
203
int width; /* field width */
204
int offset; /* field offset */
205
int reserve; /* min reserve size */
206
int size; /* total field size */
207
int base; /* numeric text base */
208
unsigned char add; /* add size to computed size */
209
char* buf; /* conversion buffer */
210
};
211
212
struct Flat_s /* Dssmeth_t.data */
213
{
214
Dsstagdisc_t dsstagdisc;
215
Dssmeth_t meth;
216
Dssmeth_t* basemeth;
217
int nfields;
218
Magic_t* magic;
219
Section_t* section;
220
Section_t* header;
221
Section_t* lastheader;
222
Section_t* trailer;
223
Section_t* lasttrailer;
224
Cxflags_t flags;
225
Cxflags_t test;
226
int binary;
227
int code;
228
int continuator;
229
int delimiter;
230
int emptyspace;
231
int escape;
232
int force;
233
int list;
234
int prototype;
235
int quotebegin;
236
int quoteend;
237
int sufficient;
238
int swap;
239
int terminator;
240
int variable;
241
size_t fixed;
242
Sfio_t* buf;
243
Field_t* fields;
244
Field_t* lastfield;
245
Field_t root;
246
Cxarray_t* array;
247
Cxformat_t* format;
248
Library_t* libraries;
249
Library_t* lastlibrary;
250
char* valbuf;
251
size_t valsiz;
252
Record_t* current;
253
Flatget_f getf;
254
unsigned char* e2a;
255
Size_t* record;
256
Size_t* block;
257
struct
258
{
259
size_t* field;
260
size_t index;
261
int fixed;
262
} truncate;
263
};
264
265
#define FW(f,w) (((w)<<4)|((f)&(CX_STRING|CX_INTEGER|CX_UNSIGNED|CX_FLOAT)))
266
267
#define SWAP(n) (((n)^int_swap)&07)
268
269
#define SWAP_none (-1)
270
#define SWAP_native (-2)
271
#define SWAP_be 0
272
#define SWAP_le 7
273
274
static Cxvalue_t nullval;
275
static Cxoperand_t nullret;
276
277
/*
278
* lazy flat field retrieval
279
*/
280
281
static Cxoperand_t*
282
flatget(register Record_t* r, int index)
283
{
284
Flat_t* flat = r->flat;
285
register Member_t* w;
286
register Member_t* p;
287
register Member_t* y;
288
register Field_t* f;
289
register unsigned char* s;
290
register unsigned char* t;
291
register unsigned char* u;
292
register unsigned char* e;
293
register unsigned char* h;
294
unsigned char* g;
295
unsigned char* m;
296
Record_t* b;
297
Cxoperand_t* v;
298
Key_t* k;
299
Cxoperand_t a;
300
int c;
301
int d;
302
int q;
303
int x;
304
size_t n;
305
306
if (index >= r->nfields)
307
return &nullret;
308
w = &r->fields[index];
309
if (w->serial != r->serial)
310
{
311
w->serial = r->serial;
312
if (w->field->structure.level > 1 && !(((Field_t*)w->field->structure.parent))->structref)
313
{
314
b = ((Field_t*)w->field->structure.parent)->record;
315
if (b->serial != r->serial)
316
{
317
b->serial = r->serial;
318
b->index = b->offset;
319
if (!(v = flatget(r, w->field->structure.parent->index)))
320
goto empty;
321
if (b->buf = b->cur = v->value.string.data)
322
{
323
b->siz = v->value.string.size;
324
r = b;
325
}
326
}
327
else if (b->buf)
328
r = b;
329
}
330
if (r->index <= index && r->index < r->kfields)
331
{
332
s = (unsigned char*)r->cur;
333
e = (unsigned char*)r->buf + r->siz;
334
if (index < r->kfields)
335
{
336
y = w;
337
if (w->field->structref)
338
y--;
339
}
340
else
341
{
342
y = &r->fields[r->kfields - 1];
343
sfstrseek(r->table->oob, 0, SEEK_SET);
344
}
345
for (p = &r->fields[r->index]; p <= y; p++)
346
{
347
f = p->field;
348
d = f->physical.format.delimiter;
349
if (d >= 0)
350
{
351
if (f->width)
352
{
353
if (cxeval(r->cx, f->width, r->record, &a) < 0)
354
goto empty;
355
n = a.value.number;
356
}
357
else if (f->physical.format.escape < 0 && f->physical.format.quotebegin < 0)
358
{
359
for (t = s; t < e && *t != d; t++);
360
n = t - s;
361
t++;
362
}
363
else
364
{
365
q = f->physical.format.quotebegin;
366
x = f->physical.format.escape;
367
if ((s + 1) >= e || *s != q)
368
{
369
n = 1;
370
if (f->physical.format.flags & CX_QUOTEALL)
371
q = -1;
372
}
373
else
374
{
375
s++;
376
n = 0;
377
q = f->physical.format.quoteend;
378
}
379
for (u = t = s; t < e; t++)
380
{
381
if ((c = *t) == x)
382
{
383
if (++t >= e)
384
{
385
if (r->dss->disc->errorf)
386
(*r->dss->disc->errorf)(r->dss, r->dss->disc, 2, "%sinvalid escape", cxlocation(r->cx, r->record), p->field->variable.name);
387
r->index = r->nfields + 1;
388
goto empty;
389
}
390
c = *t;
391
}
392
else if (n)
393
{
394
if (c == d || c == flat->terminator)
395
break;
396
if (c == q)
397
{
398
n = 0;
399
q = f->physical.format.quoteend;
400
continue;
401
}
402
}
403
else if (c == q)
404
{
405
if (x >= 0 || (t + 1) >= e || *(t + 1) != c)
406
{
407
n = 1;
408
q = f->physical.format.quotebegin;
409
continue;
410
}
411
t++;
412
}
413
if (u < t)
414
{
415
/*
416
* modify a copy of the input record image
417
*/
418
419
if (r->copy != r->serial && (h = vmnewof(r->cx->rm, 0, unsigned char, r->siz, 0)))
420
{
421
r->copy = r->serial;
422
memcpy(h, r->buf, r->siz);
423
r->cur = (char*)h + (r->cur - r->buf);
424
s = h + (s - (unsigned char*)r->buf);
425
t = h + (t - (unsigned char*)r->buf);
426
u = h + (u - (unsigned char*)r->buf);
427
e = h + r->siz;
428
r->buf = (char*)h;
429
}
430
*u = c;
431
}
432
u++;
433
}
434
if (!n)
435
{
436
if (r->dss->disc->errorf)
437
(*r->dss->disc->errorf)(r->dss, r->dss->disc, 2, "%s%s: unterminated quote", cxlocation(r->cx, r->record), p->field->variable.name);
438
r->index = r->nfields + 1;
439
goto empty;
440
}
441
n = u - s;
442
t++;
443
}
444
if (d == '\n' && n > 0 && *(s + n - 1) == '\r')
445
n--;
446
if (f->physical.format.flags & CX_MULTIPLE)
447
while (t < e && *t == d)
448
t++;
449
}
450
else
451
{
452
if (f->width)
453
{
454
if (cxeval(r->cx, f->width, r->record, &a) < 0)
455
goto empty;
456
n = a.value.number;
457
}
458
else if (f->physical.format.flags & CX_VARIABLE)
459
n = e - s;
460
else
461
n = f->physical.format.width;
462
t = s + n;
463
}
464
p->off = (char*)s - r->buf;
465
p->siz = n;
466
s = t;
467
}
468
r->index = index + 1;
469
if (w->field->structref)
470
goto empty;
471
r->cur = (char*)s;
472
}
473
else if (w->field->structref)
474
goto empty;
475
if (w->field->keyed)
476
{
477
if (w->keyed != r->serial)
478
{
479
d = w->field->physical.format.delimiter; /*HERE verify*/
480
s = (unsigned char*)r->cur;
481
e = (unsigned char*)r->buf + r->siz - 1;
482
while (s < e)
483
{
484
if ((u = s) < e && (r->table->id[*(unsigned char*)s] & 1))
485
for (s++; s < e && r->table->id[*(unsigned char*)s]; s++);
486
t = s;
487
for (;;)
488
{
489
for (; s < e && *s != d; s++);
490
if (r->table->span < 0)
491
break;
492
for (h = s; h < e && *h == d; h++);
493
if (h >= e)
494
break;
495
if (r->table->id[*(unsigned char*)h] & 1)
496
{
497
for (g = h++; h < e && r->table->id[*(unsigned char*)h]; h++);
498
if (h < e && *h == r->table->span && (!r->table->unknown || dtmatch(r->table->dict, g)))
499
break;
500
}
501
s = h;
502
}
503
if (t > u && s > t)
504
{
505
if (k = (Key_t*)dtmatch(r->table->dict, u))
506
{
507
while (t < s && isspace(*++t));
508
for (u = s++; u > t && isspace(*(u - 1)); u--);
509
do
510
{
511
if (!k->expr || cxeval(r->cx, k->expr, r->record, &a) > 0)
512
{
513
p = &r->fields[k->field->variable.index];
514
p->off = t - (unsigned char*)r->buf;
515
p->siz = u - t;
516
p->keyed = r->serial;
517
break;
518
}
519
} while (k = k->next);
520
if (p == w)
521
break;
522
continue;
523
}
524
else if (s > (t + 1) && (r->dss->flags & DSS_VERBOSE) && r->dss->disc->errorf)
525
(*r->dss->disc->errorf)(r->dss, r->dss->disc, 2, "%s%-.*s: unknown key", cxlocation(r->cx, r->record), t - u, u);
526
}
527
if (sfstrtell(r->table->oob))
528
sfputc(r->table->oob, d);
529
for (t = s++; t > u && isspace(*(t - 1)); t--);
530
sfwrite(r->table->oob, u, t - u);
531
}
532
r->cur = (char*)s;
533
if (w->keyed != r->serial)
534
{
535
if (w->field->keyed > 1)
536
{
537
w->off = 0;
538
w->siz = sfstrtell(r->table->oob);
539
s = (unsigned char*)sfstrbase(r->table->oob);
540
goto found;
541
}
542
goto empty;
543
}
544
}
545
}
546
s = (unsigned char*)r->buf + w->off;
547
found:
548
if (w->field->width)
549
{
550
if (cxeval(r->cx, w->field->width, r->record, &a) < 0)
551
goto empty;
552
n = a.value.number;
553
if (w->field->physical.format.width && n > w->field->physical.format.width)
554
{
555
if (r->dss->disc->errorf)
556
(*r->dss->disc->errorf)(r->dss, r->dss->disc, 1, "%s%s: variable field width %d exceeds fixed maximum %d -- maximum assumed", cxlocation(r->cx, r->record), w->field->variable.name, n, w->field->physical.format.width);
557
w->siz = w->field->physical.format.width;
558
}
559
else
560
{
561
w->siz = n;
562
if (!flat->fixed)
563
r->cur = (char*)s + w->siz;
564
else if (flat->sufficient && w->field->physical.format.width)
565
r->cur = (char*)s + w->field->physical.format.width;
566
else
567
{
568
r->cur = (char*)s + w->siz;
569
for (y = w; y < &r->fields[r->nfields - 1]; y++)
570
{
571
n = y->off + y->siz;
572
(++y)->off = n;
573
if (y->field->width)
574
break;
575
}
576
}
577
}
578
}
579
else if (w->field->physical.format.flags & CX_VARIABLE)
580
w->siz = r->siz - w->off;
581
if (m = w->field->map)
582
s = (unsigned char*)ccmapcpy(m, fmtbuf(w->siz), (char*)s, w->siz);
583
w->ret.type = w->field->variable.type;
584
if ((*w->field->physical.type->internalf)(r->cx, w->field->physical.type, NiL, &w->field->physical.format, &w->ret, (char*)s, w->siz, r->cx->rm, r->cx->disc) < 0)
585
{
586
empty:
587
w->ret.type = w->field->variable.type;
588
if (cxisstring(w->ret.type))
589
{
590
w->ret.value.string.data = "";
591
w->ret.value.string.size = 0;
592
}
593
else
594
w->ret.value.number = 0;
595
}
596
if (w->ret.type->generic)
597
for (x = 0; w->ret.type->generic[x]; x++)
598
if (w->ret.type->generic[x]->base == w->field->physical.type || w->ret.type->generic[x]->base == w->field->physical.type->base)
599
{
600
w->ret.type = w->ret.type->generic[x];
601
break;
602
}
603
}
604
return &w->ret;
605
}
606
607
/*
608
* lazy flat field retrieval for aligned binary data
609
*/
610
611
static Cxoperand_t*
612
flatgetbinary(register Record_t* r, int index)
613
{
614
register Member_t* w = &r->fields[index];
615
register char* s;
616
617
w->ret.type = w->field->variable.type;
618
if (w->serial != r->serial)
619
{
620
w->serial = r->serial;
621
switch (FW(w->field->physical.format.flags,w->field->physical.format.width))
622
{
623
case FW(CX_UNSIGNED|CX_INTEGER,1):
624
w->ret.value.number = *(uint8_t*)(r->buf + w->off);
625
break;
626
case FW(CX_UNSIGNED|CX_INTEGER,2):
627
w->ret.value.number = *(uint16_t*)(r->buf + w->off);
628
break;
629
case FW(CX_UNSIGNED|CX_INTEGER,4):
630
w->ret.value.number = *(uint32_t*)(r->buf + w->off);
631
break;
632
#if _typ_int64_t
633
case FW(CX_UNSIGNED|CX_INTEGER,8):
634
w->ret.value.number = (int64_t)(*(uint64_t*)(r->buf + w->off));
635
break;
636
#endif
637
case FW(CX_INTEGER,1):
638
w->ret.value.number = *(unsigned _ast_int1_t*)(r->buf + w->off);
639
break;
640
case FW(CX_INTEGER,2):
641
w->ret.value.number = *(int16_t*)(r->buf + w->off);
642
break;
643
case FW(CX_INTEGER,4):
644
w->ret.value.number = *(int32_t*)(r->buf + w->off);
645
break;
646
#if _typ_int64_t
647
case FW(CX_INTEGER,8):
648
w->ret.value.number = *(int64_t*)(r->buf + w->off);
649
break;
650
#endif
651
case FW(CX_FLOAT,4):
652
w->ret.value.number = *(_ast_flt4_t*)(r->buf + w->off);
653
break;
654
case FW(CX_FLOAT,8):
655
w->ret.value.number = *(_ast_flt8_t*)(r->buf + w->off);
656
break;
657
#ifdef _ast_flt12_t
658
case FW(CX_FLOAT,12):
659
w->ret.value.number = *(_ast_flt12_t*)(r->buf + w->off);
660
break;
661
#endif
662
#ifdef _ast_flt16_t
663
case FW(CX_FLOAT,16):
664
w->ret.value.number = *(_ast_flt16_t*)(r->buf + w->off);
665
break;
666
#endif
667
default:
668
if (!(w->siz = w->field->physical.format.width))
669
w->ret.value.string.size = 0;
670
else if ((w->field->physical.format.flags & (CX_STRING|CX_NUL)) == CX_STRING)
671
w->ret.value.string.size = (s = memchr(w->ret.value.string.data = r->buf + w->off, 0, w->siz)) ? (s - (r->buf + w->off)) : w->siz;
672
else
673
memcpy(&w->ret.value.number, r->buf + w->off, w->siz);
674
break;
675
}
676
}
677
return &w->ret;
678
}
679
680
/*
681
* flat identf
682
*/
683
684
static int
685
flatident(Dssfile_t* file, void* buf, size_t n, Dssdisc_t* disc)
686
{
687
register Flat_t* flat = (Flat_t*)file->dss->meth->data;
688
register Magicid_t* magicid;
689
register unsigned char* s;
690
register unsigned char* e;
691
int i;
692
int swap;
693
unsigned long num;
694
Magicid_data_t magic;
695
unsigned char tmp[4];
696
697
if (!flat->magic)
698
return 1;
699
if (flat->magic->version)
700
{
701
if (n < sizeof(Magicid_t))
702
return 0;
703
magicid = (Magicid_t*)buf;
704
magic = MAGICID;
705
if ((swap = swapop(&magic, &magicid->magic, sizeof(magic))) < 0)
706
return 0;
707
if (swap)
708
{
709
swapmem(swap, &magicid->size, &magicid->size, sizeof(magicid->size));
710
swapmem(swap, &magicid->version, &magicid->version, sizeof(magicid->version));
711
}
712
if (n < magicid->size)
713
return 0;
714
if (!streq(file->dss->id, magicid->name))
715
return 0;
716
if (flat->magic->string && !streq(flat->magic->string, magicid->type))
717
return 0;
718
s = (unsigned char*)buf + sizeof(Magicid_t);
719
e = (unsigned char*)buf + magicid->size;
720
while (s < e)
721
if (*s++)
722
return 0;
723
if (flat->fixed && magicid->size != flat->fixed)
724
{
725
if (disc->errorf)
726
(*disc->errorf)(NiL, disc, 2, "%s: data size %d does not match schema size %d", file->path, magicid->size, flat->fixed);
727
return -1;
728
}
729
if (magicid->version > flat->magic->version)
730
{
731
if (disc->errorf)
732
(*disc->errorf)(NiL, disc, 2, "%s: data version %s is newer than schema version %s", file->path, fmtversion(magicid->size), fmtversion(flat->fixed));
733
return -1;
734
}
735
if (flat->magic->swap == SWAP_native)
736
file->ident = swap;
737
else if (flat->magic->swap >= 0)
738
file->ident = swap ^ flat->magic->swap;
739
file->skip = magicid->size;
740
return 1;
741
}
742
if (n < flat->magic->size)
743
return 0;
744
if (flat->magic->string)
745
{
746
if (!memcmp(buf, flat->magic->string, flat->magic->length))
747
{
748
file->skip = flat->magic->size;
749
return 1;
750
}
751
}
752
else
753
{
754
num = flat->magic->number;
755
i = flat->magic->length;
756
while (i-- > 0)
757
{
758
tmp[i] = num & 0xff;
759
num >>= 8;
760
}
761
if ((swap = swapop(tmp, buf, flat->magic->length)) >= 0)
762
{
763
if (flat->magic->swap == SWAP_native)
764
file->ident = swap;
765
else if (flat->magic->swap >= 0)
766
file->ident = swap ^ flat->magic->swap;
767
file->skip = flat->magic->size;
768
return 1;
769
}
770
}
771
return 0;
772
}
773
774
/*
775
* get record/block size field
776
*/
777
778
static ssize_t
779
size_get(register Dssfile_t* file, register Size_t* z, Dssdisc_t* disc)
780
{
781
register char* b;
782
register char* s;
783
register char* e;
784
register ssize_t n;
785
786
if (!z->width)
787
return z->reserve;
788
if (!(b = (char*)sfreserve(file->io, z->reserve, z->add != 0)))
789
return sfvalue(file->io);
790
s = b + z->offset;
791
switch (z->type)
792
{
793
case 'a':
794
n = strntoul(s, z->width, NiL, z->base);
795
break;
796
case 'b':
797
n = swapget(0, s, z->width);
798
break;
799
case 'd':
800
n = 0;
801
for (e = s + z->width; s < e; s++)
802
n = n * 100 + 10 * (*(unsigned char*)s >> 4) + (*s & 0xf);
803
if (z->base & 1)
804
n /= 10;
805
break;
806
case 'e':
807
s = (char*)ccmapcpy(((Flat_t*)disc)->e2a, z->buf, s, z->width);
808
n = strntoul(s, z->width, NiL, z->base);
809
break;
810
case 'l':
811
n = swapget(3, s, z->width);
812
break;
813
case 'm':
814
n = swapget(((Flat_t*)disc)->swap, s, z->width);
815
break;
816
}
817
if (z->add)
818
sfread(file->io, b, 0);
819
return n;
820
}
821
822
/*
823
* flat readf
824
*/
825
826
static int
827
flatread(register Dssfile_t* file, register Dssrecord_t* record, Dssdisc_t* disc)
828
{
829
register Record_t* r = (Record_t*)file->data;
830
register Flat_t* flat = r->flat;
831
register char* s;
832
register ssize_t i;
833
size_t j;
834
size_t k;
835
size_t m;
836
Field_t* f;
837
Field_t* p;
838
839
for (;;)
840
{
841
if (!++r->serial)
842
{
843
r->serial = 1;
844
r->copy = 0;
845
for (i = 0; i < r->nfields; i++)
846
r->fields[i].serial = r->fields[i].keyed = 0;
847
if (flat->fixed && flat->terminator >= 0 && !flat->truncate.field)
848
{
849
/*
850
* if the first record doesn't have a terminator
851
* then we ignore the terminator for all records;
852
* only string fields are checked
853
*/
854
855
if (s = (char*)sfreserve(file->io, flat->fixed, SF_LOCKR))
856
{
857
if ((j = sfvalue(file->io)) > flat->fixed)
858
j = flat->fixed + 1;
859
f = flat->fields;
860
m = f->physical.format.width;
861
for (k = 0;; k++)
862
{
863
if (k >= j)
864
{
865
flat->terminator = -1;
866
break;
867
}
868
if (k >= m)
869
{
870
if (f = f->next)
871
m += f->physical.format.width;
872
else
873
{
874
if (s[k] != flat->terminator)
875
flat->terminator = -1;
876
break;
877
}
878
}
879
if (((unsigned char*)s)[k] == flat->terminator && (f->physical.format.flags & CX_STRING))
880
break;
881
}
882
sfread(file->io, s, 0);
883
}
884
else
885
flat->terminator = -1;
886
if (flat->terminator >= 0)
887
{
888
flat->variable = 0;
889
flat->truncate.index = flat->nfields;
890
if (!(flat->truncate.field = newof(0, size_t, flat->fixed, 0)))
891
{
892
if (disc->errorf)
893
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
894
return -1;
895
}
896
k = 0;
897
for (f = flat->fields; f; f = f->next)
898
{
899
f->truncate = f->physical.format.width;
900
m = k + f->physical.format.width;
901
while (k < m)
902
flat->truncate.field[k++] = f->variable.index;
903
}
904
}
905
else
906
{
907
flat->sufficient = 1;
908
if (disc->errorf && !(file->dss->flags & DSS_QUIET))
909
(*disc->errorf)(NiL, disc, 1, "%sflat record terminator ignored", cxlocation(r->cx, record));
910
}
911
}
912
}
913
if (flat->terminator >= 0)
914
{
915
if (flat->continuator >= 0)
916
{
917
if (!(s = sfgetr(file->io, flat->terminator, 0)))
918
break;
919
i = sfvalue(file->io);
920
if (i > 1 && *(s + i - 2) == flat->continuator)
921
{
922
for (;;)
923
{
924
s[i - 2] = flat->delimiter;
925
sfwrite(flat->buf, s, i - 1);
926
if (!(s = sfgetr(file->io, flat->terminator, 0)))
927
goto eof;
928
i = sfvalue(file->io);
929
if (i < 2 || *(s + i - 2) != flat->continuator)
930
{
931
sfwrite(flat->buf, s, i);
932
break;
933
}
934
}
935
i = sfstrtell(flat->buf);
936
s = sfstrseek(flat->buf, 0, SEEK_SET);
937
}
938
}
939
else
940
{
941
if (!(s = sfgetr(file->io, flat->terminator, 0)))
942
break;
943
i = sfvalue(file->io);
944
}
945
if (flat->fixed)
946
{
947
if (flat->sufficient = flat->fixed == (i - 1))
948
k = r->nfields;
949
else if (!flat->truncate.field)
950
{
951
if (disc->errorf)
952
(*disc->errorf)(NiL, disc, 2, "%sinvalid record length %d -- record ignored", cxlocation(r->cx, record), i);
953
continue;
954
}
955
else if (i <= flat->fixed)
956
{
957
f = r->fields[flat->truncate.field[i-1]].field;
958
f->physical.format.width = i - r->fields[f->variable.index].off - 1;
959
p = f;
960
while (p = p->next)
961
p->physical.format.width = 0;
962
k = f->variable.index;
963
}
964
else
965
k = r->nfields;
966
for (j = flat->truncate.index; j < k; j++)
967
r->fields[j].field->physical.format.width = r->fields[j].field->truncate;
968
flat->truncate.index = k;
969
}
970
r->index = 0;
971
}
972
else if (i = flat->fixed)
973
{
974
if (flat->record && (i = size_get(file, flat->record, disc)) <= 0)
975
break;
976
if (!(s = (char*)sfreserve(file->io, i, flat->variable)) && (!flat->variable || !(i = sfvalue(file->io)) || !(s = (char*)sfreserve(file->io, i, flat->variable))))
977
break;
978
}
979
else
980
{
981
if (disc->errorf)
982
(*disc->errorf)(NiL, disc, 2, "%snon-unique terminator record read not implemented", cxlocation(r->cx, record));
983
return -1;
984
}
985
r->image = r->buf = r->cur = s;
986
r->siz = i;
987
r->record = record;
988
record->data = flat->current = r;
989
if (flat->force)
990
{
991
for (j = 0; j < r->nfields; j++)
992
if (!r->fields[j].field->structref)
993
(*flat->getf)(r, j);
994
if (flat->variable)
995
{
996
i = r->fields[r->nfields - 1].off + r->fields[r->nfields - 1].siz;
997
sfread(file->io, s, i);
998
}
999
}
1000
record->size = r->siz = i;
1001
return 1;
1002
}
1003
eof:
1004
if (sfvalue(file->io) && disc->errorf)
1005
(*disc->errorf)(NiL, disc, 2, "%slast record truncated (%ld/%ld)", cxlocation(r->cx, record), (long)sfvalue(file->io), (long)flat->fixed);
1006
return 0;
1007
}
1008
1009
/*
1010
* flat writef
1011
*/
1012
1013
static int
1014
flatwrite(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
1015
{
1016
register Record_t* r = (Record_t*)record->data;
1017
register Flat_t* flat = r->flat;
1018
register Field_t* f;
1019
register int i;
1020
register unsigned char* s;
1021
Cxoperand_t* v;
1022
ssize_t n;
1023
unsigned char* b;
1024
unsigned char* e;
1025
int q;
1026
1027
if (r == flat->current)
1028
return sfwrite(file->io, r->image, r->siz) == r->siz ? 0 : -1;
1029
for (i = 0; i < r->nfields; i++)
1030
{
1031
f = r->fields[i].field;
1032
v = (*f->flatgetf)(r, i);
1033
while ((n = (*f->physical.type->externalf)(r->cx, f->physical.type, NiL, &f->physical.format, &v->value, flat->valbuf, flat->valsiz, r->cx->disc)) > flat->valsiz)
1034
{
1035
n = roundof(n, 32);
1036
if (!(flat->valbuf = newof(flat->valbuf, char, n, 0)))
1037
{
1038
if (disc->errorf)
1039
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1040
return -1;
1041
}
1042
flat->valsiz = n;
1043
}
1044
if (n < 0)
1045
return -1;
1046
else if (n > 0)
1047
{
1048
if ((f->physical.format.flags & (CX_STRING|CX_BUFFER)) && f->physical.format.delimiter >= 0 && (f->physical.format.escape >= 0 || f->physical.format.quotebegin >= 0))
1049
{
1050
if (f->physical.format.flags & CX_QUOTEALL)
1051
{
1052
q = 1;
1053
sfputc(file->io, f->physical.format.quotebegin);
1054
}
1055
else
1056
q = 0;
1057
for (e = (s = b = (unsigned char*)flat->valbuf) + n; s < e; s++)
1058
if (*s == f->physical.format.delimiter || *s == f->physical.format.escape || *s == f->physical.format.quotebegin || *s == f->physical.format.quoteend)
1059
{
1060
if (f->physical.format.escape >= 0)
1061
{
1062
sfwrite(file->io, b, s - b);
1063
sfputc(file->io, f->physical.format.escape);
1064
sfputc(file->io, *s);
1065
}
1066
else if (*s == f->physical.format.delimiter)
1067
{
1068
if (q)
1069
continue;
1070
q = 1;
1071
sfwrite(file->io, b, s - b);
1072
sfputc(file->io, f->physical.format.quotebegin);
1073
sfputc(file->io, *s);
1074
}
1075
else
1076
{
1077
sfwrite(file->io, b, s - b + 1);
1078
sfputc(file->io, *s);
1079
if (!q)
1080
{
1081
q = 1;
1082
sfputc(file->io, *s);
1083
}
1084
}
1085
b = s + 1;
1086
}
1087
if (q && !(f->physical.format.flags & CX_QUOTEALL))
1088
{
1089
q = 0;
1090
sfputc(file->io, f->physical.format.quoteend);
1091
}
1092
sfwrite(file->io, b, s - b);
1093
if (q)
1094
sfputc(file->io, f->physical.format.quoteend);
1095
}
1096
else
1097
sfwrite(file->io, flat->valbuf, n);
1098
}
1099
else if (flat->emptyspace && f->physical.format.delimiter >= 0)
1100
sfputc(file->io, ' ');
1101
if (f->physical.format.delimiter >= 0)
1102
sfputc(file->io, f->physical.format.delimiter);
1103
}
1104
return 0;
1105
}
1106
1107
/*
1108
* skip file sections in s
1109
*/
1110
1111
static int
1112
skip(Dssfile_t* file, const char* section, register Section_t* s, Dssdisc_t* disc)
1113
{
1114
register size_t i;
1115
register char* t;
1116
register char* u;
1117
int code;
1118
1119
for (; s; s = s->next)
1120
{
1121
i = s->count;
1122
do
1123
{
1124
if (s->delimiter >= 0)
1125
{
1126
if (!(t = sfgetr(file->io, s->delimiter, 0)))
1127
goto eof;
1128
}
1129
else if (s->size > 0)
1130
{
1131
if (!(t = sfreserve(file->io, s->size, 0)))
1132
goto eof;
1133
}
1134
else
1135
break;
1136
if (s->re && (code = regnexec(s->re, t, sfvalue(file->io), 0, NiL, 0)))
1137
{
1138
if (code != REG_NOMATCH)
1139
{
1140
if (disc->errorf)
1141
{
1142
char buf[256];
1143
1144
regerror(code, s->re, buf, sizeof(buf));
1145
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: %s: regular expression: %s", file->path, section, buf);
1146
}
1147
return -1;
1148
}
1149
for (u = t + sfvalue(file->io); u > t;)
1150
sfungetc(file->io, *--u);
1151
break;
1152
}
1153
} while (!i || --i);
1154
}
1155
return 0;
1156
eof:
1157
if (disc->errorf)
1158
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: unexpected EOF in %s", file->path, section);
1159
return -1;
1160
}
1161
1162
static int
1163
keycmp(Dt_t* dt, void* va, void* vb, Dtdisc_t* disc)
1164
{
1165
register unsigned char* a = (unsigned char*)va;
1166
register unsigned char* b = (unsigned char*)vb;
1167
register char* t = ((Table_t*)disc)->identified ? ((Table_t*)disc)->id : (char*)0;
1168
register int c;
1169
register int d;
1170
1171
while (!(d = (c = *a++) - (int)*b++))
1172
if (!(t ? t[c] : c))
1173
return 0;
1174
return (!*(b - 1) && !(t ? t[c] : c)) ? 0 : d;
1175
}
1176
1177
/*
1178
* allocate and initialize a Table_t
1179
*/
1180
1181
static Table_t*
1182
tabinit(Flat_t* flat, Dssdisc_t* disc)
1183
{
1184
register Table_t* t;
1185
1186
if (!(t = newof(0, Table_t, 1, 0)) || !(t->oob = sfstropen()))
1187
{
1188
if (disc->errorf)
1189
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1190
return 0;
1191
}
1192
t->disc.link = offsetof(Key_t, link);
1193
t->disc.key = offsetof(Key_t, name);
1194
t->disc.comparf = keycmp;
1195
if (!(t->dict = dtopen(&t->disc, Dtoset)))
1196
{
1197
if (disc->errorf)
1198
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1199
return 0;
1200
}
1201
t->span = -1;
1202
return t;
1203
}
1204
1205
static Cxexpr_t*
1206
keycomp(Flat_t* flat, const char* s, Dssdisc_t* disc)
1207
{
1208
Cxexpr_t* expr;
1209
void* pop;
1210
1211
if (!(pop = cxpush(flat->meth.cx, NiL, NiL, s, -1, 0)))
1212
return 0;
1213
expr = cxcomp(flat->meth.cx);
1214
cxpop(flat->meth.cx, pop);
1215
return expr;
1216
}
1217
1218
/*
1219
* final dictionary table initialization
1220
*/
1221
1222
static int
1223
tabcomp(Flat_t* flat, register Table_t* tab, Dssdisc_t* disc)
1224
{
1225
register char* s;
1226
register Key_t* k;
1227
register Key_t* q;
1228
register int i;
1229
1230
if (!tab->identified)
1231
{
1232
tab->identified = 1;
1233
for (i = 0; i <= UCHAR_MAX; i++)
1234
{
1235
if (isalpha(i) || i == '_')
1236
tab->id[i] |= 3;
1237
else if (isdigit(i) || i == '-' || i == '.' || i == ',')
1238
tab->id[i] |= 2;
1239
}
1240
}
1241
for (k = (Key_t*)dtfirst(tab->dict); k; k = (Key_t*)dtnext(tab->dict, k))
1242
for (q = k; q; q = q->next)
1243
{
1244
if (q->qualification && !(q->expr = keycomp(flat, q->qualification, disc)))
1245
{
1246
if (disc->errorf)
1247
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: %s: %s: cannot compile key qualification expression", q->field->variable.name, q->name, q->qualification);
1248
return -1;
1249
}
1250
s = q->name;
1251
tab->id[*s] |= 3;
1252
while (*++s)
1253
tab->id[*s] |= 2;
1254
}
1255
return 0;
1256
}
1257
1258
/*
1259
* allocate and initialize a Record_t
1260
*/
1261
1262
static Record_t*
1263
recinit(register Flat_t* flat, Dssfile_t* file, Record_t* b, Table_t* t, Field_t* fields, size_t n, size_t i, Dssdisc_t* disc)
1264
{
1265
register Field_t* f;
1266
register Record_t* r;
1267
register Key_t* k;
1268
size_t level;
1269
size_t off;
1270
1271
if (!fields)
1272
return 0;
1273
level = fields->structure.level;
1274
if (!n)
1275
for (f = fields; f; f = f->next, n++)
1276
if (f->structure.level < level)
1277
break;
1278
if (!(r = vmnewof(file->dss->vm, 0, Record_t, 1, (level == 1 ? n * sizeof(Member_t) : 0))))
1279
{
1280
if (disc->errorf)
1281
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1282
return 0;
1283
}
1284
r->fields = level == 1 ? (Member_t*)(r + 1) : b->fields;
1285
r->getf = flat->getf;
1286
r->offset = i;
1287
r->serial--;
1288
r->nfields = n + i;
1289
r->kfields = n + i + 1;
1290
if (t && !t->qualified)
1291
{
1292
t->qualified = 1;
1293
for (k = (Key_t*)dtfirst(t->dict); k; k = (Key_t*)dtnext(t->dict, k))
1294
if (k->next && !k->qualification)
1295
error(1, "%s: %s: field key is ambiguous -- qualification required", k->field->variable.name, k->name);
1296
}
1297
off = 0;
1298
for (f = fields; f; f = f->next, i++)
1299
{
1300
if (f->structure.members && !f->record && !(f->record = recinit(flat, file, r, f->table, f->next, 0, i + 1, disc)))
1301
return 0;
1302
if (f->structure.level == level)
1303
{
1304
if (f->keyed && r->kfields == (r->nfields + 1))
1305
r->kfields = i;
1306
}
1307
if (level == 1)
1308
{
1309
r->fields[i].field = f;
1310
if (flat->fixed)
1311
{
1312
if (flat->truncate.fixed)
1313
{
1314
if (off > flat->fixed)
1315
{
1316
off = flat->fixed;
1317
f->physical.format.width = 0;
1318
f->physical.format.delimiter = -1;
1319
}
1320
else if ((off + f->physical.format.width) >= flat->fixed)
1321
{
1322
f->physical.format.width = flat->fixed - off;
1323
f->physical.format.delimiter = -1;
1324
}
1325
}
1326
r->fields[i].off = off;
1327
off += r->fields[i].siz = f->physical.format.width;
1328
if (f->physical.format.delimiter >= 0)
1329
off++;
1330
}
1331
}
1332
}
1333
if (r->kfields <= r->nfields && (!(r->table = t) && !(r->table = tabinit(flat, disc)) || tabcomp(flat, r->table, disc)))
1334
return 0;
1335
if (flat->fixed)
1336
r->index = r->nfields;
1337
r->dss = file->dss;
1338
r->flat = flat;
1339
r->cx = file->dss->cx;
1340
r->io = file->io;
1341
return r;
1342
}
1343
1344
/*
1345
* flat fopenf
1346
*/
1347
1348
static int
1349
flatfopen(Dssfile_t* file, Dssdisc_t* disc)
1350
{
1351
register Flat_t* flat = (Flat_t*)file->dss->meth->data;
1352
size_t i;
1353
1354
if (file->flags & DSS_FILE_READ)
1355
{
1356
#if 0
1357
if (file->ident)
1358
goto noswap;
1359
#endif
1360
#if 0
1361
if (flat->variable)
1362
{
1363
char* s;
1364
1365
i = roundof(flat->fixed, 8 * 1024);
1366
if (s = vmnewof(file->dss->vm, 0, char, i, 0))
1367
sfsetbuf(file->io, s, i);
1368
}
1369
#endif
1370
if (file->skip && !sfreserve(file->io, file->skip, -1))
1371
{
1372
if (disc->errorf)
1373
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: unexpected EOF in magic header", file->path);
1374
return -1;
1375
}
1376
if (flat->header && skip(file, "header", flat->header, disc))
1377
return -1;
1378
}
1379
if (!(file->data = flat->root.record = recinit(flat, file, NiL, flat->root.table, flat->fields, flat->nfields, 0, disc)))
1380
return -1;
1381
if ((file->flags & DSS_FILE_WRITE) && flat->magic)
1382
{
1383
if (flat->swap > 0)
1384
goto noswap;
1385
if (flat->magic->version)
1386
{
1387
Magicid_t magicid;
1388
1389
memset(&magicid, 0, sizeof(Magicid_t));
1390
magicid.magic = MAGICID;
1391
strncopy(magicid.name, file->dss->id, sizeof(magicid.name));
1392
if (flat->magic->string)
1393
strncopy(magicid.type, flat->magic->string, sizeof(magicid.type));
1394
magicid.version = flat->magic->version;
1395
magicid.size = i = flat->fixed ? flat->fixed : sizeof(magicid);
1396
if (flat->magic->swap > 0)
1397
{
1398
swapmem(flat->magic->swap, &magicid.magic, &magicid.magic, sizeof(magicid.magic));
1399
swapmem(flat->magic->swap, &magicid.version, &magicid.version, sizeof(magicid.version));
1400
swapmem(flat->magic->swap, &magicid.size, &magicid.size, sizeof(magicid.size));
1401
}
1402
sfwrite(file->io, &magicid, sizeof(magicid));
1403
i -= sizeof(magicid);
1404
}
1405
else
1406
{
1407
if (flat->magic->string)
1408
sfwrite(file->io, flat->magic->string, flat->magic->length);
1409
else
1410
{
1411
union
1412
{
1413
uint8_t u1;
1414
uint16_t u2;
1415
uint32_t u4;
1416
#if _typ_int64_t
1417
uint64_t u8;
1418
#endif
1419
char buf[sizeof(intmax_t)];
1420
} num;
1421
1422
switch (flat->magic->length)
1423
{
1424
case 1:
1425
num.u1 = flat->magic->number;
1426
break;
1427
case 2:
1428
num.u2 = flat->magic->number;
1429
break;
1430
case 4:
1431
num.u4 = flat->magic->number;
1432
break;
1433
#if _typ_int64_t
1434
case 8:
1435
num.u8 = flat->magic->number;
1436
break;
1437
#endif
1438
}
1439
if (flat->magic->swap > 0)
1440
swapmem(flat->magic->swap, num.buf, num.buf, flat->magic->length);
1441
sfwrite(file->io, num.buf, flat->magic->length);
1442
}
1443
i = flat->magic->size - flat->magic->length;
1444
}
1445
while (i-- > 0)
1446
sfputc(file->io, 0);
1447
if (sferror(file->io))
1448
{
1449
if (disc->errorf)
1450
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|22, "%s: magic header write error", file->path);
1451
return -1;
1452
}
1453
}
1454
return 0;
1455
noswap:
1456
if (disc->errorf)
1457
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: binary record data swap not implemented yet", file->path);
1458
return -1;
1459
}
1460
1461
/*
1462
* flat fclosef
1463
*/
1464
1465
static int
1466
flatfclose(Dssfile_t* file, Dssdisc_t* disc)
1467
{
1468
if (!file || !file->data)
1469
return -1;
1470
vmfree(file->dss->vm, file->data);
1471
return 0;
1472
}
1473
1474
static Dssformat_t flat_format =
1475
{
1476
"flat",
1477
"flat format (2010-11-10)",
1478
CXH,
1479
flatident,
1480
flatfopen,
1481
flatread,
1482
flatwrite,
1483
0,
1484
flatfclose,
1485
0,
1486
0,
1487
0
1488
};
1489
1490
static int
1491
op_get(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
1492
{
1493
#if __APPLE__
1494
Cxoperand_t* x;
1495
1496
x = (*(((Record_t*)DSSDATA(data))->getf))((Record_t*)DSSDATA(data), pc->data.variable->index);
1497
r->type = x->type;
1498
r->refs = x->refs;
1499
r->value.number = x->value.number;
1500
#else
1501
*r = *(*(((Record_t*)DSSDATA(data))->getf))((Record_t*)DSSDATA(data), pc->data.variable->index);
1502
#endif
1503
return 0;
1504
}
1505
1506
static Cxcallout_t local_callouts[] =
1507
{
1508
CXC(CX_GET, "void", "void", op_get, 0)
1509
};
1510
1511
static Tags_t* flat_field_beg(Tag_t*, Tagframe_t*, const char*, Tagdisc_t*);
1512
static int flat_field_end(Tag_t*, Tagframe_t*, Tagdisc_t*);
1513
1514
static Tags_t* flat_field_physical_beg(Tag_t*, Tagframe_t*, const char*, Tagdisc_t*);
1515
static int flat_field_physical_end(Tag_t*, Tagframe_t*, Tagdisc_t*);
1516
1517
static Tags_t* flat_array_physical_beg(Tag_t*, Tagframe_t*, const char*, Tagdisc_t*);
1518
static int flat_array_physical_end(Tag_t*, Tagframe_t*, Tagdisc_t*);
1519
1520
static int
1521
flat_field_name_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1522
{
1523
register Flat_t* flat = (Flat_t*)disc;
1524
1525
if (!(flat->lastfield->variable.name = (const char*)strdup(data)))
1526
{
1527
if (disc->errorf)
1528
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1529
return -1;
1530
}
1531
return 0;
1532
}
1533
1534
static int
1535
flat_field_description_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1536
{
1537
register Flat_t* flat = (Flat_t*)disc;
1538
1539
if (!(flat->lastfield->variable.description = (const char*)strdup(data)))
1540
{
1541
if (disc->errorf)
1542
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1543
return -1;
1544
}
1545
return 0;
1546
}
1547
1548
static int
1549
flat_field_details_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1550
{
1551
register Flat_t* flat = (Flat_t*)disc;
1552
1553
if (!(flat->format->details = strdup(data)))
1554
{
1555
if (disc->errorf)
1556
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1557
return -1;
1558
}
1559
return 0;
1560
}
1561
1562
static int
1563
flat_field_map_end(Tag_t* tag, Tagframe_t* fp, Tagdisc_t* disc)
1564
{
1565
register Flat_t* flat = (Flat_t*)disc;
1566
1567
if (dss_map_end(tag, fp, disc))
1568
return -1;
1569
flat->format->map = (Cxmap_t*)fp->data;
1570
return 0;
1571
}
1572
1573
static int
1574
flat_field_con_end(Tag_t* tag, Tagframe_t* fp, Tagdisc_t* disc)
1575
{
1576
register Flat_t* flat = (Flat_t*)disc;
1577
1578
flat->format->constraint = (Cxconstraint_t*)fp->data;
1579
return 0;
1580
}
1581
1582
static int
1583
flat_field_type_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1584
{
1585
register Flat_t* flat = (Flat_t*)disc;
1586
char* s;
1587
Cxtype_t* t;
1588
1589
(void)cxattr(NiL, data, &s, flat->format, NiL);
1590
if (!*s)
1591
t = (Cxtype_t*)"number";
1592
else if (!(t = (Cxtype_t*)strdup(s)))
1593
{
1594
if (disc->errorf)
1595
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1596
return -1;
1597
}
1598
if (flat->format->flags & CX_FLOAT)
1599
flat->format->flags &= ~(CX_STRING|CX_BUFFER|CX_UNSIGNED|CX_INTEGER);
1600
else if (flat->format->flags & CX_UNSIGNED)
1601
{
1602
flat->format->flags &= ~(CX_STRING|CX_BUFFER);
1603
flat->format->flags |= CX_UNSIGNED|CX_INTEGER;
1604
}
1605
else if (!(flat->format->flags & (CX_STRING|CX_BUFFER|CX_INTEGER)))
1606
{
1607
if (streq(s, "string"))
1608
flat->format->flags |= CX_STRING;
1609
else if (streq(s, "buffer"))
1610
flat->format->flags |= CX_BUFFER;
1611
}
1612
if (flat->format == &flat->lastfield->variable.format)
1613
flat->lastfield->variable.type = t;
1614
else
1615
flat->lastfield->physical.type = t;
1616
return 0;
1617
}
1618
1619
static int
1620
flat_field_delimiter_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1621
{
1622
register Flat_t* flat = (Flat_t*)disc;
1623
1624
flat->format->delimiter = *data;
1625
if (flat->format->code != CC_NATIVE && (fp->attr & TAG_ATTR_conv))
1626
flat->format->delimiter = ccmapc(flat->format->delimiter, CC_NATIVE, flat->format->code);
1627
return 0;
1628
}
1629
1630
static int
1631
flat_field_multiple_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1632
{
1633
register Flat_t* flat = (Flat_t*)disc;
1634
1635
if (strtol(data, NiL, 0) > 0)
1636
flat->format->flags |= CX_MULTIPLE;
1637
else
1638
flat->format->flags &= ~CX_MULTIPLE;
1639
return 0;
1640
}
1641
1642
static int
1643
flat_field_escape_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1644
{
1645
register Flat_t* flat = (Flat_t*)disc;
1646
1647
flat->format->escape = *data;
1648
return 0;
1649
}
1650
1651
static int
1652
flat_field_quotebegin_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1653
{
1654
register Flat_t* flat = (Flat_t*)disc;
1655
1656
flat->format->quotebegin = *data;
1657
return 0;
1658
}
1659
1660
static int
1661
flat_field_quoteend_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1662
{
1663
register Flat_t* flat = (Flat_t*)disc;
1664
1665
flat->format->quoteend = *data;
1666
return 0;
1667
}
1668
1669
static int
1670
flat_field_quoteall_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1671
{
1672
register Flat_t* flat = (Flat_t*)disc;
1673
1674
if (strtol(data, NiL, 0) > 0)
1675
flat->format->flags |= CX_QUOTEALL;
1676
else
1677
flat->format->flags &= ~CX_QUOTEALL;
1678
return 0;
1679
}
1680
1681
static int
1682
flat_field_fixedpoint_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1683
{
1684
register Flat_t* flat = (Flat_t*)disc;
1685
char* e;
1686
1687
flat->format->fixedpoint = strtoul(data, &e, 0);
1688
if (*e)
1689
{
1690
if (disc->errorf)
1691
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
1692
return -1;
1693
}
1694
return 0;
1695
}
1696
1697
static int
1698
flat_field_width_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1699
{
1700
register Flat_t* flat = (Flat_t*)disc;
1701
char* e;
1702
1703
if (isdigit(*data))
1704
{
1705
flat->format->width = strtoul(data, &e, 0);
1706
if (*e)
1707
{
1708
if (disc->errorf)
1709
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
1710
return -1;
1711
}
1712
}
1713
else if (!(flat->lastfield->width = (Cxexpr_t*)strdup(data)))
1714
{
1715
if (disc->errorf)
1716
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1717
return -1;
1718
}
1719
return 0;
1720
}
1721
1722
static int
1723
flat_field_remainder_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1724
{
1725
register Flat_t* flat = (Flat_t*)disc;
1726
char* e;
1727
1728
flat->format->width = strtoul(data, &e, 0);
1729
if (*e)
1730
{
1731
if (disc->errorf)
1732
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
1733
return -1;
1734
}
1735
flat->format->flags |= CX_VARIABLE;
1736
return 0;
1737
}
1738
1739
static int
1740
flat_field_fill_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1741
{
1742
register Flat_t* flat = (Flat_t*)disc;
1743
1744
flat->format->fill = *data;
1745
return 0;
1746
}
1747
1748
static int
1749
flat_field_base_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1750
{
1751
register Flat_t* flat = (Flat_t*)disc;
1752
char* e;
1753
1754
flat->format->base = strtoul(data, &e, 0);
1755
if (*e)
1756
{
1757
if (disc->errorf)
1758
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
1759
return -1;
1760
}
1761
return 0;
1762
}
1763
1764
static int
1765
flat_field_codeset_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1766
{
1767
register Flat_t* flat = (Flat_t*)disc;
1768
1769
if ((flat->format->code = ccmapid(data)) < 0)
1770
{
1771
if (disc->errorf)
1772
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: unknown character code set", data);
1773
return -1;
1774
}
1775
return 0;
1776
}
1777
1778
static int
1779
flat_array_delimiter_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1780
{
1781
register Flat_t* flat = (Flat_t*)disc;
1782
1783
flat->array->delimiter = *data;
1784
return 0;
1785
}
1786
1787
static int
1788
flat_array_size_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1789
{
1790
register Flat_t* flat = (Flat_t*)disc;
1791
char* e;
1792
1793
if (isdigit(*data))
1794
{
1795
flat->array->size = strtoul(data, &e, 0);
1796
if (*e)
1797
{
1798
if (disc->errorf)
1799
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
1800
return -1;
1801
}
1802
}
1803
else if (!(flat->array->variable = (Cxvariable_t*)strdup(data)))
1804
{
1805
if (disc->errorf)
1806
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1807
return -1;
1808
}
1809
return 0;
1810
}
1811
1812
static Tags_t tags_array[] =
1813
{
1814
"SIZE", "Fixed array size or variable size field name.",
1815
0,0,flat_array_size_dat,0,
1816
"PHYSICAL", "Physical (file representation) details; the"
1817
" remaining tags may appear inside <PHYSICAL>."
1818
" Outside of <PHYSICAL> the tags provide logical"
1819
" (print representation) details. Logical details"
1820
" are used as physical defaults.",
1821
0,flat_array_physical_beg,0,flat_array_physical_end,
1822
"DELIMITER", "Array value delimiter character.",
1823
0,0,flat_array_delimiter_dat,0,
1824
0
1825
};
1826
1827
static Tags_t*
1828
flat_array_physical_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
1829
{
1830
register Flat_t* flat = (Flat_t*)disc;
1831
1832
if (name)
1833
{
1834
if (!flat->lastfield->physical.array && !(flat->lastfield->physical.array = newof(0, Cxarray_t, 1, 0)))
1835
{
1836
if (disc->errorf)
1837
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1838
return 0;
1839
}
1840
flat->array = flat->lastfield->physical.array;
1841
}
1842
return &tags_array[2];
1843
}
1844
1845
static int
1846
flat_array_physical_end(Tag_t* tag, Tagframe_t* fp, Tagdisc_t* disc)
1847
{
1848
register Flat_t* flat = (Flat_t*)disc;
1849
1850
flat->array = flat->lastfield->variable.array;
1851
return 0;
1852
}
1853
1854
static Tags_t*
1855
flat_array_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
1856
{
1857
register Flat_t* flat = (Flat_t*)disc;
1858
1859
if (name)
1860
{
1861
if (!flat->lastfield->variable.array && !(flat->lastfield->variable.array = newof(0, Cxarray_t, 1, 0)))
1862
{
1863
if (disc->errorf)
1864
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1865
return 0;
1866
}
1867
flat->array = flat->lastfield->variable.array;
1868
}
1869
return &tags_array[0];
1870
}
1871
1872
static Key_t*
1873
addkey(const char* data, Tagdisc_t* disc)
1874
{
1875
register Flat_t* flat = (Flat_t*)disc;
1876
register Key_t* key;
1877
register Key_t* old;
1878
register Dt_t* dict;
1879
1880
if (!(key = newof(0, Key_t, 1, strlen(data))))
1881
{
1882
if (disc->errorf)
1883
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1884
return 0;
1885
}
1886
strcpy(key->name, data);
1887
key->field = flat->lastfield;
1888
if (streq(key->name, "*"))
1889
flat->lastfield->keyed = 2;
1890
else
1891
{
1892
flat->lastfield->keyed = 1;
1893
dict = ((Field_t*)flat->lastfield->structure.parent)->table->dict;
1894
if (old = (Key_t*)dtmatch(dict, key->name))
1895
{
1896
if (!old->qualification)
1897
error(1, "%s: %s: field key is ambiguous -- qualification required", old->field->variable.name, key->name);
1898
key->next = old;
1899
dtdelete(dict, old);
1900
}
1901
dtinsert(dict, key);
1902
}
1903
return key;
1904
}
1905
1906
static int
1907
flat_field_key_name_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1908
{
1909
register Key_t* key;
1910
1911
if (fp->prev->data)
1912
{
1913
if (disc->errorf)
1914
(*disc->errorf)(NiL, disc, 2, "%s: key name already specified", data);
1915
return -1;
1916
}
1917
if (!(key = addkey(data, disc)))
1918
return -1;
1919
fp->prev->data = key;
1920
return 0;
1921
}
1922
1923
static int
1924
flat_field_key_qualification_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
1925
{
1926
register Key_t* key;
1927
1928
if (!(key = (Key_t*)fp->prev->data))
1929
{
1930
if (disc->errorf)
1931
(*disc->errorf)(NiL, disc, 2, "key must be named");
1932
return -1;
1933
}
1934
if (!(key->qualification = strdup(data)))
1935
{
1936
if (disc->errorf)
1937
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1938
return -1;
1939
}
1940
return 0;
1941
}
1942
1943
static int
1944
identifiers(register Table_t* tab, register const char* s, int flags, Tagdisc_t* disc)
1945
{
1946
register int c;
1947
register int d;
1948
register char* t;
1949
char* e;
1950
regclass_t f;
1951
char m;
1952
1953
while (c = *s++)
1954
{
1955
if (*s == '[')
1956
{
1957
switch (*(s + 1))
1958
{
1959
case ':':
1960
if (f = regclass(s + 1, &e))
1961
{
1962
s = (const char*)e;
1963
for (c = 0; c <= UCHAR_MAX; c++)
1964
if ((*f)(c))
1965
tab->id[c] |= flags;
1966
continue;
1967
}
1968
if (disc->errorf)
1969
(*disc->errorf)(NiL, disc, 2, "[%s: unknown character class", s);
1970
return -1;
1971
case '.':
1972
case '=':
1973
if (regcollate(s, &e, &m, 1, NiL) == 1)
1974
{
1975
s = (const char*)e;
1976
tab->id[m] |= flags;
1977
continue;
1978
}
1979
if (disc->errorf)
1980
(*disc->errorf)(NiL, disc, 2, "[%s: invalid collation element", s);
1981
return -1;
1982
}
1983
}
1984
tab->id[c] |= flags;
1985
if (*s == '-' && (d = *(s + 1)))
1986
{
1987
s += 2;
1988
if (c == 'A' && d == 'Z')
1989
t = "BCDEFGHIJKLMNOPQRSTUVWXYZ";
1990
else if (c == 'a' && d == 'z')
1991
t = "bcdefghijklmnopqrstuvwxyz";
1992
else if (c == '0' && d == '9')
1993
t = "123456789";
1994
else
1995
{
1996
while (++c <= d)
1997
tab->id[c] |= flags;
1998
continue;
1999
}
2000
while (c = *t++)
2001
tab->id[c] |= flags;
2002
}
2003
}
2004
return 0;
2005
}
2006
2007
static Table_t*
2008
table(Tagframe_t* fp, Tagdisc_t* disc)
2009
{
2010
Field_t* p;
2011
2012
if (!(p = fp->data) && !(p = (Field_t*)fp->prev->data))
2013
p = &((Flat_t*)disc)->root;
2014
if (!p->table)
2015
p->table = tabinit((Flat_t*)disc, (Dssdisc_t*)disc);
2016
return p->table;
2017
}
2018
2019
static int
2020
flat_field_key_id1_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2021
{
2022
return identifiers(table(fp, disc), data, 3, disc);
2023
}
2024
2025
static int
2026
flat_field_key_id2_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2027
{
2028
return identifiers(table(fp, disc), data, 2, disc);
2029
}
2030
2031
static int
2032
flat_field_key_span_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2033
{
2034
table(fp, disc)->span = *data ? *data : -1;
2035
return 0;
2036
}
2037
2038
static int
2039
flat_field_key_unknown_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2040
{
2041
table(fp, disc)->unknown = strtol(data, NiL, 0) == 1;
2042
return 0;
2043
}
2044
2045
static Tags_t tags_key[] =
2046
{
2047
"NAME", "Key name.",
2048
0,0,flat_field_key_name_dat,0,
2049
"QUALIFICATION","Key qualification expression; the key is active"
2050
" for the current record when the expression evaluates"
2051
" non-zero. Used to disambiguate conflicting key"
2052
" names. Why design data with conflicts?",
2053
0,0,flat_field_key_qualification_dat,0,
2054
"ID1", "Characters that may appear anywhere in key names,"
2055
" interpreted as the contents of an RE character"
2056
" class. The default is \b[:alpha:]_\b.",
2057
0,0,flat_field_key_id1_dat,0,
2058
"ID2", "Characters that may appear after the first character"
2059
" in key names, interpreted as the contents of an RE"
2060
" character class. The default is"
2061
" \b[:alnum:]_.,-\b.",
2062
0,0,flat_field_key_id2_dat,0,
2063
"SPAN", "The value is the key assignment character. If set"
2064
" then key values may span the field separator"
2065
" character up to the end of record or the next"
2066
" \akey\a\aspan\a\avalue\a. Such data is fraught with"
2067
" ambiguities. One must suppose that it never occurred"
2068
" to the writers that the data would someday be read.",
2069
0,0,flat_field_key_span_dat,0,
2070
"UNKNOWN", "Span unknown but otherwise syntactically correct"
2071
" keys.",
2072
0,0,flat_field_key_unknown_dat,0,
2073
0
2074
};
2075
2076
static Tags_t*
2077
flat_field_key_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2078
{
2079
register Flat_t* flat = (Flat_t*)disc;
2080
2081
if (name && !((Field_t*)flat->lastfield->structure.parent)->table && !(((Field_t*)flat->lastfield->structure.parent)->table = tabinit(flat, (Dssdisc_t*)disc)))
2082
return 0;
2083
return &tags_key[0];
2084
}
2085
2086
static int
2087
flat_field_key_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2088
{
2089
return addkey(data, disc) ? 0 : -1;
2090
}
2091
2092
static Tags_t tags_flat_field[] =
2093
{
2094
"NAME", "Field name.",
2095
0,0,flat_field_name_dat,0,
2096
"DESCRIPTION", "Field description.",
2097
0,0,flat_field_description_dat,0,
2098
"PHYSICAL", "Physical (file representation) details; the"
2099
" remaining tags may appear inside <PHYSICAL>."
2100
" Outside of <PHYSICAL> the tags provide logical"
2101
" (print representation) details. Logical details"
2102
" are used as physical defaults.",
2103
0,flat_field_physical_beg,0,flat_field_physical_end,
2104
"MAP", "Field value map;"
2105
" either a map reference name or a map definition.",
2106
0,dss_map_beg,dss_map_dat,flat_field_map_end,
2107
"TYPE", "Field type. The intrinsic types are number and"
2108
" string. Other types are defined in optional"
2109
" method and schema libraries.",
2110
0,0,flat_field_type_dat,0,
2111
"DETAILS", "An optional type-specific comma-separated string"
2112
" of name=value pairs.",
2113
0,0,flat_field_details_dat,0,
2114
"DELIMITER", "Field delimiter character.",
2115
0,0,flat_field_delimiter_dat,0,
2116
"MULTIPLE", "Multiple adjacent delimiters are equivalent to one.",
2117
0,0,flat_field_multiple_dat,0,
2118
"ESCAPE", "Field delimiter and/or quote escape character.",
2119
0,0,flat_field_escape_dat,0,
2120
"QUOTE", "Field quote begin and end character.",
2121
0,0,flat_field_quotebegin_dat,0,
2122
"QUOTEBEGIN", "Field quote begin character.",
2123
0,0,flat_field_quotebegin_dat,0,
2124
"QUOTEEND", "Field quote end character.",
2125
0,0,flat_field_quoteend_dat,0,
2126
"QUOTEALL", "Field quotes are the first and last characetrs.",
2127
0,0,flat_field_quoteall_dat,0,
2128
"CODESET", "Field codeset name; one of { native ascii ebcdic }.",
2129
0,0,flat_field_codeset_dat,0,
2130
"FIXEDPOINT", "Fixed point width.",
2131
0,0,flat_field_fixedpoint_dat,0,
2132
"WIDTH", "Field fixed width in bytes.",
2133
0,0,flat_field_width_dat,0,
2134
"REMAINDER", "Field is variable length up to the end of record.",
2135
0,0,flat_field_remainder_dat,0,
2136
"BASE", "Numeric field representation base.",
2137
0,0,flat_field_base_dat,0,
2138
"FILL", "Fixed width field fill character.",
2139
0,0,flat_field_fill_dat,0,
2140
"KEY", "name=value keyed field details. Keyed fields are"
2141
" optional and may appear in any order after the"
2142
" positional fields. All unknown keys and invalid"
2143
" key data are passed to the key named \b*\b; if there"
2144
" is no \b*\b key or if \b--verbose\b is on then an"
2145
" error message is emitted for each occurrence. If"
2146
" \b<SPAN>\b and \b<UNKNOWN>\b are enabled then"
2147
" unknown keys are spanned and unknown/invalid"
2148
" key messages are disabled.",
2149
0,flat_field_key_beg,flat_field_key_dat,0,
2150
"CONSTRAINT", "Field value constraints. Constraints, when"
2151
" enabled, are applied to each record as it is read.",
2152
0,dss_con_beg,dss_con_dat,flat_field_con_end,
2153
"ARRAY", "Array info.",
2154
0,flat_array_beg,0,0,
2155
"FIELD", "Field structure.",
2156
0,flat_field_beg,0,flat_field_end,
2157
0
2158
};
2159
2160
static Tags_t*
2161
flat_field_physical_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2162
{
2163
register Flat_t* flat = (Flat_t*)disc;
2164
2165
if (name)
2166
flat->format = &flat->lastfield->physical.format;
2167
return &tags_flat_field[3];
2168
}
2169
2170
static int
2171
flat_field_physical_end(Tag_t* tag, Tagframe_t* fp, Tagdisc_t* disc)
2172
{
2173
register Flat_t* flat = (Flat_t*)disc;
2174
2175
flat->format = &flat->lastfield->variable.format;
2176
return 0;
2177
}
2178
2179
static Tags_t*
2180
flat_field_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2181
{
2182
register Flat_t* flat = (Flat_t*)disc;
2183
Field_t* f;
2184
Field_t* p;
2185
Field_t* t;
2186
2187
if (name)
2188
{
2189
if (!(f = newof(0, Field_t, 1, 0)))
2190
{
2191
if (disc->errorf)
2192
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2193
return 0;
2194
}
2195
f->variable.structure = &f->structure;
2196
if (p = fp->data)
2197
{
2198
f->structure.parent = p->structure.parent;
2199
f->structure.level = p->structure.level;
2200
((Field_t*)fp->tail)->structure.next = &f->variable;
2201
}
2202
else
2203
{
2204
fp->data = f;
2205
if (p = (Field_t*)fp->prev->data)
2206
{
2207
f->structure.parent = &p->variable;
2208
f->structure.level = p->structure.level + 1;
2209
if (t = (Field_t*)fp->prev->head)
2210
t->structure.next = &f->variable;
2211
else
2212
p->structure.members = &f->variable;
2213
fp->prev->head = f;
2214
}
2215
else
2216
{
2217
f->structure.level = 1;
2218
f->structure.parent = &flat->root.variable;
2219
}
2220
}
2221
fp->tail = f;
2222
if (!flat->lastfield)
2223
flat->fields = f;
2224
else
2225
flat->lastfield->next = f;
2226
flat->lastfield = f;
2227
flat->format = &f->variable.format;
2228
f->variable.format.delimiter = f->physical.format.delimiter = flat->delimiter;
2229
f->variable.format.flags = f->physical.format.flags = flat->flags;
2230
f->variable.format.escape = f->physical.format.escape = flat->escape;
2231
f->variable.format.quotebegin = f->physical.format.quotebegin = flat->quotebegin;
2232
f->variable.format.quoteend = f->physical.format.quoteend = flat->quoteend;
2233
f->variable.format.code = f->physical.format.code = CC_NATIVE;
2234
f->variable.index = flat->nfields++;
2235
f->variable.type = (Cxtype_t*)"void";
2236
}
2237
return &tags_flat_field[0];
2238
}
2239
2240
static int
2241
flat_field_end(Tag_t* tag, Tagframe_t* fp, Tagdisc_t* disc)
2242
{
2243
register Flat_t* flat = (Flat_t*)disc;
2244
2245
if (flat->lastfield && !flat->lastfield->variable.name)
2246
{
2247
if (disc->errorf)
2248
(*disc->errorf)(NiL, disc, 2, "field name must be specified");
2249
return -1;
2250
}
2251
return 0;
2252
}
2253
2254
static int
2255
flat_size_type_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2256
{
2257
switch (((Size_t*)fp->prev->data)->type = *data)
2258
{
2259
case 'a':
2260
case 'b':
2261
case 'd':
2262
case 'e':
2263
case 'l':
2264
case 'm':
2265
break;
2266
default:
2267
if (disc->errorf)
2268
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: invalid size field type", data);
2269
return -1;
2270
}
2271
return 0;
2272
}
2273
2274
static int
2275
flat_size_width_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2276
{
2277
char* e;
2278
2279
((Size_t*)fp->prev->data)->width = strtoul(data, &e, 0);
2280
if (*e)
2281
{
2282
if (disc->errorf)
2283
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2284
return -1;
2285
}
2286
return 0;
2287
}
2288
2289
static int
2290
flat_size_fixed_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2291
{
2292
char* e;
2293
2294
((Size_t*)fp->prev->data)->fixed = strtoul(data, &e, 0);
2295
if (*e)
2296
{
2297
if (disc->errorf)
2298
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2299
return -1;
2300
}
2301
return 0;
2302
}
2303
2304
static int
2305
flat_size_offset_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2306
{
2307
char* e;
2308
2309
((Size_t*)fp->prev->data)->offset = strtoul(data, &e, 0);
2310
if (*e)
2311
{
2312
if (disc->errorf)
2313
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2314
return -1;
2315
}
2316
return 0;
2317
}
2318
2319
static int
2320
flat_size_base_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2321
{
2322
char* e;
2323
2324
((Size_t*)fp->prev->data)->base = strtoul(data, &e, 0);
2325
if (*e)
2326
{
2327
if (disc->errorf)
2328
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2329
return -1;
2330
}
2331
return 0;
2332
}
2333
2334
static Tags_t tags_flat_size[] =
2335
{
2336
"TYPE", "Size field physical type. The types are:"
2337
" ascii - ascii text digits,"
2338
" be_t - big endian binary,"
2339
" ebcdic - ebcdic text digits,"
2340
" le_t - little endian binary,"
2341
" magic - binary with same byte order as the"
2342
" header magic number.",
2343
0,0,flat_size_type_dat,0,
2344
"WIDTH", "Size field width in bytes.",
2345
0,0,flat_size_width_dat,0,
2346
"OFFSET", "Size field offset in bytes.",
2347
0,0,flat_size_offset_dat,0,
2348
"BASE", "Size field field representation base.",
2349
0,0,flat_size_base_dat,0,
2350
"SIZE", "Size field total width in bytes, <WIDTH>+<OFFSET>"
2351
" by default. A + prefix specifies that the size"
2352
" field total width must be added to the computed"
2353
" size to determine the record length.",
2354
0,0,flat_size_width_dat,0,
2355
"FIXED", "Fixed record size.",
2356
0,0,flat_size_fixed_dat,0,
2357
0
2358
};
2359
2360
static Tags_t*
2361
flat_size_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2362
{
2363
register Flat_t* flat = (Flat_t*)disc;
2364
Size_t* z;
2365
2366
if (name)
2367
{
2368
if (!(z = newof(0, Size_t, 1, 0)))
2369
{
2370
if (disc->errorf)
2371
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2372
return 0;
2373
}
2374
if (*name == 'B')
2375
flat->block = z;
2376
else
2377
flat->record = z;
2378
fp->data = z;
2379
}
2380
return &tags_flat_size[0];
2381
}
2382
2383
static int
2384
flat_size_end(Tag_t* tag, Tagframe_t* fp, Tagdisc_t* disc)
2385
{
2386
register Flat_t* flat = (Flat_t*)disc;
2387
register Size_t* z = (Size_t*)fp->data;
2388
2389
if (z->size < (z->offset + z->width))
2390
z->size = z->offset + z->width;
2391
z->reserve = z->fixed;
2392
if (z->size)
2393
{
2394
z->fixed = 0;
2395
if (z->reserve < z->size)
2396
z->reserve = z->size;
2397
}
2398
if (z->type == 'e')
2399
{
2400
if (!(z->buf = newof(0, char, z->reserve, 0)))
2401
{
2402
if (disc->errorf)
2403
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2404
return -1;
2405
}
2406
if (!flat->e2a)
2407
flat->e2a = ccmap(CC_EBCDIC_O, CC_ASCII);
2408
}
2409
return 0;
2410
}
2411
2412
static int
2413
flat_section_count_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2414
{
2415
register Flat_t* flat = (Flat_t*)disc;
2416
char* e;
2417
2418
flat->section->count = strtoul(data, &e, 0);
2419
if (*e && (*e != '*' || *(e + 1)))
2420
{
2421
if (disc->errorf)
2422
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2423
return -1;
2424
}
2425
return 0;
2426
}
2427
2428
static int
2429
flat_section_delimiter_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2430
{
2431
register Flat_t* flat = (Flat_t*)disc;
2432
2433
flat->section->delimiter = *data;
2434
return 0;
2435
}
2436
2437
static int
2438
flat_section_pattern_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2439
{
2440
register Flat_t* flat = (Flat_t*)disc;
2441
int code;
2442
2443
if (!(flat->section->re = newof(0, regex_t, 1, 0)))
2444
{
2445
if (disc->errorf)
2446
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2447
return -1;
2448
}
2449
if (code = regcomp(flat->section->re, data, REG_AUGMENTED|REG_LENIENT))
2450
{
2451
if (disc->errorf)
2452
{
2453
char buf[256];
2454
2455
regerror(code, flat->section->re, buf, sizeof(buf));
2456
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "regular expression: %s: %s", data, buf);
2457
}
2458
return -1;
2459
}
2460
return 0;
2461
}
2462
2463
static int
2464
flat_section_size_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2465
{
2466
register Flat_t* flat = (Flat_t*)disc;
2467
char* e;
2468
2469
flat->section->size = strtoul(data, &e, 0);
2470
if (*e)
2471
{
2472
if (disc->errorf)
2473
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2474
return -1;
2475
}
2476
return 0;
2477
}
2478
2479
static Tags_t tags_flat_section[] =
2480
{
2481
"COUNT", "Number of delimiters, patterns or sized blocks.",
2482
0,0,flat_section_count_dat,0,
2483
"DELIMITER", "Delimiter character.",
2484
0,0,flat_section_delimiter_dat,0,
2485
"PATTERN", "Regular expression; ignored if"
2486
" delimiter or size specified.",
2487
0,0,flat_section_pattern_dat,0,
2488
"SIZE", "Fixed size in bytes.",
2489
0,0,flat_section_size_dat,0,
2490
0
2491
};
2492
2493
static Tags_t*
2494
flat_header_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2495
{
2496
register Flat_t* flat = (Flat_t*)disc;
2497
Section_t* s;
2498
2499
if (name)
2500
{
2501
if (!(s = newof(0, Section_t, 1, 0)))
2502
{
2503
if (disc->errorf)
2504
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2505
return 0;
2506
}
2507
s->count = 1;
2508
s->delimiter = -1;
2509
if (!flat->lastheader)
2510
flat->header = flat->lastheader = s;
2511
else
2512
flat->lastheader = flat->lastheader->next = s;
2513
flat->section = s;
2514
}
2515
return &tags_flat_section[0];
2516
}
2517
2518
static Tags_t*
2519
flat_trailer_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2520
{
2521
register Flat_t* flat = (Flat_t*)disc;
2522
Section_t* s;
2523
2524
if (name)
2525
{
2526
if (!(s = newof(0, Section_t, 1, 0)))
2527
{
2528
if (disc->errorf)
2529
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2530
return 0;
2531
}
2532
s->count = 1;
2533
s->delimiter = -1;
2534
if (!flat->lasttrailer)
2535
flat->trailer = flat->lasttrailer = s;
2536
else
2537
flat->lasttrailer = flat->lasttrailer->next = s;
2538
flat->section = s;
2539
}
2540
return &tags_flat_section[0];
2541
}
2542
2543
static int
2544
flat_name_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2545
{
2546
register Flat_t* flat = (Flat_t*)disc;
2547
2548
if (!(flat->meth.name = strdup(data)))
2549
{
2550
if (disc->errorf)
2551
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2552
return -1;
2553
}
2554
return 0;
2555
}
2556
2557
static int
2558
flat_print_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2559
{
2560
register Flat_t* flat = (Flat_t*)disc;
2561
2562
if (!(flat->meth.print = strdup(data)))
2563
{
2564
if (disc->errorf)
2565
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2566
return -1;
2567
}
2568
return 0;
2569
}
2570
2571
static int
2572
flat_description_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2573
{
2574
register Flat_t* flat = (Flat_t*)disc;
2575
2576
if (!(flat->meth.description = (const char*)strdup(data)))
2577
{
2578
if (disc->errorf)
2579
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2580
return -1;
2581
}
2582
return 0;
2583
}
2584
2585
static int
2586
flat_library_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2587
{
2588
register Flat_t* flat = (Flat_t*)disc;
2589
register Library_t* p;
2590
2591
if (!(p = newof(0, Library_t, 1, strlen(data))))
2592
{
2593
if (disc->errorf)
2594
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2595
return -1;
2596
}
2597
strcpy(p->name, data);
2598
if (!flat->lastlibrary)
2599
flat->libraries = flat->lastlibrary = p;
2600
else
2601
flat->lastlibrary = flat->lastlibrary->next = p;
2602
return 0;
2603
}
2604
2605
static int
2606
flat_magic_string_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2607
{
2608
register Flat_t* flat = (Flat_t*)disc;
2609
2610
if (!(flat->magic->string = (const char*)strdup(data)))
2611
{
2612
if (disc->errorf)
2613
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2614
return -1;
2615
}
2616
if (!flat->magic->length)
2617
flat->magic->length = strlen(flat->magic->string);
2618
return 0;
2619
}
2620
2621
static int
2622
flat_magic_number_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2623
{
2624
register Flat_t* flat = (Flat_t*)disc;
2625
char* e;
2626
2627
flat->magic->number = strtoul(data, &e, 0);
2628
if (*e)
2629
{
2630
if (disc->errorf)
2631
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2632
return -1;
2633
}
2634
return 0;
2635
}
2636
2637
static int
2638
flat_magic_size_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2639
{
2640
register Flat_t* flat = (Flat_t*)disc;
2641
char* e;
2642
2643
flat->magic->size = strtoul(data, &e, 0);
2644
if (*e)
2645
{
2646
if (disc->errorf)
2647
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2648
return -1;
2649
}
2650
return 0;
2651
}
2652
2653
static Value_t flat_swap_val[] =
2654
{
2655
"none", SWAP_none,
2656
"native", SWAP_native,
2657
"be", SWAP_be,
2658
"le", SWAP_le,
2659
};
2660
2661
static int
2662
flat_magic_swap_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2663
{
2664
register Flat_t* flat = (Flat_t*)disc;
2665
register Value_t* v;
2666
char* e;
2667
2668
for (v = flat_swap_val; v < &flat_swap_val[elementsof(flat_swap_val)]; v++)
2669
if (!strcasecmp(data, v->name))
2670
{
2671
flat->magic->swap = v->value;
2672
break;
2673
}
2674
if (v >= &flat_swap_val[elementsof(flat_swap_val)])
2675
{
2676
flat->magic->swap = strtoul(data, &e, 0);
2677
if (*e)
2678
{
2679
if (disc->errorf)
2680
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2681
return -1;
2682
}
2683
}
2684
if (flat->magic->swap >= 0)
2685
flat->magic->swap = SWAP(flat->magic->swap);
2686
return 0;
2687
}
2688
2689
static int
2690
flat_magic_version_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2691
{
2692
register Flat_t* flat = (Flat_t*)disc;
2693
char* e;
2694
2695
flat->magic->version = strtoul(data, &e, 0);
2696
if (*e)
2697
{
2698
if (disc->errorf)
2699
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2700
return -1;
2701
}
2702
return 0;
2703
}
2704
2705
static Tags_t tags_flat_magic[] =
2706
{
2707
"STRING", "Magic string value.",
2708
0,0,flat_magic_string_dat,0,
2709
"NUMBER", "Magic number value.",
2710
0,0,flat_magic_number_dat,0,
2711
"LENGTH", "Magic number/string size in bytes.",
2712
0,0,flat_magic_size_dat,0,
2713
"SIZE", "Magic header size in bytes. If omitted then an AST"
2714
"magic header is assumed.",
2715
0,0,flat_magic_size_dat,0,
2716
"SWAP", "Magic header binary field swap operation:"
2717
" native - native byte order (default),"
2718
" be - big endian swap,"
2719
" le - little endian swap,"
2720
" 1|2|4 - swap OR of 1:bytes 2:shorts 4:ints.",
2721
0,0,flat_magic_swap_dat,0,
2722
"VERSION", "Magic version stamp, either YYYYMMDD or 0xWWXXYYZZ.",
2723
0,0,flat_magic_version_dat,0,
2724
0
2725
};
2726
2727
static Tags_t*
2728
flat_magic_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2729
{
2730
register Flat_t* flat = (Flat_t*)disc;
2731
2732
if (!(flat->magic = newof(0, Magic_t, 1, 0)))
2733
{
2734
if (disc->errorf)
2735
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2736
return 0;
2737
}
2738
flat->magic->swap = SWAP_native;
2739
return &tags_flat_magic[0];
2740
}
2741
2742
static int
2743
flat_magic_end(Tag_t* tag, Tagframe_t* fp, Tagdisc_t* disc)
2744
{
2745
register Flat_t* flat = (Flat_t*)disc;
2746
2747
if (flat->magic)
2748
{
2749
if (!flat->magic->length)
2750
flat->magic->length = 4;
2751
if (!flat->magic->size)
2752
flat->magic->size = flat->magic->length;
2753
if (flat->magic->size < flat->magic->length)
2754
{
2755
if (disc->errorf)
2756
(*disc->errorf)(NiL, disc, 2, "magic header size %u is smaller than string/number length %u", flat->magic->size, flat->magic->length);
2757
return -1;
2758
}
2759
if (!flat->magic->string && (flat->magic->length > 4 || (flat->magic->length & (flat->magic->length - 1))))
2760
{
2761
if (disc->errorf)
2762
(*disc->errorf)(NiL, disc, 2, "magic number length %u must be a power of 2 less than or equal to 4", flat->magic->length);
2763
return -1;
2764
}
2765
}
2766
return 0;
2767
}
2768
2769
static int
2770
flat_physical_swap_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2771
{
2772
register Flat_t* flat = (Flat_t*)disc;
2773
register Value_t* v;
2774
char* e;
2775
2776
for (v = flat_swap_val; v < &flat_swap_val[elementsof(flat_swap_val)]; v++)
2777
if (!strcasecmp(data, v->name))
2778
{
2779
flat->swap = v->value;
2780
break;
2781
}
2782
if (v >= &flat_swap_val[elementsof(flat_swap_val)])
2783
{
2784
flat->swap = strtoul(data, &e, 0);
2785
if (*e)
2786
{
2787
if (disc->errorf)
2788
(*disc->errorf)(NiL, disc, 2, "%s: invalid number", data);
2789
return -1;
2790
}
2791
}
2792
if (flat->swap >= 0)
2793
flat->swap = SWAP(flat->swap);
2794
return 0;
2795
}
2796
2797
static int
2798
flat_compress_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2799
{
2800
register Flat_t* flat = (Flat_t*)disc;
2801
2802
if (!(flat->meth.compress = strdup(data)))
2803
{
2804
if (disc->errorf)
2805
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2806
return -1;
2807
}
2808
return 0;
2809
}
2810
2811
static int
2812
flat_physical_continue_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2813
{
2814
register Flat_t* flat = (Flat_t*)disc;
2815
2816
flat->continuator = *data;
2817
return 0;
2818
}
2819
2820
static int
2821
flat_physical_delimiter_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2822
{
2823
register Flat_t* flat = (Flat_t*)disc;
2824
2825
flat->delimiter = *data;
2826
return 0;
2827
}
2828
2829
static int
2830
flat_physical_escape_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2831
{
2832
register Flat_t* flat = (Flat_t*)disc;
2833
2834
flat->escape = *data;
2835
return 0;
2836
}
2837
2838
static int
2839
flat_physical_quotebegin_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2840
{
2841
register Flat_t* flat = (Flat_t*)disc;
2842
2843
flat->quotebegin = *data;
2844
return 0;
2845
}
2846
2847
static int
2848
flat_physical_quoteend_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2849
{
2850
register Flat_t* flat = (Flat_t*)disc;
2851
2852
flat->quoteend = *data;
2853
return 0;
2854
}
2855
2856
static int
2857
flat_physical_quoteall_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2858
{
2859
register Flat_t* flat = (Flat_t*)disc;
2860
2861
if (strtol(data, NiL, 0) > 0)
2862
flat->flags |= CX_QUOTEALL;
2863
else
2864
flat->flags &= ~CX_QUOTEALL;
2865
return 0;
2866
}
2867
2868
static int
2869
flat_physical_multiple_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2870
{
2871
register Flat_t* flat = (Flat_t*)disc;
2872
2873
if (strtol(data, NiL, 0) > 0)
2874
flat->flags |= CX_MULTIPLE;
2875
else
2876
flat->flags &= ~CX_MULTIPLE;
2877
return 0;
2878
}
2879
2880
static int
2881
flat_physical_codeset_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2882
{
2883
register Flat_t* flat = (Flat_t*)disc;
2884
2885
if ((flat->code = ccmapid(data)) < 0)
2886
{
2887
if (disc->errorf)
2888
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: unknown character code set", data);
2889
return -1;
2890
}
2891
return 0;
2892
}
2893
2894
static int
2895
flat_physical_terminator_dat(Tag_t* tag, Tagframe_t* fp, const char* data, Tagdisc_t* disc)
2896
{
2897
register Flat_t* flat = (Flat_t*)disc;
2898
2899
flat->terminator = *data;
2900
if (flat->code != CC_NATIVE && (fp->attr & TAG_ATTR_conv))
2901
flat->terminator = ccmapc(flat->terminator, CC_NATIVE, flat->code);
2902
return 0;
2903
}
2904
2905
static Tags_t tags_flat_physical_key[] =
2906
{
2907
"ID1", "Characters that may appear anywhere in key names,"
2908
" interpreted as the contents of an RE character"
2909
" class. The default is \b[:alpha:]_\b.",
2910
0,0,flat_field_key_id1_dat,0,
2911
"ID2", "Characters that may appear after the first character"
2912
" in key names, interpreted as the contents of an RE"
2913
" character class. The default is"
2914
" \b[:alnum:]_.,-\b.",
2915
0,0,flat_field_key_id2_dat,0,
2916
"SPAN", "The value is the key assignment character. If set"
2917
" then key values may span the field separator"
2918
" character up to the end of record or the next"
2919
" \akey\a\aspan\a\avalue\a. Such data is frought with"
2920
" ambiguities. One must suppose that it never occurred"
2921
" to the writers that the data would someday be read.",
2922
0,0,flat_field_key_span_dat,0,
2923
"UNKNOWN", "Span unknown but otherwise syntactically correct"
2924
" keys.",
2925
0,0,flat_field_key_unknown_dat,0,
2926
0
2927
};
2928
2929
static Tags_t*
2930
flat_physical_key_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2931
{
2932
return &tags_flat_physical_key[0];
2933
}
2934
2935
static Tags_t tags_flat_physical[] =
2936
{
2937
"SWAP", "Binary record field swap operation:"
2938
" none - don't swap (default),"
2939
" native - swap to match the magic header NUMBER,"
2940
" be - big endian swap,"
2941
" le - little endian swap,"
2942
" 1|2|4 - swap OR of 1:bytes 2:shorts 4:ints.",
2943
0,0,flat_physical_swap_dat,0,
2944
"DELIMITER", "Default field delimiter and continuation replacement"
2945
" character.",
2946
0,0,flat_physical_delimiter_dat,0,
2947
"ESCAPE", "Default field delimiter and/or quote escape character.",
2948
0,0,flat_physical_escape_dat,0,
2949
"QUOTE", "Default field quote begin and end character.",
2950
0,0,flat_physical_quotebegin_dat,0,
2951
"QUOTEBEGIN", "Default field quote begin character.",
2952
0,0,flat_physical_quotebegin_dat,0,
2953
"QUOTEEND", "Default field quote end character.",
2954
0,0,flat_physical_quoteend_dat,0,
2955
"QUOTEALL", "Field quotes are the first and last characetrs.",
2956
0,0,flat_physical_quoteall_dat,0,
2957
"MULTIPLE", "Multiple adjacent delimiters are equivalent to one.",
2958
0,0,flat_physical_multiple_dat,0,
2959
"CODESET", "Default records codeset name; one of { native ascii ebcdic }.",
2960
0,0,flat_physical_codeset_dat,0,
2961
"CONTINUE", "Terminator continuation (escape) character.",
2962
0,0,flat_physical_continue_dat,0,
2963
"TERMINATOR", "Default record termination character.",
2964
0,0,flat_physical_terminator_dat,0,
2965
"KEY", "Default field key attributes.",
2966
0,flat_physical_key_beg,0,0,
2967
};
2968
2969
static Tags_t*
2970
flat_physical_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
2971
{
2972
return &tags_flat_physical[0];
2973
}
2974
2975
static Tags_t tags_flat[] =
2976
{
2977
"NAME", "Schema name.",
2978
0,0,flat_name_dat,0,
2979
"DESCRIPTION", "Schema description.",
2980
0,0,flat_description_dat,0,
2981
"IDENT", "Schema ident string.",
2982
0,0,0,0,
2983
"LIBRARY", "Required type/map library name;"
2984
" more than one library may be specified.",
2985
0,0,flat_library_dat,0,
2986
"MAGIC", "File magic number (identification header)"
2987
" section definitions.",
2988
0,flat_magic_beg,0,flat_magic_end,
2989
"PRINT", "Default {print} query format.",
2990
0,0,flat_print_dat,0,
2991
"COMPRESS", "Preferred compression method; compression is applied"
2992
" by the {compress} query.",
2993
0,0,flat_compress_dat,0,
2994
"HEADER", "File header section definitions.",
2995
0,flat_header_beg,0,0,
2996
"TRAILER", "File trailer section definitions.",
2997
0,flat_trailer_beg,0,0,
2998
"BLOCK", "Block size definitions.",
2999
0,flat_size_beg,0,flat_size_end,
3000
"RECORD", "Record size definitions; same as <BLOCK>.",
3001
0,flat_size_beg,0,flat_size_end,
3002
"PHYSICAL", "Default physical record and field attributes.",
3003
0,flat_physical_beg,0,0,
3004
"FIELD", "Schema field list.",
3005
0,flat_field_beg,0,flat_field_end,
3006
0
3007
};
3008
3009
static Tags_t*
3010
flat_beg(Tag_t* tag, Tagframe_t* fp, const char* name, Tagdisc_t* disc)
3011
{
3012
return &tags_flat[0];
3013
}
3014
3015
static Tags_t tags[] =
3016
{
3017
"FLAT", "Flat method schema.",
3018
0,flat_beg,0,0,
3019
"MAP", "Field value map;"
3020
" either a map reference name or a map definition.",
3021
0,dss_map_beg,dss_map_dat,dss_map_end,
3022
"METHOD", "Method name; must be flat.",
3023
0,0,0,0,
3024
0
3025
};
3026
3027
/*
3028
* outal rententive support
3029
*/
3030
3031
static int
3032
tabs(Sfio_t* op, int cur, int nxt)
3033
{
3034
cur = (nxt - cur - 1) / 8 + 1;
3035
while (cur-- > 0)
3036
sfputc(op, '\t');
3037
return nxt;
3038
}
3039
3040
/*
3041
* fill in type and format defaults
3042
*/
3043
3044
static void
3045
defaults(register Cxtype_t* type, register Cxformat_t* format, int binary, Dssdisc_t* disc)
3046
{
3047
register char* s;
3048
Cxstate_t* state = cxstate(disc);
3049
Cxtype_t* base;
3050
char details[16];
3051
3052
if (!(format->flags & (CX_INTEGER|CX_FLOAT|CX_STRING|CX_BUFFER)))
3053
format->flags |= type->format.flags & (CX_BINARY|CX_UNSIGNED|CX_INTEGER|CX_FLOAT|CX_STRING|CX_BUFFER);
3054
else if ((type->format.flags & CX_BINARY) && (format->flags & (CX_INTEGER|CX_FLOAT)))
3055
format->flags |= CX_BINARY;
3056
if (!type->internalf || !type->externalf)
3057
{
3058
if (cxisvoid(type))
3059
base = state->type_void;
3060
else if (cxisstring(type))
3061
base = state->type_string;
3062
else if (cxisbuffer(type))
3063
base = state->type_buffer;
3064
else
3065
{
3066
base = state->type_number;
3067
if (!(format->flags & CX_FLOAT))
3068
{
3069
s = details;
3070
*s++ = '%';
3071
if (format->fill > 0)
3072
*s++ = format->fill;
3073
if (format->width)
3074
s += sfsprintf(s, &details[sizeof(details)] - s, "%d", format->width);
3075
*s++ = 'l';
3076
*s++ = 'l';
3077
switch (format->base)
3078
{
3079
default:
3080
if (format->base < 64)
3081
{
3082
*s++ = '.';
3083
*s++ = '.';
3084
s += sfsprintf(s, &details[sizeof(details)] - s, "%d", format->base);
3085
break;
3086
}
3087
/*FALLTHROUGH*/
3088
case 0:
3089
case 10:
3090
*s++ = (format->flags & CX_UNSIGNED) ? 'u' : 'd';
3091
break;
3092
case 8:
3093
*s++ = 'o';
3094
break;
3095
case 16:
3096
*s++ = 'x';
3097
break;
3098
}
3099
*s = 0;
3100
format->details = strdup(details);
3101
}
3102
}
3103
if (!type->internalf)
3104
type->internalf = base->internalf;
3105
if (!type->externalf)
3106
type->externalf = base->externalf;
3107
}
3108
}
3109
3110
/*
3111
* methf
3112
*/
3113
3114
extern Dsslib_t dss_lib_flat;
3115
3116
static Dssmeth_t*
3117
flatmeth(const char* name, const char* options, const char* schema, Dssdisc_t* disc, Dssmeth_t* meth)
3118
{
3119
register Flat_t* flat;
3120
register Library_t* p;
3121
register Field_t* f;
3122
Field_t* g;
3123
Tag_t* tag;
3124
Sfio_t* sp;
3125
char* s;
3126
ssize_t n;
3127
int i;
3128
int errors;
3129
int fixed;
3130
char path[PATH_MAX];
3131
3132
if (!(flat = newof(0, Flat_t, 1, 0)))
3133
{
3134
if (disc->errorf)
3135
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
3136
return 0;
3137
}
3138
flat->basemeth = meth;
3139
flat->meth = *meth;
3140
flat->meth.data = flat;
3141
taginit(&flat->dsstagdisc.tagdisc, disc->errorf);
3142
flat->dsstagdisc.tagdisc.id = DSS_ID;
3143
flat->dsstagdisc.disc = disc;
3144
flat->dsstagdisc.meth = meth;
3145
flat->binary = 1;
3146
flat->code = CC_NATIVE;
3147
flat->swap = SWAP_none;
3148
flat->delimiter = flat->escape = flat->quotebegin = flat->quoteend = flat->terminator = flat->continuator = -1;
3149
sp = 0;
3150
if (options)
3151
{
3152
if (!(sp = sfstropen()))
3153
goto drop;
3154
sfprintf(sp, "%s", usage);
3155
if (tagusage(tags, sp, &flat->dsstagdisc.tagdisc))
3156
goto drop;
3157
sfprintf(sp, "}\n");
3158
if (dssoptlib(meth->cx->buf, &dss_lib_flat, sfstruse(sp), disc))
3159
goto drop;
3160
sfclose(sp);
3161
sp = 0;
3162
s = sfstruse(meth->cx->buf);
3163
for (;;)
3164
{
3165
switch (optstr(options, s))
3166
{
3167
case 'b':
3168
flat->binary = opt_info.num;
3169
continue;
3170
case 'e':
3171
flat->emptyspace = 1;
3172
continue;
3173
case 'h':
3174
case 'o':
3175
case 's':
3176
flat->list = opt_info.option[1];
3177
continue;
3178
case 'p':
3179
flat->prototype = 1;
3180
continue;
3181
case 'T':
3182
flat->test = opt_info.num;
3183
continue;
3184
case '?':
3185
if (disc->errorf)
3186
(*disc->errorf)(NiL, disc, ERROR_USAGE|4, "%s", opt_info.arg);
3187
goto drop;
3188
case ':':
3189
if (disc->errorf)
3190
(*disc->errorf)(NiL, disc, 2, "%s", opt_info.arg);
3191
goto drop;
3192
}
3193
break;
3194
}
3195
}
3196
if (schema && *schema)
3197
{
3198
if (!(sp = dssfind(schema, NiL, DSS_VERBOSE, path, sizeof(path), disc)))
3199
return 0;
3200
if (!(tag = tagopen(sp, path, 1, &tags[0], &flat->dsstagdisc.tagdisc)) || tagclose(tag))
3201
goto drop;
3202
sfclose(sp);
3203
sp = 0;
3204
if (!flat->fields)
3205
goto invalid;
3206
}
3207
dtinsert(flat->meth.formats, &flat_format);
3208
for (p = flat->libraries; p; p = p->next)
3209
if (!dssload(p->name, disc))
3210
return 0;
3211
for (i = 0; i < elementsof(local_callouts); i++)
3212
if (cxaddcallout(flat->meth.cx, &local_callouts[i], disc))
3213
return 0;
3214
for (f = flat->fields; f; f = f->next)
3215
{
3216
if (cxaddvariable(flat->meth.cx, &f->variable, disc))
3217
return 0;
3218
if ((s = (char*)f->width) && !(f->width = keycomp(flat, s, disc)))
3219
{
3220
if (disc->errorf)
3221
(*disc->errorf)(NiL, disc, 2, "%s: %s: invalid field width index", f->variable.name, s);
3222
return 0;
3223
}
3224
if (f->variable.array && (s = (char*)f->variable.array->variable) && !(f->variable.array->variable = (Cxvariable_t*)dtmatch(flat->meth.cx->variables, s)))
3225
{
3226
if (disc->errorf)
3227
(*disc->errorf)(NiL, disc, 2, "%s: %s: unknown array index", f->variable.name, s);
3228
return 0;
3229
}
3230
defaults(f->variable.type, &f->variable.format, 0, disc);
3231
if (!(s = (char*)f->physical.type))
3232
f->physical.type = f->variable.type;
3233
else if (!(f->physical.type = cxtype(flat->meth.cx, s, disc)))
3234
{
3235
if (disc->errorf)
3236
(*disc->errorf)(NiL, disc, 2, "%s: %s: unknown type", f->variable.name, s);
3237
return 0;
3238
}
3239
defaults(f->physical.type, &f->physical.format, flat->binary, disc);
3240
if (!f->physical.format.delimiter)
3241
f->physical.format.delimiter = f->variable.format.delimiter;
3242
if (!(f->physical.format.flags & (CX_INTEGER|CX_FLOAT|CX_STRING|CX_BUFFER)))
3243
f->physical.format.flags |= f->variable.format.flags & (CX_BINARY|CX_UNSIGNED|CX_INTEGER|CX_FLOAT|CX_STRING|CX_BUFFER|CX_NUL);
3244
if (f->physical.format.flags & CX_BINARY)
3245
{
3246
if (!f->variable.format.width && f->physical.type)
3247
f->variable.format.width = f->physical.type->format.width;
3248
}
3249
else if (!f->physical.format.map)
3250
f->physical.format.map = f->variable.format.map;
3251
if (f->physical.format.flags & CX_BUFFER)
3252
f->variable.format.flags |= CX_BUFFER;
3253
}
3254
if (flat->lastfield && flat->terminator < 0)
3255
flat->terminator = flat->lastfield->physical.format.delimiter;
3256
if (flat->terminator < 0)
3257
flat->continuator = -1;
3258
else if (flat->continuator >= 0 && !(flat->buf = sfstropen()))
3259
{
3260
if (disc->errorf)
3261
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
3262
return 0;
3263
}
3264
errors = 0;
3265
fixed = 1;
3266
for (f = flat->fields; f; f = f->next)
3267
{
3268
if (!(f->physical.format.flags & (CX_BINARY|CX_STRING|CX_BUFFER)))
3269
flat->binary = 0;
3270
if (f->physical.format.delimiter < 0 && !f->physical.format.width && !f->width && !f->keyed)
3271
{
3272
if (f->structure.members)
3273
{
3274
f->structref = 1;
3275
continue;
3276
}
3277
errors++;
3278
if (disc->errorf)
3279
(*disc->errorf)(NiL, disc, 2, "%s: a field delimiter or size must be specified", f->variable.name);
3280
}
3281
else if (f->structure.members)
3282
{
3283
#if 0
3284
if (f->physical.format.width || f->width)
3285
/*OK*/;
3286
else if (disc->errorf)
3287
(*disc->errorf)(NiL, disc, 1, "%s: structure attributes ignored", f->variable.name);
3288
#endif
3289
continue;
3290
}
3291
if (!f->variable.type)
3292
{
3293
f->variable.type = (Cxtype_t*)"string";
3294
f->variable.format.flags |= CX_STRING;
3295
}
3296
if (f->physical.format.delimiter == flat->terminator && f != flat->lastfield)
3297
flat->terminator = -1;
3298
if (f->physical.format.width)
3299
{
3300
flat->fixed += f->physical.format.width;
3301
if (f->width)
3302
flat->variable = SF_LOCKR;
3303
}
3304
else
3305
fixed = 0;
3306
if (f->physical.format.quotebegin >= 0 && f->physical.format.quoteend < 0)
3307
f->physical.format.quoteend = f->physical.format.quotebegin;
3308
if (f->physical.format.quotebegin < 0)
3309
f->physical.format.flags &= ~CX_QUOTEALL;
3310
f->map = ccmap(f->physical.format.code, CC_NATIVE);
3311
}
3312
if (errors)
3313
return 0;
3314
if (flat->block)
3315
{
3316
if (disc->errorf)
3317
(*disc->errorf)(NiL, disc, 2, "blocked data not supported yet");
3318
return 0;
3319
}
3320
if (flat->record)
3321
{
3322
if (flat->record->fixed && flat->fixed > flat->record->reserve)
3323
{
3324
flat->truncate.fixed = 1;
3325
n = flat->record->reserve;
3326
for (f = flat->fields; f; f = f->next)
3327
{
3328
if (f->width && f->physical.format.width)
3329
{
3330
g = f;
3331
while (g = g->next)
3332
n -= g->physical.format.width;
3333
if (n > 0)
3334
{
3335
if (disc->errorf)
3336
(*disc->errorf)(NiL, disc, 1, "%s: maximum variable field size shortened from %d to %d to comply with fixed record size %d", f->variable.name, f->physical.format.width, n, flat->record->reserve);
3337
f->physical.format.width = n;
3338
flat->truncate.fixed = 0;
3339
}
3340
break;
3341
}
3342
n -= f->physical.format.width;
3343
}
3344
}
3345
flat->fixed = flat->record->reserve;
3346
}
3347
else if (!fixed)
3348
{
3349
flat->fixed = 0;
3350
flat->binary = 0;
3351
}
3352
return &flat->meth;
3353
invalid:
3354
if (disc->errorf)
3355
(*disc->errorf)(NiL, disc, 2, "%s: invalid schema", options);
3356
drop:
3357
free(flat);
3358
if (sp)
3359
sfclose(sp);
3360
return 0;
3361
}
3362
3363
/*
3364
* openf
3365
*/
3366
3367
static int
3368
flatopen(Dss_t* dss, Dssdisc_t* disc)
3369
{
3370
Flat_t* flat = (Flat_t*)dss->meth->data;
3371
register Field_t* f;
3372
register Cxvariable_t* v;
3373
char* a;
3374
char* s;
3375
char* p;
3376
char* t;
3377
char* u;
3378
int offset;
3379
int fixed;
3380
int pad;
3381
int m;
3382
int n;
3383
char tmp[2];
3384
3385
if (flat)
3386
{
3387
if (flat->prototype)
3388
{
3389
for (f = flat->fields; f; f = f->next)
3390
{
3391
if ((n = f->variable.format.delimiter) < 0 && (n = f->physical.format.delimiter) < 0)
3392
n = f->next ? '|' : '\n';
3393
sfprintf(sfstdout, "%s%c", cxisvoid(f->variable.type) ? "" : f->variable.name, n);
3394
}
3395
}
3396
switch (flat->list)
3397
{
3398
case 'h':
3399
if (!(a = newof(0, char, 3 * (strlen(flat->meth.name) + 1), 0)))
3400
{
3401
if (disc->errorf)
3402
(*disc->errorf)(dss, disc, ERROR_SYSTEM|2, "out of space");
3403
return -1;
3404
}
3405
p = a;
3406
for (s = (char*)flat->meth.name; *s; s++)
3407
*a++ = isalnum(*s) ? *s : '_';
3408
*a++ = 0;
3409
if (!isalpha(*p))
3410
*p = '_';
3411
t = a;
3412
a = strcopy(a, flat->meth.name);
3413
*a++ = 0;
3414
if (islower(*t))
3415
*t = toupper(*t);
3416
u = a;
3417
for (s = p; *s; s++)
3418
*a++ = islower(*s) ? toupper(*s) : *s;
3419
*a = 0;
3420
sfprintf(sfstdout, "/*\n");
3421
sfprintf(sfstdout, " * %s dynamic interface\n", flat->meth.name);
3422
if (flat->meth.description)
3423
sfprintf(sfstdout, " * %s\n", flat->meth.description);
3424
sfprintf(sfstdout, " */\n\n");
3425
sfprintf(sfstdout, "#define %s_RECORD(data) (_%s_record_=(%s_record_t*)DSSDATA(data))\n", u, p, t);
3426
sfprintf(sfstdout, "\n");
3427
sfprintf(sfstdout, "typedef Cxvalue_t* (*%s_get_f)(void*,int);\n", t);
3428
sfprintf(sfstdout, "\n");
3429
sfprintf(sfstdout, "typedef struct %s_field_s /* record field */\n", t);
3430
sfprintf(sfstdout, "{\n");
3431
sfprintf(sfstdout, " Cxvalue_t value; /* value (first for dynamic Q) */\n");
3432
sfprintf(sfstdout, " void* field; /* static field info */\n");
3433
sfprintf(sfstdout, " size_t off; /* record data offset */\n");
3434
sfprintf(sfstdout, " size_t siz; /* record data size */\n");
3435
sfprintf(sfstdout, " unsigned int serial; /* read serial number */\n");
3436
sfprintf(sfstdout, " unsigned int keyed; /* keyed serial number */\n");
3437
sfprintf(sfstdout, "} %s_field_t;\n", t);
3438
sfprintf(sfstdout, "\n");
3439
sfprintf(sfstdout, "typedef struct %s_record_s /* current record info */\n", t);
3440
sfprintf(sfstdout, "{\n");
3441
sfprintf(sfstdout, " %s_field_t* fields; /* fields (first for dynamic Q) */\n", t);
3442
sfprintf(sfstdout, " %s_get_f getf; /* getf (second for dynamic Q) */\n", t);
3443
sfprintf(sfstdout, "} %s_record_t;\n", t);
3444
sfprintf(sfstdout, "\n");
3445
sfprintf(sfstdout, "static %s_record_t* _%s_record_;\n", t, p);
3446
sfprintf(sfstdout, "\n");
3447
for (f = flat->fields; f; f = f->next)
3448
{
3449
if (f->structure.members)
3450
continue;
3451
n = sfprintf(sfstdout, "#define %s_%s", p, f->variable.name);
3452
n = tabs(sfstdout, n, 32);
3453
n += sfprintf(sfstdout, "((*_%s_record_->getf)(_%s_record_,%d)->", p, p, f->variable.index);
3454
if (f->variable.format.flags & (CX_BUFFER|CX_STRING))
3455
{
3456
a = (f->variable.format.flags & CX_STRING) ? "string" : "buffer";
3457
n += sfprintf(sfstdout, "%s.data)", a);
3458
}
3459
else
3460
n += sfprintf(sfstdout, "number)");
3461
offset += m * f->physical.format.width;
3462
if (f->variable.description)
3463
{
3464
tabs(sfstdout, n, 64);
3465
sfprintf(sfstdout, "/* %s */\n", f->variable.description);
3466
}
3467
else
3468
sfputc(sfstdout, '\n');
3469
if (f->variable.format.flags & (CX_BUFFER|CX_STRING))
3470
{
3471
n = sfprintf(sfstdout, "#define %s_%s_size", p, f->variable.name);
3472
tabs(sfstdout, n, 32);
3473
sfprintf(sfstdout, "((*_%s_record_->getf)(_%s_record_,%d)->%s.size)\n", p, p, f->variable.index, a);
3474
}
3475
}
3476
break;
3477
case 'o':
3478
if (!flat->fixed)
3479
{
3480
if (disc->errorf)
3481
(*disc->errorf)(NiL, disc, 2, "variable width record offsets not supported");
3482
return -1;
3483
}
3484
/* HERE: under construction */
3485
offset = 0;
3486
pad = 0;
3487
for (f = flat->fields; f; f = f->next)
3488
{
3489
if (f->structure.members)
3490
{
3491
f->structure.size = offset;
3492
continue;
3493
}
3494
a = p = s = "";
3495
m = 1;
3496
n = 0;
3497
if (f->variable.array)
3498
{
3499
if (f->variable.array->size)
3500
{
3501
m = f->variable.array->size;
3502
a = sfprints("[%d]", f->variable.array->size);
3503
}
3504
else
3505
p = "*";
3506
}
3507
if (!f->structure.level)
3508
f->variable.structure = 0;
3509
if (f->variable.format.flags & CX_BUFFER)
3510
{
3511
n += sfprintf(sfstdout, "struct _%s_%s_buf_s", flat->basemeth->name, flat->meth.name);
3512
n = tabs(sfstdout, n, 24);
3513
n += sfprintf(sfstdout, "%s%s%s;", p, f->variable.name, a);
3514
}
3515
else if ((f->variable.format.flags & CX_STRING) || !(f->physical.format.flags & CX_BINARY))
3516
{
3517
n += sfprintf(sfstdout, "char");
3518
n = tabs(sfstdout, n, 24);
3519
n += sfprintf(sfstdout, "%s%s%s", p, f->variable.name, a);
3520
if (f->physical.format.width > 1)
3521
n += sfprintf(sfstdout, "[%u];", f->physical.format.width);
3522
else
3523
n += sfprintf(sfstdout, ";");
3524
}
3525
else
3526
{
3527
if (f->variable.format.flags & CX_FLOAT)
3528
n += sfprintf(sfstdout, "_ast_flt");
3529
else
3530
{
3531
if ((f->variable.format.flags & CX_UNSIGNED) || !streq((char*)f->variable.type, "number"))
3532
n += sfprintf(sfstdout, "unsigned ");
3533
n += sfprintf(sfstdout, "_ast_int");
3534
}
3535
n += sfprintf(sfstdout, "%u_t", f->physical.format.width);
3536
n = tabs(sfstdout, n, 24);
3537
n += sfprintf(sfstdout, "%s%s%s;", p, f->variable.name, a);
3538
if ((offset % f->physical.format.width) && !cxisvoid(f->variable.type))
3539
{
3540
s = "(MISALIGNED) ";
3541
if (disc->errorf)
3542
(*disc->errorf)(NiL, disc, 1, "%s: field size %u offset %u is not aligned", f->variable.name, f->physical.format.width, offset);
3543
}
3544
}
3545
offset += m * f->physical.format.width;
3546
sfputc(sfstdout, '\n');
3547
if (f->physical.format.delimiter >= 0)
3548
{
3549
n = sfprintf(sfstdout, "char");
3550
n = tabs(sfstdout, n, 24);
3551
n += sfprintf(sfstdout, "_delimiter_%d;", ++pad);
3552
tabs(sfstdout, n, 40);
3553
offset += 1;
3554
tmp[0] = f->physical.format.delimiter;
3555
tmp[1] = 0;
3556
sfprintf(sfstdout, "/* delimiter '%s' */\n", fmtesc(tmp));
3557
}
3558
if (!f->structure.next)
3559
{
3560
v = &f->variable;
3561
if (v->structure)
3562
while (!v->structure->next && (v = v->structure->parent) && v->structure)
3563
{
3564
v->structure->size = offset - v->structure->size;
3565
if (v->array)
3566
{
3567
if (v->array->size)
3568
{
3569
offset += (v->array->size - 1) * v->structure->size;
3570
sfprintf(sfstdout, "} %s[%d]", v->name, v->array->size);
3571
}
3572
else
3573
sfprintf(sfstdout, "} *%s", v->name);
3574
if (v->array->variable)
3575
sfprintf(sfstdout, " /*%s*/", v->array->variable->name);
3576
sfprintf(sfstdout, ";\n");
3577
}
3578
else
3579
sfprintf(sfstdout, "} %s;\n", v->name);
3580
}
3581
}
3582
}
3583
if (flat->binary && (fixed = offset % 8))
3584
{
3585
fixed = 8 - fixed;
3586
if (disc->errorf)
3587
(*disc->errorf)(NiL, disc, 1, "%s: record has %u unused pad byte%s", flat->meth.name, fixed, fixed == 1 ? "" : "s");
3588
}
3589
sfprintf(sfstdout, "%s\t%lu\t%u\t%u\tstruct\n", ".", offset, 0, 0);
3590
break;
3591
case 's':
3592
if (!flat->fixed)
3593
{
3594
if (disc->errorf)
3595
(*disc->errorf)(NiL, disc, 2, "variable width record structs not supported");
3596
return -1;
3597
}
3598
for (f = flat->fields; f; f = f->next)
3599
if (f->variable.format.flags & CX_BUFFER)
3600
{
3601
sfprintf(sfstdout, "/* buffer field info */\n");
3602
sfprintf(sfstdout, "struct _%s_%s_buf_s\n", flat->basemeth->name, flat->meth.name);
3603
sfprintf(sfstdout, "{\n");
3604
n = sfprintf(sfstdout, "unsigned _ast_int2_t");
3605
n = tabs(sfstdout, n, 24);
3606
n += sfprintf(sfstdout, "offset;");
3607
tabs(sfstdout, n, 40);
3608
sfprintf(sfstdout, "/* buffer data _HEAP_ offset */\n");
3609
n = sfprintf(sfstdout, "unsigned _ast_int2_t");
3610
n = tabs(sfstdout, n, 24);
3611
n += sfprintf(sfstdout, "size;");
3612
tabs(sfstdout, n, 40);
3613
sfprintf(sfstdout, "/* buffer data size */\n");
3614
sfprintf(sfstdout, "};\n");
3615
break;
3616
}
3617
if (flat->meth.description)
3618
sfprintf(sfstdout, "/* %s */\n", flat->meth.description);
3619
sfprintf(sfstdout, "struct _%s_%s_s\n", flat->basemeth->name, flat->meth.name);
3620
sfprintf(sfstdout, "{\n");
3621
offset = 0;
3622
pad = 0;
3623
for (f = flat->fields; f; f = f->next)
3624
{
3625
if (f->structure.members)
3626
{
3627
f->structure.size = offset;
3628
sfprintf(sfstdout, "struct\n{\n");
3629
continue;
3630
}
3631
a = p = s = "";
3632
m = 1;
3633
n = 0;
3634
if (f->variable.array)
3635
{
3636
if (f->variable.array->size)
3637
{
3638
m = f->variable.array->size;
3639
a = sfprints("[%d]", f->variable.array->size);
3640
}
3641
else
3642
p = "*";
3643
}
3644
if (f->structure.level)
3645
n += sfprintf(sfstdout, "/*%02d*/", f->structure.level);
3646
else
3647
f->variable.structure = 0;
3648
if (f->variable.format.flags & CX_BUFFER)
3649
{
3650
n += sfprintf(sfstdout, "struct _%s_%s_buf_s", flat->basemeth->name, flat->meth.name);
3651
n = tabs(sfstdout, n, 24);
3652
n += sfprintf(sfstdout, "%s%s%s;", p, f->variable.name, a);
3653
}
3654
else if ((f->variable.format.flags & CX_STRING) || !(f->physical.format.flags & CX_BINARY))
3655
{
3656
n += sfprintf(sfstdout, "char");
3657
n = tabs(sfstdout, n, 24);
3658
n += sfprintf(sfstdout, "%s%s%s", p, f->variable.name, a);
3659
if (f->physical.format.width > 1)
3660
n += sfprintf(sfstdout, "[%u];", f->physical.format.width);
3661
else
3662
n += sfprintf(sfstdout, ";");
3663
}
3664
else
3665
{
3666
if (f->variable.format.flags & CX_FLOAT)
3667
n += sfprintf(sfstdout, "_ast_flt");
3668
else
3669
{
3670
if ((f->variable.format.flags & CX_UNSIGNED) || !streq((char*)f->variable.type, "number"))
3671
n += sfprintf(sfstdout, "unsigned ");
3672
n += sfprintf(sfstdout, "_ast_int");
3673
}
3674
n += sfprintf(sfstdout, "%u_t", f->physical.format.width);
3675
n = tabs(sfstdout, n, 24);
3676
n += sfprintf(sfstdout, "%s%s%s;", p, f->variable.name, a);
3677
if ((offset % f->physical.format.width) && !cxisvoid(f->variable.type))
3678
{
3679
s = "(MISALIGNED) ";
3680
if (disc->errorf)
3681
(*disc->errorf)(NiL, disc, 1, "%s: field size %u offset %u is not aligned", f->variable.name, f->physical.format.width, offset);
3682
}
3683
}
3684
offset += m * f->physical.format.width;
3685
if (*s || f->variable.description)
3686
{
3687
tabs(sfstdout, n, 40);
3688
sfprintf(sfstdout, "/* %s%s */\n", s, f->variable.description ? f->variable.description : "");
3689
}
3690
else
3691
sfputc(sfstdout, '\n');
3692
if (f->physical.format.delimiter >= 0)
3693
{
3694
n = sfprintf(sfstdout, "char");
3695
n = tabs(sfstdout, n, 24);
3696
n += sfprintf(sfstdout, "_delimiter_%d;", ++pad);
3697
tabs(sfstdout, n, 40);
3698
offset += 1;
3699
tmp[0] = f->physical.format.delimiter;
3700
tmp[1] = 0;
3701
sfprintf(sfstdout, "/* delimiter '%s' */\n", fmtesc(tmp));
3702
}
3703
if (!f->structure.next)
3704
{
3705
v = &f->variable;
3706
if (v->structure)
3707
while (!v->structure->next && (v = v->structure->parent) && v->structure)
3708
{
3709
v->structure->size = offset - v->structure->size;
3710
if (v->array)
3711
{
3712
if (v->array->size)
3713
{
3714
offset += (v->array->size - 1) * v->structure->size;
3715
sfprintf(sfstdout, "} %s[%d]", v->name, v->array->size);
3716
}
3717
else
3718
sfprintf(sfstdout, "} *%s", v->name);
3719
if (v->array->variable)
3720
sfprintf(sfstdout, " /*%s*/", v->array->variable->name);
3721
sfprintf(sfstdout, ";\n");
3722
}
3723
else
3724
sfprintf(sfstdout, "} %s;\n", v->name);
3725
}
3726
}
3727
}
3728
sfprintf(sfstdout, "};\n");
3729
if (flat->binary && (fixed = offset % 8))
3730
{
3731
fixed = 8 - fixed;
3732
sfprintf(sfstdout, "/* struct has %u unused pad byte%s */\n", fixed, fixed == 1 ? "" : "s");
3733
if (disc->errorf)
3734
(*disc->errorf)(NiL, disc, 1, "%s: record has %u unused pad byte%s", flat->meth.name, fixed, fixed == 1 ? "" : "s");
3735
}
3736
sfprintf(sfstdout, "/* sizeof(struct _%s_%s_s)==%u */\n", flat->basemeth->name, flat->meth.name, offset);
3737
break;
3738
}
3739
if (flat->list || flat->prototype)
3740
exit(0);
3741
flat->getf = flatget;
3742
if (flat->binary && flat->fixed && !(flat->test & 0x0010))
3743
{
3744
offset = 0;
3745
for (f = flat->fields; f; f = f->next)
3746
{
3747
if ((f->variable.format.flags & CX_BINARY) && ((offset % f->physical.format.width) || (f->physical.format.width & (f->physical.format.width - 1)) || f->physical.format.width > 8) || f->width)
3748
break;
3749
offset += f->physical.format.width;
3750
}
3751
if (!f && !(offset % 8))
3752
flat->getf = flatgetbinary;
3753
}
3754
if (flat->record || (flat->fixed % 8))
3755
flat->getf = flatget;
3756
flat->valsiz = 64;
3757
if (!(flat->valbuf = newof(0, char, flat->valsiz, 0)))
3758
{
3759
if (disc->errorf)
3760
(*disc->errorf)(dss, disc, ERROR_SYSTEM|2, "out of space");
3761
return -1;
3762
}
3763
if (!flat->fixed || flat->record)
3764
flat->variable = 0;
3765
if (flat->variable || (dss->flags & DSS_FORCE))
3766
flat->force = 1;
3767
}
3768
return 0;
3769
}
3770
3771
static Dssmeth_t method =
3772
{
3773
"flat",
3774
"fixed-width and/or field-delimited flat file data",
3775
CXH,
3776
flatmeth,
3777
flatopen,
3778
0,
3779
0,
3780
0,
3781
0,
3782
0,
3783
0,
3784
0,
3785
DSS_BASE
3786
};
3787
3788
static const char flatten_usage[] =
3789
"[-1ls5P?\n@(#)$Id: dss flatten query (AT&T Research) 2005-05-09 $\n]"
3790
USAGE_LICENSE
3791
"[+PLUGIN?\findex\f]"
3792
"[+DESCRIPTION?Flatten input data to match flat method \bschema\b.]"
3793
"[e:emptyspace?Write empty field values as one \bspace\b character.]"
3794
"\n"
3795
"\nschema\n"
3796
"\n"
3797
;
3798
3799
/*
3800
* get source field value
3801
*/
3802
3803
static Cxvalue_t*
3804
flattenget(register Flatten_t* flatten, Cxvariable_t* var, void* data)
3805
{
3806
Cxinstruction_t x;
3807
Cxreference_t* ref;
3808
3809
if (ref = var->reference)
3810
{
3811
x.data.variable = ref->variable;
3812
if ((*flatten->cx->getf)(flatten->cx, &x, &flatten->value, NiL, NiL, data, flatten->cx->disc))
3813
return &nullval;
3814
while (ref = ref->next)
3815
{
3816
x.data.variable = ref->variable;
3817
if ((*ref->member->getf)(flatten->cx, &x, &flatten->value, NiL, NiL, NiL, flatten->cx->disc))
3818
return &nullval;
3819
}
3820
}
3821
else
3822
{
3823
x.data.variable = var;
3824
if ((*flatten->cx->getf)(flatten->cx, &x, &flatten->value, NiL, NiL, data, flatten->cx->disc))
3825
return &nullval;
3826
}
3827
return &flatten->value.value;
3828
}
3829
3830
/*
3831
* flattenget() with cxnum2str()
3832
*/
3833
3834
static Cxvalue_t*
3835
flattennum2str(register Flatten_t* flatten, Cxvariable_t* var, void* data)
3836
{
3837
Cxvalue_t* val;
3838
3839
if ((val = flattenget(flatten, var, data)) != &nullval)
3840
{
3841
if (cxnum2str(flatten->cx, &var->format, (Cxinteger_t)val->number, &val->string.data))
3842
return &nullval;
3843
val->string.size = strlen(val->string.data);
3844
}
3845
return val;
3846
}
3847
3848
/*
3849
* flattenget() with cxstr2num()
3850
*/
3851
3852
static Cxvalue_t*
3853
flattenstr2num(register Flatten_t* flatten, Cxvariable_t* var, void* data)
3854
{
3855
Cxvalue_t* val;
3856
Cxunsigned_t u;
3857
3858
if ((val = flattenget(flatten, var, data)) != &nullval)
3859
{
3860
if (cxstr2num(flatten->cx, &var->format, val->string.data, val->string.size, &u))
3861
return &nullval;
3862
val->number = (Cxinteger_t)u;
3863
}
3864
return val;
3865
}
3866
3867
/*
3868
* get nullval field value
3869
*/
3870
3871
static Cxvalue_t*
3872
flattennull(Flatten_t* flatten, Cxvariable_t* var, void* data)
3873
{
3874
return &nullval;
3875
}
3876
3877
/*
3878
* flatten query begin
3879
*/
3880
3881
static int
3882
flatten_beg(Cx_t* cx, Cxexpr_t* expr, void* data, Cxdisc_t* disc)
3883
{
3884
char** argv = (char**)data;
3885
int errors = error_info.errors;
3886
int emptyspace = 0;
3887
char* schema;
3888
Dssmeth_t* meth;
3889
Flatten_t* flatten;
3890
Field_t* f;
3891
Field_t* g;
3892
Vmalloc_t* vm;
3893
int offset;
3894
int fixed;
3895
3896
for (;;)
3897
{
3898
switch (optget(argv, flatten_usage))
3899
{
3900
case 'e':
3901
emptyspace = 1;
3902
continue;
3903
case '?':
3904
if (disc->errorf)
3905
(*disc->errorf)(NiL, disc, ERROR_USAGE|4, "%s", opt_info.arg);
3906
continue;
3907
case ':':
3908
if (disc->errorf)
3909
(*disc->errorf)(NiL, disc, 2, "%s", opt_info.arg);
3910
continue;
3911
}
3912
break;
3913
}
3914
if (error_info.errors > errors)
3915
return -1;
3916
argv += opt_info.index;
3917
if (!(schema = *argv++) || *argv)
3918
{
3919
if (disc->errorf)
3920
(*disc->errorf)(NiL, disc, ERROR_USAGE|4, "%s", optusage(NiL));
3921
return -1;
3922
}
3923
if (!(vm = vmopen(Vmdcheap, Vmlast, 0)) || !(flatten = vmnewof(vm, 0, Flatten_t, 1, 0)))
3924
{
3925
if (vm)
3926
vmclose(vm);
3927
if (disc->errorf)
3928
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
3929
return -1;
3930
}
3931
#if _HUH_2010_05_28
3932
if (!strchr(schema, ':'))
3933
schema = sfprints("%s:%s", *(char**)data, schema);
3934
#endif
3935
flatten->vm = vm;
3936
flatten->emptyspace = emptyspace;
3937
if (!(meth = dssmeth(schema, disc)) || !(flatten->dss = dssopen(0, 0, disc, meth)))
3938
{
3939
if (disc->errorf)
3940
(*disc->errorf)(NiL, disc, 2, "%s: cannot open conversion method", schema);
3941
goto bad;
3942
}
3943
flatten->cx = flatten->dss->cx;
3944
if (!flatten->cx->getf && !(flatten->cx->getf = cxcallout(flatten->cx, CX_GET, flatten->cx->state->type_void, flatten->cx->state->type_void, flatten->cx->disc)))
3945
{
3946
if (disc->errorf)
3947
(*disc->errorf)(NiL, disc, 3, "cx CX_GET callout must be defined");
3948
goto bad;
3949
}
3950
flatten->getf = flatten->cx->getf;
3951
flatten->flat = (Flat_t*)flatten->dss->meth->data;
3952
offset = 0;
3953
fixed = flatten->flat->fixed;
3954
for (f = flatten->flat->fields; f; f = f->next)
3955
{
3956
f->flattengetf = flattenget;
3957
if (!(f->flatten = (Cxvariable_t*)dtmatch(cx->variables, f->variable.name)))
3958
{
3959
f->flattengetf = flattennull;
3960
if (!cxisvoid(f->variable.type) && disc->errorf)
3961
(*disc->errorf)(NiL, disc, 1, "%s: field not in source record -- default value will be output", f->variable.name);
3962
}
3963
else if (f->flatten->format.map)
3964
{
3965
if (cxisnumber(f->variable.type) && cxisstring(f->flatten->type))
3966
f->flattengetf = flattenstr2num;
3967
else if (cxisstring(f->variable.type) && cxisnumber(f->flatten->type))
3968
f->flattengetf = flattennum2str;
3969
}
3970
if ((g = (Field_t*)dtmatch(cx->variables, f->variable.name)) && g->physical.format.code != f->physical.format.code && g->physical.format.code == CC_NATIVE)
3971
f->pam = ccmap(g->physical.format.code, f->physical.format.code);
3972
if (fixed && (f->variable.format.flags & CX_BINARY) && (offset % f->physical.format.width))
3973
{
3974
if (disc->errorf)
3975
(*disc->errorf)(NiL, disc, 2, "%s: field size %u offset %u is not aligned", f->variable.name, f->physical.format.width, offset);
3976
goto bad;
3977
}
3978
offset += f->physical.format.width;
3979
}
3980
if (flatten->flat->binary && (offset %= 8))
3981
{
3982
offset = 8 - offset;
3983
if (disc->errorf)
3984
(*disc->errorf)(NiL, disc, 2, "%s: record has %u unused pad byte%s", flatten->dss->meth->name, offset, offset == 1 ? "" : "s");
3985
goto bad;
3986
}
3987
if (!(flatten->file = dssfopen(flatten->dss, NiL, expr->op, DSS_FILE_WRITE, &flat_format)))
3988
goto bad;
3989
expr->op = flatten->file->io;
3990
expr->data = flatten;
3991
return 0;
3992
bad:
3993
if (flatten->file)
3994
dssfclose(flatten->file);
3995
if (flatten->dss)
3996
dssclose(flatten->dss);
3997
vmclose(vm);
3998
return -1;
3999
}
4000
4001
/*
4002
* flatten query action
4003
*/
4004
4005
static int
4006
flatten_act(Cx_t* cx, Cxexpr_t* expr, void* data, Cxdisc_t* disc)
4007
{
4008
register Flatten_t* flatten = (Flatten_t*)expr->data;
4009
register Field_t* f;
4010
register unsigned char* s;
4011
Cxvalue_t* v;
4012
unsigned char* b;
4013
unsigned char* e;
4014
ssize_t n;
4015
int q;
4016
4017
for (f = flatten->flat->fields; f; f = f->next)
4018
{
4019
v = (*f->flattengetf)(flatten, f->flatten, data);
4020
while ((n = (*f->physical.type->externalf)(flatten->cx, f->physical.type, NiL, &f->physical.format, v, flatten->flat->valbuf, flatten->flat->valsiz, disc)) > flatten->flat->valsiz)
4021
{
4022
n = roundof(n, 32);
4023
if (!(flatten->flat->valbuf = newof(flatten->flat->valbuf, char, n, 0)))
4024
{
4025
if (disc->errorf)
4026
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
4027
return -1;
4028
}
4029
flatten->flat->valsiz = n;
4030
}
4031
if (n < 0)
4032
return -1;
4033
else if (n > 0)
4034
{
4035
if (f->pam)
4036
ccmapcpy(f->pam, flatten->flat->valbuf, flatten->flat->valbuf, n);
4037
if ((f->physical.format.flags & (CX_STRING|CX_BUFFER)) && f->physical.format.delimiter >= 0 && (f->physical.format.escape >= 0 || f->physical.format.quotebegin >= 0))
4038
{
4039
if (f->physical.format.flags & CX_QUOTEALL)
4040
{
4041
q = 1;
4042
sfputc(flatten->file->io, f->physical.format.quotebegin);
4043
}
4044
else
4045
q = 0;
4046
for (e = (s = b = (unsigned char*)flatten->flat->valbuf) + n; s < e; s++)
4047
if (*s == f->physical.format.delimiter || *s == f->physical.format.escape || *s == f->physical.format.quotebegin || *s == f->physical.format.quoteend)
4048
{
4049
if (f->physical.format.escape >= 0)
4050
{
4051
sfwrite(flatten->file->io, b, s - b);
4052
sfputc(flatten->file->io, f->physical.format.escape);
4053
sfputc(flatten->file->io, *s);
4054
}
4055
else if (*s == f->physical.format.delimiter)
4056
{
4057
if (q)
4058
continue;
4059
q = 1;
4060
sfwrite(flatten->file->io, b, s - b);
4061
sfputc(flatten->file->io, f->physical.format.quotebegin);
4062
sfputc(flatten->file->io, *s);
4063
}
4064
else
4065
{
4066
sfwrite(flatten->file->io, b, s - b + 1);
4067
sfputc(flatten->file->io, *s);
4068
if (!q)
4069
{
4070
q = 1;
4071
sfputc(flatten->file->io, *s);
4072
}
4073
}
4074
b = s + 1;
4075
}
4076
if (q && !(f->physical.format.flags & CX_QUOTEALL))
4077
{
4078
q = 0;
4079
sfputc(flatten->file->io, f->physical.format.quoteend);
4080
}
4081
sfwrite(flatten->file->io, b, s - b);
4082
if (q)
4083
sfputc(flatten->file->io, f->physical.format.quoteend);
4084
}
4085
else
4086
sfwrite(flatten->file->io, flatten->flat->valbuf, n);
4087
}
4088
else if (flatten->emptyspace && f->physical.format.delimiter >= 0)
4089
sfputc(flatten->file->io, ' ');
4090
if (f->physical.format.delimiter >= 0)
4091
sfputc(flatten->file->io, f->physical.format.delimiter);
4092
}
4093
return 0;
4094
}
4095
4096
/*
4097
* flatten query end
4098
*/
4099
4100
static int
4101
flatten_end(Cx_t* cx, Cxexpr_t* expr, void* data, Cxdisc_t* disc)
4102
{
4103
Flatten_t* flatten = (Flatten_t*)expr->data;
4104
int r;
4105
4106
if (!flatten)
4107
return -1;
4108
expr->data = 0;
4109
r = 0;
4110
if (dssfclose(flatten->file))
4111
r = -1;
4112
if (dssclose(flatten->dss))
4113
r = -1;
4114
vmclose(flatten->vm);
4115
return r;
4116
}
4117
4118
static Cxquery_t queries[] =
4119
{
4120
{ "flatten", "query to flatten input data to flat schema format",
4121
CXH, flatten_beg, 0, flatten_act, flatten_end },
4122
{0}
4123
};
4124
4125
Dsslib_t dss_lib_flat =
4126
{
4127
"flat",
4128
"flat method"
4129
"[-1ls5Pp0?\n@(#)$Id: dss flat method (AT&T Research) 2011-08-19 $\n]"
4130
USAGE_LICENSE,
4131
CXH,
4132
0,
4133
&method,
4134
0,
4135
0,
4136
0,
4137
0,
4138
&queries[0],
4139
};
4140
4141