\input texinfo @setfilename dmbcs-micro-server.info @include version.texi @settitle The dmbcs-micro-server Library Reference Manual @syncodeindex tp fn @syncodeindex pg fn @copying This is the reference manual for the dmbcs-micro-server C++ library, version @value{VERSION}. Copyright @copyright{} 2018, 2020, 2025 DM Bespoke Computer Solutions @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. A copy of the license is also available from the Free Software Foundation Web site at @url{http://www.gnu.org/licenses/fdl.html}. @end quotation @end copying @dircategory Libraries @direntry * dmbcs-micro-server: (dmbcs-micro-server). C++ CGI utility library. @end direntry @setchapternewpage odd @titlepage @title The DMBCS micro-server Library Reference Manual @author Dale Mellor @page @vskip 0pt plus 1filll @insertcopying @end titlepage @node Top @summarycontents @contents @page @ifnottex @top The micro-server Library @insertcopying @end ifnottex @menu * Introduction:: * Using the library:: * Reference:: * Examples of Use:: * Hints on how the library might be used in a real application:: @detailmenu --- The Detailed Node Listing --- Introduction * HTTP Web Services:: * Our Choice of Name:: * Your Choice of Library:: * Outline of Library:: An overview of the library's implementation Using the library Reference * The utility functions:: * The Query_String class:: * The Hyper_Tags class:: * The Http_Server class:: The Query_String class * MACs:: * Constructors:: * Methods:: * Functions:: The Hyper_Tags class * Constructors_:: * Methods_:: * Functions_:: The Http_Server class * Constructor__:: * Functions__:: Examples of Use * Simple example -- Online multiplier:: A simple application of the library Hints on how the library might be used in a real application * Web-site skins:: Web sites which provide a user-selected `look-and-feel' * Other inheritence:: Other ideas @end detailmenu @end menu @node Introduction, Using the library, Top, Top @chapter Introduction This document introduces, defines and exemplifies use of the dmbcs-micro-server C++ library, providing services to applications for processing and responding to requests from a web browser, including the possibility of making the application a stand-alone web server in its own right (a `micro-server'). @menu * HTTP Web Services:: Introduction to CGI and web servers * Our Choice of Name:: Use of `DMBCS' * Your Choice of Library:: Some gentle advice * Outline of Library:: An overview of the library's implementation @end menu @node HTTP Web Services, Our Choice of Name, Introduction, Introduction @section HTTP Web Services A CGI program is a program, written in any language, which conforms to the Common Gateway Interface (CGI). It is a program executed by a web server (on the server machine), and is passed information about the request from the user through the UNIX environment. It is left to the program to interpret the user's requirements and to produce on its standard output channel a HTML document which the web server will relay back to the user's browser for display on his console. CGI programs are thus very flexible and amenable to lots of jobs. Some of them are very small, amounting to only a couple of lines of an interpreted language to slurp a file from the local storage and send it straight back to the browser (which is essentially what a web server would normally do but this allows the programmer to do so in a more customized way). On the other hand, some CGI programs are extremely large consisting of hundreds of thousands of lines of code which may interact with a database and other third-party systems (such as payment gateways) and do some real work on behalf of the user, before sending the results of the transactions along for the user's perusal. This project came from a CGI program of the latter description. Because of its size, complexity and the anticipated load (number of users), it was decided very early on that it would be written in a proper programming language which could be compiled optimized to run on the bare metal of the available computer system, whatever that is. Thus it would have to be C or C++. While the original implementation had been in C for political reasons, it has since been ported to the more convenient C++. As a side-effect of this development, the parts of the system which deal specifically with the business of being a CGI program have been abstracted and encapsulated, and then they were syphoned off into their own separate library; this was further extended to provide the functions of a self-contained web server. This is now being offered for general use. The result is a library which can be used to inject a self-contained web server into an arbitrary C++ code base, opening up the interface to such a legacy program to the modern world, without needing to also build the infrastructure to serve such a program to the public (although in practice infrastructure needs to be built for other reasons---like security and virtualization---but the self-contained scheme allows for greater flexibility and better functional isolation). @node Our Choice of Name, Your Choice of Library, HTTP Web Services, Introduction @section Our Choice of Name The micro-server library was written from scratch since 2004 as part of a large internet project. The requirement for a C++ framework for undertaking this task is very common, and thus it is no surprise that other efforts already exist, notably the GNU cgicc project. Some consideration was given to the name of this project. At first it was going to be called cgicc2, but that carries the implication that it somehow carries on from the GNU cgicc project, and that it is both a development and enhancement of it. This is definitely not the case, but a parallel development, completely different but solving the same problems. Unfortunately appending any number or even letter carries some implication of sequencing, and if the two projects continue (as they should) to be developed then some imbalance would occur in the rivalry. Such is definitely not the intention, but for the two projects to be seen as separate. Choice of one or other framework for any particular project should be based on what the framework offers, not what letters happen to come in its name. Thus it is decided to mark this particular library with the string 'DMBCS': all code appears inside the namespace 'DMBCS::Micro_Server' and the include file is called 'dmbcs-micro-server.h'; the project is formally known as the 'dmbcs-micro-server' C++ library. @node Your Choice of Library, Outline of Library, Our Choice of Name, Introduction @section Your Choice of Library We offer only this advice: look at the API provided by all the available libraries, and consider the nature of the working framework (paradigm) that that implies; choose the library that seems most appropriate for your project: the one that you will feel most comfortable working with. @node Outline of Library, , Your Choice of Library, Introduction @section Outline of Library The library consists of a high-level wrapper and two workhorse classes. @code{Http_Server} interfaces with multiple clients and delegates processing of their requests to registered callback functions, which make direct use of the following workhorses. @code{Query_String} looks after the part of the CGI interface which passes from the browser to the CGI program and provides methods specifically for interpreting the arguments from the browser's query string, and @code{Hyper_Tags} looks after the part of the CGI interface which passes back from the CGI program to the browser, and displays the results of the user's request; this deals with updating template HTML files with some dynamic content before passing the result to the web server for eventual transmission to the browser. @node Using the library @chapter Using the library To re-iterate: all code in this library comes in the namespace 'DMBCS::Micro_Server' and the header which introduces all of the functionality is 'dmbcs-micro-server.h'. A project would generally consist of a template HTML file with markers where dynamically-generated content needs to be placed, a .css file which should be injected into the file or provided by the server as an inclusion target in the HTML, a .js file containing code that should run client-side to implement part of the functionality of the web site, and a (micro-) web server which runs continually, listens for client connections, and provides generated HTML files and JSON data strings on demand of the client. @menu @end menu @node Reference, Examples of Use, Using the library, Top @chapter Reference @menu * The utility functions:: Useful functions needed by web applications * The Query_String class:: For processing the user's arguments * The Hyper_Tags class:: For substituting dynamic content into HTML * The Http_Server class:: To implement a micro-server in your own app @end menu @node The utility functions, The Query_String class, Reference, Reference @section The utility functions Introductory text here. @deftypefun string slurp_file_with_error (const std::string &@var{file_name}) throw (Slurp_Error) This function will attempt to open the file named file_name (which may be a complete path to the file), and read the whole lot into a string. If any errors occur in the process, a Slurp_Error object will be thrown (these exception objects do not convey any information back to the application). @end deftypefun @deftypefun string slurp_file (const std::string &@var{file_name}) This function will attempt to open file @var{file_name} (which may be a full path), and will slurp the entire contents (which are presumably a hyper-tag'd template file) into a string. If any errors occur, an empty string will be produced, and a message printed on the standard error channel to indicate the name of the file which has failed. In the majority of applications of this function, in the majority of calls, the error condition thrown from the function above will not happen; it would be regarded as an infrastructure build problem rather than a run-time error if a known file were not accessible. Thus it is wasteful to worry about and deal with the error at global level--outside the library--, rather let the program carry on and provide a message to the user's console about the missing file (the fact that the problem occurred will be obvious!) Once it is known which file has failed, the remedy will be equally obvious. @end deftypefun @deftypefun string htmlize_quotes (string && @var{input}) Any occurrence of `` in @var{input} will be replaced by `@code{"};' @end deftypefun @deftypefun string htmlize (string && @var{input}) All occurrences of HTML-special characters (<>&") will be replaced with entity representations. The main purpose of this method is to alleviate the possibility of injection attacks into a web-site; if any part of a page is generated from user-supplied input there is the danger that the user might be savvy enough to get JavaScript to execute there! But the function is quite generally useful when it is known that a string needs to appear verbatim in a web page, regardless of its contents, and thus ought to be used whenever a string is added to a set of @code{Hyper_Tag}s. @end deftypefun @deftypefun string strip_leading_space (string && @var{input}) Replace all sequences of white space at the start of all lines with a single space character. HTML recognizes all sequences of white space outside of quotes as a single space separator. Thus sequences of white space at the beginning of lines (which are used by web programmers to give a nice aesthetic indentation) are a waste of bandwidth. This function will remove all such occurrences from @var{input}. @end deftypefun @deftypefun string escape_quotes (string @var{input}) Replace all occurrences of quotation marks and escapes with escaped versions, where the escape character is the back-slash. This function will put an escape ('\') in front of ''', '''', or '\' which occur in @var{input}, and is useful (essential when dealing with user-supplied input) to ensure that strings do not mess up SQL statements. @end deftypefun @deftypefun string decode_url (string @var{url}) This function will replace '+' with ' ', and any %-escaped character codes in the @var{url} with the ASCII equivalent. This will produce a plain string, decoded from strings passed from forms or EcmaScript on web pages passed through parameter lists in URI's, as provided within the context of this library by the @code{Query_String} object. @end deftypefun @deftypefun string hexalize (unsigned char const *const @var{buffer}, size_t const @var{buffer_size}) Return an ASCII string containing the hexadecimal representation of the octets in the given @var{buffer}. The @var{buffer_size} is the number of octets to decode. @end deftypefun @deftypefun string getenv (string const & @var{env}) Return the value of the environment variable called @var{env}, or an empty string if the variable does not exist in the environment. This is a convenience wrapper around the system @code{getenv} call, adapting it to the use of strings. @end deftypefun @node The Query_String class @section The Query_String class A Query_String object is a std::map object in which the keys are the variables passed in the URL query string part and the values are the values from that query string. Methods are defined which interrogate the class in details more specific to the CGI problem, and allow for values to be extracted in either string or a numeric form, as expected by the CGI program. @menu * MACs:: * Constructors:: * Methods:: * Functions:: @end menu @node MACs, Constructors, The Query_String class, The Query_String class @subsection MACs @node Constructors @subsection Constructors @deftp {Constructor} Query_String () The null constructor, only useful if you are intending to build up a new query string for eventual inclusion into some part of a HTML page. @end deftp @deftp {Constructor} Query_String (const char *const *const @var{env}) The real workhorse constructor. The argument @var{env} should be the environment variable passed to the CGI's main routine as the third argument. This will create an object which represents the information passed to the CGI program via the query string, whether it were sent via the GET or the PUT protocols. The object returned can subsequently be used to interrogate the user's request string. @end deftp @node Methods @subsection Methods @deftp {Method} void Query_String::add (const std::string &@var{name}, const T &@var{value}) This method will add an entry into the Query_String with key @var{name} and value a string representation of @var{value}. The type T of @var{value} may be anything that can be passed into a std::ostream object via the << operator. @end deftp @deftp {Method} void Query_String::add (const std::string &@var{name}, const Query_String &@var{input}, const T &@var{fallback}) This method will add an entry into the current Query_String which is a copy of the entry in the @var{input} Query_String, unless such entry does not exist in which case a key @var{name} with value a std::string representation of @var{fallback} will be added to the current Query_String. The type T of @var{fallback} may be anything that can be passed to the << operator of a std::ostream object. @end deftp @deftp {Method} bool Query_String::posted () const Returns TRUE if the query string had been sent to the CGI program via the POST protocol, FALSE otherwise (which case would presumably have been caused by use of the GET protocol). @end deftp @deftp {Method} T Query_String::get (const std::string &name, const T &fallback) const This gets the value associated with the key @var{name} from the query string, unless no such key was present in which case @var{fallback} is returned. Note that the type of value returned is the same as that of @var{fallback}, thus @var{fallback} serves the dual role of defining the fallback value and determining the return type of the function. @end deftp @deftp {Method} std::vector Query_String::get_list (const std::string &name) const In the case that a query string value corresponds to a multiple choice selection on the HTML form, it will be a comma-separated string of selected values. This function will return a vector comprised of these values, interpreted as integers. If there is no key @var{name} in the query string, then the returned vector will have no elements (zero length). @end deftp @deftp {Method} std::vector Query_String::get_checked_array (const std::string &NAME) const @end deftp @deftp {Method} bool Query_String::has (const std::string &NAME) const This method returns TRUE if the @var{name} was a variable present in the query string, FALSE otherwise. @end deftp @deftp {Method} bool Query_String::mac_verified () const This method will return TRUE only if there was a MAC present in the query string, and the MAC was valid. Otherwise FALSE will be returned. @end deftp @node Functions @subsection Functions @deftypefun static string Query_String::add_mac (string @var{input}) This static class member will add a cryptographic MAC onto any string, but this is only meaningful for composed query strings. @end deftypefun @node The Hyper_Tags class @section The Hyper_Tags class Whereas a HTML document contains markup tags expressed as labels between angle brackets (possibly in pairs), so a micro-server template file contains dynamic content holders expressed as labels between square brackets. The Hyper_Tags class contains methods for replacing single tags with some dynamically-generated content, and for selectively keeping or removing sections of the template bracketed between pairs of hyper tags. A Hyper_Tags object should be considered a container of tag definitions. The CGI program will typically build up a list of such definitions in the container, until all the work is done when the template file is read in from local storage and the Hyper_Tags object is instructed to make all the changes in one go before sending the result to the server and hence to the user's browser. @menu * Constructors_:: * Methods_:: * Functions_:: @end menu @node Constructors_, , The Hyper_Tags class, The Hyper_Tags class @subsection Constructors_ @deftp {Constructor} Hyper_Tags () The class only has the one, default, constructor, which returns an empty object waiting to be filled with tag definitions. @end deftp @node Methods_, , Constructors_, The Hyper_Tags class @subsection Methods_ @deftp {Method} void Hyper_Tags::harden_last () Normally, a later tag definition would overrule any earlier ones when substitutions are finally made into a template file. However, if it is desired that the last tag added should be the final tag definition on substitution, then it can be `hardened' by calling this method. @end deftp @deftp {Method} bool Hyper_Tags::has (const std::string &@var{name}) const This method returns TRUE if a tag with the given @var{name} has been registered with the Hyper_Tags object. In all other cases it returns FALSE. @end deftp @deftp {Method} Hyper_Tags &Hyper_Tags::add (const Hyper_Tags &@var{registry}, const int @var{harden} = 0) This method copies all the tag definitions contained in @var{registry} into the current object, and returns a reference to the current object. If the optional @var{harden} argument is passed a non-zero value, then all the incumbent tag definitions will be hardened, as per the discussion of the harden_last () method above. @end deftp @deftp {Method} Hyper_Tags &Hyper_Tags::add (const std::string &@var{name}, string @var{substitution_text}) One of the main methods of the class. Declares that, in the final substitutions, any parts of the template file which look like ``[@var{name}/]'' should be replaced with @var{substitution_text}. The return is a reference to the current object. @end deftp @deftp {Method} Hyper_Tags &Hyper_Tags::add (const std::string &@var{name}, const int value) Declares that tags called @var{name} in the template file be replaced with a string representing the integer @var{value}. The return is a reference to the current object. @end deftp @deftp {Method} Hyper_Tags &Hyper_Tags::add (const std::string &@var{name}, const double @var{value}, const int @var{precision} = 4) Declares that tags called @var{name} be replaced with a string representing the floating-point @var{value}, with at least @var{precision} significant figures. The return is a reference to the current object. @end deftp @deftp {Method} Hyper_Tags &add (const std::string &@var{name}, Query_String &@var{q_s}, const T &@var{fallback}) Declares that tags called @var{name} be replaced with a value from @var{q_s} with the same name if this exists, or with @var{fallback} otherwise. The type T of fallback should be one of std::string, int, or double. The return is a reference to the current object. @end deftp @deftp {Method} void add_int_list (const std::string &@var{name}, I @var{begin}, I @var{end}) Here, I is an iterator type over an STL container of int's. This method declares that tags named @var{name} be substituted with a comma-separated list of integer values. @end deftp @deftp {Method} void add_date (const std::string &@var{name}, const time_t &@var{time}, const std::string &@var{format}) Specifies that tags named @var{name} be replaced with a string representing the date indicated by the UNIX @var{time} object. The conversion takes place according to @var{format}, which is described in the strftime () libc manual. @end deftp @deftp {Method} void add_file (const std::string &@var{name}, const std::string &@var{file_name}) Specifies that tags named @var{name} in the template HTML file be replaced with the entire contents of the file called @var{file_name} in the file system. @end deftp @deftp{Method} void add_passthrough_tag (const Query_String &@var{query_string}, ...) The trailing arguments are a list of const char *const, terminated with a NULL pointer. This method specifies that contents of the HTML template file which look like ``[pass-through/]'' be replaced with a set of lines which look like ``'' where the @var{names} are taken from the list of arguments to the function, and the @var{__values__} are taken from the @var{query_string} variables with the same names. Thus, if the tag in the template file is contained within ``
'' markup elements, the current values in the query string will be propagated into any query string that the new form produces. @end deftp @deftp{Type} enum Hyper_Tags::Section_Keep @{ KEEP_SECTION, LOSE_SECTION @} @end deftp @deftp{Method} Hyper_Tags §ion (const std::string &@var{name}, const Section_Keep &@var{keep}) This method declares the action to be taken when a pair of tags like ``[@var{name}]'' and ``[/@var{name}]'' are seen in a template file. If @var{keep} is KEEP_SECTION, then the tags are simply removed from the file leaving the contents between the tags intact. If @var{keep} is LOSE_SECTION then the tags and all the text between them is removed from the file. @end deftp @deftp{Method} string Hyper_Tags::substitute (string @var{html_template}, int @var{repeat} = 1) One of the main methods of the class. This will go through @var{html_template} and replace any hyper tags which have been registered with the substitution text that has been declared as the replacement. If a tag is seen in the @var{html_template} which has not been registered with the current object, then this tag will remain intact in the template. Additionally, any pairs of tags seen in @var{html_template} which have been registered as a section will be removed, possibly removing also all the text between the tags, according to the registered behaviour. @end deftp @node Functions_, , Methods_, The Hyper_Tags class @subsection Functions_ @deftypefun static string Hyper_Tags::strip_loose_tags (string @var{input}) It may happen that, after processing, a HTML template string still contains some hyper tags which have not been substituted. This static function will injudiciously remove any such tags, thus eliminating any ugliness from the page sent back to the user. @end deftypefun @node The Http_Server class, , The Hyper_Tags class, Reference @section The Http_Server class @menu * Constructor__:: * Functions__:: @end menu @node Constructor__, Functions__, The Http_Server class, The Http_Server class @subsection Constructor__ @deftypefun Http_Server::Http_Server (const int @var{socket}, const std::map @var{methods}) Create a HTTP server to listen on the @var{socket}. Processing for requests will be delegated to the @var{methods}, referenced by the HTTP-call path name via the @code{map}. When called, the @var{methods} will be passed a @code{Query_String} object and a socket on which a response must be sent; methods are provided in the Http_Server namespace to facilitate with this. Please see the example application to see how this is used in practice. @end deftypefun @node Functions__, , Constructor__, The Http_Server class @subsection Functions__ @deftypefun bool tick (Http_Server &@var{server}, const long @var{wait_us}) Cause the @var{server} to act on a single instruction from a web client, waiting up to @var{wait_us} micro-seconds for such a request to appear. The return is usually @code{TRUE}, but may be @code{FALSE} if the listening socket goes away (this is a mechanism that could be used by a request processing function to terminate the server frow within). In practice this method is called repeatedly, @emph{ad infinitum}. @end deftypefun @deftypefun void Http_Server::return_html (const int @var{socket}, const std::string &@var{html}) This method sends the @var{html} to the socket, dressed up as a valid response to a HTTP request for data. @end deftypefun @deftypefun void Http_Server::return_text (const int @var{socket}, const std::string &@var{text}) This method sends the @var{text} to the socket, dressed up as a valid response to a HTTP request for data. @end deftypefun @deftypefun void Http_Server::return_pdf (const int @var{socket}, const std::string &@var{pdf}) This method sends the @var{pdf} to the socket, dressed up as a valid response to a HTTP request for data. The `string' is actually understood as a buffer of arbitrary octects here. @end deftypefun @deftypefun void Http_Server::return_json (const int @var{socket}, const std::string &@var{json}) This method sends the @var{json} to the socket, dressed up as a valid response to a HTTP request for data. @end deftypefun @deftypefun void Http_Server::return_bad (const int @var{socket}) This method sends an empty payload to the socket, dressed up as a @emph{valid} response to a HTTP request for data (it would generally be taken by an Ecmascript application to be a `bad' response to a request for data). @end deftypefun @deftypefun void Http_Server::return_png (const int @var{socket}, const std::string &@var{png}) This method sends the @var{png} to the socket, dressed up as a valid response to a HTTP request for data. The `string' is actually understood as a buffer of arbitrary octects here. @end deftypefun @deftypefun void Http_Server::return_svg (const int @var{socket}, const std::string &@var{svg}) This method sends the @var{svg} to the socket, dressed up as a valid response to a HTTP request for data. The `string' is actually understood as a buffer of arbitrary octects here. @end deftypefun @node Examples of Use, Hints on how the library might be used in a real application, Reference, Top @chapter Examples of Use We don't start with the tradition hello, world program as this would not demonstrate in any way the dynamic nature of CGI programming! The simplest example we can think of allows the user to input two numbers and returns the product of them, and the full code for this is provided in the next section. @menu * Simple example -- Online multiplier:: A simple application of the library @end menu @node Simple example -- Online multiplier @section Simple example -- Online multiplier The following is provided as the simplest code to demonstrate use of the dmbcs-micro-server library, not to inform of any coding style or quality system approach. We assume a standard GNU system with recent @code{make}, @code{bash}, @code{gcc}, etc. Start with the HTML file @code{calc.html} @verbatim Multiplier

Multiplier

x =
CALCULATE @end verbatim And the C++ source file @code{calc.cc} @verbatim #include using namespace DMBCS::Micro_Server; /* This function both serves up the basic HTML page, and * performs the multiplication and injects the result into the * HTML. */ void home_page (Query_String const &query, int const socket) { Hyper_Tags tags; tags.add ("result", query.get ("arg_1", 0) * query.get ("arg_2", 0)); Http_Server::return_html (socket, substitute (tags, slurp_file ("calc.html"))); } int main () { auto server = Http_Server {2022, { {"", home_page}, {"compute", home_page} }}; for (;;) tick (server, 1000000); return 0; } @end verbatim then the @code{makefile} @verbatim CXXFLAGS = `pkg-config --cflags dmbcs-micro-server` LDFLAGS = `pkg-config --libs dmbcs-micro-server` @end verbatim Then at the command line type @verbatim make calc ./calc @end verbatim then point a browser at @code{http://localhost:2022/} and use the simple calculator (don't try to do anything funny: the code has been kept deliberately simple and doesn't do any error checking). Note that an answer can be obtained directly with a URL like @code{http://localhost:2022/compute?arg_1=3&arg_2=4}. @node Hints on how the library might be used in a real application, , Examples of Use, Top @chapter Hints on how the library might be used in a real application While the basic library as it is serves perfectly well for small CGI programs, the library was derived from a larger project. From this experience, it is seen that many large projects will want to produce specializations of the classes and utility functions provided by the library for the particular project. The following are some specific details about how the library was enhanced in the original project. @menu * Web-site skins:: Web sites which provide a user-selected `look-and-feel' * Other inheritence:: Other ideas @end menu @node Web-site skins, Other inheritence, Hints on how the library might be used in a real application, Hints on how the library might be used in a real application @section Web-site skins The underlying paradigm promoted by the library is one where the programmer supplies template HTML files which the CGI program populates with extra dynamic content. This opens the possibility of supplying the same dynamic content into different templates, for example where a web site allows the user to choose a favorite `skin', or `look-and-feel', then each template file would exist in different forms to provide all the different skins available. In this case, the library can be extended by ensuring that whenever a template is slurped from local storage for use, it is the template appropriate for the user's choice of skin that is pulled up. In the original project, this was achieved by placing all templates for a skin into a single directory to which the CGI program has access (it was actually a sub-directory underneath the cgi-bin directory, and the web server was configured to *not* allow direct access from a browser to these files). The main modification was to add a new utility function in the project's namespace @code{string slurp_file (const std::string &skin, const std::string &filename)} which is called by the program in lieu of slurp_file, and ensures that the file from the correct skin directory is chosen, calling through to the library function to get the eventual work done. To complete the effect, it is also necessary to derive a new class from Hyper_Tags with the following additional methods @code{blah, blah, blah} (The Query_String class works completely as is; it may be convenient to introduce this into the projects own namespace with a @code{typedef Query_String Query_String;} line in a project header file.) @node Other inheritence, , Web-site skins, Hints on how the library might be used in a real application @section Other inheritence @bye