diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-05-23 19:18:14 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-05-23 19:18:14 +0300 |
commit | 7edbff3372dfd387e4f6da45f43ba8ada6dfbe43 (patch) | |
tree | d3049ab8c07773c82104e720f92be555ae276179 | |
parent | 008b71a4d58ad33cf5a41e2aa55b9393e8420531 (diff) | |
download | gdbm-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.
-rw-r--r-- | doc/gdbm.texi | 1 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/gdbmtool.c | 99 | ||||
-rw-r--r-- | src/gdbmtool.h | 57 | ||||
-rw-r--r-- | src/gram.y | 28 | ||||
-rw-r--r-- | src/input-argv.c | 106 | ||||
-rw-r--r-- | src/input-file.c | 88 | ||||
-rw-r--r-- | src/input-rl.c | 153 | ||||
-rw-r--r-- | src/input-std.c | 45 | ||||
-rw-r--r-- | src/lex.l | 315 | ||||
-rw-r--r-- | tests/.gitignore | 3 | ||||
-rw-r--r-- | tests/Makefile.am | 37 | ||||
-rw-r--r-- | tests/config/default.exp | 221 | ||||
-rw-r--r-- | tests/gdbmtool/base.exp | 9 | ||||
-rw-r--r-- | tests/gdbmtool00.at | 37 | ||||
-rw-r--r-- | tests/gdbmtool01.at | 37 | ||||
-rw-r--r-- | tests/gdbmtool02.at | 31 | ||||
-rw-r--r-- | tests/testsuite.at | 5 |
18 files changed, 995 insertions, 281 deletions
diff --git a/doc/gdbm.texi b/doc/gdbm.texi index 2aac1c3..0876f8d 100644 --- a/doc/gdbm.texi +++ b/doc/gdbm.texi @@ -8,12 +8,13 @@ @ifinfo @dircategory Programming & development tools @direntry * GDBM: (gdbm). The GNU database manager. * gdbm_dump: (gdbm) gdbm_dump. Dump the GDBM database into a flat file. * gdbm_load: (gdbm) gdbm_load. Load the database from a flat file. +* gdbmtool: (gdbm) gdbmtool. Examine and modify a GDBM database. @end direntry @end ifinfo @c @setchapternewpage odd @comment %**end of header (This is for running Texinfo on a region.) diff --git a/src/Makefile.am b/src/Makefile.am index aff6982..766dba8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -93,12 +93,14 @@ gdbmtool_LDADD = \ ./libgdbm.la\ @READLINE_LIBS@ gdbmtool_SOURCES = \ datconv.c\ gram.y\ + input-argv.c\ + input-file.c\ lex.l\ gdbmtool.h\ gdbmtool.c\ var.c\ util.c @@ -106,10 +108,10 @@ if GDBM_COND_READLINE gdbmtool_SOURCES += input-rl.c else gdbmtool_SOURCES += input-std.c 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 @@ -75,13 +75,13 @@ opendb (char *dbname) flags |= GDBM_NOMMAP; if (variable_is_true ("sync")) flags |= GDBM_SYNC; 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)) return 1; } } @@ -1103,15 +1103,16 @@ debug_handler (struct handler_param *param) } 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 (); } void help_handler (struct handler_param *param); int help_begin (struct handler_param *param, size_t *exp_count); @@ -1453,13 +1454,13 @@ command_lookup (const char *str, struct locus *loc, struct command **pcmd) case fcom_init: found = cmd; state = fcom_found; break; case fcom_found: - if (!interactive) + if (!interactive ()) { state = fcom_abort; found = NULL; continue; } fprintf (stderr, "ambiguous command: %s\n", str); @@ -1476,24 +1477,28 @@ command_lookup (const char *str, struct locus *loc, struct command **pcmd) abort (); } } } 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; *pcmd = found; return found->tok; } 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") }, { 'c', "cache-size", N_("SIZE"), N_("set cache size") }, { 'f', "file", N_("FILE"), N_("read commands from FILE") }, { 'g', NULL, "FILE", NULL, PARSEOPT_HIDDEN }, @@ -1501,12 +1506,14 @@ struct gdbm_option optab[] = { { '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") }, + { OPT_LEX_TRACE, "lex-trace", NULL, N_("enable lexical analyzer traces") }, + { OPT_GRAM_TRACE, "gram-trace", NULL, N_("enable grammar traces") }, { 0 } }; #define ARGINC 16 @@ -1783,13 +1790,13 @@ coerce (struct gdbmarg *arg, struct argdef *def) static struct command *last_cmd; static struct gdbmarglist last_args; void run_last_command (void) { - if (interactive) + if (interactive ()) { if (last_cmd) { switch (last_cmd->repeat) { case REPEAT_NEVER: @@ -1843,13 +1850,13 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) struct gdbmarg *t; if (*argname == '[') /* Optional argument */ break; - if (!interactive) + if (!interactive ()) { terror (_("%s: not enough arguments"), cmd->name); return 1; } printf ("%s? ", argname); fflush (stdout); @@ -1893,13 +1900,13 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) param.vararg = arg; param.fp = NULL; param.data = NULL; 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 (¶m, expected_lines_ptr))) { if (pager && expected_lines > get_screen_lines ()) { pagfp = popen (pager, "w"); if (pagfp) @@ -1935,18 +1942,19 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) } return 0; } 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 { char *fname; char *p = getenv ("HOME"); if (!p) @@ -1959,17 +1967,23 @@ source_rcfile () } p = pw->pw_dir; } 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 void debug_printer (char const *fmt, ...) { @@ -1981,18 +1995,18 @@ debug_printer (char const *fmt, ...) } #endif 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 gdbm_debug_printer = debug_printer; #endif @@ -2002,30 +2016,28 @@ main (int argc, char *argv[]) bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); 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); variable_set ("open", VART_STRING, "wrcreat"); variable_set ("pager", VART_STRING, getenv ("PAGER")); input_init (); + lex_trace (0); for (opt = parseopt_first (argc, argv, optab); opt != EOF; opt = parseopt_next ()) switch (opt) { case 'f': source = optarg; - intr = 0; break; case 'l': bv = 0; variable_set ("lock", VART_BOOL, &bv); break; @@ -2065,43 +2077,70 @@ main (int argc, char *argv[]) break; case 'q': 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"), progname); exit (EXIT_USAGE); } 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); memset (¶m, 0, sizeof (param)); 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 (); return res; } diff --git a/src/gdbmtool.h b/src/gdbmtool.h index 8a7725c..c472276 100644 --- a/src/gdbmtool.h +++ b/src/gdbmtool.h @@ -20,12 +20,13 @@ #include "gdbm.h" #include "gdbmapp.h" #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <ctype.h> +#include <limits.h> #ifndef GDBM_ARG_UNUSED # define GDBM_ARG_UNUSED __attribute__ ((__unused__)) #endif #ifndef GDBM_PRINTFLIKE @@ -104,25 +105,73 @@ void lerror (struct locus *loc, const char *fmt, ...) void terror (const char *fmt, ...) GDBM_PRINTFLIKE (1, 2); 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); void print_prompt_at_bol (void); char *command_generator (const char *text, int state); @@ -68,45 +68,49 @@ input : /* empty */ ; 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; } else YYERROR; } - | error { end_def(); } '\n' + | error { end_def(); } eol { - if (interactive) + if (interactive ()) { yyclearin; yyerrok; } else YYERROR; } ; +eol : '\n' + | ';' + ; + arglist : /* empty */ { gdbmarglist_init (&$$, NULL); } | arg1list ; @@ -364,6 +368,12 @@ terror (const char *fmt, ...) int 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 @@ -59,70 +59,12 @@ retrieve_history (char *str) free (out); return 1; } 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; int count; }; @@ -177,13 +119,13 @@ input_history_handler (struct handler_param *param) } #define HISTFILE_PREFIX "~/." #define HISTFILE_SUFFIX "_history" static char * -get_history_file_name () +get_history_file_name (void) { static char *filename = NULL; if (!filename) { char *hname; @@ -219,17 +161,102 @@ void input_init (void) { /* Allow conditional parsing of the ~/.inputrc file. */ 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 @@ -13,23 +13,48 @@ 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" -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 input_init (void) { /* nothing */ @@ -16,189 +16,167 @@ 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 "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 \ do \ { \ 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); #undef YY_INPUT #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); void string_begin (void); void string_add (const char *s, int l); 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 |