~ubuntu-branches/ubuntu/jaunty/mawk/jaunty

« back to all changes in this revision

Viewing changes to files.c

  • Committer: Bazaar Package Importer
  • Author(s): James Troup
  • Date: 2001-07-18 20:40:37 UTC
  • Revision ID: james.westby@ubuntu.com-20010718204037-8hrndw7iapy9yj3w
Tags: upstream-1.3.3
ImportĀ upstreamĀ versionĀ 1.3.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 = fork())
 
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
         errmsg(errno, "failed to exec %s -c %s", shell, name) ;
 
442
         fflush(stderr) ;
 
443
         _exit(128) ;
 
444
 
 
445
      default:
 
446
         close(remote_fd) ;
 
447
         /* we could deadlock if future child inherit the local fd ,
 
448
           set close on exec flag */
 
449
         CLOSE_ON_EXEC(local_fd) ;
 
450
         break ;
 
451
   }
 
452
 
 
453
   return type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) :
 
454
      (PTR) fdopen(local_fd, "w") ;
 
455
}
 
456
 
 
457
 
 
458
 
 
459
/*------------ children ------------------*/
 
460
 
 
461
/* we need to wait for children at the end of output pipes to
 
462
   complete so we know any files they have created are complete */
 
463
 
 
464
/* dead children are kept on this list */
 
465
 
 
466
static struct child
 
467
{
 
468
   int pid ;
 
469
   int exit_status ;
 
470
   struct child *link ;
 
471
} *child_list ;
 
472
 
 
473
static void
 
474
add_to_child_list(pid, exit_status)
 
475
   int pid, exit_status ;
 
476
{
 
477
   register struct child *p = ZMALLOC(struct child) ;
 
478
 
 
479
   p->pid = pid ; p->exit_status = exit_status ;
 
480
   p->link = child_list ; child_list = p ;
 
481
}
 
482
 
 
483
static struct child *
 
484
remove_from_child_list(pid)
 
485
   int pid ;
 
486
{
 
487
   struct child dummy ;
 
488
   register struct child *p ;
 
489
   struct child *q = &dummy ;
 
490
 
 
491
   dummy.link = p = child_list ;
 
492
   while (p)
 
493
   {
 
494
      if (p->pid == pid)
 
495
      {
 
496
         q->link = p->link ;
 
497
         break ;
 
498
      }
 
499
      else
 
500
      {
 
501
         q = p ; p = p->link ; 
 
502
      }
 
503
   }
 
504
 
 
505
   child_list = dummy.link ;
 
506
   return p ;   
 
507
   /* null return if not in the list */
 
508
}
 
509
 
 
510
 
 
511
/* wait for a specific child to complete and return its
 
512
   exit status
 
513
 
 
514
   If pid is zero, wait for any single child and
 
515
   put it on the dead children list
 
516
*/
 
517
 
 
518
int
 
519
wait_for(pid)
 
520
   int pid ;
 
521
{
 
522
   int exit_status ;
 
523
   struct child *p ;
 
524
   int id ;
 
525
 
 
526
   if (pid == 0)
 
527
   {
 
528
      id = wait(&exit_status) ;
 
529
      add_to_child_list(id, exit_status) ;
 
530
   }
 
531
   /* see if an earlier wait() caught our child */
 
532
   else if (p = remove_from_child_list(pid))
 
533
   {
 
534
      exit_status = p->exit_status ;
 
535
      ZFREE(p) ;
 
536
   }
 
537
   else
 
538
   {
 
539
      /* need to really wait */
 
540
      while ((id = wait(&exit_status)) != pid)
 
541
      {
 
542
         if (id == -1)          /* can't happen */
 
543
            bozo("wait_for") ;
 
544
         else
 
545
         {
 
546
            /* we got the exit status of another child
 
547
            put it on the child list and try again */
 
548
            add_to_child_list(id, exit_status) ;
 
549
         }
 
550
      }
 
551
   }
 
552
 
 
553
   if (exit_status & 0xff)  exit_status = 128 + (exit_status & 0xff) ;
 
554
   else  exit_status = (exit_status & 0xff00) >> 8 ;
 
555
 
 
556
   return exit_status ;
 
557
}
 
558
 
 
559
#endif /* HAVE_REAL_PIPES */
 
560
 
 
561
 
 
562
void
 
563
set_stderr()   /* and stdout */
 
564
{
 
565
   FILE_NODE *p, *q ; 
 
566
   
 
567
   p = ZMALLOC(FILE_NODE) ;
 
568
   p->link = (FILE_NODE*) 0 ;
 
569
   p->type = F_TRUNC ;
 
570
   p->name = new_STRING("/dev/stdout") ;
 
571
   p->ptr = (PTR) stdout ;
 
572
   q = ZMALLOC(FILE_NODE);
 
573
   q->link = p ;
 
574
   q->type = F_TRUNC ;
 
575
   q->name = new_STRING("/dev/stderr") ;
 
576
   q->ptr = (PTR) stderr ;
 
577
   file_list = q ;
 
578
}
 
579
 
 
580
/* fopen() but no buffering to ttys */
 
581
static FILE *
 
582
tfopen(name, mode)
 
583
   char *name, *mode ;
 
584
{
 
585
   FILE *retval = fopen(name, mode) ;
 
586
 
 
587
   if (retval)
 
588
   {
 
589
      if (isatty(fileno(retval)))  setbuf(retval, (char *) 0) ;
 
590
      else
 
591
      {
 
592
#ifdef MSDOS
 
593
         enlarge_output_buffer(retval) ;
 
594
#endif
 
595
      }
 
596
   }
 
597
   return retval ;
 
598
}
 
599
 
 
600
#ifdef  MSDOS
 
601
void
 
602
enlarge_output_buffer(fp)
 
603
   FILE *fp ;
 
604
{
 
605
   if (setvbuf(fp, (char *) 0, _IOFBF, BUFFSZ) < 0)
 
606
   {
 
607
      errmsg(errno, "setvbuf failed on fileno %d", fileno(fp)) ;
 
608
      mawk_exit(2) ;
 
609
   }
 
610
}
 
611
 
 
612
void
 
613
stdout_init()
 
614
{
 
615
   if (!isatty(1))  enlarge_output_buffer(stdout) ;
 
616
   if (binmode() & 2)
 
617
   {
 
618
      setmode(1,O_BINARY) ; setmode(2,O_BINARY) ; 
 
619
   }
 
620
}
 
621
#endif /* MSDOS */