I'm actually doing my whole shell in C from scratch from a Linux computer. The thing is that I think we all do our best from creating the simplest things that can be explained easily. And I'm not sure my shell has these qualities.
All command I tried worked but command 1 | command 2 | command 3 or command 1 | command 2 > command 3. I would be glad if you had any ideas but I'm okay with it. My point is that this code it a bit heavy and I'm sure it could have been done easier.
If you have any idea to make it simpler, I would be glad to hear it.
This shell is constructed this way:
The main method calls a command function which calls a parsing function which reads the function written by the user, fills an array with the function and returns a number for each delimiter. The command is constructed by case and does an execvp on the array with the command. The thing that I'm not allowed to modify is the parsing function.
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
char *delimiteurs = ";&<>|";
char *respP[10]; // tableau contenant la commande a executer
char *fout[10];// tableau qui affiche le resultat de l'istruction shell lue dans fin
char *fin[10]; // la méthode commande va exécuter une instruction shell lue dans le tableau fin elements par element grace a parsing
char *tube[10]; // tube qui assusre la communication entre deux processus
char mot[50];
int symboleP, status, c;
void parsing(){
int i=0;
int cmot=0;
while(1){
c = getchar();
if (c == '\n') {symboleP = 0;return;}
else if (c == ';') {symboleP = 1;return;}
else if (c == '&') {symboleP = 2;return;}
else if (c == '<') {symboleP = 3;return;}
else if (c == '>') {symboleP = 4;return;}
else if (c == '|') {symboleP = 5;return;}
else if (c == EOF) {symboleP = 7;return;}
else if (c != ' ') {
symboleP = 10;
while(c != '\n' && !strchr(delimiteurs,c)){
i=0;
while(c != 32 ){ // 32 correspond a un caractère dans la table ascii
if((c != '\n') && !strchr(delimiteurs,c)){
mot[i]=c;i++;
c=getchar();
}
else {break;}
}
break;
}
while(c == ' ')
{
c=getchar();
}
ungetc(c,stdin); //
mot[i]=0;
respP[cmot++]=strdup(mot); // fonction strdup renvoie l'adresse de la nouvelle chaine de caractère qui vient dêtre duppliquer ou sinon NULL --> alloue de l'espace necessaire pour stoker au mot
fflush(stdout);
if(c == '\n' || strchr(delimiteurs,c)) //
{
respP[cmot]=0;
return;
}
}
}
}
void commande () {
pid_t pid, fid;
int background = 0;
int status;
char car;
int i, j, k, l;
int p, p2;
int execute=1;
int output=0;
int input=0;
int tube=0;
int fd[2];
int fich, fo, screen;
while(1){
if(execute==1){
if(symboleP==0){
printf("DAUPHINE> ");
}
for (j=0;j<10;j++){
respP[j]=NULL;
}
execute=0;
background=0;
}
fflush(stdout);
parsing();
switch (symboleP) {
case 0 : // SYMBOLE : \n
p=fork();
//Mettre un if pour que le père observe le fils (exec dans le fils
if(p==0){ //fils
if(tube==1){//printf("\n\n\n");
fich = open("fichtmp",O_RDONLY,0640);
close(0);
dup(fich); //fichier devient entrée 0
execvp(respP[0], respP);
close(fich); //fermeture fichier
}
else if(output==0 && input==0){ //pas de redirection
execvp(respP[0], respP);
}else if(output==1){ //dans le cas d'une redirection
printf("truc2");
close(1); // extrémité a ecrire close (1)
int filout = creat(respP[0], 0644); // fichier de sortie
execvp(fout[0], fout); // processus père ce dédouble attend la reponse du fils et c'est le fils qui va etre remplacé par la commande a exécuté
}
else if(input==1){
printf("truc3");
close(0); // on ferme lextrémité que nous allons pas utilisé: close(0) etremité a lire
int filin = open(respP[0], O_RDONLY); // fichier d'entrée
execvp(fin[0], fin);
}
return 0;
}else{ //pere
if(background==0){ //pas de bg on attend le fils
waitpid(p, NULL, 0);
}
output=0;
input=0;
execute=1;
tube=0;
}
break;
case 1: // SYMBOLE : ;
p=fork();
if(p==0){ //fils
if(output==0 && input==0 && tube==0){ //pas de redirection
execvp(respP[0], respP);
}else if(output==1){ //dans le cas d'une redirection
close(1);// pour ecrire dna sun fichier on close la lecture
int filout = creat(respP[0], 0644);// fichier de sortie
execvp(fout[0], fout);
}
else if(input==1){
close(0); // pour lire un fichier on close l'ecriture
int filin = open(respP[0], O_RDONLY); // juste lecture comme mode
execvp(fin[0], fin);
}
return 0;
}else{ //pere
waitpid(p, NULL, 0);
output=0;
input=0;
execute=1;
}
break;
case 2: // SYMBOLE : &
background=1;
break;
case 3: // SYMBOLE : <
if(input==0){
input=1;
execute=1;
for (l=0;l<10;l++){
fin[l]=respP[l];
}
}
break;
case 4: // SYMBOLE : >
if(output==0){
output=1;
execute=1;
for (l=0;l<10;l++){
fout[l]=respP[l];
}
}
break;
case 5: // SYMBOLE : |
//if(tube==0){
screen = dup(1);
close(1);
fo = open(".pipe", O_CREAT | O_TRUNC | O_RDWR, 0640);
dup(fo);
p2 = fork();
if(p2 == 0){
execvp(respP[0],respP);
}
else{
wait(&status);
close(1);
close(fo);
dup(screen);
//printf("Retour de l'écran \n");
//printf("w = %s \n", w);
//printf("com[0] = %s \n",com[0]);
i = 0;
respP[i++] = strdup(mot);
//com[i++] = 0;
parsing();
respP[i++] = strdup(mot);
respP[i++] =0; int keyboard;
keyboard = dup(0);
close(0);
fo = open(".pipe", O_RDWR, 0640);
dup(fo);
//printf("Avant le 2nd fork \n");
p2 = fork();
if(p2 == 0){
//printf("IN PID, w = %s \n",w);
//printf("IN PID, com[0] : %s \n",com[0]);
execvp(respP[0],respP);
}
else{
wait(&status);
close(0);
close(fo);
dup(keyboard);
i = 0;
return 0;
}
//dup(screen);
}
//return 0;
break;
default:
printf("");
}
}
return 0 ;
}
int main(int argc, char* argv[]) {
int i, j, k, l;
int execute=1;
while(1){
if(execute==1){
if(symboleP==0){
printf("");
}
for (j=0;j<10;j++){
respP[j]=NULL;
}
execute=0;
}
commande();
}
return 0 ;
}