aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2013-05-14 16:08:34 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2013-05-14 16:08:34 +0000
commit8cbaa44e2f1b80dd8954a0e06e0bc8a52494237f (patch)
treeacb81d52eed9a1e4f72a02b251b4bfb76691ef25
parent045ec749566683e9a4471a81901b7a3f37066376 (diff)
downloadgdbm-8cbaa44e2f1b80dd8954a0e06e0bc8a52494237f.tar.gz
gdbm-8cbaa44e2f1b80dd8954a0e06e0bc8a52494237f.tar.bz2
Change variable support.
* src/util.c: New file. * src/Makefile.am: Add new files. * src/gdbmtool.c (open_mode): New variable. (terror): Remove. (mkfilename, tildexpand): Move to util.c (opendb): Use open_mode. (import_handler): Likewise. (optab): New option -N (--norc). * src/gdbmtool.h (vparse_error): Rename to vlerror. (parse_error): Rename to lerror. (syntax_error): Rename tp terror. All uses updated. (VAR_ERR_FAILURE): Remove. (VAR_ERR_BADVALUE): New error code. (variable_mode_name): Remove. (mkfilename, tildexpand) (vgetyn, getyn): New protos. * src/lex.l (initialized): New static. (setsource): Set initialized. (vlerror): Print locus only if the lexer has been initialized. * src/var.c: Rewrite.
-rw-r--r--ChangeLog28
-rw-r--r--src/Makefile.am7
-rw-r--r--src/datconv.c8
-rw-r--r--src/gdbmtool.c186
-rw-r--r--src/gdbmtool.h21
-rw-r--r--src/gram.y24
-rw-r--r--src/lex.l23
-rw-r--r--src/util.c127
-rw-r--r--src/var.c140
9 files changed, 340 insertions, 224 deletions
diff --git a/ChangeLog b/ChangeLog
index 0ee3823..1f9d600 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,36 @@
2013-05-14 Sergey Poznyakoff <gray@gnu.org.ua>
+ Change variable handling.
+
+ * src/util.c: New file.
+ * src/Makefile.am: Add new files.
+ * src/gdbmtool.c (open_mode): New variable.
+ (terror): Remove.
+ (mkfilename, tildexpand): Move to util.c
+ (opendb): Use open_mode.
+ (import_handler): Likewise.
+ (optab): New option -N (--norc).
+
+ * src/gdbmtool.h (vparse_error): Rename to vlerror.
+ (parse_error): Rename to lerror.
+ (syntax_error): Rename tp terror.
+ All uses updated.
+ (VAR_ERR_FAILURE): Remove.
+ (VAR_ERR_BADVALUE): New error code.
+ (variable_mode_name): Remove.
+ (mkfilename, tildexpand)
+ (vgetyn, getyn): New protos.
+ * src/lex.l (initialized): New static.
+ (setsource): Set initialized.
+ (vlerror): Print locus only if the lexer has been
+ initialized.
+ * src/var.c: Rewrite.
+
+2013-05-14 Sergey Poznyakoff <gray@gnu.org.ua>
+
Provide "open" and "close" commands; implement new variables.
* src/datconv.c (datum_format): Don't print field delimiter
after the last field.
(dsprint): Bugfix.
* src/gdbmload.c (gdbm_load_from_file): Return GDBM_NO_DBNAME
diff --git a/src/Makefile.am b/src/Makefile.am
index bf2f21e..b8bebde 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,13 +23,13 @@ noinst_HEADERS = \
gdbmconst.h\
gdbmdefs.h\
gettext.h\
proto.h\
systems.h
-EXTRA_DIST = gdbm.h.in
+EXTRA_DIST = gdbm.h.in gram.h
# The libraries
VI_CURRENT = 4
VI_REVISION = 0
VI_AGE = 0
@@ -82,15 +82,14 @@ gdbmtool_LDADD = ./libgdbmapp.a ./libgdbm.la
gdbmtool_SOURCES = \
datconv.c\
gram.y\
lex.l\
gdbmtool.h\
gdbmtool.c\
- var.c
-
-EXTRA_DIST = gram.h
+ var.c\
+ util.c
AM_YFLAGS = -dtv
#AM_LFLAGS = -d
gdbm_load_LDADD = ./libgdbmapp.a ./libgdbm.la
gdbm_dump_LDADD = ./libgdbmapp.a ./libgdbm.la
diff --git a/src/datconv.c b/src/datconv.c
index 0178f41..95656db 100644
--- a/src/datconv.c
+++ b/src/datconv.c
@@ -316,13 +316,13 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv)
memset (&xd, 0, sizeof (xd));
for (; err == 0 && ds && kv; ds = ds->next, kv = kv->next)
{
if (kv->key)
{
- parse_error (&kv->loc,
+ lerror (&kv->loc,
_("mixing tagged and untagged values is not allowed"));
err = 1;
break;
}
switch (ds->type)
@@ -333,23 +333,23 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv)
switch (kv->type)
{
case KV_STRING:
err = ds->v.field.type->scan (&xd, kv->val.s);
if (err)
- parse_error (&kv->loc, _("cannot convert"));
+ 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)
{
- parse_error (&kv->loc,
+ lerror (&kv->loc,
_("cannot convert value #%d: %s"),
i, s->str);
break;
}
}
/* FIXME: Warn if (s) -> "extra data" */
@@ -380,13 +380,13 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv)
return 0;
}
static int
datum_scan_tag (datum *dat, struct dsegm *ds, struct kvpair *kv)
{
- parse_error (&kv->loc, "tagged values are not yet supported");
+ lerror (&kv->loc, "tagged values are not yet supported");
return 1;
}
int
datum_scan (datum *dat, struct dsegm *ds, struct kvpair *kv)
{
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index a561bfc..6083edc 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -34,82 +34,19 @@
char *file_name = NULL; /* Database file name */
GDBM_FILE gdbm_file = NULL; /* Database to operate upon */
datum key_data; /* Current key */
datum return_data; /* Current data */
int quiet_option = 0; /* Omit the usual welcome banner at startup */
+int open_mode; /* Default open mode */
#define SIZE_T_MAX ((size_t)-1)
unsigned input_line;
-void
-terror (int code, const char *fmt, ...)
-{
- va_list ap;
- if (!interactive)
- fprintf (stderr, "%s: ", progname);
- va_start (ap, fmt);
- vfprintf (stderr, fmt, ap);
- va_end (ap);
- fputc ('\n', stderr);
- if (code)
- exit (code);
-}
-
-char *
-mkfilename (const char *dir, const char *file, const char *suf)
-{
- char *tmp;
- size_t dirlen = strlen (dir);
- size_t suflen = suf ? strlen (suf) : 0;
- size_t fillen = strlen (file);
- size_t len;
-
- while (dirlen > 0 && dir[dirlen-1] == '/')
- dirlen--;
-
- len = dirlen + (dir[0] ? 1 : 0) + fillen + suflen;
- tmp = emalloc (len + 1);
- memcpy (tmp, dir, dirlen);
- if (dir[0])
- tmp[dirlen++] = '/';
- memcpy (tmp + dirlen, file, fillen);
- if (suf)
- memcpy (tmp + dirlen + fillen, suf, suflen);
- tmp[len] = 0;
- return tmp;
-}
-
-char *
-tildexpand (char *s)
-{
- if (s[0] == '~')
- {
- char *p = s + 1;
- size_t len = strcspn (p, "/");
- struct passwd *pw;
-
- if (len == 0)
- pw = getpwuid (getuid ());
- else
- {
- char *user = emalloc (len + 1);
-
- memcpy (user, p, len);
- user[len] = 0;
- pw = getpwnam (user);
- free (user);
- }
- if (pw)
- return mkfilename (pw->pw_dir, p + len + 1, NULL);
- }
- return estrdup (s);
-}
-
static int
opendb (char *dbname)
{
int cache_size;
int block_size;
int flags = 0;
@@ -124,31 +61,34 @@ opendb (char *dbname)
flags |= GDBM_NOLOCK;
if (!variable_is_set ("mmap"))
flags |= GDBM_NOMMAP;
if (variable_is_set ("sync"))
flags |= GDBM_SYNC;
- if (variable_is_set ("readonly"))
- flags = GDBM_READER;
- else if (variable_is_set ("newdb"))
- flags |= GDBM_NEWDB;
- else
- flags |= GDBM_WRCREAT;
+ if (open_mode == GDBM_NEWDB)
+ {
+ if (interactive && variable_is_set ("confirm") &&
+ access (dbname, F_OK) == 0)
+ {
+ if (!getyn (_("database %s already exists; overwrite"), dbname))
+ return 1;
+ }
+ }
- db = gdbm_open (dbname, block_size, flags, 00664, NULL);
+ db = gdbm_open (dbname, block_size, open_mode | flags, 0644, NULL);
if (db == NULL)
{
- syntax_error (_("cannot open database %s: %s"), dbname,
- gdbm_strerror (gdbm_errno));
+ terror (_("cannot open database %s: %s"), dbname,
+ gdbm_strerror (gdbm_errno));
return 1;
}
if (gdbm_setopt (db, GDBM_CACHESIZE, &cache_size, sizeof (int)) ==
-1)
- syntax_error (_("gdbm_setopt failed: %s"),
+ terror (_("gdbm_setopt failed: %s"),
gdbm_strerror (gdbm_errno));
if (gdbm_file)
gdbm_close (gdbm_file);
gdbm_file = db;
@@ -160,13 +100,13 @@ checkdb ()
{
if (!gdbm_file)
{
if (!file_name)
{
file_name = estrdup (GDBMTOOL_DEFFILE);
- syntax_error (_("warning: using default database file %s"),
+ terror (_("warning: using default database file %s"),
file_name);
}
return opendb (file_name);
}
return 0;
}
@@ -225,22 +165,23 @@ _gdbm_avail_list_size (GDBM_FILE dbf, size_t min_size)
/* Traverse the stack. */
while (temp)
{
if (__lseek (dbf, temp, SEEK_SET) != temp)
{
- terror (0, "lseek: %s", strerror (errno));
+ terror ("lseek: %s", strerror (errno));
break;
}
if ((rc = _gdbm_full_read (dbf, av_stk, size)))
{
if (rc == GDBM_FILE_EOF)
- terror (0, "read: %s", gdbm_strerror (rc));
+ terror ("read: %s", gdbm_strerror (rc));
else
- terror (0, "read: %s (%s)", gdbm_strerror (rc), strerror (errno));
+ terror ("read: %s (%s)",
+ gdbm_strerror (rc), strerror (errno));
break;
}
lines += av_stk->count;
if (lines > min_size)
break;
@@ -277,22 +218,22 @@ _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
/* Print the stack. */
while (temp)
{
if (__lseek (dbf, temp, SEEK_SET) != temp)
{
- terror (0, "lseek: %s", strerror (errno));
+ terror ("lseek: %s", strerror (errno));
break;
}
if ((rc = _gdbm_full_read (dbf, av_stk, size)))
{
if (rc == GDBM_FILE_EOF)
- terror (0, "read: %s", gdbm_strerror (rc));
+ terror ("read: %s", gdbm_strerror (rc));
else
- terror (0, "read: %s (%s)", gdbm_strerror (rc), strerror (errno));
+ terror ("read: %s (%s)", gdbm_strerror (rc), strerror (errno));
break;
}
/* Print the block! */
fprintf (fp, _("\nblock = %d\nsize = %d\ncount = %d\n"), temp,
av_stk->size, av_stk->count);
@@ -412,13 +353,13 @@ open_handler (struct handler_param *param)
/* Close database */
void
close_handler (struct handler_param *param)
{
if (!gdbm_file)
- syntax_error (_("nothing to close"));
+ terror (_("nothing to close"));
gdbm_close (gdbm_file);
gdbm_file = NULL;
}
/* count - count items in the database */
@@ -734,13 +675,16 @@ list_handler (struct handler_param *param)
while (key.dptr)
{
datum nextkey = gdbm_nextkey (gdbm_file, key);
data = gdbm_fetch (gdbm_file, key);
if (!data.dptr)
- terror (0, _("cannot fetch data (key %.*s)"), key.dsize, key.dptr);
+ {
+ terror (_("cannot fetch data; the key was:"));
+ datum_format (stderr, &key, dsdef[DS_KEY]);
+ }
else
{
datum_format (param->fp, &key, dsdef[DS_KEY]);
fputc (' ', param->fp);
datum_format (param->fp, &data, dsdef[DS_CONTENT]);
fputc ('\n', param->fp);
@@ -776,21 +720,22 @@ export_handler (struct handler_param *param)
else if (strcmp (param->argv[i]->v.string, "binary") == 0)
format = GDBM_DUMP_FMT_BINARY;
else if (strcmp (param->argv[i]->v.string, "ascii") == 0)
format = GDBM_DUMP_FMT_ASCII;
else
{
- syntax_error (_("unrecognized argument: %s"),
+ terror (_("unrecognized argument: %s"),
param->argv[i]->v.string);
return;
}
}
if (gdbm_dump (gdbm_file, param->argv[0]->v.string, format, flags, 0600))
{
- terror (0, _("error dumping database: %s"), gdbm_strerror (gdbm_errno));
+ terror (_("error dumping database: %s"),
+ gdbm_strerror (gdbm_errno));
}
}
/* import FILE [replace] [nometa] - import from a flat file */
void
import_handler (struct handler_param *param)
@@ -806,29 +751,27 @@ import_handler (struct handler_param *param)
if (strcmp (param->argv[i]->v.string, "replace") == 0)
flag = GDBM_REPLACE;
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"),
+ terror (_("unrecognized argument: %s"),
param->argv[i]->v.string);
return;
}
}
rc = gdbm_load (&gdbm_file, param->argv[0]->v.string, flag,
meta_mask, &err_line);
if (rc && gdbm_errno == GDBM_NO_DBNAME)
{
- const char *varname = variable_mode_name ();
- int t = 1;
+ int t = open_mode;
- variable_set ("newdb", VART_BOOL, &t);
+ open_mode = GDBM_NEWDB;
rc = checkdb ();
- if (varname)
- variable_set (varname, VART_BOOL, &t);
+ open_mode = t;
if (rc)
return;
rc = gdbm_load (&gdbm_file, param->argv[0]->v.string, flag,
meta_mask, &err_line);
@@ -836,30 +779,30 @@ import_handler (struct handler_param *param)
if (rc)
{
switch (gdbm_errno)
{
case GDBM_ERR_FILE_OWNER:
case GDBM_ERR_FILE_MODE:
- terror (0, _("error restoring metadata: %s (%s)"),
- gdbm_strerror (gdbm_errno), strerror (errno));
+ terror (_("error restoring metadata: %s (%s)"),
+ gdbm_strerror (gdbm_errno), strerror (errno));
break;
default:
if (err_line)
- terror (0, "%s:%lu: %s", param->argv[0], err_line,
- gdbm_strerror (gdbm_errno));
+ terror ("%s:%lu: %s", param->argv[0], err_line,
+ gdbm_strerror (gdbm_errno));
else
- terror (0, _("cannot load from %s: %s"), param->argv[0],
- gdbm_strerror (gdbm_errno));
+ terror (_("cannot load from %s: %s"), param->argv[0],
+ gdbm_strerror (gdbm_errno));
}
return;
}
free (file_name);
if (gdbm_setopt (gdbm_file, GDBM_GETDBNAME, &file_name, sizeof (file_name)))
- syntax_error (_("gdbm_setopt failed: %s"), gdbm_strerror (gdbm_errno));
+ terror (_("gdbm_setopt failed: %s"), gdbm_strerror (gdbm_errno));
}
/* status - print current program status */
void
status_handler (struct handler_param *param)
{
@@ -1101,13 +1044,13 @@ command_lookup (const char *str, struct locus *loc, struct command **pcmd)
abort ();
}
}
}
if (state == fcom_init)
- parse_error (loc,
+ lerror (loc,
interactive ? _("Invalid command. Try ? for help.") :
_("Unknown command"));
if (!found)
return T_BOGUS;
*pcmd = found;
@@ -1121,12 +1064,13 @@ struct gdbm_option optab[] = {
{ 'b', "block-size", N_("SIZE"), N_("set block size") },
{ 'c', "cache-size", N_("SIZE"), N_("set cache size") },
{ 'g', NULL, "FILE", NULL, PARSEOPT_HIDDEN },
{ 'l', "no-lock", NULL, N_("disable file locking") },
{ 'm', "no-mmap", NULL, N_("do not use mmap") },
{ 'n', "newdb", NULL, N_("create database") },
+ { 'N', "norc", NULL, N_("do not read .gdbmtoolrc file") },
{ 'r', "read-only", NULL, N_("open database in read-only mode") },
{ 's', "synchronize", NULL, N_("synchronize to disk after each write") },
{ 'q', "quiet", NULL, N_("don't print initial banner") },
{ 0 }
};
@@ -1363,13 +1307,13 @@ char *argtypestr[] = { "string", "datum", "k/v pair" };
struct gdbmarg *
coerce (struct gdbmarg *arg, struct argdef *def)
{
if (!coerce_tab[def->type][arg->type])
{
- parse_error (&arg->loc, _("cannot coerce %s to %s"),
+ lerror (&arg->loc, _("cannot coerce %s to %s"),
argtypestr[arg->type], argtypestr[def->type]);
return NULL;
}
return coerce_tab[def->type][arg->type] (arg, def);
}
@@ -1408,19 +1352,22 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
if (*argname == '[')
/* Optional argument */
break;
if (!interactive)
{
- syntax_error (_("%s: not enough arguments"), cmd->name);
+ terror (_("%s: not enough arguments"), cmd->name);
return 1;
}
printf ("%s? ", argname);
fflush (stdout);
if (fgets (argbuf, sizeof argbuf, stdin) == NULL)
- terror (EXIT_USAGE, _("unexpected eof"));
+ {
+ terror (_("unexpected eof"));
+ exit (EXIT_USAGE);
+ }
trimnl (argbuf);
if (i >= argmax)
{
argmax += ARGINC;
param.argv = erealloc (param.argv,
@@ -1435,13 +1382,13 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
return 1;
}
}
if (arg)
{
- syntax_error (_("%s: too many arguments"), cmd->name);
+ terror (_("%s: too many arguments"), cmd->name);
return 1;
}
/* Prepare for calling the handler */
param.argc = i;
if (!param.argv)
@@ -1462,14 +1409,14 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
{
pagfp = popen (pager, "w");
if (pagfp)
param.fp = pagfp;
else
{
- terror (0, _("cannot run pager `%s': %s"), pager,
- strerror (errno));
+ terror (_("cannot run pager `%s': %s"), pager,
+ strerror (errno));
pager = NULL;
param.fp = stdout;
}
}
else
param.fp = stdout;
@@ -1503,13 +1450,13 @@ source_rcfile ()
char *p = getenv ("HOME");
if (!p)
{
struct passwd *pw = getpwuid (getuid ());
if (!pw)
{
- terror (0, _("cannot find home directory"));
+ terror (_("cannot find home directory"));
return;
}
p = pw->pw_dir;
}
fname = mkfilename (p, GDBMTOOLRC, NULL);
if (access (fname, R_OK) == 0)
@@ -1524,22 +1471,25 @@ source_rcfile ()
int
main (int argc, char *argv[])
{
int intr;
int opt;
int bv;
+ int norc = 0;
set_progname (argv[0]);
#ifdef HAVE_SETLOCALE
setlocale (LC_ALL, "");
#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
sort_commands ();
+
+ variable_set ("open", VART_STRING, "wrcreat");
for (opt = parseopt_first (argc, argv, optab);
opt != EOF;
opt = parseopt_next ())
switch (opt)
{
@@ -1556,19 +1506,21 @@ main (int argc, char *argv[])
case 's':
bv = 1;
variable_set ("sync", VART_BOOL, &bv);
break;
case 'r':
- bv = 1;
- variable_set ("readonly", VART_BOOL, &bv);
+ variable_set ("open", VART_STRING, "readonly");
break;
case 'n':
- bv = 1;
- variable_set ("newdb", VART_BOOL, &bv);
+ variable_set ("open", VART_STRING, "newdb");
+ break;
+
+ case 'N':
+ norc = 1;
break;
case 'c':
variable_set ("cachesize", VART_STRING, optarg);
break;
@@ -1582,21 +1534,26 @@ main (int argc, char *argv[])
case 'q':
quiet_option = 1;
break;
default:
- terror (EXIT_USAGE,
- _("unknown option; try `%s -h' for more info\n"), progname);
+ terror (_("unknown option; try `%s -h' for more info"),
+ progname);
+ exit (EXIT_USAGE);
}
argc -= optind;
argv += optind;
if (argc > 1)
- terror (EXIT_USAGE, _("too many arguments"));
+ {
+ terror (_("too many arguments"));
+ exit (EXIT_USAGE);
+ }
+
if (argc == 1)
file_name = argv[0];
/* Initialize variables. */
intr = isatty (0);
dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
@@ -1608,11 +1565,12 @@ main (int argc, char *argv[])
argmax = 0;
/* Welcome message. */
if (intr && !quiet_option)
printf (_("\nWelcome to the gdbm tool. Type ? for help.\n\n"));
- source_rcfile ();
+ if (!norc)
+ source_rcfile ();
setsource ("-", intr);
return yyparse ();
}
diff --git a/src/gdbmtool.h b/src/gdbmtool.h
index 8c585f0..db18669 100644
--- a/src/gdbmtool.h
+++ b/src/gdbmtool.h
@@ -86,23 +86,24 @@ typedef struct locus gdbm_yyltype_t;
(Loc).beg.file, \
(Loc).beg.line, \
(Loc).beg.col); \
} \
while (0)
-void vparse_error (struct locus *loc, const char *fmt, va_list ap);
-void parse_error (struct locus *loc, const char *fmt, ...);
+void vlerror (struct locus *loc, const char *fmt, va_list ap);
+void lerror (struct locus *loc, const char *fmt, ...);
-void syntax_error (const char *fmt, ...);
+void terror (const char *fmt, ...);
void print_prompt (void);
int setsource (const char *filename, int intr);
extern char *file_name;
extern int interactive;
+extern int open_mode;
#define GDBMTOOLRC ".gdbmtoolrc"
#define GDBMTOOL_DEFFILE "junk.gdbm"
struct slist
@@ -224,22 +225,21 @@ void dsegm_free_list (struct dsegm *dp);
extern struct dsegm *dsdef[];
#define VART_STRING 0
#define VART_BOOL 1
#define VART_INT 2
-#define VAR_OK 0
-#define VAR_ERR_NOTDEF 1
-#define VAR_ERR_BADTYPE 2
-#define VAR_ERR_FAILURE 3
+#define VAR_OK 0
+#define VAR_ERR_NOTDEF 1
+#define VAR_ERR_BADTYPE 2
+#define VAR_ERR_BADVALUE 3
int variable_set (const char *name, int type, void *val);
int variable_get (const char *name, int type, void **val);
int variable_is_set (const char *name);
void variable_print_all (FILE *fp);
-const char *variable_mode_name ();
int unescape (int c);
int escape (int c);
void begin_def (void);
void end_def (void);
@@ -249,7 +249,10 @@ int yyerror (char *s);
int yyparse (void);
void datum_format (FILE *fp, datum const *dat, struct dsegm *ds);
int datum_scan (datum *dat, struct dsegm *ds, struct kvpair *kv);
void dsprint (FILE *fp, int what, struct dsegm *ds);
-
+char *mkfilename (const char *dir, const char *file, const char *suf);
+char *tildexpand (char *s);
+int vgetyn (const char *prompt, va_list ap);
+int getyn (const char *prompt, ...);
diff --git a/src/gram.y b/src/gram.y
index 75c7e86..a54ef0e 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -198,14 +198,14 @@ defid : T_IDENT
if (strcmp ($1, "key") == 0)
$$ = DS_KEY;
else if (strcmp ($1, "content") == 0)
$$ = DS_CONTENT;
else
{
- syntax_error (_("expected \"key\" or \"content\", "
- "but found \"%s\""), $1);
+ terror (_("expected \"key\" or \"content\", "
+ "but found \"%s\""), $1);
YYERROR;
}
}
;
deflist : def
@@ -268,53 +268,57 @@ var : T_IDENT
switch (rc)
{
case VAR_OK:
break;
case VAR_ERR_NOTDEF:
- parse_error (&@1, _("no such variable: %s"), varname);
+ lerror (&@1, _("no such variable: %s"), varname);
break;
case VAR_ERR_BADTYPE:
- parse_error (&@1, _("%s is not a boolean variable"), varname);
+ lerror (&@1, _("%s is not a boolean variable"), varname);
break;
}
free($1);
}
| T_IDENT '=' string
{
int rc = variable_set ($1, VART_STRING, $3);
- free ($3);
switch (rc)
{
case VAR_OK:
break;
case VAR_ERR_NOTDEF:
- parse_error (&@1, _("no such variable: %s"), $1);
+ lerror (&@1, _("no such variable: %s"), $1);
break;
case VAR_ERR_BADTYPE:
- parse_error (&@1, _("%s is not a string variable"), $1);
+ lerror (&@1, _("%s: bad variable type"), $1);
+ break;
+
+ case VAR_ERR_BADVALUE:
+ lerror (&@1, _("%s: value %s is not allowed"), $1, $3);
break;
}
free($1);
+ free ($3);
}
;
%%
void
-syntax_error (const char *fmt, ...)
+terror (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
- vparse_error (&yylloc, fmt, ap);
+ vlerror (&yylloc, fmt, ap);
va_end (ap);
}
int
yyerror (char *s)
{
- syntax_error ("%s", s);
+ terror ("%s", s);
return 0;
}
diff --git a/src/lex.l b/src/lex.l
index dcd9af3..919bbad 100644
--- a/src/lex.l
+++ b/src/lex.l
@@ -71,13 +71,14 @@ struct context /* Input context */
};
static struct context *context_tos;
static ino_t ino;
static dev_t dev;
int interactive; /* Are we running in interactive mode? */
-
+static int initialized;
+
static void
context_push ()
{
struct context *cp = ecalloc (1, sizeof (*cp));
cp->locus = yylloc;
@@ -141,34 +142,34 @@ setsource (const char *name, int intr)
name = "stdin";
}
else
{
if (stat (name, &st))
{
- syntax_error (_("cannot open `%s': %s"), name, strerror (errno));
+ terror (_("cannot open `%s': %s"), name, strerror (errno));
return -1;
}
else if (!S_ISREG (st.st_mode))
{
- syntax_error (_("%s is not a regular file"), name);
+ terror (_("%s is not a regular file"), name);
return -1;
}
cp = findctx (&st);
if (cp)
{
- syntax_error (_("recursive sourcing"));
+ terror (_("recursive sourcing"));
if (cp->parent)
- parse_error (&cp->locus, _("%s already sourced here"), name);
+ lerror (&cp->locus, _("%s already sourced here"), name);
return 1;
}
fp = fopen (name, "r");
if (!fp)
{
- syntax_error (_("cannot open %s for reading: %s"), name,
+ terror (_("cannot open %s for reading: %s"), name,
strerror (errno));
return 1;
}
}
if (yyin)
@@ -182,12 +183,14 @@ setsource (const char *name, int intr)
ino = st.st_ino;
point.file = estrdup (name);
point.line = 1;
point.col = 0;
+ initialized = 1;
+
return 0;
}
%}
%option nounput
@@ -416,32 +419,32 @@ escape (int c)
return p[-1];
}
return 0;
}
void
-vparse_error (struct locus *loc, const char *fmt, va_list ap)
+vlerror (struct locus *loc, const char *fmt, va_list ap)
{
if (!interactive)
fprintf (stderr, "%s: ", progname);
- if (loc)
+ if (initialized && loc && loc->beg.file)
{
YY_LOCATION_PRINT (stderr, *loc);
fprintf (stderr, ": ");
}
vfprintf (stderr, fmt, ap);
fputc ('\n', stderr);
}
void
-parse_error (struct locus *loc, const char *fmt, ...)
+lerror (struct locus *loc, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
- vparse_error (loc, fmt, ap);
+ vlerror (loc, fmt, ap);
va_end (ap);
}
struct prompt_exp;
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..d46325b
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,127 @@
+/* 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"
+#include <pwd.h>
+
+char *
+mkfilename (const char *dir, const char *file, const char *suf)
+{
+ char *tmp;
+ size_t dirlen = strlen (dir);
+ size_t suflen = suf ? strlen (suf) : 0;
+ size_t fillen = strlen (file);
+ size_t len;
+
+ while (dirlen > 0 && dir[dirlen-1] == '/')
+ dirlen--;
+
+ len = dirlen + (dir[0] ? 1 : 0) + fillen + suflen;
+ tmp = emalloc (len + 1);
+ memcpy (tmp, dir, dirlen);
+ if (dir[0])
+ tmp[dirlen++] = '/';
+ memcpy (tmp + dirlen, file, fillen);
+ if (suf)
+ memcpy (tmp + dirlen + fillen, suf, suflen);
+ tmp[len] = 0;
+ return tmp;
+}
+
+char *
+tildexpand (char *s)
+{
+ if (s[0] == '~')
+ {
+ char *p = s + 1;
+ size_t len = strcspn (p, "/");
+ struct passwd *pw;
+
+ if (len == 0)
+ pw = getpwuid (getuid ());
+ else
+ {
+ char *user = emalloc (len + 1);
+
+ memcpy (user, p, len);
+ user[len] = 0;
+ pw = getpwnam (user);
+ free (user);
+ }
+ if (pw)
+ return mkfilename (pw->pw_dir, p + len + 1, NULL);
+ }
+ return estrdup (s);
+}
+
+int
+vgetyn (const char *prompt, va_list ap)
+{
+ int state = 0;
+ int c, resp;
+
+ do
+ {
+ switch (state)
+ {
+ case 1:
+ if (c == ' ' || c == '\t')
+ continue;
+ resp = c;
+ state = 2;
+ /* fall through */
+ case 2:
+ if (c == '\n')
+ {
+ switch (resp)
+ {
+ case 'y':
+ case 'Y':
+ return 1;
+ case 'n':
+ case 'N':
+ return 0;
+ default:
+ fprintf (stdout, "%s\n", _("Please, reply 'y' or 'n'"));
+ }
+ state = 0;
+ } else
+ break;
+
+ case 0:
+ vfprintf (stdout, prompt, ap);
+ fprintf (stdout, " [y/n]?");
+ fflush (stdout);
+ state = 1;
+ break;
+ }
+ } while ((c = getchar ()) != EOF);
+ exit (EXIT_USAGE);
+}
+
+int
+getyn (const char *prompt, ...)
+{
+ va_list ap;
+ int rc;
+
+ va_start (ap, prompt);
+ rc = vgetyn (prompt, ap);
+ va_end (ap);
+ return rc;
+}
+
diff --git a/src/var.c b/src/var.c
index ffa7297..a518e94 100644
--- a/src/var.c
+++ b/src/var.c
@@ -17,187 +17,181 @@
#include "gdbmtool.h"
#define VARF_DFL 0x00
#define VARF_SET 0x01
+union value
+{
+ char *string;
+ int bool;
+ int num;
+};
+
struct variable
{
char *name;
int type;
int flags;
- union
- {
- char *string;
- int bool;
- int num;
- } v;
- int (*hook) (struct variable *, int);
+ union value v;
+ int (*hook) (struct variable *, union value *);
void *hook_data;
};
-static int mode_toggle (struct variable *var, int after);
+static int open_hook (struct variable *, union value *);
static struct variable vartab[] = {
/* Top-level prompt */
{ "ps1", VART_STRING, VARF_DFL, { "%p>%_" } },
/* Second-level prompt (used within "def" block) */
{ "ps2", VART_STRING, VARF_DFL, { "%_>%_" } },
/* This delimits array members */
{ "delim1", VART_STRING, VARF_DFL, { "," } },
/* This delimits structure members */
{ "delim2", VART_STRING, VARF_DFL, { "," } },
+ { "confirm", VART_BOOL, VARF_DFL, { num: 1 } },
{ "cachesize", VART_INT, VARF_DFL, { num: DEFAULT_CACHESIZE } },
{ "blocksize", VART_INT, VARF_DFL, { num: 0 } },
- { "readonly", VART_BOOL, VARF_DFL, { num: 0 }, mode_toggle },
- { "newdb", VART_BOOL, VARF_DFL, { 0 }, mode_toggle },
+ { "open", VART_STRING, VARF_DFL, { NULL }, open_hook },
{ "lock", VART_BOOL, VARF_DFL, { num: 1 } },
{ "mmap", VART_BOOL, VARF_DFL, { num: 1 } },
{ "sync", VART_BOOL, VARF_DFL, { num: 0 } },
{ NULL }
};
static int
-mode_toggle (struct variable *var, int after)
-{