Documentation autogenerated by HWEB



 

This is the program hweav, one-half of the HWEB text formatting system. It was written by Arthur O'DWYER in the summer of 2004. This program is free software; while Arthur O'Dwyer retains copyright, it may be used freely for any purpose.

The following string defines the version of HWEB. It should be changed whenever this program's behavior is modified.



#define HWEB_VERSION "1.1α"


#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NELEM(arr) ((int)(sizeof(arr)/sizeof *(arr)))
#define steq(x,y) (!strcmp(x,y))
#define stneq(x,y) (!steq(x,y))

typedef void (*genfuncptr)(void);
typedef genfuncptr (*State)(int);

#define NEXT       return (genfuncptr)
#define RUN(s, k)  (CODE_process((k), out), ((s != NULL)? (State) s(k): NULL))

char *Argv0;
char *OutputFilename = NULL;
int OptimizeUseMinus = 0;
int OptimizeUsePrime = 1;
int OptimizeTableNbsp = 1;
int OptimizeMozillaSubscripts = 0;
int OptimizeUseDashes = 1;
int DebugTables = 0;
int QuietMode = 0;
int ShowCode = 1;

void do_warn(const char *fmat, ...);
void do_error(const char *fmat, ...);
void do_help(int);

int CommentsAllowed;
int ParaAllowed;
int lineno;

#include "hweavc.c"
#include "hweavh.c"

enum { CCOMMENT, CPPCOMMENT };

int process(FILE *in, FILE *out);
  void HWEB_dump(FILE *out, int type);

int main(int argc, char **argv)
{
    int LiteralInputNames = 0;
    int i, j;

    Argv0 = argv[0];

    for (i=1; i < argc; ++i)
    {
        if (argv[i][0] != '-') break;
        if (argv[i][1] == '\0') break;

        if (steq(argv[i]+1, "-")) {
            LiteralInputNames = 1;
            ++i;
            break;
        }
        else if (steq(argv[i]+1, "-help") ||
                 steq(argv[i]+1, "h") || steq(argv[i]+1, "?"))
          do_help(0);
        else if (steq(argv[i]+1, "-man")) do_help(1);
        else if (steq(argv[i], "-o") || steq(argv[i], "-O")) {
            if (i >= argc-1) {
                do_error("Need output filename with -o");
            }
            OutputFilename = argv[++i];
        }
        else if (steq(argv[i], "--code"))  ShowCode = 1;
        else if (steq(argv[i], "--nocode"))  ShowCode = 0;
        else if (steq(argv[i], "--fminus"))  OptimizeUseMinus = 1;
        else if (steq(argv[i], "--fnominus"))  OptimizeUseMinus = 0;
        else if (steq(argv[i], "--fprime"))  OptimizeUsePrime = 1;
        else if (steq(argv[i], "--fnoprime"))  OptimizeUsePrime = 0;
        else if (steq(argv[i], "--fdashes"))  OptimizeUseDashes = 1;
        else if (steq(argv[i], "--fnodashes"))  OptimizeUseDashes = 0;
        else if (steq(argv[i], "--ftnbsp"))  OptimizeTableNbsp = 1;
        else if (steq(argv[i], "--fnotnbsp"))  OptimizeTableNbsp = 0;
        else if (steq(argv[i], "--fmozsub"))  OptimizeMozillaSubscripts = 1;
        else if (steq(argv[i], "--fnomozsub"))  OptimizeMozillaSubscripts = 0;
        else if (steq(argv[i], "--debug"))  DebugTables = 1;
        else {
            for (j=1; argv[i][j]; ++j) {
                if (argv[i][j] == 'q') QuietMode = 1;
                else if (argv[i][j] == 'c') {
                    ShowCode = 1;
                }
                else if (argv[i][j] == 'M') {
                    OptimizeUseMinus = 1;
                    OptimizeUsePrime = 1;
                    OptimizeUseDashes = 1;
                    OptimizeMozillaSubscripts = 1;
                }
                else do_error("Unrecognized option(s) %s; -h for help",
                    argv[i]);
            }
        }
    }

    if (i == argc)
    {
        FILE *outfp = OutputFilename? fopen(OutputFilename, "w"): stdout;
        if (outfp == NULL)
          do_error("Error opening file '%s' for output", OutputFilename);
        process(stdin, outfp);
        if (outfp != stdout)
          fclose(outfp);
    }

    for (; i < argc; ++i)
    {
        FILE *infp;
        FILE *outfp;

        if (!LiteralInputNames && steq(argv[i], "--")) {
            LiteralInputNames = 1;
            continue;
        }
        else {
            infp = (!LiteralInputNames && steq(argv[i], "-"))?
                stdin:
                fopen(argv[i], "r");
        }

        outfp = OutputFilename? fopen(OutputFilename, "w"): stdout;

        if (infp == NULL)
          do_error("Error opening file '%s' for input", argv[i]);
        if (outfp == NULL)
          do_error("Error opening file '%s' for output", OutputFilename);

        process(infp, outfp);

        if (infp != stdin)
          fclose(infp);
        if (outfp != stdout)
          fclose(outfp);
    }

    return 0;
}



int process(FILE *in, FILE *out)
{
    State cstate = Newline;
    int hwebify = 0;
    int k;
    int backslash = 0;
    int slash = 0;
    int star = 0;
    int ccomment = 0;
    int cppcomment = 0;
    int questions = 0;

    lineno = 1;

    HWEB_attach(out);
    CODE_begin(out);
    CommentsAllowed = 1;

    while ((k=getc(in)) != EOF)
    {
        if (k == '\n')
          ++lineno;

         
/* Handle trigraphs inside and outside of comments */
        if (k == '?') {
            ++questions;
            if (questions == 3) {
                if (!hwebify) cstate = RUN(cstate, '?');
                else HWEB_process('?');
                questions = 2;
            }
            continue;
        }
        else if (questions == 2) {
            questions = 0;
            switch (k) {
                case '=':  k = '#';  break;
                case '(':  k = '[';  break;
                case '/':  k = '\\'; break;
                case ')':  k = ']';  break;
                case '\'': k = '^';  break;
                case '<':  k = '{';  break;
                case '!':  k = '|';  break;
                case '>':  k = '}';  break;
                case '-':  k = '~';  break;
                default:
                    if (!hwebify) cstate = RUN(RUN(cstate, '?'), '?');
                    else HWEB_process('?'), HWEB_process('?');
            }
        }
        else if (questions == 1) {
            questions = 0;
            if (!hwebify) cstate = RUN(cstate, '?');
            else HWEB_process('?');
        }

         
/* Handle splicing lines */
        if (backslash) {
            backslash = 0;
            if (k == '\n') continue;
            if (!hwebify) {
                if (slash) cstate = RUN(cstate, '/');
                if (star) cstate = RUN(cstate, '*');
                cstate = RUN(cstate, '\\');
            }
            else {
                if (slash) HWEB_process('/');
                if (star) HWEB_process('*');
                HWEB_process('\\');
            }
            slash = star = 0;
        }
        if (k == '\\') {
            backslash = 1;
            continue;
        }

         
/* Handle comments */
        if (!CommentsAllowed)
          goto done_comments;
        if (slash) {
            slash = 0;
            if (k == '*') ccomment = 1;
            else if (k == '/') cppcomment = 1;
            else {
                cstate = RUN(cstate, '/');
            }
        }
        else if (star) {
            star = 0;
            if (k == '/') {
                ccomment = 0;
                 
/* Each comment is replaced by a single space. */
                cstate = RUN(cstate, ' ');
                hwebify = 0;
                HWEB_dump(out, CCOMMENT);
                continue;
            }
            else if (hwebify) {
                if (HWEB_process('*'))
                  do_error("Out of memory in line %d", lineno);
            }
            if (k == '*') star = 1;
        }
        else if (ccomment) {
            if (k == '*') star = 1;
        }
        else if (cppcomment) {
            if (k == '\n') {
                cppcomment = 0;
                hwebify = 0;
                HWEB_dump(out, CPPCOMMENT);
            }
        }
        else {
            if (k == '/') {
                slash = 1;
                continue;
            }
        }

         

Process C comments and dump the HTML to stdout. Ignore C++ comments altogether.



        if (hwebify) {
            if (!star)
              if (HWEB_process(k))
                do_error("Out of memory in line %d", lineno);
            continue;
        }
        else if (ccomment || cppcomment) {
            hwebify = 1;
            continue;
        }

done_comments:
        cstate = RUN(cstate, k);
        if (cstate == NULL) {
            do_warn("Error in C input, line %d", lineno);
            cstate = Newline;
        }
    }

    if (hwebify) {
        do_warn("Unexpected end-of-file inside HWEB comment, line %d", lineno);
        HWEB_dump(out, ccomment? CCOMMENT: CPPCOMMENT);
    }
    CODE_end(out);
    HWEB_release(out);

    return 0;
}


 

type is either CCOMMENT or CPPCOMMENT. We change how we print the output, depending on whether we've got a C-style or a C++-style comment, and also depending on whether the C-style comment spans more than one line. Single-line C-style comments are formatted on one line, with no calls to CODE_begin or CODE_end.



void HWEB_dump(FILE *out, int type)
{
    const char *h_input = HWEB_inbuffer;
    size_t h_len = HWEB_inbufferlen;
    size_t i;
    for (i=0; i < h_len; ++i) {
        if (h_input[i] == '\n') {
            CODE_end(out);
            if (HWEB_break(1))
              do_warn("Error in HWEB input before line %d", lineno);
            CODE_begin(out);
            return;
        }
    }
    if (type == CPPCOMMENT)
      fputs("</pre> // ", out);
    else
      fputs("</pre> /* ", out);
    if (HWEB_break(0))
      do_warn("Error in HWEB input on line %d", lineno);
    if (type == CPPCOMMENT)
      fputs("\n<pre>", out);
    else
      fputs(" */ <pre>", out);
    return;
}


void do_warn(const char *fmat, ...)
{
    static int always_continue = 0;
    char buffer[100];
    va_list ap;
    printf("%s: ", Argv0);
    va_start(ap, fmat);
    vprintf(fmat, ap);
    printf("\n");
    va_end(ap);

    if (always_continue || QuietMode) return;
    puts("I can continue trying to process this file if you want.");
    fputs("Continue? (y/n/always) ", stdout);
    fflush(stdout);
    while (fgets(buffer, sizeof buffer, stdin)) {
        if (strchr(buffer, '\n') == NULL)
          while (getchar()!='\n') continue;
        if (tolower(buffer[0]) == 'y') return;
        if (tolower(buffer[0]) == 'a') { always_continue = 1; return; }
        if (tolower(buffer[0]) == 'n') goto exit;
        if (buffer[0] == '\n') goto exit;
        puts("Please enter 'y', 'n', or 'a'.");
    }
  exit:
    puts("I could not complete my task.");
    exit(EXIT_FAILURE);
}


void do_error(const char *fmat, ...)
{
    va_list ap;
    printf("%s: ", Argv0);
    va_start(ap, fmat);
    vprintf(fmat, ap);
    printf("\n");
    va_end(ap);
    exit(EXIT_FAILURE);
}


void do_help(int man)
{
    if (man)
      goto man;
    puts("hweav [-?h] [-M] [-o name] [filename]");
    puts("Weaves an HTML document from the comments in the given file.");
    puts("  -M: optimize for viewing in Mozilla Firefox");
    puts("  -q: quiet mode; do not warn about non-fatal errors");
    puts("  -o filename: send output to specified file");
    puts("  --help: show this message");
    puts("  --man: show complete help text");
    exit(0);
  man:
    puts("hweav: Half of the HWEB literate programming system.\n");
    puts(" This program extracts C and C++ comments from source code");
    puts("   and writes an HTML document containing those comments,");
    puts("   prettyprinted.  It is essentially a pretty-printer, but");
    puts("   it includes a mathematical expression language influenced");
    puts("   heavily by Don Knuth's TeX text processing system.");
    puts(" The -o parameter specifies an output file.  It is important");
    puts("   to use -o instead of your shell's redirection");
    puts("   capabilities, since the program writes its error messages");
    puts("   to the standard output.");
    puts(" The -q option turns off interactive mode; when in \"quiet\"");
    puts("   mode, the program will not prompt the user for what to do");
    puts("   in case of non-fatal errors; it will simply print a");
    puts("   warning and then barge ahead without confirmation.");
    puts(" The -M option turns on all HTML optimizations related to the");
    puts("   Mozilla Firefox web browser.  This is generally a good");
    puts("   idea for up-to-date browsers, and a bad idea for older or");
    puts("   non-standard web browsers.");
    puts(" The --debug option turns on table borders in out-of-line");
    puts("   math mode, for debugging purposes only.");
    puts(" The --nocode option tells the program not to include source");
    puts("   code listings in the output.  The default is to");
    puts("   intersperse the code with its comments.");
    puts(" The --fnoprime, --fnominus, and --fnodashes HTML optimization"); 
    puts("   options tell the program not to use the &#8242; \"mathe-");
    puts("   matical prime\" entity, the &minus; entity, and the &mdash;");
    puts("   and &ndash; entities, respectively.  They will be replaced");
    puts("   by their ASCII equivalents if these options are selected.");
    puts(" The --ftnbsp option tells the program to insert extra &nbsp;");
    puts("   \"non-breaking space\" entities in otherwise empty table");
    puts("   cells.  This might improve appearance in some browsers.");
    exit(0);
}

This documentation was generated by HWEB, version 1.1α, by Arthur O'Dwyer.