aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2013-05-14 06:22:55 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2013-05-14 06:22:55 +0000
commit10201217d141314a78a7937027bfdbdb7c994a43 (patch)
tree0ce888c1ef130a9d6847d045cac9b04c3a1590dc /src
parent6d66bc4877a319d0f6400f5058be47f221e731da (diff)
downloadgdbm-10201217d141314a78a7937027bfdbdb7c994a43.tar.gz
gdbm-10201217d141314a78a7937027bfdbdb7c994a43.tar.bz2
Implement rc files and "source" command; improve lexical analyzer.
* src/gdbmtool.c (interactive): Move to lex.l; (mkfilename, tildexpand): New functions. (command_tab) <source>: 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.
Diffstat (limited to 'src')
-rw-r--r--src/gdbmapp.h2
-rw-r--r--src/gdbmtool.c127
-rw-r--r--src/gdbmtool.h5
-rw-r--r--src/lex.l183
-rw-r--r--src/mem.c2
5 files changed, 267 insertions, 52 deletions
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 <errno.h>
#include <ctype.h>
#include <signal.h>
+#include <pwd.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_TERMIOS_H
# include <sys/termios.h>
@@ -31,12 +32,11 @@
# include <locale.h>
#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 (&param, 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 (&param, 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; };
<DEF>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);
+ }
+<DEF>{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;
+ }
+<INITIAL,DEF>[^ \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; }
<STR>[^\\\"\n]*\\. { string_add (yytext, yyleng - 2);
string_addc (unescape (yytext[yyleng-1])); }
-{WS} ;
-\n { advance_line (); if (YYSTATE == INITIAL) return '\n'; }
-. return yytext[0];
+<INITIAL,DEF>{WS} ;
+<DEF>\n { advance_line (); }
+\n { advance_line (); return '\n'; }
+<INITIAL,DEF>. 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;

Return to:

Send suggestions and report system problems to the System administrator.