/*
 * tradu2tub.c
 * - cree 2 tubes et 1 fils
 *  - le pere scrute les descripteurs ouverts
 *    parmi stdin et l'entree du tube 2 et
 *    s'arrete lorsqu'ils sont tous fermes
 *    a chaque descripteur pres, il lit les
 *    bufsize caracteres de s ds le descripteur
 *    correspondant.
 *    si il lit dans stdin, il recopie les car 
 *    dans l'entree du tube 1
 *    si il lit dans le tube 2, il recopie les
 *    car vers la sortie standart
 *  - le fils joue le role de traducteur
 *    il redirige l'entree du tube 1 sur stdin
 *    et la sortie du tube 2 sur stdout puis
 *    se recouvre avec `tr a-z A-Z`
 **********************************************
 * Davy Dequidt
 * L3 Info Luminy
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>

int sigaction(int sig,const struct sigaction *p_action,struct sigaction *p_action_ancien);

int mysignal (int sig, void (*h)(int))
{
        struct sigaction s;
        s.sa_handler=h;
        sigemptyset (&s.sa_mask);
        s.sa_flags=SA_RESTART;
        return sigaction(sig,&s,NULL);
}

void capte( int sig ){
  switch( sig ){
    case 17 :
    case 18 :
    case 20 :
      printf("\n");
      exit(0);
    default : 
      printf("Signal recu : %d\n", sig);
  }
}

int main(int argc, char *argv[])
{  
  char *s;
  int p1[2], p2[2], pid, bufsize;
  if(argc!=2){
    printf("Usage : %s <bufsize>\n",argv[0]);
    exit(0);
  }
  bufsize = atoi(argv[1]);
  s = malloc( bufsize * sizeof *s ); /* alloc chaine de caracteres */
  if( !s ){ perror("malloc()"); exit(1); }

  pipe( p1 );
  pipe( p2 );
  if( p1<0 || p2<0 ){ perror("pipe()"); exit(1); }
  
  pid = fork();
  if( pid<0 ){
    perror("fork");
    exit(1);
  }
  if( pid==0 ){ /* fils 1 */
    close( p1[1] );
    close( p2[0] );
    close( 0 );
    if(dup( p1[0] )<0 ){ perror("dup p1->stdin"); exit(1); }
    close( 1 );
    if(dup( p2[1] )<0 ){ perror("dup p2->stdout"); exit(1); }
    execlp("tr","tr","a-z","A-Z",NULL);
  /*  execlp("cat","cat",NULL); */
    perror("execlp");
    exit(1);
  }
  
  /* pere */
   {
    fd_set set;
    int res, in=1;
    int k;
    printf("pere %d, fils %d\n", getpid(), pid);
    mysignal( 17, capte );
    mysignal( 18, capte );
    mysignal( 20, capte );
    close( p1[0] );
    close( p2[1] ); 
    while(1){
      FD_ZERO(&set);
      if( in ) FD_SET( 0, &set );
      FD_SET( p2[0], &set );
      res = select( p2[0]+1, &set, NULL, NULL, NULL );
      if( res>0 ){
        if( FD_ISSET( 0, &set) ){ /* entree standard */
 	  k = read( 0, s, bufsize);
          if( k<0 ){
            perror("read()");
            exit(1);
          }
          if( k==0 ){
            in=0;
            close( p1[1] );
            continue;
          }
          if( write( p1[1], s, k ) <0 ){
            perror("write()");
            exit(1);
          }
        }        
        if( FD_ISSET( p2[0], &set) ){ /* p2 */
          k = read( p2[0], s, bufsize);
          if( k<0 ){
            perror("read()");
            exit(1);
          }
          if( write( 1, s, k ) <0 ){
            perror("write()");
            exit(1);
          }
        }
      }else{
 	/* erreur */
	if(errno==EBADF) fprintf(stderr, "1 desc (tube) ferme\n");
 	else perror("pere select()");
      }
    }
    close( p2[0] );
    close( p1[1] );
 }
 printf("bye\n");
 return EXIT_SUCCESS;
}

