/* 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;
}