/*****************************************************
 * TEMA    : Implementacion de shell en Unix         *
 * DATA    : 20/01/1998                              *
 *****************************************************/ 

#include <fcntl.h>      /* para open */
#include <unistd.h>     /* fork,...,pipe*/
#include <sys/types.h>   /* fork,... open */
#include <sys/ipc.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>     /* Funcion printf */
#include <string.h>
#include <sys/stat.h>  /* Open,... */
#include <dirent.h>  /* Para readdir,openndir,closedir */
#include <signal.h>  /* Para usar SIGNAL */
#define Simbolo " -> "


#define SALIR "exit"
#define blanco " "
#define CD     "cambiadir"
#define LS     "ficheros"
#define RED_E  "redir-e"
#define RED_S  "redir-s"
#define RED_ES "redir-es"
#define CONCAT "encadena"
#define BREAK  "break"
#define MAN    "ayuda"
#define ERRO   "comando incorrecto ou opcion non valida \n"



/******************************************************************/
/*************OBTEN OS DEREITOS ACTUAIS DO FICHEIRO ***************/

void Transforma(mode_t Num_Permiso)
{
int c,x,Numero;
mode_t Tipo;
char Permisos[]="rwxrwxrwx";
Numero=Num_Permiso;
Tipo=(Num_Permiso & S_IFMT);
switch(Tipo){
  case S_IFIFO : printf("#[FIF]");break;
  case S_IFCHR : printf("#[CHR]");break;
  case S_IFDIR : printf("#[DIR]");break;
  case S_IFBLK : printf("#[BLK]");break;
  case S_IFREG : printf("#[---]");break;
  default : printf("#[***]");
 }
for (c=8;c>=0;c--)
 {
 x=Numero % 2;
 Numero = Numero / 2;
 if (x!=1)
   Permisos[c]='-';
 }
printf("%s",&Permisos);

}




/*****************************************************************/
/************MOSTRA PORPANTALLA O ESTADO DOS FICHEIROS************/

void Listar_Informacion(char List_fich[])
{
struct stat Estado;

  if (stat(List_fich,&Estado)==-1)
     {printf(" Erro na funcion stat \n");}
  else 
    {  
      
       Transforma(Estado.st_mode);
       printf("%10d ",Estado.st_size);
       printf("  %6d ",Estado.st_ino);
       printf("    %6d  ",Estado.st_uid);
       printf("   %6d ",Estado.st_gid);
       printf("   %6d  ",Estado.st_nlink);
       printf("%s \n",List_fich); 
     } 
}









int Busca(char linea[])
{
int i,sw;

i=-1;
sw=1;
do
{
i=i+1;
if (linea[i]==' ')  {  sw=0;}

}
while ((sw != 0) & (i<strlen(linea)));
return(i);
}


/* SEPARA UNHA LINHA NO COMANDO E OS PARAMETROS */

void Separa(char linea[],char coman[],char parametro[])
{
char com[80],*modifica;
int n;
n=Busca(linea);
strncpy(com,linea,n);
com[n]='\0';
strcpy(coman,com);
if (strlen(linea)!=n) {modifica=strchr(linea,32);
                       modifica=strchr(modifica,linea[n+1]);}
     else {modifica=blanco;}
strcpy(parametro,modifica);


}



/* MOSTRA AXUDA DOS COMANDOS DISPONIBLES */

void AXUDA(void)
{

printf("\n ");
printf(" \n  COMANDOS DISPONIBLES ");
printf("\n");
printf("\n cambiadir [dir]   :  Cambia ao directorio [dir]");
printf("\n ficheros [-a|-l]  :  Lista ficheros directorio"); 
printf("\n redir-e f s       :  Executa o programa s tomando como entrada standar s");
printf("\n redir-s f s       :  Executa o programa s tomando como saisa standard s");
printf("\n redir-es f1 f2 s  :  Executa o programa s tomando como entrada f1 e como saida f2");
printf("\n encadena s1 %s s2  :  Saida do programa s1 e entrada do programa s2 ","%");
printf("\n break [on|off]    :  Activa/Desactiva Control-C");
printf("\n ayuda             :  Mostra esta pantalla ");
printf("\n");
}

void CONTROLC(char Opcion[])
{
 if ((strcmp(Opcion,"off"))==0) 
 { sigignore(SIGINT);
   printf("Senhal de Control-C desactivada \n ");}
 else if ((strcmp(Opcion,"on"))==0)
   {signal(SIGINT,SIG_DFL);
    printf("Senhal de Control-C activada \n");}
    else printf("Parametro defectuoso.Teclee ayuda para mais informacion\n");  

}



/* Separa os parametros do comando e executao */

void Frag_Exec(char string[80])
{
 char MOD1[80],MOD2[80],aux[80],*argv[10];
 int n;

n=0;
Separa(string,MOD1,MOD2);
strcpy(aux,MOD1);
 while (strcmp(string,blanco)!=0)
    {   Separa(string,MOD1,MOD2);
        argv[n]=MOD1;
        n=n+1;
        strcpy(string,MOD2);  }
  argv[n]=NULL;
 if(execvp(aux,argv)==-1)
  {printf("\n %s : Comando Incorrecto\n",aux);
   exit(0);}
 }



/* REDIRECCIONAR A SAIDA */

void REDIR_S(char programa[])
{
 int df;
 char fich[80],string[80],MOD1[80],MOD2[80];
 
  Separa(programa,fich,string);   
  if (fork()==0)
   { if ((df=open(fich,O_CREAT|O_WRONLY,0600))==-1) 
        {printf("\nFicheiro non se puido abrir correctamente\n");}
      else 
          {dup2(df,1);
          Frag_Exec(string);}}
  else {wait(0);} 

}



/* REDIRECCIONAR A ENTRADA */

void REDIR_E(char programa[])
{
 int df;
 char fich[80],string[80],MOD1[80],MOD2[80];
 
  Separa(programa,fich,string);  
 if (fork()==0)
   { if ((df=open(fich,O_CREAT|O_RDONLY,0600))==-1) 
        {printf("\nFicheiro non se puido abrir correctamente\n");}
      else 
         {dup2(df,0);
          Frag_Exec(string);}}
  else {wait(0);} 
     
}


/* REDIRECCIONAR ENTRADA  E  SAIDA */

void REDIR_ES(char programa[])
{ 
 int Descriptor1,Descriptor2;
 char Fichero1[80],Fichero2[80],Cadea[80],aux[80];

 Separa(programa,Fichero1,aux);
 Separa(aux,Fichero2,Cadea);
 if (fork()==0)
 {
 Descriptor1=open(Fichero1,O_RDONLY,0600);
 if (Descriptor1==-1)
   {
    printf("\n %s : Fichero de entrada non existe \n",Fichero1);
    exit(0);
   }
    else
     {
      Descriptor2=open(Fichero2,O_CREAT | O_WRONLY,0600);
      dup2(Descriptor1,0);
      dup2(Descriptor2,1);
      Frag_Exec(Cadea);
     }
     
  }   
  else {wait(0);}
   
}

  
  
  

/* ENCADENA A SAIDA DUN PROGRAMA COA ENTRADA DO OUTRO */
void ENCADENA(char programa[])
{ 
 int Fildes[2],n;
 char string[80],aux[80],*aux2,aux3;
 


strcpy(string,programa);
n=0;
aux[0]=string[0];
aux[1]='\0';

while (strcmp(aux,"%")!=0)
      {  n=n+1;
         aux[0]=string[n];
         aux[1]='\0';  
        }
strncpy(aux,string,n-1);
aux[n-1]='\0';
aux3='%';
aux2=strchr(string,aux3);
aux3=string[n+2];
aux2=strchr(aux2,aux3);
strcpy(string,aux2);

if (pipe(Fildes)==-1)
 {printf("\n Erro en Chamada Pipe");}
else
{

if (fork()==0)
            {dup2(Fildes[1],1);          
             Frag_Exec(aux);}

close(Fildes[1]);

if (fork()==0)        
            {dup2(Fildes[0],0);
             Frag_Exec(string);}

else {close(Fildes[0]);
      wait(NULL);
      wait(NULL);}
}
}



/* CAMBIA DE DIRECTORIO */

void SALT_DIR(const char *Directorio)
{
 int Exito;
 if (strcmp(Directorio,blanco)==0)
   { printf("%s",getcwd(NULL,256)); }
    else
    { Exito=chdir(Directorio);
      if (Exito==-1)
        printf("\n Directorio non valido na ruta actual  \n");
     }
}



/* LISTA FICHEIROS DO DIRECTORIO */

void LIST_DIR(char modificadores[])
{ 

  char aux[2];
  DIR *dirp;
  struct dirent *direntp;
  dirp=opendir(".");
  printf("\n");
  if (strcmp(modificadores,"-l")==0)
       { printf("\n  Dereitos         Tamanho  Inodo  ID-Usuario ID-Grupo");
         printf(" Link Nome \n");
         printf("--------------------------------------------------------------------------\n");
         while ((direntp=readdir(dirp))!=NULL)
          Listar_Informacion(direntp->d_name);}
  else if (strcmp(modificadores,blanco)==0)
          {while ((direntp=readdir(dirp))!=NULL)
          { aux[0]=direntp->d_name[0];
            aux[1]='\0'; 
            if (strcmp(aux,".")!=0)
              (void)printf("# %s \n",direntp->d_name);}}
       else  if (strcmp(modificadores,"-a")==0)
             {  while ((direntp=readdir(dirp))!=NULL)
                (void)printf("# %s \n",direntp->d_name);}
              else  {printf(" %s ",ERRO);}

(void)closedir(dirp);
  
 }


/* ENCARGASE DE EXECUTAR OS COMANDO QUE INTRODUCIMOS */

int Inter(char linea[],char comando[],char modificador[])
{

int fin;
fin=1;
 if (strcmp(comando,CD)==0)
  { SALT_DIR(modificador); }
   else if (strcmp(comando,LS)==0)
        {printf("Listado de Ficheiros : \n");
         LIST_DIR(modificador); } 
     else if (strcmp(comando,RED_S)==0)
          { REDIR_S(modificador); }
         else if (strcmp(comando,RED_E)==0)
            { REDIR_E(modificador);}
            else if (strcmp(comando,RED_ES)==0)
              { REDIR_ES(modificador);}
               else if (strcmp(comando,CONCAT)==0)
                 {ENCADENA(modificador);}
                 else if (strcmp(comando,BREAK)==0)
                    { CONTROLC(modificador);  } 
                    else if (strcmp(comando,MAN)==0)
                         {  AXUDA();}   
                        else if ((fin=strcmp(comando,SALIR))==0)
                                  {printf("\n\n");}
                              else if (strcmp(comando,"\0")!=0)
                               {     if (fork()==0)
                                      {
                                       Frag_Exec(linea);
                                      }
                                      else 
                                       {wait(0);}  }
                               
                                    
printf("\n");
return(fin);
}



void main(void)
{
char linea[80],comando[80],modificador[80];
int fin;

printf("\n (c) zshell                                     1998 \n"); 
do 
{
printf(Simbolo);
gets(linea);
Separa(linea,comando,modificador);
fin=Inter(linea,comando,modificador);

}
while (fin != 0);

}







