OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / user / mawk / files.c
1
2 /********************************************
3 files.c
4 copyright 1991-94.  Michael D. Brennan
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13 /*$Log: files.c,v $
14  * Revision 1.9  1996/01/14  17:14:10  mike
15  * flush_all_output()
16  *
17  * Revision 1.8  1995/06/06  00:18:27  mike
18  * change mawk_exit(1) to mawk_exit(2)
19  *
20  * Revision 1.7  1994/12/11  20:48:50  mike
21  * fflush builtin
22  *
23  * Revision 1.6  1994/10/08  19:15:40  mike
24  * remove SM_DOS
25  *
26  * Revision 1.5  1994/04/17  20:01:37  mike
27  * recognize filename "/dev/stdout"
28  *
29  * Revision 1.4  1994/02/21  00:11:07  mike
30  * code cleanup
31  *
32  * Revision 1.3  1993/07/16  01:00:36  mike
33  * cleanup and indent
34  *
35  * Revision 5.5  1992/12/17  02:48:01  mike
36  * 1.1.2d changes for DOS
37  *
38  * Revision 5.4  1992/07/10  16:10:30  brennan
39  * patch2
40  * MsDOS: remove useless NO_BINMODE macro
41  * get process exit code on in pipes
42  *
43  * Revision 5.3  1992/04/07  20:21:17  brennan
44  * patch 2
45  * unbuffered output to a tty
46  *
47  * Revision 5.2  1992/04/07  16:03:08  brennan
48  * patch 2
49  * allow same filename for output and input, but use different descriptors
50  * E.g. < "/dev/tty" and > "/dev/tty"
51  *
52  * Revision 5.1  91/12/05  07:56:00  brennan
53  * 1.1 pre-release
54  *
55 */
56
57 /* files.c */
58
59 #include "mawk.h"
60 #include "files.h"
61 #include "memory.h"
62 #include "fin.h"
63
64 static FILE *PROTO(tfopen, (char *, char *)) ;
65 static void PROTO(efflush, (FILE*)) ;
66 static void PROTO(add_to_child_list, (int, int)) ;
67 static struct child *PROTO(remove_from_child_list, (int)) ;
68 extern int PROTO(isatty, (int)) ;
69
70 #ifdef  V7
71 #include  <sgtty.h>             /* defines FIOCLEX */
72 #endif
73
74
75 #ifndef  NO_FCNTL_H
76
77 #include <fcntl.h>
78 #define  CLOSE_ON_EXEC(fd)    fcntl(fd, F_SETFD, 1)
79
80 #else
81 #define  CLOSE_ON_EXEC(fd) ioctl(fd, FIOCLEX, (PTR) 0)
82 #endif
83
84
85 /* We store dynamically created files on a linked linear
86    list with move to the front (big surprise)  */
87
88 typedef struct file
89 {
90    struct file *link ;
91    STRING *name ;
92    short type ;
93    int pid ;                     /* we need to wait() when we close a pipe */
94    /* holds temp file index under MSDOS */
95
96 #if  HAVE_FAKE_PIPES
97    int inpipe_exit ;
98 #endif
99
100    PTR ptr ;                     /* FIN*   or  FILE*   */
101 }
102 FILE_NODE ;
103
104 static FILE_NODE *file_list ;
105
106
107 /* find a file on file_list */
108 PTR
109 file_find(sval, type)
110    STRING *sval ;
111    int type ;
112 {
113    register FILE_NODE *p = file_list ;
114    FILE_NODE *q = (FILE_NODE *) 0 ;
115    char *name = sval->str ;
116    char *ostr ;
117
118    while (1)
119    {
120       if (!p)
121       {
122          /* open a new one */
123          p = ZMALLOC(FILE_NODE) ;
124
125          switch (p->type = type)
126          {
127             case F_TRUNC:
128 #if MSDOS
129                ostr = (binmode() & 2) ? "wb" : "w" ;
130 #else
131                ostr = "w" ;
132 #endif
133                if (!(p->ptr = (PTR) tfopen(name, ostr)))
134                   goto out_failure ;
135                break ;
136
137             case F_APPEND:
138 #if MSDOS
139                ostr = (binmode() & 2) ? "ab" : "a" ;
140 #else
141                ostr = "a" ;
142 #endif
143                if (!(p->ptr = (PTR) tfopen(name, ostr)))
144                   goto out_failure ;
145                break ;
146
147             case F_IN:
148                if (!(p->ptr = (PTR) FINopen(name, 0)))
149                {
150                   zfree(p, sizeof(FILE_NODE)) ;
151                   return (PTR) 0 ;
152                }
153                break ;
154
155             case PIPE_OUT:
156             case PIPE_IN:
157
158 #if    HAVE_REAL_PIPES || HAVE_FAKE_PIPES
159
160                if (!(p->ptr = get_pipe(name, type, &p->pid)))
161                {
162                   if (type == PIPE_OUT)  goto out_failure ;
163                   else
164                   {
165                      zfree(p, sizeof(FILE_NODE)) ;
166                      return (PTR) 0 ;
167                   }
168                }
169 #else
170                rt_error("pipes not supported") ;
171 #endif
172                break ;
173
174 #ifdef  DEBUG
175             default:
176                bozo("bad file type") ;
177 #endif
178          }
179          /* successful open */
180          p->name = sval ;
181          sval->ref_cnt++ ;
182          break ;                 /* while loop */
183       }
184
185       /* search is by name and type */
186       if (strcmp(name, p->name->str) == 0 &&
187           (p->type == type ||
188       /* no distinction between F_APPEND and F_TRUNC here */
189            p->type >= F_APPEND && type >= F_APPEND))
190
191       {
192          /* found */
193          if (!q)                /*at front of list */
194             return p->ptr ;
195          /* delete from list for move to front */
196          q->link = p->link ;
197          break ;                 /* while loop */
198       }
199
200       q = p ; p = p->link ;
201    }                            /* end while loop */
202
203    /* put p at the front of the list */
204    p->link = file_list ;
205    return (PTR) (file_list = p)->ptr ;
206
207 out_failure:
208    errmsg(errno, "cannot open \"%s\" for output", name) ;
209    mawk_exit(2) ;
210
211 }
212
213
214 /* Close a file and delete it's node from the file_list.
215    Walk the whole list, in case a name has two nodes,
216    e.g. < "/dev/tty" and > "/dev/tty"
217 */
218
219 int
220 file_close(sval)
221    STRING *sval ;
222 {
223    FILE_NODE dummy ;
224    register FILE_NODE *p ;
225    FILE_NODE *q = &dummy ;       /* trails p */
226    FILE_NODE *hold ;
227    char *name = sval->str ;
228    int retval = -1 ;
229
230    dummy.link = p = file_list ;
231    while (p)
232    {
233       if (strcmp(name, p->name->str) == 0)
234       {
235          /* found */
236          switch (p->type)
237          {
238             case F_TRUNC:
239             case F_APPEND:
240                fclose((FILE *) p->ptr) ;
241                retval = 0 ;
242                break ;
243
244             case PIPE_OUT:
245                fclose((FILE *) p->ptr) ;
246
247 #if  HAVE_REAL_PIPES
248                retval = wait_for(p->pid) ;
249 #endif
250 #if  HAVE_FAKE_PIPES
251                retval = close_fake_outpipe(p->name->str, p->pid) ;
252 #endif
253                break ;
254
255             case F_IN:
256                FINclose((FIN *) p->ptr) ;
257                retval = 0 ;
258                break ;
259
260             case PIPE_IN:
261                FINclose((FIN *) p->ptr) ;
262
263 #if  HAVE_REAL_PIPES
264                retval = wait_for(p->pid) ;
265 #endif
266 #if  HAVE_FAKE_PIPES
267                {
268                   char xbuff[100] ;
269                   unlink(tmp_file_name(p->pid, xbuff)) ;
270                   retval = p->inpipe_exit ;
271                }
272 #endif
273                break ;
274          }
275
276          free_STRING(p->name) ;
277          hold = p ;
278          q->link = p = p->link ;
279          ZFREE(hold) ;
280       }
281       else
282       {
283          q = p ; p = p->link ; 
284       }
285    }
286
287    file_list = dummy.link ;
288    return retval ;
289 }
290
291 /*
292 find an output file with name == sval and fflush it
293 */
294
295 int
296 file_flush(sval)
297    STRING *sval ;
298 {
299    int ret = -1 ;
300    register FILE_NODE *p = file_list ;
301    unsigned len = sval->len ;
302    char *str = sval->str ;
303
304    if (len==0) 
305    {
306       /* for consistency with gawk */
307       flush_all_output() ;
308       return 0 ;
309    }
310       
311    while( p )
312    {
313       if ( IS_OUTPUT(p->type) &&
314            len == p->name->len &&
315            strcmp(str,p->name->str) == 0 )
316       {
317          ret = 0 ;
318          efflush((FILE*)p->ptr) ;
319          /* it's possible for a command and a file to have the same
320             name -- so keep looking */
321       }
322       p = p->link ;
323    }
324    return ret ;
325 }
326
327 void
328 flush_all_output() 
329 {
330    FILE_NODE *p ;
331
332    for(p=file_list; p ; p = p->link)
333       if (IS_OUTPUT(p->type)) efflush((FILE*)p->ptr) ;
334 }
335
336 static void
337 efflush(fp)
338    FILE *fp ;
339 {
340    if (fflush(fp) < 0)
341    {
342       errmsg(errno, "unexpected write error") ;
343       mawk_exit(2) ;
344    }
345 }
346
347
348 /* When we exit, we need to close and wait for all output pipes */
349
350 #if   HAVE_REAL_PIPES
351
352 /* work around for bug in AIX 4.1 -- If there are exactly 16 or 
353    32 or 48 ..., open files then the last one doesn't get flushed on
354    exit.  So the following is now a misnomer as we'll really close
355    all output.
356 */
357
358 void
359 close_out_pipes()
360 {
361    register FILE_NODE *p = file_list ;
362
363    while (p)
364    {
365       if (IS_OUTPUT(p->type))
366       {
367          fclose((FILE *) p->ptr) ;   
368          if (p->type == PIPE_OUT) wait_for(p->pid) ; 
369       }
370
371       p = p->link ;
372    }
373 }
374
375 #else
376 #if  HAVE_FAKE_PIPES            /* pipes are faked with temp files */
377
378 void
379 close_fake_pipes()
380 {
381    register FILE_NODE *p = file_list ;
382    char xbuff[100] ;
383
384    /* close input pipes first to free descriptors for children */
385    while (p)
386    {
387       if (p->type == PIPE_IN)
388       {
389          FINclose((FIN *) p->ptr) ;
390          unlink(tmp_file_name(p->pid, xbuff)) ;
391       }
392       p = p->link ;
393    }
394    /* doit again */
395    p = file_list ;
396    while (p)
397    {
398       if (p->type == PIPE_OUT)
399       {
400          fclose(p->ptr) ;
401          close_fake_outpipe(p->name->str, p->pid) ;
402       }
403       p = p->link ;
404    }
405 }
406 #endif /* HAVE_FAKE_PIPES */
407 #endif /* ! HAVE_REAL_PIPES */
408
409 /* hardwire to /bin/sh for portability of programs */
410 char *shell = "/bin/sh" ;
411
412 #if  HAVE_REAL_PIPES
413
414 PTR
415 get_pipe(name, type, pid_ptr)
416    char *name ;
417    int type ;
418    int *pid_ptr ;
419 {
420    int the_pipe[2], local_fd, remote_fd ;
421
422    if (pipe(the_pipe) == -1)  return (PTR) 0 ;
423    local_fd = the_pipe[type == PIPE_OUT] ;
424    remote_fd = the_pipe[type == PIPE_IN] ;
425    /* to keep output ordered correctly */
426    fflush(stdout) ; fflush(stderr) ;
427
428    switch (*pid_ptr = vfork())
429    {
430       case -1:
431          close(local_fd) ;
432          close(remote_fd) ;
433          return (PTR) 0 ;
434
435       case 0:
436          close(local_fd) ;
437          close(type == PIPE_IN) ;
438          dup(remote_fd) ;
439          close(remote_fd) ;
440          execl(shell, shell, "-c", name, (char *) 0) ;
441 #ifndef EMBED
442          errmsg(errno, "failed to exec %s -c %s", shell, name) ;
443          fflush(stderr) ;
444 #endif
445          _exit(128) ;
446
447       default:
448          close(remote_fd) ;
449          /* we could deadlock if future child inherit the local fd ,
450            set close on exec flag */
451          CLOSE_ON_EXEC(local_fd) ;
452          break ;
453    }
454
455    return type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) :
456       (PTR) fdopen(local_fd, "w") ;
457 }
458
459
460
461 /*------------ children ------------------*/
462
463 /* we need to wait for children at the end of output pipes to
464    complete so we know any files they have created are complete */
465
466 /* dead children are kept on this list */
467
468 static struct child
469 {
470    int pid ;
471    int exit_status ;
472    struct child *link ;
473 } *child_list ;
474
475 static void
476 add_to_child_list(pid, exit_status)
477    int pid, exit_status ;
478 {
479    register struct child *p = ZMALLOC(struct child) ;
480
481    p->pid = pid ; p->exit_status = exit_status ;
482    p->link = child_list ; child_list = p ;
483 }
484
485 static struct child *
486 remove_from_child_list(pid)
487    int pid ;
488 {
489    struct child dummy ;
490    register struct child *p ;
491    struct child *q = &dummy ;
492
493    dummy.link = p = child_list ;
494    while (p)
495    {
496       if (p->pid == pid)
497       {
498          q->link = p->link ;
499          break ;
500       }
501       else
502       {
503          q = p ; p = p->link ; 
504       }
505    }
506
507    child_list = dummy.link ;
508    return p ;   
509    /* null return if not in the list */
510 }
511
512
513 /* wait for a specific child to complete and return its
514    exit status
515
516    If pid is zero, wait for any single child and
517    put it on the dead children list
518 */
519
520 int
521 wait_for(pid)
522    int pid ;
523 {
524    int exit_status ;
525    struct child *p ;
526    int id ;
527
528    if (pid == 0)
529    {
530       id = wait(&exit_status) ;
531       add_to_child_list(id, exit_status) ;
532    }
533    /* see if an earlier wait() caught our child */
534    else if (p = remove_from_child_list(pid))
535    {
536       exit_status = p->exit_status ;
537       ZFREE(p) ;
538    }
539    else
540    {
541       /* need to really wait */
542       while ((id = wait(&exit_status)) != pid)
543       {
544          if (id == -1)          /* can't happen */
545             bozo("wait_for") ;
546          else
547          {
548             /* we got the exit status of another child
549             put it on the child list and try again */
550             add_to_child_list(id, exit_status) ;
551          }
552       }
553    }
554
555    if (exit_status & 0xff)  exit_status = 128 + (exit_status & 0xff) ;
556    else  exit_status = (exit_status & 0xff00) >> 8 ;
557
558    return exit_status ;
559 }
560
561 #endif /* HAVE_REAL_PIPES */
562
563
564 void
565 set_stderr()   /* and stdout */
566 {
567    FILE_NODE *p, *q ; 
568    
569    p = ZMALLOC(FILE_NODE) ;
570    p->link = (FILE_NODE*) 0 ;
571    p->type = F_TRUNC ;
572    p->name = new_STRING("/dev/stdout") ;
573    p->ptr = (PTR) stdout ;
574    q = ZMALLOC(FILE_NODE);
575    q->link = p ;
576    q->type = F_TRUNC ;
577    q->name = new_STRING("/dev/stderr") ;
578    q->ptr = (PTR) stderr ;
579    file_list = q ;
580 }
581
582 /* fopen() but no buffering to ttys */
583 static FILE *
584 tfopen(name, mode)
585    char *name, *mode ;
586 {
587    FILE *retval = fopen(name, mode) ;
588
589    if (retval)
590    {
591       if (isatty(fileno(retval)))  setbuf(retval, (char *) 0) ;
592       else
593       {
594 #ifdef MSDOS
595          enlarge_output_buffer(retval) ;
596 #endif
597       }
598    }
599    return retval ;
600 }
601
602 #ifdef  MSDOS
603 void
604 enlarge_output_buffer(fp)
605    FILE *fp ;
606 {
607    if (setvbuf(fp, (char *) 0, _IOFBF, BUFFSZ) < 0)
608    {
609       errmsg(errno, "setvbuf failed on fileno %d", fileno(fp)) ;
610       mawk_exit(2) ;
611    }
612 }
613
614 void
615 stdout_init()
616 {
617    if (!isatty(1))  enlarge_output_buffer(stdout) ;
618    if (binmode() & 2)
619    {
620       setmode(1,O_BINARY) ; setmode(2,O_BINARY) ; 
621    }
622 }
623 #endif /* MSDOS */