/*
* fmtr - formatter for web pages...
*
* Created by: Jack C Lipton (see http://www.asstr.org/~CupaSoup/
*
* Some notes:
*
* Input paragraphs are NOT indented; tab-based indented
* lines are discarded.
*
* Paragraphs are separated by a blank line.
*
* *word* emboldens the "word" (or words).
*
* _word_ emphasises the "word" (or words) via bold+italics.
*
* |line will set the line as "centered.
*
* _ alone on a line will emit '<HR SIZE=5>'.
*
*
* ===========================================================================
*
* Portability:
* This program should be relatively easy to port to any
* system that handles the file namespace in a reasonably
* Unix-like way.
*
* ===========================================================================
*
* $Id: fmtr.c,v 1.20 2007/12/24 19:11:20 jcl Exp jcl $
*
* $Author: jcl $
*
* $Log: fmtr.c,v $
* Revision 1.20 2007/12/24 19:11:20 jcl
* fixed the problem of not recognizing escapes for '_' emphasis
*
* Revision 1.19 2006/07/20 21:19:48 jcl
* pass along name of the input file to allow
* the inclusion of name.prefix and name.suffix
* to be recognized an (pre/post)-pended.
*
* Revision 1.18 2006/04/04 19:10:16 jcl
* first cut at parametrizing the text to HTML transcoder.
*
* Revision 1.17 2005/02/06 17:38:57 jcl
* another chunk of logic intended to parse the "parts" of a story
* so that a "fini" doesn't appear too soon. It still doesn't work
* but at least the logic is present.
*
* Revision 1.16 2005/01/08 19:38:44 jcl
* updated the copyright information.
*
* Revision 1.15 2005/01/03 18:56:54 jcl
* added logic (and switches) to handle different feedback forms...
*
* Revision 1.14 2004/06/27 14:57:08 jcl
* fully parameterized the "author specifics" and corrected egregious syntax errors.
*
* Revision 1.13 2004/06/27 14:48:49 jcl
* added:
* 1) logic to allow author overrides to be done globally
* (and to be compiled in, too)
* 2) ability to add preface/suffix to a transcoded page;
* this allows adding the ASSTR sponsorship or any
* disclaimers by including them from one place.
* 3) Changed addresses from softhome.net (and fixed the
* bad "pele.net" address which probably dropped a bunch
* of rate/reviews off the planet and into a bit bucket).
*
* I really need to tack on a GNU Public License to this code
* so that people aren't afraid to use it.
*
* Revision 1.12 2004/05/14 02:15:55 jcl
* added logic to enhance ability to find "(incomplete)" in a heading.
* This allows the actual transcoding logic to behave differently when
* closing the end of a file.
*
* Revision 1.11 2004/03/09 02:16:24 jcl
* handle insertion info for the Universe name
*
* Revision 1.10 2004/02/08 14:03:49 jcl
* added logic to handle EWPUB as well as ASSTR... and allows other formats as well.
*
* Revision 1.9 2003/08/11 22:58:54 jcl
* make the "Fini" dependant upon whether a "next chapter" link exists.
*
* Revision 1.8 2003/08/10 15:26:53 jcl
* added ability to use -P to provide file for "next" linkage as well
* as -N for "prev" linkages, handled implicitly.
* new logic to allow >file:label alone on a line to add links inside
* a text file.
*
* Revision 1.7 2003/08/10 14:37:36 jcl
* corrected issues w/ double // in URL
*
* Revision 1.6 2003/07/26 02:32:30 jcl
* corrected closure of TT section.
*
* Revision 1.5 2003/07/21 17:26:26 jcl
* corrected some stuff
*
* Revision 1.4 2003/07/14 11:48:41 jcl
* formatting logic
*
* Revision 1.3 2003/07/12 14:31:52 jcl
* corrected issue in emphasis/bolding logic.
*
* Revision 1.2 2003/07/12 06:03:28 jcl
* default to a zero exit code.
*
* Revision 1.1 2003/07/12 05:57:31 jcl
* Initial revision
*
* ===========================================================================
*
*/
#include <stdio.h>
/*
* Provide early location for compiled-in global overrides
*/
/* #define OVERRIDE_AUTHOR "Jack C Lipton"*/
#define WEB_AUTHORNAME "Jack C Lipton"
#define WEB_AUTHOREMAIL "cupasoup@pele.cx"
#define WEB_ROOTDIR "http://www.asstr.org/~CupaSoup/"
#define WEB_SERIALNO "CXNRITNZQLQQBDITGAVD"
#define COPYRIGHT_HEADING "2002, 2003, 2004, 2005 Jack C Lipton"
/*
* Manifest constants (stupid, yes.)
*/
#define INBUFSIZE 4096
/*
* These are used in generating the "snippet" for the
* Reader's Rate/Review system and the copyright notice.
* (Note that the "Copyright (c)" with the circle around
* the "c" is embedded in the putFini() logic.)
*
* Each author needs to tune this for themselves.
*/
#if 1
char web_authorname[512];
char web_authoremail[512];
char web_rootdir[512];
char web_serial_number[256];
#else
char *web_authorname = WEB_AUTHORNAME;
char *web_authoremail = WEB_AUTHOREMAIL;
char *web_rootdir = WEB_ROOTDIR;
char *web_serial_number = WEB_SERIALNO;
#endif
char author_override[512];
#if defined(LIX_ENABLED)
char *acrrs_url =
"http://cgi.tripod.com/lixdw1192/cgi-bin/loadeval.pl";
#endif
char *copyright_heading = COPYRIGHT_HEADING;
char *copyright_body = "All rights reserved. Please contact author for other use.";
char web_page_name[512];
char corename[512];
char next_page_name[512];
char prev_page_name[512];
/*
* SHS Formats for publication
*
* |Author:
* |Title:
* |Part:
* |Universe:
* |Summary:
* |Keywords:
* |Revision: $Revision: 1.20 $
* |Archive:
* |Mailing List:
* |FAQ:
* |RCS: $Id: fmtr.c,v 1.20 2007/12/24 19:11:20 jcl Exp jcl $
*
*/
char shs_authorname[1024];
char shs_title[1024];
char shs_part[1024];
char shs_universe[1024];
char shs_summary[4096];
char shs_keywords[1024];
char shs_revision[1024];
char shs_archive[1024];
char shs_mailinglist[1024];
char shs_faq[1024];
char shs_rcs[1024];
/*
* Here's the structure I use to map the tag names and point to
* the buffers, above; This makes the logic to fill the buffers
* that much easier.
*
* Yes, this is awkward and I might have been able to do better.
*/
struct MapItems {
char *label; /* label part of SHS line */
int lablen, /* length of label to check */
buflen; /* length of the buffer */
char *buffer; /* pointer to buffer */
};
struct MapItems shsInfo[] = {
{ "Author:", 7, 1024, shs_authorname },
{ "Title:", 6, 1024, shs_title },
{ "Part:", 5, 1024, shs_part },
{ "Universe:", 9, 1024, shs_universe },
{ "Summary:", 8, 4096, shs_summary },
{ "Keywords:", 9, 1024, shs_keywords },
{ "Revision:", 9, 1024, shs_revision },
{ "Archive:", 8, 1024, shs_archive },
{ "Mailing List:", 13, 1024, shs_mailinglist },
{ "FAQ:", 4, 1024, shs_faq },
{ "RCS:", 4, 1024, shs_rcs },
{ NULL, 0, 0, NULL }
};
/*
* Handle baseline emphasis logic
*/
char *emphasizers[2] = { "<I><B>", "</B></I>" };
char *bolders[2] = { "<B>", "</B>" };
static int bolding = 0,
emphasized = 0;
static int leadin_skip = 1;
static int consec_blank = 0; /* consecutive blank lines */
static int force_fb_form = 0; /* force creation of fb file */
/*
* A fill_mode of zero indicates normal delivery of the file; a 1
* will cause each input line to get a line break (which is really
* needed when delivering poetry).
* What's interesting is that someday I'll want to be able to flip
* this on-and-off on the fly via embedded operations, but that can
* wait...
*/
int fill_mode = 0; /* assume normal wrapping */
int adultflag = 1; /* assume ADULTSONLY tag */
int asstrflag = 1; /* generate HTML for ASSTR */
int ewpubflag = 0; /* generate HTML for EWP.ORG */
int fini_flag = 1; /* assume one complete part */
char SecName[256]; /* section name (Universe) */
/*
* Some things really want to have function prototypes to shut
* up all of the warning messages I keep getting...
*/
extern char *basename( char *);
extern char *dirname( char *);
extern char *strchr( char *, char);
extern char *strrchr( char *, char);
extern char *malloc( unsigned int);
extern char *strstr( char *, char *);
/*
* Here are the function prototypes so that all forward references
* won't bitch and moan about function typing...
*/
int cvtFile( char *, FILE *, FILE *); /* convert text part of a file */
int cvtLine( FILE *, char *); /* convert a text ling from a file */
int procSHS( char *, FILE *, FILE *, char *); /* digest SHS */
void put_acrrs_snippet( FILE *); /* insert rate/review button */
void putFini( FILE *); /* put appropriate ending on webfile */
int FindInBuffer( char *, char *); /* scan buffer for matching contents */
int mkFBform( char *); /* generate HTML feedback form */
int appendFBform( FILE *, char *); /* append a feedback form */
main( argc, argv, envp) /* formatter utility */
int argc;
char *argv[];
char *envp[];
{
int a; /* arglist index */
char textpath[1024], /* path name of input file */
webpath[1024], /* path of output file w/ + */
oldwebpage[1024]; /* assumed name of base page */
FILE *textfile, /* input file handle/pointer */
*webfile; /* resultant file pointer */
/*
* Set default values for all global variables...
*/
fill_mode = 0; /* ensure default fill mode */
strcpy( next_page_name, "");
strcpy( prev_page_name, "");
#if defined(WEB_AUTHORNAME)
strcpy( web_authorname, WEB_AUTHORNAME);
strcpy( web_authoremail, WEB_AUTHOREMAIL);
strcpy( web_rootdir, WEB_ROOTDIR);
strcpy( web_serial_number, WEB_SERIALNO);
#else
strcpy( web_authorname, "");
strcpy( web_authoremail, "");
strcpy( web_rootdir, "");
strcpy( web_serial_number, "");
#endif
#if defined(OVERRIDE_AUTHOR)
strcpy( author_override, OVERRIDE_AUTHOR);/* allow for global change */
#else
strcpy( author_override, "");
#endif
/*
* Work through the arglist, handling options that change
* the behavior of this text file filter.
*/
for ( a = 1 ; a < argc ; a++ )
{
if ( argv[a][0] == '-' )
{
switch( argv[a][1])
{
case 'I': /* override who "I" am */
if ( strlen( argv[a]) > 2 )
strcpy( author_override, &argv[a][2]);
else
strcpy( author_override, argv[++a]);
break;
case 'w': /* word fill */
fill_mode = 0;
break;
case 'l': /* line mode (for poetry) */
fill_mode = 1;
break;
case 'A': /* turn off ADULTSONLY tag */
adultflag = 0;
break;
case 'a': /* turn on ADULTSONLY tag */
adultflag = 1;
break;
case 'P': /* previous file's name */
if ( strlen(argv[a]) > 2 )
strcpy( prev_page_name, &argv[a][2]);
else
strcpy( prev_page_name, argv[++a]);
break;
case 'N': /* next file's name */
if ( strlen(argv[a]) > 2 )
strcpy( next_page_name, &argv[a][2]);
else
strcpy( next_page_name, argv[++a]);
break;
case 'e': /* target EWPUB not ASSTR */
asstrflag = 0;
ewpubflag = 1;
adultflag = 0;
break;
case 'E': /* target ASSTR not EWPUB */
asstrflag = 1;
ewpubflag = 0;
adultflag = 1;
break;
}
}
else /* process the file as named */
{
int rc;
char *cp;
char cmdline[512];
/*
* We need to synthesize the target named from
* the input name.
*/
strcpy( textpath, argv[a]); /* copy in the name */
textfile = fopen( textpath, "r");
/*
* If we can't open the input file we can
* give up trying to write something...
*/
if ( !textfile )
{
fprintf( stderr,
"Could not open [%s] for reading.\n",
textpath);
fflush( stderr);
exit( 1);
}
/*
* capture the name of the file w/o extensions
* (ie. no .txt, .x, or whatnot) and without
* the directory part (should it be present).
*/
strcpy( corename, basename(textpath));
cp = strrchr( corename, '.');
if ( cp && *cp ) { *cp = 0x00; }
/*
* Synthesize the name we'll be outputting to;
* it'll be a dir/corename.html+ so that we
* can choose whether to do a cutover (or not).
*/
strcpy( web_page_name, corename);
strcpy( webpath, dirname( textpath));
strcat( webpath, "/");
strcat( webpath, corename);
strcat( webpath, ".html");
strcpy( oldwebpage, webpath); /* name for compare */
strcat( webpath, "+"); /* new name */
/*
* Report on the start of the conversion process
*/
#if defined(BE_VERBOSE)
fprintf( stderr, "%s ... ", corename);
fflush( stderr);
#endif
webfile = fopen( webpath, "w");
fini_flag = 1; /* assume completed */
if ( !webfile )
{
/*
* if we fail to open output, puke it up
*/
fclose( textfile);
fprintf( stderr,
"Could not open [%s] for writing.\n",
webpath);
fflush( stderr);
exit( 2);
}
/*
* Now we can convert the file. The cvtFile()
* function will digest the SHS headers and
* then process the actual text. When the
* input file has been finished the putFini()
* call closes it out.
*/
cvtFile( corename, textfile, webfile);
putFini( webfile);
#if defined(BE_VERBOSE)
fprintf( stderr, "\n"); /* indicate completion */
fflush( stderr);
#endif
/*
* Done with the files, close 'em
*/
fclose( textfile);
fclose( webfile);
/*
* We want to make the "cutover" process a
* conditional one; if no changes have been
* made, we want to skip the cutover.
*/
sprintf( cmdline, "diff %s %s >/dev/null",
oldwebpage, webpath);
rc = system( cmdline);
/*
* If the diff command exited w/ a zer0, there's
* no differences, so we'll ditch the new file
* since there's no point to cutting over a file
* that has no differences.
*/
if ( rc == 0 ) /* files are identical */
{
unlink( webpath); /* discard redundant */
}
else
{
sprintf( cmdline, "cutover %s", oldwebpage);
system( cmdline);
}
}
}
exit( 0);
} /* fmtr main */
/*
* procSHS - This function reads in the source file's SHS
* (Standard Header Sequence) for ASSTR which is
* intended to keep the story meta-information in
* proximity to the actual story content. It is
* hoped this will not be clipped since it keeps
* the most useful information in a recognizable
* form.
*/
int
procSHS( corename, si, so, inbuf) /* process SHS headers and populate table */
char *corename; /* used to check for importable item */
FILE *si, /* flat ascii w/ SHS-based prefix */
*so; /* resultant HTML file to be filled */
char *inbuf; /* line that broke the SHS scanning */
{
int i, /* index into SHS map table */
llen; /* line length as seen */
char *cp; /* utility pointer */
char importname[4096]; /* name for imported objects */
/*
* Before processing the open file we need to clear the
* target buffers
*/
for ( i = 0 ; shsInfo[i].buflen > 0 ; i++ ) /* clear previous */
{
strcpy( shsInfo[i].buffer, "");
}
/*
* Read lines from the file and scan them for leadin
* SHS lines...
*/
while ( fgets( inbuf, 4095, si) )
{
llen = strlen( inbuf);
inbuf[--llen] = 0x00; /* drop the newline */
/*
* Detect changes that will indicate the end of
* the heading section...
*/
if ( llen == 0 ) break;
if ( inbuf[0] == ' ' ) break;
if ( inbuf[0] == '\t' ) break;
/*
* OK, scan the input buffer against the list of
* labels we're looking to deal with.
*/
for ( i = 0 ; shsInfo[i].buflen > 0 ; i++ )
{
struct MapItems *map;
map = &shsInfo[i];
/*
* If the label matches, we'll process it
* properly by finding the data part...
*/
if ( strncmp( inbuf, map->label, map->lablen ) == 0 )
{
char *cp;
cp = strchr( inbuf, ':');
if ( cp && *cp ) cp++;
if ( cp && *cp ) cp++;
strncpy( map->buffer, cp, map->buflen);
break;
}
}
}
/*
* Provide opportunity to process non-RCS updates
* (Any overrides that are either compiled in or have been
* added to the command line in the make file.)
*/
if ( *author_override ) /* is this a non-empty string? */
{
strcpy( shs_authorname, author_override);
}
/*
* Note: I need this code to scratch a bogus part of
* the Author: line without me having to go
* back in to each file just to remove an email
* address from the SHS headers.
*/
cp = shs_authorname;
while ( cp
&& *cp
&& ( *cp != '<' ) )
{
cp++;
}
if ( *cp == '<' ) /* e-mail address present? */
{
*cp-- = '\0';
if ( ( *cp == ' ' ) || ( *cp == '\t' ) )
{
*cp = '\0';
}
}
/*
* All the SHS information has been accumulated at this point
* so we can now start generating the web-formatted file.
*
* Note that this is ancient HTML, capiche?
*/
fprintf( so, "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
fprintf( so, "<HTML>\n<HEAD>\n\n");
fprintf( so, "<TITLE> %s </TITLE>\n\n", shs_title);
/*
* The following tag is assumed for content on ASSTR
* (I'm not really sure how this _should_ be done, BTW)
* I've implementest this as a conditional so that it
* can be turned off for other content.
*/
if ( adultflag )
{
fprintf( so, "<!--ADULTSONLY-->\n");
}
/*
* Here we fill in the Meta information we've accumulated
* from the SHS headers, as recommended by others.
*/
if ( asstrflag != 0 )
{
fprintf( so, "<META NAME=\"shs-title\" CONTENT=\"%s\" />\n", shs_title);
fprintf( so, "<META NAME=\"shs-part\" CONTENT=\"%s\" />\n", shs_part);
fprintf( so, "<META NAME=\"shs-author\" CONTENT=\"%s\" />\n", shs_authorname);
fprintf( so, "<META NAME=\"shs-keywords\" CONTENT=\"%s\" />\n", shs_keywords);
#if 0
fprintf( so, "<META NAME=\"date\" CONTENT=\"%s\" />\n", "`date`");
#endif
fprintf( so, "<META NAME=\"shs-universe\" CONTENT=\"%s\" />\n", shs_universe);
fprintf( so, "<META NAME=\"shs-summary\" CONTENT=\"%s\" />\n", shs_summary);
fprintf( so, "<META NAME=\"shs-revision\" CONTENT=\"%s\" />\n", shs_revision);
}
fprintf( so, "</HEAD>\n");
if ( ewpubflag == 1 )
{
fprintf( so, "<BODY>\n\n");
}
else
{
FILE *insertable;
char insertbuf[4096];
fprintf( so, "<BODY TEXT=\"#000000\" BGCOLOR=\"#FAF0E6\" LINK=\"#7F0000\" VLINK=\"#007F00\" ALINK=\"#00007F\">\n\n");
/*
* Insert the contents of "web.prefix" at this point
*/
insertable = fopen( "web.prefix", "r");
while ( insertable && fgets( insertbuf, 4095, insertable) )
{
fputs( insertbuf, so); /* copy line out */
}
if ( insertable )
fclose( insertable);
}
/*
* Now we can start populating the actual content of the
* web page by plugging in the initial H1 header.
*/
fprintf( so, "<H1 ALIGN=\"CENTER\">\n");
fprintf( so, "%s\n", shs_title);
if ( strcmp( shs_part, "") != 0 )
{
fprintf( so, "(part %s)\n", shs_part);
}
fprintf( so, "</H1>\n");
fprintf( so, "<CENTER>\n");
/*
* With the title out of the way we can now present the
* remainder:
* Keywords;
* Author's MAILTO and name;
* Main Page back-link;
* Rate/Review button (if enabled).
*/
if ( strcmp( shs_keywords, "" ) != 0 )
{
fprintf( so, "<B>codes:</B> %s\t<BR>\n", shs_keywords);
}
#if 0
fprintf( so, "by <A HREF=\"mailto:%s\">%s</A><BR>\n",
web_authoremail, web_authorname);
#else
fprintf( so, "by <B><BIG>%s</BIG></B> <BR>\n", shs_authorname);
#endif
if ( asstrflag != 0 )
{
fprintf( so, "(<A HREF=\"index.html\">Main Page</A>)<BR>\n");
}
if ( strlen( prev_page_name) != 0 )
{
fprintf( so, " <A HREF=\"%s\"> Previous Chapter </A> <BR>\n",
prev_page_name);
}
fflush( so);
fprintf( so, "</CENTER>\n");
fprintf( so, "<BR>\n");
#if 0
if ( asstrflag != 0 )
put_acrrs_snippet( so);
#endif
fprintf( so, "<BR>\n");
fflush( so);
/*
* If we find a "(SecName).preface" file present we want to
* merge it into the resultant stream at this point. This
* allows acknowledgements to be assembled dynamically.
*/
strcpy( SecName, "");
if ( shs_universe[0] )
{
FILE *pf;
char *cp = shs_universe;
char *dp = SecName;
char preface_path[512];
while ( cp && *cp && (*cp != ' ') )
*dp++ = *cp++;
*dp = 0x00;
sprintf( preface_path, "%s.preface", SecName);
pf = fopen( preface_path, "r");
if ( pf )
{
char iobuf[4096];
while ( fgets( iobuf, 4095, pf) )
fputs( iobuf, so);
fclose( pf);
}
}
/*
* Cheat - check for a specific prefix
*/
{
FILE *pf;
char importName[4096];
sprintf( importname, "%s.prefix", corename);
pf = fopen( importname, "r");
if ( pf )
{
char iobuf[4096];
while ( fgets( iobuf, 4095, pf) )
fputs( iobuf, so);
fclose( pf);
}
}
/*
* We make a pass through the shs_title to check for an
* incomplete work (where the word "incomplete" will be
* in the 'Title:' line):
*/
fini_flag = ( FindInBuffer(shs_title, "(incomplete)") == 0 );
/*
* Now we're ready for the game
* PLEASE NOTE: the first non-header line is left inside the
* "inbuf" buffer zone where the cvtLine() function can then
* digest it.
*/
return( 0);
} /* procSHS */
/*
* This function inserts the Rate/Review button into the web page
* being generated.
*/
void
put_acrrs_snippet( so) /* insert a rate/review button */
FILE *so;
{
#if defined(LIX_ENABLED)
fprintf( so,
"<form method=POST action=\"%s\"> ", acrrs_url);
fprintf( so,
"<input type=\"hidden\" name=\"hr\" value=\"%s/%s.html\"> ",
web_rootdir, web_page_name);
fprintf( so, "<input type=\"hidden\" name=\"cn\" value=\"1\">");
fprintf( so, "<input type=\"hidden\" name=\"em\" value=\"%s\"> ",
web_authoremail);
fprintf( so, "<input type=\"hidden\" name=\"title\" value=\"%s\"> ",
shs_title);
fprintf( so, "<input type=\"hidden\" name=\"author\" value=\"%s\"> ",
web_authorname);
fprintf( so, "<input type=\"submit\" value=\"Rate / Review\"> </form>");
#else
# if 1
# if 1
appendFBform( so, shs_title); /* generate feedback form file */
# else
mkFBform( shs_title); /* generate feedback form file */
fprintf( so,
"<A HREF=\"fb-%s.html\"> Comment on this story </A>\n",
corename);
# endif
# else
fprintf( so,
"<A HREF=\"feedback-form.html\">Comment on this story</A>\n");
# endif
#endif
} /* put_acrrs_snippet */
/*
* cvtLine - (Convert Line) tags a buffer and parses it out
* into HTML for reading.
*/
int
cvtLine( so, inbuf) /* process content of the targetted text line */
FILE *so;
char *inbuf;
{
int llen, /* chars in input buffer */
centered; /* centering tag was found */
char lastchar; /* last character processed */
char *cp; /* copy character pointer */
cp = inbuf; /* point to start of buffer */
/*
* Detect a line we need to completely ignore.
*/
if ( strncmp( cp, "//", 2) == 0 ) /* no action, meta info */
return( 0); /* this won't even break a paragraph */
/*
* Sneak in a link button to next/previous page
*/
if ( *cp == '>' ) /* button configuration line */
{
/*
* >file:label
*/
char nextfile[512];
char label[512];
char *dp;
/*
* grab the name of the file to be linked
*/
cp++;
dp = nextfile;
while ( cp && *cp && (*cp != ':') )
*dp++ = *cp++;
*dp = 0x00;
cp++; /* skip the ':' delimiter */
/*
* now grab the name to be placed as the link
*/
dp = label;
while ( cp && *cp )
*dp++ = *cp++;
*dp = 0x00;
/*
* Next we'll sneak it into the output
*/
fprintf( so, " <A HREF=\"%s\"> %s </A> ", nextfile, label);
}
/*
* Recognize the left-margin marker that tells us
* to center the rest of the line.
*/
if ( *cp == '|' ) /* tells formatter to center this line */
{
cp++; /* skip the marker */
fputs( "<BR><CENTER>", so); /* start centering for line */
centered = 1;
}
else
centered = 0;
/*
* Recognize when a '_' is alone at the left margin; that
* tells us to generate a horizontal line as a break point.
*/
if ( strcmp( inbuf, "_") == 0 )
{
fputs( "<HR SIZE=5>\n", so);
leadin_skip = 0;
consec_blank = 0;
return( 0);
}
/*
* Some more special defects...
* a { alone on a line will turn on the fill-mode
* a } alone on a line will turn off the <BR> per line
* a [ alone on a line will place the following
* text into a table.
* a ] alone on a line will close the table "box".
*/
if ( strcmp( inbuf, "{") == 0 )
{
fputs( "<TT>\n", so);
fill_mode = 1;
return( 0);
}
if ( strcmp( inbuf, "}") == 0 )
{
fputs( "</TT>\n", so);
fill_mode = 0;
return( 0);
}
if ( strcmp( inbuf, "[") == 0 )
{
fputs( "<TABLE ALIGN=CENTER BORDER=2 WIDTH=\"50%\">\n", so);
fputs( "<TR><TD>\n", so);
fill_mode = 0;
return( 0);
}
if ( strcmp( inbuf, "]") == 0 )
{
fputs( "</TD></TR>\n</TABLE>\n", so);
fill_mode = 0;
return( 0);
}
/*
* I will not have even one tab character in front of a line
* containing significant text to be processed, so we'll
* detect such lines, treat them as paragraph breaks, and
* return having processed the line.
*/
if ( ( *cp == '\0' ) /* zero-length line */
#if 1
|| ( *cp == '\t' ) /* detect first tab char */
#else
|| ( strncmp( inbuf, "\t\t", 2) == 0 ) /* multiple tabs? */
#endif
)
{
fprintf( so, "\n");
if ( bolding != 0 )
{
fprintf( so, "%s\n", bolders[bolding]);
bolding = 0;
}
if ( emphasized != 0 )
{
fprintf( so, "%s\n", emphasizers[emphasized--]);
emphasized = 0;
}
#if 0
if ( ( leadin_skip == 0 )
|| ( consec_blank++ < 2 ) )
#else
if ( consec_blank++ < 1 )
#endif
{
if ( fill_mode != 0 ) { fprintf( so, "<BR>\n"); }
else { fprintf( so, "<P>\n"); }
}
return( 0);
}
leadin_skip = 0; /* turn off leadin suppression */
consec_blank = 0;
/*
* Since the line has significant text, we'll process it
* looking for the "emphasis" indicators...
*/
lastchar = '\0'; /* a NUL to indicate left margin */
while ( cp && *cp )
{
char gotc;
gotc = *cp++;
if ( ( gotc == '\\' ) /* skip over an escape char */
&& ( lastchar != '\\' ) ) /* that wasn't escape */
{
lastchar = gotc;
continue;
}
/*
* Note: The characters used for various special
* defects should really be done using a
* table but this cut is primitive enough
* that I'm not desperate to use.
*/
/*
* Recognize a bold enter/leave tag
*/
#if 0
if ( gotc == '*' ) /* detect emphasis */
#else
if ( ( gotc == '*' ) /* unescaped emphasis */
&& ( lastchar != '\\' ) )
#endif
{
fprintf( so, "%s", bolders[bolding]);
bolding ^= 1;
continue;
}
/*
* Recognize an emphasize enter/leave tag
*/
#if 0
if ( gotc == '_' )
#else
if ( ( gotc == '_' ) /* unescaped emphasis */
&& ( lastchar != '\\' ) )
#endif
{
fprintf( so, "%s",emphasizers[emphasized]);
emphasized ^= 1;
continue;
}
/*
* If we didn't have to remap the character, we'll
* just pass it through unmolested.
*/
fputc( gotc, so); /* put out the literal char */
lastchar = gotc;
}
/*
* Based on whether fill_mode has been set, we choose to
* append a line BReak for each input line
*/
if ( fill_mode != 0 ) { fprintf( so, " <BR>\n"); }
else { fprintf( so, " \n"); }
/*
* If we got centered we want to turn it off here.
*/
if ( centered ) fputs( "</CENTER>\n", so);
return( 1);
} /* cvtLile */
/*
* cvtFile - Given an input (text) file handle and an output
* (web format) file handle, this will manage the
* processing of the SHS headings and generates the
* necessary HTML content.
*/
int
cvtFile( corename, si, so) /* process content of the target text file */
char *corename;
FILE *si,
*so;
{
int lines,
llen;
char importname[4096]; /* name for imported objects */
char inbuf[INBUFSIZE]; /* buffer for input text */
char outbuf[8192]; /* buffer for html output */
char *cp, /* copy character pointer */
*dp, /* --> destination buffer */
*twp,
*nwp;
bolding = 0;
emphasized = 0;
consec_blank = 0;
lines = 0; /* reset the count of lines */
procSHS( corename, si, so, inbuf); /* leaves first non-hdr in inbuf */
leadin_skip = 1; /* we want to suppress stuff */
cvtLine( so, inbuf); /* pass captured line */
lines++;
/*
* While we still have contents, pass the line for conversion
*/
while ( fgets( inbuf, 4095, si ) )
{
llen = strlen( inbuf);
inbuf[--llen] = 0x00; /* remove the linefeed */
lines++;
cvtLine( so, inbuf); /* do the line conversion */
}
return( 0);
} /* cvtFile */
/*
* putFini - Handles closure of the generate Web Page which
* includes the Rate/Review button, a copyright
* notice, and a flat copy of the actual SHS headers.
*/
void
putFini( so)
FILE *so;
{
int i;
fprintf( so, "<CENTER> <BR> \n");
if ( strlen( next_page_name) != 0 )
{
fprintf( so, " <A HREF=\"%s\"> Next Chapter </A> <BR>\n",
next_page_name);
}
else
{
int this_part = -1,
last_part = -2;
/*
* We'll re-check the part information for "Fini" flag...
* Part information is formated part/total, so...
* 12/12
* will justify a "Fini" whilst
* 10/12
* won't (but, really, this should have been covered
* by the prev/next link info, above).
*/
if ( strlen( shs_part) > 0 )
{
char *cp;
cp = shs_part;
while ( cp && *cp && (*cp == ' ') )
cp++; /* skip any leading blanks */
/*
* Too lazy to fix (xx/xx) damnit...
*/
if ( cp && *cp && (*cp == '(') )
cp++;
if ( cp && *cp )
{
this_part = atoi(cp);
cp = strchr( cp, '/');
if ( cp && *cp )
{
cp++; /* skip the slash */
while ( cp && *cp && (*cp == ' ') )
cp++;
if ( cp && *cp )
last_part = atoi(cp);
}
}
/*
* check the collected info
*/
if ( this_part == last_part )
fini_flag = 1;
}
/*
* generate the "default" closing
*/
if ( fini_flag != 0 )
{
fprintf( so, " <BR> * Fini * <BR> \n");
}
else
{
fprintf( so, " <BR> * (To Be Continued) * <BR> \n");
}
}
fprintf( so, "<BR>\n");
fprintf( so, "\n</CENTER>\n");
fprintf( so, "<BR>\n");
if ( asstrflag != 0 )
put_acrrs_snippet( so); /* Rate/Review button */
fprintf( so, "<BR> <BR>\n<HR SIZE=5> <BR>\n");
/*
* Insert the Copyright notice
*/
fprintf( so, "<B>Copyright © %s</B>\n", copyright_heading);
fprintf( so, "%s\n<BR> <BR>\n<HR SIZE=5>\n", copyright_body);
fprintf( so, "<BR> <BR>\n");
/*
* Insert the contents of "web.suffix" at this point
*/
{
FILE *insertable;
char insertbuf[4096];
insertable = fopen( "web.suffix", "r");
while ( insertable && fgets( insertbuf, 4095, insertable) )
{
fputs( insertbuf, so); /* copy line out */
}
if ( insertable )
fclose( insertable);
}
/*
* Now we deliver the original SHS contents to the tail
* end of the web page. We pull the contents back from
* the shsInfo table.
*/
if ( asstrflag != 0 )
{
fprintf( so, "<PRE>\n");
for ( i = 0 ; shsInfo[i].buflen > 0 ; i++ )
{
struct MapItems *map;
char *cp,
ch;
map = &shsInfo[i];
fprintf( so, "%s ", map->label);
cp = map->buffer;
while ( cp && *cp )
{
if ( *cp == '<' )
{
fputs( "<", so);
}
else if ( *cp == '>' )
{
fputs( ">", so);
}
else
fputc( *cp, so);
cp++;
}
fputs( "\n", so);
}
fprintf( so, "</PRE>\n");
}
fprintf( so, "\n\n</BODY>\n</HTML>\n"); /* emit HTML closure */
} /* putFini */
int
FindInBuffer( buffer, look4) /* look for a pattern */
char *buffer;
char *look4;
{
unsigned int isize;
char *tbuf; /* temp buffer space */
char *sp, /* source buffer */
*dp, /* copy to buffer */
*tp, /* test pointer */
ch;
/*
* make a case-limited version
*/
isize = strlen( buffer); /* get size of existing */
isize += 4; /* pad this up */
tbuf = malloc( isize); /* build up a buffer */
dp = tbuf; /* point to local copy */
sp = buffer; /* point to original */
while ( sp && *sp ) /* does a copy as lower text */
{
ch = *sp++;
if ( isupper( ch) )
*dp++ = tolower( ch);
else
*dp++ = ch;
}
*dp = 0x00; /* terminate temp buffer */
sp = strstr( tbuf, look4); /* look for a match */
free( tbuf); /* release temp space */
if ( sp && *sp ) /* recognize successful copy */
return( 1);
return( 0);
} /* FindInBuffer */
int
mkFBform( title) /* generate an HTML feedback form */
char *title; /* title to pre-fill form */
{
FILE *so; /* file for generated form */
char fbpath[512]; /* name of generated form */
sprintf( fbpath, "fb-%s.html", corename);
/*
* If the feedback form file already exists don't step on it
*/
if ( ( force_fb_form == 0 ) && ( access( fbpath, 04) == 0 ) )
{
return( 0);
}
/*
* Open the file where we'll place the feedback form
*/
so = fopen( fbpath, "w");
/*
* Populate the file with the appropriate HTML
*/
fprintf( so, "\
<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n\
<html lang=en>\n\
<head>\n\
<!--ADULTSONLY-->\n\
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n\
<meta name=\"shs-Author\" content=\"Jack C Lipton\">\n");
fprintf( so, "\
<title>Jack Lipton's Feedback Form for %s</title>\n\
</head>\n\n",
title);
fprintf( so, "\
<H1 ALIGN=CENTER>\n\
Jack C Lipton's Feedback Form for %s\n\
</H1>\n\
<br>\n",
title);
fprintf( so, "\
<H2> A Message to my Readers </H2>\n\
<p>\n\
Thank you for reading my stories.\n\
<p>\n\
This page is how the ASSTR.ORG site\n\
provides the capability to send your comments\n\
to me anonymously.\n\
However, if you would like me to respond, you may\n\
provide a return e-mail address.\n\
If you ask me questions I can only answer if a\n\
working e-mail address is provided.\n\
<p>\n");
fprintf( so, "\
<H2> Why provide feedback? </H2>\n\
<p>\n\
Feedback is the lifeblood of authors here on ASSTR.ORG;\n\
we don't get paid in any currency beyond hits on the\n\
pages and <B>feedback</B> from our readership.\n\
Encouragement, questions, critiques, typos... as a\n\
reader you may be surprised how much your words mean to us.\n\
<p>\n\
This page gives you the opportunity to tell me what\n\
you thought of the words I've written...\n\
<p>\n\
It is a <U>good</U> feeling to have my words read.\n\
<p>\n");
fprintf( so, "\
<H2> Here's your turn to talk to <b>me</b> </H2>\n\
<FORM method=\"post\" ACTION=\"http://acctcgi.asstr.org/formmail.cgi\">\n\
<INPUT TYPE=HIDDEN NAME=\"emailrequired\" VALUE=\"no\">\n\
<INPUT TYPE=HIDDEN NAME=\"successpage\" VALUE=\"AllDone.html\">\n\
<p>\n");
fprintf( so, "\
Subject (change if you wish):\n\
<INPUT NAME=\"subject\" VALUE=\"{ASSTR} Feedback - %s\" size=60>\n",
title);
fprintf( so, "\
<p>\n\
I allow for anonymous feedback, but,\n\
If you provide your e-mail address here,\n\
you <B>allow</B> me the <U>privilege</U>\n\
of replying or conversing with you:\n\
<p>\n\
E-mail:\n\
<INPUT TYPE=TEXT NAME=\"useremail\" size=60> <BR>\n\
<p>\n\
Name:\n\
<INPUT TYPE=TEXT NAME=\"username\" size=60> <BR>\n\
<p>\n\
Please enter the name of the story and\n\
your comments about it to me in the box below:\n\
<p>\n\
<TEXTAREA rows=10 cols=80 name=\"story\"></textarea> <BR>\n\
Note: <BR>\n\
Returns are only necessary between paragraphs. <BR><BR><BR>\n\
<CENTER>\n\
<INPUT type=\"submit\" value=\"Press to send message\"> <BR>\n\
</CENTER>\n\
\n\
</form>\n");
fprintf( so, "\
<hr>\n\
<p>\n\
If the above does not work for you, try:\n\
<A HREF=\"http://www1.asstr.org/cgi-bin/ah_feedback.cgi?id=CXNRITNZQLQQBDITGAVD\" TARGET=\"_new\" onClick=\"remote=window.open('http://www1.asstr.org/cgi-bin/ah_feedback.cgi?id=CXNRITNZQLQQBDITGAVD','_new', 'toolbar=no,width=570,height=700,status=no,scrollbars=yes,resizable=1');remote.opener=self;return false\">ASSTR Msg Form</A>\n\
<hr>\n\
</body>\n\
</html>\n</body>");
fclose( so);
return( 0);
} /* mkFBform */
int
appendFBform( so, title) /* append the feedback form */
FILE *so; /* HTML image */
char *title; /* title to pre-fill form */
{
/*
* Populate the file with the appropriate HTML
*/
fprintf( so, "<hr>\n");
fprintf( so, "<H2 ALIGN=CENTER> Feedback Form </H2> <br>\n");
fprintf( so, "Thank you for reading my stories.\n<p>\n");
fprintf( so, "If you would like me to respond to your comments, ");
fprintf( so, "you need to provide a return e-mail address.\n<p>\n");
fprintf( so, "<b> Why provide feedback? </b>\n\
Feedback is the lifeblood of authors here on ASSTR.ORG;\n\
we don't get paid in any currency beyond hits on the\n\
pages and <B>feedback</B> from our readership.\n\
Encouragement, questions, critiques, typos... as a\n\
reader you may be surprised how much your words mean to us.\n\
<p>\n\
It is a <U>good</U> feeling to know my words have been read ... and enjoyed.\n\
<p>\n");
fprintf( so, "\
<FORM method=\"post\" ACTION=\"http://acctcgi.asstr.org/formmail.cgi\">\n\
<INPUT TYPE=HIDDEN NAME=\"emailrequired\" VALUE=\"no\">\n\
<INPUT TYPE=HIDDEN NAME=\"successpage\" VALUE=\"AllDone.html\">\n\
<INPUT TYPE=HIDDEN NAME=\"serial_number\" VALUE=\"%s\">\n<p>\n",
web_serial_number);
fprintf( so, "\
Subject (change if you wish):\n\
<INPUT NAME=\"subject\" VALUE=\"{ASSTR} Feedback - %s\" size=60>\n",
title);
fprintf( so, "<p>\nI allow for anonymous feedback, but,\n\
If you provide your e-mail address here,\n\
you <B>allow</B> me the <U>privilege</U>\n\
of replying or conversing with you:\n\
<p>\n\
E-mail:\n\
<INPUT TYPE=TEXT NAME=\"useremail\" size=60> <BR>\n\
<p>\n\
Name:\n\
<INPUT TYPE=TEXT NAME=\"username\" size=60> <BR>\n\
<p>\n\
Please enter your comments about it to me in the box below:\n\
<p>\n\
<TEXTAREA rows=10 cols=80 name=\"story\"></textarea> <BR>\n\
Note: <BR>\n\
Returns are only necessary between paragraphs. <BR><BR><BR>\n\
<CENTER>\n\
<INPUT type=\"submit\" value=\"Press to send message\"> <BR>\n\
</CENTER>\n\
\n\
</form>\n");
fprintf( so, "\
<hr>\n\
<p>\n\
If the above does not work for you, try:\n\
<A HREF=\"http://www1.asstr.org/cgi-bin/ah_feedback.cgi?id=CXNRITNZQLQQBDITGAVD\" TARGET=\"_new\" onClick=\"remote=window.open('http://www1.asstr.org/cgi-bin/ah_feedback.cgi?id=CXNRITNZQLQQBDITGAVD','_new', 'toolbar=no,width=570,height=700,status=no,scrollbars=yes,resizable=1');remote.opener=self;return false\">ASSTR Msg Form</A>\n\
<hr>\n");
} /* appendFBform */