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