Overhaul how xundump keeps track of current object

Factor tracking of cur_type, cur_obj, cur_id and cur_is_blank into a
set of functions.  They replace getobj().  While there, improve some
error messages.
This commit is contained in:
Markus Armbruster 2011-05-07 17:30:44 +02:00
parent 465c0c8587
commit 63f972d31c

View file

@ -67,13 +67,15 @@
static char *fname; /* Name of file being read */ static char *fname; /* Name of file being read */
static int lineno; /* Current line number */ static int lineno; /* Current line number */
static int human; /* Reading human-readable syntax? */
static int ellipsis; /* Header ended with ...? */
static int is_partial; /* Is input split into parts? */
static int cur_type; /* Current table's file type */ static int cur_type; /* Current table's file type */
static void *cur_obj; /* The object being read into */ static void *cur_obj; /* The object being read into */
static int cur_id; /* and its index in the table */ static int cur_id; /* and its index in the table */
static int cur_obj_is_blank; static int cur_obj_is_blank;
static int human; /* Reading human-readable syntax? */
static int ellipsis; /* Header ended with ...? */
static int is_partial; /* Is input split into parts? */
static int nflds; /* #fields in input records */ static int nflds; /* #fields in input records */
static struct castr **fldca; /* Map field number to selector */ static struct castr **fldca; /* Map field number to selector */
static int *fldidx; /* Map field number to index */ static int *fldidx; /* Map field number to index */
@ -110,6 +112,95 @@ gripe(char *fmt, ...)
return -1; return -1;
} }
/* Make TYPE the current table. */
static void
tbl_start(int type)
{
cur_type = type;
cur_id = -1;
cur_obj = NULL;
}
/* End the current table. */
static void
tbl_end(void)
{
tbl_start(EF_BAD);
}
/*
* Seek to current table's ID-th record.
* ID must be acceptable.
* Store it in cur_obj, and set cur_id and cur_obj_is_blank accordingly.
* Return 0 on success, -1 on failure.
*/
static int
tbl_seek(int id)
{
struct empfile *ep = &empfile[cur_type];
cur_obj_is_blank = id >= ep->fids;
if (id >= ef_nelem(cur_type)) {
if (!ef_ensure_space(cur_type, id, 1))
return gripe("Can't put ID %d into table %s", id, ep->name);
}
cur_obj = ef_ptr(cur_type, id);
if (CANT_HAPPEN(!cur_obj))
return -1;
cur_id = id;
return 0;
}
/*
* Get the next object.
* Must not have a record index.
* Store it in cur_obj, and set cur_id and cur_obj_is_blank accordingly.
* Return 0 on success, -1 on failure.
*/
static int
tbl_next_obj(void)
{
int max_id = ef_id_limit(cur_type);
if (cur_id >= max_id)
return gripe("Too many rows");
return tbl_seek(cur_id + 1);
}
/*
* Get the next object, it has record index ID.
* Store it in cur_obj, and set cur_id and cur_obj_is_blank accordingly.
* Return 0 on success, -1 on failure.
*/
static int
tbl_skip_to_obj(int id)
{
int max_id;
if (id < 0)
return gripe("Field %d must be >= 0", 1);
max_id = ef_id_limit(cur_type);
if (id > max_id)
return gripe("Field %d must be <= %d", 1, max_id);
if (tbl_seek(id) < 0)
return -1;
return 0;
}
/*
* Finish table part.
* If the table has variable length, truncate it.
*/
static void
tbl_part_done(void)
{
cur_id = -1;
cur_obj = NULL;
}
/* /*
* Read and ignore field separators from FP. * Read and ignore field separators from FP.
* Return first character that is not a field separator. * Return first character that is not a field separator.
@ -478,36 +569,6 @@ fldval_must_match(int fldno)
|| fldidx[fldno] < cafldspp[i]; || fldidx[fldno] < cafldspp[i];
} }
/*
* Get the current object.
* Store it in cur_obj, and set cur_obj_is_blank accordingly.
* Return cur_obj, which is null on error.
*/
static void *
getobj(void)
{
struct empfile *ep = &empfile[cur_type];
int max_id;
if (!cur_obj) {
cur_obj_is_blank = cur_id >= ep->fids;
if (cur_obj_is_blank) {
max_id = ef_id_limit(cur_type);
if (cur_id > max_id)
gripe("Can't put ID %d into table %s, it holds only 0..%d",
cur_id, ep->name, max_id);
else if (!ef_ensure_space(cur_type, cur_id, 1))
gripe("Can't put ID %d into table %s",
cur_id, ep->name);
else
cur_obj = ef_ptr(cur_type, cur_id);
} else
cur_obj = ef_ptr(cur_type, cur_id);
}
return cur_obj;
}
/* /*
* Set value of field FLDNO in current object to DBL. * Set value of field FLDNO in current object to DBL.
* Return 1 on success, -1 on error. * Return 1 on success, -1 on error.
@ -516,7 +577,7 @@ static int
setnum(int fldno, double dbl) setnum(int fldno, double dbl)
{ {
struct castr *ca; struct castr *ca;
int idx; int next_id, idx;
char *memb_ptr; char *memb_ptr;
double old, new; double old, new;
@ -524,18 +585,20 @@ setnum(int fldno, double dbl)
if (!ca) if (!ca)
return -1; return -1;
/* if (fldno == 0) {
* If this is the record index, put it into cur_id. if (ca->ca_table == cur_type) {
*/ /* Got record index */
if (fldno == 0 && ca->ca_table == cur_type) { next_id = (int)dbl;
if (dbl < 0 || (int)dbl != dbl) if (next_id != dbl)
return gripe("Field %d can't hold this value", fldno + 1); return gripe("Field %d can't hold this value", fldno + 1);
cur_id = (int)dbl; if (tbl_skip_to_obj(next_id) < 0)
return -1;
} else {
if (tbl_next_obj() < 0)
return -1;
}
} }
memb_ptr = cur_obj;
memb_ptr = getobj();
if (!memb_ptr)
return -1;
memb_ptr += ca->ca_off; memb_ptr += ca->ca_off;
switch (ca->ca_type) { switch (ca->ca_type) {
@ -624,9 +687,11 @@ setstr(int fldno, char *str)
if (!ca) if (!ca)
return -1; return -1;
memb_ptr = getobj(); if (fldno == 0) {
if (!memb_ptr) if (tbl_next_obj() < 0)
return -1; return -1;
}
memb_ptr = cur_obj;
memb_ptr += ca->ca_off; memb_ptr += ca->ca_off;
must_match = fldval_must_match(fldno); must_match = fldval_must_match(fldno);
@ -883,6 +948,7 @@ xufooter(FILE *fp, struct castr ca[], int recs)
} }
if (skipfs(fp) != '\n') if (skipfs(fp) != '\n')
return gripe("Junk after table footer"); return gripe("Junk after table footer");
tbl_part_done();
lineno++; lineno++;
for (i = 0; ca[i].ca_name; i++) { for (i = 0; ca[i].ca_name; i++) {
@ -928,10 +994,11 @@ xundump(FILE *fp, char *file, int *plno, int expected_table)
fldidx = malloc(nf * sizeof(*fldidx)); fldidx = malloc(nf * sizeof(*fldidx));
caflds = malloc(nca * sizeof(*caflds)); caflds = malloc(nca * sizeof(*caflds));
cafldspp = calloc(nca, sizeof(*cafldspp)); cafldspp = calloc(nca, sizeof(*cafldspp));
cur_type = type;
tbl_start(type);
if (xutail(fp, ca) < 0) if (xutail(fp, ca) < 0)
type = EF_BAD; type = EF_BAD;
tbl_end();
free(cafldspp); free(cafldspp);
free(caflds); free(caflds);
@ -989,8 +1056,6 @@ xubody(FILE *fp)
if (ch == '/') if (ch == '/')
break; break;
ungetc(ch, fp); ungetc(ch, fp);
cur_obj = NULL;
cur_id = i;
if (xuflds(fp, xufld) < 0) if (xuflds(fp, xufld) < 0)
return -1; return -1;
maxid = MAX(maxid, cur_id + 1); maxid = MAX(maxid, cur_id + 1);