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