summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS7
-rw-r--r--README5
-rw-r--r--configure.ac49
-rw-r--r--doc/gdbm.texi22
-rw-r--r--doc/gdbmtool.115
-rw-r--r--src/Makefile.am12
-rw-r--r--src/gdbmtool.c102
-rw-r--r--src/gdbmtool.h31
-rw-r--r--src/gram.y7
-rw-r--r--src/input-rl.c235
-rw-r--r--src/input-std.c43
-rw-r--r--src/lex.l134
12 files changed, 578 insertions, 84 deletions
diff --git a/NEWS b/NEWS
index a564b2e..c9ab654 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
1GNU dbm NEWS -- history of user-visible changes. 2016-07-09 1GNU dbm NEWS -- history of user-visible changes. 2016-07-12
2Copyright (C) 1990-2016 Free Software Foundation, Inc. 2Copyright (C) 1990-2016 Free Software Foundation, Inc.
3See the end of file for copying conditions. 3See the end of file for copying conditions.
4 4
@@ -31,6 +31,11 @@ Instead it sets gdbm_errno to GDBM_MALLOC_ERROR and returns NULL datum.
31 31
32** gdbm_needs_recovery 32** gdbm_needs_recovery
33 33
34* Line editing in gdbmtool
35
36The gdbmtool utility now offers the usual line-editing facilities (if
37the package has been compiled with GNU Readline.
38
34 39
35Version 1.12, 2016-05-16 40Version 1.12, 2016-05-16
36 41
diff --git a/README b/README
index 99e680a..369460a 100644
--- a/README
+++ b/README
@@ -59,6 +59,11 @@ Build gdbmexport with the gdbm library from the specified directory.
59 59
60Build gdbmexport with gdbm.h from the specified directory. 60Build gdbmexport with gdbm.h from the specified directory.
61 61
62** --without-readline
63
64Don't compile GNU Readline support. By default, configure enables
65line-editing support if GNU Readline is available on the system.
66
62* Installation 67* Installation
63 68
64 make install 69 make install
diff --git a/configure.ac b/configure.ac
index 15270b9..336e05c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -124,6 +124,55 @@ AC_SUBST(GDBM183_INCLUDEDIR)
124AM_CONDITIONAL([COMPAT_OPT], [test "$want_compat" = yes]) 124AM_CONDITIONAL([COMPAT_OPT], [test "$want_compat" = yes])
125AM_CONDITIONAL([ENABLE_EXPORT], [test "$want_export" = yes]) 125AM_CONDITIONAL([ENABLE_EXPORT], [test "$want_export" = yes])
126 126
127# Check for Curses libs.
128for lib in ncurses curses termcap
129do
130 AC_CHECK_LIB($lib, tputs, [CURSES_LIBS="-l$lib"; break])
131done
132
133AC_SUBST(CURSES_LIBS)
134# Readline
135AC_ARG_WITH([readline],
136 AC_HELP_STRING([--without-readline],
137 [do not use readline]),
138 [
139case "${withval}" in
140 yes) status_readline=yes ;;
141 no) status_readline=no ;;
142 *) AC_MSG_ERROR(bad value ${withval} for --without-readline) ;;
143esac],[status_readline=probe])
144
145AC_SUBST(READLINE_LIBS)
146
147if test "$status_readline" != "no"; then
148 dnl FIXME This should only link in the curses libraries if it's
149 dnl really needed!
150 saved_LIBS=$LIBS
151 LIBS="$LIBS $CURSES_LIBS"
152 AC_CHECK_LIB(readline, readline,
153 [status_readline=yes],
154 [if test "$status_readline" = "yes"; then
155 AC_MSG_ERROR(readline requested but does not seem to be installed)
156 else
157 status_readline=no
158 fi])
159 LIBS=$saved_LIBS
160
161 if test "$status_readline" = "yes"; then
162 AC_CHECK_HEADERS(readline/readline.h,
163 AC_DEFINE(WITH_READLINE,1,[Enable use of readline]))
164 READLINE_LIBS="-lreadline $CURSES_LIBS"
165 saved_LIBS=$LIBS
166 LIBS="$LIBS $READLINE_LIBS"
167 AC_CHECK_FUNCS(rl_completion_matches)
168 LIBS=$saved_LIBS
169 fi
170else
171 status_readline=no
172fi
173
174AM_CONDITIONAL([GDBM_COND_READLINE], [test "$status_readline" = "yes"])
175
127# Initialize the test suite. 176# Initialize the test suite.
128AC_CONFIG_TESTDIR(tests) 177AC_CONFIG_TESTDIR(tests)
129AC_CONFIG_FILES([tests/Makefile tests/atlocal po/Makefile.in]) 178AC_CONFIG_FILES([tests/Makefile tests/atlocal po/Makefile.in])
diff --git a/doc/gdbm.texi b/doc/gdbm.texi
index 4c7c5c0..d172ad7 100644
--- a/doc/gdbm.texi
+++ b/doc/gdbm.texi
@@ -1828,6 +1828,12 @@ non-interactive mode (e.g.@: when running a script), all arguments must
1828be supplied with each command, otherwise @command{gdbmtool} will report an 1828be supplied with each command, otherwise @command{gdbmtool} will report an
1829error and exit immediately. 1829error and exit immediately.
1830 1830
1831@cindex readline
1832@cindex GNU Readline
1833If the package is compiled with GNU Readline, the input line can be
1834edited (@pxref{Command Line Editing, ,
1835Command Line Editing, readline, GNU Readline Library}).
1836
1831@menu 1837@menu
1832* variables:: shell variables. 1838* variables:: shell variables.
1833* commands:: shell commands. 1839* commands:: shell commands.
@@ -2113,6 +2119,22 @@ existing ones will replace them. The word @samp{nometa} turns off
2113restoring meta-information from the dump file. 2119restoring meta-information from the dump file.
2114@end deffn 2120@end deffn
2115 2121
2122@deffn {command verb} history
2123@deffnx {command verb} history @var{count}
2124@deffnx {command verb} history @var{n} @var{count}
2125Shows the command history list with line numbers. When used without
2126arguments, shows entire history. When used with one argument,
2127displays @var{count} last commands from the history. With two
2128arguments, displays @var{count} commands starting from @var{n}th
2129command. Command numbering starts with 1.
2130
2131This command is available only if GDBM was compiled with GNU Readline.
2132The history is saved in file @file{.gdbmtool_history} in the user's
2133home directory. If this file exists upon startup, it is read to
2134populate the history. Thus, command history is preserved between
2135@command{gdbmtool} invocations.
2136@end deffn
2137
2116@deffn {command verb} list 2138@deffn {command verb} list
2117List the contents of the database. 2139List the contents of the database.
2118@end deffn 2140@end deffn
diff --git a/doc/gdbmtool.1 b/doc/gdbmtool.1
index dae881c..c479822 100644
--- a/doc/gdbmtool.1
+++ b/doc/gdbmtool.1
@@ -13,7 +13,7 @@
13.\" 13.\"
14.\" You should have received a copy of the GNU General Public License 14.\" You should have received a copy of the GNU General Public License
15.\" along with GDBM. If not, see <http://www.gnu.org/licenses/>. */ 15.\" along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
16.TH GDBMTOOL 1 "May 18, 2016" "GDBM" "GDBM User Reference" 16.TH GDBMTOOL 1 "July 12, 2016" "GDBM" "GDBM User Reference"
17.SH NAME 17.SH NAME
18gdbmtool \- examine and modify a GDBM database 18gdbmtool \- examine and modify a GDBM database
19.SH SYNOPSIS 19.SH SYNOPSIS
@@ -158,7 +158,7 @@ Delete record with the given \fIKEY\fR.
158.BR dir 158.BR dir
159Print hash directory. 159Print hash directory.
160.TP 160.TP
161\fBexport\fR, \fBe\fR \fIFILE\-NAME\fR [\fBtruncate\fR] [\fBbinary\fR|\fBascii\fR] 161\fBexport\fR \fIFILE\-NAME\fR [\fBtruncate\fR] [\fBbinary\fR|\fBascii\fR]
162Export the database to the flat file \fIFILE\-NAME\fR. This is equivalent to 162Export the database to the flat file \fIFILE\-NAME\fR. This is equivalent to
163.BR gdbm_dump (1). 163.BR gdbm_dump (1).
164 164
@@ -187,6 +187,17 @@ Print a concise command summary, showing each command letter and
187verb with its parameters and a short description of what it does. 187verb with its parameters and a short description of what it does.
188Optional arguments are enclosed in square brackets. 188Optional arguments are enclosed in square brackets.
189.TP 189.TP
190.B history
191Shows the command history list with line numbers. This command is
192available only if the program was compiled with GNU Readline.
193.TP
194\fBhistory\fR \fICOUNT\fR.
195Shows \fICOUNT\fR latest commands from the command history.
196.TP
197\fBhistory\fR \fIN\fR \fICOUNT\fR.
198Shows \fICOUNT\fR commands from the command history starting with \fIN\fRth
199command.
200.TP
190\fBimport\fR \fIFILE\-NAME\fR [\fBreplace\fR] [\fBnometa\fR] 201\fBimport\fR \fIFILE\-NAME\fR [\fBreplace\fR] [\fBnometa\fR]
191Import data from a flat dump file \fIFILE\-NAME\fR. 202Import data from a flat dump file \fIFILE\-NAME\fR.
192If the 203If the
diff --git a/src/Makefile.am b/src/Makefile.am
index 6a05634..b55deb6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -79,7 +79,11 @@ libgdbmapp_a_SOURCES =\
79# Programs 79# Programs
80bin_PROGRAMS = gdbmtool gdbm_load gdbm_dump 80bin_PROGRAMS = gdbmtool gdbm_load gdbm_dump
81 81
82gdbmtool_LDADD = ./libgdbmapp.a ./libgdbm.la 82gdbmtool_LDADD = \
83 ./libgdbmapp.a\
84 ./libgdbm.la\
85 @READLINE_LIBS@
86
83gdbmtool_SOURCES = \ 87gdbmtool_SOURCES = \
84 datconv.c\ 88 datconv.c\
85 gram.y\ 89 gram.y\
@@ -89,6 +93,12 @@ gdbmtool_SOURCES = \
89 var.c\ 93 var.c\
90 util.c 94 util.c
91 95
96if GDBM_COND_READLINE
97 gdbmtool_SOURCES += input-rl.c
98else
99 gdbmtool_SOURCES += input-std.c
100endif
101
92AM_YFLAGS = -dtv 102AM_YFLAGS = -dtv
93#AM_LFLAGS = -d 103#AM_LFLAGS = -d
94 104
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 65b6740..2d57cbc 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -323,20 +323,6 @@ get_screen_lines ()
323#endif 323#endif
324 return -1; 324 return -1;
325} 325}
326
327
328#define ARG_UNUSED __attribute__ ((__unused__))
329
330#define NARGS 5
331
332struct handler_param
333{
334 int argc;
335 struct gdbmarg **argv;
336 FILE *fp;
337 void *data;
338};
339
340 326
341/* Open database */ 327/* Open database */
342void 328void
@@ -751,7 +737,7 @@ quit_handler (struct handler_param *param ARG_UNUSED)
751{ 737{
752 if (gdbm_file != NULL) 738 if (gdbm_file != NULL)
753 gdbm_close (gdbm_file); 739 gdbm_close (gdbm_file);
754 740 input_done ();
755 exit (EXIT_OK); 741 exit (EXIT_OK);
756} 742}
757 743
@@ -891,6 +877,8 @@ struct argdef
891 int ds; 877 int ds;
892}; 878};
893 879
880#define NARGS 5
881
894struct command 882struct command
895{ 883{
896 char *name; /* Command name */ 884 char *name; /* Command name */
@@ -902,7 +890,6 @@ struct command
902 struct argdef args[NARGS]; 890 struct argdef args[NARGS];
903 char *doc; 891 char *doc;
904}; 892};
905
906 893
907struct command command_tab[] = { 894struct command command_tab[] = {
908#define S(s) #s, sizeof (#s) - 1 895#define S(s) #s, sizeof (#s) - 1
@@ -1007,6 +994,13 @@ struct command command_tab[] = {
1007 NULL, open_handler, NULL, 994 NULL, open_handler, NULL,
1008 { { "FILE", GDBM_ARG_STRING }, { NULL } }, 995 { { "FILE", GDBM_ARG_STRING }, { NULL } },
1009 N_("open new database") }, 996 N_("open new database") },
997#ifdef WITH_READLINE
998 { S(history), T_CMD,
999 input_history_begin, input_history_handler, NULL,
1000 { { N_("[FROM]"), GDBM_ARG_STRING },
1001 { N_("[COUNT]"), GDBM_ARG_STRING },
1002 { NULL } }, N_("show input history") },
1003#endif
1010#undef S 1004#undef S
1011 { 0 } 1005 { 0 }
1012}; 1006};
@@ -1026,6 +1020,39 @@ sort_commands ()
1026 sizeof (command_tab[0]), cmdcmp); 1020 sizeof (command_tab[0]), cmdcmp);
1027} 1021}
1028 1022
1023/* Generator function for command completion. STATE lets us know whether
1024 to start from scratch; without any state (i.e. STATE == 0), then we
1025 start at the top of the list. */
1026char *
1027command_generator (const char *text, int state)
1028{
1029 const char *name;
1030 static int len;
1031 static struct command *cmd;
1032
1033 /* If this is a new word to complete, initialize now. This includes
1034 saving the length of TEXT for efficiency, and initializing the index
1035 variable to 0. */
1036 if (!state)
1037 {
1038 cmd = command_tab;
1039 len = strlen (text);
1040 }
1041
1042 if (!cmd->name)
1043 return NULL;
1044
1045 /* Return the next name which partially matches from the command list. */
1046 while ((name = cmd->name))
1047 {
1048 cmd++;
1049 if (strncmp (name, text, len) == 0)
1050 return strdup (name);
1051 }
1052
1053 /* If no names matched, then return NULL. */
1054 return NULL;
1055}
1029 1056
1030/* ? - help handler */ 1057/* ? - help handler */
1031#define CMDCOLS 30 1058#define CMDCOLS 30
@@ -1174,7 +1201,7 @@ gdbmarg_kvpair (struct kvpair *kvp, struct locus *loc)
1174} 1201}
1175 1202
1176struct slist * 1203struct slist *
1177slist_new (char *s) 1204slist_new_s (char *s)
1178{ 1205{
1179 struct slist *lp = emalloc (sizeof (*lp)); 1206 struct slist *lp = emalloc (sizeof (*lp));
1180 lp->next = NULL; 1207 lp->next = NULL;
@@ -1182,6 +1209,21 @@ slist_new (char *s)
1182 return lp; 1209 return lp;
1183} 1210}
1184 1211
1212struct slist *
1213slist_new (char const *s)
1214{
1215 return slist_new_s (estrdup (s));
1216}
1217
1218struct slist *
1219slist_new_l (char const *s, size_t l)
1220{
1221 char *copy = emalloc (l + 1);
1222 memcpy (copy, s, l);
1223 copy[l] = 0;
1224 return slist_new_s (copy);
1225}
1226
1185void 1227void
1186slist_free (struct slist *lp) 1228slist_free (struct slist *lp)
1187{ 1229{
@@ -1193,6 +1235,21 @@ slist_free (struct slist *lp)
1193 lp = next; 1235 lp = next;
1194 } 1236 }
1195} 1237}
1238
1239void
1240slist_insert (struct slist **where, struct slist *what)
1241{
1242 if (*where)
1243 {
1244 while (what->next)
1245 what = what->next;
1246 what->next = (*where)->next;
1247 (*where)->next = what;
1248 }
1249 else
1250 what->next = NULL;
1251 *where = what;
1252}
1196 1253
1197struct kvpair * 1254struct kvpair *
1198kvpair_string (struct locus *loc, char *val) 1255kvpair_string (struct locus *loc, char *val)
@@ -1216,7 +1273,6 @@ kvpair_list (struct locus *loc, struct slist *s)
1216 return p; 1273 return p;
1217} 1274}
1218 1275
1219
1220static void 1276static void
1221kvlist_free (struct kvpair *kvp) 1277kvlist_free (struct kvpair *kvp)
1222{ 1278{
@@ -1534,6 +1590,7 @@ main (int argc, char *argv[])
1534 int opt; 1590 int opt;
1535 int bv; 1591 int bv;
1536 int norc = 0; 1592 int norc = 0;
1593 int res;
1537 char *source = "-"; 1594 char *source = "-";
1538 1595
1539 set_progname (argv[0]); 1596 set_progname (argv[0]);
@@ -1545,15 +1602,18 @@ main (int argc, char *argv[])
1545 textdomain (PACKAGE); 1602 textdomain (PACKAGE);
1546 1603
1547 sort_commands (); 1604 sort_commands ();
1548 1605
1549 /* Initialize variables. */ 1606 /* Initialize variables. */
1550 intr = isatty (0); 1607 intr = isatty (0);
1608 interactive = intr; /* Used early by input_init */
1551 dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1); 1609 dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
1552 dsdef[DS_CONTENT] = dsegm_new_field (datadef_lookup ("string"), NULL, 1); 1610 dsdef[DS_CONTENT] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
1553 1611
1554 variable_set ("open", VART_STRING, "wrcreat"); 1612 variable_set ("open", VART_STRING, "wrcreat");
1555 variable_set ("pager", VART_STRING, getenv ("PAGER")); 1613 variable_set ("pager", VART_STRING, getenv ("PAGER"));
1556 1614
1615 input_init ();
1616
1557 for (opt = parseopt_first (argc, argv, optab); 1617 for (opt = parseopt_first (argc, argv, optab);
1558 opt != EOF; 1618 opt != EOF;
1559 opt = parseopt_next ()) 1619 opt = parseopt_next ())
@@ -1640,5 +1700,7 @@ main (int argc, char *argv[])
1640 1700
1641 if (setsource (source, intr)) 1701 if (setsource (source, intr))
1642 exit (EXIT_FATAL); 1702 exit (EXIT_FATAL);
1643 return yyparse (); 1703 res = yyparse ();
1704 input_done ();
1705 return res;
1644} 1706}
diff --git a/src/gdbmtool.h b/src/gdbmtool.h
index 84f1409..d0e9aa0 100644
--- a/src/gdbmtool.h
+++ b/src/gdbmtool.h
@@ -24,6 +24,8 @@
24#include <stdarg.h> 24#include <stdarg.h>
25#include <ctype.h> 25#include <ctype.h>
26 26
27#define ARG_UNUSED __attribute__ ((__unused__))
28
27/* Position in input file */ 29/* Position in input file */
28struct point 30struct point
29{ 31{
@@ -94,7 +96,7 @@ void lerror (struct locus *loc, const char *fmt, ...);
94 96
95void terror (const char *fmt, ...); 97void terror (const char *fmt, ...);
96 98
97void print_prompt (void); 99char *make_prompt (void);
98 100
99int setsource (const char *filename, int intr); 101int setsource (const char *filename, int intr);
100 102
@@ -104,6 +106,17 @@ extern int open_mode;
104 106
105#define GDBMTOOLRC ".gdbmtoolrc" 107#define GDBMTOOLRC ".gdbmtoolrc"
106#define GDBMTOOL_DEFFILE "junk.gdbm" 108#define GDBMTOOL_DEFFILE "junk.gdbm"
109
110ssize_t input_read (FILE *fp, char *buf, size_t size);
111void input_init (void);
112void input_done (void);
113
114struct handler_param;
115void input_history_handler (struct handler_param *param);
116int input_history_begin (struct handler_param *param, size_t *exp_count);
117
118void print_prompt_at_bol (void);
119char *command_generator (const char *text, int state);
107 120
108 121
109struct slist 122struct slist
@@ -112,8 +125,11 @@ struct slist
112 char *str; 125 char *str;
113}; 126};
114 127
115struct slist *slist_new (char *s); 128struct slist *slist_new (char const *s);
129struct slist *slist_new_s (char *s);
130struct slist *slist_new_l (char const *s, size_t l);
116void slist_free (struct slist *); 131void slist_free (struct slist *);
132void slist_insert (struct slist **where, struct slist *what);
117 133
118#define KV_STRING 0 134#define KV_STRING 0
119#define KV_LIST 1 135#define KV_LIST 1
@@ -161,6 +177,14 @@ struct gdbmarglist
161 struct gdbmarg *head, *tail; 177 struct gdbmarg *head, *tail;
162}; 178};
163 179
180struct handler_param
181{
182 int argc;
183 struct gdbmarg **argv;
184 FILE *fp;
185 void *data;
186};
187
164void gdbmarglist_init (struct gdbmarglist *, struct gdbmarg *); 188void gdbmarglist_init (struct gdbmarglist *, struct gdbmarg *);
165void gdbmarglist_add (struct gdbmarglist *, struct gdbmarg *); 189void gdbmarglist_add (struct gdbmarglist *, struct gdbmarg *);
166void gdbmarglist_free (struct gdbmarglist *lst); 190void gdbmarglist_free (struct gdbmarglist *lst);
@@ -262,3 +286,6 @@ char *mkfilename (const char *dir, const char *file, const char *suf);
262char *tildexpand (char *s); 286char *tildexpand (char *s);
263int vgetyn (const char *prompt, va_list ap); 287int vgetyn (const char *prompt, va_list ap);
264int getyn (const char *prompt, ...); 288int getyn (const char *prompt, ...);
289
290int getnum (int *pnum, char *arg, char **endp);
291int get_screen_lines (void);
diff --git a/src/gram.y b/src/gram.y
index 9a6e3c2..2f6d7c0 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -168,13 +168,12 @@ value : string
168 168
169slist : string 169slist : string
170 { 170 {
171 $$.head = $$.tail = slist_new ($1); 171 $$.head = $$.tail = slist_new_s ($1);
172 } 172 }
173 | slist ',' string 173 | slist ',' string
174 { 174 {
175 struct slist *s = slist_new ($3); 175 struct slist *s = slist_new_s ($3);
176 $1.tail->next = s; 176 slist_insert (&$1.tail, s);
177 $1.tail = s;
178 $$ = $1; 177 $$ = $1;
179 } 178 }
180 ; 179 ;
diff --git a/src/input-rl.c b/src/input-rl.c
new file mode 100644
index 0000000..f435ed4
--- a/dev/null
+++ b/src/input-rl.c
@@ -0,0 +1,235 @@
1/* This file is part of GDBM, the GNU data base manager.
2 Copyright (C) 2016 Free Software Foundation, Inc.
3
4 GDBM is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GDBM is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "gdbmtool.h"
18#include <readline/readline.h>
19#include <readline/history.h>
20
21static char *pre_input_line;
22
23static int
24pre_input (void)
25{
26 if (pre_input_line)
27 {
28 rl_insert_text (pre_input_line);
29 free (pre_input_line);
30 pre_input_line = NULL;
31 rl_redisplay ();
32 }
33 return 0;
34}
35
36static int
37retrieve_history (char *str)
38{
39 char *out;
40 int rc;
41
42 rc = history_expand (str, &out);
43 switch (rc)
44 {
45 case -1:
46 yyerror (out);
47 free (out);
48 return 1;
49
50 case 0:
51 break;
52
53 case 1:
54 pre_input_line = out;
55 return 1;
56
57 case 2:
58 printf ("%s\n", out);
59 free (out);
60 return 1;
61 }
62 return 0;
63}
64
65ssize_t
66input_read (FILE *fp, char *buf, size_t size)
67{
68 static char *input_line;
69 static size_t input_length;
70 static size_t input_off;
71#define input_ptr() (input_line + input_off)
72#define input_size() (input_length - input_off)
73
74 if (interactive)
75 {
76 size_t len = input_size ();
77 if (!len)
78 {
79 if (input_line)
80 {
81 newline:
82 free (input_line);
83 input_line = NULL;
84 buf[0] = '\n';
85 return 1;
86 }
87 else
88 {
89 char *prompt;
90 again:
91 prompt = make_prompt ();
92 input_line = readline (prompt);
93 free (prompt);
94 if (!input_line)
95 return 0;
96 input_length = strlen (input_line);
97 input_off = 0;
98 if (input_length)
99 {
100 if (retrieve_history (input_line))
101 {
102 free (input_line);
103 goto again;
104 }
105 }
106 else
107 goto newline;
108 len = input_size ();
109 add_history (input_line);
110 }
111 }
112
113 if (len > size)
114 len = size;
115 memcpy (buf, input_ptr (), len);
116 input_off += len;
117
118 return len;
119 }
120 return fread (buf, 1, size, fp);
121}
122
123struct history_param
124{
125 int from;
126 int count;
127};
128
129int
130input_history_begin (struct handler_param *param, size_t *exp_count)
131{
132 struct history_param *p;
133 int from = 0, count = history_length;
134
135 switch (param->argc)
136 {
137 case 1:
138 if (getnum (&count, param->argv[0]->v.string, NULL))
139 return 1;
140 if (count > history_length)
141 count = history_length;
142 else
143 from = history_length - count;
144 break;
145
146 case 2:
147 if (getnum (&from, param->argv[0]->v.string, NULL))
148 return 1;
149 if (from)
150 --from;
151 if (getnum (&count, param->argv[1]->v.string, NULL))
152 return 1;
153
154 if (count > history_length)
155 count = history_length;
156 }
157 p = emalloc (sizeof *p);
158 p->from = from;
159 p->count = count;
160 param->data = p;
161 if (exp_count)
162 *exp_count = count;
163 return 0;
164}
165
166void
167input_history_handler (struct handler_param *param)
168{
169 struct history_param *p = param->data;
170 int i;
171 HIST_ENTRY **hlist;
172 FILE *fp = param->fp;
173
174 hlist = history_list ();
175 for (i = 0; i < p->count; i++)
176 fprintf (fp, "%4d) %s\n", p->from + i + 1, hlist[p->from + i]->line);
177}
178
179#define HISTFILE_PREFIX "~/."
180#define HISTFILE_SUFFIX "_history"
181
182static char *
183get_history_file_name ()
184{
185 static char *filename = NULL;
186
187 if (!filename)
188 {
189 char *hname;
190
191 hname = emalloc (sizeof HISTFILE_PREFIX + strlen (rl_readline_name) +
192 sizeof HISTFILE_SUFFIX - 1);
193 strcpy (hname, HISTFILE_PREFIX);
194 strcat (hname, rl_readline_name);
195 strcat (hname, HISTFILE_SUFFIX);
196 filename = tildexpand (hname);
197 free (hname);
198 }
199 return filename;
200}
201
202static char **
203shell_completion (const char *text, int start, int end)
204{
205 char **matches;
206
207 matches = (char **) NULL;
208
209 /* If this word is at the start of the line, then it is a command
210 to complete. Otherwise it is the name of a file in the current
211 directory. */
212 if (start == 0)
213 matches = rl_completion_matches (text, command_generator);
214
215 return (matches);
216}
217
218void
219input_init (void)
220{
221 /* Allow conditional parsing of the ~/.inputrc file. */
222 rl_readline_name = (char *) progname;
223 rl_attempted_completion_function = shell_completion;
224 rl_pre_input_hook = pre_input;
225 if (interactive)
226 read_history (get_history_file_name ());
227}
228
229void
230input_done (void)
231{
232 if (interactive)
233 write_history (get_history_file_name ());
234}
235
diff --git a/src/input-std.c b/src/input-std.c
new file mode 100644
index 0000000..4508368
--- a/dev/null
+++ b/src/input-std.c
@@ -0,0 +1,43 @@
1/* This file is part of GDBM, the GNU data base manager.
2 Copyright (C) 2016 Free Software Foundation, Inc.
3
4 GDBM is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GDBM is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "gdbmtool.h"
18
19ssize_t
20input_read (FILE *fp, char *buf, size_t size)
21{
22 if (interactive)
23 {
24 print_prompt_at_bol ();
25 if (fgets (buf, size, fp) == NULL)
26 return 0;
27 return strlen (buf);
28 }
29 return fread (buf, 1, size, fp);
30}
31
32void
33input_init (void)
34{
35 /* nothing */
36}
37
38void
39input_done (void)
40{
41 /* nothing */
42}
43
diff --git a/src/lex.l b/src/lex.l
index 9c2c5f8..236474d 100644
--- a/src/lex.l
+++ b/src/lex.l
@@ -46,7 +46,7 @@ advance_line ()
46#define YY_INPUT(buf,result,max_size) \ 46#define YY_INPUT(buf,result,max_size) \
47 do \ 47 do \
48 { \ 48 { \
49 result = read_input (buf, max_size); \ 49 result = input_read (yyin, buf, max_size); \
50 } \ 50 } \
51 while (0); 51 while (0);
52 52
@@ -56,8 +56,6 @@ void string_addc (int c);
56char *string_end (void); 56char *string_end (void);
57int unescape (int c); 57int unescape (int c);
58 58
59static ssize_t read_input (char *buf, size_t size);
60
61struct context /* Input context */ 59struct context /* Input context */
62{ 60{
63 struct context *parent; /* Pointer to the parent context */ 61 struct context *parent; /* Pointer to the parent context */
@@ -315,18 +313,16 @@ end_def (void)
315 BEGIN (INITIAL); 313 BEGIN (INITIAL);
316} 314}
317 315
318static ssize_t 316void
319read_input (char *buf, size_t size) 317print_prompt_at_bol (void)
320{ 318{
321 if (interactive) 319 if (YY_AT_BOL ())
322 { 320 {
323 if (YY_AT_BOL ()) 321 char *s = make_prompt ();
324 print_prompt (); 322 fputs (s, stdout);
325 if (fgets (buf, size, yyin) == NULL) 323 fflush (stdout);
326 return 0; 324 free (s);
327 return strlen (buf);
328 } 325 }
329 return fread (buf, 1, size, yyin);
330} 326}
331 327
332 328
@@ -453,44 +449,40 @@ lerror (struct locus *loc, const char *fmt, ...)
453} 449}
454 450
455 451
456struct prompt_exp; 452static struct slist *
457 453pe_file_name (void)
458void
459pe_file_name (struct prompt_exp *p)
460{ 454{
461 if (file_name) 455 return file_name ? slist_new (file_name) : NULL;
462 fwrite (file_name, strlen (file_name), 1, stdout);
463} 456}
464 457
465void 458static struct slist *
466pe_program_name (struct prompt_exp *p) 459pe_program_name (void)
467{ 460{
468 fwrite (progname, strlen (progname), 1, stdout); 461 return slist_new (progname);
469} 462}
470 463
471void 464static struct slist *
472pe_package_name (struct prompt_exp *p) 465pe_package_name (void)
473{ 466{
474 fwrite (PACKAGE_NAME, sizeof (PACKAGE_NAME) - 1, 1, stdout); 467 return slist_new (PACKAGE_NAME);
475} 468}
476 469
477void 470static struct slist *
478pe_program_version (struct prompt_exp *p) 471pe_program_version (void)
479{ 472{
480 fwrite (PACKAGE_VERSION, sizeof (PACKAGE_VERSION) - 1, 1, stdout); 473 return slist_new (PACKAGE_VERSION);
481} 474}
482 475
483void 476static struct slist *
484pe_space (struct prompt_exp *p) 477pe_space (void)
485{ 478{
486 fwrite (" ", 1, 1, stdout); 479 return slist_new (" ");
487} 480}
488 481
489struct prompt_exp 482struct prompt_exp
490{ 483{
491 int ch; 484 int ch;
492 void (*fun) (struct prompt_exp *); 485 struct slist *(*fun) (void);
493 char *cache;
494}; 486};
495 487
496struct prompt_exp prompt_exp[] = { 488struct prompt_exp prompt_exp[] = {
@@ -502,8 +494,8 @@ struct prompt_exp prompt_exp[] = {
502 { 0 } 494 { 0 }
503}; 495};
504 496
505static void 497static int
506expand_char (int c) 498expand_char (int c, struct slist **tailp)
507{ 499{
508 struct prompt_exp *p; 500 struct prompt_exp *p;
509 501
@@ -513,58 +505,92 @@ expand_char (int c)
513 { 505 {
514 if (c == p->ch) 506 if (c == p->ch)
515 { 507 {
516 if (p->cache) 508 struct slist *s = p->fun ();
517 free (p->cache); 509 if (s)
518 p->fun (p); 510 slist_insert (tailp, s);
519 return; 511 return 0;
520 } 512 }
521 } 513 }
522 } 514 }
523 putchar ('%'); 515 return 1;
524 putchar (c);
525} 516}
526 517
527char const * 518char const *
528psname () 519psname (void)
529{ 520{
530 if (YYSTATE == DEF || YYSTATE == MLSTR) 521 if (YYSTATE == DEF || YYSTATE == MLSTR)
531 return "ps2"; 522 return "ps2";
532 return "ps1"; 523 return "ps1";
533} 524}
534 525
535void 526char *
536print_prompt () 527make_prompt (void)
537{ 528{
538 const char *s; 529 const char *s;
539 const char *prompt; 530 const char *prompt;
540 531 struct slist *head = NULL, *tail = NULL, *p;
532 char *ret, *end;
533 size_t len;
534
541 switch (variable_get (psname (), VART_STRING, (void *) &prompt)) 535 switch (variable_get (psname (), VART_STRING, (void *) &prompt))
542 { 536 {
543 case VAR_OK: 537 case VAR_OK:
544 break; 538 break;
545 539
546 case VAR_ERR_NOTSET: 540 case VAR_ERR_NOTSET:
547 return; 541 return NULL;
548 542
549 default: 543 default:
550 abort (); 544 abort ();
551 } 545 }
552 546
553 for (s = prompt; *s; s++) 547 for (s = prompt; *s; )
554 { 548 {
555 if (*s == '%') 549 if (*s == '%' && s[1])
556 { 550 {
557 if (!*++s) 551 if (s > prompt)
552 {
553 slist_insert (&tail, slist_new_l (prompt, s - prompt));
554 if (!head)
555 head = tail;
556 }
557 if (expand_char (s[1], &tail) == 0)
558 { 558 {
559 putchar ('%'); 559 if (!head)
560 break; 560 head = tail;
561 prompt = s + 2;
561 } 562 }
562 expand_char (*s); 563 else
564 prompt = s;
565 s += 2;
563 } 566 }
564 else 567 else
565 putchar (*s); 568 ++s;
569 }
570
571 if (s > prompt)
572 {
573 slist_insert (&tail, slist_new_l (prompt, s - prompt));
574 if (!head)
575 head = tail;
566 } 576 }
567 577
568 fflush (stdout); 578 len = 0;
579 for (p = head; p; p = p->next)
580 len += strlen (p->str);
581
582 ret = emalloc (len + 1);
583 end = ret;
584 for (p = head; p; p = p->next)
585 {
586 s = p->str;
587 while (*s)
588 *end++ = *s++;
589 }
590 *end = 0;
591
592 slist_free (head);
593
594 return ret;
569} 595}
570 596

Return to:

Send suggestions and report system problems to the System administrator.