/* * 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 '
'. * * * =========================================================================== * * 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.19 2006/07/20 21:19:48 jcl Exp jcl $ * * $Author: jcl $ * * $Log: fmtr.c,v $ * 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 /* * 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.19 $ * |Archive: * |Mailing List: * |FAQ: * |RCS: $Id: fmtr.c,v 1.19 2006/07/20 21:19:48 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] = { "", "" }; char *bolders[2] = { "", "" }; 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, "\n"); fprintf( so, "\n\n\n"); fprintf( so, " %s \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, "\n"); } /* * Here we fill in the Meta information we've accumulated * from the SHS headers, as recommended by others. */ if ( asstrflag != 0 ) { fprintf( so, "\n", shs_title); fprintf( so, "\n", shs_part); fprintf( so, "\n", shs_authorname); fprintf( so, "\n", shs_keywords); #if 0 fprintf( so, "\n", "`date`"); #endif fprintf( so, "\n", shs_universe); fprintf( so, "\n", shs_summary); fprintf( so, "\n", shs_revision); } fprintf( so, "\n"); if ( ewpubflag == 1 ) { fprintf( so, "\n\n"); } else { FILE *insertable; char insertbuf[4096]; fprintf( so, "\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, "

\n"); fprintf( so, "%s\n", shs_title); if ( strcmp( shs_part, "") != 0 ) { fprintf( so, "(part %s)\n", shs_part); } fprintf( so, "

\n"); fprintf( so, "
\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, "codes: %s\t
\n", shs_keywords); } #if 0 fprintf( so, "by %s
\n", web_authoremail, web_authorname); #else fprintf( so, "by %s
\n", shs_authorname); #endif if ( asstrflag != 0 ) { fprintf( so, "(Main Page)
\n"); } if ( strlen( prev_page_name) != 0 ) { fprintf( so, " Previous Chapter
\n", prev_page_name); } fflush( so); fprintf( so, "
\n"); fprintf( so, "
\n"); #if 0 if ( asstrflag != 0 ) put_acrrs_snippet( so); #endif fprintf( so, "
\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, "
", acrrs_url); fprintf( so, " ", web_rootdir, web_page_name); fprintf( so, ""); fprintf( so, " ", web_authoremail); fprintf( so, " ", shs_title); fprintf( so, " ", web_authorname); fprintf( so, "
"); #else # if 1 # if 1 appendFBform( so, shs_title); /* generate feedback form file */ # else mkFBform( shs_title); /* generate feedback form file */ fprintf( so, " Comment on this story \n", corename); # endif # else fprintf( so, "Comment on this story\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, " %s ", 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( "
", 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( "
\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
per line */ if ( strcmp( inbuf, "{") == 0 ) { fputs( "\n", so); fill_mode = 1; return( 0); } if ( strcmp( inbuf, "}") == 0 ) { fputs( "\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 ^= 1; } if ( emphasized > 0 ) { fprintf( so, "%s\n", emphasizers[emphasized--]); emphasized ^= 1; } #if 0 if ( ( leadin_skip == 0 ) || ( consec_blank++ < 2 ) ) #else if ( consec_blank++ < 1 ) #endif { if ( fill_mode != 0 ) { fprintf( so, "
\n"); } else { fprintf( so, "

\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 == '\134' ) /* skip over an escape char */ && ( lastchar != '\134' ) ) /* 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 != '\134' ) ) #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 != '\134' ) ) #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, "
\n"); } else { fprintf( so, " \n"); } /* * If we got centered we want to turn it off here. */ if ( centered ) fputs( "

\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, "

\n"); if ( strlen( next_page_name) != 0 ) { fprintf( so, " Next Chapter
\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, "
* Fini *
\n"); } else { fprintf( so, "
* (To Be Continued) *
\n"); } } fprintf( so, "
\n"); fprintf( so, "\n
\n"); fprintf( so, "
\n"); if ( asstrflag != 0 ) put_acrrs_snippet( so); /* Rate/Review button */ fprintf( so, "

\n

\n"); /* * Insert the Copyright notice */ fprintf( so, "Copyright © %s\n", copyright_heading); fprintf( so, "%s\n

\n
\n", copyright_body); fprintf( so, "

\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, "
\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, "
\n"); } fprintf( so, "\n\n\n\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, "\ \n\ \n\ \n\ \n\ \n\ \n"); fprintf( so, "\ Jack Lipton's Feedback Form for %s\n\ \n\n", title); fprintf( so, "\

\n\ Jack C Lipton's Feedback Form for %s\n\

\n\
\n", title); fprintf( so, "\

A Message to my Readers

\n\

\n\ Thank you for reading my stories.\n\

\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\

\n"); fprintf( so, "\

Why provide feedback?

\n\

\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 feedback from our readership.\n\ Encouragement, questions, critiques, typos... as a\n\ reader you may be surprised how much your words mean to us.\n\

\n\ This page gives you the opportunity to tell me what\n\ you thought of the words I've written...\n\

\n\ It is a good feeling to have my words read.\n\

\n"); fprintf( so, "\

Here's your turn to talk to me

\n\
\n\ \n\ \n\

\n"); fprintf( so, "\ Subject (change if you wish):\n\ \n", title); fprintf( so, "\

\n\ I allow for anonymous feedback, but,\n\ If you provide your e-mail address here,\n\ you allow me the privilege\n\ of replying or conversing with you:\n\

\n\ E-mail:\n\
\n\

\n\ Name:\n\
\n\

\n\ Please enter the name of the story and\n\ your comments about it to me in the box below:\n\

\n\
\n\ Note:
\n\ Returns are only necessary between paragraphs.


\n\

\n\
\n\
\n\ \n\
\n"); fprintf( so, "\
\n\

\n\ If the above does not work for you, try:\n\ ASSTR Msg Form\n\


\n\ \n\ \n"); 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, "
\n"); fprintf( so, "

Feedback Form


\n"); fprintf( so, "Thank you for reading my stories.\n

\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

\n"); fprintf( so, " Why provide feedback? \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 feedback from our readership.\n\ Encouragement, questions, critiques, typos... as a\n\ reader you may be surprised how much your words mean to us.\n\

\n\ It is a good feeling to know my words have been read ... and enjoyed.\n\

\n"); fprintf( so, "\

\n\ \n\ \n\ \n

\n", web_serial_number); fprintf( so, "\ Subject (change if you wish):\n\ \n", title); fprintf( so, "

\nI allow for anonymous feedback, but,\n\ If you provide your e-mail address here,\n\ you allow me the privilege\n\ of replying or conversing with you:\n\

\n\ E-mail:\n\
\n\

\n\ Name:\n\
\n\

\n\ Please enter your comments about it to me in the box below:\n\

\n\
\n\ Note:
\n\ Returns are only necessary between paragraphs.


\n\

\n\
\n\
\n\ \n\
\n"); fprintf( so, "\
\n\

\n\ If the above does not work for you, try:\n\ ASSTR Msg Form\n\


\n"); } /* appendFBform */