diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..dc63aac --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/README b/README new file mode 100644 index 0000000..30739f7 --- /dev/null +++ b/README @@ -0,0 +1,119 @@ +Hi, this is version 1.03 of w3ng. + +Thanks for taking the time to have a look at it. It's far from perfect, so +don't be suprised if things break, but please let me know what does break. + +Ok, quick usage. First, stick w3ng into your /cgi-bin/ directory (or, +the directory that looks like /cgi-bin/ to the outside world). In a Web page, +do the following: + + + This is my test Norton Guide + +And away you go (I hope, works for me etc... ). + +Ok, here are some of the things that are not perfect yet or that I need +other people to test and give me feedback with: + +o Test it with as many NGs as possible. + +o w3ng does some very rough low and high PC character translation. I did + it in a rush so it's not going to look perfect. I will sit down and + design the box character to ASCII chaarcter mapping, plus some other + "special" picture characters, later. + +o The source is partly ripped off from a NG reader I was writing for OS/2. + Because of this it's possibly not optimized for the job in hand, please + excuse the code at the moment (possibly some left over vars, very few + comments etc..). + +o My knowledge of HTML is not great. If you see any problems with the + resulting HTML then please let me know. + +o As far as I can tell, the source should compile clean with GCC under + Linux, GCC under OS/2 (GCC/EMX), GCC under Dos (DJGPP) and Borland + under Dos. If you find otherwise, or you find another compiler/OS + that it either a) works with or b) you've made it work with then + please let me know. + +o There is no Makefile as yet. You should know how to compile, but, for + those who don't, I've used: + + Linux + gcc w3ng.c cfgfile.c -o w3ng + OS/2 (EMX) + gcc w3ng.c cfgfile.c -o w3ng.exe + Dos (DJGPP) + gcc w3ng.c cfgfile.c -o w3ng.out + strip w3ng.out + coff2exe w3ng.out + Dos (Borland) + bcc w3ng.c cfgfile.c + +o I've now added a -href parameter to help create index pages on the fly. + For example, on my server I've got a (quick and dirty) bash script as + follows: + + #!/bin/sh + + echo Content-type: text/html + echo + echo + echo "Directory Of Norton Guide Files + echo "" + echo "" + echo "
    " + for ng_file in /dos/c/eh/*.ng + do + echo "
  • $(w3ng $ng_file -href)" + done + echo "
" + +o w3ng now has a config file to allow you to control some HTML elements. + To set the location of the config file edit the #define CONFIG_FILE + that is close the top of the source. Make sure you make this the + full name of the file and not just a point to it's location or anything. + + Currently, the following options are available: + + BODY= + ----- + + Use this to specify your own element. For example, you may want + a graphic background to your pages: + + BODY= + + Note that what you are giving is the *whole* opening body command. + + FRAMES= + ------- + + If you have a browser that can work with frames (Netscape II for example) + you can tell w3ng to work with framed HTML. Set it to anything that starts + with Y or y to turn it on: + + FRAMES=yes please! + + FRAMECOLS= + ---------- + + This lets you specify the split for the frames. The default is 30% for + the menu and 70% for the pages. You can set it like: + + FRAMECOLS=30%,70% + + Note that what you set is what will be included in the HTML. + + +Hmm, I think that is about that for the moment. Any feedback is a good +thing. If you think it can be improved then let me know. Email your +feedback to davep@hagbard.demon.co.uk + +You may also want to check http://www.acemake.com/hagbard/w3ng.html for +details of the current version and known problems. + +Also, if you need to convert a NG to a set of HTML documents then you might +want to look at http://www.acemake.com/hagbard/ng2html.html. + +Thanks for your time. diff --git a/cfgfile.c b/cfgfile.c new file mode 100644 index 0000000..9a7733a --- /dev/null +++ b/cfgfile.c @@ -0,0 +1,182 @@ +/* + + CFGFILE - CONFIG FILE READING LIBRARY + Copyright (C) 1996 David A Pearson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the license, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/* + * Modification history: + * + * $Log: cfgfile.c,v $ + * Revision 1.1 1996/04/02 16:16:35 davep + * Initial revision + * + * + */ + +#include +#include + +#include "cfgfile.h" + +#if defined( __MSDOS__ ) || defined( __EMX__ ) +#define strcasecmp( x, y ) stricmp( x, y ) +#endif + +/* Config entry structure. */ + +typedef struct +{ + char *id; + char *value; + void *next; +} cfgOPTIONS; + +/* Prorotype internal functions */ + +static cfgOPTIONS *cfgLastOption( cfgOPTIONS * ); + +/* This holds the list of config options. */ + +static cfgOPTIONS *cfgOptions = NULL; + +/* + */ + +void cfgAddOption( char *pszId, char *pszValue ) +{ + cfgOPTIONS *p; + + if ( !cfgOptions ) + { + cfgOptions = (cfgOPTIONS *) calloc( sizeof( cfgOPTIONS ), 1 ); + cfgOptions->next = NULL; + p = cfgOptions; + } + else + { + p = cfgLastOption( cfgOptions ); + p->next = (void *) calloc( sizeof( cfgOPTIONS ), 1 ); + p = p->next; + p->next = NULL; + } + + p->id = (char *) malloc( strlen( pszId ) + 1 ); + p->value = (char *) malloc( strlen( pszValue ) + 1 ); + strcpy( p->id, pszId ); + strcpy( p->value, pszValue ); +} + +/* + */ + +int cfgReadFile( char *pszFile ) +{ + int i = 0; + FILE *f = fopen( pszFile, "r" ); + char *pszSplit; + char szBuffer[ 512 ]; + + cfgReset(); + + if ( f != NULL ) + { + while ( fgets( szBuffer, sizeof( szBuffer ), f ) ) + { + szBuffer[ strlen( szBuffer ) - 1 ] = 0; + if ( *szBuffer && *szBuffer != ';' && *szBuffer != '#' ) + { + pszSplit = szBuffer; + + while ( *pszSplit && *pszSplit != '=' ) + { + ++pszSplit; + } + + if ( *pszSplit ) + { + *pszSplit = 0; + ++pszSplit; + + if ( *pszSplit ) + { + cfgAddOption( szBuffer, pszSplit ); + ++i; + } + } + } + } + fclose( f ); + } + + return( i ); +} + +/* + */ + +char *cfgGetSetting( char *pszId ) +{ + char *p = NULL; + cfgOPTIONS *cfg = cfgOptions; + + while ( cfg && !p ) + { + if ( strcasecmp( pszId, cfg->id ) == 0 ) + { + p = cfg->value; + } + else + { + cfg = (cfgOPTIONS *) cfg->next; + } + } + + return( p ); +} + +/* + */ + +void cfgReset( void ) +{ + cfgOPTIONS *cfg = cfgOptions; + cfgOPTIONS *last; + + while ( cfg ) + { + if ( cfg->id ) free( cfg->id ); + if ( cfg->value ) free( cfg->value ); + last = cfg; + cfg = (cfgOPTIONS *) cfg->next; + free( last ); + } +} + +/* + */ + +static cfgOPTIONS *cfgLastOption( cfgOPTIONS *p ) +{ + while ( p->next ) + { + p = p->next; + } + + return( p ); +} diff --git a/cfgfile.h b/cfgfile.h new file mode 100644 index 0000000..061ef80 --- /dev/null +++ b/cfgfile.h @@ -0,0 +1,46 @@ +/* + + CFGFILE - CONFIG FILE READING LIBRARY + Copyright (C) 1996 David A Pearson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the license, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/* + * Modification history: + * + * $Log: cfgfile.h,v $ + * Revision 1.1 1996/04/02 16:16:53 davep + * Initial revision + * + * + */ + +/* Ensure we only get included once. */ + +#ifndef __CFGFILE_H +#define __CFGFILE_H + +/* Prototype functions found in the "library". */ + +void cfgAddOption( char *, char * ); +int cfgReadFile( char * ); +char *cfgGetSetting( char * ); +void cfgReset( void ); + +#endif + + diff --git a/w3ng.c b/w3ng.c new file mode 100644 index 0000000..07984bf --- /dev/null +++ b/w3ng.c @@ -0,0 +1,1222 @@ +/* + + W3NG CGI-BIN NORTON GUIDE FILTER. + Copyright (C) 1996 David A Pearson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the license, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/* + * Modification history: + * + * $Log: w3ng.c,v $ + * Revision 1.12 1996/04/01 15:10:16 davep + * Changed to work with Norton Guides that have no menu at all. + * + * Revision 1.11 1996/03/29 14:09:15 davep + * Added the ability to produce frames aware HTML code. + * + * Revision 1.10 1996/03/28 18:35:12 davep + * Added the config file allowing the setting of the token. This + * will allow you to specify (for example) a background image for the body + * of the message. + * + * Revision 1.9 1996/03/25 11:53:17 davep + * Fixed one more HTML silly. + * + * Revision 1.8 1996/03/22 17:35:40 davep + * Fixed Hex2Byte() which was badly broken. Also did some more work on + * producing correct HTML. The & characters was breaking some viewers + * such as Lynx, Explorer and Mosaic. This now produces a &. + * + * Revision 1.7 1996/03/21 16:45:31 davep + * Changed ReadLong() to work correctly for 16bit compilers. + * + * Revision 1.6 1996/03/20 19:59:46 davep + * Small changes to the style of HTML generated. This fixed the problem + * of some browsers not being able to handle the < and > symbols. + * + * Revision 1.5 1996/03/18 08:00:08 davep + * Fixed the problem with drop menus that have no menu items. + * + * Revision 1.4 1996/02/26 21:14:48 davep + * Added the -href switch. + * Fixed the "no null" bug with the NG header. + * + * Revision 1.3 1996/02/19 20:11:05 davep + * Made some changes so that it should now compile clean under Linux (GCC), + * OS/2 (GCC/EMX) and MS-Dos (Borland, DJGPP). The code still needs a good + * tidy (too much hang-over from Expect Guide) and a comment or two wouldn't + * hurt I guess. + * + * Revision 1.2 1996/02/16 10:40:52 davep + * Now compiles clean under Linux (GCC), OS/2 (EMX) and Dos (BCC). + * Also added a header to each page that gives the user the ability + * to navigate the guide a bit more like NG or EH would. + * + * Revision 1.1 1996/02/15 18:57:13 davep + * Initial revision + * + */ + +/* Account for some of the messy stuff we have to do with DOS compilers. */ + +#if defined( __MSDOS__ ) +#include +#if defined( __GNUC__ ) +#define _MAX_PATH MAXPATH +#define _MAX_FNAME MAXFILE +#define _MAX_EXT MAXEXT +#define _splitpath fnsplit +#define _makepath fnmerge +#endif +#endif + +/* Usual standard header files. */ + +#include +#include +#include +#include +#include + +/* Include file for the cfg*() functions. */ + +#include "cfgfile.h" + +/* Structure of the header record of a Norton Guide database. */ + +typedef struct +{ + unsigned short usMagic; + short sUnknown1; + short sUnknown2; + unsigned short usMenuCount; + char szTitle[ 40 ]; + char szCredits[ 5 ][ 66 ]; +} NGHEADER; + +/* Structure to hold a tidy version of the header. */ + +typedef struct +{ + unsigned short usMenuCount; + char szTitle[ 41 ]; + char szCredits[ 5 ][ 67 ]; +} NGTIDYHEAD; + +/* Handy defines. */ + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* Prototype functions found in this file. */ + +void ProcessNgRequest( int, char ** ); +int LoadWhat( char * ); +void ReadNG( FILE *, int, long ); +void ShowMainMenu( NGTIDYHEAD *, FILE *, int ); +void SkipSection( FILE * ); +long FindFirstShort( FILE * ); +void ShowMenu( FILE *, int ); +void GetStrZ( FILE *, char *, int ); +int ReadWord( FILE * ); +long ReadLong( FILE * ); +void ShowText( FILE *, long ); +void ShowShort( FILE * ); +void ShowLong( FILE * ); +void ExpandText( char * ); +unsigned char SaneText( unsigned char ); +int Hex2Byte( char * ); +void StandardButtons( void ); +void TidyHeader( NGHEADER *, NGTIDYHEAD * ); +void cgiHeader( void ); +void cgiFooter( void ); +void PrintHtmlChar( char ); +void LoadConfig( void ); +#if defined( __MSDOS__ ) || defined( __EMX__ ) +char *GetBaseName( char * ); +char *UnDosifyPath( char * ); +#endif + +/* The version number of w3ng. */ + +#define W3NG_VERSION "1.03" + +/* If you are compiling under Dos in 16bit mode, then un-comment the + following: */ + +/* #define _16_BIT_COMPILER_ */ + +/* Types of items that can be loaded. */ + +#define LOAD_INFO 1 +#define LOAD_MENU 2 +#define LOAD_FMENU 3 +#define LOAD_TEXT 4 +#define LOAD_HREF 5 +#define LOAD_UNKNOWN 6 + +#if defined( __MSDOS__ ) || defined( __EMX__ ) +#define strncasecmp( x, y, z ) strnicmp( x, y, z ) +#endif + +/* Decrypt the NGs "encryption". */ + +#define NG_DECRYPT( x ) ( (unsigned char) ( x ^ 0x1A ) ) + +/* Read a byte and decrypt it. */ + +#define NG_READBYTE( f ) ( NG_DECRYPT( getc( f ) ) ) + +/* A couple of file wide variables because I was feeling lazy. */ + +char *pszBasename; /* The basename of this program. */ +char *pszFile; /* The name of the NG we are reading. */ + +/* Change this to point to the location of the config file. */ + +#define CONFIG_FILE "/usr/local/etc/httpd/conf/w3ng.conf" + +/* Variable settinsg that affect the look of the generated HTML. */ + +char *pszBodyString = ""; +int iFrames = FALSE; +char *pszFrameCols = "30%,70%"; + +/* + * Function.: main() + * Prototype: int main( int argc, char **argv ) + * Arguments: You need me to explain that? + * Returns..: Program exit status. + * Notes....: It's main! + */ + +int main( int argc, char **argv ) +{ + if ( argc > 1 ) + { + +#if defined( __MSDOS__ ) || defined( __EMX__ ) + + /* + * If we are running on an OS that gives the full path to the exe + * attempt to strip if off, we only want the name of the EXE. I + * could have hard coded this, but what if you change the name of + * the executable? + */ + + pszBasename = GetBaseName( argv[ 0 ] ); + + /* + * Tidy up the name of the Norton Guide database. This means + * tunring all the \s into /s. + */ + + pszFile = UnDosifyPath( argv[ 1 ] ); + +#else + + /* + * With luck we are running on some kind of Unix clone, in which + * case, unless I'm wrong, argv[ 0 ] is just the basename of + * the executable. + */ + + pszBasename = argv[ 0 ]; + pszFile = argv[ 1 ]; +#endif + + LoadConfig(); + ProcessNgRequest( argc, argv ); + cfgReset(); + +#if defined( __MSDOS__ ) || defined( __EMX__ ) + + free( pszBasename ); + free( pszFile ); + +#endif + } + else + { + cgiHeader(); + printf( "usage: %s <file> [ -menu | -info | -href |" + " <offset> ]\n", argv[ 0 ] ); + cgiFooter(); + } + + return( 0 ); +} + +/* + * Function.: cgiHeader() + * Prototype: void cgiHeader( void ) + * Arguments: None. + * Returns..: Nothing. + * Notes....: Display the usual cgi header thingy. + */ + +void cgiHeader( void ) +{ + printf( "Content-type: text/html\n\n\n" ); +} + + +/* + * Function.: cgiFooter() + * Prototype: void cgiFooter( void ) + * Arguments: None. + * Returns..: Nothing. + * Notes....: Display a footer that says what was used to generate the + * .........: page and display my email address just in case. I won't + * .........: blame you if you change this or take it out. + */ + +void cgiFooter( void ) +{ + printf( "
This page created by w3ng v" W3NG_VERSION + ", the Norton Guide to HTML conversion utility. " + "Written by " + "Dave Pearson
\n\n" ); +} + +/* + * Function.: ProcessNgRequest() + * Prototype: void ProcessNgRequest( int argc, char **argv ) + * Arguments: Guess. + * Returns..: Nothing. + * Notes....: Take the command line, work out what needs doing and farm + * .........: out the work. + */ + +void ProcessNgRequest( int argc, char **argv ) +{ + int iLoadUp = LOAD_UNKNOWN; + long lOffset = 0; + FILE *fleNG = fopen( pszFile, "rb" ); + + if ( fleNG ) + { + if ( argc > 2 ) + { + /* If argv[ 2 ] starts with a '-'.... */ + + if ( *argv[ 2 ] == '-' ) + { + /* ....we expect it to be a "command". */ + + iLoadUp = LoadWhat( &argv[ 2 ][ 1 ] ); + } + else + { + + /* + * otherwise it should be a value that is the byte offset + * of a page to view from the NG. + */ + + lOffset = atol( argv[ 2 ] ); + iLoadUp = LOAD_TEXT; + } + } + + /* Now we know what we are suposed to be doing, go read the guide. */ + + ReadNG( fleNG, iLoadUp, lOffset ); + fclose( fleNG ); + } + else + { + printf( "Error: Can't find %s for opening\n", pszFile ); + } +} + +/* + * Function.: LoadWhat() + * Prototype: int LoadWhat( char *pszCmd ) + * Arguments: is a pointer to a null terminated string. This will + * .........: contain a "command". + * Returns..: One of the LOAD_* constants to tell the caller what the + * .........: command asked for. + * Notes....: Takes a string command and works out what the caller is asking + * .........: for. + */ + +int LoadWhat( char *pszCmd ) +{ + int iWhat = LOAD_UNKNOWN; + + if ( strncasecmp( pszCmd, "INFO", 4 ) == 0 ) + { + /* Display the "info" or "about" info for the guide. */ + iWhat = LOAD_INFO; + } + else if ( strncasecmp( pszCmd, "MENU", 4 ) == 0 ) + { + /* Display the top level menu. */ + iWhat = LOAD_MENU; + } + else if ( strncasecmp( pszCmd, "FMENU", 5 ) == 0 ) + { + /* Display the framed menu. */ + iWhat = LOAD_FMENU; + } + else if ( strncasecmp( pszCmd, "HREF", 4 ) == 0 ) + { + /* Display a href for the guide. */ + iWhat = LOAD_HREF; + } + + return( iWhat ); +} + +/* + * Function.: ReadNG() + * Prototype: void ReadNG( FILE *fleNG, int iLoadUp, long lOffset ) + * Arguments: is the (FILE *) handle for the Norton Guide. + * .........: is the ID of what we should load. + * .........: is the offset if this is a page and not a menu. + * Returns..: Nothing. + * Notes....: Based on what we are suppose to do, this function + * .........: DoesTheRightThing(TM). + */ + +void ReadNG( FILE *fleNG, int iLoadUp, long lOffset ) +{ + NGHEADER ngHeader; + NGTIDYHEAD ngTidyHead; + + /* + * Read in the header. Note that for the moment I don't check the + * magic number, so if you try to read a file that isn't a guide + * things could get strange. I will tidy this up at some point. + */ + + (void) fread( &ngHeader, sizeof( NGHEADER ), 1, fleNG ); + + /* Now tidy up the header. */ + + TidyHeader( &ngHeader, &ngTidyHead ); + + /* We could be looking at a guide that has no menu, if so, find the + first short entry and use that instead. */ + + if ( !ngTidyHead.usMenuCount && ( iLoadUp == LOAD_MENU || + iLoadUp == LOAD_FMENU )) + { + iLoadUp = LOAD_TEXT; + if ( !( lOffset = FindFirstShort( fleNG ) ) ) + { + printf( "w3ng error: Can't find a menu or short entry\n" ); + exit( 1 ); + } + } + + switch ( iLoadUp ) + { + + case LOAD_INFO : /* Load the "info" or "about" details for the guide. */ + cgiHeader(); + printf( "%s - Information\n", + ngTidyHead.szTitle ); + printf( "%s
  Title: %s\n", pszBodyString, ngTidyHead.szTitle );
+	printf( "Credits: %s\n"
+	       "         %s\n"
+	       "         %s\n"
+	       "         %s\n"
+	       "         %s\n
", + ngTidyHead.szCredits[ 0 ], + ngTidyHead.szCredits[ 1 ], + ngTidyHead.szCredits[ 2 ], + ngTidyHead.szCredits[ 3 ], + ngTidyHead.szCredits[ 4 ] ); + cgiFooter(); + break; + + case LOAD_MENU : /* Load the top level menu for the guide */ + cgiHeader(); + printf( "%s - Menu\n", + ngTidyHead.szTitle ); + if ( iFrames ) + { + printf( "\n", pszFrameCols ); + } + printf( "%s\n", pszBodyString ); + ShowMainMenu( &ngTidyHead, fleNG, FALSE ); + printf( "</BODY>" ); + if ( iFrames ) + { + printf( "\n\n\n\n\n", pszBasename, + pszFile, pszBasename, pszFile ); + } + else + { + cgiFooter(); + } + break; + + case LOAD_FMENU : /* Load the framed menu. */ + cgiHeader(); + printf( "%s - Menu\n", + ngTidyHead.szTitle ); + printf( "%s\n", pszBodyString ); + ShowMainMenu( &ngTidyHead, fleNG, TRUE ); + printf( "" ); + cgiFooter(); + break; + + case LOAD_TEXT : /* Load a page from the guide. */ + cgiHeader(); + printf( "%s - Text\n", + ngTidyHead.szTitle ); + printf( "%s
\n", pszBodyString );
+	ShowText( fleNG, lOffset );
+	printf( "
\n" ); + cgiFooter(); + break; + + case LOAD_HREF : /* Display a href for the guide. */ + printf( "%s", + pszBasename, pszFile, ngTidyHead.szTitle ); + + } +} + +/* + * Function.: ShowMainMenu() + * Prototype: void ShowMainMenu( NGTIDYHEAD *ngHeader, FILE *fleNG ) + * Arguments: is a NGTIDYHEAD structure populated with cleaned + * .........: up contents of the NG header. + * .........: is the (FILE *) handle of the NG. + * Returns..: Nothing. + * Notes....: Scans thru the NG, finds the main menu and displays it. + */ + +void ShowMainMenu( NGTIDYHEAD *ngHeader, FILE *fleNG, int iFramed ) +{ + int iID; + int i = 0; + + printf( "
    \n" ); + + do + { + iID = ReadWord( fleNG ); + + switch ( iID ) + { + case 0 : + case 1 : + SkipSection( fleNG ); + break; + case 2 : + ShowMenu( fleNG, iFramed ); + ++i; + break; + default : + iID = 5; + } + } while ( iID != 5 && i != ngHeader->usMenuCount ); + + printf( "
\n" ); +} + +/* + */ + +long FindFirstShort( FILE *f ) +{ + long lOffset = 0L; + int iID; + + do + { + iID = ReadWord( f ); + + switch( iID ) + { + case 0 : + lOffset = ftell( f ) - (long) sizeof( short ); + iID = 5; + break; + case 1 : + SkipSection( f ); + break; + case 2 : + SkipSection( f ); + break; + default : + iID = 5; + } + } while ( iID != 5 ); + + return( lOffset ); +} + +/* + */ + +void SkipSection( FILE *fleNG ) +{ + int iLen = ReadWord( fleNG ); + + fseek( fleNG, (long) 22L + iLen, SEEK_CUR ); +} + +/* + */ + +void ShowMenu( FILE *fleNG, int iFramed ) +{ + int iItems; + int i; + long l; + char szTitle[ 51 ]; + long *lpOffsets; + + (void) ReadWord( fleNG ); + iItems = ReadWord( fleNG ); + + fseek( fleNG, 20L, SEEK_CUR ); + + lpOffsets = (long *) calloc( iItems, sizeof( long ) ); + + assert( lpOffsets ); /* Ouch! */ + + for ( i = 1; i < iItems; i++ ) + { + lpOffsets[ i - 1 ] = ReadLong( fleNG ); + } + + l = ftell( fleNG ); + l += ( 8 * iItems ); + + fseek( fleNG, l, SEEK_SET ); + + GetStrZ( fleNG, szTitle, 40 ); + + printf( "

  • %s
  • \n", szTitle ); + printf( "

      \n" ); + + for ( i = 1; i < iItems; i++ ) + { + GetStrZ( fleNG, szTitle, 50 ); + + if ( !*szTitle ) + { + strcpy( szTitle, "(No Text For Menu Item)" ); + } + + printf( "

    1. %s
    2. \n", pszBasename, pszFile, + lpOffsets[ i - 1 ], iFramed ? " TARGET=\"display\"" : "", + szTitle ); + } + + printf( "

    \n" ); + + (void) getc( fleNG ); + + free( lpOffsets ); +} + +/* + */ + +void ShowText( FILE *fleNG, long lOffset ) +{ + int iID; + + fseek( fleNG, lOffset, SEEK_SET ); + + iID = ReadWord( fleNG ); + + if ( iID == 0 ) + { + ShowShort( fleNG ); + } + else if ( iID == 1 ) + { + ShowLong( fleNG ); + } + else + { + printf( "%s error: Unknown type ID of #%d", pszBasename, iID ); + } +} + +/* + */ + +void ShowShort( FILE *fleNG ) +{ + int iItems; + long *plOffsets; + int i; + char szBuffer[ 512 ]; + long lParent; + unsigned uParentLine; + + (void) ReadWord( fleNG ); + iItems = ReadWord( fleNG ); + (void) ReadWord( fleNG ); + + uParentLine = (unsigned) ReadWord( fleNG ); + lParent = ReadLong( fleNG ); + + fseek( fleNG, 12L, SEEK_CUR ); + + plOffsets = (long *) calloc( iItems, sizeof( long ) ); + + assert( plOffsets ); /* Ouch! */ + + for ( i = 0; i < iItems; i++ ) + { + ReadWord( fleNG ); + plOffsets[ i ] = ReadLong( fleNG ); + } + + printf( "" ); + + if ( lParent > 0 && uParentLine < 0xFFFF ) + { + printf( "[^^Up^^]", + pszBasename, pszFile, lParent ); + } + else + { + printf( "[^^Up^^] " ); + } + + StandardButtons(); + + printf( "
    " );
    +    
    +    for ( i = 0; i < iItems; i++ )
    +    {
    +	GetStrZ( fleNG, szBuffer, sizeof( szBuffer ) );
    +	if ( plOffsets[ i ] > 0 )
    +	{
    +	    printf( "",
    +		   pszBasename, pszFile, plOffsets[ i ] );
    +	    ExpandText( szBuffer );
    +	    printf( "\n" );
    +	}
    +	else
    +	{
    +	    ExpandText( szBuffer );
    +	    printf( "\n" );
    +	}
    +    }
    +    
    +    free( plOffsets );
    +}
    +
    +/*
    + */
    +
    +void ShowLong( FILE *fleNG )
    +{
    +    int      iItems;
    +    int      iSeeAlsos;
    +    int      i;
    +    int      iCnt;
    +    long     lPrevious;
    +    long     lNext;
    +    char     szBuffer[ 512 ];
    +    long     *plOffsets;
    +    long     lParent;
    +    unsigned uParentLine;
    +    
    +    (void) ReadWord( fleNG );
    +    
    +    iItems      = ReadWord( fleNG );
    +    iSeeAlsos   = ReadWord( fleNG );
    +    uParentLine = (unsigned) ReadWord( fleNG );
    +    lParent     = ReadLong( fleNG );
    +    
    +    fseek( fleNG, 4L, SEEK_CUR );
    +    
    +    lPrevious = ReadLong( fleNG );
    +    lNext     = ReadLong( fleNG );
    +    
    +    lPrevious = ( lPrevious == -1L ? 0L : lPrevious );
    +    lNext     = ( lNext == -1L ? 0L : lNext );
    +    
    +    printf( "
    " ); + if ( lPrevious ) + { + printf( "[<<Previous Entry]" + " ", pszBasename, pszFile, lPrevious ); + } + else + { + printf( "[<<Previous Entry] " ); + } + + if ( lParent > 0 && uParentLine < 0xFFFF ) + { + printf( "[^^Up^^] ", + pszBasename, pszFile, lParent ); + } + else + { + printf( "[^^Up^^] " ); + } + + if ( lNext ) + { + printf( "[Next Entry>>]", + pszBasename, pszFile, lNext ); + } + else + { + printf( "[Next Entry>>] " ); + } + + StandardButtons(); + + printf( "
    " );
    +    
    +    for ( i = 0; i < iItems; i++ )
    +    {
    +	GetStrZ( fleNG, szBuffer, sizeof( szBuffer ) );
    +	ExpandText( szBuffer );
    +	printf( "\n" );
    +    }
    +    
    +    if ( iSeeAlsos )
    +    {
    +	printf( "

    See Also: " ); + + iCnt = ReadWord( fleNG ); + plOffsets = (long *) calloc( iCnt, sizeof( long ) ); + + for ( i = 0; i < iCnt; i++ ) + { + /* There is a reason for this < 20 check, but + I can't remember what it is, so I'll leave + it in for the moment. */ + + if ( i < 20 ) + { + plOffsets[ i ] = ReadLong( fleNG ); + } + else + { + fseek( fleNG, 4L, SEEK_SET ); + } + } + + for ( i = 0; i < iCnt; i++ ) + { + if ( i < 20 ) + { + GetStrZ( fleNG, szBuffer, sizeof( szBuffer ) ); + printf( "" + "%s ", + pszBasename, pszFile, + plOffsets[ i ], szBuffer ); + } + } + + printf( "
    " );
    +    }
    +}
    +
    +/*
    + */
    +
    +int ReadWord( FILE *f )
    +{
    +    unsigned char b1 = NG_READBYTE( f );
    +    unsigned char b2 = NG_READBYTE( f );
    +    
    +    return( ( b2 << 8 ) + b1 );
    +}
    +
    +/*
    + */
    +
    +long ReadLong( FILE *f )
    +{
    +    int i1 = ReadWord( f );
    +    int i2 = ReadWord( f );
    +
    +#ifdef _16_BIT_COMPILER_
    +    long l  = 0;
    +    int  *i = (int *) &l;
    +
    +    i[ 0 ] = i1;
    +    i[ 1 ] = i2;
    +
    +    return( (long) l );
    +#else
    +    return( ( i2 << 16 ) + i1 );
    +#endif
    +}
    +
    +/*
    + */
    +
    +void GetStrZ( FILE *f, char *pszBuffer, int iMax )
    +{
    +    long lSavPos = ftell( f );
    +    int  fEOS = 0;
    +    int  i;
    +    
    +    (void) fread( pszBuffer, iMax, 1, f );
    +    
    +    for ( i = 0; i < iMax && !fEOS; i++, pszBuffer++ )
    +    {
    +	*pszBuffer = NG_DECRYPT( *pszBuffer );
    +	fEOS       = ( *pszBuffer == 0 );
    +    }
    +    
    +    fseek( f, (long) lSavPos + i, SEEK_SET );
    +}
    +
    +/*
    + */
    +
    +void ExpandText( char *pszText )
    +{
    +    char *psz   = pszText;
    +    int  iBold  = 0;
    +    int  iUnder = 0;
    +    int  iSpaces;
    +    int  i;
    +    
    +    while ( *psz )
    +    {
    +	switch ( *psz )
    +	{
    +	case '^' :
    +	    ++psz;
    +	    
    +	    switch ( *psz )
    +	    {
    +	    case 'a' :
    +	    case 'A' :
    +		++psz;
    +		/* I suppose I could use the colour attribute, but for
    +		   the moment just skip it. */
    +		(void) Hex2Byte( psz );
    +		++psz;
    +		break;
    +	    case 'b' :
    +	    case 'B' :
    +		printf( iBold ? "" : "" );
    +		iBold = !iBold;
    +		break;
    +	    case 'c' :
    +	    case 'C' :
    +		++psz;
    +		PrintHtmlChar( SaneText( Hex2Byte( psz ) ) );
    +		++psz;
    +		break;
    +	    case 'n' :
    +	    case 'N' :
    +		if ( iBold ) printf( "" );
    +		if ( iUnder ) printf( "" );
    +		iBold = 0;
    +		iUnder = 0;
    +		break;
    +	    case 'r' :
    +	    case 'R' :
    +		/* Turn on reverse */
    +		break;
    +	    case 'u' :
    +	    case 'U' :
    +		printf( iUnder ? "" : "" );
    +		iUnder = !iUnder;
    +		break;
    +	    case '^' :
    +		putchar( '^' );
    +		break;
    +	    default :
    +		--psz;
    +	    }
    +	    break;
    +	case (char) 0xFF :
    +	    ++psz;
    +	    
    +	    iSpaces = *psz;
    +	    
    +	    for ( i = 0; i < iSpaces; i++ )
    +	    {
    +		putchar( ' ' );
    +	    }
    +	    break;
    +	default :
    +	    PrintHtmlChar( SaneText( *psz ) );
    +	    break;
    +	}
    +	
    +	++psz;
    +    }
    +    
    +    if ( iBold ) printf( "" );
    +    if ( iUnder ) printf( "" );
    +}
    +
    +/*
    + */
    +
    +unsigned char SaneText( unsigned char bChar )
    +{
    +    switch ( bChar )
    +    {
    +    case 0xB3 :            /* Vertical graphics. */
    +    case 0xB4 :
    +    case 0xB5 :
    +    case 0xB6 :
    +    case 0xB9 :
    +    case 0xBA :
    +    case 0xC3 :
    +    case 0xCC :
    +	bChar = '|';
    +	break;
    +    case 0xC4 :            /* Horizontal graphics. */
    +    case 0xC1 :
    +    case 0xC2 :
    +    case 0xC6 :
    +    case 0xC7 :
    +    case 0xCA :
    +    case 0xCB :
    +    case 0xCD :
    +    case 0xCF :
    +    case 0xD0 :
    +    case 0xD1 :
    +    case 0xD2 :
    +	bChar = '-';
    +	break;
    +    case 0xB7 :            /* Corner graphics. */
    +    case 0xB8 :
    +    case 0xBB :
    +    case 0xBC :
    +    case 0xBD :
    +    case 0xBE :
    +    case 0xBF :
    +    case 0xC0 :
    +    case 0xC5 :
    +    case 0xC8 :
    +    case 0xC9 :
    +    case 0xCE :
    +    case 0xD3 :
    +    case 0xD4 :
    +    case 0xD5 :
    +    case 0xD6 :
    +    case 0xD7 :
    +    case 0xD8 :
    +    case 0xD9 :
    +    case 0xDA :
    +	bChar = '+';
    +	break;
    +    case 0xDB :            /* Block graphics */
    +    case 0xDC :
    +    case 0xDD :
    +    case 0xDE :
    +    case 0xDF :
    +    case 0xB0 :
    +    case 0xB1 :
    +    case 0xB2 :
    +	bChar = '#';
    +	break;
    +    default :
    +	if ( ( bChar < ' ' || bChar > 0x7E ) && bChar )
    +	{
    +	    bChar = '.';
    +	}
    +    }
    +    
    +    return( bChar );
    +}
    +
    +/*
    + */
    +
    +int Hex2Byte( char *psz )
    +{
    +    int iByte;
    +    int i;
    +    unsigned char bByte = 0;
    +    
    +    for ( i = 0; i < 2; i++, psz++ )
    +    {
    +	*psz = (char) toupper( *psz );
    +	
    +	if ( *psz > '/' && *psz < ':' )
    +	{
    +	    iByte = ( ( (int) *psz ) - '0' );
    +	}
    +	else if ( *psz > '@' && *psz < 'G' )
    +	{
    +	    iByte = ( ( (int) *psz ) - '7' );
    +	}
    +	
    +	bByte += ( iByte * ( !i ? 16 : 1 ) );
    +    }
    +    
    +    return( (int) bByte );
    +}
    +
    +/*
    + */
    +
    +void StandardButtons( void )
    +{
    +    printf( " [Menu]",
    +	   pszBasename, pszFile, iFrames ? "fmenu" : "menu",
    +	   iFrames ? " TARGET=\"menu\"" : "" );
    +    printf( " "
    +	   "[About The Guide]", pszBasename, pszFile );
    +}
    +
    +/*
    + */
    +
    +void TidyHeader( NGHEADER *pngHeader, NGTIDYHEAD *pngTidy )
    +{
    +    int i;
    +    int n;
    +
    +    for ( i = 0; i < 40; i++ )
    +    {
    +	pngHeader->szTitle[ i ] = SaneText( pngHeader->szTitle[ i ] );
    +    }
    +
    +    for ( i = 0; i < 5; i++ )
    +    {
    +	for ( n = 0; n < 66; n++ )
    +	{
    +	    pngHeader->szCredits[ i ][ n ] = 
    +		SaneText( pngHeader->szCredits[ i ][ n ] );
    +	}
    +    }
    +
    +    pngTidy->usMenuCount = pngHeader->usMenuCount;
    +    strncpy( pngTidy->szTitle, pngHeader->szTitle, 40 );
    +
    +    for ( i = 0; i < 5; i++ )
    +    {
    +	strncpy( pngTidy->szCredits[ i ], pngHeader->szCredits[ i ], 66 );
    +    }
    +}
    +
    +/*
    + */
    +
    +void PrintHtmlChar( char c )
    +{
    +    switch ( c )
    +    {
    +    case '<' :
    +	printf( "<" );
    +	break;
    +    case '>' :
    +	printf( ">" );
    +	break;
    +    case '&' :
    +        printf( "&" );
    +	break;
    +    case 0x0 :
    +	printf( " " );
    +	break;
    +    default :
    +	printf( "%c", c );
    +    }
    +}
    +
    +/*
    + */
    +
    +void LoadConfig( void )
    +{
    +    char *p;
    +
    +    if ( cfgReadFile( CONFIG_FILE ) )
    +    {
    +	if ( cfgGetSetting( "BODY" ) )
    +	{
    +	    pszBodyString = cfgGetSetting( "BODY" );
    +	}
    +	if ( cfgGetSetting( "FRAMECOLS" ) )
    +	{
    +	    pszFrameCols  = cfgGetSetting( "FRAMECOLS" );
    +	}
    +
    +	if ( ( p = cfgGetSetting( "FRAMES" ) ) )
    +	{
    +	    iFrames = ( *p == '1' || *p == 'Y' || *p == 'y' );
    +	}
    +    }
    +}
    +
    +#if defined( __MSDOS__ ) || defined( __EMX__ )
    +
    +/*
    + */
    +
    +char *GetBaseName( char *pszExePath )
    +{
    +    char szFile[ _MAX_FNAME ];
    +    char szExt[ _MAX_EXT ];
    +    char szWork[ _MAX_PATH ];
    +    char *pszBase;
    +    
    +    _splitpath( pszExePath, NULL, NULL, szFile, szExt );
    +    _makepath( szWork, "", "", szFile, szExt );
    +    
    +    pszBase = malloc( strlen( szWork ) + 1 );
    +    
    +    assert( pszBase ); /* Ouch! */
    +    
    +    strcpy( pszBase, szWork );
    +    
    +    return( pszBase );
    +}
    +
    +/*
    + */
    +
    +char *UnDosifyPath( char *pszPath )
    +{
    +    char *pszSanePath = malloc( strlen( pszPath ) + 1 );
    +    char *p           = pszSanePath;
    +    
    +    assert( pszSanePath ); /* Ouch! */
    +    
    +    strcpy( pszSanePath, pszPath );
    +    
    +    while ( *p )
    +    {
    +	if ( *p == '\\' )
    +	{
    +	    *p = '/';
    +	}
    +	++p;
    +    }
    +    
    +    return( pszSanePath );
    +}
    +
    +#endif