PDA

View Full Version : [C]:minishell


mercury841
17-04-2006, 20:22
Ciao ragazzi ho bisogno di un aiuto con questo esercizio :

Scrivere una mini schell che iterativamente legge una riga di testo ed esegue il suo contenuto in un processo dedicato (attendendo la terminazione di questo processo). La shell termina col comando stop. (Suggerimenti: per la lettura della linea di comando si puo usare la funzione della libreria c fgets).

Questo è il codice che fino ad ora ho prodotto:


#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main (int argc, char *argv[]){

int pid;
int status;
char *stringa;



stringa=calloc(20,sizeof(char));
if ((stringa=fgets(stringa,20,stdin)) == NULL) exit(1);

while ( strncmp(stringa,"stop",4) != 0){
if ( (pid = fork()) < 0){
perror("fork");
exit(1);
}else{
if (pid == 0){//figlio
if ( execlp(stringa,stringa,(char *)0) < 0 )
perror("execlp"),exit(1);
}else{//padre
//aspetto la terminazione di mio figlio
wait(&status);
}//fine else padre
}//fine else

if ((stringa=fgets(stringa,20,stdin)) == NULL) exit(1);
}//fine while


exit (0);
}


Una volta letta la stringa iterativamente, come mando in esecuzione la stringa? Ho provato con execlp(stringa,stringa,(char *)0) però non funziona.
Grazie per l'attenzione.

shinya
17-04-2006, 20:46
Dai un'occhiata qui: http://www.advancedlinuxprogramming.com/alp-folder

E' un ottimo libro, ed è g-r-a-t-i-s!

andbin
17-04-2006, 22:21
Una volta letta la stringa iterativamente, come mando in esecuzione la stringa? Ho provato con execlp(stringa,stringa,(char *)0) però non funziona.Intanto ti consiglio di usare un ciclo do-while invece di un while. Il motivo è semplice: la lettura della stringa la devi fare comunque almeno 1 volta, quindi un do-while è più opportuno e logico.

Per la execlp, ti dico subito che dovresti gestire la cosa in modo un po' diverso. Ognuna delle funzioni execXX (ce ne sono ben 5) si aspetta un certo numero di parametri da passare all'nuovo processo. Le exec con la "l" si aspettano una lista di argomenti terminata da un NULL, mentre le exec con la "v" si aspettano un array di char* il cui ultimo elemento è un NULL.

Se in input prendi la stringa "ls -la /etc", dovresti spezzare tu in qualche modo la stringa in modo da ottenere N stringhe, ad esempio: "ls", "-la" e "/etc". La prima stringa è il primo parametro (il nome del programma) da passare alla exec e le restanti stringhe sono gli argomenti. Qundi credo che sia molto meglio usare una delle exec che accetta un array. Creare un array è facile e ti risolve brillantemente il problema.

mercury841
17-04-2006, 22:41
Intanto ti consiglio di usare un ciclo do-while invece di un while. Il motivo è semplice: la lettura della stringa la devi fare comunque almeno 1 volta, quindi un do-while è più opportuno e logico.

Per la execlp, ti dico subito che dovresti gestire la cosa in modo un po' diverso. Ognuna delle funzioni execXX (ce ne sono ben 5) si aspetta un certo numero di parametri da passare all'nuovo processo. Le exec con la "l" si aspettano una lista di argomenti terminata da un NULL, mentre le exec con la "v" si aspettano un array di char* il cui ultimo elemento è un NULL.

Se in input prendi la stringa "ls -la /etc", dovresti spezzare tu in qualche modo la stringa in modo da ottenere N stringhe, ad esempio: "ls", "-la" e "/etc". La prima stringa è il primo parametro (il nome del programma) da passare alla exec e le restanti stringhe sono gli argomenti. Qundi credo che sia molto meglio usare una delle exec che accetta un array. Creare un array è facile e ti risolve brillantemente il problema.


Si infatti ci avevo pensato, solo che speravo ci fosse un modo più semplice oppure che si potesse eseguire direttamente tutta la stringa. Grazie per l'aiuto e per la disponibilità,ciao

andbin
17-04-2006, 22:50
Si infatti ci avevo pensato, solo che speravo ci fosse un modo più semplice oppure che si potesse eseguire direttamente tutta la stringa.No, purtroppo le exec ti obbligano a gestire gli argomenti come stringhe separate. Comunque ti assicuro che non è complicatissimo creare dinamicamente un array di char*, spezzare la stringa in input e richiamare la exec.

mercury841
18-04-2006, 14:20
Mi potreste dare una mano nell'allocazione di un array di stringhe?Ciao e grazie

andbin
18-04-2006, 14:31
Mi potreste dare una mano nell'allocazione di un array di stringhe?Ciao e grazieCerto! Bisogna solo vedere quanto, per te, è accettabile per dimensionare correttamente l'array.
Mi spiego meglio: se hai in input una stringa lunga al massimo 40 caratteri, supponendo di avere 1 car., 1 spazio, 1 car., ecc..., risulta che puoi avere al massimo 20 parametri.
Ora, 20 parametri sono pochi e l'array lo si potrebbe dichiarare (senza fare nemmeno allocazioni dinamiche) come:
char *stringhe[21]; /* uno in più per il NULL finale */
Oppure lo si può allocare dinamicamente specificando una dimensione fissa oppure ancora (soluzione più complessa però) creare una specie di array ridimensionabile a run-time, un po' come succede in altri linguaggi.

Insomma, dipende molto da come vuoi gestire il numero dei parametri.

mercury841
18-04-2006, 15:01
Certo! Bisogna solo vedere quanto, per te, è accettabile per dimensionare correttamente l'array.
Mi spiego meglio: se hai in input una stringa lunga al massimo 40 caratteri, supponendo di avere 1 car., 1 spazio, 1 car., ecc..., risulta che puoi avere al massimo 20 parametri.
Ora, 20 parametri sono pochi e l'array lo si potrebbe dichiarare (senza fare nemmeno allocazioni dinamiche) come:
char *stringhe[21]; /* uno in più per il NULL finale */
Oppure lo si può allocare dinamicamente specificando una dimensione fissa oppure ancora (soluzione più complessa però) creare una specie di array ridimensionabile a run-time, un po' come succede in altri linguaggi.

Insomma, dipende molto da come vuoi gestire il numero dei parametri.

Si grazie per l'aiuto. Se invece non volessi dare una dimensione fissa all'array ma di volta in volta a seconda del numero di parametri riallocarmi lo spazio necessario con l'utilizzo di realloc????

andbin
18-04-2006, 15:17
Si grazie per l'aiuto. Se invece non volessi dare una dimensione fissa all'array ma di volta in volta a seconda del numero di parametri riallocarmi lo spazio necessario con l'utilizzo di realloc????Si può fare (e in mille modi diversi ;) ).

Io ad esempio farei così: una struttura
typedef struct
{
char **strings;
int size;
int capacity;
} STRING_ARRAY;
Poi farei una serie di funzioni, per 1) Inizializzare la struttura, 2) De-inizializzare la struttura, 3) Aggiungere una stringa all'array.

Poi tutta la "logica" di (ri)allocazione dell'array è da fare ovviamente!
Pensaci un po', poi al massimo butto giù (appena ho tempo) del codice.

mercury841
18-04-2006, 23:31
Ho fatto in questo modo, sembra funzionare. Mentre se utilizzo la funzione dealloca, che adesso è commentata nel codice, non funziona.Qualcuno ha idea di quale sia il motivo?????

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>


char **crea_vettore(char *stringa);
void dealloca(char **array_di_stringhe);

int main (int argc, char *argv[]){

int pid,i;
int status;
char *stringa;//stringa dove memorizzo la stringa dei comandi
char **stringhe; //array di stringhe



stringa=(char *)calloc(20,sizeof(char));

if ((stringa=fgets(stringa,20,stdin)) == NULL) exit(1);
while ( strncmp(stringa,"stop",4) != 0){

stringhe=crea_vettore(stringa);
if ( (pid = fork()) < 0){
perror("fork");
exit(1);
}else{
if (pid == 0){//figlio
if ( execvp(stringhe[0],stringhe) < 0 )
perror("execvp"),exit(1);
}else{//padre
//aspetto la terminazione di mio figlio
wait(&status);
//dealloca(stringhe);//libero memoria
}//fine else padre
}//fine else

if ((stringa=fgets(stringa,20,stdin)) == NULL) exit(1);
}//fine while


exit (0);
}

char **crea_vettore(char *stringa){

char **stringhe;
char *parola=NULL;
int i=0,
size=1,
j=0;

if ((stringhe=(char **)malloc(size*sizeof(char *))) == NULL)
perror("malloc"),exit(1);//errore allocazione

while ( stringa[i] != '\0' ){//scandisco tutta la stringa e la divido in tante parole

while ( (stringa[i] != ' ') && (stringa[i] != '\0') && (stringa[i] != '\n')){
//costruisco la parola
parola=(char *)realloc(parola,(j+1)*sizeof(char *));
parola[j]=stringa[i];
j=j+1;
i=i+1;
}
if ( ( stringa[i] == ' ') || (stringa[i] == '\n') )
i=i+1;
printf("parola= %s\n",parola);
if (parola != NULL){//parola trovata
stringhe=(char **)realloc(stringhe,(size+1)*sizeof(char *));
if ( (stringhe[size-1]=(char *)malloc(strlen(parola)+1)) == NULL)
perror("malloc"),exit(1);//errore allocazione
strcpy(stringhe[size-1],parola);
size=size+1;
}
parola=NULL;
j=0;
}
stringhe[size-1]=NULL;//fine dell array di stringhe

return (stringhe);
}


void dealloca(char **array_di_stringhe){

int i=0;

while ( array_di_stringhe[i] != NULL ){
free(array_di_stringhe[i]);
i=i+1;
}
free(array_di_stringhe[i]);
free(array_di_stringhe);
return;

}