summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog23
-rw-r--r--awk.h13
-rw-r--r--awkgram.c2
-rw-r--r--awkgram.y2
-rw-r--r--debug.c2
-rw-r--r--ext.c75
-rw-r--r--interpret.h11
-rw-r--r--main.c2
-rw-r--r--msg.c4
9 files changed, 100 insertions, 34 deletions
diff --git a/ChangeLog b/ChangeLog
index 5c6b8114..9b46a929 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2012-04-21 John Haque <j.eh@mchsi.com>
+
+ Shutdown routine for a dynamic extension.
+
+ * awk.h (SRCFILE): New field fini_func.
+ * ext.c (load_ext): Takes an additional argument to look up and
+ save the clean up routine in SRCFILE struct.
+ (INIT_FUNC, FINI_FUNC): Defines for default init and fini routine
+ names.
+ (do_ext): Use default for the name of the init or fini routine if
+ one is not supplied. Adjust call to load_ext().
+ (close_extensions): Execute fini routines.
+ * interpret.h (Op_at_exit): Call close_extensions().
+ * msg.c (gawk_exit): Ditto.
+ * debug.c (close_all): Ditto.
+ * main.c (main): Adjust call to load_ext().
+ * awkgram.y (tokentab): Specify 2nd and 3rd optional arguments
+ for the extension() built-in.
+
+ Unrelated:
+
+ * interpret.h (Op_arrayfor_init): Use assoc_length for array size.
+
2012-04-19 John Haque <j.eh@mchsi.com>
Enhanced array interface to support transparent implementation
diff --git a/awk.h b/awk.h
index 8b9861b4..c89ed977 100644
--- a/awk.h
+++ b/awk.h
@@ -953,6 +953,8 @@ typedef struct srcfile {
int fd;
int maxlen; /* size of the longest line */
+ void (*fini_func)(); /* dynamic extension of type SRC_EXTLIB */
+
char *lexptr;
char *lexend;
char *lexeme;
@@ -1488,12 +1490,13 @@ extern STACK_ITEM *grow_stack(void);
extern void dump_fcall_stack(FILE *fp);
extern int register_exec_hook(Func_pre_exec preh, Func_post_exec posth);
/* ext.c */
-NODE *do_ext(int nargs);
-NODE *load_ext(const char *lib_name, const char *init_func, NODE *obj);
+extern NODE *do_ext(int nargs);
+extern NODE *load_ext(SRCFILE *s, const char *init_func, const char *fini_func, NODE *obj);
+extern void close_extensions(void);
#ifdef DYNAMIC
-void make_builtin(const char *, NODE *(*)(int), int);
-NODE *get_argument(int);
-NODE *get_actual_argument(int, int, int);
+extern void make_builtin(const char *, NODE *(*)(int), int);
+extern NODE *get_argument(int);
+extern NODE *get_actual_argument(int, int, int);
#define get_scalar_argument(i, opt) get_actual_argument((i), (opt), FALSE)
#define get_array_argument(i, opt) get_actual_argument((i), (opt), TRUE)
#endif
diff --git a/awkgram.c b/awkgram.c
index fd38c527..a447b23a 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -4519,7 +4519,7 @@ static const struct token tokentab[] = {
{"eval", Op_symbol, LEX_EVAL, 0, 0, 0},
{"exit", Op_K_exit, LEX_EXIT, 0, 0, 0},
{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)},
-{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext, 0},
+{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext, 0},
{"fflush", Op_builtin, LEX_BUILTIN, RESX|A(0)|A(1), do_fflush, 0},
{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0},
{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0},
diff --git a/awkgram.y b/awkgram.y
index 76b40a52..3258f004 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -1822,7 +1822,7 @@ static const struct token tokentab[] = {
{"eval", Op_symbol, LEX_EVAL, 0, 0, 0},
{"exit", Op_K_exit, LEX_EXIT, 0, 0, 0},
{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)},
-{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext, 0},
+{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext, 0},
{"fflush", Op_builtin, LEX_BUILTIN, RESX|A(0)|A(1), do_fflush, 0},
{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0},
{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0},
diff --git a/debug.c b/debug.c
index 36454366..8bd3e841 100644
--- a/debug.c
+++ b/debug.c
@@ -5344,6 +5344,8 @@ close_all()
}
}
+ close_extensions();
+
set_gawk_output(NULL); /* closes output_fp if not stdout */
}
diff --git a/ext.c b/ext.c
index f2919db7..dc312cce 100644
--- a/ext.c
+++ b/ext.c
@@ -28,28 +28,44 @@
*/
#include "awk.h"
+extern SRCFILE *srcfiles;
#ifdef DYNAMIC
+#define INIT_FUNC "dlload"
+#define FINI_FUNC "dlunload"
+
#include <dlfcn.h>
/* do_ext --- load an extension at run-time: interface to load_ext */
-
+
NODE *
do_ext(int nargs)
{
- NODE *obj, *fun, *ret = NULL;
+ NODE *obj, *init = NULL, *fini = NULL, *ret = NULL;
SRCFILE *s;
- extern SRCFILE *srcfiles;
+ char *init_func = NULL;
+ char *fini_func = NULL;
- fun = POP_STRING();
+ if (nargs == 3) {
+ fini = POP_STRING();
+ fini_func = fini->stptr;
+ }
+ if (nargs >= 2) {
+ init = POP_STRING();
+ init_func = init->stptr;
+ }
obj = POP_STRING();
s = add_srcfile(SRC_EXTLIB, obj->stptr, srcfiles, NULL, NULL);
if (s != NULL)
- ret = load_ext(s->fullpath, fun->stptr, obj);
+ ret = load_ext(s, init_func, fini_func, obj);
+
DEREF(obj);
- DEREF(fun);
+ if (fini != NULL)
+ DEREF(fini);
+ if (init != NULL)
+ DEREF(init);
if (ret == NULL)
ret = dupnode(Nnull_string);
return ret;
@@ -58,13 +74,20 @@ do_ext(int nargs)
/* load_ext --- load an external library */
NODE *
-load_ext(const char *lib_name, const char *init_func, NODE *obj)
+load_ext(SRCFILE *s, const char *init_func, const char *fini_func, NODE *obj)
{
NODE *tmp = NULL;
NODE *(*func)(NODE *, void *);
void *dl;
int flags = RTLD_LAZY;
int *gpl_compat;
+ const char *lib_name = s->fullpath;
+
+ if (init_func == NULL || init_func[0] == '\0')
+ init_func = INIT_FUNC;
+
+ if (fini_func == NULL || fini_func[0] == '\0')
+ fini_func = FINI_FUNC;
if (do_sandbox)
fatal(_("extensions are not allowed in sandbox mode"));
@@ -76,18 +99,18 @@ load_ext(const char *lib_name, const char *init_func, NODE *obj)
flags |= RTLD_GLOBAL;
#endif
- if ((dl = dlopen(lib_name, flags)) == NULL)
- fatal(_("extension: cannot open library `%s' (%s)\n"), lib_name,
+ if ((dl = dlopen(s->fullpath, flags)) == NULL)
+ fatal(_("extension: cannot open library `%s' (%s)"), lib_name,
dlerror());
/* Per the GNU Coding standards */
gpl_compat = (int *) dlsym(dl, "plugin_is_GPL_compatible");
if (gpl_compat == NULL)
- fatal(_("extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n"),
+ fatal(_("extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)"),
lib_name, dlerror());
func = (NODE *(*)(NODE *, void *)) dlsym(dl, init_func);
if (func == NULL)
- fatal(_("extension: library `%s': cannot call function `%s' (%s)\n"),
+ fatal(_("extension: library `%s': cannot call function `%s' (%s)"),
lib_name, init_func, dlerror());
if (obj == NULL) {
@@ -95,11 +118,12 @@ load_ext(const char *lib_name, const char *init_func, NODE *obj)
tmp = (*func)(obj, dl);
unref(tmp);
unref(obj);
- return NULL;
- }
+ tmp = NULL;
+ } else
+ tmp = (*func)(obj, dl);
- tmp = (*func)(obj, dl);
- return tmp;
+ s->fini_func = (void (*)(void)) dlsym(dl, fini_func);
+ return tmp;
}
@@ -118,7 +142,7 @@ make_builtin(const char *name, NODE *(*func)(int), int count)
fatal(_("extension: missing function name"));
while ((c = *sp++) != '\0') {
- if ((sp == &name[1] && c != '_' && ! isalpha((unsigned char) c))
+ if ((sp == & name[1] && c != '_' && ! isalpha((unsigned char) c))
|| (sp > &name[1] && ! is_identchar((unsigned char) c)))
fatal(_("extension: illegal character `%c' in function name `%s'"), c, name);
}
@@ -184,9 +208,10 @@ get_argument(int i)
}
-/* get_actual_argument --- get the i'th scalar or array argument of a
- dynamically linked function, allowed to be optional.
-*/
+/*
+ * get_actual_argument --- get the i'th scalar or array argument of a
+ * dynamically linked function, allowed to be optional.
+ */
NODE *
get_actual_argument(int i, int optional, int want_array)
@@ -257,3 +282,15 @@ load_ext(const char *lib_name, const char *init_func, NODE *obj)
return NULL;
}
#endif
+
+/* close_extensions --- execute extension cleanup routines */
+
+void
+close_extensions()
+{
+ SRCFILE *s;
+
+ for (s = srcfiles->next; s != srcfiles; s = s->next)
+ if (s->stype == SRC_EXTLIB && s->fini_func)
+ (*s->fini_func)();
+}
diff --git a/interpret.h b/interpret.h
index 0b830010..2fed2243 100644
--- a/interpret.h
+++ b/interpret.h
@@ -106,6 +106,8 @@ top:
*/
if (stdio_problem && ! exiting && exit_val == 0)
exit_val = 1;
+
+ close_extensions();
}
break;
@@ -763,12 +765,6 @@ mod:
/* get the array */
array = POP_ARRAY();
- /* sanity: check if empty */
- if (assoc_empty(array))
- goto arrayfor;
-
- num_elems = array->table_size;
-
if (sorted_in == NULL) /* do this once */
sorted_in = make_string("sorted_in", 9);
@@ -788,7 +784,8 @@ mod:
list = assoc_list(array, how_to_sort, SORTED_IN);
-arrayfor:
+ num_elems = assoc_length(array);
+
getnode(r);
r->type = Node_arrayfor;
r->for_list = list;
diff --git a/main.c b/main.c
index 8a38a760..570c0d53 100644
--- a/main.c
+++ b/main.c
@@ -637,7 +637,7 @@ out:
/* load extension libs */
for (s = srcfiles->next; s != srcfiles; s = s->next) {
if (s->stype == SRC_EXTLIB)
- (void) load_ext(s->fullpath, "dlload", NULL);
+ (void) load_ext(s, NULL, NULL, NULL);
else
have_srcfile++;
}
diff --git a/msg.c b/msg.c
index 78818187..dabd20e3 100644
--- a/msg.c
+++ b/msg.c
@@ -158,5 +158,9 @@ gawk_exit(int status)
exit_val = status;
longjmp(fatal_tag, 1);
}
+
+ /* we could close_io() here */
+ close_extensions();
+
exit(status);
}