source: vendor/gawk/3.1.5/io.c@ 3513

Last change on this file since 3513 was 3076, checked in by bird, 18 years ago

gawk 3.1.5

File size: 84.3 KB
Line 
1/*
2 * io.c --- routines for dealing with input and output and records
3 */
4
5/*
6 * Copyright (C) 1986, 1988, 1989, 1991-2005 the Free Software Foundation, Inc.
7 *
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Programming Language.
10 *
11 * GAWK is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * GAWK is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "awk.h"
27
28#ifdef HAVE_SYS_PARAM_H
29#undef RE_DUP_MAX /* avoid spurious conflict w/regex.h */
30#include <sys/param.h>
31#endif /* HAVE_SYS_PARAM_H */
32
33#ifndef O_RDONLY
34#include <fcntl.h>
35#endif
36#ifndef O_ACCMODE
37#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
38#endif
39
40#ifdef HAVE_TERMIOS_H
41#include <termios.h>
42#endif
43#ifdef HAVE_STROPTS_H
44#include <stropts.h>
45#endif
46
47#ifdef HAVE_SOCKETS
48#ifdef HAVE_SYS_SOCKET_H
49#include <sys/socket.h>
50#else
51#include <socket.h>
52#endif /* HAVE_SYS_SOCKET_H */
53#ifdef HAVE_NETINET_IN_H
54#include <netinet/in.h>
55#else
56#include <in.h>
57#endif /* HAVE_NETINET_IN_H */
58#ifdef HAVE_NETDB_H
59#include <netdb.h>
60#endif /* HAVE_NETDB_H */
61#endif /* HAVE_SOCKETS */
62
63#ifdef __EMX__
64#include <process.h>
65#endif
66
67#ifndef ENFILE
68#define ENFILE EMFILE
69#endif
70
71extern int MRL;
72
73#ifdef HAVE_SOCKETS
74enum inet_prot { INET_NONE, INET_TCP, INET_UDP, INET_RAW };
75
76#ifndef SHUT_RD
77#define SHUT_RD 0
78#endif
79
80#ifndef SHUT_WR
81#define SHUT_WR 1
82#endif
83
84#ifndef SHUT_RDWR
85#define SHUT_RDWR 2
86#endif
87
88#endif /* HAVE_SOCKETS */
89
90#ifdef atarist
91#include <stddef.h>
92#endif
93
94#if defined(GAWK_AIX)
95#undef TANDEM /* AIX defines this in one of its header files */
96#undef MSDOS /* For good measure, */
97#undef WIN32 /* yes, I'm paranoid */
98#endif
99
100#if defined(MSDOS) || defined(WIN32) || defined(TANDEM)
101#define PIPES_SIMULATED
102#endif
103
104typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type;
105
106/* Several macros make the code a bit clearer: */
107/* */
108/* */
109/* <defines and enums>= */
110#define at_eof(iop) ((iop->flag & IOP_AT_EOF) != 0)
111#define has_no_data(iop) (iop->dataend == NULL)
112#define no_data_left(iop) (iop->off >= iop->dataend)
113/* The key point to the design is to split out the code that searches through */
114/* a buffer looking for the record and the terminator into separate routines, */
115/* with a higher-level routine doing the reading of data and buffer management. */
116/* This makes the code easier to manage; the buffering code is the same independent */
117/* of how we find a record. Communication is via the return value: */
118/* */
119/* */
120/* <defines and enums>= */
121typedef enum recvalues {
122 REC_OK, /* record and terminator found, recmatch struct filled in */
123 NOTERM, /* no terminator found, give me more input data */
124 TERMATEND, /* found terminator at end of buffer */
125 TERMNEAREND /* found terminator close to end of buffer, for RE might be bigger */
126} RECVALUE;
127/* Between calls to a scanning routine, the state is stored in */
128/* an [[enum scanstate]] variable. Not all states apply to all */
129/* variants, but the higher code doesn't really care. */
130/* */
131/* */
132/* <defines and enums>= */
133typedef enum scanstate {
134 NOSTATE, /* scanning not started yet (all) */
135 INLEADER, /* skipping leading data (RS = "") */
136 INDATA, /* in body of record (all) */
137 INTERM /* scanning terminator (RS = "", RS = regexp) */
138} SCANSTATE;
139/* When a record is seen ([[REC_OK]] or [[TERMATEND]]), the following */
140/* structure is filled in. */
141/* */
142/* */
143/* <recmatch>= */
144struct recmatch {
145 char *start; /* record start */
146 size_t len; /* length of record */
147 char *rt_start; /* start of terminator */
148 size_t rt_len; /* length of terminator */
149};
150
151static IOBUF *nextfile P((int skipping));
152static int inrec P((IOBUF *iop));
153static int iop_close P((IOBUF *iop));
154struct redirect *redirect P((NODE *tree, int *errflg));
155static void close_one P((void));
156static int close_redir P((struct redirect *rp, int exitwarn, two_way_close_type how));
157#ifndef PIPES_SIMULATED
158static int wait_any P((int interesting));
159#endif
160static IOBUF *gawk_popen P((const char *cmd, struct redirect *rp));
161static IOBUF *iop_open P((const char *file, const char *how, IOBUF *buf));
162static IOBUF *iop_alloc P((int fd, const char *name, IOBUF *buf));
163static int gawk_pclose P((struct redirect *rp));
164static int do_pathopen P((const char *file));
165static int str2mode P((const char *mode));
166static void spec_setup P((IOBUF *iop, int len, int allocate));
167static int specfdopen P((IOBUF *iop, const char *name, const char *mode));
168static int pidopen P((IOBUF *iop, const char *name, const char *mode));
169static int useropen P((IOBUF *iop, const char *name, const char *mode));
170static int two_way_open P((const char *str, struct redirect *rp));
171static int pty_vs_pipe P((const char *command));
172
173static RECVALUE rs1scan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state));
174static RECVALUE rsnullscan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state));
175static RECVALUE rsrescan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state));
176
177static RECVALUE (*matchrec) P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)) = rs1scan;
178
179static int get_a_record P((char **out, IOBUF *iop, int *errcode));
180
181#if defined(HAVE_POPEN_H)
182#include "popen.h"
183#endif
184
185static struct redirect *red_head = NULL;
186static NODE *RS;
187static Regexp *RS_re_yes_case;
188static Regexp *RS_re_no_case;
189static Regexp *RS_regexp;
190
191int RS_is_null;
192
193extern int output_is_tty;
194extern NODE *ARGC_node;
195extern NODE *ARGV_node;
196extern NODE *ARGIND_node;
197extern NODE *ERRNO_node;
198extern NODE **fields_arr;
199
200static jmp_buf filebuf; /* for do_nextfile() */
201
202#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__EMX__) || defined(__CYGWIN__)
203/* binmode --- convert BINMODE to string for fopen */
204
205static const char *
206binmode(const char *mode)
207{
208 switch (mode[0]) {
209 case 'r':
210 if ((BINMODE & 1) != 0)
211 mode = "rb";
212 break;
213 case 'w':
214 case 'a':
215 if ((BINMODE & 2) != 0)
216 mode = (mode[0] == 'w' ? "wb" : "ab");
217 break;
218 }
219 return mode;
220}
221#else
222#define binmode(mode) (mode)
223#endif
224
225#ifdef VMS
226/* File pointers have an extra level of indirection, and there are cases where
227 `stdin' can be null. That can crash gawk if fileno() is used as-is. */
228static int vmsrtl_fileno P((FILE *));
229static int vmsrtl_fileno(fp) FILE *fp; { return fileno(fp); }
230#undef fileno
231#define fileno(FP) (((FP) && *(FP)) ? vmsrtl_fileno(FP) : -1)
232#endif /* VMS */
233
234/* do_nextfile --- implement gawk "nextfile" extension */
235
236void
237do_nextfile()
238{
239 (void) nextfile(TRUE);
240 longjmp(filebuf, 1);
241}
242
243/* nextfile --- move to the next input data file */
244
245static IOBUF *
246nextfile(int skipping)
247{
248 static long i = 1;
249 static int files = FALSE;
250 NODE *arg;
251 static IOBUF *curfile = NULL;
252 static IOBUF mybuf;
253 const char *fname;
254
255 if (skipping) {
256 if (curfile != NULL)
257 iop_close(curfile);
258 curfile = NULL;
259 return NULL;
260 }
261 if (curfile != NULL) {
262 if (at_eof(curfile)) {
263 (void) iop_close(curfile);
264 curfile = NULL;
265 } else
266 return curfile;
267 }
268 for (; i < (long) (ARGC_node->lnode->numbr); i++) {
269 arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i), FALSE);
270 if (arg->stlen == 0)
271 continue;
272 arg->stptr[arg->stlen] = '\0';
273 if (! do_traditional) {
274 unref(ARGIND_node->var_value);
275 ARGIND_node->var_value = make_number((AWKNUM) i);
276 }
277 if (! arg_assign(arg->stptr, FALSE)) {
278 files = TRUE;
279 fname = arg->stptr;
280 curfile = iop_open(fname, binmode("r"), &mybuf);
281 if (curfile == NULL)
282 goto give_up;
283 curfile->flag |= IOP_NOFREE_OBJ;
284 /* This is a kludge. */
285 unref(FILENAME_node->var_value);
286 FILENAME_node->var_value = dupnode(arg);
287 FNR = 0;
288 i++;
289 break;
290 }
291 }
292 if (files == FALSE) {
293 files = TRUE;
294 /* no args. -- use stdin */
295 /* FNR is init'ed to 0 */
296 unref(FILENAME_node->var_value);
297 FILENAME_node->var_value = make_string("-", 1);
298 fname = "-";
299 curfile = iop_open(fname, binmode("r"), &mybuf);
300 if (curfile == NULL)
301 goto give_up;
302 curfile->flag |= IOP_NOFREE_OBJ;
303 }
304 return curfile;
305
306 give_up:
307 fatal(_("cannot open file `%s' for reading (%s)"),
308 fname, strerror(errno));
309 /* NOTREACHED */
310 return (IOBUF *) 0;
311}
312
313/* set_FNR --- update internal FNR from awk variable */
314
315void
316set_FNR()
317{
318 FNR = (long) FNR_node->var_value->numbr;
319}
320
321/* set_NR --- update internal NR from awk variable */
322
323void
324set_NR()
325{
326 NR = (long) NR_node->var_value->numbr;
327}
328
329/* inrec --- This reads in a record from the input file */
330
331static int
332inrec(IOBUF *iop)
333{
334 char *begin;
335 register int cnt;
336 int retval = 0;
337
338 if (at_eof(iop) && no_data_left(iop))
339 cnt = EOF;
340 else if ((iop->flag & IOP_CLOSED) != 0)
341 cnt = EOF;
342 else
343 cnt = get_a_record(&begin, iop, NULL);
344
345 if (cnt == EOF) {
346 cnt = 0;
347 retval = 1;
348 } else {
349 NR += 1;
350 FNR += 1;
351 set_record(begin, cnt);
352 }
353
354 return retval;
355}
356
357/* iop_close --- close an open IOP */
358
359static int
360iop_close(IOBUF *iop)
361{
362 int ret;
363
364 if (iop == NULL)
365 return 0;
366 errno = 0;
367
368 iop->flag &= ~IOP_AT_EOF;
369 iop->flag |= IOP_CLOSED; /* there may be dangling pointers */
370 iop->dataend = NULL;
371#ifdef _CRAY
372 /* Work around bug in UNICOS popen */
373 if (iop->fd < 3)
374 ret = 0;
375 else
376#endif
377 /* save these for re-use; don't free the storage */
378 if ((iop->flag & IOP_IS_INTERNAL) != 0) {
379 iop->off = iop->buf;
380 iop->end = iop->buf + strlen(iop->buf);
381 iop->count = 0;
382 return 0;
383 }
384
385 /* Don't close standard files or else crufty code elsewhere will lose */
386 /* FIXME: *DO* close it. Just reopen on an invalid handle. */
387 if (iop->fd == fileno(stdin)
388 || iop->fd == fileno(stdout)
389 || iop->fd == fileno(stderr))
390 ret = 0;
391 else
392 ret = close(iop->fd);
393
394 if (iop->close_func != NULL)
395 (*iop->close_func)(iop);
396
397 if (ret == -1)
398 warning(_("close of fd %d (`%s') failed (%s)"), iop->fd,
399 iop->name, strerror(errno));
400 if ((iop->flag & IOP_NO_FREE) == 0) {
401 /*
402 * Be careful -- $0 may still reference the buffer even though
403 * an explicit close is being done; in the future, maybe we
404 * can do this a bit better.
405 */
406 if (iop->buf) {
407 if ((fields_arr[0]->stptr >= iop->buf)
408 && (fields_arr[0]->stptr < (iop->buf + iop->size))) {
409 NODE *t;
410
411 t = make_string(fields_arr[0]->stptr,
412 fields_arr[0]->stlen);
413 unref(fields_arr[0]);
414 fields_arr[0] = t;
415 /*
416 * 1/27/2003: This used to be here:
417 *
418 * reset_record();
419 *
420 * Don't do that; reset_record() throws away all fields,
421 * saves FS etc. We just need to make sure memory isn't
422 * corrupted and that references to $0 and fields work.
423 */
424 }
425 free(iop->buf);
426 iop->buf = NULL;
427 }
428 if ((iop->flag & IOP_NOFREE_OBJ) == 0)
429 free((char *) iop);
430 }
431 return ret == -1 ? 1 : 0;
432}
433
434/* do_input --- the main input processing loop */
435
436void
437do_input()
438{
439 IOBUF *iop;
440 extern int exiting;
441 int rval1, rval2, rval3;
442
443 (void) setjmp(filebuf); /* for `nextfile' */
444
445 while ((iop = nextfile(FALSE)) != NULL) {
446 /*
447 * This was:
448 if (inrec(iop) == 0)
449 while (interpret(expression_value) && inrec(iop) == 0)
450 continue;
451 * Now expand it out for ease of debugging.
452 */
453 rval1 = inrec(iop);
454 if (rval1 == 0) {
455 for (;;) {
456 rval2 = rval3 = -1; /* for debugging */
457 rval2 = interpret(expression_value);
458 if (rval2 != 0)
459 rval3 = inrec(iop);
460 if (rval2 == 0 || rval3 != 0)
461 break;
462 }
463 }
464 if (exiting)
465 break;
466 }
467}
468
469/* redflags2str --- turn redirection flags into a string, for debugging */
470
471const char *
472redflags2str(int flags)
473{
474 static const struct flagtab redtab[] = {
475 { RED_FILE, "RED_FILE" },
476 { RED_PIPE, "RED_PIPE" },
477 { RED_READ, "RED_READ" },
478 { RED_WRITE, "RED_WRITE" },
479 { RED_APPEND, "RED_APPEND" },
480 { RED_NOBUF, "RED_NOBUF" },
481 { RED_EOF, "RED_EOF" },
482 { RED_TWOWAY, "RED_TWOWAY" },
483 { RED_PTY, "RED_PTY" },
484 { RED_SOCKET, "RED_SOCKET" },
485 { RED_TCP, "RED_TCP" },
486 { 0, NULL }
487 };
488
489 return genflags2str(flags, redtab);
490}
491
492/* redirect --- Redirection for printf and print commands */
493
494struct redirect *
495redirect(NODE *tree, int *errflg)
496{
497 register NODE *tmp;
498 register struct redirect *rp;
499 register char *str;
500 int tflag = 0;
501 int outflag = 0;
502 const char *direction = "to";
503 const char *mode;
504 int fd;
505 const char *what = NULL;
506
507 switch (tree->type) {
508 case Node_redirect_append:
509 tflag = RED_APPEND;
510 /* FALL THROUGH */
511 case Node_redirect_output:
512 outflag = (RED_FILE|RED_WRITE);
513 tflag |= outflag;
514 if (tree->type == Node_redirect_output)
515 what = ">";
516 else
517 what = ">>";
518 break;
519 case Node_redirect_pipe:
520 tflag = (RED_PIPE|RED_WRITE);
521 what = "|";
522 break;
523 case Node_redirect_pipein:
524 tflag = (RED_PIPE|RED_READ);
525 what = "|";
526 break;
527 case Node_redirect_input:
528 tflag = (RED_FILE|RED_READ);
529 what = "<";
530 break;
531 case Node_redirect_twoway:
532 tflag = (RED_READ|RED_WRITE|RED_TWOWAY);
533 what = "|&";
534 break;
535 default:
536 fatal(_("invalid tree type %s in redirect()"),
537 nodetype2str(tree->type));
538 break;
539 }
540 tmp = tree_eval(tree->subnode);
541 if (do_lint && (tmp->flags & STRCUR) == 0)
542 lintwarn(_("expression in `%s' redirection only has numeric value"),
543 what);
544 tmp = force_string(tmp);
545 str = tmp->stptr;
546
547 if (str == NULL || *str == '\0')
548 fatal(_("expression for `%s' redirection has null string value"),
549 what);
550
551 if (do_lint
552 && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen)))
553 lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"), str, what);
554
555#ifdef HAVE_SOCKETS
556 if (STREQN(str, "/inet/", 6)) {
557 tflag |= RED_SOCKET;
558 if (STREQN(str + 6, "tcp/", 4))
559 tflag |= RED_TCP; /* use shutdown when closing */
560 }
561#endif /* HAVE_SOCKETS */
562
563 for (rp = red_head; rp != NULL; rp = rp->next) {
564#ifndef PIPES_SIMULATED
565 /*
566 * This is an efficiency hack. We want to
567 * recover the process slot for dead children,
568 * if at all possible. Messing with signal() for
569 * SIGCLD leads to lots of headaches. However, if
570 * we've gotten EOF from a child input pipeline, it's
571 * good bet that the child has died. So recover it.
572 */
573 if ((rp->flag & RED_EOF) && tree->type == Node_redirect_pipein) {
574 if (rp->pid != -1)
575 wait_any(0);
576 }
577#endif /* PIPES_SIMULATED */
578
579 /* now check for a match */
580 if (strlen(rp->value) == tmp->stlen
581 && memcmp(rp->value, str, tmp->stlen) == 0
582 && ((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag
583 || (outflag != 0
584 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) {
585
586 int rpflag = (rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY));
587 int newflag = (tflag & ~(RED_NOBUF|RED_EOF|RED_PTY));
588
589 if (do_lint && rpflag != newflag)
590 lintwarn(
591 _("unnecessary mixing of `>' and `>>' for file `%.*s'"),
592 (int) tmp->stlen, rp->value);
593
594 break;
595 }
596 }
597
598 if (rp == NULL) {
599 emalloc(rp, struct redirect *, sizeof(struct redirect),
600 "redirect");
601 emalloc(str, char *, tmp->stlen+1, "redirect");
602 memcpy(str, tmp->stptr, tmp->stlen);
603 str[tmp->stlen] = '\0';
604 rp->value = str;
605 rp->flag = tflag;
606 rp->fp = NULL;
607 rp->iop = NULL;
608 rp->pid = -1;
609 rp->status = 0;
610 /* maintain list in most-recently-used first order */
611 if (red_head != NULL)
612 red_head->prev = rp;
613 rp->prev = NULL;
614 rp->next = red_head;
615 red_head = rp;
616 } else
617 str = rp->value; /* get \0 terminated string */
618
619 while (rp->fp == NULL && rp->iop == NULL) {
620 if (rp->flag & RED_EOF)
621 /*
622 * encountered EOF on file or pipe -- must be cleared
623 * by explicit close() before reading more
624 */
625 return rp;
626 mode = NULL;
627 errno = 0;
628 switch (tree->type) {
629 case Node_redirect_output:
630 mode = binmode("w");
631 if ((rp->flag & RED_USED) != 0)
632 mode = (rp->mode[1] == 'b') ? "ab" : "a";
633 break;
634 case Node_redirect_append:
635 mode = binmode("a");
636 break;
637 case Node_redirect_pipe:
638 /* synchronize output before new pipe */
639 (void) flush_io();
640
641 os_restore_mode(fileno(stdin));
642 if ((rp->fp = popen(str, binmode("w"))) == NULL)
643 fatal(_("can't open pipe `%s' for output (%s)"),
644 str, strerror(errno));
645 /* set close-on-exec */
646 os_close_on_exec(fileno(rp->fp), str, "pipe", "to");
647 rp->flag |= RED_NOBUF;
648 break;
649 case Node_redirect_pipein:
650 direction = "from";
651 if (gawk_popen(str, rp) == NULL)
652 fatal(_("can't open pipe `%s' for input (%s)"),
653 str, strerror(errno));
654 break;
655 case Node_redirect_input:
656 direction = "from";
657 rp->iop = iop_open(str, binmode("r"), NULL);
658 break;
659 case Node_redirect_twoway:
660 direction = "to/from";
661 if (! two_way_open(str, rp)) {
662#ifdef HAVE_SOCKETS
663 /* multiple messages make life easier for translators */
664 if (STREQN(str, "/inet/", 6))
665 fatal(_("can't open two way socket `%s' for input/output (%s)"),
666 str, strerror(errno));
667 else
668#endif
669 fatal(_("can't open two way pipe `%s' for input/output (%s)"),
670 str, strerror(errno));
671 }
672 break;
673 default:
674 cant_happen();
675 }
676 if (mode != NULL) {
677 errno = 0;
678 fd = devopen(str, mode);
679 if (fd > INVALID_HANDLE) {
680 if (fd == fileno(stdin))
681 rp->fp = stdin;
682 else if (fd == fileno(stdout))
683 rp->fp = stdout;
684 else if (fd == fileno(stderr))
685 rp->fp = stderr;
686 else {
687#if defined(F_GETFL) && defined(O_APPEND)
688 int fd_flags;
689
690 fd_flags = fcntl(fd, F_GETFL);
691 if (fd_flags != -1 && (fd_flags & O_APPEND) == O_APPEND)
692 rp->fp = fdopen(fd, binmode("a"));
693 else
694#endif
695 rp->fp = fdopen(fd, (const char *) mode);
696 rp->mode = (const char *) mode;
697 /* don't leak file descriptors */
698 if (rp->fp == NULL)
699 close(fd);
700 }
701 if (rp->fp != NULL && isatty(fd))
702 rp->flag |= RED_NOBUF;
703 /* Move rp to the head of the list. */
704 if (red_head != rp) {
705 if ((rp->prev->next = rp->next) != NULL)
706 rp->next->prev = rp->prev;
707 red_head->prev = rp;
708 rp->prev = NULL;
709 rp->next = red_head;
710 red_head = rp;
711 }
712 }
713 }
714 if (rp->fp == NULL && rp->iop == NULL) {
715 /* too many files open -- close one and try again */
716 if (errno == EMFILE || errno == ENFILE)
717 close_one();
718#if defined __MINGW32__ || defined __sun
719 else if (errno == 0) /* HACK! */
720 close_one();
721#endif
722#ifdef VMS
723 /* Alpha/VMS V7.1's C RTL is returning this instead
724 of EMFILE (haven't tried other post-V6.2 systems) */
725#define SS$_EXQUOTA 0x001C
726 else if (errno == EIO && vaxc$errno == SS$_EXQUOTA)
727 close_one();
728#endif
729 else {
730 /*
731 * Some other reason for failure.
732 *
733 * On redirection of input from a file,
734 * just return an error, so e.g. getline
735 * can return -1. For output to file,
736 * complain. The shell will complain on
737 * a bad command to a pipe.
738 */
739 if (errflg != NULL)
740 *errflg = errno;
741 if (tree->type == Node_redirect_output
742 || tree->type == Node_redirect_append) {
743 /* multiple messages make life easier for translators */
744 if (*direction == 'f')
745 fatal(_("can't redirect from `%s' (%s)"),
746 str, strerror(errno));
747 else
748 fatal(_("can't redirect to `%s' (%s)"),
749 str, strerror(errno));
750 } else {
751 free_temp(tmp);
752 return NULL;
753 }
754 }
755 }
756 }
757 free_temp(tmp);
758 return rp;
759}
760
761/* getredirect --- find the struct redirect for this file or pipe */
762
763struct redirect *
764getredirect(const char *str, int len)
765{
766 struct redirect *rp;
767
768 for (rp = red_head; rp != NULL; rp = rp->next)
769 if (strlen(rp->value) == len && memcmp(rp->value, str, len) == 0)
770 return rp;
771
772 return NULL;
773}
774
775/* close_one --- temporarily close an open file to re-use the fd */
776
777static void
778close_one()
779{
780 register struct redirect *rp;
781 register struct redirect *rplast = NULL;
782
783 static short warned = FALSE;
784
785 if (do_lint && ! warned) {
786 warned = TRUE;
787 lintwarn(_("reached system limit for open files: starting to multiplex file descriptors"));
788 }
789
790 /* go to end of list first, to pick up least recently used entry */
791 for (rp = red_head; rp != NULL; rp = rp->next)
792 rplast = rp;
793 /* now work back up through the list */
794 for (rp = rplast; rp != NULL; rp = rp->prev) {
795 /* don't close standard files! */
796 if (rp->fp == NULL || rp->fp == stderr || rp->fp == stdout)
797 continue;
798
799 if ((rp->flag & (RED_FILE|RED_WRITE)) == (RED_FILE|RED_WRITE)) {
800 rp->flag |= RED_USED;
801 errno = 0;
802 if (/* do_lint && */ fclose(rp->fp) != 0)
803 warning(_("close of `%s' failed (%s)."),
804 rp->value, strerror(errno));
805 rp->fp = NULL;
806 break;
807 }
808 }
809 if (rp == NULL)
810 /* surely this is the only reason ??? */
811 fatal(_("too many pipes or input files open"));
812}
813
814/* do_close --- completely close an open file or pipe */
815
816NODE *
817do_close(NODE *tree)
818{
819 NODE *tmp, *tmp2;
820 register struct redirect *rp;
821 two_way_close_type how = CLOSE_ALL; /* default */
822
823 tmp = force_string(tree_eval(tree->lnode)); /* 1st arg: redir to close */
824
825 if (tree->rnode != NULL) {
826 /* 2nd arg if present: "to" or "from" for two-way pipe */
827 /* DO NOT use _() on the strings here! */
828 tmp2 = force_string(tree->rnode->lnode);
829 if (strcasecmp(tmp2->stptr, "to") == 0)
830 how = CLOSE_TO;
831 else if (strcasecmp(tmp2->stptr, "from") == 0)
832 how = CLOSE_FROM;
833 else
834 fatal(_("close: second argument must be `to' or `from'"));
835 free_temp(tmp2);
836 }
837
838 for (rp = red_head; rp != NULL; rp = rp->next) {
839 if (strlen(rp->value) == tmp->stlen
840 && memcmp(rp->value, tmp->stptr, tmp->stlen) == 0)
841 break;
842 }
843
844 if (rp == NULL) { /* no match, return -1 */
845 char *cp;
846
847 if (do_lint)
848 lintwarn(_("close: `%.*s' is not an open file, pipe or co-process"),
849 (int) tmp->stlen, tmp->stptr);
850
851 /* update ERRNO manually, using errno = ENOENT is a stretch. */
852 cp = _("close of redirection that was never opened");
853 unref(ERRNO_node->var_value);
854 ERRNO_node->var_value = make_string(cp, strlen(cp));
855
856 free_temp(tmp);
857 return tmp_number((AWKNUM) -1.0);
858 }
859 free_temp(tmp);
860 fflush(stdout); /* synchronize regular output */
861 tmp = tmp_number((AWKNUM) close_redir(rp, FALSE, how));
862 rp = NULL;
863 /*
864 * POSIX says close() returns 0 on success, non-zero otherwise.
865 * For POSIX, at this point we just return 0. Otherwise we
866 * return the exit status of the process or of pclose(), depending.
867 * This whole business is a mess.
868 */
869 if (do_posix) {
870 free_temp(tmp);
871 return tmp_number((AWKNUM) 0);
872 }
873 return tmp;
874}
875
876/* close_rp --- separate function to just do closing */
877
878static int
879close_rp(struct redirect *rp, two_way_close_type how)
880{
881 int status = 0;
882
883 errno = 0;
884 if ((rp->flag & RED_TWOWAY) != 0) { /* two-way pipe */
885 /* write end: */
886 if ((how == CLOSE_ALL || how == CLOSE_TO) && rp->fp != NULL) {
887#ifdef HAVE_SOCKETS
888 if ((rp->flag & RED_TCP) != 0)
889 (void) shutdown(fileno(rp->fp), SHUT_WR);
890#endif /* HAVE_SOCKETS */
891
892 if ((rp->flag & RED_PTY) != 0) {
893 fwrite("\004\n", sizeof("\004\n") - 1, 1, rp->fp);
894 fflush(rp->fp);
895 }
896 status = fclose(rp->fp);
897 rp->fp = NULL;
898 }
899
900 /* read end: */
901 if (how == CLOSE_ALL || how == CLOSE_FROM) {
902 if ((rp->flag & RED_SOCKET) != 0 && rp->iop != NULL) {
903#ifdef HAVE_SOCKETS
904 if ((rp->flag & RED_TCP) != 0)
905 (void) shutdown(rp->iop->fd, SHUT_RD);
906#endif /* HAVE_SOCKETS */
907 (void) iop_close(rp->iop);
908 } else
909 status = gawk_pclose(rp);
910
911 rp->iop = NULL;
912 }
913 } else if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) { /* write to pipe */
914 status = pclose(rp->fp);
915 if ((BINMODE & 1) != 0)
916 os_setbinmode(fileno(stdin), O_BINARY);
917
918 rp->fp = NULL;
919 } else if (rp->fp != NULL) { /* write to file */
920 status = fclose(rp->fp);
921 rp->fp = NULL;
922 } else if (rp->iop != NULL) { /* read from pipe/file */
923 if ((rp->flag & RED_PIPE) != 0) /* read from pipe */
924 status = gawk_pclose(rp);
925 /* gawk_pclose sets rp->iop to null */
926 else { /* read from file */
927 status = iop_close(rp->iop);
928 rp->iop = NULL;
929 }
930 }
931
932 return status;
933}
934
935/* close_redir --- close an open file or pipe */
936
937static int
938close_redir(register struct redirect *rp, int exitwarn, two_way_close_type how)
939{
940 int status = 0;
941
942 if (rp == NULL)
943 return 0;
944 if (rp->fp == stdout || rp->fp == stderr)
945 goto checkwarn; /* bypass closing, remove from list */
946
947 if (do_lint && (rp->flag & RED_TWOWAY) == 0 && how != CLOSE_ALL)
948 lintwarn(_("close: redirection `%s' not opened with `|&', second argument ignored"),
949 rp->value);
950
951 status = close_rp(rp, how);
952
953 /* SVR4 awk checks and warns about status of close */
954 if (status != 0) {
955 int save_errno = errno;
956 char *s = strerror(save_errno);
957
958 /*
959 * Too many people have complained about this.
960 * As of 2.15.6, it is now under lint control.
961 */
962 if (do_lint) {
963 if ((rp->flag & RED_PIPE) != 0)
964 lintwarn(_("failure status (%d) on pipe close of `%s' (%s)"),
965 status, rp->value, s);
966 else
967 lintwarn(_("failure status (%d) on file close of `%s' (%s)"),
968 status, rp->value, s);
969 }
970
971 if (! do_traditional) {
972 /* set ERRNO too so that program can get at it */
973 update_ERRNO_saved(save_errno);
974 }
975 }
976
977checkwarn:
978 if (exitwarn) {
979 /*
980 * Don't use lintwarn() here. If lint warnings are fatal,
981 * doing so prevents us from closing other open redirections.
982 *
983 * Using multiple full messages instead of string parameters
984 * for the types makes message translation easier.
985 */
986 if ((rp->flag & RED_SOCKET) != 0)
987 warning(_("no explicit close of socket `%s' provided"),
988 rp->value);
989 else if ((rp->flag & RED_TWOWAY) != 0)
990 warning(_("no explicit close of co-process `%s' provided"),
991 rp->value);
992 else if ((rp->flag & RED_PIPE) != 0)
993 warning(_("no explicit close of pipe `%s' provided"),
994 rp->value);
995 else
996 warning(_("no explicit close of file `%s' provided"),
997 rp->value);
998 }
999
1000 /* remove it from the list if closing both or both ends have been closed */
1001 if (how == CLOSE_ALL || (rp->iop == NULL && rp->fp == NULL)) {
1002 if (rp->next != NULL)
1003 rp->next->prev = rp->prev;
1004 if (rp->prev != NULL)
1005 rp->prev->next = rp->next;
1006 else
1007 red_head = rp->next;
1008 free(rp->value);
1009 free((char *) rp);
1010 }
1011
1012 return status;
1013}
1014
1015/* flush_io --- flush all open output files */
1016
1017int
1018flush_io()
1019{
1020 register struct redirect *rp;
1021 int status = 0;
1022
1023 errno = 0;
1024 if (fflush(stdout)) {
1025 warning(_("error writing standard output (%s)"), strerror(errno));
1026 status++;
1027 }
1028 if (fflush(stderr)) {
1029 warning(_("error writing standard error (%s)"), strerror(errno));
1030 status++;
1031 }
1032 for (rp = red_head; rp != NULL; rp = rp->next)
1033 /* flush both files and pipes, what the heck */
1034 if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
1035 if (fflush(rp->fp)) {
1036 if (rp->flag & RED_PIPE)
1037 warning(_("pipe flush of `%s' failed (%s)."),
1038 rp->value, strerror(errno));
1039 else if (rp->flag & RED_TWOWAY)
1040 warning(_("co-process flush of pipe to `%s' failed (%s)."),
1041 rp->value, strerror(errno));
1042 else
1043 warning(_("file flush of `%s' failed (%s)."),
1044 rp->value, strerror(errno));
1045 status++;
1046 }
1047 }
1048 if (status != 0)
1049 status = -1; /* canonicalize it */
1050 return status;
1051}
1052
1053/* close_io --- close all open files, called when exiting */
1054
1055int
1056close_io(int *stdio_problem)
1057{
1058 register struct redirect *rp;
1059 register struct redirect *next;
1060 int status = 0;
1061
1062 errno = 0;
1063 for (rp = red_head; rp != NULL; rp = next) {
1064 next = rp->next;
1065 /*
1066 * close_redir() will print a message if needed
1067 * if do_lint, warn about lack of explicit close
1068 */
1069 if (close_redir(rp, do_lint, CLOSE_ALL))
1070 status++;
1071 rp = NULL;
1072 }
1073 /*
1074 * Some of the non-Unix os's have problems doing an fclose
1075 * on stdout and stderr. Since we don't really need to close
1076 * them, we just flush them, and do that across the board.
1077 */
1078 *stdio_problem = FALSE;
1079 if (fflush(stdout)) {
1080 warning(_("error writing standard output (%s)"), strerror(errno));
1081 status++;
1082 *stdio_problem = TRUE;
1083 }
1084 if (fflush(stderr)) {
1085 warning(_("error writing standard error (%s)"), strerror(errno));
1086 status++;
1087 *stdio_problem = TRUE;
1088 }
1089 return status;
1090}
1091
1092/* str2mode --- convert a string mode to an integer mode */
1093
1094static int
1095str2mode(const char *mode)
1096{
1097 int ret;
1098 const char *second = & mode[1];
1099
1100 if (*second == 'b')
1101 second++;
1102
1103 switch(mode[0]) {
1104 case 'r':
1105 ret = O_RDONLY;
1106 if (*second == '+' || *second == 'w')
1107 ret = O_RDWR;
1108 break;
1109
1110 case 'w':
1111 ret = O_WRONLY|O_CREAT|O_TRUNC;
1112 if (*second == '+' || *second == 'r')
1113 ret = O_RDWR|O_CREAT|O_TRUNC;
1114 break;
1115
1116 case 'a':
1117 ret = O_WRONLY|O_APPEND|O_CREAT;
1118 if (*second == '+')
1119 ret = O_RDWR|O_APPEND|O_CREAT;
1120 break;
1121
1122 default:
1123 ret = 0; /* lint */
1124 cant_happen();
1125 }
1126 if (strchr(mode, 'b') != NULL)
1127 ret |= O_BINARY;
1128 return ret;
1129}
1130
1131#ifdef HAVE_SOCKETS
1132/* socketopen --- open a socket and set it into connected state */
1133
1134static int
1135socketopen(enum inet_prot type, int localport, int remoteport, const char *remotehostname)
1136{
1137 struct hostent *hp = gethostbyname(remotehostname);
1138 struct sockaddr_in local_addr, remote_addr;
1139 int socket_fd;
1140 int any_remote_host = strcmp(remotehostname, "0");
1141
1142 socket_fd = INVALID_HANDLE;
1143 switch (type) {
1144 case INET_TCP:
1145 if (localport != 0 || remoteport != 0) {
1146 int on = 1;
1147#ifdef SO_LINGER
1148 struct linger linger;
1149
1150 memset(& linger, '\0', sizeof(linger));
1151#endif
1152 socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1153 setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,
1154 (char *) & on, sizeof(on));
1155#ifdef SO_LINGER
1156 linger.l_onoff = 1;
1157 linger.l_linger = 30; /* linger for 30/100 second */
1158 setsockopt(socket_fd, SOL_SOCKET, SO_LINGER,
1159 (char *) & linger, sizeof(linger));
1160#endif
1161 }
1162 break;
1163 case INET_UDP:
1164 if (localport != 0 || remoteport != 0)
1165 socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1166 break;
1167 case INET_RAW:
1168#ifdef SOCK_RAW
1169 if (localport == 0 && remoteport == 0)
1170 socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1171#endif
1172 break;
1173 case INET_NONE:
1174 /* fall through */
1175 default:
1176 cant_happen();
1177 break;
1178 }
1179
1180 if (socket_fd < 0 || socket_fd == INVALID_HANDLE
1181 || (hp == NULL && any_remote_host != 0))
1182 return INVALID_HANDLE;
1183
1184 local_addr.sin_family = remote_addr.sin_family = AF_INET;
1185 local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1186 remote_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1187 local_addr.sin_port = htons(localport);
1188 remote_addr.sin_port = htons(remoteport);
1189 if (bind(socket_fd, (struct sockaddr *) &local_addr, sizeof(local_addr)) == 0) {
1190 if (any_remote_host != 0) { /* not ANY => create a client */
1191 if (type == INET_TCP || type == INET_UDP) {
1192 memcpy(&remote_addr.sin_addr, hp->h_addr,
1193 sizeof(remote_addr.sin_addr));
1194 if (connect(socket_fd,
1195 (struct sockaddr *) &remote_addr,
1196 sizeof(remote_addr)) != 0) {
1197 close(socket_fd);
1198 if (localport == 0)
1199 socket_fd = INVALID_HANDLE;
1200 else
1201 socket_fd = socketopen(type, localport, 0, "0");
1202 }
1203 } else {
1204 /* /inet/raw client not ready yet */
1205 fatal(_("/inet/raw client not ready yet, sorry"));
1206 if (geteuid() != 0)
1207 fatal(_("only root may use `/inet/raw'."));
1208 }
1209 } else { /* remote host is ANY => create a server */
1210 if (type == INET_TCP) {
1211 int clientsocket_fd = INVALID_HANDLE;
1212 socklen_t namelen = sizeof(remote_addr);
1213
1214 if (listen(socket_fd, 1) >= 0
1215 && (clientsocket_fd = accept(socket_fd,
1216 (struct sockaddr *) &remote_addr,
1217 &namelen)) >= 0) {
1218 close(socket_fd);
1219 socket_fd = clientsocket_fd;
1220 } else {
1221 close(socket_fd);
1222 socket_fd = INVALID_HANDLE;
1223 }
1224 } else if (type == INET_UDP) {
1225#ifdef MSG_PEEK
1226 char buf[10];
1227 socklen_t readle;
1228
1229 if (recvfrom(socket_fd, buf, 1, MSG_PEEK,
1230 (struct sockaddr *) & remote_addr,
1231 & readle) < 1
1232 || readle != sizeof(remote_addr)
1233 || connect(socket_fd,
1234 (struct sockaddr *)& remote_addr,
1235 readle) != 0) {
1236 close(socket_fd);
1237 socket_fd = INVALID_HANDLE;
1238 }
1239#endif
1240 } else {
1241 /* /inet/raw server not ready yet */
1242 fatal(_("/inet/raw server not ready yet, sorry"));
1243 if (geteuid() != 0)
1244 fatal(_("only root may use `/inet/raw'."));
1245 }
1246 }
1247 } else {
1248 close(socket_fd);
1249 socket_fd = INVALID_HANDLE;
1250 }
1251
1252 return socket_fd;
1253}
1254#endif /* HAVE_SOCKETS */
1255
1256/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
1257
1258/*
1259 * This separate version is still needed for output, since file and pipe
1260 * output is done with stdio. iop_open() handles input with IOBUFs of
1261 * more "special" files. Those files are not handled here since it makes
1262 * no sense to use them for output.
1263 */
1264
1265/*
1266 * Strictly speaking, "name" is not a "const char *" because we temporarily
1267 * change the string.
1268 */
1269
1270int
1271devopen(const char *name, const char *mode)
1272{
1273 int openfd;
1274 char *cp;
1275 char *ptr;
1276 int flag = 0;
1277 extern unsigned long strtoul P((const char *, char **endptr, int base));
1278
1279 flag = str2mode(mode);
1280
1281 if (STREQ(name, "-"))
1282 return fileno(stdin);
1283
1284 openfd = INVALID_HANDLE;
1285
1286 if (do_traditional)
1287 goto strictopen;
1288
1289 if ((openfd = os_devopen(name, flag)) != INVALID_HANDLE) {
1290 os_close_on_exec(openfd, name, "file", "");
1291 return openfd;
1292 }
1293
1294 if (STREQN(name, "/dev/", 5)) {
1295 cp = (char *) name + 5;
1296
1297 if (STREQ(cp, "stdin") && (flag & O_ACCMODE) == O_RDONLY)
1298 openfd = fileno(stdin);
1299 else if (STREQ(cp, "stdout") && (flag & O_ACCMODE) == O_WRONLY)
1300 openfd = fileno(stdout);
1301 else if (STREQ(cp, "stderr") && (flag & O_ACCMODE) == O_WRONLY)
1302 openfd = fileno(stderr);
1303 else if (STREQN(cp, "fd/", 3)) {
1304 cp += 3;
1305 openfd = (int) strtoul(cp, &ptr, 10);
1306 if (openfd <= INVALID_HANDLE || ptr == cp)
1307 openfd = INVALID_HANDLE;
1308 }
1309 /* do not set close-on-exec for inherited fd's */
1310 if (openfd != INVALID_HANDLE)
1311 return openfd;
1312 } else if (STREQN(name, "/inet/", 6)) {
1313#ifdef HAVE_SOCKETS
1314 /* /inet/protocol/localport/hostname/remoteport */
1315 enum inet_prot protocol = INET_NONE;
1316 int localport, remoteport;
1317 char *hostname;
1318 char *hostnameslastcharp;
1319 char *localpname;
1320 char proto[4];
1321 struct servent *service;
1322
1323 cp = (char *) name + 6;
1324 /* which protocol? */
1325 if (STREQN(cp, "tcp/", 4))
1326 protocol = INET_TCP;
1327 else if (STREQN(cp, "udp/", 4))
1328 protocol = INET_UDP;
1329 else if (STREQN(cp, "raw/", 4))
1330 protocol = INET_RAW;
1331 else
1332 fatal(_("no (known) protocol supplied in special filename `%s'"),
1333 name);
1334
1335 proto[0] = cp[0];
1336 proto[1] = cp[1];
1337 proto[2] = cp[2];
1338 proto[3] = '\0';
1339 cp += 4;
1340
1341 /* which localport? */
1342 localpname = cp;
1343 while (*cp != '/' && *cp != '\0')
1344 cp++;
1345 /*
1346 * Require a port, let them explicitly put 0 if
1347 * they don't care.
1348 */
1349 if (*cp != '/' || cp == localpname)
1350 fatal(_("special file name `%s' is incomplete"), name);
1351 /* We change the special file name temporarily because we
1352 * need a 0-terminated string here for conversion with atoi().
1353 * By using atoi() the use of decimal numbers is enforced.
1354 */
1355 *cp = '\0';
1356
1357 localport = atoi(localpname);
1358 if (strcmp(localpname, "0") != 0
1359 && (localport <= 0 || localport > 65535)) {
1360 service = getservbyname(localpname, proto);
1361 if (service == NULL)
1362 fatal(_("local port invalid in `%s'"), name);
1363 else
1364 localport = ntohs(service->s_port);
1365 }
1366 *cp = '/';
1367
1368 /* which hostname? */
1369 cp++;
1370 hostname = cp;
1371 while (*cp != '/' && *cp != '\0')
1372 cp++;
1373 if (*cp != '/' || cp == hostname)
1374 fatal(_("must supply a remote hostname to `/inet'"));
1375 *cp = '\0';
1376 hostnameslastcharp = cp;
1377
1378 /* which remoteport? */
1379 cp++;
1380 /*
1381 * The remote port ends the special file name.
1382 * This means there already is a 0 at the end of the string.
1383 * Therefore no need to patch any string ending.
1384 *
1385 * Here too, require a port, let them explicitly put 0 if
1386 * they don't care.
1387 */
1388 if (*cp == '\0')
1389 fatal(_("must supply a remote port to `/inet'"));
1390 remoteport = atoi(cp);
1391 if (strcmp(cp, "0") != 0
1392 && (remoteport <= 0 || remoteport > 65535)) {
1393 service = getservbyname(cp, proto);
1394 if (service == NULL)
1395 fatal(_("remote port invalid in `%s'"), name);
1396 else
1397 remoteport = ntohs(service->s_port);
1398 }
1399
1400 /* Open Sesame! */
1401 openfd = socketopen(protocol, localport, remoteport, hostname);
1402 *hostnameslastcharp = '/';
1403
1404#else /* ! HAVE_SOCKETS */
1405 fatal(_("TCP/IP communications are not supported"));
1406#endif /* HAVE_SOCKETS */
1407 }
1408
1409strictopen:
1410 if (openfd == INVALID_HANDLE)
1411 openfd = open(name, flag, 0666);
1412 if (openfd != INVALID_HANDLE) {
1413 if (os_isdir(openfd))
1414 fatal(_("file `%s' is a directory"), name);
1415
1416 os_close_on_exec(openfd, name, "file", "");
1417 }
1418 return openfd;
1419}
1420
1421
1422/* spec_setup --- setup an IOBUF for a special internal file */
1423
1424static void
1425spec_setup(IOBUF *iop, int len, int allocate)
1426{
1427 char *cp;
1428
1429 if (allocate) {
1430 emalloc(cp, char *, len+2, "spec_setup");
1431 iop->buf = cp;
1432 } else {
1433 len = strlen(iop->buf);
1434 iop->buf[len++] = '\n'; /* get_a_record clobbered it */
1435 iop->buf[len] = '\0'; /* just in case */
1436 }
1437 iop->off = iop->buf;
1438 iop->count = 0;
1439 iop->size = len;
1440 iop->end = iop->buf + len;
1441 iop->dataend = iop->end;
1442 iop->fd = -1;
1443 iop->flag = IOP_IS_INTERNAL | IOP_AT_START;
1444}
1445
1446/* specfdopen --- open an fd special file */
1447
1448static int
1449specfdopen(IOBUF *iop, const char *name, const char *mode)
1450{
1451 int fd;
1452 IOBUF *tp;
1453
1454 fd = devopen(name, mode);
1455 if (fd == INVALID_HANDLE)
1456 return INVALID_HANDLE;
1457 tp = iop_alloc(fd, name, NULL);
1458 if (tp == NULL) {
1459 /* don't leak fd's */
1460 close(fd);
1461 return INVALID_HANDLE;
1462 }
1463 *iop = *tp;
1464 iop->flag |= IOP_NO_FREE;
1465 free(tp);
1466 return 0;
1467}
1468
1469#ifdef GETPGRP_VOID
1470#define getpgrp_arg() /* nothing */
1471#else
1472#define getpgrp_arg() getpid()
1473#endif
1474
1475/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
1476
1477static int
1478pidopen(IOBUF *iop, const char *name, const char *mode ATTRIBUTE_UNUSED)
1479{
1480 char tbuf[BUFSIZ];
1481 int i;
1482 const char *cp = name + 5;
1483
1484 warning(_("use `PROCINFO[\"%s\"]' instead of `%s'"), cp, name);
1485
1486 if (name[6] == 'g')
1487 sprintf(tbuf, "%d\n", (int) getpgrp(getpgrp_arg()));
1488 else if (name[6] == 'i')
1489 sprintf(tbuf, "%d\n", (int) getpid());
1490 else
1491 sprintf(tbuf, "%d\n", (int) getppid());
1492 i = strlen(tbuf);
1493 spec_setup(iop, i, TRUE);
1494 strcpy(iop->buf, tbuf);
1495 return 0;
1496}
1497
1498/* useropen --- "open" /dev/user */
1499
1500/*
1501 * /dev/user creates a record as follows:
1502 * $1 = getuid()
1503 * $2 = geteuid()
1504 * $3 = getgid()
1505 * $4 = getegid()
1506 * If multiple groups are supported, then $5 through $NF are the
1507 * supplementary group set.
1508 */
1509
1510static int
1511useropen(IOBUF *iop, const char *name ATTRIBUTE_UNUSED, const char *mode ATTRIBUTE_UNUSED)
1512{
1513 char tbuf[BUFSIZ], *cp;
1514 int i;
1515
1516 warning(_("use `PROCINFO[...]' instead of `/dev/user'"));
1517
1518 sprintf(tbuf, "%d %d %d %d", (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid());
1519
1520 cp = tbuf + strlen(tbuf);
1521#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
1522 for (i = 0; i < ngroups; i++) {
1523 *cp++ = ' ';
1524 sprintf(cp, "%d", (int) groupset[i]);
1525 cp += strlen(cp);
1526 }
1527#endif
1528 *cp++ = '\n';
1529 *cp++ = '\0';
1530
1531 i = strlen(tbuf);
1532 spec_setup(iop, i, TRUE);
1533 strcpy(iop->buf, tbuf);
1534 return 0;
1535}
1536
1537/* iop_open --- handle special and regular files for input */
1538
1539static IOBUF *
1540iop_open(const char *name, const char *mode, IOBUF *iop)
1541{
1542 int openfd = INVALID_HANDLE;
1543 int flag = 0;
1544 static struct internal {
1545 const char *name;
1546 int compare;
1547 int (*fp) P((IOBUF *, const char *, const char *));
1548 IOBUF iob;
1549 } table[] = {
1550 { "/dev/fd/", 8, specfdopen },
1551 { "/dev/stdin", 10, specfdopen },
1552 { "/dev/stdout", 11, specfdopen },
1553 { "/dev/stderr", 11, specfdopen },
1554 { "/inet/", 6, specfdopen },
1555 { "/dev/pid", 8, pidopen },
1556 { "/dev/ppid", 9, pidopen },
1557 { "/dev/pgrpid", 11, pidopen },
1558 { "/dev/user", 9, useropen },
1559 };
1560 int devcount = sizeof(table) / sizeof(table[0]);
1561
1562 flag = str2mode(mode);
1563
1564 if (STREQ(name, "-"))
1565 openfd = fileno(stdin);
1566 else if (do_traditional)
1567 goto strictopen;
1568 else if (STREQN(name, "/dev/", 5) || STREQN(name, "/inet/", 6)) {
1569 int i;
1570
1571 for (i = 0; i < devcount; i++) {
1572 if (STREQN(name, table[i].name, table[i].compare)) {
1573 iop = & table[i].iob;
1574
1575 if (iop->buf != NULL) {
1576 spec_setup(iop, 0, FALSE);
1577 return iop;
1578 } else if ((*table[i].fp)(iop, name, mode) == 0)
1579 return iop;
1580 else {
1581 warning(_("could not open `%s', mode `%s'"),
1582 name, mode);
1583 return NULL;
1584 }
1585 }
1586 }
1587 /* not in table, fall through to regular code */
1588 }
1589
1590strictopen:
1591 if (openfd == INVALID_HANDLE)
1592 openfd = open(name, flag, 0666);
1593 if (openfd != INVALID_HANDLE) {
1594 if (os_isdir(openfd))
1595 fatal(_("file `%s' is a directory"), name);
1596 }
1597 /*
1598 * At this point, fd could still be INVALID_HANDLE.
1599 * We pass it to `iop_alloc' anyway, in case an open hook
1600 * can manage to open the file.
1601 */
1602 iop = iop_alloc(openfd, name, iop);
1603 if (iop != NULL) {
1604 if (iop->fd > fileno(stderr))
1605 os_close_on_exec(iop->fd, name, "file", "");
1606 } else if (openfd != INVALID_HANDLE) /* have an fd, but IOP is null */
1607 (void) close(openfd); /* avoid fd leak */
1608 return iop;
1609}
1610
1611/* two_way_open --- open a two way communications channel */
1612
1613static int
1614two_way_open(const char *str, struct redirect *rp)
1615{
1616 static int no_ptys = FALSE;
1617
1618#ifdef HAVE_SOCKETS
1619 /* case 1: socket */
1620 if (STREQN(str, "/inet/", 6)) {
1621 int fd, newfd;
1622
1623 fd = devopen(str, "rw");
1624 if (fd == INVALID_HANDLE)
1625 return FALSE;
1626 rp->fp = fdopen(fd, "w");
1627 if (rp->fp == NULL) {
1628 close(fd);
1629 return FALSE;
1630 }
1631 newfd = dup(fd);
1632 if (newfd < 0) {
1633 fclose(rp->fp);
1634 return FALSE;
1635 }
1636 os_close_on_exec(newfd, str, "socket", "to/from");
1637 rp->iop = iop_alloc(newfd, str, NULL);
1638 if (rp->iop == NULL) {
1639 fclose(rp->fp);
1640 return FALSE;
1641 }
1642 rp->flag |= RED_SOCKET;
1643 return TRUE;
1644 }
1645#endif /* HAVE_SOCKETS */
1646
1647#ifdef HAVE_PORTALS
1648 /* case 1.5: portal */
1649 if (STREQN(str, "/p/", 3)) {
1650 int fd, newfd;
1651
1652 fd = open(str, O_RDWR);
1653 if (fd == INVALID_HANDLE)
1654 return FALSE;
1655 rp->fp = fdopen(fd, "w");
1656 if (rp->fp == NULL) {
1657 close(fd);
1658 return FALSE;
1659 }
1660 newfd = dup(fd);
1661 if (newfd < 0) {
1662 fclose(rp->fp);
1663 return FALSE;
1664 }
1665 os_close_on_exec(newfd, str, "portal", "to/from");
1666 rp->iop = iop_alloc(newfd, str, NULL);
1667 if (rp->iop == NULL) {
1668 fclose(rp->fp);
1669 return FALSE;
1670 }
1671 rp->flag |= RED_SOCKET;
1672 return TRUE;
1673 }
1674#endif /* HAVE_PORTALS */
1675
1676#ifdef HAVE_TERMIOS_H
1677 /* case 2: use ptys for two-way communications to child */
1678 if (! no_ptys && pty_vs_pipe(str)) {
1679 static int initialized = FALSE;
1680 static char first_pty_letter;
1681#ifdef HAVE_GRANTPT
1682 static int have_dev_ptmx;
1683#endif
1684 char slavenam[32];
1685 char c;
1686 int master, dup_master;
1687 int slave;
1688 int save_errno;
1689 pid_t pid;
1690 struct stat statb;
1691 struct termios st;
1692
1693 if (! initialized) {
1694 initialized = TRUE;
1695#ifdef HAVE_GRANTPT
1696 have_dev_ptmx = (stat("/dev/ptmx", &statb) >= 0);
1697#endif
1698 c = 'p';
1699 do {
1700 sprintf(slavenam, "/dev/pty%c0", c);
1701 if (stat(slavenam, &statb) >= 0) {
1702 first_pty_letter = c;
1703 break;
1704 }
1705 if (++c > 'z')
1706 c = 'a';
1707 } while (c != 'p');
1708 }
1709
1710#ifdef HAVE_GRANTPT
1711 if (have_dev_ptmx) {
1712 master = open("/dev/ptmx", O_RDWR);
1713 if (master >= 0) {
1714 char *tem;
1715
1716 grantpt(master);
1717 unlockpt(master);
1718 tem = ptsname(master);
1719 if (tem != NULL) {
1720 strcpy(slavenam, tem);
1721 goto got_the_pty;
1722 }
1723 (void) close(master);
1724 }
1725 }
1726#endif
1727
1728 if (first_pty_letter) {
1729 /*
1730 * Assume /dev/ptyXNN and /dev/ttyXN naming system.
1731 * The FIRST_PTY_LETTER gives the first X to try. We try in the
1732 * sequence FIRST_PTY_LETTER, .., 'z', 'a', .., FIRST_PTY_LETTER.
1733 * Is this worthwhile, or just over-zealous?
1734 */
1735 c = first_pty_letter;
1736 do {
1737 int i;
1738 for (i = 0; i < 16; i++) {
1739 sprintf(slavenam, "/dev/pty%c%x", c, i);
1740 if (stat(slavenam, &statb) < 0) {
1741 no_ptys = TRUE; /* bypass all this next time */
1742 goto use_pipes;
1743 }
1744
1745 if ((master = open(slavenam, O_RDWR)) >= 0) {
1746 slavenam[sizeof("/dev/") - 1] = 't';
1747 if (access(slavenam, R_OK | W_OK) == 0)
1748 goto got_the_pty;
1749 close(master);
1750 }
1751 }
1752 if (++c > 'z')
1753 c = 'a';
1754 } while (c != first_pty_letter);
1755 } else
1756 no_ptys = TRUE;
1757
1758 /* Couldn't find a pty. Fall back to using pipes. */
1759 goto use_pipes;
1760
1761 got_the_pty:
1762 if ((slave = open(slavenam, O_RDWR)) < 0) {
1763 fatal(_("could not open `%s', mode `%s'"),
1764 slavenam, "r+");
1765 }
1766
1767#ifdef I_PUSH
1768 /*
1769 * Push the necessary modules onto the slave to
1770 * get terminal semantics.
1771 */
1772 ioctl(slave, I_PUSH, "ptem");
1773 ioctl(slave, I_PUSH, "ldterm");
1774#endif
1775
1776#ifdef TIOCSCTTY
1777 ioctl(slave, TIOCSCTTY, 0);
1778#endif
1779 tcgetattr(slave, &st);
1780 st.c_iflag &= ~(ISTRIP | IGNCR | INLCR | IXOFF);
1781 st.c_iflag |= (ICRNL | IGNPAR | BRKINT | IXON);
1782 st.c_oflag &= ~OPOST;
1783 st.c_cflag &= ~CSIZE;
1784 st.c_cflag |= CREAD | CS8 | CLOCAL;
1785 st.c_lflag &= ~(ECHO | ECHOE | ECHOK | NOFLSH | TOSTOP);
1786 st.c_lflag |= ISIG;
1787#if 0
1788 st.c_cc[VMIN] = 1;
1789 st.c_cc[VTIME] = 0;
1790#endif
1791
1792 /* Set some control codes to default values */
1793#ifdef VINTR
1794 st.c_cc[VINTR] = '\003'; /* ^c */
1795#endif
1796#ifdef VQUIT
1797 st.c_cc[VQUIT] = '\034'; /* ^| */
1798#endif
1799#ifdef VERASE
1800 st.c_cc[VERASE] = '\177'; /* ^? */
1801#endif
1802#ifdef VKILL
1803 st.c_cc[VKILL] = '\025'; /* ^u */
1804#endif
1805#ifdef VEOF
1806 st.c_cc[VEOF] = '\004'; /* ^d */
1807#endif
1808 tcsetattr(slave, TCSANOW, &st);
1809
1810 switch (pid = fork ()) {
1811 case 0:
1812 /* Child process */
1813 if (close(master) == -1)
1814 fatal(_("close of master pty failed (%s)"), strerror(errno));
1815 if (close(1) == -1)
1816 fatal(_("close of stdout in child failed (%s)"),
1817 strerror(errno));
1818 if (dup(slave) != 1)
1819 fatal(_("moving slave pty to stdout in child failed (dup: %s)"), strerror(errno));
1820 if (close(0) == -1)
1821 fatal(_("close of stdin in child failed (%s)"),
1822 strerror(errno));
1823 if (dup(slave) != 0)
1824 fatal(_("moving slave pty to stdin in child failed (dup: %s)"), strerror(errno));
1825 if (close(slave))
1826 fatal(_("close of slave pty failed (%s)"), strerror(errno));
1827
1828 /* stderr does NOT get dup'ed onto child's stdout */
1829
1830 signal(SIGPIPE, SIG_DFL);
1831
1832 execl("/bin/sh", "sh", "-c", str, NULL);
1833 _exit(errno == ENOENT ? 127 : 126);
1834
1835 case -1:
1836 save_errno = errno;
1837 close(master);
1838 errno = save_errno;
1839 return FALSE;
1840
1841 }
1842
1843 /* parent */
1844 if (close(slave))
1845 fatal(_("close of slave pty failed (%s)"), strerror(errno));
1846
1847 rp->pid = pid;
1848 rp->iop = iop_alloc(master, str, NULL);
1849 if (rp->iop == NULL) {
1850 (void) close(master);
1851 (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */
1852 return FALSE;
1853 }
1854
1855 /*
1856 * Force read and write ends of two-way connection to
1857 * be different fd's so they can be closed independently.
1858 */
1859 if ((dup_master = dup(master)) < 0
1860 || (rp->fp = fdopen(dup_master, "w")) == NULL) {
1861 iop_close(rp->iop);
1862 rp->iop = NULL;
1863 (void) close(master);
1864 (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */
1865 if (dup_master > 0)
1866 (void) close(dup_master);
1867 return FALSE;
1868 }
1869 rp->flag |= RED_PTY;
1870 os_close_on_exec(master, str, "pipe", "from");
1871 os_close_on_exec(dup_master, str, "pipe", "to");
1872 first_pty_letter = '\0'; /* reset for next command */
1873 return TRUE;
1874 }
1875#endif /* HAVE_TERMIOS_H */
1876
1877use_pipes:
1878#ifndef PIPES_SIMULATED /* real pipes */
1879 /* case 3: two way pipe to a child process */
1880 {
1881 int ptoc[2], ctop[2];
1882 int pid;
1883 int save_errno;
1884#ifdef __EMX__
1885 int save_stdout, save_stdin;
1886#endif
1887
1888 if (pipe(ptoc) < 0)
1889 return FALSE; /* errno set, diagnostic from caller */
1890
1891 if (pipe(ctop) < 0) {
1892 save_errno = errno;
1893 close(ptoc[0]);
1894 close(ptoc[1]);
1895 errno = save_errno;
1896 return FALSE;
1897 }
1898
1899#ifdef __EMX__
1900 save_stdin = dup(0); /* duplicate stdin */
1901 save_stdout = dup(1); /* duplicate stdout */
1902
1903 if (save_stdout == -1 || save_stdin == -1) {
1904 /* if an error occurrs close all open file handles */
1905 save_errno = errno;
1906 if (save_stdin != -1)
1907 close(save_stdin);
1908 if (save_stdout != -1)
1909 close(save_stdout);
1910 close(ptoc[0]); close(ptoc[1]);
1911 close(ctop[0]); close(ctop[1]);
1912 errno = save_errno;
1913 return FALSE;
1914 }
1915
1916 /* connect pipes to stdin and stdout */
1917 close(1); /* close stdout */
1918 if (dup(ctop[1]) != 1) /* connect pipe input to stdout */
1919 fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
1920
1921 close(0); /* close stdin */
1922 if (dup(ptoc[0]) != 0) /* connect pipe output to stdin */
1923 fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno));
1924
1925 /* none of these handles must be inherited by the child process */
1926 (void) close(ptoc[0]); /* close pipe output, child will use stdin instead */
1927 (void) close(ctop[1]); /* close pipe input, child will use stdout instead */
1928
1929 os_close_on_exec(ptoc[1], str, "pipe", "from"); /* pipe input: output of the parent process */
1930 os_close_on_exec(ctop[0], str, "pipe", "from"); /* pipe output: input of the parent process */
1931 os_close_on_exec(save_stdin, str, "pipe", "from"); /* saved stdin of the parent process */
1932 os_close_on_exec(save_stdout, str, "pipe", "from"); /* saved stdout of the parent process */
1933
1934 /* stderr does NOT get dup'ed onto child's stdout */
1935 pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", str, NULL);
1936
1937 /* restore stdin and stdout */
1938 close(1);
1939 if (dup(save_stdout) != 1)
1940 fatal(_("restoring stdout in parent process failed\n"));
1941 close(save_stdout);
1942
1943 close(0);
1944 if (dup(save_stdin) != 0)
1945 fatal(_("restoring stdin in parent process failed\n"));
1946 close(save_stdin);
1947
1948 if (pid < 0) { /* spawnl() failed */
1949 save_errno = errno;
1950 close(ptoc[1]);
1951 close(ctop[0]);
1952
1953 errno = save_errno;
1954 return FALSE;
1955 }
1956
1957#else /* NOT __EMX__ */
1958 if ((pid = fork()) < 0) {
1959 save_errno = errno;
1960 close(ptoc[0]); close(ptoc[1]);
1961 close(ctop[0]); close(ctop[1]);
1962 errno = save_errno;
1963 return FALSE;
1964 }
1965
1966 if (pid == 0) { /* child */
1967 if (close(1) == -1)
1968 fatal(_("close of stdout in child failed (%s)"),
1969 strerror(errno));
1970 if (dup(ctop[1]) != 1)
1971 fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
1972 if (close(0) == -1)
1973 fatal(_("close of stdin in child failed (%s)"),
1974 strerror(errno));
1975 if (dup(ptoc[0]) != 0)
1976 fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno));
1977 if ( close(ptoc[0]) == -1 || close(ptoc[1]) == -1
1978 || close(ctop[0]) == -1 || close(ctop[1]) == -1)
1979 fatal(_("close of pipe failed (%s)"), strerror(errno));
1980 /* stderr does NOT get dup'ed onto child's stdout */
1981 execl("/bin/sh", "sh", "-c", str, NULL);
1982 _exit(errno == ENOENT ? 127 : 126);
1983 }
1984#endif /* NOT __EMX__ */
1985
1986 /* parent */
1987 rp->pid = pid;
1988 rp->iop = iop_alloc(ctop[0], str, NULL);
1989 if (rp->iop == NULL) {
1990 (void) close(ctop[0]);
1991 (void) close(ctop[1]);
1992 (void) close(ptoc[0]);
1993 (void) close(ptoc[1]);
1994 (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */
1995
1996 return FALSE;
1997 }
1998 rp->fp = fdopen(ptoc[1], "w");
1999 if (rp->fp == NULL) {
2000 iop_close(rp->iop);
2001 rp->iop = NULL;
2002 (void) close(ctop[0]);
2003 (void) close(ctop[1]);
2004 (void) close(ptoc[0]);
2005 (void) close(ptoc[1]);
2006 (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */
2007
2008 return FALSE;
2009 }
2010
2011#ifndef __EMX__
2012 os_close_on_exec(ctop[0], str, "pipe", "from");
2013 os_close_on_exec(ptoc[1], str, "pipe", "from");
2014
2015 (void) close(ptoc[0]);
2016 (void) close(ctop[1]);
2017#endif
2018
2019 return TRUE;
2020 }
2021
2022#else /*PIPES_SIMULATED*/
2023
2024 fatal(_("`|&' not supported"));
2025 /*NOTREACHED*/
2026 return FALSE;
2027
2028#endif
2029}
2030
2031#ifndef PIPES_SIMULATED /* real pipes */
2032
2033/* wait_any --- wait for a child process, close associated pipe */
2034
2035static int
2036wait_any(int interesting) /* pid of interest, if any */
2037{
2038 RETSIGTYPE (*hstat) P((int)), (*istat) P((int)), (*qstat) P((int));
2039 int pid;
2040 int status = 0;
2041 struct redirect *redp;
2042
2043 hstat = signal(SIGHUP, SIG_IGN);
2044 istat = signal(SIGINT, SIG_IGN);
2045 qstat = signal(SIGQUIT, SIG_IGN);
2046 for (;;) {
2047#ifdef HAVE_SYS_WAIT_H /* Posix compatible sys/wait.h */
2048 pid = wait(&status);
2049#else
2050 pid = wait((union wait *)&status);
2051#endif /* NeXT */
2052 if (interesting && pid == interesting) {
2053 break;
2054 } else if (pid != -1) {
2055 for (redp = red_head; redp != NULL; redp = redp->next)
2056 if (pid == redp->pid) {
2057 redp->pid = -1;
2058 redp->status = status;
2059 break;
2060 }
2061 }
2062 if (pid == -1 && errno == ECHILD)
2063 break;
2064 }
2065 signal(SIGHUP, hstat);
2066 signal(SIGINT, istat);
2067 signal(SIGQUIT, qstat);
2068 return status;
2069}
2070
2071/* gawk_popen --- open an IOBUF on a child process */
2072
2073static IOBUF *
2074gawk_popen(const char *cmd, struct redirect *rp)
2075{
2076 int p[2];
2077 register int pid;
2078#ifdef __EMX__
2079 int save_stdout;
2080#endif
2081
2082 /*
2083 * used to wait for any children to synchronize input and output,
2084 * but this could cause gawk to hang when it is started in a pipeline
2085 * and thus has a child process feeding it input (shell dependant)
2086 */
2087 /*(void) wait_any(0);*/ /* wait for outstanding processes */
2088
2089 if (pipe(p) < 0)
2090 fatal(_("cannot open pipe `%s' (%s)"), cmd, strerror(errno));
2091
2092#ifdef __EMX__
2093 save_stdout = dup(1); /* save stdout */
2094 rp->iop = NULL;
2095 if (save_stdout == -1)
2096 return rp->iop; /* failed */
2097
2098 close(1); /* close stdout */
2099 if (dup(p[1]) != 1)
2100 fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
2101
2102 /* none of these handles must be inherited by the child process */
2103 close(p[1]); /* close pipe input */
2104
2105 os_close_on_exec(p[0], cmd, "pipe", "from"); /* pipe output: input of the parent process */
2106 os_close_on_exec(save_stdout, cmd, "pipe", "from"); /* saved stdout of the parent process */
2107
2108 pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", cmd, NULL);
2109
2110 /* restore stdout */
2111 close(1);
2112 if (dup(save_stdout) != 1)
2113 fatal(_("restoring stdout in parent process failed\n"));
2114 close(save_stdout);
2115
2116#else /* NOT __EMX__ */
2117 if ((pid = fork()) == 0) {
2118 if (close(1) == -1)
2119 fatal(_("close of stdout in child failed (%s)"),
2120 strerror(errno));
2121 if (dup(p[1]) != 1)
2122 fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
2123 if (close(p[0]) == -1 || close(p[1]) == -1)
2124 fatal(_("close of pipe failed (%s)"), strerror(errno));
2125 execl("/bin/sh", "sh", "-c", cmd, NULL);
2126 _exit(errno == ENOENT ? 127 : 126);
2127 }
2128#endif /* NOT __EMX__ */
2129
2130 if (pid == -1)
2131 fatal(_("cannot create child process for `%s' (fork: %s)"), cmd, strerror(errno));
2132 rp->pid = pid;
2133#ifndef __EMX__
2134 if (close(p[1]) == -1)
2135 fatal(_("close of pipe failed (%s)"), strerror(errno));
2136#endif
2137 os_close_on_exec(p[0], cmd, "pipe", "from");
2138 rp->iop = iop_alloc(p[0], cmd, NULL);
2139 if (rp->iop == NULL)
2140 (void) close(p[0]);
2141
2142 return rp->iop;
2143}
2144
2145/* gawk_pclose --- close an open child pipe */
2146
2147static int
2148gawk_pclose(struct redirect *rp)
2149{
2150 if (rp->iop != NULL)
2151 (void) iop_close(rp->iop);
2152 rp->iop = NULL;
2153
2154 /* process previously found, return stored status */
2155 if (rp->pid == -1)
2156 return rp->status;
2157 rp->status = wait_any(rp->pid);
2158 rp->pid = -1;
2159 return rp->status;
2160}
2161
2162#else /* PIPES_SIMULATED */
2163
2164/*
2165 * use temporary file rather than pipe
2166 * except if popen() provides real pipes too
2167 */
2168
2169#if defined(VMS) || defined(OS2) || defined (MSDOS) || defined(WIN32) || defined(TANDEM) || defined(__EMX__)
2170
2171/* gawk_popen --- open an IOBUF on a child process */
2172
2173static IOBUF *
2174gawk_popen(const char *cmd, struct redirect *rp)
2175{
2176 FILE *current;
2177
2178 os_restore_mode(fileno(stdin));
2179 current = popen(cmd, binmode("r"));
2180 if ((BINMODE & 1) != 0)
2181 os_setbinmode(fileno(stdin), O_BINARY);
2182 if (current == NULL)
2183 return NULL;
2184 os_close_on_exec(fileno(current), cmd, "pipe", "from");
2185 rp->iop = iop_alloc(fileno(current), cmd, NULL);
2186 if (rp->iop == NULL) {
2187 (void) pclose(current);
2188 current = NULL;
2189 }
2190 rp->ifp = current;
2191 return rp->iop;
2192}
2193
2194/* gawk_pclose --- close an open child pipe */
2195
2196static int
2197gawk_pclose(struct redirect *rp)
2198{
2199 int rval, aval, fd = rp->iop->fd;
2200
2201 if (rp->iop != NULL) {
2202 rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */
2203 rval = iop_close(rp->iop);
2204 }
2205 rp->iop = NULL;
2206 aval = pclose(rp->ifp);
2207 rp->ifp = NULL;
2208 return (rval < 0 ? rval : aval);
2209}
2210#else /* not (VMS || OS2 || MSDOS || TANDEM) */
2211
2212static struct pipeinfo {
2213 char *command;
2214 char *name;
2215} pipes[_NFILE];
2216
2217/* gawk_popen --- open an IOBUF on a child process */
2218
2219static IOBUF *
2220gawk_popen(const char *cmd, struct redirect *rp)
2221{
2222 int current;
2223 char *name;
2224 static char cmdbuf[256];
2225
2226 /* get a name to use */
2227 if ((name = tempnam(".", "pip")) == NULL)
2228 return NULL;
2229 sprintf(cmdbuf, "%s > %s", cmd, name);
2230 system(cmdbuf);
2231 if ((current = open(name, O_RDONLY)) == INVALID_HANDLE)
2232 return NULL;
2233 pipes[current].name = name;
2234 emalloc(pipes[current].command, char *, strlen(cmd)+1, "gawk_popen");
2235 strcpy(pipes[current].command, cmd);
2236 os_close_on_exec(current, cmd, "pipe", "from");
2237 rp->iop = iop_alloc(current, name, NULL);
2238 if (rp->iop == NULL)
2239 (void) close(current);
2240 return rp->iop;
2241}
2242
2243/* gawk_pclose --- close an open child pipe */
2244
2245static int
2246gawk_pclose(struct redirect *rp)
2247{
2248 int cur = rp->iop->fd;
2249 int rval = 0;
2250
2251 if (rp->iop != NULL)
2252 rval = iop_close(rp->iop);
2253 rp->iop = NULL;
2254
2255 /* check for an open file */
2256 if (pipes[cur].name == NULL)
2257 return -1;
2258 unlink(pipes[cur].name);
2259 free(pipes[cur].name);
2260 pipes[cur].name = NULL;
2261 free(pipes[cur].command);
2262 return rval;
2263}
2264#endif /* not (VMS || OS2 || MSDOS || TANDEM) */
2265
2266#endif /* PIPES_SIMULATED */
2267
2268/* do_getline --- read in a line, into var and with redirection, as needed */
2269
2270NODE *
2271do_getline(NODE *tree)
2272{
2273 struct redirect *rp = NULL;
2274 IOBUF *iop;
2275 int cnt = EOF;
2276 char *s = NULL;
2277 int errcode;
2278
2279 while (cnt == EOF) {
2280 if (tree->rnode == NULL) { /* no redirection */
2281 iop = nextfile(FALSE);
2282 if (iop == NULL) /* end of input */
2283 return tmp_number((AWKNUM) 0.0);
2284 } else {
2285 int redir_error = 0;
2286
2287 rp = redirect(tree->rnode, &redir_error);
2288 if (rp == NULL && redir_error) { /* failed redirect */
2289 if (! do_traditional)
2290 update_ERRNO_saved(redir_error);
2291
2292 return tmp_number((AWKNUM) -1.0);
2293 }
2294 iop = rp->iop;
2295 if (iop == NULL) /* end of input */
2296 return tmp_number((AWKNUM) 0.0);
2297 }
2298 errcode = 0;
2299 cnt = get_a_record(&s, iop, &errcode);
2300 if (errcode != 0) {
2301 if (! do_traditional && (errcode != -1))
2302 update_ERRNO_saved(errcode);
2303
2304 return tmp_number((AWKNUM) -1.0);
2305 }
2306 if (cnt == EOF) {
2307 if (rp != NULL) {
2308 /*
2309 * Don't do iop_close() here if we are
2310 * reading from a pipe; otherwise
2311 * gawk_pclose will not be called.
2312 */
2313 if ((rp->flag & (RED_PIPE|RED_TWOWAY)) == 0) {
2314 (void) iop_close(iop);
2315 rp->iop = NULL;
2316 }
2317 rp->flag |= RED_EOF; /* sticky EOF */
2318 return tmp_number((AWKNUM) 0.0);
2319 } else
2320 continue; /* try another file */
2321 }
2322 if (rp == NULL) {
2323 NR++;
2324 FNR++;
2325 }
2326 if (tree->lnode == NULL) /* no optional var. */
2327 set_record(s, cnt);
2328 else { /* assignment to variable */
2329 Func_ptr after_assign = NULL;
2330 NODE **lhs;
2331
2332 lhs = get_lhs(tree->lnode, &after_assign, FALSE);
2333 unref(*lhs);
2334 *lhs = make_string(s, cnt);
2335 (*lhs)->flags |= MAYBE_NUM;
2336 /* we may have to regenerate $0 here! */
2337 if (after_assign != NULL)
2338 (*after_assign)();
2339 }
2340 }
2341 return tmp_number((AWKNUM) 1.0);
2342}
2343
2344/* pathopen --- pathopen with default file extension handling */
2345
2346int
2347pathopen(const char *file)
2348{
2349 int fd = do_pathopen(file);
2350
2351#ifdef DEFAULT_FILETYPE
2352 if (! do_traditional && fd <= INVALID_HANDLE) {
2353 char *file_awk;
2354 int save = errno;
2355#ifdef VMS
2356 int vms_save = vaxc$errno;
2357#endif
2358
2359 /* append ".awk" and try again */
2360 emalloc(file_awk, char *, strlen(file) +
2361 sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
2362 sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE);
2363 fd = do_pathopen(file_awk);
2364 free(file_awk);
2365 if (fd <= INVALID_HANDLE) {
2366 errno = save;
2367#ifdef VMS
2368 vaxc$errno = vms_save;
2369#endif
2370 }
2371 }
2372#endif /*DEFAULT_FILETYPE*/
2373
2374 return fd;
2375}
2376
2377/* do_pathopen --- search $AWKPATH for source file */
2378
2379static int
2380do_pathopen(const char *file)
2381{
2382 static const char *savepath = NULL;
2383 static int first = TRUE;
2384 const char *awkpath;
2385 char *cp, *trypath;
2386 int fd;
2387 int len;
2388
2389 if (STREQ(file, "-"))
2390 return 0;
2391
2392 if (do_traditional)
2393 return devopen(file, "r");
2394
2395 if (first) {
2396 first = FALSE;
2397 if ((awkpath = getenv("AWKPATH")) != NULL && *awkpath)
2398 savepath = awkpath; /* used for restarting */
2399 else
2400 savepath = defpath;
2401 }
2402 awkpath = savepath;
2403
2404 /* some kind of path name, no search */
2405 if (ispath(file))
2406 return devopen(file, "r");
2407
2408 /* no arbitrary limits: */
2409 len = strlen(awkpath) + strlen(file) + 2;
2410 emalloc(trypath, char *, len, "do_pathopen");
2411
2412 do {
2413 trypath[0] = '\0';
2414
2415 for (cp = trypath; *awkpath && *awkpath != envsep; )
2416 *cp++ = *awkpath++;
2417
2418 if (cp != trypath) { /* nun-null element in path */
2419 /* add directory punctuation only if needed */
2420 if (! isdirpunct(*(cp-1)))
2421 *cp++ = '/';
2422 /* append filename */
2423 strcpy(cp, file);
2424 } else
2425 strcpy(trypath, file);
2426 if ((fd = devopen(trypath, "r")) > INVALID_HANDLE) {
2427 free(trypath);
2428 return fd;
2429 }
2430
2431 /* no luck, keep going */
2432 if(*awkpath == envsep && awkpath[1] != '\0')
2433 awkpath++; /* skip colon */
2434 } while (*awkpath != '\0');
2435 free(trypath);
2436
2437 /*
2438 * You might have one of the awk paths defined, WITHOUT the current
2439 * working directory in it. Therefore try to open the file in the
2440 * current directory.
2441 */
2442 return devopen(file, "r");
2443}
2444
2445#ifdef TEST
2446int bufsize = 8192;
2447
2448void
2449fatal(const char *s)
2450{
2451 printf("%s\n", s);
2452 exit(1);
2453}
2454#endif
2455
2456/* open hooks, mainly for use by extension functions */
2457
2458static struct open_hook {
2459 struct open_hook *next;
2460 void *(*open_func)(IOBUF *);
2461} *open_hooks;
2462
2463/* register_open_hook --- add an open hook to the list */
2464
2465void
2466register_open_hook(void *(*open_func)(IOBUF *))
2467{
2468 struct open_hook *oh;
2469
2470 emalloc(oh, struct open_hook *, sizeof(*oh), "register_open_hook");
2471 oh->open_func = open_func;
2472 oh->next = open_hooks;
2473 open_hooks = oh;
2474}
2475
2476/* iop_alloc --- allocate an IOBUF structure for an open fd */
2477
2478static IOBUF *
2479iop_alloc(int fd, const char *name, IOBUF *iop)
2480{
2481 struct stat sbuf;
2482 struct open_hook *oh;
2483
2484 if (iop == NULL)
2485 emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
2486 memset(iop, '\0', sizeof(IOBUF));
2487 iop->flag = 0;
2488 iop->fd = fd;
2489 iop->name = name;
2490
2491 /* walk through open hooks, stop at first one that responds */
2492 for (oh = open_hooks; oh != NULL; oh = oh->next) {
2493 if ((iop->opaque = (*oh->open_func)(iop)) != NULL)
2494 break;
2495 }
2496
2497 if (iop->fd == INVALID_HANDLE) {
2498 free(iop);
2499 return NULL;
2500 }
2501 if (isatty(iop->fd))
2502 iop->flag |= IOP_IS_TTY;
2503 iop->readsize = iop->size = optimal_bufsize(iop->fd, & sbuf);
2504 iop->sbuf = sbuf;
2505 if (do_lint && S_ISREG(sbuf.st_mode) && sbuf.st_size == 0)
2506 lintwarn(_("data file `%s' is empty"), name);
2507 errno = 0;
2508 iop->count = iop->scanoff = 0;
2509 emalloc(iop->buf, char *, iop->size += 2, "iop_alloc");
2510 iop->off = iop->buf;
2511 iop->dataend = NULL;
2512 iop->end = iop->buf + iop->size;
2513 iop->flag |= IOP_AT_START;
2514 return iop;
2515}
2516
2517#define set_RT_to_null() \
2518 (void)(! do_traditional && (unref(RT_node->var_value), \
2519 RT_node->var_value = Nnull_string))
2520
2521#define set_RT(str, len) \
2522 (void)(! do_traditional && (unref(RT_node->var_value), \
2523 RT_node->var_value = make_string(str, len)))
2524
2525/* grow must increase size of buffer, set end, make sure off and dataend point at */
2526/* right spot. */
2527/* */
2528/* */
2529/* <growbuffer>= */
2530/* grow_iop_buffer --- grow the buffer */
2531
2532static void
2533grow_iop_buffer(IOBUF *iop)
2534{
2535 size_t valid = iop->dataend - iop->off;
2536 size_t off = iop->off - iop->buf;
2537 size_t newsize;
2538
2539 /*
2540 * Lop off original extra two bytes, double the size,
2541 * add them back.
2542 */
2543 newsize = ((iop->size - 2) * 2) + 2;
2544
2545 /* Check for overflow */
2546 if (newsize <= iop->size)
2547 fatal(_("could not allocate more input memory"));
2548
2549 /* Make sure there's room for a disk block */
2550 if (newsize - valid < iop->readsize)
2551 newsize += iop->readsize + 2;
2552
2553 /* Check for overflow, again */
2554 if (newsize <= iop->size)
2555 fatal(_("could not allocate more input memory"));
2556
2557 iop->size = newsize;
2558 erealloc(iop->buf, char *, iop->size, "grow_iop_buffer");
2559 iop->off = iop->buf + off;
2560 iop->dataend = iop->off + valid;
2561 iop->end = iop->buf + iop->size;
2562}
2563
2564/* Here are the routines. */
2565/* */
2566/* */
2567/* <rs1scan>= */
2568/* rs1scan --- scan for a single character record terminator */
2569
2570static RECVALUE
2571rs1scan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
2572{
2573 register char *bp;
2574 register char rs;
2575#ifdef MBS_SUPPORT
2576 size_t mbclen = 0;
2577 mbstate_t mbs;
2578#endif
2579
2580 memset(recm, '\0', sizeof(struct recmatch));
2581 rs = RS->stptr[0];
2582 *(iop->dataend) = rs; /* set sentinel */
2583 recm->start = iop->off; /* beginning of record */
2584
2585 bp = iop->off;
2586 if (*state == INDATA) /* skip over data we've already seen */
2587 bp += iop->scanoff;
2588
2589#ifdef MBS_SUPPORT
2590 /*
2591 * From: Bruno Haible <bruno@clisp.org>
2592 * To: Aharon Robbins <arnold@skeeve.com>, gnits@gnits.org
2593 * Subject: Re: multibyte locales: any way to find if a character isn't multibyte?
2594 * Date: Mon, 23 Jun 2003 12:20:16 +0200
2595 * Cc: isamu@yamato.ibm.com
2596 *
2597 * Hi,
2598 *
2599 * > Is there any way to make the following query to the current locale?
2600 * >
2601 * > Given an 8-bit value, can this value ever appear as part of
2602 * > a multibyte character?
2603 *
2604 * There is no simple answer here. The easiest solution I see is to
2605 * get the current locale's codeset (via locale_charset() which is a
2606 * wrapper around nl_langinfo(CODESET)), and then perform a case-by-case
2607 * treatment of the known multibyte encodings, from GB2312 to EUC-JISX0213;
2608 * for the unibyte encodings, a single btowc() call will tell you.
2609 *
2610 * > This is particularly critical for me for ASCII newline ('\n'). If I
2611 * > can be guaranteed that it never shows up as part of a multibyte character,
2612 * > I can speed up gawk considerably in mulitbyte locales.
2613 *
2614 * This is much simpler to answer!
2615 * In all ASCII based multibyte encodings used for locales today (this
2616 * excludes EBCDIC based doublebyte encodings from IBM, and also excludes
2617 * ISO-2022-JP which is used for email exchange but not as a locale encoding)
2618 * ALL bytes in the range 0x00..0x2F occur only as a single character, not
2619 * as part of a multibyte character.
2620 *
2621 * So it's safe to assume, but deserves a comment in the source.
2622 *
2623 * Bruno
2624 ***************************************************************
2625 * From: Bruno Haible <bruno@clisp.org>
2626 * To: Aharon Robbins <arnold@skeeve.com>
2627 * Subject: Re: multibyte locales: any way to find if a character isn't multibyte?
2628 * Date: Mon, 23 Jun 2003 14:27:49 +0200
2629 *
2630 * On Monday 23 June 2003 14:11, you wrote:
2631 *
2632 * > if (rs != '\n' && MB_CUR_MAX > 1) {
2633 *
2634 * If you assume ASCII, you can even write
2635 *
2636 * if (rs >= 0x30 && MB_CUR_MAX > 1) {
2637 *
2638 * (this catches also the space character) but if portability to EBCDIC
2639 * systems is desired, your code is fine as is.
2640 *
2641 * Bruno
2642 */
2643 /* Thus, the check for \n here; big speedup ! */
2644 if (rs != '\n' && gawk_mb_cur_max > 1) {
2645 int len = iop->dataend - bp;
2646 int found = 0;
2647 memset(&mbs, 0, sizeof(mbstate_t));
2648 do {
2649 if (*bp == rs)
2650 found = 1;
2651 mbclen = mbrlen(bp, len, &mbs);
2652 if ((mbclen == 1) || (mbclen == (size_t) -1)
2653 || (mbclen == (size_t) -2) || (mbclen == 0)) {
2654 /* We treat it as a singlebyte character. */
2655 mbclen = 1;
2656 }
2657 len -= mbclen;
2658 bp += mbclen;
2659 } while (len > 0 && ! found);
2660
2661 /* Check that newline found isn't the sentinel. */
2662 if (found && (bp - mbclen) < iop->dataend) {
2663 /*
2664 * set len to what we have so far, in case this is
2665 * all there is
2666 */
2667 recm->len = bp - recm->start - mbclen;
2668 recm->rt_start = bp - mbclen;
2669 recm->rt_len = mbclen;
2670 *state = NOSTATE;
2671 return REC_OK;
2672 } else {
2673 /* also set len */
2674 recm->len = bp - recm->start;
2675 *state = INDATA;
2676 iop->scanoff = bp - iop->off;
2677 return NOTERM;
2678 }
2679 }
2680#endif
2681 while (*bp != rs)
2682 bp++;
2683
2684 /* set len to what we have so far, in case this is all there is */
2685 recm->len = bp - recm->start;
2686
2687 if (bp < iop->dataend) { /* found it in the buffer */
2688 recm->rt_start = bp;
2689 recm->rt_len = 1;
2690 *state = NOSTATE;
2691 return REC_OK;
2692 } else {
2693 *state = INDATA;
2694 iop->scanoff = bp - iop->off;
2695 return NOTERM;
2696 }
2697}
2698
2699/* <rsrescan>= */
2700/* rsrescan --- search for a regex match in the buffer */
2701
2702static RECVALUE
2703rsrescan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
2704{
2705 register char *bp;
2706 size_t restart = 0, reend = 0;
2707 Regexp *RSre = RS_regexp;
2708 int regex_flags = RE_NEED_START;
2709
2710 memset(recm, '\0', sizeof(struct recmatch));
2711 recm->start = iop->off;
2712
2713 bp = iop->off;
2714 if (*state == INDATA)
2715 bp += iop->scanoff;
2716
2717 if ((iop->flag & IOP_AT_START) == 0)
2718 regex_flags |= RE_NO_BOL;
2719again:
2720 /* case 1, no match */
2721 if (research(RSre, bp, 0, iop->dataend - bp, regex_flags) == -1) {
2722 /* set len, in case this all there is. */
2723 recm->len = iop->dataend - iop->off;
2724 return NOTERM;
2725 }
2726
2727 /* ok, we matched within the buffer, set start and end */
2728 restart = RESTART(RSre, iop->off);
2729 reend = REEND(RSre, iop->off);
2730
2731 /* case 2, null regex match, grow buffer, try again */
2732 if (restart == reend) {
2733 *state = INDATA;
2734 iop->scanoff = reend + 1;
2735 /*
2736 * If still room in buffer, skip over null match
2737 * and restart search. Otherwise, return.
2738 */
2739 if (bp + iop->scanoff < iop->dataend) {
2740 bp += iop->scanoff;
2741 goto again;
2742 }
2743 recm->len = (bp - iop->off) + restart;
2744 return NOTERM;
2745 }
2746
2747 /*
2748 * At this point, we have a non-empty match.
2749 *
2750 * First, fill in rest of data. The rest of the cases return
2751 * a record and terminator.
2752 */
2753 recm->len = restart;
2754 recm->rt_start = bp + restart;
2755 recm->rt_len = reend - restart;
2756 *state = NOSTATE;
2757
2758 /*
2759 * 3. Match exactly at end:
2760 * if re is a simple string match
2761 * found a simple string match at end, return REC_OK
2762 * else
2763 * grow buffer, add more data, try again
2764 * fi
2765 */
2766 if (iop->off + reend >= iop->dataend) {
2767 if (reisstring(RS->stptr, RS->stlen, RSre, iop->off))
2768 return REC_OK;
2769 else
2770 return TERMATEND;
2771 }
2772
2773 /*
2774 * 4. Match within xxx bytes of end & maybe islong re:
2775 * return TERMNEAREND
2776 */
2777
2778 /*
2779 * case 4, match succeeded, but there may be more in
2780 * the next input buffer.
2781 *
2782 * Consider an RS of xyz(abc)? where the
2783 * exact end of the buffer is xyza and the
2784 * next two, unread, characters are bc.
2785 *
2786 * This matches the "xyz" and ends up putting the
2787 * "abc" into the front of the next record. Ooops.
2788 *
2789 * The remaybelong() function looks to see if the
2790 * regex contains one of: + * ? |. This is a very
2791 * simple heuristic, but in combination with the
2792 * "end of match within a few bytes of end of buffer"
2793 * check, should keep things reasonable.
2794 */
2795
2796 /*
2797 * XXX: The reisstring and remaybelong tests should
2798 * really be done once when RS is assigned to and
2799 * then tested as flags here. Maybe one day.
2800 */
2801
2802 /* succession of tests is easier to trace in GDB. */
2803 if (remaybelong(RS->stptr, RS->stlen)) {
2804 char *matchend = iop->off + reend;
2805
2806 if (iop->dataend - matchend < RS->stlen)
2807 return TERMNEAREND;
2808 }
2809
2810 return REC_OK;
2811}
2812
2813/* <rsnullscan>= */
2814/* rsnullscan --- handle RS = "" */
2815
2816static RECVALUE
2817rsnullscan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
2818{
2819 register char *bp;
2820
2821 if (*state == NOSTATE || *state == INLEADER)
2822 memset(recm, '\0', sizeof(struct recmatch));
2823
2824 recm->start = iop->off;
2825
2826 bp = iop->off;
2827 if (*state != NOSTATE)
2828 bp += iop->scanoff;
2829
2830 /* set sentinel */
2831 *(iop->dataend) = '\n';
2832
2833 if (*state == INTERM)
2834 goto find_longest_terminator;
2835 else if (*state == INDATA)
2836 goto scan_data;
2837 /* else
2838 fall into things from beginning,
2839 either NOSTATE or INLEADER */
2840
2841/* skip_leading: */
2842 /* leading newlines are ignored */
2843 while (*bp == '\n' && bp < iop->dataend)
2844 bp++;
2845
2846 if (bp >= iop->dataend) { /* LOTS of leading newlines, sheesh. */
2847 *state = INLEADER;
2848 iop->scanoff = bp - iop->off;
2849 return NOTERM;
2850 }
2851
2852 iop->off = recm->start = bp; /* real start of record */
2853scan_data:
2854 while (*bp++ != '\n')
2855 continue;
2856
2857 if (bp >= iop->dataend) { /* no terminator */
2858 iop->scanoff = recm->len = bp - iop->off - 1;
2859 *state = INDATA;
2860 return NOTERM;
2861 }
2862
2863 /* found one newline before end of buffer, check next char */
2864 if (*bp != '\n')
2865 goto scan_data;
2866
2867 /* we've now seen at least two newlines */
2868 *state = INTERM;
2869 recm->len = bp - iop->off - 1;
2870 recm->rt_start = bp - 1;
2871
2872find_longest_terminator:
2873 /* find as many newlines as we can, to set RT */
2874 while (*bp == '\n' && bp < iop->dataend)
2875 bp++;
2876
2877 recm->rt_len = bp - recm->rt_start;
2878 iop->scanoff = bp - iop->off;
2879
2880 if (bp >= iop->dataend)
2881 return TERMATEND;
2882
2883 return REC_OK;
2884}
2885
2886/* <getarecord>= */
2887/* get_a_record --- read a record from IOP into out, return length of EOF, set RT */
2888
2889int
2890get_a_record(char **out, /* pointer to pointer to data */
2891 IOBUF *iop, /* input IOP */
2892 int *errcode) /* pointer to error variable */
2893{
2894 struct recmatch recm;
2895 SCANSTATE state;
2896 RECVALUE ret;
2897 int retval;
2898 NODE *rtval = NULL;
2899 static RECVALUE (*lastmatchrec)P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)) = NULL;
2900
2901 if (at_eof(iop) && no_data_left(iop))
2902 return EOF;
2903
2904 if (iop->get_record != NULL)
2905 return (*iop->get_record)(out, iop, errcode);
2906
2907 /* <fill initial buffer>= */
2908 if (has_no_data(iop) || no_data_left(iop)) {
2909 iop->count = read(iop->fd, iop->buf, iop->readsize);
2910 if (iop->count == 0) {
2911 iop->flag |= IOP_AT_EOF;
2912 return EOF;
2913 } else if (iop->count == -1) {
2914 if (! do_traditional && errcode != NULL) {
2915 *errcode = errno;
2916 iop->flag |= IOP_AT_EOF;
2917 return EOF;
2918 } else
2919 fatal(_("error reading input file `%s': %s"),
2920 iop->name, strerror(errno));
2921 } else {
2922 iop->dataend = iop->buf + iop->count;
2923 iop->off = iop->buf;
2924 }
2925 }
2926
2927
2928
2929 /* <loop through file to find a record>= */
2930 state = NOSTATE;
2931 for (;;) {
2932 size_t dataend_off;
2933
2934 ret = (*matchrec)(iop, & recm, & state);
2935
2936 iop->flag &= ~IOP_AT_START;
2937
2938 if (ret == REC_OK)
2939 break;
2940
2941 /* need to add more data to buffer */
2942 /* <shift data down in buffer>= */
2943 dataend_off = iop->dataend - iop->off;
2944 memmove(iop->buf, iop->off, dataend_off);
2945 iop->off = iop->buf;
2946 iop->dataend = iop->buf + dataend_off;
2947
2948 /* <adjust recm contents>= */
2949 recm.start = iop->off;
2950 if (recm.rt_start != NULL)
2951 recm.rt_start = iop->off + recm.len;
2952
2953 /* <read more data, break if EOF>= */
2954 if ((iop->flag & IOP_IS_INTERNAL) != 0) {
2955 iop->flag |= IOP_AT_EOF;
2956 break;
2957 } else {
2958#define min(x, y) (x < y ? x : y)
2959 /* subtract one in read count to leave room for sentinel */
2960 size_t room_left = iop->end - iop->dataend - 1;
2961 size_t amt_to_read = min(iop->readsize, room_left);
2962
2963 if (amt_to_read < iop->readsize) {
2964 grow_iop_buffer(iop);
2965 /* <adjust recm contents>= */
2966 recm.start = iop->off;
2967 if (recm.rt_start != NULL)
2968 recm.rt_start = iop->off + recm.len;
2969
2970 /* recalculate amt_to_read */
2971 room_left = iop->end - iop->dataend - 1;
2972 amt_to_read = min(iop->readsize, room_left);
2973 }
2974 while (amt_to_read + iop->readsize < room_left)
2975 amt_to_read += iop->readsize;
2976
2977 iop->count = read(iop->fd, iop->dataend, amt_to_read);
2978 if (iop->count == -1) {
2979 if (! do_traditional && errcode != NULL) {
2980 *errcode = errno;
2981 iop->flag |= IOP_AT_EOF;
2982 break;
2983 } else
2984 fatal(_("error reading input file `%s': %s"),
2985 iop->name, strerror(errno));
2986 } else if (iop->count == 0) {
2987 /*
2988 * hit EOF before matching RS, so end
2989 * the record and set RT to ""
2990 */
2991 iop->flag |= IOP_AT_EOF;
2992 break;
2993 } else
2994 iop->dataend += iop->count;
2995 }
2996
2997
2998 }
2999
3000
3001
3002 /* <set record, RT, return right value>= */
3003
3004 /*
3005 * rtval is not a static pointer to avoid dangling pointer problems
3006 * in case awk code assigns to RT. A remote possibility, to be sure,
3007 * but Bitter Experience teaches us not to make ``that'll never
3008 * happen'' kinds of assumptions.
3009 */
3010 rtval = RT_node->var_value;
3011
3012 if (recm.rt_len == 0) {
3013 set_RT_to_null();
3014 lastmatchrec = NULL;
3015 } else {
3016 assert(recm.rt_start != NULL);
3017 /*
3018 * Optimization. For rs1 case, don't set RT if
3019 * character is same as last time. This knocks a
3020 * chunk of time off something simple like
3021 *
3022 * gawk '{ print }' /some/big/file
3023 *
3024 * Similarly, for rsnull case, if length of new RT is
3025 * shorter than current RT, just bump length down in RT.
3026 *
3027 * Make sure that matchrec didn't change since the last
3028 * check. (Ugh, details, details, details.)
3029 */
3030 if (lastmatchrec == NULL || lastmatchrec != matchrec) {
3031 lastmatchrec = matchrec;
3032 set_RT(recm.rt_start, recm.rt_len);
3033 } else if (matchrec == rs1scan) {
3034 if (rtval->stlen != 1 || rtval->stptr[0] != recm.rt_start[0])
3035 set_RT(recm.rt_start, recm.rt_len);
3036 /* else
3037 leave it alone */
3038 } else if (matchrec == rsnullscan) {
3039 if (rtval->stlen <= recm.rt_len)
3040 rtval->stlen = recm.rt_len;
3041 else
3042 set_RT(recm.rt_start, recm.rt_len);
3043 } else
3044 set_RT(recm.rt_start, recm.rt_len);
3045 }
3046
3047 if (recm.len == 0) {
3048 *out = NULL;
3049 retval = 0;
3050 } else {
3051 assert(recm.start != NULL);
3052 *out = recm.start;
3053 retval = recm.len;
3054 }
3055
3056 iop->off += recm.len + recm.rt_len;
3057
3058 if (recm.len == 0 && recm.rt_len == 0 && at_eof(iop))
3059 return EOF;
3060 else
3061 return retval;
3062
3063}
3064
3065/* set_RS --- update things as appropriate when RS is set */
3066
3067void
3068set_RS()
3069{
3070 static NODE *save_rs = NULL;
3071
3072 /*
3073 * Don't use cmp_nodes(), which pays attention to IGNORECASE.
3074 */
3075 if (save_rs
3076 && RS_node->var_value->stlen == save_rs->stlen
3077 && memcmp(RS_node->var_value->stptr, save_rs->stptr, save_rs->stlen) == 0) {
3078 /*
3079 * It could be that just IGNORECASE changed. If so,
3080 * update the regex and then do the same for FS.
3081 * set_IGNORECASE() relies on this routine to call
3082 * set_FS().
3083 */
3084 RS_regexp = (IGNORECASE ? RS_re_no_case : RS_re_yes_case);
3085 goto set_FS;
3086 }
3087 unref(save_rs);
3088 save_rs = dupnode(RS_node->var_value);
3089 RS_is_null = FALSE;
3090 RS = force_string(RS_node->var_value);
3091 if (RS_regexp != NULL) {
3092 refree(RS_re_yes_case);
3093 refree(RS_re_no_case);
3094 RS_re_yes_case = RS_re_no_case = RS_regexp = NULL;
3095 }
3096 if (RS->stlen == 0) {
3097 RS_is_null = TRUE;
3098 matchrec = rsnullscan;
3099 } else if (RS->stlen > 1) {
3100 static int warned = FALSE;
3101
3102 RS_re_yes_case = make_regexp(RS->stptr, RS->stlen, FALSE, TRUE);
3103 RS_re_no_case = make_regexp(RS->stptr, RS->stlen, TRUE, TRUE);
3104 RS_regexp = (IGNORECASE ? RS_re_no_case : RS_re_yes_case);
3105
3106 matchrec = rsrescan;
3107
3108 if (do_lint && ! warned) {
3109 lintwarn(_("multicharacter value of `RS' is a gawk extension"));
3110 warned = TRUE;
3111 }
3112 } else
3113 matchrec = rs1scan;
3114set_FS:
3115 if (! using_fieldwidths())
3116 set_FS();
3117}
3118
3119/* pty_vs_pipe --- return true if should use pty instead of pipes for `|&' */
3120
3121/*
3122 * This works by checking if PROCINFO["command", "pty"] exists and is true.
3123 */
3124
3125static int
3126pty_vs_pipe(const char *command)
3127{
3128#ifdef HAVE_TERMIOS_H
3129 char *full_index;
3130 size_t full_len;
3131 NODE *val;
3132 NODE *sub;
3133
3134 if (PROCINFO_node == NULL)
3135 return FALSE;
3136
3137 full_len = strlen(command)
3138 + SUBSEP_node->var_value->stlen
3139 + 3 /* strlen("pty") */
3140 + 1; /* string terminator */
3141 emalloc(full_index, char *, full_len, "pty_vs_pipe");
3142 sprintf(full_index, "%s%.*spty", command,
3143 (int) SUBSEP_node->var_value->stlen, SUBSEP_node->var_value->stptr);
3144
3145 sub = tmp_string(full_index, strlen(full_index));
3146 val = in_array(PROCINFO_node, sub);
3147 free_temp(sub);
3148 free(full_index);
3149
3150 if (val) {
3151 if (val->flags & MAYBE_NUM)
3152 (void) force_number(val);
3153 if (val->flags & NUMBER)
3154 return (val->numbr != 0.0);
3155 else
3156 return (val->stlen != 0);
3157 }
3158#endif /* HAVE_TERMIOS_H */
3159 return FALSE;
3160}
3161
3162/* iopflags2str --- make IOP flags printable */
3163
3164const char *
3165iopflags2str(int flag)
3166{
3167 static const struct flagtab values[] = {
3168 { IOP_IS_TTY, "IOP_IS_TTY" },
3169 { IOP_IS_INTERNAL, "IOP_IS_INTERNAL" },
3170 { IOP_NO_FREE, "IOP_NO_FREE" },
3171 { IOP_NOFREE_OBJ, "IOP_NOFREE_OBJ" },
3172 { IOP_AT_EOF, "IOP_AT_EOF" },
3173 { IOP_CLOSED, "IOP_CLOSED" },
3174 { IOP_AT_START, "IOP_AT_START" },
3175 { 0, NULL }
3176 };
3177
3178 return genflags2str(flag, values);
3179}
Note: See TracBrowser for help on using the repository browser.