aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-10-09 09:13:34 +0300
committerSergey Poznyakoff <gray@gnu.org>2020-10-09 09:17:47 +0300
commitbc62092ab628f78fc848ec2da3bfcbba495bcdaa (patch)
tree2c5eac6485d651685901663fde0efa099b228be4 /src
parenteacef7351b01c2e784b4538102eb371289e5aa54 (diff)
downloadgdbm-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.c181
-rw-r--r--src/gdbmtool.c11
-rw-r--r--src/gdbmtool.h5
-rw-r--r--src/gram.y13
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
diff --git a/src/gram.y b/src/gram.y
index aa2ee87..17b50c1 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -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);
}
;

Return to:

Send suggestions and report system problems to the System administrator.