summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2021-08-10 13:49:43 +0300
committerSergey Poznyakoff <gray@gnu.org>2021-08-10 13:49:43 +0300
commit51504931f45e1342c64965a321d2c12603d8c2ae (patch)
treed7fe13760c8ab71a7eca72578ba27c221be1b5de
parentd2a7d621722b8f80caf3f3081a28fbd06781f405 (diff)
downloadgdbm-51504931f45e1342c64965a321d2c12603d8c2ae.tar.gz
gdbmtool: rewrite handler parameter functions; fix memory leaks
* src/input-null.c: New file. * src/Makefile.am: Add input-null.c * src/mem.c (e2nrealloc): New function. * src/gdbmapp.h (e2nrealloc): New proto. * src/gdbmtool.c (quit_handler): Exit from parser instead of exiting from the program. (param): Remove global. (param_expand,param_push_arg,param_free): New functions for handling parameters. (param_free_argv): Take a single argument. Clear all parameters up to argc. (run_command): Rewrite parameter handling using new functions. (main): Call input_init() after the input stream has been set up. Call yylex_destroy when finished. * src/gdbmtool.h (instream_null_create): New proto. (handler_param): Change type of argc to size_t. New field argmax. (HANDLER_PARAM_INITIALIZER): New define. (yylex_destroy): New proto. * src/input-rl.c (history_file_name): New static. (get_history_file_name): Initialize history_file_name. (input_init): Initialize input history only in interactive mode. (input_done): Free input history only in interactive mode.
-rw-r--r--src/Makefile.am1
-rw-r--r--src/gdbmapp.h1
-rw-r--r--src/gdbmtool.c106
-rw-r--r--src/gdbmtool.h8
-rw-r--r--src/input-null.c51
-rw-r--r--src/input-rl.c20
-rw-r--r--src/mem.c33
7 files changed, 168 insertions, 52 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0d10f23..fa08bf3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -100,6 +100,7 @@ gdbmtool_SOURCES = \
gram.y\
input-argv.c\
input-file.c\
+ input-null.c\
lex.l\
gdbmtool.h\
gdbmtool.c\
diff --git a/src/gdbmapp.h b/src/gdbmapp.h
index 06d1cea..5c60e7b 100644
--- a/src/gdbmapp.h
+++ b/src/gdbmapp.h
@@ -34,6 +34,7 @@ void *erealloc (void *ptr, size_t size);
void *ecalloc (size_t nmemb, size_t size);
void *ezalloc (size_t size);
char *estrdup (const char *str);
+void *e2nrealloc (void *p, size_t *pn, size_t s);
#define PARSEOPT_HIDDEN 0x01
#define PARSEOPT_ALIAS 0x02
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 61d81a9..2c1f469 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -1165,9 +1165,10 @@ list_handler (struct handler_param *param)
void
quit_handler (struct handler_param *param GDBM_ARG_UNUSED)
{
- closedb ();
- input_done ();
- exit (EXIT_OK);
+ while (!input_context_pop ())
+ ;
+ if (input_context_push (instream_null_create ()))
+ exit (EXIT_FATAL);
}
/* export FILE [truncate] - export to a flat file format */
@@ -1871,8 +1872,6 @@ struct gdbm_option optab[] = {
{ 0 }
};
-#define ARGINC 16
-
struct gdbmarg *
gdbmarg_string (char *string, struct locus *loc)
@@ -2082,18 +2081,53 @@ gdbmarglist_free (struct gdbmarglist *lst)
lst->head = lst->tail = NULL;
}
-struct handler_param param;
-size_t argmax;
+static void
+param_expand (struct handler_param *p)
+{
+ if (p->argc == p->argmax)
+ p->argv = e2nrealloc (p->argv, &p->argmax, sizeof (p->argv[0]));
+}
-void
-param_free_argv (struct handler_param *p, int n)
+static void
+param_free_argv (struct handler_param *p)
{
- int i;
+ size_t i;
- for (i = 0; i < n; i++)
+ for (i = 0; i < p->argc; i++)
gdbmarg_destroy (&p->argv[i]);
p->argc = 0;
}
+
+static void
+param_free (struct handler_param *p)
+{
+ param_free_argv (p);
+ free (p->argv);
+ p->argv = NULL;
+ p->argmax = 0;
+}
+
+static struct gdbmarg *coerce (struct gdbmarg *arg, struct argdef *def);
+
+static int
+param_push_arg (struct handler_param *p, struct gdbmarg *arg,
+ struct argdef *def)
+{
+ param_expand (p);
+ if ((p->argv[p->argc] = coerce (arg, def)) == NULL)
+ {
+ return 1;
+ }
+ p->argc++;
+ return 0;
+}
+
+static void
+param_term (struct handler_param *p)
+{
+ param_expand (p);
+ p->argv[p->argc] = NULL;
+}
typedef struct gdbmarg *(*coerce_type_t) (struct gdbmarg *arg,
struct argdef *def);
@@ -2141,7 +2175,7 @@ coerce_type_t coerce_tab[GDBM_ARG_MAX][GDBM_ARG_MAX] = {
char *argtypestr[] = { "string", "datum", "k/v pair" };
-struct gdbmarg *
+static struct gdbmarg *
coerce (struct gdbmarg *arg, struct argdef *def)
{
if (!coerce_tab[def->type][arg->type])
@@ -2190,22 +2224,17 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
char argbuf[128];
size_t expected_lines, *expected_lines_ptr;
FILE *pagfp = NULL;
-
+ struct handler_param param = HANDLER_PARAM_INITIALIZER;
+
variable_get ("pager", VART_STRING, (void**) &pager);
arg = arglist ? arglist->head : NULL;
for (i = 0; cmd->args[i].name && arg; i++, arg = arg->next)
{
- if (i >= argmax)
- {
- argmax += ARGINC;
- param.argv = erealloc (param.argv,
- sizeof (param.argv[0]) * argmax);
- }
- if ((param.argv[i] = coerce (arg, &cmd->args[i])) == NULL)
+ if (param_push_arg (&param, arg, &cmd->args[i]))
{
- param_free_argv (&param, i);
+ param_free (&param);
return 1;
}
}
@@ -2222,6 +2251,7 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
if (!interactive ())
{
terror (_("%s: not enough arguments"), cmd->name);
+ param_free (&param);
return 1;
}
printf ("%s? ", argname);
@@ -2233,18 +2263,12 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
}
trimnl (argbuf);
- if (i >= argmax)
- {
- argmax += ARGINC;
- param.argv = erealloc (param.argv,
- sizeof (param.argv[0]) * argmax);
- }
-
+
t = gdbmarg_string (estrdup (argbuf), &yylloc);
- if ((param.argv[i] = coerce (t, &cmd->args[i])) == NULL)
+ if (param_push_arg (&param, t, &cmd->args[i]))
{
+ param_free (&param);
gdbmarg_free (t);
- param_free_argv (&param, i);
return 1;
}
}
@@ -2252,17 +2276,12 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
if (arg && !cmd->variadic)
{
terror (_("%s: too many arguments"), cmd->name);
+ param_free (&param);
return 1;
}
/* Prepare for calling the handler */
- param.argc = i;
- if (!param.argv)
- {
- argmax = ARGINC;
- param.argv = ecalloc (argmax, sizeof (param.argv[0]));
- }
- param.argv[i] = NULL;
+ param_term (&param);
param.vararg = arg;
param.fp = NULL;
param.data = NULL;
@@ -2298,8 +2317,8 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
pclose (pagfp);
}
- param_free_argv (&param, param.argc);
-
+ param_free (&param);
+
last_cmd = cmd;
if (arglist->head != last_args.head)
{
@@ -2391,7 +2410,6 @@ main (int argc, char *argv[])
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);
@@ -2504,15 +2522,14 @@ main (int argc, char *argv[])
signal (SIGPIPE, SIG_IGN);
- memset (&param, 0, sizeof (param));
- argmax = 0;
-
if (!norc)
source_rcfile ();
if (!input)
input = instream_stdin_create ();
+ input_init ();
+
/* Welcome message. */
if (instream_interactive (input) && !variable_is_true ("quiet"))
printf (_("\nWelcome to the gdbm tool. Type ? for help.\n\n"));
@@ -2520,7 +2537,8 @@ main (int argc, char *argv[])
if (input_context_push (input))
exit (EXIT_FATAL);
res = yyparse ();
- closedb ();
+ yylex_destroy ();
input_done ();
+ closedb ();
return res;
}
diff --git a/src/gdbmtool.h b/src/gdbmtool.h
index 14245e8..c753871 100644
--- a/src/gdbmtool.h
+++ b/src/gdbmtool.h
@@ -165,9 +165,11 @@ 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);
+instream_t instream_null_create (void);
int interactive (void);
int input_context_push (instream_t);
+int input_context_pop (void);
struct handler_param;
void input_history_handler (struct handler_param *param);
@@ -239,13 +241,16 @@ struct gdbmarglist
struct handler_param
{
- int argc;
+ size_t argc;
+ size_t argmax;
struct gdbmarg **argv;
struct gdbmarg *vararg;
FILE *fp;
void *data;
};
+#define HANDLER_PARAM_INITIALIZER { 0, 0, NULL, NULL, NULL, NULL }
+
#define PARAM_STRING(p,n) ((p)->argv[n]->v.string)
#define PARAM_DATUM(p,n) ((p)->argv[n]->v.dat)
#define PARAM_KVPAIR(p,n) ((p)->argv[n]->v.kvpair)
@@ -342,6 +347,7 @@ void begin_def (void);
void end_def (void);
int yylex (void);
+int yylex_destroy (void);
int yyerror (char const *s);
int yyparse (void);
diff --git a/src/input-null.c b/src/input-null.c
new file mode 100644
index 0000000..265abb8
--- /dev/null
+++ b/src/input-null.c
@@ -0,0 +1,51 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2018-2021 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"
+
+static ssize_t
+instream_null_read (instream_t istr, char *buf, size_t size)
+{
+ return 0;
+}
+
+static void
+instream_null_close (instream_t istr)
+{
+ free (istr);
+}
+
+static int
+instream_null_eq (instream_t a, instream_t b)
+{
+ return a == b;
+}
+
+instream_t
+instream_null_create (void)
+{
+ struct instream *istr;
+
+ istr = emalloc (sizeof *istr);
+ istr->in_name = "null";
+ istr->in_inter = 0;
+ istr->in_read = instream_null_read;
+ istr->in_close = instream_null_close;
+ istr->in_eq = instream_null_eq;
+
+ return istr;
+}
+
diff --git a/src/input-rl.c b/src/input-rl.c
index 1f361dd..e530b9c 100644
--- a/src/input-rl.c
+++ b/src/input-rl.c
@@ -122,12 +122,12 @@ input_history_handler (struct handler_param *param)
#define HISTFILE_PREFIX "~/."
#define HISTFILE_SUFFIX "_history"
+static char *history_file_name;
+
static char *
get_history_file_name (void)
{
- static char *filename = NULL;
-
- if (!filename)
+ if (!history_file_name)
{
char *hname;
@@ -136,10 +136,10 @@ get_history_file_name (void)
strcpy (hname, HISTFILE_PREFIX);
strcat (hname, rl_readline_name);
strcat (hname, HISTFILE_SUFFIX);
- filename = tildexpand (hname);
+ history_file_name = tildexpand (hname);
free (hname);
}
- return filename;
+ return history_file_name;
}
static char **
@@ -165,13 +165,19 @@ input_init (void)
rl_readline_name = (char *) progname;
rl_attempted_completion_function = shell_completion;
rl_pre_input_hook = pre_input;
- read_history (get_history_file_name ());
+ if (interactive ())
+ read_history (get_history_file_name ());
}
void
input_done (void)
{
- write_history (get_history_file_name ());
+ if (history_file_name)
+ {
+ write_history (history_file_name);
+ free (history_file_name);
+ history_file_name = NULL;
+ }
}
static void
diff --git a/src/mem.c b/src/mem.c
index bfbeafc..8b2da75 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -71,4 +71,37 @@ estrdup (const char *str)
return p;
}
+void *
+e2nrealloc (void *p, size_t *pn, size_t s)
+{
+ size_t n = *pn;
+ char *newp;
+
+ if (!p)
+ {
+ if (!n)
+ {
+ /* The approximate size to use for initial small
+ allocation requests, when the invoking code
+ specifies an old size of zero. 64 bytes is
+ the largest "small" request for the
+ GNU C library malloc. */
+ enum { DEFAULT_MXFAST = 64 };
+
+ n = DEFAULT_MXFAST / s;
+ n += !n;
+ }
+ }
+ else if ((size_t) -1 / 3 * 2 / s <= n)
+ {
+ ealloc_die ();
+ }
+ else
+ n += (n + 1) / 2;
+
+ newp = erealloc (p, n * s);
+ *pn = n;
+ return newp;
+}
+