From 10201217d141314a78a7937027bfdbdb7c994a43 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 14 May 2013 06:22:55 +0000 Subject: Implement rc files and "source" command; improve lexical analyzer. * src/gdbmtool.c (interactive): Move to lex.l; (mkfilename, tildexpand): New functions. (command_tab) : New command. (main): Source rc file, if present. * src/gdbmtool.h (setsource): Change return type and signature. * src/lex.l: Implement context stack. Change DEF to be an exclusive state. * src/gdbmapp.h (estrdup): Argument is const. * src/mem.c: Likewise. --- ChangeLog | 18 +++++- src/gdbmapp.h | 2 +- src/gdbmtool.c | 127 ++++++++++++++++++++++++++++++++++----- src/gdbmtool.h | 5 +- src/lex.l | 183 ++++++++++++++++++++++++++++++++++++++++++++++----------- src/mem.c | 2 +- 6 files changed, 284 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3dd14f6..ddbdaa4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,23 @@ +2013-05-14 Sergey Poznyakoff + + Implement rc files and "source" command; improve lexical analyzer. + + * src/gdbmtool.c (interactive): Move to lex.l; + (mkfilename, tildexpand): New functions. + (command_tab) : New command. + (main): Source rc file, if present. + * src/gdbmtool.h (setsource): Change return type + and signature. + * src/lex.l: Implement context stack. + Change DEF to be an exclusive state. + + * src/gdbmapp.h (estrdup): Argument is const. + * src/mem.c: Likewise. + 2013-05-14 Sergey Poznyakoff Add support for Berkeley dump format version 3 (read-only). - + * src/gdbmapp.h: Include gettext.h and locale.h. * src/gdbmload.c: Support for Berkeley dump format, version 3. diff --git a/src/gdbmapp.h b/src/gdbmapp.h index d978cef..8cec6fb 100644 --- a/src/gdbmapp.h +++ b/src/gdbmapp.h @@ -33,7 +33,7 @@ void *emalloc (size_t size); void *erealloc (void *ptr, size_t size); void *ecalloc (size_t nmemb, size_t size); void *ezalloc (size_t size); -char *estrdup (char *str); +char *estrdup (const char *str); #define PARSEOPT_HIDDEN 0x01 #define PARSEOPT_ALIAS 0x02 diff --git a/src/gdbmtool.c b/src/gdbmtool.c index 5e672b2..905c3fb 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #ifdef HAVE_SYS_TERMIOS_H # include @@ -31,12 +32,11 @@ # include #endif -char *file_name = NULL; /* Database file name */ +char *file_name = NULL; /* Database file name */ 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 quiet_option = 0; /* Omit usual welcome banner at startup */ +datum key_data; /* Current key */ +datum return_data; /* Current data */ +int quiet_option = 0; /* Omit the usual welcome banner at startup */ #define SIZE_T_MAX ((size_t)-1) @@ -56,7 +56,57 @@ terror (int code, const char *fmt, ...) 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); +} + size_t bucket_print_lines (hash_bucket *bucket) @@ -698,6 +748,16 @@ status_handler (struct handler_param *param) fprintf (param->fp, _("Database file: %s\n"), file_name); } +void +source_handler (struct handler_param *param) +{ + char *fname = tildexpand (param->argv[0]->v.string); + if (setsource (fname, 0) == 0) + yyparse (); + free (fname); +} + + void help_handler (struct handler_param *param); int help_begin (struct handler_param *param, size_t *exp_count); @@ -810,6 +870,10 @@ struct command command_tab[] = { { { "key|content", ARG_STRING }, { "{ field-list }", ARG_STRING }, { NULL } }, N_("define structure") }, + { S(source), T_CMD, + NULL, source_handler, NULL, + { { "file", ARG_STRING }, + { NULL } }, N_("source command script") }, #undef S { 0 } }; @@ -1279,12 +1343,44 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) return 0; } - + +static void +source_rcfile () +{ + if (access (GDBMTOOLRC, R_OK) == 0) + { + if (setsource (GDBMTOOLRC, 0) == 0) + yyparse (); + } + else + { + char *fname; + char *p = getenv ("HOME"); + if (!p) + { + struct passwd *pw = getpwuid (getuid ()); + if (!pw) + { + terror (0, _("cannot find home directory")); + return; + } + p = pw->pw_dir; + } + fname = mkfilename (p, GDBMTOOLRC, NULL); + if (access (fname, R_OK) == 0) + { + if (setsource (fname, 0) == 0) + yyparse (); + } + free (fname); + } +} + int main (int argc, char *argv[]) { - char cmdbuf[1000]; - + int intr; + int cache_size = DEFAULT_CACHESIZE; int block_size = 0; @@ -1369,7 +1465,7 @@ main (int argc, char *argv[]) file_name = "junk.gdbm"; /* Initialize variables. */ - interactive = isatty (0); + intr = isatty (0); dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1); dsdef[DS_CONTENT] = dsegm_new_field (datadef_lookup ("string"), NULL, 1); @@ -1397,16 +1493,15 @@ main (int argc, char *argv[]) signal (SIGPIPE, SIG_IGN); + memset (¶m, 0, sizeof (param)); + argmax = 0; + /* Welcome message. */ - if (interactive && !quiet_option) + if (intr && !quiet_option) printf (_("\nWelcome to the gdbm tool. Type ? for help.\n\n")); - memset (¶m, 0, sizeof (param)); - argmax = 0; + source_rcfile (); - setsource ("stdin", stdin); - //FIXME + setsource ("-", intr); return yyparse (); - - return 0; } diff --git a/src/gdbmtool.h b/src/gdbmtool.h index 4097629..96e0ba5 100644 --- a/src/gdbmtool.h +++ b/src/gdbmtool.h @@ -95,10 +95,13 @@ void syntax_error (const char *fmt, ...); void print_prompt (void); -void setsource (const char *filename, FILE *file); +int setsource (const char *filename, int intr); extern char *file_name; extern int interactive; + +#define GDBMTOOLRC ".gdbmtoolrc" + struct slist { diff --git a/src/lex.l b/src/lex.l index 8de9f42..fda3002 100644 --- a/src/lex.l +++ b/src/lex.l @@ -57,11 +57,140 @@ char *string_end (void); int unescape (int c); static ssize_t read_input (char *buf, size_t size); + +struct context /* Input context */ +{ + struct context *parent; /* Pointer to the parent context */ + struct locus locus; /* Locus */ + struct point point; + int interactive; + ino_t ino; /* Inode number */ + dev_t dev; /* Device number */ + FILE *file; /* Input file */ + YY_BUFFER_STATE buf; /* Buffer */ +}; + +static struct context *context_tos; +static ino_t ino; +static dev_t dev; +int interactive; /* Are we running in interactive mode? */ + +static void +context_push () +{ + struct context *cp = ecalloc (1, sizeof (*cp)); + + cp->locus = yylloc; + cp->point = point; + cp->interactive = interactive; + cp->ino = ino; + cp->dev = dev; + cp->file = yyin; + cp->buf = YY_CURRENT_BUFFER; + cp->parent = context_tos; + context_tos = cp; +} + +int +context_pop () +{ + struct context *cp = context_tos; + + fclose (yyin); + yyin = NULL; + free (point.file); + + if (!cp) + return 1; + + context_tos = cp->parent; + + yylloc = cp->locus; + point = cp->point; + interactive = cp->interactive; + ino = cp->ino; + dev = cp->dev; + yyin = cp->file; + yy_delete_buffer (YY_CURRENT_BUFFER); + yy_switch_to_buffer (cp->buf); + + return 0; +} + +static struct context * +findctx (struct stat *st) +{ + struct context *cp; + + for (cp = context_tos; cp; cp = cp->parent) + if (cp->dev == st->st_dev && cp->ino == st->st_ino) + break; + return cp; +} +int +setsource (const char *name, int intr) +{ + int rc; + struct stat st; + struct context *cp; + FILE *fp; + + if (strcmp (name, "-") == 0) + { + fp = stdin; + name = "stdin"; + } + else + { + if (stat (name, &st)) + { + syntax_error (_("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); + return -1; + } + + cp = findctx (&st); + if (cp) + { + syntax_error (_("recursive sourcing")); + if (cp->parent) + parse_error (&cp->locus, _("%s already sourced here"), name); + return 1; + } + + fp = fopen (name, "r"); + if (!fp) + { + syntax_error (_("cannot open %s for reading: %s"), name, + strerror (errno)); + return 1; + } + } + + if (yyin) + context_push (); + + yyin = fp; + yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE)); + + interactive = intr; + dev = st.st_dev; + ino = st.st_ino; + + point.file = estrdup (name); + point.line = 1; + point.col = 0; + + return 0; +} %} -%x STR -%s DEF +%x STR DEF WS [ \t][ \t]* IDENT [a-zA-Z_][a-zA-Z_0-9-]* @@ -119,22 +248,11 @@ O [0-7] return T_NUM; }; 0|{P} { yylval.num = strtoul (yytext, NULL, 10); return T_NUM; }; - -^[ \t]*{IDENT} { if (YYSTATE == DEF) - { - if (yylval.type = datadef_lookup (yytext)) - return T_TYPE; - } - else - { - return command_lookup (yytext, &yylloc, &yylval.cmd); - } - - yylval.string = estrdup (yytext); - return T_IDENT; - } -{IDENT} { if (YYSTATE == DEF && - (yylval.type = datadef_lookup (yytext))) +^[ \t]*\? { return command_lookup ("help", &yylloc, &yylval.cmd); } +^[ \t]*{IDENT} { char *p = yytext + strspn (yytext, " \t"); + return command_lookup (p, &yylloc, &yylval.cmd); + } +{IDENT} { if ((yylval.type = datadef_lookup (yytext))) return T_TYPE; else { @@ -142,7 +260,11 @@ O [0-7] return T_IDENT; } } -[^ \t\n\[\]{},=]+ { yylval.string = estrdup (yytext); return T_WORD; } +{IDENT} { yylval.string = estrdup (yytext); + return T_IDENT; + } +[^ \t\n\[\]{},=]+ { yylval.string = estrdup (yytext); + return T_WORD; } \"[^\\\"\n]*\" { yylval.string = emalloc (yyleng - 1); memcpy (yylval.string, yytext+1, yyleng-2); yylval.string[yyleng-2] = 0; @@ -158,24 +280,16 @@ O [0-7] return T_WORD; } [^\\\"\n]*\\. { string_add (yytext, yyleng - 2); string_addc (unescape (yytext[yyleng-1])); } -{WS} ; -\n { advance_line (); if (YYSTATE == INITIAL) return '\n'; } -. return yytext[0]; +{WS} ; +\n { advance_line (); } +\n { advance_line (); return '\n'; } +. return yytext[0]; %% -void -setsource (const char *filename, FILE *file) -{ - point.file = (char*) filename; - point.line = 1; - point.col = 0; - yyin = file; -} - int yywrap () { - return 1; + return context_pop (); } void @@ -309,7 +423,10 @@ vparse_error (struct locus *loc, const char *fmt, va_list ap) if (!interactive) fprintf (stderr, "%s", progname); if (loc) - YY_LOCATION_PRINT (stderr, *loc); + { + fprintf (stderr, ": "); + YY_LOCATION_PRINT (stderr, *loc); + } fprintf (stderr, ": "); vfprintf (stderr, fmt, ap); fputc ('\n', stderr); diff --git a/src/mem.c b/src/mem.c index 62bde53..d405f31 100644 --- a/src/mem.c +++ b/src/mem.c @@ -60,7 +60,7 @@ ezalloc (size_t size) } char * -estrdup (char *str) +estrdup (const char *str) { char *p; -- cgit v1.2.1