diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-10-09 09:13:34 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-10-09 09:17:47 +0300 |
commit | bc62092ab628f78fc848ec2da3bfcbba495bcdaa (patch) | |
tree | 2c5eac6485d651685901663fde0efa099b228be4 /src | |
parent | eacef7351b01c2e784b4538102eb371289e5aa54 (diff) | |
download | gdbm-bc62092ab628f78fc848ec2da3bfcbba495bcdaa.tar.gz gdbm-bc62092ab628f78fc848ec2da3bfcbba495bcdaa.tar.bz2 |
Implement tagged structure initializers.
* NEWS: Document changes.
* doc/gdbm.texi: Document changes.
* src/datconv.c (datum_scan_tag): Implement tagged structure
initialization.
* src/gdbmtool.c (kvlist_free): Made extern.
(kvlist_find): New function.
* src/gdbmtool.h (kvlist_find, kvlist_free)
(dsegm_list_find): New protos.
(dsegm_free_list): Rename to dsegm_list_free. All uses changed.
* src/gram.y: Forbid duplicate tags in kvlist.
Diffstat (limited to 'src')
-rw-r--r-- | src/datconv.c | 181 | ||||
-rw-r--r-- | src/gdbmtool.c | 11 | ||||
-rw-r--r-- | src/gdbmtool.h | 5 | ||||
-rw-r--r-- | src/gram.y | 13 |
4 files changed, 152 insertions, 58 deletions
diff --git a/src/datconv.c b/src/datconv.c index 8b3b65c..295598d 100644 --- a/src/datconv.c +++ b/src/datconv.c @@ -202,7 +202,7 @@ dsegm_new_field (struct datadef *type, char *id, int dim) } void -dsegm_free_list (struct dsegm *dp) +dsegm_list_free (struct dsegm *dp) { while (dp) { @@ -212,6 +212,16 @@ dsegm_free_list (struct dsegm *dp) } } +struct dsegm * +dsegm_list_find (struct dsegm *dp, char const *name) +{ + for (; dp; dp = dp->next) + if (dp->type == FDEF_FLD && dp->v.field.name && + strcmp (dp->v.field.name, name) == 0) + break; + return dp; +} + void datum_format (FILE *fp, datum const *dat, struct dsegm *ds) { @@ -312,11 +322,63 @@ xd_store (struct xdatum *xd, void *val, size_t size) } static int -datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) +dsconv (struct xdatum *xd, struct dsegm *ds, struct kvpair *kv) { - struct xdatum xd; int i; + int err = 0; struct slist *s; + + if (!ds->v.field.type->scan) + abort (); + + if (kv->type == KV_STRING && ds->v.field.dim > 1) + { + /* If a char[] value was supplied as a quoted string. + convert it to list for further processing */ + if (ds->v.field.type->size == 1) + { + struct slist *head = slist_new_l (kv->val.s, 1); + struct slist *tail = head; + char *s; + for (s = kv->val.s + 1; *s; s++) + slist_insert (&tail, slist_new_l (s, 1)); + free (kv->val.s); + kv->val.l = head; + kv->type = KV_LIST; + } + } + + switch (kv->type) + { + case KV_STRING: + err = ds->v.field.type->scan (xd, kv->val.s); + if (err) + lerror (&kv->loc, _("cannot convert")); + break; + + case KV_LIST: + for (i = 0, s = kv->val.l; i < ds->v.field.dim && s; i++, s = s->next) + { + err = ds->v.field.type->scan (xd, s->str); + if (err) + { + lerror (&kv->loc, _("cannot convert value #%d: %s"), i, s->str); + break; + } + } + if (s) + { + lerror (&kv->loc, "surplus initializers ignored"); + err = 1; + } + } + return err; +} + +static int +datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) +{ + struct xdatum xd; int err = 0; memset (&xd, 0, sizeof (xd)); @@ -334,53 +396,7 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) switch (ds->type) { case FDEF_FLD: - if (!ds->v.field.type->scan) - abort (); - - if (kv->type == KV_STRING && ds->v.field.dim > 1) - { - /* If a char[] value was supplied as a quoted string. - convert it to list for further processing */ - if (ds->v.field.type->size == 1) - { - struct slist *head = slist_new_l (kv->val.s, 1); - struct slist *tail = head; - char *s; - for (s = kv->val.s + 1; *s; s++) - slist_insert (&tail, slist_new_l (s, 1)); - free (kv->val.s); - kv->val.l = head; - kv->type = KV_LIST; - } - } - - switch (kv->type) - { - case KV_STRING: - err = ds->v.field.type->scan (&xd, kv->val.s); - if (err) - lerror (&kv->loc, _("cannot convert")); - break; - - case KV_LIST: - for (i = 0, s = kv->val.l; i < ds->v.field.dim && s; - i++, s = s->next) - { - err = ds->v.field.type->scan (&xd, s->str); - if (err) - { - lerror (&kv->loc, - _("cannot convert value #%d: %s"), - i, s->str); - break; - } - } - if (s) - { - lerror (&kv->loc, "surplus initializers ignored"); - err = 1; - } - } + err = dsconv (&xd, ds, kv); kv = kv->next; break; @@ -409,10 +425,69 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) } static int -datum_scan_tag (datum *dat, struct dsegm *ds, struct kvpair *kv) +datum_scan_tag (datum *dat, struct dsegm *ds, struct kvpair *kvlist) { - lerror (&kv->loc, "tagged values are not yet supported"); - return 1; + struct xdatum xd; + int err = 0; + struct kvpair *kv; + + /* Check keywords for consistency */ + for (kv = kvlist; kv; kv = kv->next) + { + if (!kv->key) + { + lerror (&kv->loc, + _("mixing tagged and untagged values is not allowed")); + return 1; + } + if (!dsegm_list_find (ds, kv->key)) + { + lerror (&kv->loc, _("%s: no such field in datum"), kv->key); + return 1; + } + } + + /* Initialize datum */ + memset (&xd, 0, sizeof (xd)); + + for (; err == 0 && ds; ds = ds->next) + { + switch (ds->type) + { + case FDEF_FLD: + kv = kvlist_find (kvlist, ds->v.field.name); + if (kv) + err = dsconv (&xd, ds, kv); + else + { + size_t sz = ds->v.field.type->size * ds->v.field.dim; + xd_expand (&xd, xd.off + sz); + xd.off += sz; + } + break; + + case FDEF_OFF: + xd_expand (&xd, ds->v.n); + xd.off = ds->v.n; + break; + + case FDEF_PAD: + xd_expand (&xd, xd.off + ds->v.n); + xd.off += ds->v.n; + break; + } + } + + if (err) + { + free (xd.dptr); + return 1; + } + + dat->dptr = xd.dptr; + dat->dsize = xd.dsize; + + return 0; } int diff --git a/src/gdbmtool.c b/src/gdbmtool.c index ceffaef..8ecffd0 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -1673,7 +1673,7 @@ kvpair_list (struct locus *loc, struct slist *s) return p; } -static void +void kvlist_free (struct kvpair *kvp) { while (kvp) @@ -1695,6 +1695,15 @@ kvlist_free (struct kvpair *kvp) } } +struct kvpair * +kvlist_find (struct kvpair *kv, char const *tag) +{ + for (; kv; kv = kv->next) + if (kv->key && strcmp (kv->key, tag) == 0) + break; + return kv; +} + int gdbmarg_free (struct gdbmarg *arg) { diff --git a/src/gdbmtool.h b/src/gdbmtool.h index 0bd3a81..73bbb77 100644 --- a/src/gdbmtool.h +++ b/src/gdbmtool.h @@ -207,6 +207,8 @@ struct kvpair struct kvpair *kvpair_string (struct locus *loc, char *val); struct kvpair *kvpair_list (struct locus *loc, struct slist *s); +struct kvpair *kvlist_find (struct kvpair *kv, char const *tag); +void kvlist_free (struct kvpair *kvp); #define GDBM_ARG_STRING 0 @@ -304,7 +306,8 @@ struct dsegm struct dsegm *dsegm_new (int type); struct dsegm *dsegm_new_field (struct datadef *type, char *id, int dim); -void dsegm_free_list (struct dsegm *dp); +void dsegm_list_free (struct dsegm *dp); +struct dsegm *dsegm_list_find (struct dsegm *dp, char const *name); #define DS_KEY 0 #define DS_CONTENT 1 @@ -148,6 +148,13 @@ kvlist : kvpair } | kvlist ',' kvpair { + if (kvlist_find ($1.head, $3->key)) + { + lerror (&@3, _("duplicate tag: %s"), $3->key); + kvlist_free ($1.head); + $1.head = $1.tail = NULL; + YYERROR; + } $1.tail->next = $3; $1.tail = $3; $$ = $1; @@ -191,7 +198,7 @@ string : T_IDENT defn : T_DEF defid { begin_def (); } defbody { end_def (); - dsegm_free_list (dsdef[$2]); + dsegm_list_free (dsdef[$2]); dsdef[$2] = $4; } ; @@ -299,7 +306,7 @@ asgn : T_IDENT default: lerror (&@1, _("unexpected error setting %s: %d"), $1, rc); } - free($1); + free ($1); } | T_IDENT '=' string { @@ -349,7 +356,7 @@ var : T_IDENT lerror (&@1, _("%s: variable cannot be unset"), $1); break; } - free($1); + free ($1); } ; |