Il programma trivia contenuto nell’archivio chiede una serie di domande “banali” all’utente della forma:
Di che colore e' il cavallo ..... di Napoleone?
dove ….. è un colore scelto casualmente. L’utente deve rispondere con il colore corretto, che viene confrontato carattere per carattere. Non è necessario usare un separatore alla fine del colore perché trivia leggerà un numero di caratteri uguale a quello del colore atteso (caratteri che non sono lettere minuscole vengono comunque ignorati dal programma).
Normalmente il programma legge e scrive su terminale. E’ possibile specificare due pipe come argomenti da riga di comando usando rispettivamente le opzioni -i (input) e -o (output). In tale caso trivia crea le due pipe e le utilizza per comunicare. Alla fine dell’esecuzione le pipe vengono eliminate. Ad esempio:
$ ./trivia -i /tmp/pipeIn -o /tmp/pipeOut
L’obiettivo della verifica è di realizzare un programma che, usando le pipe, legga la domanda (dalla pipe di output -o) e risponda con il colore corretto (sulla pipe di input -i) a tutte le domande poste. Quando tutte le risposte sono corrette il programma termina con la stampa:
[*] Congratulazioni! Hai superato il trivia quiz!
Il programma supporta altre opzioni:
-v attiva la modalità verbosa.
-h mostra le opzioni supportate.
Segue un esempio di esecuzione dove l’interazione avviene tramite standard input e standard output.
$ ./trivia
Di che colore è il cavallo grigio di Napoleone?grigio
Di che colore è il cavallo rosa di Napoleone?rosso
[ERRORE] letto s invece di a
$
Suggerimenti
Non è necessario bufferizzare il colore che leggete dalla pipe e costruire una stringa in quanto potete usare direttamente l’altra pipe come buffer.
Il programma trivia crea e distrugge le pipe. Quando dovete testare la vostra soluzione, invocate prima trivia poi il vostro programma.
Per rendere eseguibile il programma utilizzare chmod +x nome, es. chmod +x trivia-x86-64
Note (per tutte le verifiche)
Programmi che non compilano o non superano il testnon verranno valutati (non consegnateli).
Solo i programmi funzionanti verranno valutati in base ai commenti. Commentate in maniera appropriata il vostro programma e inserite un commento iniziale in cui spiegate l’idea risolutiva e specificate in che modo dobbiamo invocare il programma trivia per testare la vostra soluzione. Soluzioni non commentate non saranno valutate. Vedere la soluzione sotto per un esempio di commenti appropriati ed esaurienti.
NON COPIATE E NON FATE COPIARE! (Nel caso di soluzioni copiate verrà annullata la verifica di chi copia e chi ha fatto copiare indistintamente)
/*
* Soluzione del trivia quiz per il corso di Sistemi Operativi 2019
* Prima verifica: pipe
*
* NOTA: Eseguire in questo modo per evitare che parta prima che trivia
* abbia creato le pipe
*
* ./trivia -i /tmp/pipeIn -o /tmp/pipeOut & (sleep 1; ./soluzione )
*
* in alternativa lanciare i due programmi su due terminali diversi
*
* Author: Riccardo Focardi
*
* Commento generale (necessario per una valutazione positiva):
*
* La soluzione proposta consiste in un ciclo while(1) che svolge
* le seguenti operazioni:
*
* 1. Legge dalla pipe di output del programma trivia il prefisso della
* domanda "Di che colore e' il cavallo " costituita da 28 (PREFIX)
* caratteri e lo ignora;
* 2. Legge dalla pipe di output del programma trivia il colore che è
* costituito da una parola di lettere minuscole e lo invia, carattere
* per carattere, sulla pipe di input del programma trivia. Usando
* questa tecnica non è necessario bufferizzare la stringa
* corrispondente al nome del colore. Di fatto si utilizza la pipe di
* input di trivia come buffer (vedi il primo suggerimento);
* 3. Legge dalla pipe di output di trivia la parte rimante della domanda
* " di Napoleone?" e lo ignora. E' sufficiente leggere tutti i
* caratteri fino al punto di domanda.
*
* Si noti che il punto 3 è fondamentale per mantenere le letture
* sincronizzate: quando viene letta la domanda successiva, quella
* precedente deve essere stata rimossa dalla pipe di output di trivia
*
* Si noti inoltre che tutte le letture avvengono carattere per carattere
* questo ci dà, in generale, maggiore controllo sulla quantità di byte
* letti. Si ricordi, infatti, che il terzo parametro della read indica
* il numero massimo di byte da leggere e non viene necessariamente
* raggiunto in una lettura.
*/
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define pipeIn "/tmp/pipeIn"
#define pipeOut "/tmp/pipeOut"
#define PREFIX 28
int main() {
int fd0,fd1;
int i;
char c;
/*
* Apre pipeOut in lettura e pipeIn in scrittura. Se una delle
* due operazioni di apertura fallisce stampa un messaggio di
* errore e termina l'esecuzione
*/
if ((fd0=open(pipeOut,O_RDONLY))<0 || (fd1=open(pipeIn,O_WRONLY))<0){
perror("errore apertura pipe"); // messaggio di errore
exit(EXIT_FAILURE); // termina l'esecuzione
}
while(1) {
/*
* Legge il prefisso "Di che colore e' il cavallo " che è
* lungo esattamente 28 caratteri (PREFIX)
*/
for(i=0;i<PREFIX && read(fd0,&c,1);i++);
/*
* Quando la pipe pipeOut viene chiusa dal programma trivia
* la read ritorna 0 prima che i abbia raggiunto PREFIX
* e usciamo dal programma.
* Questo permette di riconoscere il caso in cui abbiamo
* riposto correttamente a tutte le domande in quanto non
* ci sarà una successiva domanda e la read ritornerà zero
* alla prima iterazione (i==0)
*/
if (i<PREFIX) exit(EXIT_SUCCESS);
/*
* legge da pipeOut finché il carattere letto è una lettera
* minuscola. Ogni carattere letto viene scritto immediatamente
* su pipeIn in modo da non dover costruire una stringa. Di
* fatto pipeIn funge da buffer.
*/
while(read(fd0,&c,1) && c>='a' && c<='z') {
write(fd1,&c,1); // manda il colore carattere per carattere
}
/*
* legge il resto della domanda, ovvero ogni carattere finché
* non viene letto il punto di domanda. Questo è fondamentale
* per tenere la lettura in 'sync'. Se non svuotiamo la pipe
* dal resto della domanda " di Napoleone?" la lettura successiva
* leggerà proprio quei caratteri perdendo la sincronizzazione
*/
while(read(fd0,&c,1) && c!='?');
}
}
Video che mostra come arrivare alla soluzione sopra, step-by-step: