Listing 1: Source code for HTML class


//hello.cpp
#include "html.h"
void
main(int argc, char *argv[]){
    Pause::init(argc, argv);
    cout << (Html() << "Hello, world!");
    }
//html.h
#if !defined(HTML_DEFINED)
#define HTML_DEFINED
#include "strClass.h"
    class
BlockOption : public String{
    friend ostream& operator << ( ostream& out, BlockOption& option);
protected:
    String name;
public:
    BlockOption(BlockOption& b) :
        String((String&) b), name(b.name){}
    BlockOption(const char * const _name, 
                const char * const value):
        name(_name), String(value){}
    BlockOption(const char * const _name) : name(_name){}
    CAST_INJECTORS(BlockOption)
    };
CAST_IOMANIP(BlockOption)
ostream& operator << ( ostream& out, BlockOption& b);
class Block;
ostream& operator << ( ostream& out, Block& b);
class Block : public String {
    friend ostream& operator << ( ostream& out, Block& b);
protected:
    String tag;
    BlockOption* option[10];
    unsigned blockOptionCount;
public:
    Block():tag(),blockOptionCount(0){}
    Block(const char * const _tag):
        tag(_tag),blockOptionCount(0){}
    Block( Block& sourceBlock);
    ~Block();
    Block& operator<<( BlockOption& opt );
    Block& filter(const char * text);
    CAST_INJECTORS(Block)
    Block& operator<< ( Block& b ){
        (ostrstream&)*this << b;
        return *this;
        }
};
CAST_IOMANIP(Block)
class Anchor : public Block{
public:
      Anchor(const char * const ref) : Block("a"){
        (Block&)*this << BlockOption( "HREF", ref);
        }
    CAST_INJECTORS(Anchor)
Anchor& filter(const char * text)
    { ((Block&)*this).filter(text); return *this;}
};
CAST_IOMANIP(Anchor)
class Html : public Block {
    friend ostream& operator << ( ostream& out, Html &html);
protected:
    String title;
    int isIndex;
    static int responseHeader;
public:
    Html(const char * const _title, int _isIndex =0) : 
        Block("body"), title(_title), isIndex(_isIndex){};
    Html() : Block("body"), title(), isIndex(0){};
    static void noResponseHeader(){ responseHeader =0;}
    CAST_INJECTORS(Html)
    Html& operator << ( Block& b ) {
        ((ostrstream&)(Block&)(*this)) << b ;
        return *this;
        }
    Html& filter(const char * text)
        { ((Block&)*this).filter(text); return *this;}
};
CAST_IOMANIP(Html)
ostream& operator << ( ostream& out, Html &html);
#endif
//html.cpp
#include "html.h"
void message( char* code, unsigned long line,
              char* file, char* date){
    cout << (
        Html("Error")
        << (Block("H1") << "Error!")
        <<    (Block("DL")
            << "\n<DT>CODE<DD>" << code
            << "\n<DT>LINE<DD>" << line
            << "\n<DT>FILE<DD>" << file
            << "\n<DT>DATE<DD>" << date
            << "\n"
            )
        );
    }
//********************* Block messages ************************
    Block& Block :: operator<< ( BlockOption& opt ){
        if(blockOptionCount < 10)    // Deep copy the option
            option[blockOptionCount++] = new BlockOption(opt);
        return *this;
    }
    Block::Block( Block& b): String(b), tag(b.tag){
        for(blockOptionCount =0;
            blockOptionCount < b.blockOptionCount;
            blockOptionCount++
            )
            option[blockOptionCount] =
                new BlockOption(*b.option[b.blockOptionCount]);
    }
    Block::~Block(){
        unsigned k =0;
        while(k < blockOptionCount) delete option[k++];
    }
    Block& Block::filter(const char * text){
        char *s =(char*)text, c;
        while( (c =*s++) != 0 )
            switch(c){
                case '&':  *this << "&amp"; break;
                case '<':  *this << "&lt";  break;
                default:  *this << c;
            }
        return *this;
    }
    ostream& operator<< ( ostream& out, Block& b){
        out << "<" << b.tag;
        unsigned k =0;
        while(k < b.blockOptionCount)
            out << b.option[k++];
        out << ">" ;
        return out << (String&)b << "</" << b.tag << ">\n";
    }
//********************* BlockOption **************************
    ostream& operator<< ( ostream& out, BlockOption& b){
        out << " ";
        out << b.name;
        out << "=\"";
        out << (String&)b;
        out << "\"";
        return out;
    }
//******************** Html messages *************************
    int Html::responseHeader =1;
    ostream& operator<<( ostream& out, Html& body){
        Block htmlBlock("html");
        if( body.title.notNull() || body.isIndex ){
            Block head("head");
            if(body.title.notNull()){
                Block title("title");
                title << body.title;
                head << title;
                }
            if( body.isIndex )
                head << "<isIndex>";
            htmlBlock << head;
            }
        htmlBlock << (Block&)body;
        if(Html::responseHeader)
            out << "Content-type: text/html\n\n";
        else
            out << "Suppress:  Content-type: text/html\n\n";
        return out << htmlBlock << endl;
    }
//strClass.h
#if !defined(STRINGCLASS_DEFINED)
#define STRINGCLASS_DEFINED
#include <strstrea.h>
#include <string.h>
/************************ Pause *****************************
To force a pause() at exit, include:
    Pause::init(argc, argv);
at the beginning of main(), and include "-pause"
as a command line arguement.
*/
class Pause{
    static char *programName;
    static int noPause;
    friend ostream& operator<<(ostream& out, Pause& pause);
    friend void pause();
public:
    static void init(int argc, char *argv[]);
  };
//************************ String *****************************
//    ostream& operator <<(ostream& out, Pause& pause);
#define MESSAGE(s) message(#s,__LINE__,__FILE__,__DATE__)
#define ASSERT(s) if((s)==NULL){ \
    MESSAGE(s); \
    exit(1); \
    }
extern void message( char* code, unsigned long line, 
                     char* file, char* date);
#define CAST_INJECTORS(CLASS) \
    CLASS& operator<< (char _c) { \
        (ostrstream&)*this << _c;    return *this; } \
    CLASS& operator<< (signed char _c) { \
        (ostrstream&)*this << _c;    return *this; } \
    . . .
    //portions omitted to save space
    //complete macro available on code disk -- mb
    . . .
#include <iomanip.h>
#ifdef _MSC_VER // for Microsoft's parameterized io manipulators
#define CAST_IOMANIP(CLASS) \
    inline CLASS& operator \
<<(CLASS& _s, const SMANIP(int)& _f) { \
    (ostream&)_s << _f ; return _s; \
    } \
    inline CLASS& operator \
<<(CLASS& _s, const SMANIP(long)& _f) { \
    (ostream&)_s << _f ; return _s; \
    }
#else // for Borland's template class io manipulators
#define CAST_IOMANIP(CLASS) \
    inline CLASS& operator \
<<(CLASS& _s, smanip<int>& _f) { \
    (ostream&)_s << _f ; \
    return _s; \
    } \
    inline CLASS& operator \
<<(CLASS& _s, smanip<long>& _f) { \
    (ostream&)_s << _f ; \
    return _s; \
    }
#endif
class String : public ostrstream{
    String& replace(const char * const str);
public:
    CAST_INJECTORS(String)
    String() : ostrstream(){}
    String(const char * const s){(ostrstream&)*this << s;}
    String(String& str){
        if(str.notNull())
            (ostrstream&)*this << (const char * const)str;
    }
    String& testType(){ return *this;}
    String& setNull();
    int notNull(){ return rdbuf()->out_waiting();}
    int isNull(){ return !notNull();}
    String& operator= (const char * const val) {
        return replace(val);
        }
    int operator!= ( String& val) {
        return (strcmp((char*)*this,(char*)val) != 0);
        }
    int operator== ( String& val) {
        return !strcmp((char*)*this,(char*)val);
        }
    operator char*  (void);
};
    inline ostream& operator<<(ostream& out, String& s){
    return (out << (char *)s);
    }
CAST_IOMANIP(String)
#endif
//strClass.cpp
#include "strClass.h"
#include <stdlib.h>
void pause(){
    cerr << Pause::programName 
         << ":  press [Enter] to continue...";
    cin.unsetf(ios::skipws);
    char x;
    cin >> &x;
    cin.clear();
    cin.setf(ios::skipws);
}
//********************* Pause messages ************************
int Pause::noPause = -1;
char* Pause::programName ="";
void Pause::init(int argc, char *argv[]){
    programName = *argv++;
    if(noPause == -1){
        noPause = 1;
        while( --argc && noPause )
            if( !strcmp( *argv++, "-pause") ){
                noPause =0;
                atexit(pause);
                }
        }
}
//******************** String messages *************************
String::operator char*  (void){
    streampos pos =tellp();
    (ostrstream&)*this << ends; //append null byte to the buffer
    char *s =str();             // get a pointer to the buffer
    rdbuf()->freeze(0);         // unfreeze the buffer
    seekp(pos);          //backup over the terminal null byte
    ASSERT((ios&)*this); //test for inability to allocate buffer
    return s;
    }
String& String::setNull(){
    seekp(0);                // rewind the buffer
    rdbuf()->freeze(0);    // unfreeze the buffer
    return *this;
    }
String& String::replace(const char * const str){
    return setNull() << str; // put the new string in the buffer
    }
//End of File