diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-05-13 06:27:44 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-05-13 06:27:44 +0000 |
commit | 1638ed6202b77b521214128189dc4aacdb5fe098 (patch) | |
tree | 2e82fd4a16bef6f4d29bf11b4b4b62e7fa9de28f /src | |
parent | 4785154fda6411a384a4ead5abb18c22bb77a8f0 (diff) | |
download | gdbm-1638ed6202b77b521214128189dc4aacdb5fe098.tar.gz gdbm-1638ed6202b77b521214128189dc4aacdb5fe098.tar.bz2 |
Handle structured key and content data in gdbmtool.
* src/datconv.c: New file.
* src/Makefile.am (gdbmtool_SOURCES): Add datconv.c.
* src/gdbmtool.h (slist, kvpair): New structures.
(gdbmarg): Keep various types of data depending on the
value of the type member.
(slist_new, slist_free)
(kvpair_string, kvpair_list): New protos.
(gdbmarg_new): Remove.
(gdbmarg_string, gdbmarg_datum)
(gdbmarg_kvpair, gdbmarg_free)
(gdbmarg_destroy): New protos.
(xd_expand, xd_store, datadef_locate): New protos.
(field, dsegm): New structs.
(dsegm_new, dsegm_new_field, dsegm_free_list): New protos.
* src/gdbmtool.c: Rewrite.
* src/gram.y: Change grammar to allow for defining key and
content structure and for supplying structured data as arguments
to fetch, store and similar functions.
* src/lex.l: Handle new token types.
* tests/dtload.c (main): Fix parser.
* tests/gtload.c: Likewise.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/datconv.c | 385 | ||||
-rw-r--r-- | src/gdbmtool.c | 448 | ||||
-rw-r--r-- | src/gdbmtool.h | 97 | ||||
-rw-r--r-- | src/gram.y | 154 | ||||
-rw-r--r-- | src/lex.l | 73 |
6 files changed, 1022 insertions, 136 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index d5561ea..795832d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,7 @@ bin_PROGRAMS = gdbmtool gdbm_load gdbm_dump gdbmtool_LDADD = ./libgdbmapp.a ./libgdbm.la gdbmtool_SOURCES = \ + datconv.c\ gram.y\ lex.l\ gdbmtool.h\ diff --git a/src/datconv.c b/src/datconv.c new file mode 100644 index 0000000..2ef64a6 --- /dev/null +++ b/src/datconv.c @@ -0,0 +1,385 @@ +/* This file is part of GDBM, the GNU data base manager. + Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation, + Inc. + + GDBM is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GDBM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GDBM. If not, see <http://www.gnu.org/licenses/>. */ + +#include "gdbmtool.h" + +#define DEFFMT(name, type, fmt) \ +static int \ +name (FILE *fp, void *ptr, int size) \ +{ \ + fprintf (fp, fmt, *(type*) ptr); \ + return size; \ +} + +DEFFMT (f_char, char, "%c") +DEFFMT (f_int, int, "%d") +DEFFMT (f_uint, unsigned, "%u") +DEFFMT (f_long, long, "%ld") +DEFFMT (f_ulong, unsigned long, "%lu") +DEFFMT (f_llong, long long, "%lld") +DEFFMT (f_ullong, unsigned long long, "%llu") +DEFFMT (f_float, float, "%f") +DEFFMT (f_double, double, "%e") + +static int +f_string (FILE *fp, void *ptr, int size) +{ + int sz; + char *s; + + for (sz = 1, s = ptr; *s; s++, sz++) + { + int c; + + if (isprint (*s)) + fputc (*s, fp); + else if ((c = escape (*s))) + fprintf (fp, "\\%c", c); + else + fprintf (fp, "\\%03o", *s); + } + return sz; +} + +static int +f_zstring (FILE *fp, void *ptr, int size) +{ + int sz; + char *s; + + for (sz = 0, s = ptr; sz < size; s++, sz++) + { + int c; + + if (isprint (*s)) + fputc (*s, fp); + else if ((c = escape (*s))) + fprintf (fp, "\\%c", c); + else + fprintf (fp, "\\%03o", *s); + } + return sz; +} + +int +s_char (struct xdatum *xd, char *str) +{ + xd_store (xd, str, 1); + return 0; +} + +#define DEFNSCAN(name, type, temptype, strto) \ +int \ +name (struct xdatum *xd, char *str) \ +{ \ + temptype n; \ + type t; \ + char *p; \ + \ + errno = 0; \ + n = strto (str, &p, 0); \ + if (*p) \ + return 1; \ + if (errno == ERANGE || (t = n) != n) \ + return 1; \ + xd_store (xd, &n, sizeof (n)); \ + return 0; \ +} + +DEFNSCAN(s_int, int, long, strtol) +DEFNSCAN(s_uint, unsigned, unsigned long, strtol) +DEFNSCAN(s_long, long, long, strtoul) +DEFNSCAN(s_ulong, unsigned long, unsigned long, strtoul) +DEFNSCAN(s_llong, long long, long long, strtoll) +DEFNSCAN(s_ullong, unsigned long long, unsigned long long, strtoull) + +int +s_double (struct xdatum *xd, char *str) +{ + double d; + char *p; + + errno = 0; + d = strtod (str, &p); + if (errno || *p) + return 1; + xd_store (xd, &d, sizeof (d)); + return 0; +} + +int +s_float (struct xdatum *xd, char *str) +{ + float d; + char *p; + + errno = 0; + d = strtof (str, &p); + if (errno || *p) + return 1; + xd_store (xd, &d, sizeof (d)); + return 0; +} + +int +s_string (struct xdatum *xd, char *str) +{ + xd_store (xd, str, strlen (str) + 1); + return 0; +} + +int +s_zstring (struct xdatum *xd, char *str) +{ + xd_store (xd, str, strlen (str)); + return 0; +} + +static struct datadef datatab[] = { + { "char", sizeof(char), f_char, s_char }, + { "int", sizeof(int), f_int, s_int }, + { "unsigned", sizeof(unsigned), f_uint, s_uint }, + { "uint", sizeof(unsigned), f_uint, s_uint }, + { "long", sizeof(long), f_long, s_long }, + { "ulong", sizeof(unsigned long), f_ulong, s_ulong }, + { "llong", sizeof(long long), f_llong, s_llong }, + { "ullong", sizeof(unsigned long long), f_ullong, s_ullong }, + { "float", sizeof(float), f_float, s_float }, + { "double", sizeof(double), f_double, s_double }, + { "string", 0, f_string, s_string }, + { "zstring", 0, f_zstring, s_zstring }, + { NULL } +}; + +struct datadef * +datadef_locate (const char *name) +{ + struct datadef *p; + + for (p = datatab; p->name; p++) + if (strcmp (p->name, name) == 0) + return p; + return NULL; +} + +struct dsegm * +dsegm_new (int type) +{ + struct dsegm *p = emalloc (sizeof (*p)); + p->next = NULL; + p->type = type; + return p; +} + +struct dsegm * +dsegm_new_field (struct datadef *type, char *id, int dim) +{ + struct dsegm *p = dsegm_new (FDEF_FLD); + p->v.field.type = type; + p->v.field.name = id; + p->v.field.dim = dim; + return p; +} + +void +dsegm_free_list (struct dsegm *dp) +{ + while (dp) + { + struct dsegm *next = dp->next; + free (dp); + dp = next; + } +} + +void +datum_format (FILE *fp, datum const *dat, struct dsegm *ds, char *delim) +{ + int off = 0; + + if (!ds) + { + fprintf (fp, "%.*s\n", dat->dsize, dat->dptr); + return; + } + + for (; ds && off <= dat->dsize; ds = ds->next) + { + switch (ds->type) + { + case FDEF_FLD: + if (ds->v.field.name) + fprintf (fp, "%s=", ds->v.field.name); + if (ds->v.field.dim > 1) + fprintf (fp, "{ "); + if (ds->v.field.type->format) + { + int i, n; + + for (i = 0; i < ds->v.field.dim; i++) + { + if (i) + fwrite (delim, strlen (delim), 1, fp); + if (off + ds->v.field.type->size > dat->dsize) + { + fprintf (fp, _("(not enough data)")); + off += dat->dsize; + break; + } + else + { + n = ds->v.field.type->format (fp, + (char*) dat->dptr + off, + ds->v.field.type->size ? + ds->v.field.type->size : + dat->dsize - off); + off += n; + } + } + } + if (ds->v.field.dim > 1) + fprintf (fp, " }"); + fwrite (delim, strlen (delim), 1, fp); + break; + + case FDEF_OFF: + off = ds->v.n; + break; + + case FDEF_PAD: + off += ds->v.n; + break; + } + } +} + +struct xdatum +{ + char *dptr; + size_t dsize; + size_t dmax; + int off; +}; + +void +xd_expand (struct xdatum *xd, size_t size) +{ + if (xd->dmax < size) + { + xd->dptr = erealloc (xd->dptr, size); + memset (xd->dptr + xd->dmax, 0, size - xd->dmax); + xd->dmax = size; + } +} + +void +xd_store (struct xdatum *xd, void *val, size_t size) +{ + xd_expand (xd, xd->off + size); + memcpy (xd->dptr + xd->off, val, size); + xd->off += size; + if (xd->off > xd->dsize) + xd->dsize = xd->off; +} + +int +datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) +{ + struct xdatum xd; + int i, n; + struct slist *s; + int err = 0; + + memset (&xd, 0, sizeof (xd)); + + for (; err == 0 && ds && kv; ds = ds->next, kv = kv->next) + { + if (kv->key) + { + parse_error (&kv->loc, + _("mixing tagged and untagged values is not allowed")); + err = 1; + break; + } + + switch (ds->type) + { + case FDEF_FLD: + if (!ds->v.field.type->scan) + abort (); + + switch (kv->type) + { + case KV_STRING: + err = ds->v.field.type->scan (&xd, kv->val.s); + if (err) + parse_error (&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) + { + parse_error (&kv->loc, + _("cannot convert value #%d: %s"), + i, s->str); + break; + } + } + /* FIXME: Warn if (s) -> "extra data" */ + } + 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 +datum_scan_tag (datum *dat, struct dsegm *ds, struct kvpair *kv) +{ + parse_error (&kv->loc, "tagged values are not yet supported"); + return 1; +} + +int +datum_scan (datum *dat, struct dsegm *ds, struct kvpair *kv) +{ + return (kv->key ? datum_scan_tag : datum_scan_notag) (dat, ds, kv); +} diff --git a/src/gdbmtool.c b/src/gdbmtool.c index 82da808..78ffb6e 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -38,8 +38,6 @@ GDBM_FILE gdbm_file = NULL; /* Database to operate upon */ int interactive; /* Are we running in interactive mode? */ datum key_data; /* Current key */ datum return_data; /* Current data */ -int key_z = 1; /* Keys are nul-terminated strings */ -int data_z = 1; /* Data are nul-terminated strings */ int quiet_option = 0; /* Omit usual welcome banner at startup */ #define SIZE_T_MAX ((size_t)-1) @@ -235,6 +233,7 @@ trimnl (char *str) return 0; } +#if 0 void read_from_file (const char *name, int replace) { @@ -273,6 +272,8 @@ read_from_file (const char *name, int replace) for (*p++ = 0; *p && isspace (*p); p++) ; + + FIXME key.dptr = buf; key.dsize = strlen (buf) + key_z; data.dptr = p; @@ -283,6 +284,7 @@ read_from_file (const char *name, int replace) } fclose (fp); } +#endif int get_screen_lines () @@ -333,7 +335,7 @@ get_record_count () struct handler_param { int argc; - char **argv; + struct gdbmarg **argv; FILE *fp; void *data; }; @@ -353,11 +355,7 @@ count_handler (struct handler_param *param) void delete_handler (struct handler_param *param) { - if (key_data.dptr != NULL) - free (key_data.dptr); - key_data.dptr = strdup (param->argv[0]); - key_data.dsize = strlen (param->argv[0]) + key_z; - if (gdbm_delete (gdbm_file, key_data) != 0) + if (gdbm_delete (gdbm_file, param->argv[0]->v.dat) != 0) { if (gdbm_errno == GDBM_ITEM_NOT_FOUND) terror (0, _("Item not found")); @@ -370,14 +368,11 @@ delete_handler (struct handler_param *param) void fetch_handler (struct handler_param *param) { - if (key_data.dptr != NULL) - free (key_data.dptr); - key_data.dptr = strdup (param->argv[0]); - key_data.dsize = strlen (param->argv[0]) + key_z; - return_data = gdbm_fetch (gdbm_file, key_data); + return_data = gdbm_fetch (gdbm_file, param->argv[0]->v.dat); if (return_data.dptr != NULL) { - fprintf (param->fp, "%.*s\n", return_data.dsize, return_data.dptr); + datum_format (param->fp, &return_data, dsdef[DS_CONTENT], ","); + fputc ('\n', param->fp); free (return_data.dptr); } else @@ -388,14 +383,9 @@ fetch_handler (struct handler_param *param) void store_handler (struct handler_param *param) { - datum key; - datum data; - - key.dptr = param->argv[0]; - key.dsize = strlen (param->argv[0]) + key_z; - data.dptr = param->argv[1]; - data.dsize = strlen (param->argv[1]) + data_z; - if (gdbm_store (gdbm_file, key, data, GDBM_REPLACE) != 0) + if (gdbm_store (gdbm_file, + param->argv[0]->v.dat, param->argv[1]->v.dat, + GDBM_REPLACE) != 0) fprintf (stderr, _("Item not inserted.\n")); } @@ -409,9 +399,13 @@ firstkey_handler (struct handler_param *param) key_data = gdbm_firstkey (gdbm_file); if (key_data.dptr != NULL) { - fprintf (param->fp, "%.*s\n", key_data.dsize, key_data.dptr); + datum_format (param->fp, &key_data, dsdef[DS_KEY], ","); + fputc ('\n', param->fp); + return_data = gdbm_fetch (gdbm_file, key_data); - fprintf (param->fp, "%.*s\n", return_data.dsize, return_data.dptr); + datum_format (param->fp, &return_data, dsdef[DS_CONTENT], ","); + fputc ('\n', param->fp); + free (return_data.dptr); } else @@ -422,20 +416,25 @@ firstkey_handler (struct handler_param *param) void nextkey_handler (struct handler_param *param) { - if (param->argv[0]) + if (param->argc == 1) { if (key_data.dptr != NULL) free (key_data.dptr); - key_data.dptr = strdup (param->argv[0]); - key_data.dsize = strlen (param->argv[0]) + key_z; + key_data.dptr = emalloc (param->argv[0]->v.dat.dsize); + key_data.dsize = param->argv[0]->v.dat.dsize; + memcpy (key_data.dptr, param->argv[0]->v.dat.dptr, key_data.dsize); } return_data = gdbm_nextkey (gdbm_file, key_data); if (return_data.dptr != NULL) { key_data = return_data; - fprintf (param->fp, "%.*s\n", key_data.dsize, key_data.dptr); + datum_format (param->fp, &key_data, dsdef[DS_KEY], ","); + fputc ('\n', param->fp); + return_data = gdbm_fetch (gdbm_file, key_data); - fprintf (param->fp, "%.*s\n", return_data.dsize, return_data.dptr); + datum_format (param->fp, &return_data, dsdef[DS_CONTENT], ","); + fputc ('\n', param->fp); + free (return_data.dptr); } else @@ -521,7 +520,7 @@ print_bucket_begin (struct handler_param *param, size_t *exp_count) { int temp; - if (getnum (&temp, param->argv[0], NULL)) + if (getnum (&temp, param->argv[0]->v.string, NULL)) return 1; if (temp >= gdbm_file->header->dir_size / 4) @@ -594,11 +593,8 @@ print_header_handler (struct handler_param *param) void hash_handler (struct handler_param *param) { - datum key; - - key.dptr = param->argv[0]; - key.dsize = strlen (param->argv[0]) + key_z; - fprintf (param->fp, _("hash value = %x. \n"), _gdbm_hash (key)); + fprintf (param->fp, _("hash value = %x. \n"), + _gdbm_hash (param->argv[0]->v.dat)); } /* K - print the bucket cache */ @@ -623,6 +619,8 @@ print_version_handler (struct handler_param *param) fprintf (param->fp, "%s\n", gdbm_version); } +#if 0 +FIXME /* < file [replace] - read entries from file and store */ void read_handler (struct handler_param *param) @@ -630,6 +628,7 @@ read_handler (struct handler_param *param) read_from_file (param->argv[0], param->argv[1] && strcmp (param->argv[1], "replace") == 0); } +#endif /* l - List all entries */ int @@ -656,8 +655,10 @@ list_handler (struct handler_param *param) terror (0, _("cannot fetch data (key %.*s)"), key.dsize, key.dptr); else { - fprintf (param->fp, "%.*s %.*s\n", key.dsize, key.dptr, data.dsize, - data.dptr); + datum_format (param->fp, &key, dsdef[DS_KEY], ","); + fputc (' ', param->fp); + datum_format (param->fp, &data, dsdef[DS_CONTENT], ","); + fputc ('\n', param->fp); free (data.dptr); } free (key.dptr); @@ -685,20 +686,21 @@ export_handler (struct handler_param *param) for (i = 1; i < param->argc; i++) { - if (strcmp (param->argv[i], "truncate") == 0) + if (strcmp (param->argv[i]->v.string, "truncate") == 0) flags = GDBM_NEWDB; - else if (strcmp (param->argv[i], "binary") == 0) + else if (strcmp (param->argv[i]->v.string, "binary") == 0) format = GDBM_DUMP_FMT_BINARY; - else if (strcmp (param->argv[i], "ascii") == 0) + else if (strcmp (param->argv[i]->v.string, "ascii") == 0) format = GDBM_DUMP_FMT_ASCII; else { - syntax_error (_("unrecognized argument: %s"), param->argv[i]); + syntax_error (_("unrecognized argument: %s"), + param->argv[i]->v.string); return; } } - if (gdbm_dump (gdbm_file, param->argv[0], format, flags, 0600)) + if (gdbm_dump (gdbm_file, param->argv[0]->v.string, format, flags, 0600)) { terror (0, _("error dumping database: %s"), gdbm_strerror (gdbm_errno)); } @@ -715,18 +717,20 @@ import_handler (struct handler_param *param) for (i = 1; i < param->argc; i++) { - if (strcmp (param->argv[i], "replace") == 0) + if (strcmp (param->argv[i]->v.string, "replace") == 0) flag = GDBM_REPLACE; - else if (strcmp (param->argv[i], "nometa") == 0) + else if (strcmp (param->argv[i]->v.string, "nometa") == 0) meta_mask = GDBM_META_MASK_MODE | GDBM_META_MASK_OWNER; else { - syntax_error (_("unrecognized argument: %s"), param->argv[i]); + syntax_error (_("unrecognized argument: %s"), + param->argv[i]->v.string); return; } } - if (gdbm_load (&gdbm_file, param->argv[0], flag, meta_mask, &err_line)) + if (gdbm_load (&gdbm_file, param->argv[0]->v.string, flag, + meta_mask, &err_line)) { switch (gdbm_errno) { @@ -758,24 +762,6 @@ void status_handler (struct handler_param *param) { fprintf (param->fp, _("Database file: %s\n"), file_name); - fprintf (param->fp, _("Zero terminated keys: %s\n"), boolstr (key_z)); - fprintf (param->fp, _("Zero terminated data: %s\n"), boolstr (data_z)); -} - -/* z - toggle key nul-termination */ -void -key_z_handler (struct handler_param *param) -{ - key_z = !key_z; - fprintf (param->fp, _("Zero terminated keys: %s\n"), boolstr (key_z)); -} - -/* Z - toggle data nul-termination */ -void -data_z_handler (struct handler_param *param) -{ - data_z = !data_z; - fprintf (param->fp, _("Zero terminated data: %s\n"), boolstr (data_z)); } struct prompt_exp; @@ -874,12 +860,19 @@ void prompt_handler (struct handler_param *param) { free (prompt); - prompt = estrdup (param->argv[0]); + prompt = estrdup (param->argv[0]->v.string); } void help_handler (struct handler_param *param); int help_begin (struct handler_param *param, size_t *exp_count); +struct argdef +{ + char *name; + int type; + int ds; +}; + struct command { char *name; /* Command name */ @@ -887,7 +880,7 @@ struct command int (*begin) (struct handler_param *param, size_t *); void (*handler) (struct handler_param *param); void (*end) (void *data); - char *args[NARGS]; + struct argdef args[NARGS]; char *doc; }; @@ -896,81 +889,96 @@ struct command command_tab[] = { #define S(s) #s, sizeof (#s) - 1 { S(count), NULL, count_handler, NULL, - { NULL, NULL, }, N_("count (number of entries)") }, + { { NULL } }, N_("count (number of entries)") }, { S(delete), NULL, delete_handler, NULL, - { N_("key"), NULL, }, N_("delete") }, + { { N_("key"), ARG_DATUM, DS_KEY }, { NULL } }, N_("delete") }, { S(export), NULL, export_handler, NULL, - { N_("file"), "[truncate]", "[binary|ascii]" }, N_("export") }, + { { N_("file"), ARG_STRING }, + { "[truncate]", ARG_STRING }, + { "[binary|ascii]", ARG_STRING }, + { NULL } }, + N_("export") }, { S(fetch), NULL, fetch_handler, NULL, - { N_("key"), NULL }, N_("fetch") }, + { { N_("key"), ARG_DATUM, DS_KEY }, { NULL } }, N_("fetch") }, { S(import), NULL, import_handler, NULL, - { N_("file"), "[replace]", "[nometa]" }, N_("import") }, + { { N_("file"), ARG_STRING }, + { "[replace]", ARG_STRING }, + { "[nometa]" , ARG_STRING }, + { NULL } }, + N_("import") }, { S(list), list_begin, list_handler, NULL, - { NULL, NULL }, N_("list") }, + { { NULL } }, N_("list") }, { S(next), NULL, nextkey_handler, NULL, - { N_("[key]"), NULL }, N_("nextkey") }, + { { N_("[key]"), ARG_STRING }, + { NULL } }, + N_("nextkey") }, { S(store), NULL, store_handler, NULL, - { N_("key"), N_("data") }, N_("store") }, + { { N_("key"), ARG_DATUM, DS_KEY }, + { N_("data"), ARG_DATUM, DS_CONTENT }, + { NULL } }, + N_("store") }, { S(first), NULL, firstkey_handler, NULL, - { NULL, NULL }, N_("firstkey") }, + { { NULL } }, N_("firstkey") }, +#if 0 + FIXME { S(read), NULL, read_handler, NULL, - { N_("file"), "[replace]" }, + { { N_("file"), ARG_STRING }, + { "[replace]", ARG_STRING }, + { NULL } }, N_("read entries from file and store") }, +#endif { S(reorganize), NULL, reorganize_handler, NULL, - { NULL, NULL, }, N_("reorganize") }, - { S(key-zero), - NULL, key_z_handler, NULL, - { NULL, NULL }, N_("toggle key nul-termination") }, + { { NULL } }, N_("reorganize") }, { S(avail), avail_begin, avail_handler, NULL, - { NULL, NULL, }, N_("print avail list") }, + { { NULL } }, N_("print avail list") }, { S(bucket), print_bucket_begin, print_current_bucket_handler, NULL, - { N_("bucket-number"), NULL, }, N_("print a bucket") }, + { { N_("bucket-number"), ARG_STRING }, + { NULL } }, N_("print a bucket") }, { S(current), print_current_bucket_begin, print_current_bucket_handler, NULL, - { NULL, NULL, }, + { { NULL } }, N_("print current bucket") }, { S(dir), print_dir_begin, print_dir_handler, NULL, - { NULL, NULL, }, N_("print hash directory") }, + { { NULL } }, N_("print hash directory") }, { S(header), print_header_begin , print_header_handler, NULL, - { NULL, NULL, }, N_("print file header") }, + { { NULL } }, N_("print file header") }, { S(hash), NULL, hash_handler, NULL, - { N_("key"), NULL, }, N_("hash value of key") }, + { { N_("key"), ARG_DATUM, DS_KEY }, + { NULL } }, N_("hash value of key") }, { S(cache), print_cache_begin, print_cache_handler, NULL, - { NULL, NULL, }, N_("print the bucket cache") }, + { { NULL } }, N_("print the bucket cache") }, { S(status), NULL, status_handler, NULL, - { NULL, NULL }, N_("print current program status") }, + { { NULL } }, N_("print current program status") }, { S(version), NULL, print_version_handler, NULL, - { NULL, NULL, }, N_("print version of gdbm") }, - { S(data-zero), - NULL, data_z_handler, NULL, - { NULL, NULL }, N_("toggle data nul-termination") }, + { { NULL } }, N_("print version of gdbm") }, { S(help), help_begin, help_handler, NULL, - { NULL, NULL, }, N_("print this help list") }, + { { NULL } }, N_("print this help list") }, { S(prompt), NULL, prompt_handler, NULL, - { N_("text") }, N_("set command prompt") }, + { { N_("text"), ARG_STRING }, + { NULL } }, N_("set command prompt") }, { S(quit), NULL, quit_handler, NULL, - { NULL, NULL, }, N_("quit the program") }, + { { NULL } }, N_("quit the program") }, #undef S { 0 } }; @@ -1015,8 +1023,8 @@ help_handler (struct handler_param *param) n = fprintf (fp, " %s", cmd->name); - for (i = 0; i < NARGS && cmd->args[i]; i++) - n += fprintf (fp, " %s", gettext (cmd->args[i])); + for (i = 0; i < NARGS && cmd->args[i].name; i++) + n += fprintf (fp, " %s", gettext (cmd->args[i].name)); if (n < CMDCOLS) fprintf (fp, "%*.s", CMDCOLS-n, ""); @@ -1086,6 +1094,136 @@ struct gdbm_option optab[] = { #define ARGINC 16 +struct gdbmarg * +gdbmarg_string (char *string) +{ + struct gdbmarg *arg = emalloc (sizeof (*arg)); + arg->next = NULL; + arg->type = ARG_STRING; + arg->ref = 1; + arg->v.string = string; + return arg; +} + +struct gdbmarg * +gdbmarg_datum (datum *dat) +{ + struct gdbmarg *arg = emalloc (sizeof (*arg)); + arg->next = NULL; + arg->type = ARG_DATUM; + arg->ref = 1; + arg->v.dat = *dat; + return arg; +} + +struct gdbmarg * +gdbmarg_kvpair (struct kvpair *kvp) +{ + struct gdbmarg *arg = emalloc (sizeof (*arg)); + arg->next = NULL; + arg->type = ARG_KVPAIR; + arg->ref = 1; + arg->v.kvpair = kvp; + return arg; +} + +struct slist * +slist_new (char *s) +{ + struct slist *lp = emalloc (sizeof (*lp)); + lp->next = NULL; + lp->str = s; +} + +void +slist_free (struct slist *lp) +{ + while (lp) + { + struct slist *next = lp->next; + free (lp->str); + free (lp); + lp = next; + } +} + +struct kvpair * +kvpair_string (struct locus *loc, char *val) +{ + struct kvpair *p = ecalloc (1, sizeof (*p)); + p->type = KV_STRING; + if (loc) + p->loc = *loc; + p->val.s = val; + return p; +} + +struct kvpair * +kvpair_list (struct locus *loc, struct slist *s) +{ + struct kvpair *p = ecalloc (1, sizeof (*p)); + p->type = KV_LIST; + if (loc) + p->loc = *loc; + p->val.l = s; + return p; +} + + +static void +kvlist_free (struct kvpair *kvp) +{ + while (kvp) + { + struct kvpair *next = kvp->next; + free (kvp->key); + switch (kvp->type) + { + case KV_STRING: + free (kvp->val.s); + break; + + case KV_LIST: + slist_free (kvp->val.l); + break; + } + free (kvp); + kvp = next; + } +} + +int +gdbmarg_free (struct gdbmarg *arg) +{ + if (arg && --arg->ref == 0) + { + switch (arg->type) + { + case ARG_STRING: + free (arg->v.string); + break; + + case ARG_KVPAIR: + kvlist_free (arg->v.kvpair); + break; + + case ARG_DATUM: + free (arg->v.dat.dptr); + break; + } + free (arg); + return 0; + } + return 1; +} + +void +gdbmarg_destroy (struct gdbmarg **parg) +{ + if (parg && gdbmarg_free (*parg)) + *parg = NULL; +} + void gdbmarglist_init (struct gdbmarglist *lst, struct gdbmarg *arg) { @@ -1113,25 +1251,83 @@ gdbmarglist_free (struct gdbmarglist *lst) for (arg = lst->head; arg; ) { struct gdbmarg *next = arg->next; - free (arg->string); - free (arg); + gdbmarg_free (arg); arg = next; } } + +struct handler_param param; +size_t argmax; + +void +param_free_argv (struct handler_param *param, int n) +{ + int i; + + for (i = 0; i < n; i++) + gdbmarg_destroy (¶m->argv[i]); + param->argc = 0; +} + +typedef struct gdbmarg *(*coerce_type_t) (struct gdbmarg *arg, + struct argdef *def); struct gdbmarg * -gdbmarg_new (char *string) +coerce_ref (struct gdbmarg *arg, struct argdef *def) { - struct gdbmarg *arg = emalloc (sizeof (*arg)); - arg->next = NULL; - arg->string = string; + ++arg->ref; return arg; } - -struct handler_param param; -size_t argmax; +struct gdbmarg * +coerce_k2d (struct gdbmarg *arg, struct argdef *def) +{ + datum d; + + if (datum_scan (&d, dsdef[def->ds], arg->v.kvpair)) + return NULL; + return gdbmarg_datum (&d); +} + +struct gdbmarg * +coerce_s2d (struct gdbmarg *arg, struct argdef *def) +{ + datum d; + struct kvpair kvp; + + memset (&kvp, 0, sizeof (kvp)); + kvp.type = KV_STRING; + kvp.val.s = arg->v.string; + if (datum_scan (&d, dsdef[def->ds], &kvp)) + return NULL; + return gdbmarg_datum (&d); +} + +#define coerce_fail NULL + +coerce_type_t coerce_tab[ARG_MAX][ARG_MAX] = { + /* s d k */ + /* s */ { coerce_ref, coerce_fail, coerce_fail }, + /* d */ { coerce_s2d, coerce_ref, coerce_k2d }, + /* k */ { coerce_fail, coerce_fail, coerce_ref } +}; + +char *argtypestr[] = { "string", "datum", "k/v pair" }; + +struct gdbmarg * +coerce (struct gdbmarg *arg, struct argdef *def) +{ + if (!coerce_tab[def->type][arg->type]) + { + //FIXME: locus + syntax_error (_("cannot coerce %s to %s"), + argtypestr[arg->type], argtypestr[def->type]); + return NULL; + } + return coerce_tab[def->type][arg->type] (arg, def); +} + int run_command (const char *verb, struct gdbmarglist *arglist) { @@ -1148,8 +1344,8 @@ run_command (const char *verb, struct gdbmarglist *arglist) return 1; arg = arglist ? arglist->head : NULL; - - for (i = 0; cmd->args[i] && arg; i++, arg = arg->next) + + for (i = 0; cmd->args[i].name && arg; i++, arg = arg->next) { if (i >= argmax) { @@ -1157,15 +1353,22 @@ run_command (const char *verb, struct gdbmarglist *arglist) param.argv = erealloc (param.argv, sizeof (param.argv[0]) * argmax); } - param.argv[i] = estrdup (arg->string); + if ((param.argv[i] = coerce (arg, &cmd->args[i])) == NULL) + { + param_free_argv (¶m, i); + return 1; + } } - for (; cmd->args[i]; i++) + for (; cmd->args[i].name; i++) { - char *argname = cmd->args[i]; + char *argname = cmd->args[i].name; + struct gdbmarg *t; + if (*argname == '[') /* Optional argument */ break; + if (!interactive) { syntax_error (_("%s: not enough arguments"), cmd->name); @@ -1183,7 +1386,14 @@ run_command (const char *verb, struct gdbmarglist *arglist) param.argv = erealloc (param.argv, sizeof (param.argv[0]) * argmax); } - param.argv[i] = estrdup (argbuf); + + t = gdbmarg_string (estrdup (argbuf)); + if ((param.argv[i] = coerce (t, &cmd->args[i])) == NULL) + { + gdbmarg_free (t); + param_free_argv (¶m, i); + return 1; + } } if (arg) @@ -1194,6 +1404,12 @@ run_command (const char *verb, struct gdbmarglist *arglist) /* Prepare for calling the handler */ param.argc = i; + if (!param.argv) + { + argmax = ARGINC; + param.argv = ecalloc (argmax, sizeof (param.argv[0])); + } + param.argv[i] = NULL; param.fp = NULL; param.data = NULL; pagfp = NULL; @@ -1227,10 +1443,8 @@ run_command (const char *verb, struct gdbmarglist *arglist) if (pagfp) pclose (pagfp); } - - for (i = 0; i < param.argc; i++) - free (param.argv[i]); - param.argc = 0; |