diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | awk.h | 1 | ||||
-rw-r--r-- | extension/ChangeLog | 9 | ||||
-rw-r--r-- | extension/Makefile.am | 5 | ||||
-rw-r--r-- | extension/Makefile.in | 19 | ||||
-rw-r--r-- | extension/configh.in | 6 | ||||
-rwxr-xr-x | extension/configure | 6 | ||||
-rw-r--r-- | extension/configure.ac | 6 | ||||
-rw-r--r-- | extension/select.c | 183 | ||||
-rw-r--r-- | gawkapi.c | 84 | ||||
-rw-r--r-- | gawkapi.h | 29 | ||||
-rw-r--r-- | io.c | 34 |
12 files changed, 379 insertions, 20 deletions
@@ -1,3 +1,20 @@ +2013-06-30 Andrew J. Schorr <aschorr@telemetry-investments.com> + * awk.h (redirect_string): Declare new function that provides API access + to the redirection mechanism. + * gawkapi.h (GAWK_API_MINOR_VERSION): Bump from 0 to 1 since 2 new + hooks were added to the api. + (gawk_api_t): Add 2 new functions api_lookup_file and api_get_file. + (lookup_file, get_file): New macros to wrap the new API functions. + * gawkapi.c (curfile): Declare this extern, since it is needed + by lookup_file and get_flie. + (api_lookup_file): Find an open file using curfile or getredirect(). + (api_get_file): Find or open a file using curfile or redirect_string(). + (api_impl): Add api_lookup_file and api_get_file. + * io.c (redirect_string): Renamed from redirect and changed arguments + to take a string instead of a 'NODE *'. This allows it to be called + through the API's new get_file hook. + (redirect): Now implemented by calling redirect_string backend function. + 2013-06-27 Arnold D. Robbins <arnold@skeeve.com> * awkgram.y: Minor whitespace cleanup, remove redundant ifdef. @@ -1517,6 +1517,7 @@ extern void set_FNR(void); extern void set_NR(void); extern struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg); +extern struct redirect *redirect_string(char *redir_exp_str, size_t redir_exp_len, int not_string_flag, int redirtype, int *errflg); extern NODE *do_close(int nargs); extern int flush_io(void); extern int close_io(bool *stdio_problem); diff --git a/extension/ChangeLog b/extension/ChangeLog index 04159df8..37cfccf2 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,12 @@ +2013-06-30 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (pkgextension_LTLIBRARIES): Add select.la. + (select_la_SOURCES, select_la_LDFLAGS, select_la_LIBADD): Build new + select extension. + * configure.ac (AC_CHECK_HEADERS): Add signal.h. + (AC_CHECK_FUNCS): Add sigaction. + * select.c: Implement the new select extension. + 2013-06-10 Arnold D. Robbins <arnold@skeeve.com> * configure.ac (AC_HEADER_MAJOR): New macro added. diff --git a/extension/Makefile.am b/extension/Makefile.am index 7b52b14b..58fc3df6 100644 --- a/extension/Makefile.am +++ b/extension/Makefile.am @@ -42,6 +42,7 @@ pkgextension_LTLIBRARIES = \ revoutput.la \ revtwoway.la \ rwarray.la \ + select.la \ testext.la \ time.la @@ -70,6 +71,10 @@ ordchr_la_SOURCES = ordchr.c ordchr_la_LDFLAGS = $(MY_MODULE_FLAGS) ordchr_la_LIBADD = $(MY_LIBS) +select_la_SOURCES = select.c +select_la_LDFLAGS = $(MY_MODULE_FLAGS) +select_la_LIBADD = $(MY_LIBS) + readdir_la_SOURCES = readdir.c gawkdirfd.h readdir_la_LDFLAGS = $(MY_MODULE_FLAGS) readdir_la_LIBADD = $(MY_LIBS) diff --git a/extension/Makefile.in b/extension/Makefile.in index 8d0a2869..97ee41fe 100644 --- a/extension/Makefile.in +++ b/extension/Makefile.in @@ -203,6 +203,12 @@ rwarray_la_OBJECTS = $(am_rwarray_la_OBJECTS) rwarray_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(rwarray_la_LDFLAGS) $(LDFLAGS) -o $@ +select_la_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_select_la_OBJECTS = select.lo +select_la_OBJECTS = $(am_select_la_OBJECTS) +select_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(select_la_LDFLAGS) $(LDFLAGS) -o $@ testext_la_DEPENDENCIES = $(am__DEPENDENCIES_2) am_testext_la_OBJECTS = testext.lo testext_la_OBJECTS = $(am_testext_la_OBJECTS) @@ -253,12 +259,14 @@ SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \ $(fork_la_SOURCES) $(inplace_la_SOURCES) $(ordchr_la_SOURCES) \ $(readdir_la_SOURCES) $(readfile_la_SOURCES) \ $(revoutput_la_SOURCES) $(revtwoway_la_SOURCES) \ - $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES) + $(rwarray_la_SOURCES) $(select_la_SOURCES) \ + $(testext_la_SOURCES) $(time_la_SOURCES) DIST_SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \ $(fork_la_SOURCES) $(inplace_la_SOURCES) $(ordchr_la_SOURCES) \ $(readdir_la_SOURCES) $(readfile_la_SOURCES) \ $(revoutput_la_SOURCES) $(revtwoway_la_SOURCES) \ - $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES) + $(rwarray_la_SOURCES) $(select_la_SOURCES) \ + $(testext_la_SOURCES) $(time_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ @@ -497,6 +505,7 @@ pkgextension_LTLIBRARIES = \ revoutput.la \ revtwoway.la \ rwarray.la \ + select.la \ testext.la \ time.la @@ -520,6 +529,9 @@ inplace_la_LIBADD = $(MY_LIBS) ordchr_la_SOURCES = ordchr.c ordchr_la_LDFLAGS = $(MY_MODULE_FLAGS) ordchr_la_LIBADD = $(MY_LIBS) +select_la_SOURCES = select.c +select_la_LDFLAGS = $(MY_MODULE_FLAGS) +select_la_LIBADD = $(MY_LIBS) readdir_la_SOURCES = readdir.c gawkdirfd.h readdir_la_LDFLAGS = $(MY_MODULE_FLAGS) readdir_la_LIBADD = $(MY_LIBS) @@ -664,6 +676,8 @@ revtwoway.la: $(revtwoway_la_OBJECTS) $(revtwoway_la_DEPENDENCIES) $(EXTRA_revtw $(AM_V_CCLD)$(revtwoway_la_LINK) -rpath $(pkgextensiondir) $(revtwoway_la_OBJECTS) $(revtwoway_la_LIBADD) $(LIBS) rwarray.la: $(rwarray_la_OBJECTS) $(rwarray_la_DEPENDENCIES) $(EXTRA_rwarray_la_DEPENDENCIES) $(AM_V_CCLD)$(rwarray_la_LINK) -rpath $(pkgextensiondir) $(rwarray_la_OBJECTS) $(rwarray_la_LIBADD) $(LIBS) +select.la: $(select_la_OBJECTS) $(select_la_DEPENDENCIES) $(EXTRA_select_la_DEPENDENCIES) + $(AM_V_CCLD)$(select_la_LINK) -rpath $(pkgextensiondir) $(select_la_OBJECTS) $(select_la_LIBADD) $(LIBS) testext.la: $(testext_la_OBJECTS) $(testext_la_DEPENDENCIES) $(EXTRA_testext_la_DEPENDENCIES) $(AM_V_CCLD)$(testext_la_LINK) -rpath $(pkgextensiondir) $(testext_la_OBJECTS) $(testext_la_LIBADD) $(LIBS) time.la: $(time_la_OBJECTS) $(time_la_DEPENDENCIES) $(EXTRA_time_la_DEPENDENCIES) @@ -686,6 +700,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/revoutput.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/revtwoway.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rwarray.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testext.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@ diff --git a/extension/configh.in b/extension/configh.in index 8571844b..a7212dc1 100644 --- a/extension/configh.in +++ b/extension/configh.in @@ -78,6 +78,12 @@ /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT +/* Define to 1 if you have the `sigaction' function. */ +#undef HAVE_SIGACTION + +/* Define to 1 if you have the <signal.h> header file. */ +#undef HAVE_SIGNAL_H + /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H diff --git a/extension/configure b/extension/configure index f59548c1..02ff3dc8 100755 --- a/extension/configure +++ b/extension/configure @@ -14002,7 +14002,8 @@ fi fi fi -for ac_header in dirent.h fnmatch.h limits.h time.h sys/time.h sys/select.h sys/param.h +for ac_header in dirent.h fnmatch.h limits.h time.h sys/time.h sys/select.h \ + sys/param.h signal.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -14017,7 +14018,8 @@ done for ac_func in fdopendir fnmatch gettimeofday \ - getdtablesize nanosleep select GetSystemTimeAsFileTime + getdtablesize nanosleep select sigaction \ + GetSystemTimeAsFileTime do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/extension/configure.ac b/extension/configure.ac index d819ebfa..5b95f966 100644 --- a/extension/configure.ac +++ b/extension/configure.ac @@ -67,10 +67,12 @@ else fi AC_HEADER_MAJOR -AC_CHECK_HEADERS(dirent.h fnmatch.h limits.h time.h sys/time.h sys/select.h sys/param.h) +AC_CHECK_HEADERS(dirent.h fnmatch.h limits.h time.h sys/time.h sys/select.h \ + sys/param.h signal.h) AC_CHECK_FUNCS(fdopendir fnmatch gettimeofday \ - getdtablesize nanosleep select GetSystemTimeAsFileTime) + getdtablesize nanosleep select sigaction \ + GetSystemTimeAsFileTime) GAWK_FUNC_DIRFD GAWK_PREREQ_DIRFD diff --git a/extension/select.c b/extension/select.c new file mode 100644 index 00000000..f74ae250 --- /dev/null +++ b/extension/select.c @@ -0,0 +1,183 @@ +/* + * select.c - Builtin functions to provide select I/O multiplexing. + */ + +/* + * Copyright (C) 2013 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 + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#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 "gawkapi.h" + +#include "gettext.h" +#define _(msgid) gettext(msgid) +#define N_(msgid) msgid + +static const gawk_api_t *api; /* for convenience macros to work */ +static awk_ext_id_t *ext_id; +static const char *ext_version = "ordchr extension: version 1.0"; +static awk_bool_t (*init_func)(void) = NULL; + +int plugin_is_GPL_compatible; + +#if defined(HAVE_SELECT) && defined(HAVE_SYS_SELECT_H) +#include <sys/select.h> +#endif + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +/* do_ord --- return numeric value of first char of string */ + +static awk_value_t * +do_select(int nargs, awk_value_t *result) +{ + static const char *argname[] = { "read", "write", "except" }; + struct { + awk_value_t array; + awk_flat_array_t *flat; + fd_set bits; + int *array2fd; + } fds[3]; + awk_value_t timeout_arg; + int i; + struct timeval maxwait; + struct timeval *timeout; + int nfds = 0; + int rc; + + if (do_lint && nargs > 5) + lintwarn(ext_id, _("select: called with too many arguments")); + +#define EL fds[i].flat->elements[j] + for (i = 0; i < sizeof(fds)/sizeof(fds[0]); i++) { + size_t j; + + if (! get_argument(i, AWK_ARRAY, & fds[i].array)) { + warning(ext_id, _("select: bad array parameter `%s'"), argname[i]); + update_ERRNO_string(_("select: bad array parameter")); + return make_number(-1, result); + } + /* N.B. flatten_array fails for empty arrays, so that's OK */ + FD_ZERO(&fds[i].bits); + if (flatten_array(fds[i].array.array_cookie, &fds[i].flat)) { + emalloc(fds[i].array2fd, int *, fds[i].flat->count*sizeof(int), "select"); + for (j = 0; j < fds[i].flat->count; j++) { + fds[i].array2fd[j] = -1; + switch (EL.index.val_type) { + case AWK_NUMBER: + if (EL.index.num_value >= 0) + fds[i].array2fd[j] = EL.index.num_value; + if (fds[i].array2fd[j] != EL.index.num_value) + fds[i].array2fd[j] = -1; + break; + case AWK_STRING: + if (EL.value.val_type == AWK_STRING) { + const awk_input_buf_t *buf; + if ((buf = get_file(EL.index.str_value.str, EL.index.str_value.len, EL.value.str_value.str, EL.value.str_value.len)) != NULL) + fds[i].array2fd[j] = buf->fd; + } + break; + } + if (fds[i].array2fd[j] < 0) { + warning(ext_id, _("select: get_file failed")); + update_ERRNO_string(_("select: get_file failed")); + if (! release_flattened_array(fds[i].array.array_cookie, fds[i].flat)) + warning(ext_id, _("select: release_flattened_array failed")); + free(fds[i].array2fd); + return make_number(-1, result); + } + FD_SET(fds[i].array2fd[j], &fds[i].bits); + if (nfds <= fds[i].array2fd[j]) + nfds = fds[i].array2fd[j]+1; + } + } + else + fds[i].flat = NULL; + } + if (get_argument(3, AWK_NUMBER, &timeout_arg)) { + double secs = timeout_arg.num_value; + if (secs < 0) { + warning(ext_id, _("select: treating negative timeout as zero")); + secs = 0; + } + maxwait.tv_sec = secs; + maxwait.tv_usec = (secs-(double)maxwait.tv_sec)*1000000.0; + timeout = &maxwait; + } else + timeout = NULL; + rc = select(nfds, &fds[0].bits, &fds[1].bits, &fds[2].bits, timeout); + + if (rc < 0) { + update_ERRNO_int(errno); + /* bit masks are undefined, so delete all array entries */ + for (i = 0; i < sizeof(fds)/sizeof(fds[0]); i++) { + if (fds[i].flat) { + size_t j; + for (j = 0; j < fds[i].flat->count; j++) + EL.flags |= AWK_ELEMENT_DELETE; + if (! release_flattened_array(fds[i].array.array_cookie, fds[i].flat)) + warning(ext_id, _("select: release_flattened_array failed")); + free(fds[i].array2fd); + } + } + return make_number(rc, result); + } + + for (i = 0; i < sizeof(fds)/sizeof(fds[0]); i++) { + if (fds[i].flat) { + size_t j; + /* remove array elements not set in the bit mask */ + for (j = 0; j < fds[i].flat->count; j++) { + if (! FD_ISSET(fds[i].array2fd[j], &fds[i].bits)) + EL.flags |= AWK_ELEMENT_DELETE; + } + if (! release_flattened_array(fds[i].array.array_cookie, fds[i].flat)) + warning(ext_id, _("select: release_flattened_array failed")); + free(fds[i].array2fd); + } + } +#undef EL + + /* Set the return value */ + return make_number(rc, result); +} + +static awk_ext_func_t func_table[] = { + { "select", do_select, 5 }, +}; + +/* define the dl_load function using the boilerplate macro */ + +dl_load_func(func_table, select, "") @@ -25,6 +25,8 @@ #include "awk.h" +extern IOBUF *curfile; /* required by api_lookup_file and api_get_file */ + static awk_bool_t node_to_awk_value(NODE *node, awk_value_t *result, awk_valtype_t wanted); /* @@ -1028,6 +1030,84 @@ api_release_value(awk_ext_id_t id, awk_value_cookie_t value) return true; } +/* api_lookup_file --- return a handle to an open file */ + +static const awk_input_buf_t * +api_lookup_file(awk_ext_id_t id, const char *name, size_t namelen) +{ + const struct redirect *f; + + if ((name == NULL) || (namelen == 0)) { + if (curfile == NULL) + return NULL; + return &curfile->public; + } + if ((f = getredirect(name, namelen)) == NULL) + return NULL; + return &f->iop->public; +} + +/* api_get_file --- return a handle to an existing or newly opened file */ + +static const awk_input_buf_t * +api_get_file(awk_ext_id_t id, const char *name, size_t namelen, const char *filetype, size_t typelen) +{ + const struct redirect *f; + int flag; /* not used, sigh */ + enum redirval redirtype; + + if ((name == NULL) || (namelen == 0)) { + if (curfile == NULL) { + if (nextfile(& curfile, false) <= 0) + return NULL; + /* XXX Fix me! */ + fputs("Bug: need to call BEGINFILE!\n", stderr); + } + return &curfile->public; + } + redirtype = redirect_none; + switch (typelen) { + case 1: + switch (*filetype) { + case '<': + redirtype = redirect_input; + break; + case '>': + redirtype = redirect_output; + break; + } + break; + case 2: + switch (*filetype) { + case '>': + if (filetype[1] == '>') + redirtype = redirect_append; + break; + case '|': + switch (filetype[1]) { + case '>': + redirtype = redirect_pipe; + break; + case '<': + redirtype = redirect_pipein; + break; + case '&': + redirtype = redirect_twoway; + break; + } + break; + } + } + if (redirtype == redirect_none) { + warning(_("cannot open unrecognized file type `%s' for `%s'"), + filetype, name); + return NULL; + } + if ((f = redirect_string(name, namelen, 0, redirtype, &flag)) == NULL) + return NULL; + return &f->iop->public; +} + /* * Register a version string for this extension with gawk. */ @@ -1107,6 +1187,10 @@ gawk_api_t api_impl = { api_clear_array, api_flatten_array, api_release_flattened_array, + + /* Find/get open files */ + api_lookup_file, + api_get_file, }; /* init_ext_api --- init the extension API */ @@ -264,7 +264,7 @@ typedef struct awk_two_way_processor { /* Current version of the API. */ enum { GAWK_API_MAJOR_VERSION = 1, - GAWK_API_MINOR_VERSION = 0 + GAWK_API_MINOR_VERSION = 1 }; /* A number of typedefs related to different types of values. */ @@ -665,6 +665,27 @@ typedef struct gawk_api { awk_bool_t (*api_release_flattened_array)(awk_ext_id_t id, awk_array_t a_cookie, awk_flat_array_t *data); + + /* + * Look up a currently open file. If the name is NULL, it returns + * data for the currently open input file corresponding to FILENAME. + * If the file is not found, it returns NULL. + */ + const awk_input_buf_t *(*api_lookup_file)(awk_ext_id_t id, + const char *name, + size_t name_len); + /* + * Look up a file. If the name is NULL, it returns + * data for the currently open input file corresponding to FILENAME. + * If the file is not already open, it tries to open it. + * The "filetype" argument should be one of: + * ">", ">>", "<", "|>", "|<", and "|&" + */ + const awk_input_buf_t *(*api_get_file)(awk_ext_id_t id, + const char *name, + size_t name_len, + const char *filetype, + size_t typelen); } gawk_api_t; #ifndef GAWK /* these are not for the gawk code itself! */ @@ -742,6 +763,12 @@ typedef struct gawk_api { #define release_value(value) \ (api->api_release_value(ext_id, value)) +#define lookup_file(name, namelen) \ + (api->api_lookup_file(ext_id, name, namelen)) + +#define get_file(name, namelen, filetype, typelen) \ + (api->api_get_file(ext_id, name, namelen, filetype, typelen)) + #define register_ext_version(version) \ (api->api_register_ext_version(ext_id, version)) @@ -686,10 +686,9 @@ redflags2str(int flags) /* redirect --- Redirection for printf and print commands */ struct redirect * -redirect(NODE *redir_exp, int redirtype, int *errflg) +redirect_string(char *str, size_t explen, int not_string, int redirtype, int *errflg) { struct redirect *rp; - char *str; int tflag = 0; int outflag = 0; const char *direction = "to"; @@ -736,18 +735,16 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) default: cant_happen(); } - if (do_lint && (redir_exp->flags & STRCUR) == 0) + if (do_lint && not_string) lintwarn(_("expression in `%s' redirection only has numeric value"), what); - redir_exp = force_string(redir_exp); - str = redir_exp->stptr; if (str == NULL || *str == '\0') fatal(_("expression for `%s' redirection has null string value"), what); - if (do_lint && (strncmp(str, "0", redir_exp->stlen) == 0 - || strncmp(str, "1", redir_exp->stlen) == 0)) + if (do_lint && (strncmp(str, "0", explen) == 0 + || strncmp(str, "1", explen) == 0)) lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"), str, what); @@ -785,8 +782,8 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) #endif /* PIPES_SIMULATED */ /* now check for a match */ - if (strlen(rp->value) == redir_exp->stlen - && memcmp(rp->value, str, redir_exp->stlen) == 0 + if (strlen(rp->value) == explen + && memcmp(rp->value, str, explen) == 0 && ((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag || (outflag != 0 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) { @@ -797,22 +794,24 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) if (do_lint && rpflag != newflag) lintwarn( _("unnecessary mixing of `>' and `>>' for file `%.*s'"), - (int) redir_exp->stlen, rp->value); + (int) explen, rp->value); break; } } if (rp == NULL) { + char *newstr; new_rp = true; if (save_rp != NULL) { rp = save_rp; efree(rp->value); } else emalloc(rp, struct redirect *, sizeof(struct redirect), "redirect"); - emalloc(str, char *, redir_exp->stlen + 1, "redirect"); - memcpy(str, redir_exp->stptr, redir_exp->stlen); - str[redir_exp->stlen] = '\0'; + emalloc(newstr, char *, explen + 1, "redirect"); + memcpy(newstr, str, explen); + newstr[explen] = '\0'; + str = newstr; rp->value = str; rp->flag = tflag; init_output_wrapper(& rp->output); @@ -998,6 +997,15 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) return rp; } +struct redirect * +redirect(NODE *redir_exp, int redirtype, int *errflg) +{ + int not_string = ((redir_exp->flags & STRCUR) == 0); + redir_exp = force_string(redir_exp); + return redirect_string(redir_exp->stptr, redir_exp->stlen, not_string, + redirtype, errflg); +} + /* getredirect --- find the struct redirect for this file or pipe */ struct redirect * |