Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/jcl/cpy2dss.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2003-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
22
/*
23
* convert copybook to dss flat schema
24
*/
25
26
static const char usage[] =
27
"[-?\n@(#)$Id: cpy2dss (AT&T Research) 2007-02-20 $\n]"
28
USAGE_LICENSE
29
"[+NAME?cpy2dss - convert copybook to dss flat schema]"
30
"[+DESCRIPTION?\bcpy2dss\b converts each copybook \afile\a operand to a"
31
" \bdss\b flat schema file on the standard output. If no \afile\a"
32
" operands are specified then the standard input is read.]"
33
"[+?Duplicate structure and field names are disambiguated by appending"
34
" \b_\b\acount\a to the names, where \acount\a > 1. \bRENAMES\b"
35
" and level 88 fields are ignored.]"
36
"[b:bytemask?Output a single line where each character represents the"
37
" type of the corresponding byte in the physical representation of"
38
" a copybook record, where \b0\b means \bPIC\b and \an\a means"
39
" \bCOMP-\b\an\a.]"
40
"[c:codeset?Set the \bstring\b codeset name.]:[codeset:=ebcdic-m]"
41
"[C:comp?Convert COMP-\afrom\a to COMP-\ato\a.]:[from::to]"
42
"[d:delimiter?Set the \b--text\b field delimiter character. XML"
43
" &\aname\a; and #\adecimal\a; forms are accepted.]:[delimiter:=|]"
44
"[D:terminator?Set the \b--text\b record terminator character. XML"
45
" &\aname\a; and #\adecimal\a; forms are"
46
" accepted.]:[terminator:=&newline;]"
47
"[e:escape?Set the \b--text\b field escape character. XML"
48
" &\aname\a; and #\adecimal\a; forms are accepted.]:[delimiter:=\boff\b]"
49
"[k:keep?Keep original names. Otherwise non-identifier characters are"
50
" converted to \b_\b.]"
51
"[l:little-endian|le?Little-endian binary integer encoding.]"
52
"[o:offsets?Output the name, offset, size, number of elements and type"
53
" of each member, one per line, on the standard output. Scalar"
54
" fields have 0 elements.]"
55
"[q:quote?Set the \b--text\b field quote begin character. If"
56
" \b--end-quote\b is not specified then it is the same as"
57
" \b--quote\b. XML &\aname\a; and #\adecimal\a; forms are"
58
" accepted.]:[quote:=\"]"
59
"[Q:end-quote?Set the \b--text\b field quote end character. If"
60
" \b--quote\b is not specified then it is the same as"
61
" \b--end-quote\b. XML &\aname\a; and #\adecimal\a; forms are"
62
" accepted.]:[quote:=\"]"
63
"[r:reclen|record-length?Sets the physical record format to be fixed"
64
" with a record length of \areclen\a bytes.]#[reclen]"
65
"[s!:sized-struct?Check for embedded size/data structures.]"
66
"[t:text?Generate a field-delimited newline-terminated text schema"
67
" using the local codeset.]"
68
"[T:regress?Massage output for regression testing.]"
69
"[v:variable?If \b--notext\b is on then records are variable length,"
70
" delimited by the \b--terminator\b character. If \b--text\b is"
71
" on then the size field \b--sized\b structures is omitted from"
72
" the output.]"
73
"\n"
74
"\n[ file ... ]\n"
75
"\n"
76
;
77
78
#include <ast.h>
79
#include <ctype.h>
80
#include <ccode.h>
81
#include <dt.h>
82
#include <ls.h>
83
#include <tm.h>
84
#include <error.h>
85
86
#define CPY_VERSION 20030220L
87
88
#define cpyinit(d,e) (memset(d,0,sizeof(Cpydisc_t)),(d)->version=CPY_VERSION,(d)->errorf=(Error_f)(e))
89
90
#define CPY_binary (1<<0)
91
#define CPY_number (1<<1)
92
#define CPY_pointer (1<<2)
93
#define CPY_signed (1<<3)
94
#define CPY_string (1<<4)
95
#define CPY_sync (1<<5)
96
97
#define CPY_XML 0
98
#define CPY_BYTEMASK 1
99
#define CPY_OFFSETS 2
100
101
#define CPY_ALIGN(w) (((w)<=2)?2:4)
102
103
struct Cpyfield_s; typedef struct Cpyfield_s Cpyfield_t;
104
105
struct Cpyfield_s
106
{
107
Dtlink_t link;
108
Cpyfield_t* parent;
109
Cpyfield_t* members;
110
Cpyfield_t* next;
111
Cpyfield_t* sized;
112
Cpyfield_t* redefines;
113
char* dimension;
114
unsigned long offset;
115
int comp;
116
int dup;
117
int level;
118
int fixedpoint;
119
int mindimension;
120
int maxdimension;
121
int structure;
122
int width;
123
int total;
124
unsigned int flags;
125
char name[8];
126
};
127
128
typedef struct Cpydisc_s
129
{
130
uint32_t version;
131
Error_f errorf;
132
} Cpydisc_t;
133
134
typedef struct Cpy_s
135
{
136
const char* id;
137
Cpydisc_t* disc;
138
Cpyfield_t* first;
139
Cpyfield_t* last;
140
Sfio_t* ip;
141
char* cp;
142
char* ofile;
143
int item;
144
int oline;
145
int size;
146
Vmalloc_t* vm;
147
Dt_t* dt;
148
} Cpy_t;
149
150
static struct State_s
151
{
152
char* codeset;
153
char* delimiter;
154
char* endian;
155
char* escape;
156
char* quotebegin;
157
char* quoteend;
158
char* terminator;
159
160
size_t fixed;
161
162
int keep;
163
int output;
164
int regress;
165
int sized;
166
int text;
167
int variable;
168
169
int comp[10];
170
} state;
171
172
static char empty[] = "\n";
173
174
Cpy_t*
175
cpyopen(const char* path, Sfio_t* ip, Cpydisc_t* disc)
176
{
177
register Cpy_t* cpy;
178
Vmalloc_t* vm;
179
180
static Dtdisc_t dictdisc;
181
182
dictdisc.key = offsetof(Cpyfield_t, name);
183
dictdisc.size = 0;
184
dictdisc.link = offsetof(Cpyfield_t, link);
185
if (!(vm = vmopen(Vmdcheap, Vmlast, 0)) || !(cpy = vmnewof(vm, 0, Cpy_t, 1, 0)) || !(cpy->dt = dtnew(vm, &dictdisc, Dtset)))
186
{
187
if (vm)
188
vmclose(vm);
189
if (disc->errorf)
190
(*disc->errorf)(cpy, disc, ERROR_SYSTEM|2, "out of space");
191
return 0;
192
}
193
cpy->id = "cpy";
194
cpy->vm = vm;
195
cpy->disc = disc;
196
cpy->ip = ip;
197
cpy->cp = empty;
198
cpy->ofile = error_info.file;
199
error_info.file = (char*)path;
200
cpy->oline = error_info.line;
201
error_info.line = 0;
202
return cpy;
203
}
204
205
int
206
cpyclose(Cpy_t* cpy)
207
{
208
error_info.file = cpy->ofile;
209
error_info.line = cpy->oline;
210
vmclose(cpy->vm);
211
return 0;
212
}
213
214
char*
215
cpylex(register Cpy_t* cpy)
216
{
217
register char* s;
218
register int q;
219
220
if (cpy->item)
221
{
222
cpy->item = 0;
223
cpy->size = 0;
224
return "";
225
}
226
for (;;)
227
{
228
switch (*cpy->cp)
229
{
230
case '*':
231
case '\n':
232
do
233
{
234
if (!(cpy->cp = sfgetr(cpy->ip, '\n', 0)))
235
{
236
cpy->cp = empty;
237
return 0;
238
}
239
error_info.line++;
240
} while ((q = sfvalue(cpy->ip)) < 7);
241
if (q > 72)
242
cpy->cp[72] = '\n';
243
cpy->cp += 6;
244
continue;
245
case ' ':
246
case '\t':
247
case '\r':
248
cpy->cp++;
249
continue;
250
}
251
break;
252
}
253
s = cpy->cp;
254
q = 0;
255
for (;;)
256
{
257
switch (*cpy->cp++)
258
{
259
case '\n':
260
*(cpy->cp - 1) = 0;
261
cpy->size = cpy->cp - s - 1;
262
cpy->cp = empty;
263
return s;
264
case ' ':
265
case '\t':
266
case '\r':
267
if (!q)
268
break;
269
continue;
270
case '\'':
271
q = !q;
272
continue;
273
case '.':
274
if (!q)
275
{
276
if (cpy->cp > s + 1)
277
{
278
if (isdigit(*cpy->cp) && (isdigit(*(cpy->cp - 2)) || *(cpy->cp - 2) == ')'))
279
continue;
280
cpy->item = 1;
281
}
282
*cpy->cp = '\n';
283
break;
284
}
285
continue;
286
case '-':
287
if ((cpy->cp - 1) == s && isdigit(*cpy->cp))
288
continue;
289
/*FALLTHROUGH*/
290
case ':':
291
case '&':
292
if (!q && !state.keep)
293
*(cpy->cp - 1) = '_';
294
continue;
295
default:
296
continue;
297
}
298
break;
299
}
300
*(cpy->cp - 1) = 0;
301
cpy->size = cpy->cp - s - 1;
302
return s;
303
}
304
305
Cpyfield_t*
306
cpyfield(register Cpy_t* cpy)
307
{
308
register char* s;
309
register Cpyfield_t* f;
310
Cpyfield_t* p;
311
size_t n;
312
char* e;
313
int fixedpoint;
314
int level;
315
int width;
316
317
do
318
{
319
if (!(s = cpylex(cpy)))
320
return 0;
321
} while (!strncasecmp(s, "SKIP", 4));
322
level = (int)strtol(s, &e, 10);
323
if (*e)
324
{
325
if (cpy->disc->errorf)
326
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: syntax error: level number expected", s);
327
return 0;
328
}
329
if (!(s = cpylex(cpy)) || !*s)
330
return 0;
331
if (!(f = vmnewof(cpy->vm, 0, Cpyfield_t, 1, cpy->size)))
332
{
333
if (cpy->disc->errorf)
334
(*cpy->disc->errorf)(cpy, cpy->disc, ERROR_SYSTEM|2, "out of space");
335
return 0;
336
}
337
if (cpy->first)
338
cpy->last->next = f;
339
else
340
cpy->first = f;
341
cpy->last = f;
342
f->level = level;
343
e = s;
344
while ((p = (Cpyfield_t*)dtmatch(cpy->dt, e)) && p->dup)
345
{
346
p->dup++;
347
e = sfprints("%s_%d", s, p->dup);
348
}
349
strcpy(f->name, e);
350
if (!p)
351
dtinsert(cpy->dt, f);
352
f->dup = 1;
353
f->structure = 1;
354
while ((s = cpylex(cpy)) && *s)
355
{
356
again:
357
if (!strcasecmp(s, "BINARY"))
358
{
359
f->structure = 0;
360
f->flags |= CPY_binary;
361
}
362
else if (!strncasecmp(s, "COMP", 4))
363
{
364
f->structure = 0;
365
s += !strncasecmp(s, "COMPUTATIONAL", 13) ? 13 : 4;
366
if (*s++ != '_')
367
f->comp = 1;
368
else
369
{
370
f->comp = (int)strtol(s, &e, 10);
371
if (*e || f->comp <= 0 || f->comp > 9)
372
{
373
if (cpy->disc->errorf)
374
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: syntax error: COMP number in range 1..9 expected", s);
375
continue;
376
}
377
}
378
f->comp = state.comp[f->comp];
379
}
380
else if (!strcasecmp(s, "DEPENDING"))
381
{
382
if (!(s = cpylex(cpy)) || !*s)
383
break;
384
if (strcasecmp(s, "ON"))
385
{
386
if (cpy->disc->errorf)
387
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: syntax error: ON expected", s);
388
continue;
389
}
390
if (!(s = cpylex(cpy)) || !*s)
391
break;
392
if (!(p = (Cpyfield_t*)dtmatch(cpy->dt, s)))
393
{
394
if (!(p = vmnewof(cpy->vm, 0, Cpyfield_t, 1, cpy->size)))
395
{
396
if (cpy->disc->errorf)
397
(*cpy->disc->errorf)(cpy, cpy->disc, ERROR_SYSTEM|2, "out of space");
398
return 0;
399
}
400
dtinsert(cpy->dt, p);
401
}
402
else if (p->dup > 1)
403
{
404
s = sfprints("%s_%d", p->name, p->dup);
405
if (!(p = (Cpyfield_t*)dtmatch(cpy->dt, s)))
406
{
407
if (cpy->disc->errorf)
408
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: internal error: dup not found", s);
409
return 0;
410
}
411
}
412
f->dimension = p->name;
413
}
414
else if (!strcasecmp(s, "INDEXED"))
415
{
416
if (!(s = cpylex(cpy)) || !*s)
417
break;
418
if (strcasecmp(s, "BY"))
419
{
420
if (cpy->disc->errorf)
421
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: syntax error: BY expected", s);
422
continue;
423
}
424
if (!(s = cpylex(cpy)) || !*s)
425
break;
426
}
427
else if (!strcasecmp(s, "IS"))
428
/*ignore*/;
429
else if (!strcasecmp(s, "OCCURS"))
430
{
431
if (!(s = cpylex(cpy)) || !*s)
432
break;
433
f->mindimension = (int)strtol(s, &e, 10);
434
if (*e)
435
{
436
if (cpy->disc->errorf)
437
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: syntax error: minimum OCCURS number expected", s);
438
continue;
439
}
440
if (!(s = cpylex(cpy)) || !*s)
441
break;
442
if (!strcasecmp(s, "TO"))
443
{
444
if (!(s = cpylex(cpy)) || !*s)
445
break;
446
f->maxdimension = (int)strtol(s, &e, 10);
447
if (*e)
448
{
449
if (cpy->disc->errorf)
450
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: syntax error: maximum OCCURS number expected", s);
451
continue;
452
}
453
if (!(s = cpylex(cpy)) || !*s)
454
break;
455
}
456
else
457
f->maxdimension = f->mindimension;
458
if (strcasecmp(s, "TIMES"))
459
goto again;
460
}
461
else if (!strncasecmp(s, "PACKED", 6))
462
{
463
f->structure = 0;
464
f->comp = 3;
465
}
466
else if (!strncasecmp(s, "PIC", 3))
467
{
468
f->structure = 0;
469
if (!(s = cpylex(cpy)) || !*s)
470
break;
471
fixedpoint = width = 0;
472
for (;;)
473
{
474
switch (*s++)
475
{
476
case 0:
477
break;
478
case 'S':
479
case 's':
480
case '-':
481
f->flags |= CPY_signed;
482
continue;
483
case 'V':
484
case 'v':
485
case '.':
486
fixedpoint = 1;
487
continue;
488
case '9':
489
f->flags |= CPY_number;
490
width++;
491
continue;
492
case 'X':
493
case 'x':
494
f->flags |= CPY_string;
495
width++;
496
continue;
497
case '(':
498
width = 0;
499
n = (int)strtol(s, &e, 10);
500
if (*e == ')')
501
e++;
502
s = e;
503
f->width += n;
504
if (fixedpoint)
505
{
506
fixedpoint = 0;
507
f->fixedpoint = n;
508
}
509
continue;
510
default:
511
if (cpy->disc->errorf)
512
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: unknown PIC", s - 1);
513
break;
514
}
515
break;
516
}
517
if (width)
518
{
519
f->width += width;
520
if (fixedpoint)
521
f->fixedpoint = width;
522
}
523
}
524
else if (!strcasecmp(s, "POINTER"))
525
{
526
f->structure = 0;
527
f->flags |= CPY_pointer;
528
f->width = 4;
529
s += 7;
530
f->comp = state.comp[5];
531
}
532
else if (!strcasecmp(s, "REDEFINES"))
533
{
534
if (!(s = cpylex(cpy)) || !*s)
535
{
536
if (cpy->disc->errorf)
537
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "redefined member name expected");
538
return 0;
539
}
540
e = s;
541
while ((p = (Cpyfield_t*)dtmatch(cpy->dt, e)) && p->dup > 1)
542
e = sfprints("%s_%d", s, p->dup);
543
if (!(f->redefines = p))
544
{
545
if (cpy->disc->errorf)
546
(*cpy->disc->errorf)(cpy, cpy->disc, 2, "%s: unknown member", s);
547
return 0;
548
}
549
}
550
else if (!strncasecmp(s, "SYNC", 4))
551
f->flags |= CPY_sync;
552
else if (!strcasecmp(s, "USAGE"))
553
f->structure = 0;
554
else if (!strncasecmp(s, "VALUE", 5))
555
{
556
f->structure = 0;
557
while ((s = cpylex(cpy)) && *s);
558
break;
559
}
560
else if (cpy->disc->errorf)
561
(*cpy->disc->errorf)(cpy, cpy->disc, 1, "%s: unknown attribute", s);
562
}
563
return f;
564
}
565
566
static int
567
compwidth(Cpyfield_t* field, int width)
568
{
569
switch (field->comp)
570
{
571
case 0:
572
if (field->fixedpoint)
573
width++;
574
if (field->flags & CPY_signed)
575
width++;
576
break;
577
case 1:
578
case 5:
579
if (width <= 2)
580
width = 1;
581
else if (width <= 4)
582
width = 2;
583
else if (width <= 9)
584
width = 4;
585
else
586
width = 8;
587
break;
588
case 3:
589
width = (width + 2) / 2;
590
break;
591
}
592
return width;
593
}
594
595
static char*
596
typename(Cpyfield_t* field)
597
{
598
char* type;
599
600
if (field->flags & CPY_pointer)
601
type = "unsigned char*";
602
else if (field->flags & CPY_binary)
603
type = state.endian;
604
else
605
switch (field->comp)
606
{
607
case 1:
608
type = "be_t";
609
break;
610
case 2:
611
type = "ibm_t";
612
break;
613
case 3:
614
type = "bcd_t";
615
break;
616
case 5:
617
type = "le_t";
618
break;
619
default:
620
type = 0;
621
break;
622
}
623
return type;
624
}
625
626
#define INDENT(n) (&indent[sizeof(indent)-(n)-1])
627
628
int
629
cpy2dss(const char* path, Sfio_t* ip, Sfio_t* op, Cpydisc_t* disc, time_t stamp)
630
{
631
Cpy_t* cpy;
632
Cpyfield_t* field;
633
Cpyfield_t* next;
634
Cpyfield_t* parent;
635
Cpyfield_t* member;
636
char* delimiter;
637
char* type;
638
unsigned long offset;
639
long n;
640
int c;
641
int i;
642
int j;
643
int lev;
644
int skip;
645
int structure;
646
int width;
647
int levels[256];
648
char indent[elementsof(levels) + 2];
649
650
if (!(cpy = cpyopen(path, ip, disc)))
651
return -1;
652
memset(indent, ' ', sizeof(indent) - 1);
653
indent[sizeof(indent) - 1] = 0;
654
if (field = cpyfield(cpy))
655
{
656
parent = field;
657
member = 0;
658
offset = field->width;
659
i = state.sized && !state.text && state.fixed;
660
while (next = cpyfield(cpy))
661
if (i)
662
{
663
width = next->width;
664
if (next->flags & CPY_number)
665
width = compwidth(next, width);
666
offset += width;
667
if (!member && (i = strlen(parent->name)) && !memcmp(parent->name, next->name, i) && strmatch(next->name + i, "?(_)(siz|SIZ|LEN|len)*"))
668
member = next;
669
parent = next;
670
}
671
if (i && offset > state.fixed)
672
{
673
if (!member || !(member = member->next))
674
error(1, "accumulated field sizes %lu exceeds fixed record size %lu", offset, state.fixed);
675
else
676
{
677
if ((n = member->width - (offset - state.fixed)) > 0)
678
{
679
error(1, "%s: maximum variable field size shortened from %d to %ld to comply with fixed record size %u", member->name, member->width, n, state.fixed);
680
member->width = n;
681
}
682
}
683
}
684
levels[lev = 0] = 0;
685
switch (state.output)
686
{
687
case CPY_OFFSETS:
688
offset = 0;
689
break;
690
case CPY_XML:
691
sfprintf(sfstdout, "<METHOD>flat</>\n");
692
sfprintf(sfstdout, "<FLAT>\n");
693
sfprintf(op, "%s<NAME>%s</>\n", INDENT(lev + 1), field->name);
694
if (state.regress)
695
{
696
stamp = 0x42d9e64b;
697
if (path && (delimiter = strrchr(path, '/')))
698
path = (const char*)delimiter + 1;
699
}
700
sfprintf(op, "%s<DESCRIPTION>converted by %s from copybook %s</>\n", INDENT(lev + 1), error_info.id, path ? path : "standard input");
701
sfprintf(op, "%s<IDENT>@(#)$Id: %s (AT&T Research) %s $</>\n", INDENT(lev + 1), field->name, fmttime("%Y-%m-%d", stamp));
702
sfprintf(sfstdout, "%s<LIBRARY>num_t</>\n", INDENT(lev + 1));
703
if (state.fixed)
704
{
705
sfprintf(sfstdout, "%s<RECORD>\n", INDENT(lev + 1));
706
sfprintf(sfstdout, "%s<FIXED>%I*u</>\n", INDENT(lev + 2), sizeof(state.fixed), state.fixed);
707
sfprintf(sfstdout, "%s</>\n", INDENT(lev + 1));
708
}
709
if (state.text && (state.escape || state.quotebegin))
710
{
711
sfprintf(sfstdout, "%s<PHYSICAL>\n", INDENT(lev + 1));
712
if (state.escape)
713
sfprintf(sfstdout, "%s<ESCAPE>%s</>\n", INDENT(lev + 2), state.escape);
714
if (state.quotebegin)
715
{
716
if (state.quoteend)
717
{
718
sfprintf(sfstdout, "%s<QUOTEBEGIN>%s</>\n", INDENT(lev + 2), state.quotebegin);
719
sfprintf(sfstdout, "%s<QUOTEEND>%s</>\n", INDENT(lev + 2), state.quoteend);
720
}
721
else
722
sfprintf(sfstdout, "%s<QUOTE>%s</>\n", INDENT(lev + 2), state.quotebegin);
723
sfprintf(sfstdout, "%s<QUOTEALL>1</>\n", INDENT(lev + 2));
724
}
725
sfprintf(sfstdout, "%s</>\n", INDENT(lev + 1));
726
}
727
break;
728
}
729
parent = 0;
730
skip = 0;
731
structure = 1;
732
if (next = field->next)
733
levels[++lev] = next->level;
734
while (field = next)
735
{
736
delimiter = (next = field->next) ? state.delimiter : state.terminator;
737
if (field->level == 88)
738
continue;
739
if (!structure)
740
{
741
if (state.output == CPY_XML && !skip)
742
sfprintf(op, "%s</>\n", INDENT(lev));
743
for (i = lev; i > 0 && field->level != levels[i]; i--);
744
if (i > 0)
745
while (lev > i)
746
{
747
lev--;
748
switch (state.output)
749
{
750
case CPY_OFFSETS:
751
parent->total = offset - parent->offset;
752
if (parent->maxdimension)
753
{
754
offset += parent->total * (parent->maxdimension - 1);
755
parent->total *= parent->maxdimension;
756
}
757
if (parent->redefines && parent->redefines->total > parent->total)
758
{
759
offset += parent->redefines->total - parent->total;
760
parent->total = parent->redefines->total;
761
}
762
break;
763
case CPY_XML:
764
sfprintf(op, "%s</>\n", INDENT(lev));
765
break;
766
}
767
parent = parent->parent;
768
}
769
}
770
skip = 0;
771
field->parent = parent;
772
if (structure = field->structure)
773
{
774
if (!next)
775
{
776
if (disc->errorf)
777
(*disc->errorf)(cpy, disc, 2, "%s: empty struct", field->name);
778
cpyclose(cpy);
779
return -1;
780
}
781
parent = field;
782
if ((lev + 1) >= elementsof(levels))
783
{
784
if (disc->errorf)
785
(*disc->errorf)(cpy, disc, 2, "%s: nesting too deep", field->name);
786
cpyclose(cpy);
787
return -1;
788
}
789
levels[lev + 1] = next->level;
790
}
791
if (state.output == CPY_XML)
792
{
793
if (state.sized && state.text && state.variable && field->parent && (field->flags & CPY_number))
794
{
795
i = strlen(field->parent->name);
796
if (!memcmp(field->parent->name, field->name, i) && strmatch(field->name + i, "?(_)(siz|SIZ|LEN|len)*"))
797
{
798
skip = 1;
799
continue;
800
}
801
}
802
sfprintf(op, "%s<FIELD>\n", INDENT(lev));
803
sfprintf(op, "%s<NAME>%s</>\n", INDENT(lev + 1), field->name);
804
if (field->redefines)
805
{
806
sfprintf(op, "%s<UNION>%s</>\n", INDENT(lev + 1), field->redefines->name);
807
structure = 1;
808
}
809
if (field->dimension || field->maxdimension)
810
{
811
sfprintf(op, "%s<ARRAY>\n", INDENT(lev + 1));
812
if (field->dimension)
813
sfprintf(op, "%s<SIZE>%s</>\n", INDENT(lev + 2), field->dimension);
814
if (field->maxdimension)
815
sfprintf(op, "%s<SIZE>%d</>\n", INDENT(lev + 2), field->maxdimension);
816
sfprintf(op, "%s</>\n", INDENT(lev + 1));
817
}
818
if (field->flags & CPY_string)
819
{
820
sfprintf(op, "%s<TYPE>string</>\n", INDENT(lev + 1));
821
sfprintf(op, "%s<PHYSICAL>\n", INDENT(lev + 1));
822
sfprintf(op, "%s<CODESET>%s</>\n", INDENT(lev + 2), state.codeset);
823
}
824
else if (field->flags & (CPY_number|CPY_pointer))
825
{
826
sfprintf(op, "%s<TYPE>", INDENT(lev + 1));
827
if (!(field->flags & CPY_signed))
828
sfprintf(op, "unsigned ");
829
sfprintf(op, "number</>\n");
830
sfprintf(op, "%s<PHYSICAL>\n", INDENT(lev + 1));
831
if (state.text)
832
sfprintf(op, "%s<CODESET>%s</>\n", INDENT(lev + 2), state.codeset);
833
else if (field->flags & CPY_binary)
834
sfprintf(op, "%s<TYPE>%s</>\n", INDENT(lev + 2), state.endian);
835
else
836
{
837
field->width = compwidth(field, field->width);
838
if (type = typename(field))
839
sfprintf(op, "%s<TYPE>%s</>\n", INDENT(lev + 2), type);
840
else
841
{
842
sfprintf(op, "%s<CODESET>%s</>\n", INDENT(lev + 2), state.codeset);
843
sfprintf(op, "%s<FILL>0</>\n", INDENT(lev + 2));
844
}
845
}
846
if (field->fixedpoint)
847
sfprintf(op, "%s<FIXEDPOINT>%d</>\n", INDENT(lev + 2), field->fixedpoint);
848
if (field->flags & CPY_sync)
849
sfprintf(op, "%s<ALIGN>%d</>\n", INDENT(lev + 2), CPY_ALIGN(field->width));
850
}
851
if (field->flags & (CPY_string|CPY_number|CPY_pointer))
852
{
853
if (!state.text)
854
sfprintf(op, "%s<WIDTH>%d</>\n", INDENT(lev + 2), field->width);
855
if (state.sized && field->parent)
856
{
857
if (field->flags & CPY_number)
858
{
859
i = strlen(field->parent->name);
860
if (!memcmp(field->parent->name, field->name, i) && strmatch(field->name + i, "?(_)(siz|SIZ|LEN|len)*"))
861
field->parent->sized = field;
862
}
863
else if (field->parent->sized)
864
{
865
sfprintf(op, "%s<WIDTH>%s</>\n", INDENT(lev + 2), field->parent->sized->name);
866
field->parent->sized = 0;
867
}
868
}
869
if (state.text || state.variable && delimiter == state.terminator)
870
sfprintf(op, "%s<DELIMITER>%s</>\n", INDENT(lev + 2), delimiter);
871
sfprintf(op, "%s</>\n", INDENT(lev + 1));
872
}
873
}
874
else
875
{
876
if (field->redefines)
877
offset = field->redefines->offset;
878
c = '0';
879
if (field->flags & CPY_number)
880
{
881
c += field->comp;
882
field->width = compwidth(field, field->width);
883
}
884
width = field->width;
885
if (field->flags & CPY_sync)
886
{
887
i = CPY_ALIGN(width);
888
if (j = offset & (i - 1))
889
offset += i - j;
890
}
891
if (field->maxdimension)
892
width *= field->maxdimension;
893
if (state.output == CPY_BYTEMASK)
894
for (i = 0; i < width; i++)
895
sfputc(op, c);
896
else
897
{
898
field->offset = offset;
899
offset += width;
900
if (field->structure)
901
{
902
type = "struct";
903
for (member = field->next; member && member->level > field->level; member = member->next)
904
width += member->width * (member->maxdimension ? member->maxdimension : 1);
905
if (field->maxdimension)
906
width *= field->maxdimension;
907
}
908
else if (field->flags & CPY_pointer)
909
type = "pointer";
910
else if (field->flags & CPY_string)
911
type = "string";
912
else if (field->flags & CPY_number)
913
{
914
if (state.text || !(type = typename(field)))
915
type = (field->flags & CPY_signed) ? "number" : "unsigned";
916
}
917
sfprintf(sfstdout, "%s\t%lu\t%u", field->name, field->offset, width);
918
if (field->dimension)
919
sfprintf(sfstdout, "\t%s", field->dimension);
920
else
921
sfprintf(sfstdout, "\t%d", field->maxdimension);
922
sfprintf(sfstdout, "\t%s\n", type);
923
}
924
}
925
lev += structure;
926
}
927
switch (state.output)
928
{
929
case CPY_OFFSETS:
930
while (levels[lev] > 0 && parent)
931
{
932
lev--;
933
parent->total = offset - parent->offset;
934
if (parent->maxdimension)
935
{
936
offset += parent->total * (parent->maxdimension - 1);
937
parent->total *= parent->maxdimension;
938
}
939
if (parent->redefines && parent->redefines->total > parent->total)
940
{
941
offset += parent->redefines->total - parent->total;
942
parent->total = parent->redefines->total;
943
}
944
parent = parent->parent;
945
}
946
sfprintf(sfstdout, "%s\t%lu\t%u\t%u\tstruct\n", ".", offset, 0, 0);
947
break;
948
case CPY_XML:
949
while (levels[lev] > 0)
950
{
951
sfprintf(op, "%s</>\n", INDENT(lev));
952
lev--;
953
}
954
sfprintf(op, "</>\n");
955
break;
956
}
957
}
958
if (state.output == CPY_BYTEMASK)
959
sfputc(op, '\n');
960
lev = sfsync(op);
961
if (cpyclose(cpy))
962
lev = -1;
963
return lev;
964
}
965
966
int
967
main(int argc, char** argv)
968
{
969
char* file;
970
Sfio_t* ip;
971
char* e;
972
int i;
973
int j;
974
Cpydisc_t disc;
975
struct stat st;
976
977
error_info.id = "cpy2dss";
978
state.codeset = "ebcdic-m";
979
state.delimiter = "|";
980
state.endian = "be_t";
981
state.output = CPY_XML;
982
state.quotebegin = "\"";
983
state.sized = 1;
984
state.terminator = "&newline;";
985
for (i = 0; i < elementsof(state.comp); i++)
986
state.comp[i] = i;
987
cpyinit(&disc, errorf);
988
for (;;)
989
{
990
switch (optget(argv, usage))
991
{
992
case 'b':
993
state.output = CPY_BYTEMASK;
994
continue;
995
case 'c':
996
state.codeset = opt_info.arg;
997
continue;
998
case 'C':
999
i = strtol(opt_info.arg, &e, 0);
1000
j = *e ? strtol(e + 1, &e, 0) : 0;
1001
if (i <= 0 || i > 9 || j <= 0 || j > 9 || *e)
1002
error(2, "%s: COMP from:to expected in range 1..9", opt_info.arg);
1003
state.comp[i] = j;
1004
continue;
1005
case 'd':
1006
state.delimiter = opt_info.arg;
1007
continue;
1008
case 'D':
1009
state.terminator = opt_info.arg;
1010
continue;
1011
case 'e':
1012
state.escape = opt_info.arg;
1013
continue;
1014
case 'k':
1015
state.keep = opt_info.num;
1016
continue;
1017
case 'l':
1018
state.endian = "le_t";
1019
continue;
1020
case 'o':
1021
state.output = CPY_OFFSETS;
1022
continue;
1023
case 'r':
1024
state.fixed = opt_info.num;
1025
continue;
1026
case 's':
1027
state.sized = opt_info.num;
1028
continue;
1029
case 't':
1030
state.text = 1;
1031
state.codeset = ccmapname(CC_NATIVE);
1032
continue;
1033
case 'T':
1034
state.regress = opt_info.num;
1035
continue;
1036
case 'v':
1037
state.variable = opt_info.num;
1038
continue;
1039
case '?':
1040
error(ERROR_USAGE|4, "%s", opt_info.arg);
1041
break;
1042
case ':':
1043
error(2, "%s", opt_info.arg);
1044
break;
1045
}
1046
break;
1047
}
1048
argv += opt_info.index;
1049
if (error_info.errors)
1050
error(ERROR_USAGE|4, "%s", optusage(NiL));
1051
if (!state.quotebegin)
1052
state.quotebegin = state.quoteend;
1053
else if (!state.quoteend)
1054
state.quoteend = state.quotebegin;
1055
if (state.quotebegin && state.quoteend && streq(state.quotebegin, state.quoteend))
1056
state.quoteend = 0;
1057
if (!*argv)
1058
cpy2dss(NiL, sfstdin, sfstdout, &disc, time(NiL));
1059
else
1060
while (file = *argv++)
1061
{
1062
if (!stat(file, &st) && (ip = sfopen(NiL, file, "r")))
1063
{
1064
cpy2dss(file, ip, sfstdout, &disc, st.st_mtime);
1065
sfclose(ip);
1066
}
1067
else
1068
error(ERROR_SYSTEM|2, "%s: cannot read", file);
1069
}
1070
return error_info.errors != 0;
1071
}
1072
1073