aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog23
-rw-r--r--awk.h9
-rw-r--r--ext.c4
-rw-r--r--extension/ChangeLog5
-rw-r--r--extension/Makefile.am3
-rw-r--r--extension/Makefile.in22
-rw-r--r--extension/readdir.c220
-rw-r--r--gawkapi.c8
-rw-r--r--gawkapi.h28
-rw-r--r--io.c129
10 files changed, 365 insertions, 86 deletions
diff --git a/ChangeLog b/ChangeLog
index 5ad8cef2..6d097640 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2012-07-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ Start refactoring of IOBUF handling and turn "open hooks"
+ into "input parsers".
+
+ * awk.h (IOP_NOFREE_OBJ): Flag removed.
+ (register_input_parser): Renamed from register_open_hook.
+ * ext.c (load_ext): Make sure lib_name is not NULL.
+ * gawk_api.c (api_register_input_parser): Renamed from
+ api_register_open_hook.
+ * gawk_api.h (api_register_input_parser): Renamed from
+ api_register_open_hook. Rework structure to have "do you want it"
+ and "take control of it" functions.
+ * io.c (iop_alloc): Remove third argument which is IOBUF pointer.
+ Always malloc it. Remove use of IOP_NOFREE_OBJ everywhere.
+ (find_input_parser): Renamed from find_open_hook.
+ (nextfile): Don't use static IOBUF.
+ (iop_close): Call close_func first. Then close fd or remap it
+ if it's still not INVALID_HANDLE.
+ (register_input_parser): Renamed from register_open_hook.
+ Use a FIFO list and check if more than one parser will accept the
+ file. If so, fatal error.
+
2012-07-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
* configure.ac: Instead of using acl_shlibext for the shared library
diff --git a/awk.h b/awk.h
index a85fef85..fbb57b01 100644
--- a/awk.h
+++ b/awk.h
@@ -910,10 +910,9 @@ typedef struct iobuf {
int flag;
# define IOP_IS_TTY 1
-# define IOP_NOFREE_OBJ 2
-# define IOP_AT_EOF 4
-# define IOP_CLOSED 8
-# define IOP_AT_START 16
+# define IOP_AT_EOF 2
+# define IOP_CLOSED 4
+# define IOP_AT_START 8
} IOBUF;
typedef void (*Func_ptr)(void);
@@ -1543,7 +1542,7 @@ extern int isdirpunct(int c);
/* io.c */
extern void init_io(void);
-extern void register_open_hook(void *(*open_func)(IOBUF_PUBLIC *));
+extern void register_input_parser(awk_input_parser_t *input_parser);
extern void set_FNR(void);
extern void set_NR(void);
diff --git a/ext.c b/ext.c
index af6542d4..17ade95a 100644
--- a/ext.c
+++ b/ext.c
@@ -51,6 +51,9 @@ load_ext(const char *lib_name)
if (do_traditional || do_posix)
fatal(_("-l / @load are gawk extensions"));
+ if (lib_name == NULL)
+ fatal(_("load_ext: received NULL lib_name"));
+
if ((dl = dlopen(lib_name, flags)) == NULL)
fatal(_("load_ext: cannot open library `%s' (%s)\n"), lib_name,
dlerror());
@@ -60,6 +63,7 @@ load_ext(const char *lib_name)
if (gpl_compat == NULL)
fatal(_("load_ext: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n"),
lib_name, dlerror());
+
install_func = (int (*)(const gawk_api_t *const, awk_ext_id_t))
dlsym(dl, INIT_FUNC);
if (install_func == NULL)
diff --git a/extension/ChangeLog b/extension/ChangeLog
index 80cb44d7..939a6aed 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,8 @@
+2012-07-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ * readdir.c: New file.
+ * Makefile.am (readdir): New extension.
+
2012-07-20 Arnold D. Robbins <arnold@skeeve.com>
* filefuncs.3am, fnmatch.3am, ordchr.3am, readfile.3am:
diff --git a/extension/Makefile.am b/extension/Makefile.am
index abe778e2..32969099 100644
--- a/extension/Makefile.am
+++ b/extension/Makefile.am
@@ -36,6 +36,7 @@ pkgextension_LTLIBRARIES = \
fnmatch.la \
fork.la \
ordchr.la \
+ readdir.la \
readfile.la \
rwarray.la \
testext.la \
@@ -51,6 +52,8 @@ fork_la_SOURCES = fork.c
fork_la_LDFLAGS = $(MY_MODULE_FLAGS)
ordchr_la_SOURCES = ordchr.c
ordchr_la_LDFLAGS = $(MY_MODULE_FLAGS)
+readdir_la_SOURCES = readdir.c
+readdir_la_LDFLAGS = $(MY_MODULE_FLAGS)
readfile_la_SOURCES = readfile.c
readfile_la_LDFLAGS = $(MY_MODULE_FLAGS)
rwarray_la_SOURCES = rwarray.c
diff --git a/extension/Makefile.in b/extension/Makefile.in
index 71920fec..14c9e149 100644
--- a/extension/Makefile.in
+++ b/extension/Makefile.in
@@ -154,6 +154,12 @@ ordchr_la_OBJECTS = $(am_ordchr_la_OBJECTS)
ordchr_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(ordchr_la_LDFLAGS) $(LDFLAGS) -o $@
+readdir_la_LIBADD =
+am_readdir_la_OBJECTS = readdir.lo
+readdir_la_OBJECTS = $(am_readdir_la_OBJECTS)
+readdir_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(readdir_la_LDFLAGS) $(LDFLAGS) -o $@
readfile_la_LIBADD =
am_readfile_la_OBJECTS = readfile.lo
readfile_la_OBJECTS = $(am_readfile_la_OBJECTS)
@@ -192,11 +198,13 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \
- $(fork_la_SOURCES) $(ordchr_la_SOURCES) $(readfile_la_SOURCES) \
- $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES)
+ $(fork_la_SOURCES) $(ordchr_la_SOURCES) $(readdir_la_SOURCES) \
+ $(readfile_la_SOURCES) $(rwarray_la_SOURCES) \
+ $(testext_la_SOURCES) $(time_la_SOURCES)
DIST_SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \
- $(fork_la_SOURCES) $(ordchr_la_SOURCES) $(readfile_la_SOURCES) \
- $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES)
+ $(fork_la_SOURCES) $(ordchr_la_SOURCES) $(readdir_la_SOURCES) \
+ $(readfile_la_SOURCES) $(rwarray_la_SOURCES) \
+ $(testext_la_SOURCES) $(time_la_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -349,6 +357,7 @@ pkgextension_LTLIBRARIES = \
fnmatch.la \
fork.la \
ordchr.la \
+ readdir.la \
readfile.la \
rwarray.la \
testext.la \
@@ -363,6 +372,8 @@ fork_la_SOURCES = fork.c
fork_la_LDFLAGS = $(MY_MODULE_FLAGS)
ordchr_la_SOURCES = ordchr.c
ordchr_la_LDFLAGS = $(MY_MODULE_FLAGS)
+readdir_la_SOURCES = readdir.c
+readdir_la_LDFLAGS = $(MY_MODULE_FLAGS)
readfile_la_SOURCES = readfile.c
readfile_la_LDFLAGS = $(MY_MODULE_FLAGS)
rwarray_la_SOURCES = rwarray.c
@@ -471,6 +482,8 @@ fork.la: $(fork_la_OBJECTS) $(fork_la_DEPENDENCIES) $(EXTRA_fork_la_DEPENDENCIES
$(fork_la_LINK) -rpath $(pkgextensiondir) $(fork_la_OBJECTS) $(fork_la_LIBADD) $(LIBS)
ordchr.la: $(ordchr_la_OBJECTS) $(ordchr_la_DEPENDENCIES) $(EXTRA_ordchr_la_DEPENDENCIES)
$(ordchr_la_LINK) -rpath $(pkgextensiondir) $(ordchr_la_OBJECTS) $(ordchr_la_LIBADD) $(LIBS)
+readdir.la: $(readdir_la_OBJECTS) $(readdir_la_DEPENDENCIES) $(EXTRA_readdir_la_DEPENDENCIES)
+ $(readdir_la_LINK) -rpath $(pkgextensiondir) $(readdir_la_OBJECTS) $(readdir_la_LIBADD) $(LIBS)
readfile.la: $(readfile_la_OBJECTS) $(readfile_la_DEPENDENCIES) $(EXTRA_readfile_la_DEPENDENCIES)
$(readfile_la_LINK) -rpath $(pkgextensiondir) $(readfile_la_OBJECTS) $(readfile_la_LIBADD) $(LIBS)
rwarray.la: $(rwarray_la_OBJECTS) $(rwarray_la_DEPENDENCIES) $(EXTRA_rwarray_la_DEPENDENCIES)
@@ -490,6 +503,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fnmatch.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fork.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ordchr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readdir.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readfile.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rwarray.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testext.Plo@am__quote@
diff --git a/extension/readdir.c b/extension/readdir.c
new file mode 100644
index 00000000..a39e0c3a
--- /dev/null
+++ b/extension/readdir.c
@@ -0,0 +1,220 @@
+/*
+ * readdir.c --- Provide an open hook to read directories
+ *
+ * Arnold Robbins
+ * arnold@skeeve.com
+ * Written 7/2012
+ */
+
+/*
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK 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 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define _BSD_SOURCE
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "config.h"
+#include "gawkapi.h"
+
+static const gawk_api_t *api; /* for convenience macros to work */
+static awk_ext_id_t *ext_id;
+
+int plugin_is_GPL_compatible;
+
+/* ftype --- return type of file as a single character string */
+
+static const char *
+ftype(struct dirent *entry)
+{
+#ifdef DT_BLK
+ switch (entry->d_type) {
+ case DT_BLK: return "b";
+ case DT_CHR: return "c";
+ case DT_DIR: return "d";
+ case DT_FIFO: return "p";
+ case DT_LNK: return "l";
+ case DT_REG: return "f";
+ case DT_SOCK: return "s";
+ default:
+ case DT_UNKNOWN: return "u";
+ }
+#else
+ struct stat sbuf;
+
+ if (lstat(entry->d_name, & sbuf) < 0)
+ return "u";
+
+ switch (sbuf.st_mode & S_IFMT) {
+ case S_IFREG: return "f";
+ case S_IFBLK: return "b";
+ case S_IFCHR: return "c";
+ case S_IFDIR: return "d";
+#ifdef S_IFSOCK
+ case S_IFSOCK: return "s";
+#endif
+#ifdef S_IFIFO
+ case S_IFIFO: return "p";
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK: return "l";
+#endif
+#ifdef S_IFDOOR /* Solaris weirdness */
+ case S_IFDOOR: return "D";
+#endif /* S_IFDOOR */
+ }
+ return "u";
+#endif
+}
+
+
+/* dir_get_record --- get one record at a time out of a directory */
+
+static int
+dir_get_record(char **out, struct iobuf_public *iobuf, int *errcode)
+{
+ DIR *dp;
+ struct dirent *dirent;
+ char buf[1000];
+ size_t len;
+
+ if (out == NULL || iobuf == NULL || iobuf->opaque == NULL)
+ return EOF;
+
+ if (errcode != NULL)
+ *errcode = 0;
+
+ /* FIXME: Need stuff for setting RT */
+ dp = (DIR *) iobuf->opaque;
+ dirent = readdir(dp);
+ if (dirent == NULL)
+ return EOF;
+
+ sprintf(buf, "%ld/%s/%s", dirent->d_ino, dirent->d_name, ftype(dirent));
+ len = strlen(buf);
+ emalloc(*out, char *, len + 1, "dir_get_record");
+ strcpy(*out, buf);
+ return len;
+}
+
+/* dir_close --- close up when done */
+
+static void
+dir_close(struct iobuf_public *iobuf)
+{
+ DIR *dp;
+
+ if (iobuf == NULL || iobuf->opaque == NULL)
+ return;
+
+ dp = (DIR *) iobuf->opaque;
+ closedir(dp);
+ iobuf->fd = -1;
+}
+
+/* dir_can_take_file --- return true if we want the file */
+
+static int
+dir_can_take_file(IOBUF_PUBLIC *iobuf)
+{
+ struct stat sbuf;
+ int fd;
+
+ if (iobuf == NULL)
+ return 0;
+
+ fd = iobuf->fd;
+ return (fd >= 0 && fstat(fd, & sbuf) >= 0 && S_ISDIR(sbuf.st_mode));
+}
+
+/* dir_take_control_of --- set up input parser */
+
+static int
+dir_take_control_of(IOBUF_PUBLIC *iobuf)
+{
+ struct stat sbuf;
+ int fd;
+ DIR *dp = NULL;
+
+ if (iobuf == NULL)
+ return 0;
+
+ fd = iobuf->fd;
+ if (dir_can_take_file(iobuf)) {
+ dp = fdopendir(fd);
+ if (dp == NULL)
+ return 0;
+
+ iobuf->opaque = dp;
+ iobuf->get_record = dir_get_record;
+ iobuf->close_func = dir_close;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static awk_input_parser_t readdir_parser = {
+ "readdir",
+ dir_can_take_file,
+ dir_take_control_of,
+ NULL
+};
+
+#ifdef TEST_DUPLICATE
+static awk_input_parser_t readdir_parser2 = {
+ "readdir2",
+ dir_can_take_file,
+ dir_take_control_of,
+ NULL
+};
+#endif
+
+int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id)
+{
+ api = api_p;
+ ext_id = id;
+
+ if (api->major_version != GAWK_API_MAJOR_VERSION
+ || api->minor_version < GAWK_API_MINOR_VERSION) {
+ fprintf(stderr, "readdir: version mismatch with gawk!\n");
+ fprintf(stderr, "\tmy version (%d, %d), gawk version (%d, %d)\n",
+ GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION,
+ api->major_version, api->minor_version);
+ exit(1);
+ }
+
+
+ register_input_parser(& readdir_parser);
+#ifdef TEST_DUPLICATE
+ register_input_parser(& readdir_parser2);
+#endif
+
+ return 1;
+}
diff --git a/gawkapi.c b/gawkapi.c
index 9e1c1095..09c9f399 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -215,14 +215,14 @@ api_lintwarn(awk_ext_id_t id, const char *format, ...)
}
}
-/* api_register_open_hook --- register an open hook; for opening files read-only */
+/* api_register_input_parser --- register an input_parser; for opening files read-only */
static void
-api_register_open_hook(awk_ext_id_t id, void* (*open_func)(IOBUF_PUBLIC *))
+api_register_input_parser(awk_ext_id_t id, awk_input_parser_t *input_parser)
{
(void) id;
- register_open_hook(open_func);
+ register_input_parser(input_parser);
}
/* Functions to update ERRNO */
@@ -942,7 +942,7 @@ gawk_api_t api_impl = {
api_warning,
api_lintwarn,
- api_register_open_hook,
+ api_register_input_parser,
api_update_ERRNO_int,
api_update_ERRNO_string,
diff --git a/gawkapi.h b/gawkapi.h
index 90df6293..58162002 100644
--- a/gawkapi.h
+++ b/gawkapi.h
@@ -69,6 +69,13 @@
extern "C" {
#endif
+/* This is used to keep the extension from modifying certain fields in some structs. */
+#ifdef GAWK
+#define awk_const
+#else
+#define awk_const const
+#endif
+
/* portions of IOBUF that should be accessible to extension functions: */
typedef struct iobuf_public {
const char *name; /* filename */
@@ -78,6 +85,14 @@ typedef struct iobuf_public {
void (*close_func)(struct iobuf_public *);
} IOBUF_PUBLIC;
+typedef struct input_parser {
+ const char *name; /* name of parser */
+ int (*can_take_file)(IOBUF_PUBLIC *iobuf);
+ int (*take_control_of)(IOBUF_PUBLIC *iobuf);
+ struct input_parser *awk_const next; /* for use by gawk */
+} awk_input_parser_t;
+
+
#define GAWK_API_MAJOR_VERSION 0
#define GAWK_API_MINOR_VERSION 0
@@ -156,13 +171,6 @@ typedef struct awk_element {
awk_value_t value;
} awk_element_t;
-/* This is used to keep the extension from modifying certain fields. */
-#ifdef GAWK
-#define awk_const
-#else
-#define awk_const const
-#endif
-
/*
* A "flattened" array. See the description above for how
* to use the elements contained herein.
@@ -281,8 +289,8 @@ typedef struct gawk_api {
void (*api_warning)(awk_ext_id_t id, const char *format, ...);
void (*api_lintwarn)(awk_ext_id_t id, const char *format, ...);
- /* Register an open hook; for opening files read-only */
- void (*api_register_open_hook)(awk_ext_id_t id, void* (*open_func)(IOBUF_PUBLIC *));
+ /* Register an input parser; for opening files read-only */
+ void (*api_register_input_parser)(awk_ext_id_t id, awk_input_parser_t *input_parser);
/* Functions to update ERRNO */
void (*api_update_ERRNO_int)(awk_ext_id_t id, int errno_val);
@@ -464,7 +472,7 @@ typedef struct gawk_api {
#define warning api->api_warning
#define lintwarn api->api_lintwarn
-#define register_open_hook(func) (api->api_register_open_hook(ext_id, func))
+#define register_input_parser(parser) (api->api_register_input_parser(ext_id, parser))
#define update_ERRNO_int(e) (api->api_update_ERRNO_int(ext_id, e))
#define update_ERRNO_string(str, translate) \
diff --git a/io.c b/io.c
index ab204e09..584e434c 100644
--- a/io.c
+++ b/io.c
@@ -203,12 +203,12 @@ static int close_redir(struct redirect *rp, bool exitwarn, two_way_close_type ho
static int wait_any(int interesting);
#endif
static IOBUF *gawk_popen(const char *cmd, struct redirect *rp);
-static IOBUF *iop_alloc(int fd, const char *name, IOBUF *buf, bool do_openhooks);
+static IOBUF *iop_alloc(int fd, const char *name, bool do_input_parsers);
static int gawk_pclose(struct redirect *rp);
static int str2mode(const char *mode);
static int two_way_open(const char *str, struct redirect *rp);
static int pty_vs_pipe(const char *command);
-static void find_open_hook(IOBUF *iop);
+static void find_input_parser(IOBUF *iop);
static RECVALUE rs1scan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state);
static RECVALUE rsnullscan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state);
@@ -336,10 +336,14 @@ after_beginfile(IOBUF **curfile)
* so delay check until now.
*/
- find_open_hook(iop);
+ find_input_parser(iop);
}
/* nextfile --- move to the next input data file */
+/*
+ * Return value > 0 ----> run BEGINFILE block
+ * *curfile = NULL ----> hit EOF, run ENDFILE block
+ */
int
nextfile(IOBUF **curfile, bool skipping)
@@ -347,7 +351,6 @@ nextfile(IOBUF **curfile, bool skipping)
static long i = 1;
static bool files = false;
NODE *arg, *tmp;
- static IOBUF mybuf;
const char *fname;
int fd = INVALID_HANDLE;
int errcode = 0;
@@ -406,12 +409,11 @@ nextfile(IOBUF **curfile, bool skipping)
mpz_set_ui(MFNR, 0);
#endif
FNR = 0;
- iop = *curfile = iop_alloc(fd, fname, & mybuf, false);
+ iop = *curfile = iop_alloc(fd, fname, false);
if (fd == INVALID_HANDLE)
iop->errcode = errcode;
else
iop->errcode = 0;
- iop->flag |= IOP_NOFREE_OBJ;
return ++i; /* run beginfile block */
}
}
@@ -427,8 +429,7 @@ nextfile(IOBUF **curfile, bool skipping)
FILENAME_node->var_value = make_string("-", 1);
FILENAME_node->var_value->flags |= MAYBE_NUM; /* be pedantic */
fname = "-";
- iop = *curfile = iop_alloc(fileno(stdin), fname, & mybuf, false);
- iop->flag |= IOP_NOFREE_OBJ;
+ iop = *curfile = iop_alloc(fileno(stdin), fname, false);
if (iop->public.fd == INVALID_HANDLE) {
errcode = errno;
@@ -539,11 +540,6 @@ iop_close(IOBUF *iop)
if (iop == NULL)
return 0;
- if (iop->public.fd == INVALID_HANDLE) { /* from nextfile(...) above */
- assert(iop->buf == NULL);
- assert((iop->flag & IOP_NOFREE_OBJ) != 0);
- return 0;
- }
errno = 0;
@@ -555,16 +551,18 @@ iop_close(IOBUF *iop)
* So we remap the standard file to /dev/null.
* Thanks to Jim Meyering for the suggestion.
*/
- if (iop->public.fd == fileno(stdin)
- || iop->public.fd == fileno(stdout)
- || iop->public.fd == fileno(stderr))
- ret = remap_std_file(iop->public.fd);
- else
- ret = close(iop->public.fd);
-
if (iop->public.close_func != NULL)
iop->public.close_func(&iop->public);
+ if (iop->public.fd != INVALID_HANDLE) {
+ if (iop->public.fd == fileno(stdin)
+ || iop->public.fd == fileno(stdout)
+ || iop->public.fd == fileno(stderr))
+ ret = remap_std_file(iop->public.fd);
+ else
+ ret = close(iop->public.fd);
+ }
+
if (ret == -1)
warning(_("close of fd %d (`%s') failed (%s)"), iop->public.fd,
iop->public.name, strerror(errno));
@@ -595,8 +593,7 @@ iop_close(IOBUF *iop)
efree(iop->buf);
iop->buf = NULL;
}
- if ((iop->flag & IOP_NOFREE_OBJ) == 0)
- efree(iop);
+ efree(iop);
return ret == -1 ? 1 : 0;
}
@@ -805,7 +802,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
/* do not free rp, saving it for reuse (save_rp = rp) */
return NULL;
}
- rp->iop = iop_alloc(fd, str, NULL, true);
+ rp->iop = iop_alloc(fd, str, true);
break;
case redirect_twoway:
direction = "to/from";
@@ -1618,10 +1615,7 @@ strictopen:
if (openfd > fileno(stderr))
os_close_on_exec(openfd, name, "file", "");
}
- /*
- * XXX: FIXME: if fd is INVALID_HANDLE, see if an open hook
- * can do something.
- */
+
return openfd;
}
@@ -1652,7 +1646,7 @@ two_way_open(const char *str, struct redirect *rp)
}
os_close_on_exec(fd, str, "socket", "to/from");
os_close_on_exec(newfd, str, "socket", "to/from");
- rp->iop = iop_alloc(newfd, str, NULL, true);
+ rp->iop = iop_alloc(newfd, str, true);
if (rp->iop == NULL) {
close(newfd);
fclose(rp->fp);
@@ -1848,7 +1842,7 @@ two_way_open(const char *str, struct redirect *rp)
}
rp->pid = pid;
- rp->iop = iop_alloc(master, str, NULL, true);
+ rp->iop = iop_alloc(master, str, true);
if (rp->iop == NULL) {
(void) close(master);
(void) kill(pid, SIGKILL);
@@ -2001,7 +1995,7 @@ use_pipes:
/* parent */
rp->pid = pid;
- rp->iop = iop_alloc(ctop[0], str, NULL, true);
+ rp->iop = iop_alloc(ctop[0], str, true);
if (rp->iop == NULL) {
(void) close(ctop[0]);
(void) close(ctop[1]);
@@ -2165,7 +2159,7 @@ gawk_popen(const char *cmd, struct redirect *rp)
}
#endif
os_close_on_exec(p[0], cmd, "pipe", "from");
- rp->iop = iop_alloc(p[0], cmd, NULL, true);
+ rp->iop = iop_alloc(p[0], cmd, true);
if (rp->iop == NULL)
(void) close(p[0]);
@@ -2210,7 +2204,7 @@ gawk_popen(const char *cmd, struct redirect *rp)
if (current == NULL)
return NULL;
os_close_on_exec(fileno(current), cmd, "pipe", "from");
- rp->iop = iop_alloc(fileno(current), cmd, NULL, true);
+ rp->iop = iop_alloc(fileno(current), cmd, true);
if (rp->iop == NULL) {
(void) pclose(current);
current = NULL;
@@ -2585,63 +2579,73 @@ srcopen(SRCFILE *s)
return INVALID_HANDLE;
}
-/* open hooks, mainly for use by extension functions */
+/* input parsers, mainly for use by extension functions */
-static struct open_hook {
- struct open_hook *next;
- void *(*open_func)(IOBUF_PUBLIC *);
-} *open_hooks;
+static awk_input_parser_t *ip_head, *ip_tail;
-/* register_open_hook --- add an open hook to the list */
+/* register_input_parser --- add an input parser to the list, FIFO */
void
-register_open_hook(void *(*open_func)(IOBUF_PUBLIC *))
+register_input_parser(awk_input_parser_t *input_parser)
{
- struct open_hook *oh;
+ if (input_parser == NULL)
+ fatal(_("register_input_parser: received NULL pointer"));
- emalloc(oh, struct open_hook *, sizeof(*oh), "register_open_hook");
- oh->open_func = open_func;
- oh->next = open_hooks;
- open_hooks = oh;
+ input_parser->next = NULL; /* force it */
+ if (ip_head == NULL) {
+ ip_head = ip_tail = input_parser;
+ } else {
+ ip_tail->next = input_parser;
+ ip_tail = ip_tail->next;
+ }
}
-/* find_open_hook --- search the list of open hooks */
+/* find_input_parser --- search the list of input parsers */
static void
-find_open_hook(IOBUF *iop)
+find_input_parser(IOBUF *iop)
{
- struct open_hook *oh;
+ awk_input_parser_t *ip, *ip2;
- /* walk through open hooks, stop at first one that responds */
- for (oh = open_hooks; oh != NULL; oh = oh->next) {
- if ((iop->public.opaque = (*oh->open_func)(&iop->public)) != NULL)
- break;
+ /* if already associated with an input parser, bail out early */
+ if (iop->public.get_record != NULL)
+ return;
+
+ ip = ip2 = NULL;
+ for (ip2 = ip_head; ip2 != NULL; ip2 = ip2->next) {
+ if (ip2->can_take_file(& iop->public)) {
+ if (ip == NULL)
+ ip = ip2; /* found first one */
+ else
+ fatal(_("input parser `%s' conflicts with previously installed input parser `%s'"),
+ ip2->name, ip->name);
+ }
}
+
+ if (ip != NULL)
+ ip->take_control_of(& iop->public);
}
/* iop_alloc --- allocate an IOBUF structure for an open fd */
static IOBUF *
-iop_alloc(int fd, const char *name, IOBUF *iop, bool do_openhooks)
+iop_alloc(int fd, const char *name, bool do_input_parsers)
{
struct stat sbuf;
- bool iop_malloced = false;
+ IOBUF *iop;
+
+ emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
- if (iop == NULL) {
- emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
- iop_malloced = true;
- }
memset(iop, '\0', sizeof(IOBUF));
iop->public.fd = fd;
iop->public.name = name;
iop->read_func = ( ssize_t(*)() ) read;
- if (do_openhooks) {
- find_open_hook(iop);
- /* tried to find open hook and could not */
+ if (do_input_parsers) {
+ find_input_parser(iop);
+ /* tried to find open parser and could not */
if (iop->public.fd == INVALID_HANDLE) {
- if (iop_malloced)
- efree(iop);
+ efree(iop);
return NULL;
}
} else if (iop->public.fd == INVALID_HANDLE)
@@ -3300,7 +3304,6 @@ iopflags2str(int flag)
{
static const struct flagtab values[] = {
{ IOP_IS_TTY, "IOP_IS_TTY" },
- { IOP_NOFREE_OBJ, "IOP_NOFREE_OBJ" },
{ IOP_AT_EOF, "IOP_AT_EOF" },
{ IOP_CLOSED, "IOP_CLOSED" },
{ IOP_AT_START, "IOP_AT_START" },