home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / MAWK113.ZIP / mawk113 / files.c < prev    next >
C/C++ Source or Header  |  1992-12-16  |  11KB  |  469 lines

  1.  
  2. /********************************************
  3. files.c
  4. copyright 1991, 1992.  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 5.5  1992/12/17  02:48:01  mike
  15.  * 1.1.2d changes for DOS
  16.  *
  17.  * Revision 5.4  1992/07/10  16:10:30  brennan
  18.  * patch2
  19.  * MsDOS: remove useless NO_BINMODE macro
  20.  * get process exit code on in pipes
  21.  *
  22.  * Revision 5.3  1992/04/07  20:21:17  brennan
  23.  * patch 2
  24.  * unbuffered output to a tty
  25.  *
  26.  * Revision 5.2  1992/04/07  16:03:08  brennan
  27.  * patch 2
  28.  * allow same filename for output and input, but use different descriptors
  29.  * E.g. < "/dev/tty" and > "/dev/tty"
  30.  *
  31.  * Revision 5.1  91/12/05  07:56:00  brennan
  32.  * 1.1 pre-release
  33.  * 
  34. */
  35.  
  36. /* files.c */
  37.  
  38. #include "mawk.h"
  39. #include "files.h"
  40. #include "memory.h"
  41. #include "fin.h"
  42.  
  43. static FILE  *PROTO(tfopen, (char*,char*)) ;
  44. static  void  PROTO(add_to_child_list, (int,int)) ;
  45. static struct child *PROTO(remove_from_child_list, (int)) ;
  46. extern int PROTO(isatty, (int)) ;
  47.  
  48. #ifdef  V7
  49. #include  <sgtty.h>    /* defines FIOCLEX */
  50. #endif
  51.   
  52.  
  53. #if  HAVE_FCNTL_H  
  54.  
  55. #include <fcntl.h>
  56. #define  CLOSE_ON_EXEC(fd)   (void) fcntl(fd, F_SETFD, 1)
  57.  
  58. #else
  59. #define  CLOSE_ON_EXEC(fd) ioctl(fd, FIOCLEX, (PTR) 0)
  60. #endif
  61.  
  62.  
  63. /* We store dynamically created files on a linked linear
  64.    list with move to the front (big surprise)  */
  65.  
  66. typedef struct file {
  67. struct file *link ;
  68. STRING  *name ;
  69. short type ;
  70. int pid ;  /* we need to wait() when we close a pipe */
  71.            /* holds temp file index under MSDOS */
  72.  
  73. #if  HAVE_FAKE_PIPES
  74. int inpipe_exit ; 
  75. #endif
  76.  
  77. PTR   ptr ;  /* FIN*   or  FILE*   */
  78. }  FILE_NODE ;
  79.  
  80. static FILE_NODE *file_list ;
  81.  
  82.  
  83. /* find a file on file_list */
  84. PTR  file_find( sval, type )
  85.   STRING *sval ;
  86.   int type ;
  87. { register FILE_NODE *p = file_list ;
  88.   FILE_NODE *q = (FILE_NODE *) 0 ;
  89.   char *name = sval->str ;
  90.   char *ostr ;
  91.  
  92.   while (1)
  93.   {
  94.     if ( !p )   /* open a new one */
  95.     {
  96.       p = ZMALLOC(FILE_NODE) ; 
  97.       switch( p->type = type )
  98.       {
  99.         case  F_TRUNC :
  100. #if MSDOS 
  101.             ostr = (binmode()&2) ? "wb" : "w" ;
  102. #else
  103.             ostr = "w" ;
  104. #endif
  105.             if ( !(p->ptr = (PTR) tfopen(name, ostr)) )
  106.                 goto out_failure ;
  107.             break ;
  108.  
  109.         case  F_APPEND :
  110. #if MSDOS 
  111.             ostr = (binmode()&2) ? "ab" : "a" ;
  112. #else
  113.             ostr = "a" ;
  114. #endif
  115.             if ( !(p->ptr = (PTR) tfopen(name, ostr)) )
  116.                 goto out_failure ;
  117.             break ;
  118.  
  119.         case  F_IN  :
  120.             if ( !(p->ptr = (PTR) FINopen(name, 0)) )
  121.             { zfree(p, sizeof(FILE_NODE)) ; return (PTR) 0 ; }
  122.             break ;
  123.  
  124.         case  PIPE_OUT :
  125.         case  PIPE_IN :
  126.  
  127. #if    HAVE_REAL_PIPES || HAVE_FAKE_PIPES 
  128.  
  129.             if ( !(p->ptr = get_pipe(name, type, &p->pid)) )
  130.                 if ( type == PIPE_OUT ) goto out_failure ;
  131.                 else
  132.                 { zfree(p, sizeof(FILE_NODE) ) ;
  133.                   return (PTR) 0 ;
  134.                 }
  135. #else
  136.          rt_error("pipes not supported") ;
  137. #endif
  138.             break ;
  139.  
  140. #ifdef  DEBUG
  141.         default :
  142.             bozo("bad file type") ;
  143. #endif
  144.       }
  145.       /* successful open */
  146.       p->name = sval ;
  147.       sval->ref_cnt++ ;
  148.       break ; /* while loop */
  149.     }
  150.  
  151.     /* search is by name and type */
  152.     if ( strcmp(name, p->name->str) == 0 &&
  153.      ( p->type == type ||
  154.            /* no distinction between F_APPEND and F_TRUNC here */
  155.        p->type >= F_APPEND && type >= F_APPEND ))
  156.  
  157.     { /* found */
  158.       if ( !q )  /*at front of list */
  159.           return  p->ptr ;
  160.       /* delete from list for move to front */
  161.       q->link = p->link ;
  162.       break ; /* while loop */
  163.     }
  164.     q = p ; p = p->link ;
  165.   } /* end while loop */
  166.  
  167.   /* put p at the front of the list */
  168.   p->link = file_list ;
  169.   return  (PTR) (file_list = p)->ptr ;
  170.  
  171. out_failure:
  172.   errmsg(errno, "cannot open \"%s\" for output", name) ;
  173.   mawk_exit(1) ;
  174.  
  175. }
  176.  
  177.  
  178. /* Close a file and delete it's node from the file_list.
  179.    Walk the whole list, in case a name has two nodes,
  180.    e.g. < "/dev/tty" and > "/dev/tty"
  181. */
  182.  
  183. int  file_close( sval )
  184.   STRING *sval ;
  185. { register FILE_NODE *p = file_list ;
  186.   FILE_NODE *q = (FILE_NODE *) 0 ; /* trails p */
  187.   FILE_NODE *hold ;
  188.   char *name = sval->str ;
  189.   int retval = -1 ;
  190.  
  191.   while ( p )
  192.         if ( strcmp(name,p->name->str) == 0 ) /* found */
  193.         { 
  194.           switch( p->type )
  195.           {
  196.             case  F_TRUNC :
  197.             case  F_APPEND :    
  198.                 (void) fclose((FILE *) p->ptr) ;
  199.         retval = 0 ;
  200.                 break ;
  201.  
  202.             case  PIPE_OUT :
  203.                 (void) fclose((FILE *) p->ptr) ;
  204.  
  205. #if  HAVE_REAL_PIPES
  206.                 retval =  wait_for(p->pid) ;
  207. #endif
  208. #if  HAVE_FAKE_PIPES
  209.                 retval = close_fake_outpipe(p->name->str,p->pid) ;
  210. #endif
  211.                 break ;
  212.  
  213.             case F_IN  :
  214.                 FINclose((FIN *) p->ptr) ;
  215.         retval = 0 ;
  216.                 break ;
  217.  
  218.             case PIPE_IN :
  219.                 FINclose((FIN *) p->ptr) ;
  220.  
  221. #if  HAVE_REAL_PIPES
  222.                 retval = wait_for(p->pid) ;
  223. #endif
  224. #if  HAVE_FAKE_PIPES
  225.           { 
  226.         char xbuff[100] ;
  227.                 (void) unlink(tmp_file_name(p->pid,xbuff)) ;
  228.         retval = p->inpipe_exit ;
  229.           }
  230. #endif
  231.                 break ;
  232.           }
  233.  
  234.           free_STRING(p->name) ;
  235.       hold = p ;
  236.           if ( q )  q->link = p = p->link ;
  237.           else  file_list = p = p->link ;
  238.  
  239.           ZFREE(hold) ;
  240.         }
  241.         else { q = p ; p = p->link ; }
  242.  
  243.   return retval ;
  244. }
  245.  
  246. /* When we exit, we need to close and wait for all output pipes */
  247.  
  248.  
  249. #if   HAVE_REAL_PIPES
  250.  
  251. void close_out_pipes()
  252. { register FILE_NODE *p = file_list ;
  253.  
  254.   while ( p )
  255.   { if ( p->type == PIPE_OUT )
  256.     { (void) fclose((FILE *) p->ptr) ;  (void) wait_for(p->pid) ; }
  257.     p = p->link ;
  258.   }
  259. }
  260.  
  261. #else
  262. #if  HAVE_FAKE_PIPES  /* pipes are faked with temp files */
  263.  
  264. void  close_fake_pipes()
  265. { register FILE_NODE *p = file_list ;
  266.   char xbuff[100] ;
  267.  
  268.   /* close input pipes first to free descriptors for children */
  269.   while ( p )
  270.   {
  271.     if ( p->type == PIPE_IN )
  272.     { FINclose((FIN *) p->ptr) ;
  273.       (void) unlink(tmp_file_name(p->pid,xbuff)) ; 
  274.     }
  275.     p = p->link ;
  276.   }
  277.   /* doit again */
  278.   p = file_list ;
  279.   while ( p )
  280.   {
  281.     if ( p->type == PIPE_OUT )
  282.     {
  283.       (void) fclose(p->ptr) ;
  284.       (void) close_fake_outpipe(p->name->str,p->pid) ;
  285.     }
  286.     p = p->link ;
  287.   }
  288. }
  289. #endif /* HAVE_FAKE_PIPES */
  290. #endif /* ! HAVE_REAL_PIPES */
  291.  
  292. /* hardwire to /bin/sh for portability of programs */
  293. char *shell = "/bin/sh" ;
  294.  
  295. #if  HAVE_REAL_PIPES
  296.  
  297. PTR get_pipe( name, type, pid_ptr)
  298.   char *name ;
  299.   int type ;
  300.   int *pid_ptr ;
  301. { int the_pipe[2], local_fd, remote_fd ;
  302.  
  303.   if ( pipe(the_pipe) == -1 )  return (PTR) 0 ;
  304.   local_fd = the_pipe[type == PIPE_OUT] ;
  305.   remote_fd = the_pipe[type == PIPE_IN ] ;
  306.   /* to keep output ordered correctly */
  307.   fflush(stdout) ; fflush(stderr) ;
  308.  
  309.   switch( *pid_ptr = fork() )
  310.   { case -1 :  
  311.       (void) close(local_fd) ;
  312.       (void) close(remote_fd) ;
  313.       return (PTR) 0 ;
  314.  
  315.     case  0 :
  316.         (void) close(local_fd) ;
  317.         (void) close(type == PIPE_IN) ;
  318.         (void) dup( remote_fd ) ;
  319.         (void) close( remote_fd ) ;
  320.         (void) execl(shell, shell, "-c", name, (char *) 0 ) ;
  321.         errmsg(errno, "failed to exec %s -c %s" , shell, name) ;
  322.         fflush(stderr) ;
  323.         _exit(128) ;
  324.  
  325.     default :
  326.         (void) close(remote_fd) ;
  327.         /* we could deadlock if future child inherit the local fd ,
  328.            set close on exec flag */
  329.         CLOSE_ON_EXEC(local_fd) ;
  330.         break ;
  331.   }
  332.  
  333.   return  type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) : 
  334.                             (PTR)  fdopen(local_fd, "w")  ;
  335. }
  336.   
  337.  
  338.  
  339. /*------------ children ------------------*/
  340.  
  341. /* we need to wait for children at the end of output pipes to
  342.    complete so we know any files they have created are complete */
  343.  
  344. /* dead children are kept on this list */
  345.  
  346. static struct child {
  347. int pid ;
  348. int exit_status ;
  349. struct child *link ;
  350. }  *child_list ;
  351.  
  352. static  void  add_to_child_list(pid, exit_status)
  353.   int pid, exit_status ;
  354. { register struct child *p = 
  355.           (struct child *) zmalloc(sizeof(struct child)) ;
  356.  
  357.   p->pid = pid ; p->exit_status = exit_status ;
  358.   p->link = child_list ; child_list = p ;
  359. }
  360.  
  361. static struct child *remove_from_child_list(pid)
  362.   int pid ;
  363. { register struct child *p = child_list ;
  364.   struct child *q = (struct child *) 0 ;
  365.  
  366.   while ( p )
  367.     if ( p->pid == pid )
  368.     {
  369.         if ( q ) q->link = p->link ;
  370.         else child_list = p->link ;
  371.         break ;
  372.     }
  373.     else { q = p ; p = p->link ; }
  374.  
  375.   return p ;  /* null return if not in the list */
  376. }
  377.     
  378.  
  379. /* wait for a specific child to complete and return its 
  380.    exit status 
  381.  
  382.    If pid is zero, wait for any single child
  383. */
  384.  
  385. int wait_for(pid)
  386.   int pid ;
  387. { int exit_status ;
  388.   struct child *p ;
  389.   int id ;
  390.  
  391.   if ( pid == 0 )
  392.   {
  393.     id = wait(&exit_status) ;
  394.     add_to_child_list(id, exit_status) ;
  395.   }
  396.   else
  397.   /* see if an earlier wait() caught our child */
  398.   if ( p = remove_from_child_list(pid) ) 
  399.   { exit_status = p->exit_status ;
  400.     ZFREE(p) ;
  401.   }
  402.   else /* need to really wait */
  403.     while ( (id = wait(&exit_status)) != pid )
  404.         if ( id == -1 ) /* can't happen */  bozo("wait_for") ;
  405.         else
  406.         { /* we got the exit status of another child
  407.              put it on the child list and try again */
  408.           add_to_child_list(id, exit_status ) ;
  409.         }
  410.  
  411.   if ( exit_status & 0xff ) 
  412.        exit_status = 128 + (exit_status & 0xff) ;
  413.   else  exit_status = (exit_status & 0xff00)>>8 ;
  414.  
  415.   return exit_status ;
  416. }
  417.         
  418. #endif  /* HAVE_REAL_PIPES */
  419. void set_stderr()
  420. {
  421.   file_list = ZMALLOC(FILE_NODE) ;
  422.   file_list->link = (FILE_NODE*) 0 ;
  423.   file_list->type = F_TRUNC ;
  424.   file_list->name = new_STRING("/dev/stderr") ;
  425.   file_list->ptr = (PTR) stderr ;
  426. }
  427.  
  428. /* fopen() but no buffering to ttys */
  429. static FILE *tfopen(name, mode)
  430.   char *name, *mode ;
  431. {
  432.   FILE *retval = fopen(name,mode) ;
  433.  
  434.   if ( retval )
  435.   {
  436.     if ( isatty(fileno(retval)) )  setbuf(retval, (char*)0) ;
  437.     else
  438.     {
  439. #if  LM_DOS
  440.        enlarge_output_buffer(retval) ;
  441. #endif
  442.     }
  443.   }
  444.   return retval ;
  445. }
  446.  
  447. #if  LM_DOS
  448. void enlarge_output_buffer( fp )
  449.   FILE *fp ;
  450. {
  451.   if ( setvbuf(fp, (char*) 0, _IOFBF, BUFFSZ) < 0 )
  452.   {
  453.     errmsg(errno, "setvbuf failed on fileno %d", fileno(fp)) ;
  454.     mawk_exit(1) ;
  455.   }
  456. }
  457. #endif
  458.  
  459. #if  MSDOS
  460. void
  461. stdout_init()
  462. {
  463. #if  LM_DOS
  464.    if ( ! isatty(1) )  enlarge_output_buffer(stdout) ;
  465. #endif
  466.    if ( binmode() & 2 ) { setmode(1,O_BINARY) ; setmode(2,O_BINARY) ; }
  467. }
  468. #endif /* MSDOS */
  469.