/* Programma html.cc: * Scrivere un programma C++ che, utilizzando le classi stream, legga un file di testo in HTML e: * Definisca una classe template 'lista' * Costruisca una classe 'linea' derivata da 'lista' che immagazzinerà una linea di * testo del file (le linee non supereranno * mai i 300 caratteri) * Inserisca in una lista le linee lette * Definisca una classe 'colore' che ha tre attributi interi chiamati R, G e B, derivata da lista * La classe 'linea' conterrà un puntatore alla classe 'colore', per gestire una lista di 'colori'. * Il costruttore della classe 'linea' eseguirà una scansione della linea stessa, alla ricerca di * stringhe del tipo '#RRGGBB' * che descrivono un colore. Ogni volta che individuerà una tale stringa, la analizzerà, interpretando * ogni coppia di lettere * (RR, GG e BB) come coppie di cifre esadecimali. * Per ogni stringa '#RRGGBB' costuirà una nuova istanza della classe 'colore' che conterrà i valori * dei tre colori base * estratti dal testo, inserendoli nella propria lista di colori. * Per finire verrà stampato il testo HRML, riga per riga, stampando dopo ogni riga l'elenco dei colori * utilizzati in quella * riga, in decimale, allineati ordinatamente. * Modificare il programma in modo che: * Il programma si fermi se incontra il colore di valore R=255 G=0 B=0. * Il costruttore di 'line' non individui direttamente i colori nella linea, ma richiami un metodo * creacolore che ricevera' come parametro l'istrstream contenente la linea letta e creerà il 'colore' * se ne trova uno * Il costruttore userà un loop infinito per leggere i colori, la terminazione avverrà tramite un'eccezione. * Il metodo creacolore potrà lanciare due eccezioni di tipo diverso: * 1.se l'istrstream va' in errore (se finisce la stringa) * 2.se viene letto il colore R=255 G=0 B=0 (valore 0xff0000) * Il costruttore di 'line' lancerà un'eccezione se il file di ingresso và in errore (EOF) * La funzione principale esegua un loop infinito per creare le istanze di 'line', ma * 1.Gestirà l'eccezione inviata dal costruttore di 'line' per 'EOF', terminando regolarmente * 2.Gestirà l'eccezione inviata da creacolore stampando un opportuno messaggio e terminando ancora regolarmente */ #include <iostream.h> #include <iomanip.h> #include <fstream.h> #include <strstream.h> /* Classi per le eccezioni (costituiscono il tipo dell'eccezione) */ class lineEndException { // Eccezione per 'fine linea' }; class colorException { // Eccezione per 'colore rosso' }; class fileEndException { // Eccezione per 'fine file' }; /* Classe template list * Per consentire di gestire elementi di tipi diversi (derivati), con gli * opportuni tipi di ritorno e per i parametri, deve essere una classe * template. */ template <class T> class list { list *next; // Puntatore al prossimo della catena protected : // Definisco un tipo puntatore a classe finale, per costruire // variabili passate per riferimento (un puntatore non va bene) typedef T *TPtr; // Funzione che inserisce il nuovo elemento in coda alla lista void append (list *newEl) { if (next) next -> append (newEl); else next = newEl; }; // Funzione virtuale pura che stampera' l'elemento virtual void print () = 0; public : // Costruttore: si aggiunge in coda ad una lista 'base' list (TPtr &base) { next = 0; if (base) ((list*)base) -> append (this); else base = (T*) this;}; // Funzione pubblica che stampa l'intera lista, se chiamata sulla base void printall () { print (); if (next) next -> printall ();}; // Distruttore virtuale - distrugge tutti gli elementi della lista virtual ~list () { if (next) delete next; }; }; class colore : public list<colore> { int r,g,b; // I valori dei colori primari di questo colore // Metodo di stampa, stampa le componenti del colore virtual void print () { cout << "Colore R=" << setw (3) << setfill ('0') << r << " G="<< setw (3) << setfill ('0') << g << " B="<< setw (3) << setfill ('0') << b << endl; }; public: // Costruttore: Ininzializza la superclasse ed i colori primari colore (TPtr &l, int R, int G, int B) : list<colore> (l) { r=R; g=G; b=B; }; }; class line : public list<line> { static const int MAXLEN = 300; // Costante: dimensione del buffer static char inbuf [MAXLEN]; // Buffer statico per la lettura delle linee char *content; // Puntatore alla linea corrente colore *colori; // Lista dei colori della linea virtual void print (); // Funzione di stampa, ridefinisce la virtuale pura... // Metodo 'cercacolore' che lancia un'eccezione... void cercacolore (colore **colori, istrstream &istr); public: line (TPtr &l); // Costruttore che legge dallo stream ed inserisce in lista void build (istream &in); }; char line::inbuf [MAXLEN]; /* Metodo che analizza l'istrstream passato come aprametro per individuare * un 'colore' (stringa '#RRGGBB'). Lancia un'eccezione 'lineEndException' * se lo stram finisce (fine linea) ed una 'colorException' se incontra il * colore rosso (#FF0000). */ void line::cercacolore (colore **colori, istrstream &istr) { colorException c; // Eccezione 'colore' lineEndException e; // Eccezione 'fine linea' istr.ignore (MAXLEN,'#'); // Scarta caratteri fino al prossimo '#' if (istr) // Se con questo non ha esaurito la stringa { char colorbuf [7]; // Buffer per i sei caratteri da leggere (+ null) istr.width (7); // indica al nostro strstream quanto e' lunga la nostra stringa istr >> colorbuf; // Estrae da istr 6 caratteri + 1 terminatore (visto che non ho spazi) istrstream icol (colorbuf); // Creo un'altro istrstream per convertire il dato int col = -1; // Numero che conterra' i colori (tutti insieme) icol >> hex >> col; // Estraggo il numero HEX a 6 cifre dalla nostra stringa if (col >= 0) // Se ha letto veramente il dato (non era errato) // Creo un nuovo 'colore' spezzando il numero letto tramite rotazioni e maschere new colore (*colori, (col >> 16) & 0xff, (col >> 8) & 0xff, col & 0xff); if (col == 0xff0000) // Se riconosce il colore rosso (#ff0000) throw (c); // Lancia l'eccezione 'colorException' } else // Se 'istr' e' in errore (fine linea) throw (e); // Lancia l'eccezione 'lineEndException' } /* Metodo che 'riempie' la struttura 'line' leggendo i dati dal file. * Occorre un metodo diverso dal costruttore, perche' se il costruttore viene * interrotto da un'eccezione, la struttura non viene creata. * Legge una linea dal file e la immagazzina, quindi costruisce * un istrstream sulla linea e lo alanizza con cercacolore */ void line::build (istream &in) { in.getline (inbuf, MAXLEN); // Legge la linea dallo stream content = new char [strlen (inbuf) + 1]; // Alloca lo spazio per la linea if (content) // Se l'allocazione ha avuto successo strcpy (content, inbuf); // Immagazzina la linea letta if (!in) // Se e' finito il file { fileEndException e; // (variabile per lanciare l'eccezione) throw (e); // Lancia l'eccezione 'fileEndException' } istrstream istr(inbuf); // Crea un istrstream con la linea letta try { // --- try block --- while (1) // Loop infinito (interrotto dall'eccezione) { cercacolore (&colori, istr); // Chiama la funzione che estrae un colore } } catch (lineEndException e) { // Intercetta l'eccezione 'lineEndException' return; // ma non l'eccezione 'colorException' } } /* Costruttore che inserisce l'elemento nella lista (tramite i costruttore di 'list') * ed azzera gli attributi */ line::line (TPtr &l) : list<line> (l) { colori = 0; // Lista inizialmente vuota content = 0; } void line::print () { if (content) // Se ha la linea cout << content << endl; // La stampa if (colori) // Se ha la lista dei colori colori -> printall (); // Stampa anche quella } int main (int argc, char **argv) { line *l = 0; if (argc != 2) { cerr << "Il programma va chiamato con un nome di file come parametro" << endl; return -1; } ifstream in (argv [1]); // Costruisce un nuovo ifstream a partire dal nome del file if (!in) // Se e' in stato di errore, non c'era il file { cerr << "Il file " << argv [1] << " non esiste" << endl; return -1; } try { // --- Try block --- while (1) // loop infinito (verra' interrotto dall'eccezione) { (new line (l)) -> build (in); // Costruisce una nuova 'line' e poi la inizializza con il contenuto del file } } catch (fileEndException e) { // Eccezione di 'fine file' prodotta da 'build' cout << "File terminato normalmente" << endl; } catch (colorException e) { // Eccezione di 'colore rosso' prodotta da 'cercacolore' cout << "Incontrato il colore per terminare" << endl; } if (l) // Se ha creato la lista di linee l -> printall (); // La stampa else cout << "Il file " << argv [1] << " era vuoto" << endl; in.close(); // Chiude il file (sarebbe chiuso comunque alla distruzione do 'in') return 0; }