aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--NEWS23
-rw-r--r--doc/gdbm.texi30
-rw-r--r--src/datconv.c181
-rw-r--r--src/gdbmtool.c11
-rw-r--r--src/gdbmtool.h5
-rw-r--r--src/gram.y13
6 files changed, 199 insertions, 64 deletions
diff --git a/NEWS b/NEWS
index cb1ee4e..c815aff 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,26 @@
-GNU dbm NEWS -- history of user-visible changes. 2018-10-27
-Copyright (C) 1990-2019 Free Software Foundation, Inc.
+GNU dbm NEWS -- history of user-visible changes. 2020-10-09
+Copyright (C) 1990-2020 Free Software Foundation, Inc.
See the end of file for copying conditions.
Please send gdbm bug reports to <bug-gdbm@gnu.org>.
+Version 1.18.90 (git)
+
+* Pre-read the memory mapped regions on systems that support it.
+
+This speeds up operations on big databases.
+
+* gdbmtool: tagged initialization of structured data
+
+Initializers for structured data can be given in tagged form, e.g.:
+
+ store somekey { status=2, id={a,u,x}, name="foo" }
+
+* Bugfixes:
+
+** Preserve locking type during database reorganization
+
+
Version 1.18.1 - 2018-10-27
* Fix debian bug 910911
@@ -505,7 +522,7 @@ Version 0.9
----------------------------------------------------------------------
Copyright information:
-Copyright (C) 1990-2017 Free Software Foundation, Inc.
+Copyright (C) 1990-2020 Free Software Foundation, Inc.
Permission is granted to anyone to make or distribute verbatim copies
of this document as received, in any medium, provided that the
diff --git a/doc/gdbm.texi b/doc/gdbm.texi
index 1b63d0b..43fb2a2 100644
--- a/doc/gdbm.texi
+++ b/doc/gdbm.texi
@@ -2674,11 +2674,35 @@ status=2,id=@{ a, u, x @},name="quux"
@end example
To supply a structured datum as an argument to a @command{gdbmtool}
-command, use the same notation, but without field names, e.g.:
+command, use the same notation, e.g.:
@example
-gdbmtool> hash @{ 2, @{a,u,x@}, "quux" @}
-hash value = 13089969.
+gdbmtool> store newkey @{ status=2, id=@{a,u,x@}, name="quux" @}
+@end example
+
+The order in which the fields are listed is not significant. The
+above command can as well be written as:
+
+@example
+gdbmtool> store newkey @{ id=@{a,u,x@}, status=2, name="quux" @}
+@end example
+
+You are not required to supply all defined fields. Any number of them
+can be omitted, provided that at least one remains. The omitted
+fields are filled with 0:
+
+@example
+gdbmtool> store newkey @{ name="bar" @}
+gdbmtool> fetch newkey
+status=0,id=@{ ,, @},name=bar
+@end example
+
+Yet another way to supply structured data to a command is by listing
+the value for each field in the order they are defined, without field
+names:
+
+@example
+gdbmtool> store newkey @{ 2, @{a,u,x@}, "quux" @}
@end example
@node startup files
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.