From 8cbaa44e2f1b80dd8954a0e06e0bc8a52494237f Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 14 May 2013 16:08:34 +0000 Subject: 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. --- ChangeLog | 28 +++++++++ src/Makefile.am | 7 +-- src/datconv.c | 8 +-- src/gdbmtool.c | 186 ++++++++++++++++++++++---------------------------------- src/gdbmtool.h | 21 ++++--- src/gram.y | 24 +++++--- src/lex.l | 23 ++++--- src/util.c | 127 ++++++++++++++++++++++++++++++++++++++ src/var.c | 140 ++++++++++++++++++++---------------------- 9 files changed, 340 insertions(+), 224 deletions(-) create mode 100644 src/util.c diff --git a/ChangeLog b/ChangeLog index 0ee3823..1f9d600 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2013-05-14 Sergey Poznyakoff + + 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 Provide "open" and "close" commands; implement new variables. diff --git a/src/Makefile.am b/src/Makefile.am index bf2f21e..b8bebde 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,7 @@ noinst_HEADERS = \ proto.h\ systems.h -EXTRA_DIST = gdbm.h.in +EXTRA_DIST = gdbm.h.in gram.h # The libraries VI_CURRENT = 4 @@ -85,9 +85,8 @@ gdbmtool_SOURCES = \ lex.l\ gdbmtool.h\ gdbmtool.c\ - var.c - -EXTRA_DIST = gram.h + var.c\ + util.c AM_YFLAGS = -dtv #AM_LFLAGS = -d diff --git a/src/datconv.c b/src/datconv.c index 0178f41..95656db 100644 --- a/src/datconv.c +++ b/src/datconv.c @@ -319,7 +319,7 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) { if (kv->key) { - parse_error (&kv->loc, + lerror (&kv->loc, _("mixing tagged and untagged values is not allowed")); err = 1; break; @@ -336,7 +336,7 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) 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: @@ -346,7 +346,7 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) 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; @@ -383,7 +383,7 @@ datum_scan_notag (datum *dat, struct dsegm *ds, struct kvpair *kv) 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; } diff --git a/src/gdbmtool.c b/src/gdbmtool.c index a561bfc..6083edc 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -37,76 +37,13 @@ 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) { @@ -127,25 +64,28 @@ opendb (char *dbname) 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) @@ -163,7 +103,7 @@ checkdb () 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); @@ -228,16 +168,17 @@ _gdbm_avail_list_size (GDBM_FILE dbf, size_t min_size) { 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; } @@ -280,16 +221,16 @@ _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf) { 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; } @@ -415,7 +356,7 @@ 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; } @@ -737,7 +678,10 @@ list_handler (struct handler_param *param) 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]); @@ -779,7 +723,7 @@ export_handler (struct handler_param *param) format = GDBM_DUMP_FMT_ASCII; else { - syntax_error (_("unrecognized argument: %s"), + terror (_("unrecognized argument: %s"), param->argv[i]->v.string); return; } @@ -787,7 +731,8 @@ export_handler (struct handler_param *param) 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)); } } @@ -809,7 +754,7 @@ import_handler (struct handler_param *param) 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; } @@ -819,13 +764,11 @@ import_handler (struct handler_param *param) 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; @@ -839,24 +782,24 @@ import_handler (struct handler_param *param) { 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 */ @@ -1104,7 +1047,7 @@ command_lookup (const char *str, struct locus *loc, struct command **pcmd) } if (state == fcom_init) - parse_error (loc, + lerror (loc, interactive ? _("Invalid command. Try ? for help.") : _("Unknown command")); if (!found) @@ -1124,6 +1067,7 @@ struct gdbm_option optab[] = { { '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") }, @@ -1366,7 +1310,7 @@ 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; } @@ -1411,13 +1355,16 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) 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) @@ -1438,7 +1385,7 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) if (arg) { - syntax_error (_("%s: too many arguments"), cmd->name); + terror (_("%s: too many arguments"), cmd->name); return 1; } @@ -1465,8 +1412,8 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) 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; } @@ -1506,7 +1453,7 @@ source_rcfile () struct passwd *pw = getpwuid (getuid ()); if (!pw) { - terror (0, _("cannot find home directory")); + terror (_("cannot find home directory")); return; } p = pw->pw_dir; @@ -1527,6 +1474,7 @@ main (int argc, char *argv[]) int intr; int opt; int bv; + int norc = 0; set_progname (argv[0]); @@ -1537,6 +1485,8 @@ main (int argc, char *argv[]) textdomain (PACKAGE); sort_commands (); + + variable_set ("open", VART_STRING, "wrcreat"); for (opt = parseopt_first (argc, argv, optab); opt != EOF; @@ -1559,13 +1509,15 @@ main (int argc, char *argv[]) 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': @@ -1585,15 +1537,20 @@ main (int argc, char *argv[]) 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]; @@ -1611,7 +1568,8 @@ main (int argc, char *argv[]) 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 @@ -89,10 +89,10 @@ typedef struct locus gdbm_yyltype_t; } \ 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); @@ -100,6 +100,7 @@ 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" @@ -227,16 +228,15 @@ extern struct dsegm *dsdef[]; #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); @@ -252,4 +252,7 @@ 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 @@ -201,8 +201,8 @@ defid : T_IDENT $$ = DS_CONTENT; else { - syntax_error (_("expected \"key\" or \"content\", " - "but found \"%s\""), $1); + terror (_("expected \"key\" or \"content\", " + "but found \"%s\""), $1); YYERROR; } } @@ -271,11 +271,11 @@ var : T_IDENT 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); @@ -283,38 +283,42 @@ var : T_IDENT | 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 @@ -74,7 +74,8 @@ 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 () { @@ -144,28 +145,28 @@ setsource (const char *name, int intr) { 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; } @@ -185,6 +186,8 @@ setsource (const char *name, int intr) point.line = 1; point.col = 0; + initialized = 1; + return 0; } %} @@ -419,11 +422,11 @@ escape (int c) } 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, ": "); @@ -433,12 +436,12 @@ vparse_error (struct locus *loc, const char *fmt, va_list ap) } 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); } 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 . */ + +#include "gdbmtool.h" +#include + +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 @@ -20,22 +20,24 @@ #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 */ @@ -46,10 +48,10 @@ static struct variable vartab[] = { { "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 } }, @@ -57,39 +59,31 @@ static struct variable vartab[] = { }; static int -mode_toggle (struct variable *var, int after) -{ - if (after) - { - struct variable *vp; - int newval = !var->v.bool; - - for (vp = vartab; vp->name; vp++) - { - if (vp == var) - continue; - else if (vp->hook == mode_toggle) - { - vp->v.bool = newval; - newval = 0; - } - } - } - return 0; -} - -const char * -variable_mode_name () +open_hook (struct variable *var, union value *v) { - struct variable *vp; + static struct { + char *s; + int t; + } trans[] = { + { "newdb", GDBM_NEWDB }, + { "wrcreat", GDBM_WRCREAT }, + { "rw", GDBM_WRCREAT }, + { "reader", GDBM_READER }, + { "readonly", GDBM_READER }, + { NULL } + }; + int i; - for (vp = vartab; vp->name; vp++) - if (vp->hook == mode_toggle && vp->v.bool) - return vp->name; + for (i = 0; trans[i].s; i++) + if (strcmp (trans[i].s, v->string) == 0) + { + open_mode = trans[i].t; + return VAR_OK; + } - return NULL; + return VAR_ERR_BADVALUE; } - + static struct variable * varfind (const char *name) { @@ -102,33 +96,33 @@ varfind (const char *name) return NULL; } -typedef int (*setvar_t) (struct variable *, void *); +typedef int (*setvar_t) (union value *, void *); static int -s2s (struct variable *vp, void *val) +s2s (union value *vp, void *val) { - vp->v.string = estrdup (val); - return 0; + vp->string = estrdup (val); + return VAR_OK; } static int -b2s (struct variable *vp, void *val) +b2s (union value *vp, void *val) { - vp->v.string = estrdup (*(int*)val ? "true" : "false"); - return 0; + vp->string = estrdup (*(int*)val ? "true" : "false"); + return VAR_OK; } static int -i2s (struct variable *vp, void *val) +i2s (union value *vp, void *val) { char buf[128]; snprintf (buf, sizeof buf, "%d", *(int*)val); - vp->v.string = estrdup (buf); - return 0; + vp->string = estrdup (buf); + return VAR_OK; } static int -s2b (struct variable *vp, void *val) +s2b (union value *vp, void *val) { static char *trueval[] = { "on", "true", "yes", NULL }; static char *falseval[] = { "off", "false", "no", NULL }; @@ -139,26 +133,26 @@ s2b (struct variable *vp, void *val) for (i = 0; trueval[i]; i++) if (strcasecmp (trueval[i], val) == 0) { - vp->v.bool = 1; + vp->bool = 1; return 0; } for (i = 0; falseval[i]; i++) if (strcasecmp (falseval[i], val) == 0) { - vp->v.bool = 0; + vp->bool = 0; return 1; } n = strtoul (val, &p, 0); if (*p) return VAR_ERR_BADTYPE; - vp->v.bool = !!n; + vp->bool = !!n; return VAR_OK; } static int -s2i (struct variable *vp, void *val) +s2i (union value *vp, void *val) { char *p; int n = strtoul (val, &p, 0); @@ -166,35 +160,35 @@ s2i (struct variable *vp, void *val) if (*p) return VAR_ERR_BADTYPE; - vp->v.num = n; + vp->num = n; return VAR_OK; } static int -b2b (struct variable *vp, void *val) +b2b (union value *vp, void *val) { - vp->v.bool = !!*(int*)val; + vp->bool = !!*(int*)val; return VAR_OK; } static int -b2i (struct variable *vp, void *val) +b2i (union value *vp, void *val) { - vp->v.num = *(int*)val; + vp->num = *(int*)val; return VAR_OK; } static int -i2i (struct variable *vp, void *val) +i2i (union value *vp, void *val) { - vp->v.num = *(int*)val; + vp->num = *(int*)val; return VAR_OK; } static int -i2b (struct variable *vp, void *val) +i2b (union value *vp, void *val) { - vp->v.bool = *(int*)val; + vp->bool = *(int*)val; return VAR_OK; } @@ -210,25 +204,25 @@ variable_set (const char *name, int type, void *val) { struct variable *vp = varfind (name); int rc; + union value v; if (!vp) return VAR_ERR_NOTDEF; - if (vp->hook && vp->hook (vp, 0)) - return VAR_ERR_FAILURE; + memset (&v, 0, sizeof (v)); + rc = setvar[vp->type][type] (&v, val); + if (rc) + return rc; + + if (vp->hook && (rc = vp->hook (vp, &v)) != VAR_OK) + return rc; if (vp->type == VART_STRING && (vp->flags && VARF_SET)) free (vp->v.string); - rc = setvar[vp->type][type] (vp, val); - - if (rc) - return rc; + vp->v = v; vp->flags |= VARF_SET; - if (vp->hook) - vp->hook (vp, 1); - return VAR_OK; } @@ -276,7 +270,7 @@ variable_print_all (FILE *fp) break; case VART_BOOL: - fprintf (fp, "%s%s", vp->v.bool ? "no" : "", vp->name); + fprintf (fp, "%s%s", vp->v.bool ? "" : "no", vp->name); break; case VART_STRING: -- cgit v1.2.1