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,7 +1,7 @@
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
5Please send gdbm bug reports to <bug-gdbm@gnu.org>. 5Please send gdbm bug reports to <bug-gdbm@gnu.org>.
6 6
7Version 1.12.90 (Git) 7Version 1.12.90 (Git)
@@ -28,12 +28,17 @@ Instead it sets gdbm_errno to GDBM_MALLOC_ERROR and returns NULL datum.
28** gdbm_last_errno 28** gdbm_last_errno
29 29
30** gdbm_clear_error 30** gdbm_clear_error
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
37* New configuration variable COMPATINCLUDEDIR 42* New configuration variable COMPATINCLUDEDIR
38 43
39When used with --enable-libgdbm-compat, this variable points to the 44When used with --enable-libgdbm-compat, this variable points to the
diff --git a/README b/README
index 99e680a..369460a 100644
--- a/README
+++ b/README
@@ -56,12 +56,17 @@ a loader argument valid for the use with cc(1), e.g.: -lgdbm-1.8.
56Build gdbmexport with the gdbm library from the specified directory. 56Build gdbmexport with the gdbm library from the specified directory.
57 57
58** --gdbm183-includedir=DIR 58** --gdbm183-includedir=DIR
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
65 70
66* Bug reporting 71* Bug reporting
67 72
diff --git a/configure.ac b/configure.ac
index 15270b9..336e05c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -121,12 +121,61 @@ AC_CHECK_MEMBERS([struct stat.st_blksize])
121AC_SUBST(GDBM183_LIBRARY) 121AC_SUBST(GDBM183_LIBRARY)
122AC_SUBST(GDBM183_LIBDIR) 122AC_SUBST(GDBM183_LIBDIR)
123AC_SUBST(GDBM183_INCLUDEDIR) 123AC_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])
130AM_MISSING_PROG([AUTOM4TE], [autom4te]) 179AM_MISSING_PROG([AUTOM4TE], [autom4te])
131 180
132AC_CONFIG_FILES([Makefile 181AC_CONFIG_FILES([Makefile
diff --git a/doc/gdbm.texi b/doc/gdbm.texi
index 4c7c5c0..d172ad7 100644
--- a/doc/gdbm.texi
+++ b/doc/gdbm.texi
@@ -1825,12 +1825,18 @@ data? @kbd{3}
1825 1825
1826However, such prompting is possible only in interactive mode. In 1826However, such prompting is possible only in interactive mode. In
1827non-interactive mode (e.g.@: when running a script), all arguments must 1827non-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.
1834* definitions:: how to define structured data. 1840* definitions:: how to define structured data.
1835* startup files:: 1841* startup files::
1836@end menu 1842@end menu
@@ -2110,12 +2116,28 @@ Import data from a flat dump file @var{file-name}
2110(@pxref{Flat files}). If the word @samp{replace} is given 2116(@pxref{Flat files}). If the word @samp{replace} is given
2111as an argument, any records with the same keys as the already 2117as an argument, any records with the same keys as the already
2112existing ones will replace them. The word @samp{nometa} turns off 2118existing 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
2119 2141
2120@deffn {command verb} next [@var{key}] 2142@deffn {command verb} next [@var{key}]
2121Sequential access: fetch and display the next record. If the @var{key} is 2143Sequential access: fetch and display the next record. If the @var{key} is
diff --git a/doc/gdbmtool.1 b/doc/gdbmtool.1
index dae881c..c479822 100644
--- a/doc/gdbmtool.1
+++ b/doc/gdbmtool.1
@@ -10,13 +10,13 @@
10.\" but WITHOUT ANY WARRANTY; without even the implied warranty of 10.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
11.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12.\" GNU General Public License for more details. 12.\" GNU General Public License for more details.
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
20\fBgdbmtool\fR [\fB\-lmNnqrs\fR] [\fB\-b\fR \fISIZE\fR] [\fB\-c\fR \fISIZE\fR]\ 20\fBgdbmtool\fR [\fB\-lmNnqrs\fR] [\fB\-b\fR \fISIZE\fR] [\fB\-c\fR \fISIZE\fR]\
21 [\fB\-f\fR \fIFILE\fR] [\fB\-\-block\-size\fR=\fISIZE\fR] 21 [\fB\-f\fR \fIFILE\fR] [\fB\-\-block\-size\fR=\fISIZE\fR]
22 [\fB\-\-cache\-size\fR=\fISIZE\fR] [\fB\-\-file\fR \fIFILE\fR]\ 22 [\fB\-\-cache\-size\fR=\fISIZE\fR] [\fB\-\-file\fR \fIFILE\fR]\
@@ -155,13 +155,13 @@ Print the current bucket.
155\fBdelete\fR \fIKEY\fR 155\fBdelete\fR \fIKEY\fR
156Delete record with the given \fIKEY\fR. 156Delete record with the given \fIKEY\fR.
157.TP 157.TP
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
165This command will not overwrite an existing file, unless the 165This command will not overwrite an existing file, unless the
166.B truncate 166.B truncate
167parameter is also given. Another optional parameter determines the type of 167parameter is also given. Another optional parameter determines the type of
@@ -184,12 +184,23 @@ Print file header.
184.TP 184.TP
185.BR help " or " ? 185.BR help " or " ?
186Print a concise command summary, showing each command letter and 186Print 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
193.B replace 204.B replace
194argument is given, any records with the same keys as the already 205argument is given, any records with the same keys as the already
195existing ones will replace them. The 206existing ones will replace them. The
diff --git a/src/Makefile.am b/src/Makefile.am
index 6a05634..b55deb6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -76,21 +76,31 @@ libgdbmapp_a_SOURCES =\
76 parseopt.c\ 76 parseopt.c\
77 progname.c 77 progname.c
78 78
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\
86 lex.l\ 90 lex.l\
87 gdbmtool.h\ 91 gdbmtool.h\
88 gdbmtool.c\ 92 gdbmtool.c\
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
95gdbm_load_LDADD = ./libgdbmapp.a ./libgdbm.la 105gdbm_load_LDADD = ./libgdbmapp.a ./libgdbm.la
96gdbm_dump_LDADD = ./libgdbmapp.a ./libgdbm.la 106gdbm_dump_LDADD = ./libgdbmapp.a ./libgdbm.la
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 65b6740..2d57cbc 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -320,26 +320,12 @@ get_screen_lines ()
320 const char *lines = getenv ("LINES"); 320 const char *lines = getenv ("LINES");
321 if (lines) 321 if (lines)
322 return strtol (lines, NULL, 10); 322 return strtol (lines, NULL, 10);
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
343open_handler (struct handler_param *param) 329open_handler (struct handler_param *param)
344{ 330{
345 if (opendb (param->argv[0]->v.string) == 0) 331 if (opendb (param->argv[0]->v.string) == 0)
@@ -748,13 +734,13 @@ list_handler (struct handler_param *param)
748/* quit - quit the program */ 734/* quit - quit the program */
749void 735void
750quit_handler (struct handler_param *param ARG_UNUSED) 736quit_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
758/* export FILE [truncate] - export to a flat file format */ 744/* export FILE [truncate] - export to a flat file format */
759void 745void
760export_handler (struct handler_param *param) 746export_handler (struct handler_param *param)
@@ -888,24 +874,25 @@ struct argdef
888{ 874{
889 char *name; 875 char *name;
890 int type; 876 int type;
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 */
897 size_t len; /* Name length */ 885 size_t len; /* Name length */
898 int tok; 886 int tok;
899 int (*begin) (struct handler_param *param, size_t *); 887 int (*begin) (struct handler_param *param, size_t *);
900 void (*handler) (struct handler_param *param); 888 void (*handler) (struct handler_param *param);
901 void (*end) (void *data); 889 void (*end) (void *data);
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
909 { S(count), T_CMD, 896 { S(count), T_CMD,
910 checkdb, count_handler, NULL, 897 checkdb, count_handler, NULL,
911 { { NULL } }, N_("count (number of entries)") }, 898 { { NULL } }, N_("count (number of entries)") },
@@ -1004,12 +991,19 @@ struct command command_tab[] = {
1004 NULL, close_handler, NULL, 991 NULL, close_handler, NULL,
1005 { { NULL } }, N_("close the database") }, 992 { { NULL } }, N_("close the database") },
1006 { S(open), T_CMD, 993 { S(open), T_CMD,
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};
1013 1007
1014static int 1008static int
1015cmdcmp (const void *a, const void *b) 1009cmdcmp (const void *a, const void *b)
@@ -1023,12 +1017,45 @@ void
1023sort_commands () 1017sort_commands ()
1024{ 1018{
1025 qsort (command_tab, sizeof (command_tab) / sizeof (command_tab[0]) - 1, 1019 qsort (command_tab, sizeof (command_tab) / sizeof (command_tab[0]) - 1,
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
1032 1059
1033int 1060int
1034help_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count) 1061help_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
@@ -1171,31 +1198,61 @@ gdbmarg_kvpair (struct kvpair *kvp, struct locus *loc)
1171 arg->loc = *loc; 1198 arg->loc = *loc;
1172 arg->v.kvpair = kvp; 1199 arg->v.kvpair = kvp;
1173 return arg; 1200 return arg;
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;
1181 lp->str = s; 1208 lp->str = 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{
1188 while (lp) 1230 while (lp)
1189 { 1231 {
1190 struct slist *next = lp->next; 1232 struct slist *next = lp->next;
1191 free (lp->str); 1233 free (lp->str);
1192 free (lp); 1234 free (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)
1199{ 1256{
1200 struct kvpair *p = ecalloc (1, sizeof (*p)); 1257 struct kvpair *p = ecalloc (1, sizeof (*p));
1201 p->type = KV_STRING; 1258 p->type = KV_STRING;
@@ -1213,13 +1270,12 @@ kvpair_list (struct locus *loc, struct slist *s)
1213 if (loc) 1270 if (loc)
1214 p->loc = *loc; 1271 p->loc = *loc;
1215 p->val.l = s; 1272 p->val.l = 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{
1223 while (kvp) 1279 while (kvp)
1224 { 1280 {
1225 struct kvpair *next = kvp->next; 1281 struct kvpair *next = kvp->next;
@@ -1531,32 +1587,36 @@ int
1531main (int argc, char *argv[]) 1587main (int argc, char *argv[])
1532{ 1588{
1533 int intr; 1589 int intr;
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]);
1540 1597
1541#ifdef HAVE_SETLOCALE 1598#ifdef HAVE_SETLOCALE
1542 setlocale (LC_ALL, ""); 1599 setlocale (LC_ALL, "");
1543#endif 1600#endif
1544 bindtextdomain (PACKAGE, LOCALEDIR); 1601 bindtextdomain (PACKAGE, LOCALEDIR);
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 ())
1560 switch (opt) 1620 switch (opt)
1561 { 1621 {
1562 case 'f': 1622 case 'f':
@@ -1637,8 +1697,10 @@ main (int argc, char *argv[])
1637 /* Welcome message. */ 1697 /* Welcome message. */
1638 if (intr && !variable_is_true ("quiet")) 1698 if (intr && !variable_is_true ("quiet"))
1639 printf (_("\nWelcome to the gdbm tool. Type ? for help.\n\n")); 1699 printf (_("\nWelcome to the gdbm tool. Type ? for help.\n\n"));
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
@@ -21,12 +21,14 @@
21#include "gdbmapp.h" 21#include "gdbmapp.h"
22#include <stdlib.h> 22#include <stdlib.h>
23#include <stdio.h> 23#include <stdio.h>
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{
30 char *file; /* file name */ 32 char *file; /* file name */
31 unsigned line; /* line number */ 33 unsigned line; /* line number */
32 unsigned col; /* column number */ 34 unsigned col; /* column number */
@@ -91,32 +93,46 @@ typedef struct locus gdbm_yyltype_t;
91 93
92void vlerror (struct locus *loc, const char *fmt, va_list ap); 94void vlerror (struct locus *loc, const char *fmt, va_list ap);
93void lerror (struct locus *loc, const char *fmt, ...); 95void 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
101extern char *file_name; 103extern char *file_name;
102extern int interactive; 104extern int interactive;
103extern int open_mode; 105extern 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
110{ 123{
111 struct slist *next; 124 struct slist *next;
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
120 136
121struct kvpair 137struct kvpair
122{ 138{
@@ -158,12 +174,20 @@ struct gdbmarg
158/* List of arguments */ 174/* List of arguments */
159struct gdbmarglist 175struct gdbmarglist
160{ 176{
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);
167 191
168struct gdbmarg *gdbmarg_string (char *, struct locus *); 192struct gdbmarg *gdbmarg_string (char *, struct locus *);
169struct gdbmarg *gdbmarg_datum (datum *, struct locus *); 193struct gdbmarg *gdbmarg_datum (datum *, struct locus *);
@@ -259,6 +283,9 @@ int datum_scan (datum *dat, struct dsegm *ds, struct kvpair *kv);
259void dsprint (FILE *fp, int what, struct dsegm *ds); 283void dsprint (FILE *fp, int what, struct dsegm *ds);
260 284
261char *mkfilename (const char *dir, const char *file, const char *suf); 285char *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
@@ -165,19 +165,18 @@ value : string
165 $$ = kvpair_list (&@1, $2.head); 165 $$ = kvpair_list (&@1, $2.head);
166 } 166 }
167 ; 167 ;
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 ;
181 180
182string : T_IDENT 181string : T_IDENT
183 | T_WORD 182 | T_WORD
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
@@ -43,24 +43,22 @@ advance_line ()
43 while (0); 43 while (0);
44 44
45#undef YY_INPUT 45#undef YY_INPUT
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
53void string_begin (void); 53void string_begin (void);
54void string_add (const char *s, int l); 54void string_add (const char *s, int l);
55void string_addc (int c); 55void 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 */
64 struct locus locus; /* Locus */ 62 struct locus locus; /* Locus */
65 struct point point; 63 struct point point;
66 int interactive; 64 int interactive;
@@ -312,24 +310,22 @@ begin_def (void)
312void 310void
313end_def (void) 311end_def (void)
314{ 312{
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
333struct strseg 329struct strseg
334{ 330{
335 struct strseg *next; 331 struct strseg *next;
@@ -450,121 +446,151 @@ lerror (struct locus *loc, const char *fmt, ...)
450 va_start (ap, fmt); 446 va_start (ap, fmt);
451 vlerror (loc, fmt, ap); 447 vlerror (loc, fmt, ap);
452 va_end (ap); 448 va_end (ap);
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[] = {
497 { 'f', pe_file_name }, 489 { 'f', pe_file_name },
498 { 'p', pe_program_name }, 490 { 'p', pe_program_name },
499 { 'P', pe_package_name }, 491 { 'P', pe_package_name },
500 { 'v', pe_program_version }, 492 { 'v', pe_program_version },
501 { '_', pe_space }, 493 { '_', pe_space },
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
510 if (c && c != '%') 502 if (c && c != '%')
511 { 503 {
512 for (p = prompt_exp; p->ch; p++) 504 for (p = prompt_exp; p->ch; p++)
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.