aboutsummaryrefslogtreecommitdiffstats
path: root/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'io.c')
-rw-r--r--io.c322
1 files changed, 254 insertions, 68 deletions
diff --git a/io.c b/io.c
index d700d87a..d618181d 100644
--- a/io.c
+++ b/io.c
@@ -190,7 +190,7 @@
#define setsid() /* nothing */
#endif /* HAVE_SETSID */
-#if defined(GAWK_AIX)
+#if defined(_AIX)
#undef TANDEM /* AIX defines this in one of its header files */
#endif
@@ -265,7 +265,6 @@ struct recmatch {
static int iop_close(IOBUF *iop);
-struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg);
static void close_one(void);
static int close_redir(struct redirect *rp, bool exitwarn, two_way_close_type how);
#ifndef PIPES_SIMULATED
@@ -276,7 +275,7 @@ static IOBUF *iop_alloc(int fd, const char *name, int errno_val);
static IOBUF *iop_finish(IOBUF *iop);
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 two_way_open(const char *str, struct redirect *rp, int extfd);
static int pty_vs_pipe(const char *command);
static void find_input_parser(IOBUF *iop);
static bool find_output_wrapper(awk_output_buf_t *outbuf);
@@ -324,6 +323,8 @@ static Regexp *RS_re_yes_case; /* regexp for RS when ignoring case */
static Regexp *RS_re_no_case; /* regexp for RS when not ignoring case */
static Regexp *RS_regexp;
+static const char nonfatal[] = "NONFATAL";
+
bool RS_is_null;
extern NODE *ARGC_node;
@@ -600,7 +601,8 @@ inrec(IOBUF *iop, int *errcode)
else
cnt = get_a_record(& begin, iop, errcode);
- if (cnt == EOF) {
+ /* Note that get_a_record may return -2 when I/O would block */
+ if (cnt < 0) {
retval = false;
} else {
INCREMENT_REC(NR);
@@ -728,13 +730,13 @@ redflags2str(int flags)
return genflags2str(flags, redtab);
}
-/* redirect --- Redirection for printf and print commands */
+/* redirect_string --- Redirection for printf and print commands, use string info */
struct redirect *
-redirect(NODE *redir_exp, int redirtype, int *errflg)
+redirect_string(const char *str, size_t explen, bool not_string,
+ int redirtype, int *errflg, int extfd, bool failure_fatal)
{
struct redirect *rp;
- char *str;
int tflag = 0;
int outflag = 0;
const char *direction = "to";
@@ -783,18 +785,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);
@@ -832,8 +832,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))) {
@@ -844,23 +844,25 @@ 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';
- rp->value = str;
+ emalloc(newstr, char *, explen + 1, "redirect");
+ memcpy(newstr, str, explen);
+ newstr[explen] = '\0';
+ str = newstr;
+ rp->value = newstr;
rp->flag = tflag;
init_output_wrapper(& rp->output);
rp->output.name = str;
@@ -892,10 +894,20 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
mode = binmode("a");
break;
case redirect_pipe:
+ if (extfd >= 0) {
+ warning(_("get_file cannot create pipe `%s' with fd %d"), str, extfd);
+ return NULL;
+ }
/* synchronize output before new pipe */
(void) flush_io();
os_restore_mode(fileno(stdin));
+ /*
+ * Don't check failure_fatal; see input pipe below.
+ * Note that the failure happens upon failure to fork,
+ * using a non-existant program will still succeed the
+ * popen().
+ */
if ((rp->output.fp = popen(str, binmode("w"))) == NULL)
fatal(_("can't open pipe `%s' for output (%s)"),
str, strerror(errno));
@@ -905,6 +917,10 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
rp->flag |= RED_NOBUF;
break;
case redirect_pipein:
+ if (extfd >= 0) {
+ warning(_("get_file cannot create pipe `%s' with fd %d"), str, extfd);
+ return NULL;
+ }
direction = "from";
if (gawk_popen(str, rp) == NULL)
fatal(_("can't open pipe `%s' for input (%s)"),
@@ -912,7 +928,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
break;
case redirect_input:
direction = "from";
- fd = devopen(str, binmode("r"));
+ fd = (extfd >= 0) ? extfd : devopen(str, binmode("r"));
if (fd == INVALID_HANDLE && errno == EISDIR) {
*errflg = EISDIR;
/* do not free rp, saving it for reuse (save_rp = rp) */
@@ -929,15 +945,19 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
}
break;
case redirect_twoway:
+#ifndef HAVE_SOCKETS
+ if (extfd >= 0) {
+ warning(_("get_file socket creation not supported on this platform for `%s' with fd %d"), str, extfd);
+ return NULL;
+ }
+#endif
direction = "to/from";
- if (! two_way_open(str, rp)) {
-#ifdef HAVE_SOCKETS
- if (inetfile(str, NULL)) {
+ if (! two_way_open(str, rp, extfd)) {
+ if (! failure_fatal || is_non_fatal_redirect(str)) {
*errflg = errno;
/* do not free rp, saving it for reuse (save_rp = rp) */
return NULL;
} else
-#endif
fatal(_("can't open two way pipe `%s' for input/output (%s)"),
str, strerror(errno));
}
@@ -949,7 +969,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
if (mode != NULL) {
errno = 0;
rp->output.mode = mode;
- fd = devopen(str, mode);
+ fd = (extfd >= 0) ? extfd : devopen(str, mode);
if (fd > INVALID_HANDLE) {
if (fd == fileno(stdin))
@@ -1015,11 +1035,14 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
* can return -1. For output to file,
* complain. The shell will complain on
* a bad command to a pipe.
+ *
+ * 12/2014: Take nonfatal settings in PROCINFO into account.
*/
if (errflg != NULL)
*errflg = errno;
- if ( redirtype == redirect_output
- || redirtype == redirect_append) {
+ if (failure_fatal && ! is_non_fatal_redirect(str) &&
+ (redirtype == redirect_output
+ || redirtype == redirect_append)) {
/* multiple messages make life easier for translators */
if (*direction == 'f')
fatal(_("can't redirect from `%s' (%s)"),
@@ -1050,6 +1073,18 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
return rp;
}
+/* redirect --- Redirection for printf and print commands */
+
+struct redirect *
+redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal)
+{
+ bool 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, -1, failure_fatal);
+}
+
/* getredirect --- find the struct redirect for this file or pipe */
struct redirect *
@@ -1064,6 +1099,34 @@ getredirect(const char *str, int len)
return NULL;
}
+/* is_non_fatal_std --- return true if fp is stdout/stderr and nonfatal */
+
+bool
+is_non_fatal_std(FILE *fp)
+{
+ if (in_PROCINFO(nonfatal, NULL, NULL))
+ return true;
+
+ /* yucky logic. sigh. */
+ if (fp == stdout) {
+ return ( in_PROCINFO("-", nonfatal, NULL) != NULL
+ || in_PROCINFO("/dev/stdout", nonfatal, NULL) != NULL);
+ } else if (fp == stderr) {
+ return (in_PROCINFO("/dev/stderr", nonfatal, NULL) != NULL);
+ }
+
+ return false;
+}
+
+/* is_non_fatal_redirect --- return true if redirected I/O should be nonfatal */
+
+bool
+is_non_fatal_redirect(const char *str)
+{
+ return in_PROCINFO(nonfatal, NULL, NULL) != NULL
+ || in_PROCINFO(str, nonfatal, NULL) != NULL;
+}
+
/* close_one --- temporarily close an open file to re-use the fd */
static void
@@ -1436,7 +1499,7 @@ str2mode(const char *mode)
static int
socketopen(int family, int type, const char *localpname,
- const char *remotepname, const char *remotehostname)
+ const char *remotepname, const char *remotehostname, bool *hard_error)
{
struct addrinfo *lres, *lres0;
struct addrinfo lhints;
@@ -1455,8 +1518,11 @@ socketopen(int family, int type, const char *localpname,
lerror = getaddrinfo(NULL, localpname, & lhints, & lres);
if (lerror) {
- if (strcmp(localpname, "0") != 0)
- fatal(_("local port %s invalid in `/inet'"), localpname);
+ if (strcmp(localpname, "0") != 0) {
+ warning(_("local port %s invalid in `/inet'"), localpname);
+ *hard_error = true;
+ return INVALID_HANDLE;
+ }
lres0 = NULL;
lres = & lhints;
} else
@@ -1474,7 +1540,9 @@ socketopen(int family, int type, const char *localpname,
if (rerror) {
if (lres0 != NULL)
freeaddrinfo(lres0);
- fatal(_("remote host and port information (%s, %s) invalid"), remotehostname, remotepname);
+ warning(_("remote host and port information (%s, %s) invalid"), remotehostname, remotepname);
+ *hard_error = true;
+ return INVALID_HANDLE;
}
rres0 = rres;
socket_fd = INVALID_HANDLE;
@@ -1640,6 +1708,7 @@ devopen(const char *name, const char *mode)
char *cp;
int flag;
struct inet_socket_info isi;
+ int save_errno = 0;
openfd = devopen_simple(name, mode, false);
if (openfd != INVALID_HANDLE)
@@ -1651,6 +1720,14 @@ devopen(const char *name, const char *mode)
goto strictopen;
} else if (inetfile(name, & isi)) {
#ifdef HAVE_SOCKETS
+#define DEFAULT_RETRIES 20
+ static unsigned long def_retries = DEFAULT_RETRIES;
+ static bool first_time = true;
+ unsigned long retries = 0;
+ static long msleep = 1000;
+ bool hard_error = false;
+ bool non_fatal = is_non_fatal_redirect(name);
+
cp = (char *) name;
/* socketopen requires NUL-terminated strings */
@@ -1658,13 +1735,6 @@ devopen(const char *name, const char *mode)
cp[isi.remotehost.offset+isi.remotehost.len] = '\0';
/* remoteport comes last, so already NUL-terminated */
- {
-#define DEFAULT_RETRIES 20
- static unsigned long def_retries = DEFAULT_RETRIES;
- static bool first_time = true;
- unsigned long retries = 0;
- static long msleep = 1000;
-
if (first_time) {
char *cp, *end;
unsigned long count = 0;
@@ -1690,25 +1760,41 @@ devopen(const char *name, const char *mode)
msleep *= 1000;
}
}
- retries = def_retries;
+ /*
+ * PROCINFO["NONFATAL"] or PROCINFO[name, "NONFATAL"] overrrides
+ * GAWK_SOCK_RETRIES. The explicit code in the program carries
+ * a bigger stick than the environment variable does.
+ */
+ retries = non_fatal ? 1 : def_retries;
+ errno = 0;
do {
- openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset, name+isi.remoteport.offset, name+isi.remotehost.offset);
+ openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset,
+ name+isi.remoteport.offset, name+isi.remotehost.offset,
+ & hard_error);
retries--;
- } while (openfd == INVALID_HANDLE && retries > 0 && usleep(msleep) == 0);
- }
+ } while (openfd == INVALID_HANDLE && ! hard_error && retries > 0 && usleep(msleep) == 0);
+ save_errno = errno;
- /* restore original name string */
- cp[isi.localport.offset+isi.localport.len] = '/';
- cp[isi.remotehost.offset+isi.remotehost.len] = '/';
+ /* restore original name string */
+ cp[isi.localport.offset+isi.localport.len] = '/';
+ cp[isi.remotehost.offset+isi.remotehost.len] = '/';
#else /* ! HAVE_SOCKETS */
- fatal(_("TCP/IP communications are not supported"));
+ fatal(_("TCP/IP communications are not supported"));
#endif /* HAVE_SOCKETS */
}
strictopen:
- if (openfd == INVALID_HANDLE)
+ if (openfd == INVALID_HANDLE) {
openfd = open(name, flag, 0666);
+ /*
+ * ENOENT means there is no such name in the filesystem.
+ * Therefore it's ok to propagate up the error from
+ * getaddrinfo() that's in save_errno.
+ */
+ if (openfd == INVALID_HANDLE && errno == ENOENT && save_errno)
+ errno = save_errno;
+ }
#if defined(__EMX__) || defined(__MINGW32__)
if (openfd == INVALID_HANDLE && errno == EACCES) {
/* On OS/2 and Windows directory access via open() is
@@ -1731,16 +1817,16 @@ strictopen:
/* two_way_open --- open a two way communications channel */
static int
-two_way_open(const char *str, struct redirect *rp)
+two_way_open(const char *str, struct redirect *rp, int extfd)
{
static bool no_ptys = false;
#ifdef HAVE_SOCKETS
/* case 1: socket */
- if (inetfile(str, NULL)) {
+ if (extfd >= 0 || inetfile(str, NULL)) {
int fd, newfd;
- fd = devopen(str, "rw");
+ fd = (extfd >= 0) ? extfd : devopen(str, "rw");
if (fd == INVALID_HANDLE)
return false;
if ((BINMODE & BINMODE_OUTPUT) != 0)
@@ -2211,17 +2297,43 @@ use_pipes:
#ifndef PIPES_SIMULATED /* real pipes */
-/* wait_any --- wait for a child process, close associated pipe */
+/*
+ * wait_any --- if the argument pid is 0, wait for all child processes that
+ * have exited. We loop to make sure to reap all children that have exited to
+ * minimize the risk of running out of process slots. Since we don't process
+ * SIGCHLD, we do not immediately reap exited children. So when we get here,
+ * we want to reap any that have piled up.
+ *
+ * Note: on platforms that do not support waitpid with WNOHANG, when called with
+ * a zero argument, this function will hang until all children have exited.
+ *
+ * AJS, 2013-07-07: I do not see why we need to ignore signals during this
+ * function. This function just waits and updates the pid and status fields.
+ * I don't see why that should interfere with any signal handlers. But I am
+ * reluctant to remove this protection. So I changed to use sigprocmask to
+ * block signals instead to avoid interfering with installed signal handlers.
+ */
static int
wait_any(int interesting) /* pid of interest, if any */
{
- RETSIGTYPE (*hstat)(int), (*istat)(int), (*qstat)(int);
int pid;
int status = 0;
struct redirect *redp;
+#ifdef HAVE_SIGPROCMASK
+ sigset_t set, oldset;
+
+ /* I have no idea why we are blocking signals during this function... */
+ sigemptyset(& set);
+ sigaddset(& set, SIGINT);
+ sigaddset(& set, SIGHUP);
+ sigaddset(& set, SIGQUIT);
+ sigprocmask(SIG_BLOCK, & set, & oldset);
+#else
+ void (*hstat)(int), (*istat)(int), (*qstat)(int);
istat = signal(SIGINT, SIG_IGN);
+#endif
#ifdef __MINGW32__
if (interesting < 0) {
status = -1;
@@ -2237,11 +2349,22 @@ wait_any(int interesting) /* pid of interest, if any */
break;
}
}
-#else
+#else /* ! __MINGW32__ */
+#ifndef HAVE_SIGPROCMASK
hstat = signal(SIGHUP, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
+#endif
for (;;) {
-# ifdef HAVE_SYS_WAIT_H /* POSIX compatible sys/wait.h */
+# if defined(HAVE_WAITPID) && defined(WNOHANG)
+ /*
+ * N.B. If the caller wants status for a specific child process
+ * (i.e. interesting is non-zero), then we must hang until we
+ * get exit status for that child.
+ */
+ if ((pid = waitpid(-1, & status, (interesting ? 0 : WNOHANG))) == 0)
+ /* No children have exited */
+ break;
+# elif defined(HAVE_SYS_WAIT_H) /* POSIX compatible sys/wait.h */
pid = wait(& status);
# else
pid = wait((union wait *) & status);
@@ -2259,10 +2382,16 @@ wait_any(int interesting) /* pid of interest, if any */
if (pid == -1 && errno == ECHILD)
break;
}
+#ifndef HAVE_SIGPROCMASK
signal(SIGHUP, hstat);
signal(SIGQUIT, qstat);
#endif
+#endif /* ! __MINGW32__ */
+#ifndef HAVE_SIGPROCMASK
signal(SIGINT, istat);
+#else
+ sigprocmask(SIG_SETMASK, & oldset, NULL);
+#endif
return status;
}
@@ -2464,7 +2593,7 @@ do_getline_redir(int into_variable, enum redirval redirtype)
assert(redirtype != redirect_none);
redir_exp = TOP();
- rp = redirect(redir_exp, redirtype, & redir_error);
+ rp = redirect(redir_exp, redirtype, & redir_error, false);
DEREF(redir_exp);
decr_sp();
if (rp == NULL) {
@@ -2483,7 +2612,7 @@ do_getline_redir(int into_variable, enum redirval redirtype)
if (errcode != 0) {
if (! do_traditional && (errcode != -1))
update_ERRNO_int(errcode);
- return make_number((AWKNUM) -1.0);
+ return make_number((AWKNUM) cnt);
}
if (cnt == EOF) {
@@ -2533,7 +2662,7 @@ do_getline(int into_variable, IOBUF *iop)
update_ERRNO_int(errcode);
if (into_variable)
(void) POP_ADDRESS();
- return make_number((AWKNUM) -1.0);
+ return make_number((AWKNUM) cnt);
}
if (cnt == EOF)
@@ -2597,6 +2726,7 @@ init_awkpath(path_info *pi)
end++;
len = end - start;
if (len > 0) {
+ /* +2 is correct here; leave room for / */
emalloc(p, char *, len + 2, "init_awkpath");
memcpy(p, start, len);
@@ -3051,7 +3181,7 @@ iop_finish(IOBUF *iop)
lintwarn(_("data file `%s' is empty"), iop->public.name);
iop->errcode = errno = 0;
iop->count = iop->scanoff = 0;
- emalloc(iop->buf, char *, iop->size += 2, "iop_finish");
+ emalloc(iop->buf, char *, iop->size += 1, "iop_finish");
iop->off = iop->buf;
iop->dataend = NULL;
iop->end = iop->buf + iop->size;
@@ -3083,10 +3213,10 @@ grow_iop_buffer(IOBUF *iop)
size_t newsize;
/*
- * Lop off original extra two bytes, double the size,
- * add them back.
+ * Lop off original extra byte, double the size,
+ * add it back.
*/
- newsize = ((iop->size - 2) * 2) + 2;
+ newsize = ((iop->size - 1) * 2) + 1;
/* Check for overflow */
if (newsize <= iop->size)
@@ -3094,7 +3224,7 @@ grow_iop_buffer(IOBUF *iop)
/* Make sure there's room for a disk block */
if (newsize - valid < iop->readsize)
- newsize += iop->readsize + 2;
+ newsize += iop->readsize + 1;
/* Check for overflow, again */
if (newsize <= iop->size)
@@ -3426,10 +3556,45 @@ find_longest_terminator:
return REC_OK;
}
+/* retryable --- return true if PROCINFO[<filename>, "RETRY"] exists */
+
+static inline int
+retryable(IOBUF *iop)
+{
+ return PROCINFO_node && in_PROCINFO(iop->public.name, "RETRY", NULL);
+}
+
+/* errno_io_retry --- Does the I/O error indicate that the operation should be retried later? */
+
+static inline int
+errno_io_retry(void)
+{
+ switch (errno) {
+#ifdef EAGAIN
+ case EAGAIN:
+#endif
+#ifdef EWOULDBLOCK
+#if !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)
+ case EWOULDBLOCK:
+#endif
+#endif
+#ifdef EINTR
+ case EINTR:
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT:
+#endif
+ return 1;
+ default:
+ return 0;
+ }
+}
+
/*
* get_a_record --- read a record from IOP into out,
* return length of EOF, set RT.
* Note that errcode is never NULL, and the caller initializes *errcode to 0.
+ * If I/O would block, return -2.
*/
static int
@@ -3473,8 +3638,10 @@ get_a_record(char **out, /* pointer to pointer to data */
iop->flag |= IOP_AT_EOF;
return EOF;
} else if (iop->count == -1) {
- iop->flag |= IOP_AT_EOF;
*errcode = errno;
+ if (errno_io_retry() && retryable(iop))
+ return -2;
+ iop->flag |= IOP_AT_EOF;
return EOF;
} else {
iop->dataend = iop->buf + iop->count;
@@ -3548,6 +3715,8 @@ get_a_record(char **out, /* pointer to pointer to data */
iop->count = iop->public.read_func(iop->public.fd, iop->dataend, amt_to_read);
if (iop->count == -1) {
*errcode = errno;
+ if (errno_io_retry() && retryable(iop))
+ return -2;
iop->flag |= IOP_AT_EOF;
break;
} else if (iop->count == 0) {
@@ -3699,8 +3868,10 @@ pty_vs_pipe(const char *command)
#ifdef HAVE_TERMIOS_H
NODE *val;
- if (PROCINFO_node == NULL)
- return false;
+ /*
+ * N.B. No need to check for NULL PROCINFO_node, since the
+ * in_PROCINFO function now checks that for us.
+ */
val = in_PROCINFO(command, "pty", NULL);
if (val) {
if ((val->flags & MAYBE_NUM) != 0)
@@ -3842,12 +4013,21 @@ in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx)
NODE *r, *sub = NULL;
NODE *subsep = SUBSEP_node->var_value;
+ if (PROCINFO_node == NULL || (pidx1 == NULL && pidx2 == NULL))
+ return NULL;
+
/* full_idx is in+out parameter */
if (full_idx)
sub = *full_idx;
- str_len = strlen(pidx1) + subsep->stlen + strlen(pidx2);
+ if (pidx1 != NULL && pidx2 == NULL)
+ str_len = strlen(pidx1);
+ else if (pidx1 == NULL && pidx2 != NULL)
+ str_len = strlen(pidx2);
+ else
+ str_len = strlen(pidx1) + subsep->stlen + strlen(pidx2);
+
if (sub == NULL) {
emalloc(str, char *, str_len + 1, "in_PROCINFO");
sub = make_str_node(str, str_len, ALREADY_MALLOCED);
@@ -3861,8 +4041,14 @@ in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx)
sub->stlen = str_len;
}
- sprintf(sub->stptr, "%s%.*s%s", pidx1, (int)subsep->stlen,
- subsep->stptr, pidx2);
+ if (pidx1 != NULL && pidx2 == NULL)
+ strcpy(sub->stptr, pidx1);
+ else if (pidx1 == NULL && pidx2 != NULL)
+ strcpy(sub->stptr, pidx2);
+ else
+ sprintf(sub->stptr, "%s%.*s%s", pidx1, (int)subsep->stlen,
+ subsep->stptr, pidx2);
+
r = in_array(PROCINFO_node, sub);
if (! full_idx)
unref(sub);