b-make libg++-2.3.90
[unix-history] / gnu / usr.bin / awk / io.c
CommitLineData
8c4ebc23
JH
1/*
2 * io.c --- routines for dealing with input and output and records
3 */
4
5/*
6 * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
7 *
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Progamming 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 GAWK; see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26#include "awk.h"
27
28#ifndef O_RDONLY
29#include <fcntl.h>
30#endif
31
32#if !defined(S_ISDIR) && defined(S_IFDIR)
33#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
34#endif
35
36#ifndef atarist
37#define INVALID_HANDLE (-1)
38#else
39#define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1)
40#endif
41
42#if defined(MSDOS) || defined(atarist)
43#define PIPES_SIMULATED
44#endif
45
46static IOBUF *nextfile P((int skipping));
47static int inrec P((IOBUF *iop));
48static int iop_close P((IOBUF *iop));
49struct redirect *redirect P((NODE *tree, int *errflg));
50static void close_one P((void));
51static int close_redir P((struct redirect *rp));
52#ifndef PIPES_SIMULATED
53static int wait_any P((int interesting));
54#endif
55static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
56static IOBUF *iop_open P((char *file, char *how));
57static int gawk_pclose P((struct redirect *rp));
58static int do_pathopen P((char *file));
59
60extern FILE *fdopen();
61extern FILE *popen();
62
63static struct redirect *red_head = NULL;
64
65extern int output_is_tty;
66extern NODE *ARGC_node;
67extern NODE *ARGV_node;
68extern NODE *ARGIND_node;
69extern NODE *ERRNO_node;
70extern NODE **fields_arr;
71
72static jmp_buf filebuf; /* for do_nextfile() */
73
74/* do_nextfile --- implement gawk "next file" extension */
75
76void
77do_nextfile()
78{
79 (void) nextfile(1);
80 longjmp(filebuf, 1);
81}
82
83static IOBUF *
84nextfile(skipping)
85int skipping;
86{
87 static int i = 1;
88 static int files = 0;
89 NODE *arg;
90 int fd = INVALID_HANDLE;
91 static IOBUF *curfile = NULL;
92
93 if (skipping) {
94 if (curfile != NULL)
95 iop_close(curfile);
96 curfile = NULL;
97 return NULL;
98 }
99 if (curfile != NULL) {
100 if (curfile->cnt == EOF) {
101 (void) iop_close(curfile);
102 curfile = NULL;
103 } else
104 return curfile;
105 }
106 for (; i < (int) (ARGC_node->lnode->numbr); i++) {
107 arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i));
108 if (arg->stptr[0] == '\0')
109 continue;
110 arg->stptr[arg->stlen] = '\0';
111 if (! do_unix) {
112 ARGIND_node->var_value->numbr = i;
113 ARGIND_node->var_value->flags = NUM|NUMBER;
114 }
115 if (!arg_assign(arg->stptr)) {
116 files++;
117 curfile = iop_open(arg->stptr, "r");
118 if (curfile == NULL)
119 fatal("cannot open file `%s' for reading (%s)",
120 arg->stptr, strerror(errno));
121 /* NOTREACHED */
122 /* This is a kludge. */
123 unref(FILENAME_node->var_value);
124 FILENAME_node->var_value =
125 dupnode(arg);
126 FNR = 0;
127 i++;
128 break;
129 }
130 }
131 if (files == 0) {
132 files++;
133 /* no args. -- use stdin */
134 /* FILENAME is init'ed to "-" */
135 /* FNR is init'ed to 0 */
136 curfile = iop_alloc(fileno(stdin));
137 }
138 return curfile;
139}
140
141void
142set_FNR()
143{
144 FNR = (int) FNR_node->var_value->numbr;
145}
146
147void
148set_NR()
149{
150 NR = (int) NR_node->var_value->numbr;
151}
152
153/*
154 * This reads in a record from the input file
155 */
156static int
157inrec(iop)
158IOBUF *iop;
159{
160 char *begin;
161 register int cnt;
162 int retval = 0;
163
164 cnt = get_a_record(&begin, iop, *RS, NULL);
165 if (cnt == EOF) {
166 cnt = 0;
167 retval = 1;
168 } else {
169 NR += 1;
170 FNR += 1;
171 }
172 set_record(begin, cnt, 1);
173
174 return retval;
175}
176
177static int
178iop_close(iop)
179IOBUF *iop;
180{
181 int ret;
182
183 if (iop == NULL)
184 return 0;
185 errno = 0;
186
187#ifdef _CRAY
188 /* Work around bug in UNICOS popen */
189 if (iop->fd < 3)
190 ret = 0;
191 else
192#endif
193 /* save these for re-use; don't free the storage */
194 if ((iop->flag & IOP_IS_INTERNAL) != 0) {
195 iop->off = iop->buf;
196 iop->end = iop->buf + strlen(iop->buf);
197 iop->cnt = 0;
198 iop->secsiz = 0;
199 return 0;
200 }
201
202 /* Don't close standard files or else crufty code elsewhere will lose */
203 if (iop->fd == fileno(stdin) ||
204 iop->fd == fileno(stdout) ||
205 iop->fd == fileno(stderr))
206 ret = 0;
207 else
208 ret = close(iop->fd);
209 if (ret == -1)
210 warning("close of fd %d failed (%s)", iop->fd, strerror(errno));
211 if ((iop->flag & IOP_NO_FREE) == 0) {
212 /*
213 * be careful -- $0 may still reference the buffer even though
214 * an explicit close is being done; in the future, maybe we
215 * can do this a bit better
216 */
217 if (iop->buf) {
218 if ((fields_arr[0]->stptr >= iop->buf)
219 && (fields_arr[0]->stptr < iop->end)) {
220 NODE *t;
221
222 t = make_string(fields_arr[0]->stptr,
223 fields_arr[0]->stlen);
224 unref(fields_arr[0]);
225 fields_arr [0] = t;
226 reset_record ();
227 }
228 free(iop->buf);
229 }
230 free((char *)iop);
231 }
232 return ret == -1 ? 1 : 0;
233}
234
235void
236do_input()
237{
238 IOBUF *iop;
239 extern int exiting;
240
241 if (setjmp(filebuf) != 0) {
242 }
243 while ((iop = nextfile(0)) != NULL) {
244 if (inrec(iop) == 0)
245 while (interpret(expression_value) && inrec(iop) == 0)
246 ;
247 if (exiting)
248 break;
249 }
250}
251
252/* Redirection for printf and print commands */
253struct redirect *
254redirect(tree, errflg)
255NODE *tree;
256int *errflg;
257{
258 register NODE *tmp;
259 register struct redirect *rp;
260 register char *str;
261 int tflag = 0;
262 int outflag = 0;
263 char *direction = "to";
264 char *mode;
265 int fd;
266 char *what = NULL;
267
268 switch (tree->type) {
269 case Node_redirect_append:
270 tflag = RED_APPEND;
271 /* FALL THROUGH */
272 case Node_redirect_output:
273 outflag = (RED_FILE|RED_WRITE);
274 tflag |= outflag;
275 if (tree->type == Node_redirect_output)
276 what = ">";
277 else
278 what = ">>";
279 break;
280 case Node_redirect_pipe:
281 tflag = (RED_PIPE|RED_WRITE);
282 what = "|";
283 break;
284 case Node_redirect_pipein:
285 tflag = (RED_PIPE|RED_READ);
286 what = "|";
287 break;
288 case Node_redirect_input:
289 tflag = (RED_FILE|RED_READ);
290 what = "<";
291 break;
292 default:
293 fatal ("invalid tree type %d in redirect()", tree->type);
294 break;
295 }
296 tmp = tree_eval(tree->subnode);
297 if (do_lint && ! (tmp->flags & STR))
298 warning("expression in `%s' redirection only has numeric value",
299 what);
300 tmp = force_string(tmp);
301 str = tmp->stptr;
302 if (str == NULL || *str == '\0')
303 fatal("expression for `%s' redirection has null string value",
304 what);
305 if (do_lint
306 && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen)))
307 warning("filename `%s' for `%s' redirection may be result of logical expression", str, what);
308 for (rp = red_head; rp != NULL; rp = rp->next)
309 if (strlen(rp->value) == tmp->stlen
310 && STREQN(rp->value, str, tmp->stlen)
311 && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag
312 || (outflag
313 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
314 break;
315 if (rp == NULL) {
316 emalloc(rp, struct redirect *, sizeof(struct redirect),
317 "redirect");
318 emalloc(str, char *, tmp->stlen+1, "redirect");
319 memcpy(str, tmp->stptr, tmp->stlen);
320 str[tmp->stlen] = '\0';
321 rp->value = str;
322 rp->flag = tflag;
323 rp->fp = NULL;
324 rp->iop = NULL;
325 rp->pid = 0; /* unlikely that we're worried about init */
326 rp->status = 0;
327 /* maintain list in most-recently-used first order */
328 if (red_head)
329 red_head->prev = rp;
330 rp->prev = NULL;
331 rp->next = red_head;
332 red_head = rp;
333 }
334 while (rp->fp == NULL && rp->iop == NULL) {
335 if (rp->flag & RED_EOF)
336 /* encountered EOF on file or pipe -- must be cleared
337 * by explicit close() before reading more
338 */
339 return rp;
340 mode = NULL;
341 errno = 0;
342 switch (tree->type) {
343 case Node_redirect_output:
344 mode = "w";
345 if (rp->flag & RED_USED)
346 mode = "a";
347 break;
348 case Node_redirect_append:
349 mode = "a";
350 break;
351 case Node_redirect_pipe:
352 if ((rp->fp = popen(str, "w")) == NULL)
353 fatal("can't open pipe (\"%s\") for output (%s)",
354 str, strerror(errno));
355 rp->flag |= RED_NOBUF;
356 break;
357 case Node_redirect_pipein:
358 direction = "from";
359 if (gawk_popen(str, rp) == NULL)
360 fatal("can't open pipe (\"%s\") for input (%s)",
361 str, strerror(errno));
362 break;
363 case Node_redirect_input:
364 direction = "from";
365 rp->iop = iop_open(str, "r");
366 break;
367 default:
368 cant_happen();
369 }
370 if (mode != NULL) {
371 fd = devopen(str, mode);
372 if (fd > INVALID_HANDLE) {
373 if (fd == fileno(stdin))
374 rp->fp = stdin;
375 else if (fd == fileno(stdout))
376 rp->fp = stdout;
377 else if (fd == fileno(stderr))
378 rp->fp = stderr;
379 else
380 rp->fp = fdopen(fd, mode);
381 if (isatty(fd))
382 rp->flag |= RED_NOBUF;
383 }
384 }
385 if (rp->fp == NULL && rp->iop == NULL) {
386 /* too many files open -- close one and try again */
387 if (errno == EMFILE)
388 close_one();
389 else {
390 /*
391 * Some other reason for failure.
392 *
393 * On redirection of input from a file,
394 * just return an error, so e.g. getline
395 * can return -1. For output to file,
396 * complain. The shell will complain on
397 * a bad command to a pipe.
398 */
399 *errflg = errno;
400 if (tree->type == Node_redirect_output
401 || tree->type == Node_redirect_append)
402 fatal("can't redirect %s `%s' (%s)",
403 direction, str, strerror(errno));
404 else {
405 free_temp(tmp);
406 return NULL;
407 }
408 }
409 }
410 }
411 free_temp(tmp);
412 return rp;
413}
414
415static void
416close_one()
417{
418 register struct redirect *rp;
419 register struct redirect *rplast = NULL;
420
421 /* go to end of list first, to pick up least recently used entry */
422 for (rp = red_head; rp != NULL; rp = rp->next)
423 rplast = rp;
424 /* now work back up through the list */
425 for (rp = rplast; rp != NULL; rp = rp->prev)
426 if (rp->fp && (rp->flag & RED_FILE)) {
427 rp->flag |= RED_USED;
428 errno = 0;
429 if (fclose(rp->fp))
430 warning("close of \"%s\" failed (%s).",
431 rp->value, strerror(errno));
432 rp->fp = NULL;
433 break;
434 }
435 if (rp == NULL)
436 /* surely this is the only reason ??? */
437 fatal("too many pipes or input files open");
438}
439
440NODE *
441do_close(tree)
442NODE *tree;
443{
444 NODE *tmp;
445 register struct redirect *rp;
446
447 tmp = force_string(tree_eval(tree->subnode));
448 for (rp = red_head; rp != NULL; rp = rp->next) {
449 if (strlen(rp->value) == tmp->stlen
450 && STREQN(rp->value, tmp->stptr, tmp->stlen))
451 break;
452 }
453 free_temp(tmp);
454 if (rp == NULL) /* no match */
455 return tmp_number((AWKNUM) 0.0);
456 fflush(stdout); /* synchronize regular output */
457 tmp = tmp_number((AWKNUM)close_redir(rp));
458 rp = NULL;
459 return tmp;
460}
461
462static int
463close_redir(rp)
464register struct redirect *rp;
465{
466 int status = 0;
467
468 if (rp == NULL)
469 return 0;
470 if (rp->fp == stdout || rp->fp == stderr)
471 return 0;
472 errno = 0;
473 if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
474 status = pclose(rp->fp);
475 else if (rp->fp)
476 status = fclose(rp->fp);
477 else if (rp->iop) {
478 if (rp->flag & RED_PIPE)
479 status = gawk_pclose(rp);
480 else {
481 status = iop_close(rp->iop);
482 rp->iop = NULL;
483 }
484 }
485 /* SVR4 awk checks and warns about status of close */
486 if (status) {
487 char *s = strerror(errno);
488
489 warning("failure status (%d) on %s close of \"%s\" (%s).",
490 status,
491 (rp->flag & RED_PIPE) ? "pipe" :
492 "file", rp->value, s);
493
494 if (! do_unix) {
495 /* set ERRNO too so that program can get at it */
496 unref(ERRNO_node->var_value);
497 ERRNO_node->var_value = make_string(s, strlen(s));
498 }
499 }
500 if (rp->next)
501 rp->next->prev = rp->prev;
502 if (rp->prev)
503 rp->prev->next = rp->next;
504 else
505 red_head = rp->next;
506 free(rp->value);
507 free((char *)rp);
508 return status;
509}
510
511int
512flush_io ()
513{
514 register struct redirect *rp;
515 int status = 0;
516
517 errno = 0;
518 if (fflush(stdout)) {
519 warning("error writing standard output (%s).", strerror(errno));
520 status++;
521 }
522 if (fflush(stderr)) {
523 warning("error writing standard error (%s).", strerror(errno));
524 status++;
525 }
526 for (rp = red_head; rp != NULL; rp = rp->next)
527 /* flush both files and pipes, what the heck */
528 if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
529 if (fflush(rp->fp)) {
530 warning("%s flush of \"%s\" failed (%s).",
531 (rp->flag & RED_PIPE) ? "pipe" :
532 "file", rp->value, strerror(errno));
533 status++;
534 }
535 }
536 return status;
537}
538
539int
540close_io ()
541{
542 register struct redirect *rp;
543 register struct redirect *next;
544 int status = 0;
545
546 errno = 0;
547 if (fclose(stdout)) {
548 warning("error writing standard output (%s).", strerror(errno));
549 status++;
550 }
551 if (fclose(stderr)) {
552 warning("error writing standard error (%s).", strerror(errno));
553 status++;
554 }
555 for (rp = red_head; rp != NULL; rp = next) {
556 next = rp->next;
557 if (close_redir(rp))
558 status++;
559 rp = NULL;
560 }
561 return status;
562}
563
564/* str2mode --- convert a string mode to an integer mode */
565
566static int
567str2mode(mode)
568char *mode;
569{
570 int ret;
571
572 switch(mode[0]) {
573 case 'r':
574 ret = O_RDONLY;
575 break;
576
577 case 'w':
578 ret = O_WRONLY|O_CREAT|O_TRUNC;
579 break;
580
581 case 'a':
582 ret = O_WRONLY|O_APPEND|O_CREAT;
583 break;
584 default:
585 cant_happen();
586 }
587 return ret;
588}
589
590/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
591
592/*
593 * This separate version is still needed for output, since file and pipe
594 * output is done with stdio. iop_open() handles input with IOBUFs of
595 * more "special" files. Those files are not handled here since it makes
596 * no sense to use them for output.
597 */
598
599int
600devopen(name, mode)
601char *name, *mode;
602{
603 int openfd = INVALID_HANDLE;
604 char *cp, *ptr;
605 int flag = 0;
606 struct stat buf;
607 extern double strtod();
608
609 flag = str2mode(mode);
610
611 if (do_unix)
612 goto strictopen;
613
614#ifdef VMS
615 if ((openfd = vms_devopen(name, flag)) >= 0)
616 return openfd;
617#endif /* VMS */
618
619 if (STREQ(name, "-"))
620 openfd = fileno(stdin);
621 else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
622 cp = name + 5;
623
624 if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY)
625 openfd = fileno(stdin);
626 else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY)
627 openfd = fileno(stdout);
628 else if (STREQ(cp, "stderr") && (flag & O_WRONLY) == O_WRONLY)
629 openfd = fileno(stderr);
630 else if (STREQN(cp, "fd/", 3)) {
631 cp += 3;
632 openfd = (int)strtod(cp, &ptr);
633 if (openfd <= INVALID_HANDLE || ptr == cp)
634 openfd = INVALID_HANDLE;
635 }
636 }
637
638strictopen:
639 if (openfd == INVALID_HANDLE)
640 openfd = open(name, flag, 0666);
641 if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
642 if (S_ISDIR(buf.st_mode))
643 fatal("file `%s' is a directory", name);
644 return openfd;
645}
646
647
648/* spec_setup --- setup an IOBUF for a special internal file */
649
650void
651spec_setup(iop, len, allocate)
652IOBUF *iop;
653int len;
654int allocate;
655{
656 char *cp;
657
658 if (allocate) {
659 emalloc(cp, char *, len+2, "spec_setup");
660 iop->buf = cp;
661 } else {
662 len = strlen(iop->buf);
663 iop->buf[len++] = '\n'; /* get_a_record clobbered it */
664 iop->buf[len] = '\0'; /* just in case */
665 }
666 iop->off = iop->buf;
667 iop->cnt = 0;
668 iop->secsiz = 0;
669 iop->size = len;
670 iop->end = iop->buf + len;
671 iop->fd = -1;
672 iop->flag = IOP_IS_INTERNAL;
673}
674
675/* specfdopen --- open a fd special file */
676
677int
678specfdopen(iop, name, mode)
679IOBUF *iop;
680char *name, *mode;
681{
682 int fd;
683 IOBUF *tp;
684
685 fd = devopen(name, mode);
686 if (fd == INVALID_HANDLE)
687 return INVALID_HANDLE;
688 tp = iop_alloc(fd);
689 if (tp == NULL)
690 return INVALID_HANDLE;
691 *iop = *tp;
692 iop->flag |= IOP_NO_FREE;
693 free(tp);
694 return 0;
695}
696
697/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
698
699int
700pidopen(iop, name, mode)
701IOBUF *iop;
702char *name, *mode;
703{
704 char tbuf[BUFSIZ];
705 int i;
706
707 if (name[6] == 'g')
708/* following #if will improve in 2.16 */
709#if defined(__svr4__) || defined(i860) || defined(_AIX) || defined(BSD4_4) || defined(__386BSD__)
710 sprintf(tbuf, "%d\n", getpgrp());
711#else
712 sprintf(tbuf, "%d\n", getpgrp(getpid()));
713#endif
714 else if (name[6] == 'i')
715 sprintf(tbuf, "%d\n", getpid());
716 else
717 sprintf(tbuf, "%d\n", getppid());
718 i = strlen(tbuf);
719 spec_setup(iop, i, 1);
720 strcpy(iop->buf, tbuf);
721 return 0;
722}
723
724/* useropen --- "open" /dev/user */
725
726/*
727 * /dev/user creates a record as follows:
728 * $1 = getuid()
729 * $2 = geteuid()
730 * $3 = getgid()
731 * $4 = getegid()
732 * If multiple groups are supported, the $5 through $NF are the
733 * supplementary group set.
734 */
735
736int
737useropen(iop, name, mode)
738IOBUF *iop;
739char *name, *mode;
740{
741 char tbuf[BUFSIZ], *cp;
742 int i;
743#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
744 int groupset[NGROUPS_MAX];
745 int ngroups;
746#endif
747
748 sprintf(tbuf, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
749
750 cp = tbuf + strlen(tbuf);
751#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
752 ngroups = getgroups(NGROUPS_MAX, groupset);
753 if (ngroups == -1)
754 fatal("could not find groups: %s", strerror(errno));
755
756 for (i = 0; i < ngroups; i++) {
757 *cp++ = ' ';
758 sprintf(cp, "%d", groupset[i]);
759 cp += strlen(cp);
760 }
761#endif
762 *cp++ = '\n';
763 *cp++ = '\0';
764
765
766 i = strlen(tbuf);
767 spec_setup(iop, i, 1);
768 strcpy(iop->buf, tbuf);
769 return 0;
770}
771
772/* iop_open --- handle special and regular files for input */
773
774static IOBUF *
775iop_open(name, mode)
776char *name, *mode;
777{
778 int openfd = INVALID_HANDLE;
779 char *cp, *ptr;
780 int flag = 0;
781 int i;
782 struct stat buf;
783 IOBUF *iop;
784 static struct internal {
785 char *name;
786 int compare;
787 int (*fp)();
788 IOBUF iob;
789 } table[] = {
790 { "/dev/fd/", 8, specfdopen },
791 { "/dev/stdin", 10, specfdopen },
792 { "/dev/stdout", 11, specfdopen },
793 { "/dev/stderr", 11, specfdopen },
794 { "/dev/pid", 8, pidopen },
795 { "/dev/ppid", 9, pidopen },
796 { "/dev/pgrpid", 11, pidopen },
797 { "/dev/user", 9, useropen },
798 };
799 int devcount = sizeof(table) / sizeof(table[0]);
800
801 flag = str2mode(mode);
802
803 if (do_unix)
804 goto strictopen;
805
806 if (STREQ(name, "-"))
807 openfd = fileno(stdin);
808 else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
809 int i;
810
811 for (i = 0; i < devcount; i++) {
812 if (STREQN(name, table[i].name, table[i].compare)) {
813 IOBUF *iop = & table[i].iob;
814
815 if (iop->buf != NULL) {
816 spec_setup(iop, 0, 0);
817 return iop;
818 } else if ((*table[i].fp)(iop, name, mode) == 0)
819 return iop;
820 else {
821 warning("could not open %s, mode `%s'",
822 name, mode);
823 return NULL;
824 }
825 }
826 }
827 }
828
829strictopen:
830 if (openfd == INVALID_HANDLE)
831 openfd = open(name, flag, 0666);
832 if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
833 if ((buf.st_mode & S_IFMT) == S_IFDIR)
834 fatal("file `%s' is a directory", name);
835 iop = iop_alloc(openfd);
836 return iop;
837}
838
839#ifndef PIPES_SIMULATED
840 /* real pipes */
841static int
842wait_any(interesting)
843int interesting; /* pid of interest, if any */
844{
845 SIGTYPE (*hstat)(), (*istat)(), (*qstat)();
846 int pid;
847 int status = 0;
848 struct redirect *redp;
849 extern int errno;
850
851 hstat = signal(SIGHUP, SIG_IGN);
852 istat = signal(SIGINT, SIG_IGN);
853 qstat = signal(SIGQUIT, SIG_IGN);
854 for (;;) {
855#ifdef NeXT
856 pid = wait((union wait *)&status);
857#else
858 pid = wait(&status);
859#endif /* NeXT */
860 if (interesting && pid == interesting) {
861 break;
862 } else if (pid != -1) {
863 for (redp = red_head; redp != NULL; redp = redp->next)
864 if (pid == redp->pid) {
865 redp->pid = -1;
866 redp->status = status;
867 if (redp->fp) {
868 pclose(redp->fp);
869 redp->fp = 0;
870 }
871 if (redp->iop) {
872 (void) iop_close(redp->iop);
873 redp->iop = 0;
874 }
875 break;
876 }
877 }
878 if (pid == -1 && errno == ECHILD)
879 break;
880 }
881 signal(SIGHUP, hstat);
882 signal(SIGINT, istat);
883 signal(SIGQUIT, qstat);
884 return(status);
885}
886
887static IOBUF *
888gawk_popen(cmd, rp)
889char *cmd;
890struct redirect *rp;
891{
892 int p[2];
893 register int pid;
894
895 /* used to wait for any children to synchronize input and output,
896 * but this could cause gawk to hang when it is started in a pipeline
897 * and thus has a child process feeding it input (shell dependant)
898 */
899 /*(void) wait_any(0);*/ /* wait for outstanding processes */
900
901 if (pipe(p) < 0)
902 fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
903 if ((pid = fork()) == 0) {
904 if (close(1) == -1)
905 fatal("close of stdout in child failed (%s)",
906 strerror(errno));
907 if (dup(p[1]) != 1)
908 fatal("dup of pipe failed (%s)", strerror(errno));
909 if (close(p[0]) == -1 || close(p[1]) == -1)
910 fatal("close of pipe failed (%s)", strerror(errno));
911 if (close(0) == -1)
912 fatal("close of stdin in child failed (%s)",
913 strerror(errno));
914 execl("/bin/sh", "sh", "-c", cmd, 0);
915 _exit(127);
916 }
917 if (pid == -1)
918 fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
919 rp->pid = pid;
920 if (close(p[1]) == -1)
921 fatal("close of pipe failed (%s)", strerror(errno));
922 return (rp->iop = iop_alloc(p[0]));
923}
924
925static int
926gawk_pclose(rp)
927struct redirect *rp;
928{
929 (void) iop_close(rp->iop);
930 rp->iop = NULL;
931
932 /* process previously found, return stored status */
933 if (rp->pid == -1)
934 return (rp->status >> 8) & 0xFF;
935 rp->status = wait_any(rp->pid);
936 rp->pid = -1;
937 return (rp->status >> 8) & 0xFF;
938}
939
940#else /* PIPES_SIMULATED */
941 /* use temporary file rather than pipe */
942
943#ifdef VMS
944static IOBUF *
945gawk_popen(cmd, rp)
946char *cmd;
947struct redirect *rp;
948{
949 FILE *current;
950
951 if ((current = popen(cmd, "r")) == NULL)
952 return NULL;
953 return (rp->iop = iop_alloc(fileno(current)));
954}
955
956static int
957gawk_pclose(rp)
958struct redirect *rp;
959{
960 int rval, aval, fd = rp->iop->fd;
961 FILE *kludge = fdopen(fd, "r"); /* pclose needs FILE* w/ right fileno */
962
963 rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */
964 rval = iop_close(rp->iop);
965 rp->iop = NULL;
966 aval = pclose(kludge);
967 return (rval < 0 ? rval : aval);
968}
969#else /* VMS */
970
971static
972struct {
973 char *command;
974 char *name;
975} pipes[_NFILE];
976
977static IOBUF *
978gawk_popen(cmd, rp)
979char *cmd;
980struct redirect *rp;
981{
982 extern char *strdup(const char *);
983 int current;
984 char *name;
985 static char cmdbuf[256];
986
987 /* get a name to use. */
988 if ((name = tempnam(".", "pip")) == NULL)
989 return NULL;
990 sprintf(cmdbuf,"%s > %s", cmd, name);
991 system(cmdbuf);
992 if ((current = open(name,O_RDONLY)) == INVALID_HANDLE)
993 return NULL;
994 pipes[current].name = name;
995 pipes[current].command = strdup(cmd);
996 rp->iop = iop_alloc(current);
997 return (rp->iop = iop_alloc(current));
998}
999
1000static int
1001gawk_pclose(rp)
1002struct redirect *rp;
1003{
1004 int cur = rp->iop->fd;
1005 int rval;
1006
1007 rval = iop_close(rp->iop);
1008 rp->iop = NULL;
1009
1010 /* check for an open file */
1011 if (pipes[cur].name == NULL)
1012 return -1;
1013 unlink(pipes[cur].name);
1014 free(pipes[cur].name);
1015 pipes[cur].name = NULL;
1016 free(pipes[cur].command);
1017 return rval;
1018}
1019#endif /* VMS */
1020
1021#endif /* PIPES_SIMULATED */
1022
1023NODE *
1024do_getline(tree)
1025NODE *tree;
1026{
1027 struct redirect *rp = NULL;
1028 IOBUF *iop;
1029 int cnt = EOF;
1030 char *s = NULL;
1031 int errcode;
1032
1033 while (cnt == EOF) {
1034 if (tree->rnode == NULL) { /* no redirection */
1035 iop = nextfile(0);
1036 if (iop == NULL) /* end of input */
1037 return tmp_number((AWKNUM) 0.0);
1038 } else {
1039 int redir_error = 0;
1040
1041 rp = redirect(tree->rnode, &redir_error);
1042 if (rp == NULL && redir_error) { /* failed redirect */
1043 if (! do_unix) {
1044 char *s = strerror(redir_error);
1045
1046 unref(ERRNO_node->var_value);
1047 ERRNO_node->var_value =
1048 make_string(s, strlen(s));
1049 }
1050 return tmp_number((AWKNUM) -1.0);
1051 }
1052 iop = rp->iop;
1053 if (iop == NULL) /* end of input */
1054 return tmp_number((AWKNUM) 0.0);
1055 }
1056 errcode = 0;
1057 cnt = get_a_record(&s, iop, *RS, & errcode);
1058 if (! do_unix && errcode != 0) {
1059 char *s = strerror(errcode);
1060
1061 unref(ERRNO_node->var_value);
1062 ERRNO_node->var_value = make_string(s, strlen(s));
1063 return tmp_number((AWKNUM) -1.0);
1064 }
1065 if (cnt == EOF) {
1066 if (rp) {
1067 /*
1068 * Don't do iop_close() here if we are
1069 * reading from a pipe; otherwise
1070 * gawk_pclose will not be called.
1071 */
1072 if (!(rp->flag & RED_PIPE)) {
1073 (void) iop_close(iop);
1074 rp->iop = NULL;
1075 }
1076 rp->flag |= RED_EOF; /* sticky EOF */
1077 return tmp_number((AWKNUM) 0.0);
1078 } else
1079 continue; /* try another file */
1080 }
1081 if (!rp) {
1082 NR += 1;
1083 FNR += 1;
1084 }
1085 if (tree->lnode == NULL) /* no optional var. */
1086 set_record(s, cnt, 1);
1087 else { /* assignment to variable */
1088 Func_ptr after_assign = NULL;
1089 NODE **lhs;
1090
1091 lhs = get_lhs(tree->lnode, &after_assign);
1092 unref(*lhs);
1093 *lhs = make_string(s, strlen(s));
1094 (*lhs)->flags |= MAYBE_NUM;
1095 /* we may have to regenerate $0 here! */
1096 if (after_assign)
1097 (*after_assign)();
1098 }
1099 }
1100 return tmp_number((AWKNUM) 1.0);
1101}
1102
1103int
1104pathopen (file)
1105char *file;
1106{
1107 int fd = do_pathopen(file);
1108
1109#ifdef DEFAULT_FILETYPE
1110 if (! do_unix && fd <= INVALID_HANDLE) {
1111 char *file_awk;
1112 int save = errno;
1113#ifdef VMS
1114 int vms_save = vaxc$errno;
1115#endif
1116
1117 /* append ".awk" and try again */
1118 emalloc(file_awk, char *, strlen(file) +
1119 sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
1120 sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE);
1121 fd = do_pathopen(file_awk);
1122 free(file_awk);
1123 if (fd <= INVALID_HANDLE) {
1124 errno = save;
1125#ifdef VMS
1126 vaxc$errno = vms_save;
1127#endif
1128 }
1129 }
1130#endif /*DEFAULT_FILETYPE*/
1131
1132 return fd;
1133}
1134
1135static int
1136do_pathopen (file)
1137char *file;
1138{
1139 static char *savepath = DEFPATH; /* defined in config.h */
1140 static int first = 1;
1141 char *awkpath, *cp;
1142 char trypath[BUFSIZ];
1143 int fd;
1144
1145 if (STREQ(file, "-"))
1146 return (0);
1147
1148 if (do_unix)
1149 return (devopen(file, "r"));
1150
1151 if (first) {
1152 first = 0;
1153 if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath)
1154 savepath = awkpath; /* used for restarting */
1155 }
1156 awkpath = savepath;
1157
1158 /* some kind of path name, no search */
1159#ifdef VMS /* (strchr not equal implies either or both not NULL) */
1160 if (strchr(file, ':') != strchr(file, ']')
1161 || strchr(file, '>') != strchr(file, '/'))
1162#else /*!VMS*/
1163#ifdef MSDOS
1164 if (strchr(file, '/') != strchr(file, '\\')
1165 || strchr(file, ':') != NULL)
1166#else
1167 if (strchr(file, '/') != NULL)
1168#endif /*MSDOS*/
1169#endif /*VMS*/
1170 return (devopen(file, "r"));
1171
1172 do {
1173 trypath[0] = '\0';
1174 /* this should take into account limits on size of trypath */
1175 for (cp = trypath; *awkpath && *awkpath != ENVSEP; )
1176 *cp++ = *awkpath++;
1177
1178 if (cp != trypath) { /* nun-null element in path */
1179 /* add directory punctuation only if needed */
1180#ifdef VMS
1181 if (strchr(":]>/", *(cp-1)) == NULL)
1182#else
1183#ifdef MSDOS
1184 if (strchr(":\\/", *(cp-1)) == NULL)
1185#else
1186 if (*(cp-1) != '/')
1187#endif
1188#endif
1189 *cp++ = '/';
1190 /* append filename */
1191 strcpy (cp, file);
1192 } else
1193 strcpy (trypath, file);
1194 if ((fd = devopen(trypath, "r")) >= 0)
1195 return (fd);
1196
1197 /* no luck, keep going */
1198 if(*awkpath == ENVSEP && awkpath[1] != '\0')
1199 awkpath++; /* skip colon */
1200 } while (*awkpath);
1201 /*
1202 * You might have one of the awk
1203 * paths defined, WITHOUT the current working directory in it.
1204 * Therefore try to open the file in the current directory.
1205 */
1206 return (devopen(file, "r"));
1207}