diff options
-rw-r--r-- | ChangeLog | 23 | ||||
-rw-r--r-- | awk.h | 9 | ||||
-rw-r--r-- | ext.c | 4 | ||||
-rw-r--r-- | extension/ChangeLog | 5 | ||||
-rw-r--r-- | extension/Makefile.am | 3 | ||||
-rw-r--r-- | extension/Makefile.in | 22 | ||||
-rw-r--r-- | extension/readdir.c | 220 | ||||
-rw-r--r-- | gawkapi.c | 8 | ||||
-rw-r--r-- | gawkapi.h | 28 | ||||
-rw-r--r-- | io.c | 129 |
10 files changed, 365 insertions, 86 deletions
@@ -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 @@ -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); @@ -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; +} @@ -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, @@ -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) \ @@ -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" }, |