cpy2dss.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 2003-2011 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* convert copybook to dss flat schema
*/
static const char usage[] =
"[-?\n@(#)$Id: cpy2dss (AT&T Research) 2007-02-20 $\n]"
"[+NAME?cpy2dss - convert copybook to dss flat schema]"
"[+DESCRIPTION?\bcpy2dss\b converts each copybook \afile\a operand to a"
" \bdss\b flat schema file on the standard output. If no \afile\a"
" operands are specified then the standard input is read.]"
"[+?Duplicate structure and field names are disambiguated by appending"
" \b_\b\acount\a to the names, where \acount\a > 1. \bRENAMES\b"
" and level 88 fields are ignored.]"
"[b:bytemask?Output a single line where each character represents the"
" type of the corresponding byte in the physical representation of"
" a copybook record, where \b0\b means \bPIC\b and \an\a means"
" \bCOMP-\b\an\a.]"
"[c:codeset?Set the \bstring\b codeset name.]:[codeset:=ebcdic-m]"
"[C:comp?Convert COMP-\afrom\a to COMP-\ato\a.]:[from::to]"
"[d:delimiter?Set the \b--text\b field delimiter character. XML"
" &\aname\a; and #\adecimal\a; forms are accepted.]:[delimiter:=|]"
"[D:terminator?Set the \b--text\b record terminator character. XML"
" &\aname\a; and #\adecimal\a; forms are"
" accepted.]:[terminator:=&newline;]"
"[e:escape?Set the \b--text\b field escape character. XML"
" &\aname\a; and #\adecimal\a; forms are accepted.]:[delimiter:=\boff\b]"
"[k:keep?Keep original names. Otherwise non-identifier characters are"
" converted to \b_\b.]"
"[l:little-endian|le?Little-endian binary integer encoding.]"
"[o:offsets?Output the name, offset, size, number of elements and type"
" of each member, one per line, on the standard output. Scalar"
" fields have 0 elements.]"
"[q:quote?Set the \b--text\b field quote begin character. If"
" \b--end-quote\b is not specified then it is the same as"
" \b--quote\b. XML &\aname\a; and #\adecimal\a; forms are"
" accepted.]:[quote:=\"]"
"[Q:end-quote?Set the \b--text\b field quote end character. If"
" \b--quote\b is not specified then it is the same as"
" \b--end-quote\b. XML &\aname\a; and #\adecimal\a; forms are"
" accepted.]:[quote:=\"]"
"[r:reclen|record-length?Sets the physical record format to be fixed"
" with a record length of \areclen\a bytes.]#[reclen]"
"[t:text?Generate a field-delimited newline-terminated text schema"
" using the local codeset.]"
"[T:regress?Massage output for regression testing.]"
"[v:variable?If \b--notext\b is on then records are variable length,"
" delimited by the \b--terminator\b character. If \b--text\b is"
" on then the size field \b--sized\b structures is omitted from"
" the output.]"
"\n"
"\n[ file ... ]\n"
"\n"
;
#include <ast.h>
#include <ctype.h>
#include <ccode.h>
#include <dt.h>
#include <ls.h>
#include <tm.h>
#include <error.h>
#define CPY_VERSION 20030220L
#define cpyinit(d,e) (memset(d,0,sizeof(Cpydisc_t)),(d)->version=CPY_VERSION,(d)->errorf=(Error_f)(e))
#define CPY_binary (1<<0)
#define CPY_XML 0
#define CPY_BYTEMASK 1
#define CPY_OFFSETS 2
struct Cpyfield_s
{
char* dimension;
unsigned long offset;
int comp;
int dup;
int level;
int fixedpoint;
int mindimension;
int maxdimension;
int structure;
int width;
int total;
unsigned int flags;
char name[8];
};
typedef struct Cpydisc_s
{
} Cpydisc_t;
typedef struct Cpy_s
{
const char* id;
char* cp;
char* ofile;
int item;
int oline;
int size;
} Cpy_t;
static struct State_s
{
char* codeset;
char* delimiter;
char* endian;
char* escape;
char* quotebegin;
char* quoteend;
char* terminator;
int keep;
int output;
int regress;
int sized;
int text;
int variable;
int comp[10];
} state;
static char empty[] = "\n";
{
if (!(vm = vmopen(Vmdcheap, Vmlast, 0)) || !(cpy = vmnewof(vm, 0, Cpy_t, 1, 0)) || !(cpy->dt = dtnew(vm, &dictdisc, Dtset)))
{
if (vm)
return 0;
}
error_info.line = 0;
return cpy;
}
int
{
return 0;
}
char*
{
register char* s;
register int q;
{
return "";
}
for (;;)
{
{
case '*':
case '\n':
do
{
{
return 0;
}
error_info.line++;
if (q > 72)
continue;
case ' ':
case '\t':
case '\r':
continue;
}
break;
}
q = 0;
for (;;)
{
{
case '\n':
return s;
case ' ':
case '\t':
case '\r':
if (!q)
break;
continue;
case '\'':
q = !q;
continue;
case '.':
if (!q)
{
{
continue;
}
break;
}
continue;
case '-':
continue;
/*FALLTHROUGH*/
case ':':
case '&':
continue;
default:
continue;
}
break;
}
return s;
}
{
register char* s;
register Cpyfield_t* f;
Cpyfield_t* p;
size_t n;
char* e;
int fixedpoint;
int level;
int width;
do
{
return 0;
if (*e)
{
return 0;
}
return 0;
{
return 0;
}
else
e = s;
{
p->dup++;
}
if (!p)
f->dup = 1;
f->structure = 1;
{
if (!strcasecmp(s, "BINARY"))
{
f->structure = 0;
f->flags |= CPY_binary;
}
{
f->structure = 0;
if (*s++ != '_')
f->comp = 1;
else
{
{
continue;
}
}
}
else if (!strcasecmp(s, "DEPENDING"))
{
break;
if (strcasecmp(s, "ON"))
{
continue;
}
break;
{
{
return 0;
}
}
else if (p->dup > 1)
{
{
return 0;
}
}
}
else if (!strcasecmp(s, "INDEXED"))
{
break;
if (strcasecmp(s, "BY"))
{
continue;
}
break;
}
else if (!strcasecmp(s, "IS"))
/*ignore*/;
else if (!strcasecmp(s, "OCCURS"))
{
break;
if (*e)
{
continue;
}
break;
if (!strcasecmp(s, "TO"))
{
break;
if (*e)
{
continue;
}
break;
}
else
f->maxdimension = f->mindimension;
if (strcasecmp(s, "TIMES"))
goto again;
}
{
f->structure = 0;
f->comp = 3;
}
{
f->structure = 0;
break;
fixedpoint = width = 0;
for (;;)
{
switch (*s++)
{
case 0:
break;
case 'S':
case 's':
case '-':
f->flags |= CPY_signed;
continue;
case 'V':
case 'v':
case '.':
fixedpoint = 1;
continue;
case '9':
f->flags |= CPY_number;
width++;
continue;
case 'X':
case 'x':
f->flags |= CPY_string;
width++;
continue;
case '(':
width = 0;
n = (int)strtol(s, &e, 10);
if (*e == ')')
e++;
s = e;
f->width += n;
if (fixedpoint)
{
fixedpoint = 0;
f->fixedpoint = n;
}
continue;
default:
break;
}
break;
}
if (width)
{
if (fixedpoint)
f->fixedpoint = width;
}
}
else if (!strcasecmp(s, "POINTER"))
{
f->structure = 0;
f->flags |= CPY_pointer;
f->width = 4;
s += 7;
}
else if (!strcasecmp(s, "REDEFINES"))
{
{
return 0;
}
e = s;
if (!(f->redefines = p))
{
return 0;
}
}
else if (!strcasecmp(s, "USAGE"))
f->structure = 0;
{
f->structure = 0;
break;
}
}
return f;
}
static int
{
{
case 0:
if (field->fixedpoint)
width++;
width++;
break;
case 1:
case 5:
if (width <= 2)
width = 1;
else if (width <= 4)
width = 2;
else if (width <= 9)
width = 4;
else
width = 8;
break;
case 3:
break;
}
return width;
}
static char*
{
char* type;
type = "unsigned char*";
else
{
case 1:
type = "be_t";
break;
case 2:
type = "ibm_t";
break;
case 3:
type = "bcd_t";
break;
case 5:
type = "le_t";
break;
default:
type = 0;
break;
}
return type;
}
int
{
char* delimiter;
char* type;
unsigned long offset;
long n;
int c;
int i;
int j;
int lev;
int skip;
int structure;
int width;
int levels[256];
return -1;
{
member = 0;
if (i)
{
if (!member && (i = strlen(parent->name)) && !memcmp(parent->name, next->name, i) && strmatch(next->name + i, "?(_)(siz|SIZ|LEN|len)*"))
}
{
else
{
{
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);
}
}
}
{
case CPY_OFFSETS:
offset = 0;
break;
case CPY_XML:
{
stamp = 0x42d9e64b;
}
sfprintf(op, "%s<DESCRIPTION>converted by %s from copybook %s</>\n", INDENT(lev + 1), error_info.id, path ? path : "standard input");
sfprintf(op, "%s<IDENT>@(#)$Id: %s (AT&T Research) %s $</>\n", INDENT(lev + 1), field->name, fmttime("%Y-%m-%d", stamp));
{
}
{
if (state.quotebegin)
{
{
}
else
}
}
break;
}
parent = 0;
skip = 0;
structure = 1;
{
continue;
if (!structure)
{
if (i > 0)
while (lev > i)
{
lev--;
{
case CPY_OFFSETS:
if (parent->maxdimension)
{
}
{
}
break;
case CPY_XML:
break;
}
}
}
skip = 0;
{
if (!next)
{
return -1;
}
{
return -1;
}
}
{
{
if (!memcmp(field->parent->name, field->name, i) && strmatch(field->name + i, "?(_)(siz|SIZ|LEN|len)*"))
{
skip = 1;
continue;
}
}
{
structure = 1;
}
{
if (field->maxdimension)
}
{
}
{
else
{
else
{
}
}
if (field->fixedpoint)
}
{
{
{
if (!memcmp(field->parent->name, field->name, i) && strmatch(field->name + i, "?(_)(siz|SIZ|LEN|len)*"))
}
{
}
}
}
}
else
{
c = '0';
{
}
{
if (j = offset & (i - 1))
offset += i - j;
}
if (field->maxdimension)
for (i = 0; i < width; i++)
else
{
{
type = "struct";
if (field->maxdimension)
}
type = "pointer";
type = "string";
{
}
else
}
}
}
{
case CPY_OFFSETS:
{
lev--;
if (parent->maxdimension)
{
}
{
}
}
break;
case CPY_XML:
{
lev--;
}
break;
}
}
lev = -1;
return lev;
}
int
{
char* file;
char* e;
int i;
int j;
for (;;)
{
{
case 'b':
continue;
case 'c':
continue;
case 'C':
j = *e ? strtol(e + 1, &e, 0) : 0;
if (i <= 0 || i > 9 || j <= 0 || j > 9 || *e)
continue;
case 'd':
continue;
case 'D':
continue;
case 'e':
continue;
case 'k':
continue;
case 'l':
continue;
case 'o':
continue;
case 'r':
continue;
case 's':
continue;
case 't':
continue;
case 'T':
continue;
case 'v':
continue;
case '?':
break;
case ':':
break;
}
break;
}
if (error_info.errors)
if (!state.quotebegin)
if (!*argv)
else
{
{
}
else
}
return error_info.errors != 0;
}