www.digitalmars.com         C & C++   DMDScript  

D - An example of a use of C macros that has not been discussed

reply "Paul Sheer" <psheer icon.co.za> writes:
An example of a use of C macros that has not been discussed
===========================================================

In an embedded http server I wrote, I want all my pages to be in the
constant section, so I defined macros to easily create HTTP pages
with a consistent format, declared all as "const char *". What follows
is an actual sample of code.

I would VERY much like to use D for embedded projects. I believe
it is absolutely essential to be able to manipulate constant data
as in the example below. Even C macros are not powerful enough IMO.

On-the-fly generation of the HTML text is not an option.

-paul

#define RESPONSE_HEADER(n,s) "\
HTTP/1.0 " #n " " #s "\r\n\
Server: PaulOS internal proxy\r\n\
Content-Type: text/html\r\n\
Proxy-Connection: close\r\n\
\r\n\
"

#define RESPONSE_TEXT_HEADER(n,s) "\
HTTP/1.0 " #n " " #s "\r\n\
Server: PaulOS internal proxy\r\n\
Content-Type: text/plain\r\n\
Proxy-Connection: close\r\n\
\r\n\
"

#define HTML_TOP(meta,title,body) "\
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n\
<HTML>\r\n\
<HEAD>\r\n\
<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=ISO-8859-1\">\
" meta "\r\n\
<TITLE>" title "</TITLE>\r\n\
</HEAD>\r\n\
<BODY" body ">\r\n"

#define HTML_BOTTOM "\
<TABLE width=\"100%\" border=\"0\" rules=\"none\" cellspacing=\"0\"
cellpadding=\"0\"><TR><TD align=\"right\">\r\n\
<A href=\"credits\" target=\"_blank\"></A>\r\n\
</TD></TR></TABLE>\r\n\
</BODY></HTML>\r\n"

#define HTML_HEADER(h1,h2) HTML_TOP("", #h1 ": " #h2, "") "\
<TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"
cellspacing=\"0\" cellpadding=\"3\"><TR><TD>\r\n\
<TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"
cellspacing=\"0\" cellpadding=\"5\"><TR><TD>\r\n\
<CENTER><FONT face=\"Arial, Helvetica, sans-serif\"
color=\"#0080FF\"><B>InsTconnect Router</B></FONT></CENTER>\r\n\
</TD></TR></TABLE>\r\n\
</TD></TR></TABLE>\r\n\
<P><FONT size=\"+2\"><B>" #h1 "</B></FONT><P>\r\n\
<FONT size=\"+1\"><B>" #h2 "</B></FONT><P>\r\n\
<P>\r\n\
<TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"
cellspacing=\"0\" cellpadding=\"3\"><TR><TD>\r\n\
<TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"
cellspacing=\"0\" cellpadding=\"10\"><TR><TD>\r\n\
"

#define HTML_FOOTER() "\
</TD></TR></TABLE>\r\n\
</TD></TR></TABLE>\r\n" HTML_BOTTOM

#define DECLARE_MESSAGE(a,b,c,d)	static const char a[] = b c d HTML_FOOTER()


DECLARE_MESSAGE(NODIAL_RESPONSE, RESPONSE_HEADER (200, Ok), HTML_HEADER(DIAL,
Wait for dial), \
"You must enable \"HTTP proxy\" in your web browser for this action to
work.\r\n");

DECLARE_MESSAGE(NO_MATCH, RESPONSE_HEADER (404, Not Found), HTML_HEADER(ERROR,
Invalid request), \
"You made a request to the router that was invalid.\r\n");

DECLARE_MESSAGE(BAD_USER_NAME, RESPONSE_HEADER (200, Ok), HTML_HEADER(REGISTER,
Bad user name), \
"The user name <FONT color=\"red\">$U</FONT> is to short or already
exists.\r\n");

DECLARE_MESSAGE(SETPASSWORD_SUCCESS, RESPONSE_HEADER (200, Ok),
HTML_HEADER(REGISTER, Set password success), \
"The administrator password has been set.\r\n");

DECLARE_MESSAGE(USER_ADDED, RESPONSE_HEADER (200, Ok), HTML_HEADER(REGISTER,
Success), \
"User <FONT color=\"red\">$U</FONT> is now associated\r\n\
with IP address <FONT color=\"red\">$I</FONT>. You are now\r\n\
free to use this gateway.\r\n");
Jan 12 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
I understand what you're doing, and you're right, D doesn't offer the
ability to stringize macro parameters.

I would guess that such strings & macros form only a small part of your
program, couldn't a .d file be generated programmatically? For example,
write a D program along the lines of:

void main()
{
    string("foo", "bar");
}

void string(char[] s, char[] t)
{
    file.write("char[] abc = \"prefix" ~ s ~ "middle" ~ t ~ "suffix\";");
}

"Paul Sheer" <psheer icon.co.za> wrote in message
news:avru6h$1ri8$1 digitaldaemon.com...
 An example of a use of C macros that has not been discussed
 ===========================================================

 In an embedded http server I wrote, I want all my pages to be in the
 constant section, so I defined macros to easily create HTTP pages
 with a consistent format, declared all as "const char *". What follows
 is an actual sample of code.

 I would VERY much like to use D for embedded projects. I believe
 it is absolutely essential to be able to manipulate constant data
 as in the example below. Even C macros are not powerful enough IMO.

 On-the-fly generation of the HTML text is not an option.

 -paul

 #define RESPONSE_HEADER(n,s) "\
 HTTP/1.0 " #n " " #s "\r\n\
 Server: PaulOS internal proxy\r\n\
 Content-Type: text/html\r\n\
 Proxy-Connection: close\r\n\
 \r\n\
 "

 #define RESPONSE_TEXT_HEADER(n,s) "\
 HTTP/1.0 " #n " " #s "\r\n\
 Server: PaulOS internal proxy\r\n\
 Content-Type: text/plain\r\n\
 Proxy-Connection: close\r\n\
 \r\n\
 "

 #define HTML_TOP(meta,title,body) "\
 <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n\
 <HTML>\r\n\
 <HEAD>\r\n\
 <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;

 " meta "\r\n\
 <TITLE>" title "</TITLE>\r\n\
 </HEAD>\r\n\
 <BODY" body ">\r\n"

 #define HTML_BOTTOM "\
 <TABLE width=\"100%\" border=\"0\" rules=\"none\" cellspacing=\"0\"

 <A href=\"credits\" target=\"_blank\"></A>\r\n\
 </TD></TR></TABLE>\r\n\
 </BODY></HTML>\r\n"

 #define HTML_HEADER(h1,h2) HTML_TOP("", #h1 ": " #h2, "") "\
 <TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"

 <TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"

 <CENTER><FONT face=\"Arial, Helvetica, sans-serif\"

 </TD></TR></TABLE>\r\n\
 </TD></TR></TABLE>\r\n\
 <P><FONT size=\"+2\"><B>" #h1 "</B></FONT><P>\r\n\
 <FONT size=\"+1\"><B>" #h2 "</B></FONT><P>\r\n\
 <P>\r\n\
 <TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"

 <TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"

 "

 #define HTML_FOOTER() "\
 </TD></TR></TABLE>\r\n\
 </TD></TR></TABLE>\r\n" HTML_BOTTOM

 #define DECLARE_MESSAGE(a,b,c,d) static const char a[] = b c d

 DECLARE_MESSAGE(NODIAL_RESPONSE, RESPONSE_HEADER (200, Ok),

 "You must enable \"HTTP proxy\" in your web browser for this action to

 DECLARE_MESSAGE(NO_MATCH, RESPONSE_HEADER (404, Not Found),

 "You made a request to the router that was invalid.\r\n");

 DECLARE_MESSAGE(BAD_USER_NAME, RESPONSE_HEADER (200, Ok),

 "The user name <FONT color=\"red\">$U</FONT> is to short or already

 DECLARE_MESSAGE(SETPASSWORD_SUCCESS, RESPONSE_HEADER (200, Ok),

 "The administrator password has been set.\r\n");

 DECLARE_MESSAGE(USER_ADDED, RESPONSE_HEADER (200, Ok),

 "User <FONT color=\"red\">$U</FONT> is now associated\r\n\
 with IP address <FONT color=\"red\">$I</FONT>. You are now\r\n\
 free to use this gateway.\r\n");

Jan 12 2003
parent reply "Paul Sheer" <psheer icon.co.za> writes:
 I understand what you're doing, and you're right, D doesn't offer the
 ability to stringize macro parameters.
 
 I would guess that such strings & macros form only a small part of your
 program, 

yes, but they are used all over; for example (this is just toooo convenient): const struct device __device[] = { {"/dev/null", (void *) 0, &file_null}, {"/dev/ttyS0", (void *) SAMSUMG_UART1, &file_samsungserial}, {"/dev/ttyS1", (void *) SAMSUMG_UART0, &file_samsungserial}, {"/dev/loop0", (void *) 0, &file_loop}, #ifdef HAVE_ETH {"/dev/eth0", (void *) 0, &file_samsungeth}, #endif #ifdef HAVE_PPPOE {"/dev/pppoe", (void *) 0, &file_pppoe}, #endif #ifdef HAVE_HDLC {"/dev/hdlc0", (void *) SAMSUNG_HDLC_A, &file_samsunghdlc}, #endif #ifdef HAVE_NET {"/dev/tcp", (void *) IPPROTO_TCP, &file_socket}, #ifdef HAVE_UDP {"/dev/udp", (void *) IPPROTO_UDP, &file_udp}, #endif #endif {"/dev/flash", (void *) ((u_int32_t) 0x1000000 | 0x4000000), &file_flash}, #ifdef HAVE_PPPCONF {"/etc/ppp.conf", (void *) &pppconf_data, &file_staticfile}, #endif {0, 0, 0}, };
 couldn't a .d file be generated programmatically? 

yes, but then it would be like having a D macro preprocessor in any case :-) you see, people ARE going to use the C preprocessor regardless of whether you include it as part of the D specification. They simply HAVE to use it in some situations. the same happened with the Haskell compiler: people use cpp with haskell. So you might as well create a better macro language than cpp.
 For example, write a [...]

yeah yeah i got you :-) you see D is so important for embedded systems because they are notoriously difficult to debug. with D you can write pretty safe code, but you can still write things like a tcp stack which you would previously only do in C. -paul --------------------------
 void main()
 {
     string("foo", "bar");
 }
 
 void string(char[] s, char[] t)
 {
     file.write("char[] abc = \"prefix" ~ s ~ "middle" ~ t ~ "suffix\";");
 }
 
 "Paul Sheer" <psheer icon.co.za> wrote in message
 news:avru6h$1ri8$1 digitaldaemon.com...
 An example of a use of C macros that has not been discussed
 ===========================================================

 In an embedded http server I wrote, I want all my pages to be in the
 constant section, so I defined macros to easily create HTTP pages
 with a consistent format, declared all as "const char *". What follows
 is an actual sample of code.

 I would VERY much like to use D for embedded projects. I believe
 it is absolutely essential to be able to manipulate constant data
 as in the example below. Even C macros are not powerful enough IMO.

 On-the-fly generation of the HTML text is not an option.

 -paul

 #define RESPONSE_HEADER(n,s) "\
 HTTP/1.0 " #n " " #s "\r\n\
 Server: PaulOS internal proxy\r\n\
 Content-Type: text/html\r\n\
 Proxy-Connection: close\r\n\
 \r\n\
 "

 #define RESPONSE_TEXT_HEADER(n,s) "\
 HTTP/1.0 " #n " " #s "\r\n\
 Server: PaulOS internal proxy\r\n\
 Content-Type: text/plain\r\n\
 Proxy-Connection: close\r\n\
 \r\n\
 "

 #define HTML_TOP(meta,title,body) "\
 <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n\
 <HTML>\r\n\
 <HEAD>\r\n\
 <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;

 " meta "\r\n\
 <TITLE>" title "</TITLE>\r\n\
 </HEAD>\r\n\
 <BODY" body ">\r\n"

 #define HTML_BOTTOM "\
 <TABLE width=\"100%\" border=\"0\" rules=\"none\" cellspacing=\"0\"

 <A href=\"credits\" target=\"_blank\"></A>\r\n\
 </TD></TR></TABLE>\r\n\
 </BODY></HTML>\r\n"

 #define HTML_HEADER(h1,h2) HTML_TOP("", #h1 ": " #h2, "") "\
 <TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"

 <TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"

 <CENTER><FONT face=\"Arial, Helvetica, sans-serif\"

 </TD></TR></TABLE>\r\n\
 </TD></TR></TABLE>\r\n\
 <P><FONT size=\"+2\"><B>" #h1 "</B></FONT><P>\r\n\
 <FONT size=\"+1\"><B>" #h2 "</B></FONT><P>\r\n\
 <P>\r\n\
 <TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"

 <TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"

 "

 #define HTML_FOOTER() "\
 </TD></TR></TABLE>\r\n\
 </TD></TR></TABLE>\r\n" HTML_BOTTOM

 #define DECLARE_MESSAGE(a,b,c,d) static const char a[] = b c d

 DECLARE_MESSAGE(NODIAL_RESPONSE, RESPONSE_HEADER (200, Ok),

 "You must enable \"HTTP proxy\" in your web browser for this action to

 DECLARE_MESSAGE(NO_MATCH, RESPONSE_HEADER (404, Not Found),

 "You made a request to the router that was invalid.\r\n");

 DECLARE_MESSAGE(BAD_USER_NAME, RESPONSE_HEADER (200, Ok),

 "The user name <FONT color=\"red\">$U</FONT> is to short or already

 DECLARE_MESSAGE(SETPASSWORD_SUCCESS, RESPONSE_HEADER (200, Ok),

 "The administrator password has been set.\r\n");

 DECLARE_MESSAGE(USER_ADDED, RESPONSE_HEADER (200, Ok),

 "User <FONT color=\"red\">$U</FONT> is now associated\r\n\
 with IP address <FONT color=\"red\">$I</FONT>. You are now\r\n\
 free to use this gateway.\r\n");


Jan 13 2003
next sibling parent "Mike Wynn" <mike.wynn l8night.co.uk> writes:
there is 'version'
 const struct device __device[] = {
     {"/dev/null", (void *) 0, &file_null},
     {"/dev/ttyS0", (void *) SAMSUMG_UART1, &file_samsungserial},
     {"/dev/ttyS1", (void *) SAMSUMG_UART0, &file_samsungserial},
     {"/dev/loop0", (void *) 0, &file_loop},
 #ifdef HAVE_ETH
     {"/dev/eth0", (void *) 0, &file_samsungeth},
 #endif
 #ifdef HAVE_PPPOE
     {"/dev/pppoe", (void *) 0, &file_pppoe},
 #endif

like (but not quite D code) Device __devices[] = [ new Device( .... ), new Device( .... ), version ( HAVE_ETH ) { new Device( "Ethernet", ... ), } ]; currently you have to create arrays in you modules static initialiser, rather than declare it "inline" (D only has runtime inits rather than optional compile time inits).
Jan 13 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
With D, you'd wrap the entire struct declaration in a version declaration.
Whether it would wind up looking better or worse than the #ifdef version is
a matter of personal taste.

Also, yes, people will always be writing programs that spit out source code
to be compiled. I do it all the time, usually for generating complex tables.
No macro processor is going to do it.

"Paul Sheer" <psheer icon.co.za> wrote in message
news:avtseg$1s5r$1 digitaldaemon.com...
 I understand what you're doing, and you're right, D doesn't offer the
 ability to stringize macro parameters.

 I would guess that such strings & macros form only a small part of your
 program,

yes, but they are used all over; for example (this is just toooo convenient): const struct device __device[] = { {"/dev/null", (void *) 0, &file_null}, {"/dev/ttyS0", (void *) SAMSUMG_UART1, &file_samsungserial}, {"/dev/ttyS1", (void *) SAMSUMG_UART0, &file_samsungserial}, {"/dev/loop0", (void *) 0, &file_loop}, #ifdef HAVE_ETH {"/dev/eth0", (void *) 0, &file_samsungeth}, #endif #ifdef HAVE_PPPOE {"/dev/pppoe", (void *) 0, &file_pppoe}, #endif #ifdef HAVE_HDLC {"/dev/hdlc0", (void *) SAMSUNG_HDLC_A, &file_samsunghdlc}, #endif #ifdef HAVE_NET {"/dev/tcp", (void *) IPPROTO_TCP, &file_socket}, #ifdef HAVE_UDP {"/dev/udp", (void *) IPPROTO_UDP, &file_udp}, #endif #endif {"/dev/flash", (void *) ((u_int32_t) 0x1000000 | 0x4000000),

 #ifdef HAVE_PPPCONF
     {"/etc/ppp.conf", (void *) &pppconf_data, &file_staticfile},
 #endif
     {0, 0, 0},
 };

 couldn't a .d file be generated programmatically?

yes, but then it would be like having a D macro preprocessor in any case :-) you see, people ARE going to use the C preprocessor regardless of whether you include it as part of the D specification. They simply HAVE to use it in some situations. the same happened with the Haskell compiler: people use cpp with haskell. So you might as well create a better macro language than cpp.
 For example, write a [...]

yeah yeah i got you :-) you see D is so important for embedded systems because they are notoriously difficult to debug. with D you can write pretty safe code, but you can still write things like a tcp stack which you would previously only do in C. -paul --------------------------
 void main()
 {
     string("foo", "bar");
 }

 void string(char[] s, char[] t)
 {
     file.write("char[] abc = \"prefix" ~ s ~ "middle" ~ t ~


 }

 "Paul Sheer" <psheer icon.co.za> wrote in message
 news:avru6h$1ri8$1 digitaldaemon.com...
 An example of a use of C macros that has not been discussed
 ===========================================================

 In an embedded http server I wrote, I want all my pages to be in the
 constant section, so I defined macros to easily create HTTP pages
 with a consistent format, declared all as "const char *". What follows
 is an actual sample of code.

 I would VERY much like to use D for embedded projects. I believe
 it is absolutely essential to be able to manipulate constant data
 as in the example below. Even C macros are not powerful enough IMO.

 On-the-fly generation of the HTML text is not an option.

 -paul

 #define RESPONSE_HEADER(n,s) "\
 HTTP/1.0 " #n " " #s "\r\n\
 Server: PaulOS internal proxy\r\n\
 Content-Type: text/html\r\n\
 Proxy-Connection: close\r\n\
 \r\n\
 "

 #define RESPONSE_TEXT_HEADER(n,s) "\
 HTTP/1.0 " #n " " #s "\r\n\
 Server: PaulOS internal proxy\r\n\
 Content-Type: text/plain\r\n\
 Proxy-Connection: close\r\n\
 \r\n\
 "

 #define HTML_TOP(meta,title,body) "\
 <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n\
 <HTML>\r\n\
 <HEAD>\r\n\
 <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;

 " meta "\r\n\
 <TITLE>" title "</TITLE>\r\n\
 </HEAD>\r\n\
 <BODY" body ">\r\n"

 #define HTML_BOTTOM "\
 <TABLE width=\"100%\" border=\"0\" rules=\"none\" cellspacing=\"0\"

 <A href=\"credits\" target=\"_blank\"></A>\r\n\
 </TD></TR></TABLE>\r\n\
 </BODY></HTML>\r\n"

 #define HTML_HEADER(h1,h2) HTML_TOP("", #h1 ": " #h2, "") "\
 <TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"

 <TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"

 <CENTER><FONT face=\"Arial, Helvetica, sans-serif\"

 </TD></TR></TABLE>\r\n\
 </TD></TR></TABLE>\r\n\
 <P><FONT size=\"+2\"><B>" #h1 "</B></FONT><P>\r\n\
 <FONT size=\"+1\"><B>" #h2 "</B></FONT><P>\r\n\
 <P>\r\n\
 <TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"

 <TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"

 "

 #define HTML_FOOTER() "\
 </TD></TR></TABLE>\r\n\
 </TD></TR></TABLE>\r\n" HTML_BOTTOM

 #define DECLARE_MESSAGE(a,b,c,d) static const char a[] = b c d

 DECLARE_MESSAGE(NODIAL_RESPONSE, RESPONSE_HEADER (200, Ok),

 "You must enable \"HTTP proxy\" in your web browser for this action to

 DECLARE_MESSAGE(NO_MATCH, RESPONSE_HEADER (404, Not Found),

 "You made a request to the router that was invalid.\r\n");

 DECLARE_MESSAGE(BAD_USER_NAME, RESPONSE_HEADER (200, Ok),

 "The user name <FONT color=\"red\">$U</FONT> is to short or already

 DECLARE_MESSAGE(SETPASSWORD_SUCCESS, RESPONSE_HEADER (200, Ok),

 "The administrator password has been set.\r\n");

 DECLARE_MESSAGE(USER_ADDED, RESPONSE_HEADER (200, Ok),

 "User <FONT color=\"red\">$U</FONT> is now associated\r\n\
 with IP address <FONT color=\"red\">$I</FONT>. You are now\r\n\
 free to use this gateway.\r\n");



Jan 13 2003
prev sibling parent "Kelvin Lee" <kiyolee *hongkong*.com> writes:
I think this is all about the code optimization problem.
C compiler used to rely on developers to optimize this kind of situations.

But I think, for this piece of code:

char* f(char* s)
{
    return "abc " + s + " xyz";
}

void foo()
{
    char *p = f("123");
    char *q = f(p);
}

/* I know, this may not be really correct D code */

A smart enough compiler should simply assign p a pointer to the string "abc
123 xyz" while execute some code for assigning the right thing to q.

If the compiler is so smart, the following kind of macro processing is
completely unnecessary.

In addition, if this kind of optimization can be turned off, debugging this
kind of "macros" would become much easier.

BTW, can the D compiler do something like this?

Kiyo

"Paul Sheer" <psheer icon.co.za> wrote in message
news:avru6h$1ri8$1 digitaldaemon.com...
 An example of a use of C macros that has not been discussed
 ===========================================================

 In an embedded http server I wrote, I want all my pages to be in the
 constant section, so I defined macros to easily create HTTP pages
 with a consistent format, declared all as "const char *". What follows
 is an actual sample of code.

 I would VERY much like to use D for embedded projects. I believe
 it is absolutely essential to be able to manipulate constant data
 as in the example below. Even C macros are not powerful enough IMO.

 On-the-fly generation of the HTML text is not an option.

 -paul

 #define RESPONSE_HEADER(n,s) "\
 HTTP/1.0 " #n " " #s "\r\n\
 Server: PaulOS internal proxy\r\n\
 Content-Type: text/html\r\n\
 Proxy-Connection: close\r\n\
 \r\n\
 "

 #define RESPONSE_TEXT_HEADER(n,s) "\
 HTTP/1.0 " #n " " #s "\r\n\
 Server: PaulOS internal proxy\r\n\
 Content-Type: text/plain\r\n\
 Proxy-Connection: close\r\n\
 \r\n\
 "

 #define HTML_TOP(meta,title,body) "\
 <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n\
 <HTML>\r\n\
 <HEAD>\r\n\
 <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;

 " meta "\r\n\
 <TITLE>" title "</TITLE>\r\n\
 </HEAD>\r\n\
 <BODY" body ">\r\n"

 #define HTML_BOTTOM "\
 <TABLE width=\"100%\" border=\"0\" rules=\"none\" cellspacing=\"0\"

 <A href=\"credits\" target=\"_blank\"></A>\r\n\
 </TD></TR></TABLE>\r\n\
 </BODY></HTML>\r\n"

 #define HTML_HEADER(h1,h2) HTML_TOP("", #h1 ": " #h2, "") "\
 <TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"

 <TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"

 <CENTER><FONT face=\"Arial, Helvetica, sans-serif\"

 </TD></TR></TABLE>\r\n\
 </TD></TR></TABLE>\r\n\
 <P><FONT size=\"+2\"><B>" #h1 "</B></FONT><P>\r\n\
 <FONT size=\"+1\"><B>" #h2 "</B></FONT><P>\r\n\
 <P>\r\n\
 <TABLE bgcolor=\"#0080FF\" width=\"100%\" border=\"0\" rules=\"none\"

 <TABLE bgcolor=\"#FFFFFF\" width=\"100%\" border=\"0\" rules=\"none\"

 "

 #define HTML_FOOTER() "\
 </TD></TR></TABLE>\r\n\
 </TD></TR></TABLE>\r\n" HTML_BOTTOM

 #define DECLARE_MESSAGE(a,b,c,d) static const char a[] = b c d

 DECLARE_MESSAGE(NODIAL_RESPONSE, RESPONSE_HEADER (200, Ok),

 "You must enable \"HTTP proxy\" in your web browser for this action to

 DECLARE_MESSAGE(NO_MATCH, RESPONSE_HEADER (404, Not Found),

 "You made a request to the router that was invalid.\r\n");

 DECLARE_MESSAGE(BAD_USER_NAME, RESPONSE_HEADER (200, Ok),

 "The user name <FONT color=\"red\">$U</FONT> is to short or already

 DECLARE_MESSAGE(SETPASSWORD_SUCCESS, RESPONSE_HEADER (200, Ok),

 "The administrator password has been set.\r\n");

 DECLARE_MESSAGE(USER_ADDED, RESPONSE_HEADER (200, Ok),

 "User <FONT color=\"red\">$U</FONT> is now associated\r\n\
 with IP address <FONT color=\"red\">$I</FONT>. You are now\r\n\
 free to use this gateway.\r\n");

Jan 13 2003