diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-08-10 13:49:43 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-08-10 13:49:43 +0300 |
commit | 51504931f45e1342c64965a321d2c12603d8c2ae (patch) | |
tree | d7fe13760c8ab71a7eca72578ba27c221be1b5de | |
parent | d2a7d621722b8f80caf3f3081a28fbd06781f405 (diff) | |
download | gdbm-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.am | 1 | ||||
-rw-r--r-- | src/gdbmapp.h | 1 | ||||
-rw-r--r-- | src/gdbmtool.c | 106 | ||||
-rw-r--r-- | src/gdbmtool.h | 8 | ||||
-rw-r--r-- | src/input-null.c | 51 | ||||
-rw-r--r-- | src/input-rl.c | 20 | ||||
-rw-r--r-- | src/mem.c | 33 |
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 (¶m, arg, &cmd->args[i])) { - param_free_argv (¶m, i); + param_free (¶m); 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 (¶m); 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 (¶m, t, &cmd->args[i])) { + param_free (¶m); gdbmarg_free (t); - param_free_argv (¶m, 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 (¶m); 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 (¶m); 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 (¶m, param.argc); - + param_free (¶m); + 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 (¶m, 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 @@ -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; +} + |