aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-05-23 19:18:14 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-05-23 19:18:14 +0300
commit7edbff3372dfd387e4f6da45f43ba8ada6dfbe43 (patch)
treed3049ab8c07773c82104e720f92be555ae276179 /src
parent008b71a4d58ad33cf5a41e2aa55b9393e8420531 (diff)
downloadgdbm-7edbff3372dfd387e4f6da45f43ba8ada6dfbe43.tar.gz
gdbm-7edbff3372dfd387e4f6da45f43ba8ada6dfbe43.tar.bz2
gdbmtool: accept commands from command line as well as from file
Commands can be supplied to gdbmtool in three ways: 1. From a file, using the --file (-f) option: gdbmtool -f comfile 2. From the command line, if first argument is the database name: gdbmtool test.db count \; fetch mykey \; avail Note the use of semicolon to delimit commands. 3. From the interactive shell, if neither of the above is used. * src/Makefile.am: Add new sources. * src/gdbmtool.c: Use new stream functions for input. * src/gdbmtool.h (setsource): Remove proto. (instream_t): New data type. (instream_name, instream_read) (instream_close, instream_interactive) (instream_eq): New functions. (instream_stdin_create) (instream_argv_create) (instream_file_create) (interactive, input_context_push): New protos. * src/gram.y: Accept ; in place of newline. * src/input-argv.c: New file. * src/input-file.c: New file. * src/input-rl.c: Rewrite to provide instream_t API. * src/input-std.c: Likewise. * src/lex.l: Rewrite. * tests/.gitignore: Update. * tests/Makefile.am: Add new tests. Incorporate DejaGNU tests. * tests/config/default.exp: New file. * tests/gdbmtool/base.exp: New file. * tests/gdbmtool00.at: New file. * tests/gdbmtool01.at: New file. * tests/gdbmtool02.at: New file. * tests/testsuite.at: Include new tests.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/gdbmtool.c99
-rw-r--r--src/gdbmtool.h57
-rw-r--r--src/gram.y28
-rw-r--r--src/input-argv.c106
-rw-r--r--src/input-file.c88
-rw-r--r--src/input-rl.c153
-rw-r--r--src/input-std.c45
-rw-r--r--src/lex.l315
9 files changed, 617 insertions, 278 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index aff6982..766dba8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -96,6 +96,8 @@ gdbmtool_LDADD = \
gdbmtool_SOURCES = \
datconv.c\
gram.y\
+ input-argv.c\
+ input-file.c\
lex.l\
gdbmtool.h\
gdbmtool.c\
@@ -109,7 +111,7 @@ else
endif
AM_YFLAGS = -dtv
-#AM_LFLAGS = -d
+AM_LFLAGS = -d
gdbm_load_LDADD = ./libgdbmapp.a ./libgdbm.la
gdbm_dump_LDADD = ./libgdbmapp.a ./libgdbm.la
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index b322260..c522ad0 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -78,7 +78,7 @@ opendb (char *dbname)
if (open_mode == GDBM_NEWDB)
{
- if (interactive && variable_is_true ("confirm") &&
+ if (interactive () && variable_is_true ("confirm") &&
access (dbname, F_OK) == 0)
{
if (!getyn (_("database %s already exists; overwrite"), dbname))
@@ -1106,9 +1106,10 @@ void
source_handler (struct handler_param *param)
{
char *fname = tildexpand (PARAM_STRING (param, 0));
- if (setsource (fname, 0) == 0)
- yyparse ();
+ instream_t istr = instream_file_create (fname);
free (fname);
+ if (input_context_push (istr) == 0)
+ yyparse ();
}
@@ -1456,7 +1457,7 @@ command_lookup (const char *str, struct locus *loc, struct command **pcmd)
break;
case fcom_found:
- if (!interactive)
+ if (!interactive ())
{
state = fcom_abort;
found = NULL;
@@ -1479,9 +1480,8 @@ command_lookup (const char *str, struct locus *loc, struct command **pcmd)
}
if (state == fcom_init)
- lerror (loc,
- interactive ? _("Invalid command. Try ? for help.") :
- _("Unknown command"));
+ lerror (loc, interactive () ? _("Invalid command. Try ? for help.") :
+ _("Unknown command"));
if (!found)
return T_BOGUS;
@@ -1490,7 +1490,12 @@ command_lookup (const char *str, struct locus *loc, struct command **pcmd)
}
char *parseopt_program_doc = N_("examine and/or modify a GDBM database");
-char *parseopt_program_args = N_("DBFILE");
+char *parseopt_program_args = N_("DBFILE [COMMAND [ARG ...]]");
+
+enum {
+ OPT_LEX_TRACE = 256,
+ OPT_GRAM_TRACE
+};
struct gdbm_option optab[] = {
{ 'b', "block-size", N_("SIZE"), N_("set block size") },
@@ -1504,6 +1509,8 @@ struct gdbm_option optab[] = {
{ '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") },
+ { OPT_LEX_TRACE, "lex-trace", NULL, N_("enable lexical analyzer traces") },
+ { OPT_GRAM_TRACE, "gram-trace", NULL, N_("enable grammar traces") },
{ 0 }
};
@@ -1786,7 +1793,7 @@ static struct gdbmarglist last_args;
void
run_last_command (void)
{
- if (interactive)
+ if (interactive ())
{
if (last_cmd)
{
@@ -1846,7 +1853,7 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
/* Optional argument */
break;
- if (!interactive)
+ if (!interactive ())
{
terror (_("%s: not enough arguments"), cmd->name);
return 1;
@@ -1896,7 +1903,7 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
pagfp = NULL;
expected_lines = 0;
- expected_lines_ptr = (interactive && pager) ? &expected_lines : NULL;
+ expected_lines_ptr = (interactive () && pager) ? &expected_lines : NULL;
if (!(cmd->begin && cmd->begin (&param, expected_lines_ptr)))
{
if (pager && expected_lines > get_screen_lines ())
@@ -1938,12 +1945,13 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
}
static void
-source_rcfile ()
+source_rcfile (void)
{
+ instream_t istr = NULL;
+
if (access (GDBMTOOLRC, R_OK) == 0)
{
- if (setsource (GDBMTOOLRC, 0) == 0)
- yyparse ();
+ istr = instream_file_create (GDBMTOOLRC);
}
else
{
@@ -1962,11 +1970,17 @@ source_rcfile ()
fname = mkfilename (p, GDBMTOOLRC, NULL);
if (access (fname, R_OK) == 0)
{
- if (setsource (fname, 0) == 0)
- yyparse ();
+ istr = instream_file_create (GDBMTOOLRC);
}
free (fname);
}
+
+ if (istr)
+ {
+ if (input_context_push (istr))
+ exit (EXIT_FATAL);
+ yyparse ();
+ }
}
#if GDBM_DEBUG_ENABLE
@@ -1984,12 +1998,12 @@ debug_printer (char const *fmt, ...)
int
main (int argc, char *argv[])
{
- int intr;
int opt;
int bv;
int norc = 0;
int res;
- char *source = "-";
+ char *source = NULL;
+ instream_t input = NULL;
set_progname (argv[0]);
#if GDBM_DEBUG_ENABLE
@@ -2005,8 +2019,6 @@ main (int argc, char *argv[])
sort_commands ();
/* Initialize variables. */
- intr = isatty (0);
- interactive = intr; /* Used early by input_init */
dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
dsdef[DS_CONTENT] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
@@ -2014,6 +2026,7 @@ main (int argc, char *argv[])
variable_set ("pager", VART_STRING, getenv ("PAGER"));
input_init ();
+ lex_trace (0);
for (opt = parseopt_first (argc, argv, optab);
opt != EOF;
@@ -2022,7 +2035,6 @@ main (int argc, char *argv[])
{
case 'f':
source = optarg;
- intr = 0;
break;
case 'l':
@@ -2068,6 +2080,14 @@ main (int argc, char *argv[])
bv = 1;
variable_set ("quiet", VART_BOOL, &bv);
break;
+
+ case OPT_LEX_TRACE:
+ lex_trace (1);
+ break;
+
+ case OPT_GRAM_TRACE:
+ gram_trace (1);
+ break;
default:
terror (_("unknown option; try `%s -h' for more info"),
@@ -2078,14 +2098,30 @@ main (int argc, char *argv[])
argc -= optind;
argv += optind;
- if (argc > 1)
+ if (source && strcmp (source, "-"))
{
- terror (_("too many arguments"));
- exit (EXIT_USAGE);
+ input = instream_file_create (source);
+ if (!input)
+ exit (1);
+ }
+
+ if (argc >= 1)
+ {
+ file_name = estrdup (argv[0]);
+ argc--;
+ argv++;
+ if (argc)
+ {
+ if (input)
+ {
+ terror (_("--file and and command cannot be used together"));
+ exit (EXIT_USAGE);
+ }
+ input = instream_argv_create (argc, argv);
+ if (!input)
+ exit (1);
+ }
}
-
- if (argc == 1)
- file_name = estrdup (argv[0]);
signal (SIGPIPE, SIG_IGN);
@@ -2093,13 +2129,16 @@ main (int argc, char *argv[])
argmax = 0;
if (!norc)
- source_rcfile ();
+ source_rcfile ();
+
+ if (!input)
+ input = instream_stdin_create ();
/* Welcome message. */
- if (intr && !variable_is_true ("quiet"))
+ if (instream_interactive (input) && !variable_is_true ("quiet"))
printf (_("\nWelcome to the gdbm tool. Type ? for help.\n\n"));
- if (setsource (source, intr))
+ if (input_context_push (input))
exit (EXIT_FATAL);
res = yyparse ();
input_done ();
diff --git a/src/gdbmtool.h b/src/gdbmtool.h
index 8a7725c..c472276 100644
--- a/src/gdbmtool.h
+++ b/src/gdbmtool.h
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
+#include <limits.h>
#ifndef GDBM_ARG_UNUSED
# define GDBM_ARG_UNUSED __attribute__ ((__unused__))
@@ -107,19 +108,67 @@ void terror (const char *fmt, ...)
char *make_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"
-ssize_t input_read (FILE *fp, char *buf, size_t size);
+typedef struct instream *instream_t;
+
+struct instream
+{
+ char *in_name; /* Input stream name */
+ int in_inter; /* True if this is an interactive stream */
+ ssize_t (*in_read) (instream_t, char*, size_t);
+ /* Read from stream */
+ void (*in_close) (instream_t);
+ /* Close the stream */
+ int (*in_eq) (instream_t, instream_t);
+ /* Return true if both streams refer to the
+ same input */
+};
+
+static inline char const *
+instream_name (instream_t in)
+{
+ return in->in_name;
+}
+
+static inline ssize_t
+instream_read (instream_t in, char *buf, size_t size)
+{
+ return in->in_read (in, buf, size);
+}
+
+static inline void
+instream_close (instream_t in)
+{
+ in->in_close (in);
+}
+
+static inline int
+instream_interactive (instream_t in)
+{
+ return in->in_inter;
+}
+
+static inline int
+instream_eq (instream_t a, instream_t b)
+{
+ return a->in_eq (a, b);
+}
+
void input_init (void);
void input_done (void);
+instream_t instream_stdin_create (void);
+instream_t instream_argv_create (int argc, char **argv);
+instream_t instream_file_create (char const *name);
+
+int interactive (void);
+int input_context_push (instream_t);
+
struct handler_param;
void input_history_handler (struct handler_param *param);
int input_history_begin (struct handler_param *param, size_t *exp_count);
diff --git a/src/gram.y b/src/gram.y
index 57d90c5..5372795 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -71,20 +71,20 @@ stmtlist : stmt
| stmtlist stmt
;
-stmt : /* empty */ '\n'
+stmt : /* empty */ eol
{
run_last_command ();
}
- | T_CMD arglist '\n'
+ | T_CMD arglist eol
{
- if (run_command ($1, &$2) && !interactive)
+ if (run_command ($1, &$2) && !interactive ())
exit (EXIT_USAGE);
}
- | set '\n'
- | defn '\n'
- | T_BOGUS '\n'
+ | set eol
+ | defn eol
+ | T_BOGUS eol
{
- if (interactive)
+ if (interactive ())
{
yyclearin;
yyerrok;
@@ -92,9 +92,9 @@ stmt : /* empty */ '\n'
else
YYERROR;
}
- | error { end_def(); } '\n'
+ | error { end_def(); } eol
{
- if (interactive)
+ if (interactive ())
{
yyclearin;
yyerrok;
@@ -104,6 +104,10 @@ stmt : /* empty */ '\n'
}
;
+eol : '\n'
+ | ';'
+ ;
+
arglist : /* empty */
{
gdbmarglist_init (&$$, NULL);
@@ -367,3 +371,9 @@ yyerror (char const *s)
terror ("%s", s);
return 0;
}
+
+void
+gram_trace (int n)
+{
+ yydebug = 1;
+}
diff --git a/src/input-argv.c b/src/input-argv.c
new file mode 100644
index 0000000..278398c
--- /dev/null
+++ b/src/input-argv.c
@@ -0,0 +1,106 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2018 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 <stdlib.h>
+
+struct instream_argv
+{
+ struct instream base; /* Base structure */
+ int argc; /* Number of arguments */
+ char **argv; /* Vector of arguments */
+ int idx; /* Index of the current argument */
+ char *cur; /* Current position in argv[idx] */
+ int delim; /* True if cur points to a delimiter */
+};
+
+static ssize_t
+instream_argv_read (instream_t istr, char *buf, size_t size)
+{
+ size_t len, total = 0;
+ struct instream_argv *i = (struct instream_argv*)istr;
+
+ while (total < size)
+ {
+ if (*i->cur == 0)
+ {
+ if (i->idx == i->argc)
+ {
+ if (!i->delim)
+ {
+ i->cur = "\n";
+ i->delim = 1;
+ }
+ else
+ break;
+ }
+ else if (!i->delim)
+ {
+ i->cur = " ";
+ i->delim = 1;
+ }
+ else
+ {
+ i->cur = i->argv[i->idx++];
+ i->delim = 0;
+ }
+ }
+
+ len = strlen (i->cur);
+ if (len > size - total)
+ len = size - total;
+ memcpy (buf + total, i->cur, len);
+ i->cur += len;
+ total += len;
+ }
+ return total;
+}
+
+static void
+instream_argv_close (instream_t istr)
+{
+ struct instream_argv *i = (struct instream_argv *)istr;
+ free (i);
+}
+
+static int
+instream_argv_eq (instream_t a, instream_t b)
+{
+ return 0;
+}
+
+instream_t
+instream_argv_create (int argc, char **argv)
+{
+ struct instream_argv *istr;
+
+ istr = emalloc (sizeof *istr);
+ istr->base.in_name = "argv";
+ istr->base.in_inter = 0;
+ istr->base.in_read = instream_argv_read;
+ istr->base.in_close = instream_argv_close;
+ istr->base.in_eq = instream_argv_eq;
+
+ istr->argc = argc;
+ istr->argv = argv;
+ istr->idx = 0;
+ istr->cur = "";
+ istr->delim = 1;
+
+ return (instream_t) istr;
+}
+
+
diff --git a/src/input-file.c b/src/input-file.c
new file mode 100644
index 0000000..5cbb030
--- /dev/null
+++ b/src/input-file.c
@@ -0,0 +1,88 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2018 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"
+
+struct instream_file
+{
+ struct instream base; /* Base structure */
+ FILE *fp; /* Opened file */
+ dev_t dev; /* Device number */
+ ino_t ino; /* Inode number */
+};
+
+static ssize_t
+instream_file_read (instream_t istr, char *buf, size_t size)
+{
+ struct instream_file *file = (struct instream_file *)istr;
+ return fread (buf, 1, size, file->fp);
+}
+
+static void
+instream_file_close (instream_t istr)
+{
+ struct instream_file *file = (struct instream_file *)istr;
+ fclose (file->fp);
+ free (file->base.in_name);
+ free (file);
+}
+
+static int
+instream_file_eq (instream_t a, instream_t b)
+{
+ struct instream_file *file_a = (struct instream_file *)a;
+ struct instream_file *file_b = (struct instream_file *)b;
+ return file_a->dev == file_b->dev && file_a->ino == file_b->ino;
+}
+
+instream_t
+instream_file_create (char const *name)
+{
+ struct instream_file *istr;
+ struct stat st;
+ FILE *fp;
+
+ if (stat (name, &st))
+ {
+ terror (_("cannot open `%s': %s"), name, strerror (errno));
+ return NULL;
+ }
+ else if (!S_ISREG (st.st_mode))
+ {
+ terror (_("%s is not a regular file"), name);
+ return NULL;
+ }
+
+ fp = fopen (name, "r");
+ if (!fp)
+ {
+ terror (_("cannot open %s for reading: %s"), name,
+ strerror (errno));
+ return NULL;
+ }
+
+ istr = emalloc (sizeof *istr);
+ istr->base.in_name = estrdup (name);
+ istr->base.in_inter = 0;
+ istr->base.in_read = instream_file_read;
+ istr->base.in_close = instream_file_close;
+ istr->base.in_eq = instream_file_eq;
+ istr->fp = fp;
+ istr->dev = st.st_dev;
+ istr->ino = st.st_ino;
+
+ return (instream_t) istr;
+}
diff --git a/src/input-rl.c b/src/input-rl.c
index d09feff..695d351 100644
--- a/src/input-rl.c
+++ b/src/input-rl.c
@@ -62,64 +62,6 @@ retrieve_history (char *str)
return 0;
}
-ssize_t
-input_read (FILE *fp, char *buf, size_t size)
-{
- static char *input_line;
- static size_t input_length;
- static size_t input_off;
-#define input_ptr() (input_line + input_off)
-#define input_size() (input_length - input_off)
-
- if (interactive)
- {
- size_t len = input_size ();
- if (!len)
- {
- if (input_line)
- {
- newline:
- free (input_line);
- input_line = NULL;
- buf[0] = '\n';
- return 1;
- }
- else
- {
- char *prompt;
- again:
- prompt = make_prompt ();
- input_line = readline (prompt);
- free (prompt);
- if (!input_line)
- return 0;
- input_length = strlen (input_line);
- input_off = 0;
- if (input_length)
- {
- if (retrieve_history (input_line))
- {
- free (input_line);
- goto again;
- }
- }
- else
- goto newline;
- len = input_size ();
- add_history (input_line);
- }
- }
-
- if (len > size)
- len = size;
- memcpy (buf, input_ptr (), len);
- input_off += len;
-
- return len;
- }
- return fread (buf, 1, size, fp);
-}
-
struct history_param
{
int from;
@@ -180,7 +122,7 @@ input_history_handler (struct handler_param *param)
#define HISTFILE_SUFFIX "_history"
static char *
-get_history_file_name ()
+get_history_file_name (void)
{
static char *filename = NULL;
@@ -222,14 +164,99 @@ input_init (void)
rl_readline_name = (char *) progname;
rl_attempted_completion_function = shell_completion;
rl_pre_input_hook = pre_input;
- if (interactive)
- read_history (get_history_file_name ());
+ read_history (get_history_file_name ());
}
void
input_done (void)
{
- if (interactive)
- write_history (get_history_file_name ());
+ write_history (get_history_file_name ());
+}
+
+static void
+instream_stdin_close (instream_t istr)
+{
+ free (istr);
+}
+
+static ssize_t
+stdin_read_readline (instream_t istr, char *buf, size_t size)
+{
+ static char *input_line;
+ static size_t input_length;
+ static size_t input_off;
+#define input_ptr() (input_line + input_off)
+#define input_size() (input_length - input_off)
+ size_t len = input_size ();
+ if (!len)
+ {
+ if (input_line)
+ {
+ newline:
+ free (input_line);
+ input_line = NULL;
+ buf[0] = '\n';
+ return 1;
+ }
+ else
+ {
+ char *prompt;
+ again:
+ prompt = make_prompt ();
+ input_line = readline (prompt);
+ free (prompt);
+ if (!input_line)
+ return 0;
+ input_length = strlen (input_line);
+ input_off = 0;
+ if (input_length)
+ {
+ if (retrieve_history (input_line))
+ {
+ free (input_line);
+ goto again;
+ }
+ }
+ else
+ goto newline;
+ len = input_size ();
+ add_history (input_line);
+ }
+ }
+
+ if (len > size)
+ len = size;
+ memcpy (buf, input_ptr (), len);
+ input_off += len;
+
+ return len;
+}
+
+static ssize_t
+instream_stdin_read (instream_t istr, char *buf, size_t size)
+{
+ if (istr->in_inter)
+ return stdin_read_readline (istr, buf, size);
+ return fread (buf, 1, size, stdin);
+}
+
+static int
+instream_stdin_eq (instream_t a, instream_t b)
+{
+ return 0;
}
+instream_t
+instream_stdin_create (void)
+{
+ struct instream *istr;
+
+ istr = emalloc (sizeof *istr);
+ istr->in_name = "stdin";
+ istr->in_inter = isatty (fileno (stdin));
+ istr->in_read = instream_stdin_read;
+ istr->in_close = instream_stdin_close;
+ istr->in_eq = instream_stdin_eq;
+
+ return istr;
+}
diff --git a/src/input-std.c b/src/input-std.c
index e4f883d..45ae506 100644
--- a/src/input-std.c
+++ b/src/input-std.c
@@ -16,17 +16,42 @@
#include "gdbmtool.h"
-ssize_t
-input_read (FILE *fp, char *buf, size_t size)
+static ssize_t
+instream_stdin_read (instream_t istr, char *buf, size_t size)
{
- if (interactive)
- {
- print_prompt_at_bol ();
- if (fgets (buf, size, fp) == NULL)
- return 0;
- return strlen (buf);
- }
- return fread (buf, 1, size, fp);
+ if (istr->in_inter)
+ print_prompt_at_bol ();
+ if (fgets (buf, size, stdin) == NULL)
+ return 0;
+ return strlen (buf);
+}
+
+static void
+instream_stdin_close (instream_t istr)
+{
+ free (istr);
+}
+
+static int
+instream_stdin_eq (instream_t a, instream_t b)
+{
+ return 0;
+}
+
+instream_t
+instream_stdin_create (void)
+{
+ struct instream_file *istr;
+
+ istr = emalloc (sizeof *istr);
+ istr->base.in_name = "stdin";
+ istr->base.in_inter = isatty (fileno (stdin));
+ istr->base.in_read = instream_stdin_read;
+ istr->base.in_close = instream_stdin_close;
+ istr->base.in_eq = instream_stdin_eq;
+ istr->fp = stdin;
+
+ return istr;
}
void
diff --git a/src/lex.l b/src/lex.l
index a2a8ee8..0318031 100644
--- a/src/lex.l
+++ b/src/lex.l
@@ -19,14 +19,23 @@
#include "gdbmtool.h"
#include "gram.h"
-struct point point;
-
+struct context /* Input context */
+{
+ struct context *parent; /* Pointer to the parent context */
+ struct locus locus; /* Locus */
+ struct point point;
+ YY_BUFFER_STATE buf; /* Buffer */
+ instream_t input;
+};
+
+static struct context *context_tos;
+
/* Advance locus to the next line */
void
-advance_line ()
+advance_line (void)
{
- ++point.line;
- point.col = 0;
+ ++context_tos->point.line;
+ context_tos->point.col = 0;
}
#define YY_USER_ACTION \
@@ -34,11 +43,11 @@ advance_line ()
{ \
if (YYSTATE == 0) \
{ \
- yylloc.beg = point; \
+ yylloc.beg = context_tos->point; \
yylloc.beg.col++; \
} \
- point.col += yyleng; \
- yylloc.end = point; \
+ context_tos->point.col += yyleng; \
+ yylloc.end = context_tos->point; \
} \
while (0);
@@ -46,7 +55,10 @@ advance_line ()
#define YY_INPUT(buf,result,max_size) \
do \
{ \
- result = input_read (yyin, buf, max_size); \
+ if (context_tos) \
+ result = instream_read (context_tos->input, buf, max_size); \
+ else \
+ result = 0; \
} \
while (0);
@@ -56,146 +68,112 @@ void string_addc (int c);
char *string_end (void);
int unescape (int c);
-struct context /* Input context */
+int
+interactive (void)
{
- 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 */
-};
+ return context_tos && instream_interactive (context_tos->input);
+}
+
+static struct context *
+input_context_lookup (instream_t istr)
+{
+ struct context *cp;
-static struct context *context_tos;
-static ino_t ino;
-static dev_t dev;
-int interactive; /* Are we running in interactive mode? */
-static int initialized;
+ for (cp = context_tos; cp; cp = cp->parent)
+ if (instream_eq (cp->input, istr))
+ break;
+ return cp;
+}
-static void
-context_push ()
+int
+input_context_push (instream_t input)
{
- struct context *cp = ecalloc (1, sizeof (*cp));
+ struct context *cp;
+
+ cp = input_context_lookup (input);
+ if (cp)
+ {
+ terror (_("recursive sourcing"));
+ if (cp->parent)
+ lerror (&cp->locus, _("%s already sourced here"),
+ instream_name (input));
+ return 1;
+ }
+ yy_switch_to_buffer (yy_create_buffer (NULL, YY_BUF_SIZE));
+
+ /* Create new 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->point.file = estrdup (instream_name (input));
+ cp->point.line = 1;
+ cp->point.col = 0;
+
+ cp->input = input;
cp->buf = YY_CURRENT_BUFFER;
cp->parent = context_tos;
context_tos = cp;
+
+ return 0;
}
+void
+lex_trace (int n)
+{
+ yy_flex_debug = n;
+}
+
int
-context_pop ()
+input_context_pop (void)
{
- struct context *cp = context_tos;
+ struct context *cp;
- fclose (yyin);
- yyin = NULL;
- free (point.file);
- point.file = NULL;
+ if (!context_tos)
+ return 1;
+ instream_close (context_tos->input);
+ free (context_tos->point.file);
memset (&yylloc, 0, sizeof (yylloc));
-
+ cp = context_tos->parent;
+ free (context_tos);
+ context_tos = cp;
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)
+static int
+t_num (int base)
{
- struct stat st;
- struct context *cp;
- FILE *fp;
-
- if (strcmp (name, "-") == 0)
+ long n;
+ errno = 0;
+ n = strtol (yytext, NULL, base);
+ if (errno)
{
- fp = stdin;
- name = "stdin";
+ lerror (&yylloc, "%s", strerror (errno));
+ return T_BOGUS;
}
- else
+ if (n < INT_MIN || n > INT_MAX)
{
- if (stat (name, &st))
- {
- terror (_("cannot open `%s': %s"), name, strerror (errno));
- return -1;
- }
- else if (!S_ISREG (st.st_mode))
- {
- terror (_("%s is not a regular file"), name);
- return -1;
- }
-
- cp = findctx (&st);
- if (cp)
- {
- terror (_("recursive sourcing"));
- if (cp->parent)
- lerror (&cp->locus, _("%s already sourced here"), name);
- return 1;
- }
-
- fp = fopen (name, "r");
- if (!fp)
- {
- terror (_("cannot open %s for reading: %s"), name,
- strerror (errno));
- return 1;
- }
+ lerror (&yylloc, "value out of range");
+ return T_BOGUS;
}
-
- 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;
-
- initialized = 1;
-
- return 0;
+ yylval.num = n;
+ return T_NUM;
}
+
%}
%option noinput
%option nounput
+%option nodefault
-%x STR MLSTR DEF
+%x CMD STR MLSTR DEF
WS [ \t][ \t]*
IDENT [a-zA-Z_][a-zA-Z_0-9-]*
@@ -238,67 +216,82 @@ O [0-7]
REJECT;
}
if (file)
- point.file = file;
- point.line = line;
- point.col = 0;
+ context_tos->point.file = file;
+ context_tos->point.line = line;
+ context_tos->point.col = 0;
}
#.*\n advance_line ();
#.* /* end-of-file comment */;
-<DEF>off { return T_OFF; }
-<DEF>pad { return T_PAD; }
-<DEF>0[xX]{X}{X}* { yylval.num = strtoul (yytext, NULL, 16);
- return T_NUM; };
-<DEF>0{O}{O}* { yylval.num = strtoul (yytext, NULL, 8);
- return T_NUM; };
-<DEF>0|{P} { yylval.num = strtoul (yytext, NULL, 10);
- return T_NUM; };
-^[ \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;
-