/* 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. */ #include <iostream.h> #include <iomanip.h> #include <fstream.h> #include <strstream.h> /* 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... public: line (TPtr &l, istream &in); // Costruttore che legge dallo stream ed inserisce in lista }; char line::inbuf [MAXLEN]; line::line (TPtr &l, istream &in) : list<line> (l) { colori = 0; // Lista inizialmente vuota 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 istrstream istr(inbuf); // Crea un istrstream con la linea letta while (istr) // Loop fino a che ho caratteri nell'istrstream { 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); } } } 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; } while (in) // Finche' lo stream non e' in errore (EOF) new line (l,in); // Costruisce una nuova 'line' estraendola dal file 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; }