/* xmgrpipe.c
 * interface pour xmgr -npipe option
 */

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>

#include <errno.h>
#include <varargs.h>

#include <ctype.h>


/* declaration des procedures de communications avec xmgr */
int   xmgrpipe_open();
int   xmgrpipe_printf();    /* pb en mode FILE */
void  xmgrpipe_unlink();
void  xmgrpipe_signal();

/* declaration des variables statiques utilisees */
char  xmgrpipe_name[40];
int   xmgrpipe_num;
int   xmgrpipe_addcr;
int   xmgrpipe_sigint;
pid_t xmgrpipe_pid;
jmp_buf xmgrpipe_sjbuf;

/* les chemins ... */
#define XMGR_PATH "/usr/local/bin/xmgr"

/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/*   int xmgrpipe_open ( int status, char prg_name,int add_cr ) */
/*   prepare xmgr a fonctioner en pipe avec l'application       */
/*   status :  0 retour si echec,  n exit(n) si echec           */
/*   add_cr :  0  ou 1 si ajout de \n en emission (pb fortran ) */
/*   valeur :  -1 si echec, File_num du pipe sinon              */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */

int xmgrpipe_open ( status, prg_name, add_cr )
int status;
char *prg_name;
int add_cr;
{

    int  num, result;
    
    struct stat stat_buf;
    
    
    xmgrpipe_addcr = add_cr;
    
/* ------- recherche d'un nom pour le tube ------------ */
   
    num = 0;
    for (num = result = 0; num < 100 && result != -1; num++ )
    {   sprintf( xmgrpipe_name, "%s.fifo_%02d", prg_name, num );
        result = stat( xmgrpipe_name, &stat_buf );
        if ( result != -1 )
             fprintf( stderr,"file_name '%s' : stat %d, recherche d'un autre pipe\n",
                   xmgrpipe_name, result);
        }
    if ( result != -1 || num >= 100 )
    {    fprintf( stderr," Abandon, impossible de trouver un nom de pipe '%s'\n",
                   xmgrpipe_name);
         if ( status ) exit( status ); else return -1;
         }
                   
/* ------- creation du tube nomme ------------ */

    if (mknod( xmgrpipe_name , S_IFIFO | 0666, 0 ))
    {    fprintf( stderr,"Abandon, creation impossible du tube nomme '%s' errno %d\n", 
                 xmgrpipe_name, errno );
         if ( status ) exit( status ); else return -1;
         }
    else fprintf( stderr,"Creation du tube nomme '%s' reussie\n", xmgrpipe_name );


    xmgrpipe_pid = 0;
    if (atexit( xmgrpipe_unlink) )
    {    fprintf( stderr,"Echec sur atexit : le tube nomme '%s' ne sera pas detruit automatiquement\n",
                 xmgrpipe_name );
          }

/* ---------- lancement de xmgr  -------------- */

     if ((xmgrpipe_pid = fork()) == (pid_t)0) 
     {     /*  we are in child then exec ... */
           result = execlp (XMGR_PATH, XMGR_PATH, "-npipe", xmgrpipe_name, (char *)0);
           if ( result = -1 )
           {    fprintf( stderr,"Abandon, Exec to xmgr failed, errno = %d\npath : %s\n", 
                          errno, XMGR_PATH );
                if ( status ) exit( status ); else return -1;
           }    }  
                 
     else if (xmgrpipe_pid < (pid_t)0) 
     {            
           fprintf( stderr,"Abandon, Child creation failed : %d\n", xmgrpipe_pid);
           if ( status ) exit( status ); else return -1;
          }
     fprintf( stderr,"Child pid = %d\n", xmgrpipe_pid);

/* ----------- ouverture en ecriture du tube ---------- */

    if (( xmgrpipe_num = open(xmgrpipe_name, O_WRONLY , 0 )) == -1)
    {    fprintf( stderr,"Ouverture impossible du tube nomme '%s', errno %d\n", 
                  xmgrpipe_name, errno );
         if ( status ) exit( status ); else return -1;
         }
    fprintf( stderr,"Ouverture du tube nomme '%s' reussie : #%d\n", 
                  xmgrpipe_name, xmgrpipe_num );
                  
/* ----------- interception des signaux ^C ---------- */
      
    signal( SIGINT, xmgrpipe_signal );
               signal( SIGPIPE, xmgrpipe_signal );
     
                 
    return xmgrpipe_num;
    }
      
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/*   int xmgrpipe_wait ( int number )                           */
/*   autorise la mise en attente des prochaines ecritures       */
/*    a concurence de number, elles seront ecrites au prochain  */
/*   xmgrpipe_print, retourne le nb de chaines en attente       */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
static int xmgrpipe_waitfor = 10;
static int xmgrpipe_waiting = 0;
static char * xmgrpipe_buffer = NULL;

int xmgrpipe_wait ( number )
int number;
{
     xmgrpipe_waitfor = number;
     if ( xmgrpipe_waiting >= xmgrpipe_waitfor ) xmgrpipe_printf ("");
     return xmgrpipe_waiting;
     }

/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/*   int xmgrpipe_printf ( char *format, ... )                  */
/*   ecrit sur le pipe en verifiant pas de pb                   */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */

int xmgrpipe_printf( va_alist )
va_dcl
{

      va_list args;
      char *fmt;
      char buffer[1024];
      int lg, result;
      int (*istat)();
      
      va_start(args);

      fmt = va_arg(args, char *);

      vsprintf( buffer, fmt, args);
      va_end(args);
      
      if ( buffer[0] && xmgrpipe_addcr ) strcat( buffer, "\n");
      
      if ( xmgrpipe_buffer != NULL )
      {    if ( buffer[0] )
           {   fmt = (char * ) malloc ( 2 + strlen(xmgrpipe_buffer) + strlen(buffer) );
               strcpy( fmt, xmgrpipe_buffer);
               strcat( fmt, buffer);
               free (xmgrpipe_buffer);
               xmgrpipe_buffer = fmt;
               }
            else fmt = xmgrpipe_buffer;
            }
      else fmt = buffer;       
      
      lg = strlen(fmt);
      if ( lg == 0 ) return;
      
/* ----------- interception des signaux ---------- */

      if ( xmgrpipe_waiting >= xmgrpipe_waitfor ) 
      {     setjmp( xmgrpipe_sjbuf );
            signal( SIGPIPE, xmgrpipe_signal ); 
            }
      else signal( SIGPIPE, SIG_IGN );

      result = write( xmgrpipe_num, fmt, lg );
      if ( result != lg )
      {    if ( errno == 32 )
           {    xmgrpipe_waiting++;
                if ( xmgrpipe_buffer == NULL )
                {    xmgrpipe_buffer = (char * ) malloc ( 2 + strlen(fmt) );
                     strcpy( xmgrpipe_buffer, fmt);
                }    
           }
           else 
         fprintf (stderr, "\nxmgrpipe %s #%d errno %d waiting %d MAX %d\n%s%s\n", 
             xmgrpipe_name, xmgrpipe_num, errno, 
             xmgrpipe_waiting, xmgrpipe_waitfor, fmt, 
             strerror( errno ));
         }
      else
      {    xmgrpipe_waiting = 0;      
           if (xmgrpipe_buffer != NULL) 
           {    free (xmgrpipe_buffer);
                xmgrpipe_buffer = NULL; 
                }
           }
      }
    
    
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/*   void xmgrpipe_unlink ( void )                             */
/*   detruit le pipe apres le programme                         */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */

void xmgrpipe_unlink (  )
{

    signal( SIGPIPE, SIG_DFL );
    if (unlink( xmgrpipe_name ) == -1 )
    fprintf( stderr,"Suppresssion du tube nomme '%s' impossible : errno=%d\n", 
                  xmgrpipe_name, errno );
    
    if ( xmgrpipe_pid )
       if ( kill( xmgrpipe_pid, SIGKILL ) == -1 )
            fprintf( stderr,"Impossible de tuer xmgr (pid %d ): errno=%d\n", 
                  xmgrpipe_pid, errno );
      
    }
    
    
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/*   void xmgrpipe_signal ( void )                              */
/*   capture le broken pipe et attend que la lecture soit       */
/*   reactiove du cote de xmgr                                  */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */

void xmgrpipe_signal ( val )
int val;
{
     int stat_loc;
     int result;
     
     if (val == SIGINT )          exit(3);
         
     result = waitpid( xmgrpipe_pid, &stat_loc, WNOHANG ) ;
     if ( result == -1 )
     {    if ( WIFEXITED(stat_loc) ) 
          {    fprintf ( stderr," xmgr pid %d n'existe plus\n", xmgrpipe_pid);
               xmgrpipe_pid = 0;
               exit( 3 );
               }
          else
          if (  WIFSTOPPED(stat_loc) )
          {    fprintf ( stderr," xmgr pid %d est stoppe\n", xmgrpipe_pid);
               }
          }
     sleep( 1 );
     longjmp( xmgrpipe_sjbuf, 0 );
    
     }
    
    
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
	
