summaryrefslogtreecommitdiff
path: root/web/nuweb
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /web/nuweb
Initial commit
Diffstat (limited to 'web/nuweb')
-rw-r--r--web/nuweb/msdos/arena.c51
-rw-r--r--web/nuweb/msdos/input.c164
-rw-r--r--web/nuweb/msdos/latex.c361
-rw-r--r--web/nuweb/msdos/literate.bib119
-rw-r--r--web/nuweb/msdos/main.c144
-rw-r--r--web/nuweb/msdos/makefile45
-rw-r--r--web/nuweb/msdos/names.c422
-rw-r--r--web/nuweb/msdos/nuweb.1107
-rw-r--r--web/nuweb/msdos/nuweb.bbl58
-rw-r--r--web/nuweb/msdos/nuweb.tex3897
-rw-r--r--web/nuweb/msdos/nuweb.toc43
-rw-r--r--web/nuweb/msdos/nuweb.w2723
-rw-r--r--web/nuweb/msdos/output.c101
-rw-r--r--web/nuweb/msdos/pass1.c116
-rw-r--r--web/nuweb/msdos/readme28
-rw-r--r--web/nuweb/msdos/readme.txt14
-rw-r--r--web/nuweb/msdos/scraps.c542
-rw-r--r--web/nuweb/nuweb0.87b/Makefile63
-rw-r--r--web/nuweb/nuweb0.87b/README36
-rw-r--r--web/nuweb/nuweb0.87b/arena.c48
-rw-r--r--web/nuweb/nuweb0.87b/global.c15
-rw-r--r--web/nuweb/nuweb0.87b/global.h64
-rw-r--r--web/nuweb/nuweb0.87b/html.c335
-rw-r--r--web/nuweb/nuweb0.87b/input.c108
-rw-r--r--web/nuweb/nuweb0.87b/latex.c361
-rw-r--r--web/nuweb/nuweb0.87b/literate.bib129
-rw-r--r--web/nuweb/nuweb0.87b/main.c105
-rw-r--r--web/nuweb/nuweb0.87b/names.c368
-rw-r--r--web/nuweb/nuweb0.87b/nuweb.w3599
-rw-r--r--web/nuweb/nuweb0.87b/nuwebdoc.tex5796
-rw-r--r--web/nuweb/nuweb0.87b/output.c51
-rw-r--r--web/nuweb/nuweb0.87b/pass1.c64
-rw-r--r--web/nuweb/nuweb0.87b/scraps.c607
-rw-r--r--web/nuweb/nuweb_ami/ami_nuweb0.90.lhabin0 -> 138815 bytes
-rw-r--r--web/nuweb/nuweb_ami/ami_nuweb0.90.readme61
-rw-r--r--web/nuweb/os2/nuweb087.txt81
36 files changed, 20826 insertions, 0 deletions
diff --git a/web/nuweb/msdos/arena.c b/web/nuweb/msdos/arena.c
new file mode 100644
index 0000000000..ce0f738a3c
--- /dev/null
+++ b/web/nuweb/msdos/arena.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+typedef struct chunk {
+ struct chunk *next;
+ char *limit;
+ char *avail;
+} Chunk;
+Chunk first = { NULL, NULL, NULL };
+Chunk *arena = &first;
+void *arena_getmem(n)
+ int n;
+{
+ char *q;
+ char *p = arena->avail;
+ n = (n + 3) & ~3; /* ensuring alignment to 4 bytes */
+ q = p + n;
+ if (q <= arena->limit) {
+ arena->avail = q;
+ return p;
+ }
+ {
+ Chunk *ap = arena;
+ Chunk *np = ap->next;
+ while (np) {
+ char *v = sizeof(Chunk) + (char *) np;
+ if (v + n <= np->limit) {
+ np->avail = v + n;
+ arena = np;
+ return v;
+ }
+ ap = np;
+ np = ap->next;
+ }
+ {
+ int m = n + 10000;
+ np = (Chunk *) malloc(m);
+ np->limit = m + (char *) np;
+ np->avail = n + sizeof(Chunk) + (char *) np;
+ np->next = NULL;
+ ap->next = np;
+ arena = np;
+ return sizeof(Chunk) + (char *) np;
+ }
+ }
+}
+void arena_free()
+{
+ arena = &first;
+}
diff --git a/web/nuweb/msdos/input.c b/web/nuweb/msdos/input.c
new file mode 100644
index 0000000000..48e74b3432
--- /dev/null
+++ b/web/nuweb/msdos/input.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!0)
+#endif
+typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+
+int tex_flag; /* if FALSE, don't emit the .tex file */
+int output_flag; /* if FALSE, don't emit the output files */
+int compare_flag; /* if FALSE, overwrite without comparison */
+char *command_name;
+char *source_name; /* name of the current file */
+int source_line; /* current line in the source file */
+Name *file_names;
+Name *macro_names;
+Name *user_names;
+
+void pass1();
+void write_tex();
+void write_files();
+void source_open(); /* pass in the name of the source file */
+int source_get(); /* no args; returns the next char or EOF */
+void init_scraps();
+int collect_scrap();
+int write_scraps();
+Name *collect_file_name();
+Name *collect_macro_name();
+Name *collect_scrap_name();
+Name *name_add();
+Name *prefix_add();
+char *save_string();
+void reverse_lists();
+void *arena_getmem();
+void arena_free();
+
+
+static FILE *source_file; /* the current input file */
+static int source_peek;
+static int double_at;
+static int include_depth;
+struct {
+ FILE *file;
+ char *name;
+ int line;
+} stack[10];
+int source_get()
+{
+ int c = source_peek;
+ switch (c) {
+ case EOF: {
+ fclose(source_file);
+ if (include_depth) {
+ include_depth--;
+ source_file = stack[include_depth].file;
+ source_line = stack[include_depth].line;
+ source_name = stack[include_depth].name;
+ source_peek = getc(source_file);
+ c = source_get();
+ }
+ }
+ return c;
+ case '@': {
+ c = getc(source_file);
+ if (double_at) {
+ source_peek = c;
+ double_at = FALSE;
+ c = '@';
+ }
+ else
+ switch (c) {
+ case 'i': {
+ if (include_depth < 10) {
+ char name[100];
+ {
+ char *p = name;
+ do
+ c = getc(source_file);
+ while (c == ' ' || c == '\t');
+ while (isgraph(c)) {
+ *p++ = c;
+ c = getc(source_file);
+ }
+ *p = '\0';
+ if (c != '\n') {
+ fprintf(stderr, "%s: unexpected characters after file name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ }
+ stack[include_depth].name = source_name;
+ stack[include_depth].file = source_file;
+ stack[include_depth].line = source_line + 1;
+ include_depth++;
+ source_line = 1;
+ source_name = save_string(name);
+ source_file = fopen(source_name, "r");
+ if (!source_file) {
+ fprintf(stderr, "%s: can't open include file %s\n",
+ command_name, source_name);
+ exit(-1);
+ }
+ source_peek = getc(source_file);
+ c = source_get();
+ }
+ else {
+ fprintf(stderr, "%s: include nesting too deep (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ }
+ break;
+ case 'f': case 'm': case 'u':
+ case 'd': case 'o': case 'D': case 'O':
+ case '{': case '}': case '<': case '>': case '|':
+ source_peek = c;
+ c = '@';
+ break;
+ case '@': source_peek = c;
+ double_at = TRUE;
+ break;
+ default: fprintf(stderr, "%s: bad @ sequence (%s, line %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ }
+ return c;
+ case '\n': source_line++;
+ default: source_peek = getc(source_file);
+ return c;
+ }
+}
+void source_open(name)
+ char *name;
+{
+ source_file = fopen(name, "r");
+ if (!source_file) {
+ fprintf(stderr, "%s: couldn't open %s\n", command_name, name);
+ exit(-1);
+ }
+ source_name = name;
+ source_line = 1;
+ source_peek = getc(source_file);
+ double_at = FALSE;
+ include_depth = 0;
+}
diff --git a/web/nuweb/msdos/latex.c b/web/nuweb/msdos/latex.c
new file mode 100644
index 0000000000..05cdd4de65
--- /dev/null
+++ b/web/nuweb/msdos/latex.c
@@ -0,0 +1,361 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!0)
+#endif
+typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+
+int tex_flag; /* if FALSE, don't emit the .tex file */
+int output_flag; /* if FALSE, don't emit the output files */
+int compare_flag; /* if FALSE, overwrite without comparison */
+char *command_name;
+char *source_name; /* name of the current file */
+int source_line; /* current line in the source file */
+Name *file_names;
+Name *macro_names;
+Name *user_names;
+
+void pass1();
+void write_tex();
+void write_files();
+void source_open(); /* pass in the name of the source file */
+int source_get(); /* no args; returns the next char or EOF */
+void init_scraps();
+int collect_scrap();
+int write_scraps();
+Name *collect_file_name();
+Name *collect_macro_name();
+Name *collect_scrap_name();
+Name *name_add();
+Name *prefix_add();
+char *save_string();
+void reverse_lists();
+void *arena_getmem();
+void arena_free();
+
+
+static void copy_scrap(); /* formats the body of a scrap */
+static void print_scrap_numbers(); /* formats a list of scrap numbers */
+static void format_entry(); /* formats an index entry */
+static void format_user_entry();
+void write_tex(file_name, tex_name)
+ char *file_name;
+ char *tex_name;
+{
+ FILE *tex_file = fopen(tex_name, "w");
+ if (tex_file) {
+ source_open(file_name);
+ {
+ int scraps = 1;
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@')
+ {
+ int big_definition = FALSE;
+ c = source_get();
+ switch (c) {
+ case 'O': big_definition = TRUE;
+ case 'o': {
+ Name *name = collect_file_name();
+ {
+ fputs("\\begin{flushleft}\n", tex_file);
+ if (!big_definition)
+ fputs("\\begin{minipage}{\\linewidth}\n", tex_file);
+ }
+ fprintf(tex_file, "\\verb@\"%s\"@", name->spelling);
+ fprintf(tex_file, " {\\footnotesize %d }$\\equiv$\n", scraps++);
+ {
+ fputs("\\vspace{-1.5ex}\n\\begin{quote}\n", tex_file);
+ copy_scrap(tex_file);
+ fputs("$\\Diamond$\n\\end{quote}\n\\vspace{-2ex}\n", tex_file);
+ }
+ {
+ if (name->defs->next) {
+ fputs("{\\footnotesize File defined by scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->defs);
+ fputs("}\n", tex_file);
+ }
+ }
+ {
+ if (!big_definition)
+ fputs("\\end{minipage}\\\\[4ex]\n", tex_file);
+ fputs("\\end{flushleft}\n", tex_file);
+ do
+ c = source_get();
+ while (isspace(c));
+ }
+ }
+ break;
+ case 'D': big_definition = TRUE;
+ case 'd': {
+ Name *name = collect_macro_name();
+ {
+ fputs("\\begin{flushleft}\n", tex_file);
+ if (!big_definition)
+ fputs("\\begin{minipage}{\\linewidth}\n", tex_file);
+ }
+ fprintf(tex_file, "$\\langle$%s", name->spelling);
+ fprintf(tex_file, " {\\footnotesize %d}$\\rangle\\equiv$\n", scraps++);
+ {
+ fputs("\\vspace{-1.5ex}\n\\begin{quote}\n", tex_file);
+ copy_scrap(tex_file);
+ fputs("$\\Diamond$\n\\end{quote}\n\\vspace{-2ex}\n", tex_file);
+ }
+ {
+ fputs("{\\footnotesize ", tex_file);
+ if (name->defs->next) {
+ fputs("Macro defined by scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->defs);
+ fputs("\\\\[-1ex]\n", tex_file);
+ }
+ }
+ {
+ if (name->uses) {
+ if (name->uses->next) {
+ fputs("Macro referenced in scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->uses);
+ fputs("}\n", tex_file);
+ }
+ else
+ fprintf(tex_file, "Macro referenced in scrap %d.}\n", name->uses->scrap);
+ }
+ else {
+ fputs("Macro never referenced.}\n", tex_file);
+ fprintf(stderr, "%s: <%s> never referenced.\n",
+ command_name, name->spelling);
+ }
+ }
+ {
+ if (!big_definition)
+ fputs("\\end{minipage}\\\\[4ex]\n", tex_file);
+ fputs("\\end{flushleft}\n", tex_file);
+ do
+ c = source_get();
+ while (isspace(c));
+ }
+ }
+ break;
+ case 'f': {
+ if (file_names) {
+ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);
+ format_entry(file_names, tex_file, TRUE);
+ fputs("\\end{list}", tex_file);
+ }
+ c = source_get();
+ }
+ break;
+ case 'm': {
+ if (macro_names) {
+ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);
+ format_entry(macro_names, tex_file, FALSE);
+ fputs("\\end{list}", tex_file);
+ }
+ c = source_get();
+ }
+ break;
+ case 'u': {
+ if (user_names) {
+ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);
+ format_user_entry(user_names, tex_file);
+ fputs("\\end{list}", tex_file);
+ }
+ c = source_get();
+ }
+ break;
+ case '@': putc(c, tex_file);
+ default: c = source_get();
+ break;
+ }
+ }
+ else {
+ putc(c, tex_file);
+ c = source_get();
+ }
+ }
+ }
+ fclose(tex_file);
+ }
+ else
+ fprintf(stderr, "%s: can't open %s\n", command_name, tex_name);
+}
+static void print_scrap_numbers(tex_file, scraps)
+ FILE *tex_file;
+ Scrap_Node *scraps;
+{
+ fprintf(tex_file, "%d", scraps->scrap);
+ scraps = scraps->next;
+ while (scraps->next) {
+ fprintf(tex_file, ", %d", scraps->scrap);
+ scraps = scraps->next;
+ }
+ fprintf(tex_file, " and~%d.", scraps->scrap);
+}
+static void copy_scrap(file)
+ FILE *file;
+{
+ int indent = 0;
+ int c = source_get();
+ fputs("\\verb@", file);
+ while (1) {
+ switch (c) {
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': fputs("@{\\tt @}\\verb@", file);
+ break;
+ case '|': {
+ do {
+ do
+ c = source_get();
+ while (c != '@');
+ c = source_get();
+ } while (c != '}');
+ }
+ case '}': putc('@', file);
+ return;
+ case '<': {
+ Name *name = collect_scrap_name();
+ fprintf(file, "@$\\langle$%s {\\footnotesize ", name->spelling);
+ if (name->defs)
+ fprintf(file, "%d", name->defs->scrap);
+ else {
+ putc('?', file);
+ fprintf(stderr, "%s: scrap never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ fputs("}$\\rangle$\\verb@", file);
+ }
+ break;
+ default: /* ignore these since pass1 will have warned about them */
+ break;
+ }
+ }
+ break;
+ case '\n': fputs("@\\\\\n\\verb@", file);
+ indent = 0;
+ break;
+ case '\t': {
+ int delta = 8 - (indent % 8);
+ indent += delta;
+ while (delta > 0) {
+ putc(' ', file);
+ delta--;
+ }
+ }
+ break;
+ default: putc(c, file);
+ indent++;
+ break;
+ }
+ c = source_get();
+ }
+}
+static void format_entry(name, tex_file, file_flag)
+ Name *name;
+ FILE *tex_file;
+ int file_flag;
+{
+ while (name) {
+ format_entry(name->llink, tex_file, file_flag);
+ {
+ fputs("\\item \\hspace{-\\leftmargin}", tex_file);
+ if (file_flag) {
+ fprintf(tex_file, "\\verb@\"%s\"@ ", name->spelling);
+ {
+ Scrap_Node *p = name->defs;
+ fputs("{\\footnotesize Defined by scrap", tex_file);
+ if (p->next) {
+ fputs("s ", tex_file);
+ print_scrap_numbers(tex_file, p);
+ }
+ else
+ fprintf(tex_file, " %d.", p->scrap);
+ putc('}', tex_file);
+ }
+ }
+ else {
+ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);
+ {
+ Scrap_Node *p = name->defs;
+ if (p) {
+ while (1) {
+ fprintf(tex_file, "%d", p->scrap);
+ p = p->next;
+ if (!p) break;
+ fputs(", ", tex_file);
+ }
+ }
+ else
+ putc('?', tex_file);
+ }
+ fputs("}$\\rangle$ ", tex_file);
+ {
+ Scrap_Node *p = name->uses;
+ fputs("{\\footnotesize ", tex_file);
+ if (p) {
+ fputs("Referenced in scrap", tex_file);
+ if (p->next) {
+ fputs("s ", tex_file);
+ print_scrap_numbers(tex_file, p);
+ }
+ else
+ fprintf(tex_file, " %d.", p->scrap);
+ }
+ else
+ fputs("Not referenced.", tex_file);
+ putc('}', tex_file);
+ }
+ }
+ putc('\n', tex_file);
+ }
+ name = name->rlink;
+ }
+}
+static void format_user_entry(name, tex_file)
+ Name *name;
+ FILE *tex_file;
+{
+ while (name) {
+ format_user_entry(name->llink, tex_file);
+ {
+ Scrap_Node *uses = name->uses;
+ Scrap_Node *defs = name->defs;
+ fprintf(tex_file, "\\item \\hspace{-\\leftmargin}\\verb@%s@: ",
+ name->spelling);
+ do {
+ if (uses && (!defs || uses->scrap < defs->scrap)) {
+ fprintf(tex_file, "%d", uses->scrap);
+ uses = uses->next;
+ }
+ else if (defs && (!uses || defs->scrap <= uses->scrap)) {
+ if (uses && defs->scrap == uses->scrap)
+ uses = uses->next;
+ fprintf(tex_file, "\\underline{%d}", defs->scrap);
+ defs = defs->next;
+ }
+ if (uses || defs) fputs(", ", tex_file);
+ } while (uses || defs);
+ fputs(".\n", tex_file);
+ }
+ name = name->rlink;
+ }
+}
diff --git a/web/nuweb/msdos/literate.bib b/web/nuweb/msdos/literate.bib
new file mode 100644
index 0000000000..6c60823bad
--- /dev/null
+++ b/web/nuweb/msdos/literate.bib
@@ -0,0 +1,119 @@
+
+% abbreviations known to bibtex 0.99c
+% acms ACM Computing Surveys
+% acta Acta Informatica
+% cacm Communications of the ACM
+% ibmjrd IBM Journal of Research and Development
+% ibmsj IBM Systems Journal
+% ieeese IEEE Transactions on Software Engineering
+% ieeetc IEEE Transactions on Computers
+% ieeetcad IEEE Transactions on Computer-Aided Design of ICs
+% ipl Information Processing Letters
+% jacm Journal of the ACM
+% jcss Journal of Computer and System Sciences
+% scp Science of Computer Programming
+% sicomp SIAM Journal on Computing
+% tocs ACM Transactions on Computer Systems
+% tods ACM Transactions on Database Systems
+% tog ACM Transactions on Graphics
+% toms ACM Transactions on Mathematical Software
+% toois ACM Transactions on Office Information Systems
+% toplas ACM Transactions on Programming Languages and Systems
+% tcs Theoretical Computer Science
+
+@string{spe="Software -- Practice and Experience"}
+
+
+@unpublished{noweb,
+ author="Norman Ramsey",
+ title="Literate-Programming Tools Need Not Be Complex",
+ month=aug,
+ year=1992,
+ note="Submitted to IEEE Software"
+}
+
+@article{aho:75,
+ author="Alfred V. Aho and Margaret J. Corasick",
+ title="Efficient String Matching: An Aid to Bibliographic Search",
+ pages="333--340",
+ journal=cacm,
+ year=1975,
+ month=jun,
+ volume=18,
+ number=6
+}
+
+
+@article{knuth:84,
+ author="Donald E. Knuth",
+ title="Literate Programming",
+ pages="97--111",
+ journal="The Computer Journal",
+ year="1984",
+ month=may,
+ volume=27,
+ number=2
+}
+
+@techreport{levy:90,
+ author="Silvio Levy and Donald E. Knuth",
+ title="{{\tt CWEB}} User Manual: The {{\small CWEB}} System of
+ Structured Documentation",
+ year="1990",
+ month=oct,
+ institution="Stanford University",
+ number="{\small STAN}-{\small CS}-83-977",
+ note="Available for anonymous ftp from {\tt labrea.stanford.edu} in
+ directory {\tt pub/cweb}"
+}
+
+@book{texbook,
+ author="Donald E. Knuth",
+ title="The {{\TeX}}book",
+ publisher="Addison-Wesley",
+ year=1986,
+ series="Computers \& Typesetting"
+}
+
+@book{tex:program,
+ author="Donald E. Knuth",
+ title="{{\TeX}}: The Program",
+ publisher="Addison-Wesley",
+ year=1986,
+ series="Computers \& Typesetting"
+}
+
+@book{metafont:program,
+ author="Donald E. Knuth",
+ title="{{\small\sf METAFONT:}} The Program",
+ publisher="Addison-Wesley",
+ year=1986,
+ series="Computers \& Typesetting"
+}
+
+@book{latex,
+ author="Leslie Lamport",
+ title="{{\LaTeX:}} A Document Preparation System",
+ publisher="Addison-Wesley",
+ year=1986
+}
+
+@booklet{funnelweb,
+ title="{FunnelWeb} User's Manual",
+ author="Ross N. Williams",
+ note="Available for anonymous ftp from {\tt sirius.itd.adelaide.edu.au}
+ in directory {\tt pub/funnelweb}",
+ month=may,
+ year=1992
+}
+
+@article{hanson:90,
+ title="Fast Allocation and Deallocation of Memory Based on Object Lifetimes",
+ author="David R. Hanson",
+ journal=spe,
+ year=1990,
+ month=jan,
+ volume=20,
+ number=1,
+ pages="5--12"
+}
diff --git a/web/nuweb/msdos/main.c b/web/nuweb/msdos/main.c
new file mode 100644
index 0000000000..089df94eec
--- /dev/null
+++ b/web/nuweb/msdos/main.c
@@ -0,0 +1,144 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!0)
+#endif
+typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+
+int tex_flag; /* if FALSE, don't emit the .tex file */
+int output_flag; /* if FALSE, don't emit the output files */
+int compare_flag; /* if FALSE, overwrite without comparison */
+char *command_name;
+char *source_name; /* name of the current file */
+int source_line; /* current line in the source file */
+Name *file_names;
+Name *macro_names;
+Name *user_names;
+
+void pass1();
+void write_tex();
+void write_files();
+void source_open(); /* pass in the name of the source file */
+int source_get(); /* no args; returns the next char or EOF */
+void init_scraps();
+int collect_scrap();
+int write_scraps();
+Name *collect_file_name();
+Name *collect_macro_name();
+Name *collect_scrap_name();
+Name *name_add();
+Name *prefix_add();
+char *save_string();
+void reverse_lists();
+void *arena_getmem();
+void arena_free();
+
+
+void main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int arg = 1;
+ tex_flag = TRUE;
+ output_flag = TRUE;
+ compare_flag = TRUE;
+ command_name = argv[0];
+ while (arg < argc) {
+ char *s = argv[arg];
+ if (*s++ == '-') {
+ {
+ char c = *s++;
+ while (c) {
+ switch (c) {
+ case 'c': compare_flag = FALSE;
+ break;
+ case 'o': output_flag = FALSE;
+ break;
+ case 't': tex_flag = FALSE;
+ break;
+ case 'v': printf("nuweb version 0.6\n");
+ break;
+ default: fprintf(stderr, "%s: unexpected argument ignored. ",
+ command_name);
+ fprintf(stderr, "Usage is: %s [-cot] file...\n",
+ command_name);
+ break;
+ }
+ c = *s++;
+ }
+ }
+ arg++;
+ }
+ else break;
+ }
+ if (arg < argc)
+ do {
+ {
+ char source_name[100];
+ char tex_name[100];
+ {
+ char *p = argv[arg];
+ char *q = source_name;
+ char *trim = q;
+ char *dot = NULL;
+ char c = *p++;
+ while (c) {
+ *q++ = c;
+ if (c == '/') {
+ trim = q;
+ dot = NULL;
+ }
+ else if (c == '.')
+ dot = q - 1;
+ c = *p++;
+ }
+ *q = '\0';
+ if (dot) {
+ *dot = '\0';
+ sprintf(tex_name, "%s.tex", trim);
+ *dot = '.';
+ }
+ else {
+ sprintf(tex_name, "%s.tex", trim);
+ *q++ = '.';
+ *q++ = 'w';
+ *q = '\0';
+ }
+ }
+ {
+ pass1(source_name);
+ if (tex_flag)
+ write_tex(source_name, tex_name);
+ if (output_flag)
+ write_files(file_names);
+ arena_free();
+ }
+ }
+ arg++;
+ } while (arg < argc);
+ else {
+ fprintf(stderr, "%s: expected a file name. ", command_name);
+ fprintf(stderr, "Usage is: %s [-cot] file-name...\n", command_name);
+ exit(-1);
+ }
+ exit(0);
+}
diff --git a/web/nuweb/msdos/makefile b/web/nuweb/msdos/makefile
new file mode 100644
index 0000000000..0a99d9a892
--- /dev/null
+++ b/web/nuweb/msdos/makefile
@@ -0,0 +1,45 @@
+CC = cc
+
+CFLAGS = -O
+
+TARGET = nuweb
+
+OBJS = main.o pass1.o latex.o output.o input.o scraps.o names.o arena.o
+
+LIBS =
+
+.SUFFIXES: .tex .dvi .w
+
+.w.tex:
+ nuweb $*
+
+.tex.dvi:
+ latex $*
+
+.w.dvi:
+ $(MAKE) $*.tex
+ $(MAKE) $*.dvi
+
+all:
+ $(MAKE) $(TARGET).tex
+ $(MAKE) $(TARGET)
+
+shar: $(TARGET).tex
+ shar -o $(TARGET).shar Makefile README literate.bib nuweb.w \
+ nuweb.tex arena.c input.c latex.c main.c names.c \
+ output.c pass1.c scraps.c
+
+clean:
+ rm -f *.tex *.log *.dvi *~ *.blg
+
+veryclean:
+ rm -f *.o *.c *.h *.tex *.log *.dvi *~ *.blg
+
+view: $(TARGET).dvi
+ xdvi $(TARGET).dvi
+
+print: $(TARGET).dvi
+ lpr -d $(TARGET).dvi
+
+$(TARGET): $(OBJS)
+ $(CC) -o $(TARGET) $(OBJS)
diff --git a/web/nuweb/msdos/names.c b/web/nuweb/msdos/names.c
new file mode 100644
index 0000000000..b89e77cfe2
--- /dev/null
+++ b/web/nuweb/msdos/names.c
@@ -0,0 +1,422 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!0)
+#endif
+typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+
+int tex_flag; /* if FALSE, don't emit the .tex file */
+int output_flag; /* if FALSE, don't emit the output files */
+int compare_flag; /* if FALSE, overwrite without comparison */
+char *command_name;
+char *source_name; /* name of the current file */
+int source_line; /* current line in the source file */
+Name *file_names;
+Name *macro_names;
+Name *user_names;
+
+void pass1();
+void write_tex();
+void write_files();
+void source_open(); /* pass in the name of the source file */
+int source_get(); /* no args; returns the next char or EOF */
+void init_scraps();
+int collect_scrap();
+int write_scraps();
+Name *collect_file_name();
+Name *collect_macro_name();
+Name *collect_scrap_name();
+Name *name_add();
+Name *prefix_add();
+char *save_string();
+void reverse_lists();
+void *arena_getmem();
+void arena_free();
+
+
+enum { LESS, GREATER, EQUAL, PREFIX, EXTENSION };
+
+static int compare(x, y)
+ char *x;
+ char *y;
+{
+ int len, result;
+ int xl = strlen(x);
+ int yl = strlen(y);
+ int xp = x[xl - 1] == ' ';
+ int yp = y[yl - 1] == ' ';
+ if (xp) xl--;
+ if (yp) yl--;
+ len = xl < yl ? xl : yl;
+ result = strncmp(x, y, len);
+ if (result < 0) return GREATER;
+ else if (result > 0) return LESS;
+ else if (xl < yl) {
+ if (xp) return EXTENSION;
+ else return LESS;
+ }
+ else if (xl > yl) {
+ if (yp) return PREFIX;
+ else return GREATER;
+ }
+ else return EQUAL;
+}
+char *save_string(s)
+ char *s;
+{
+ char *new = (char *) arena_getmem((strlen(s) + 1) * sizeof(char));
+ strcpy(new, s);
+ return new;
+}
+Name *prefix_add(root, spelling)
+ Name **root;
+ char *spelling;
+{
+ Name *node = *root;
+ while (node) {
+ switch (compare(node->spelling, spelling)) {
+ case GREATER: root = &node->rlink;
+ break;
+ case LESS: root = &node->llink;
+ break;
+ case EQUAL: return node;
+ case EXTENSION: node->spelling = save_string(spelling);
+ return node;
+ case PREFIX: {
+ if (ambiguous_prefix(node->llink, spelling) ||
+ ambiguous_prefix(node->rlink, spelling))
+ fprintf(stderr,
+ "%s: ambiguous prefix @<%s...@> (%s, line %d)\n",
+ command_name, spelling, source_name, source_line);
+ }
+ return node;
+ }
+ node = *root;
+ }
+ {
+ node = (Name *) arena_getmem(sizeof(Name));
+ node->spelling = save_string(spelling);
+ node->mark = FALSE;
+ node->llink = NULL;
+ node->rlink = NULL;
+ node->uses = NULL;
+ node->defs = NULL;
+ node->tab_flag = TRUE;
+ node->indent_flag = TRUE;
+ node->debug_flag = FALSE;
+ *root = node;
+ return node;
+ }
+}
+static int ambiguous_prefix(node, spelling)
+ Name *node;
+ char *spelling;
+{
+ while (node) {
+ switch (compare(node->spelling, spelling)) {
+ case GREATER: node = node->rlink;
+ break;
+ case LESS: node = node->llink;
+ break;
+ case EQUAL:
+ case EXTENSION:
+ case PREFIX: return TRUE;
+ }
+ }
+ return FALSE;
+}
+static int robs_strcmp(x, y)
+ char *x;
+ char *y;
+{
+ char *xx = x;
+ char *yy = y;
+ int xc = toupper(*xx);
+ int yc = toupper(*yy);
+ while (xc == yc && xc) {
+ xx++;
+ yy++;
+ xc = toupper(*xx);
+ yc = toupper(*yy);
+ }
+ if (xc != yc) return xc - yc;
+ xc = *x;
+ yc = *y;
+ while (xc == yc && xc) {
+ x++;
+ y++;
+ xc = *x;
+ yc = *y;
+ }
+ if (isupper(xc) && islower(yc))
+ return xc * 2 - (toupper(yc) * 2 + 1);
+ if (islower(xc) && isupper(yc))
+ return toupper(xc) * 2 + 1 - yc * 2;
+ return xc - yc;
+}
+Name *name_add(root, spelling)
+ Name **root;
+ char *spelling;
+{
+ Name *node = *root;
+ while (node) {
+ int result = robs_strcmp(node->spelling, spelling);
+ if (result > 0)
+ root = &node->llink;
+ else if (result < 0)
+ root = &node->rlink;
+ else
+ return node;
+ node = *root;
+ }
+ {
+ node = (Name *) arena_getmem(sizeof(Name));
+ node->spelling = save_string(spelling);
+ node->mark = FALSE;
+ node->llink = NULL;
+ node->rlink = NULL;
+ node->uses = NULL;
+ node->defs = NULL;
+ node->tab_flag = TRUE;
+ node->indent_flag = TRUE;
+ node->debug_flag = FALSE;
+ *root = node;
+ return node;
+ }
+}
+Name *collect_file_name()
+{
+ Name *new_name;
+ char name[100];
+ char *p = name;
+ int start_line = source_line;
+ int c = source_get();
+ while (isspace(c))
+ c = source_get();
+ while (isgraph(c)) {
+ *p++ = c;
+ c = source_get();
+ }
+ if (p == name) {
+ fprintf(stderr, "%s: expected file name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ *p = '\0';
+ new_name = name_add(&file_names, name);
+ {
+ while (1) {
+ while (isspace(c))
+ c = source_get();
+ if (c == '-') {
+ c = source_get();
+ do {
+ switch (c) {
+ case 't': new_name->tab_flag = FALSE;
+ break;
+ case 'd': new_name->debug_flag = TRUE;
+ break;
+ case 'i': new_name->indent_flag = FALSE;
+ break;
+ default : fprintf(stderr, "%s: unexpected per-file flag (%s, %d)\n",
+ command_name, source_name, source_line);
+ break;
+ }
+ c = source_get();
+ } while (!isspace(c));
+ }
+ else break;
+ }
+ }
+ if (c == '@' && source_get() == '{')
+ return new_name;
+ else {
+ fprintf(stderr, "%s: expected @{ after file name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+}
+Name *collect_macro_name()
+{
+ char name[100];
+ char *p = name;
+ int start_line = source_line;
+ int c = source_get();
+ while (isspace(c))
+ c = source_get();
+ while (c != EOF) {
+ switch (c) {
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': *p++ = c;
+ break;
+ case '{': {
+ if (p > name && p[-1] == ' ')
+ p--;
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ if (p == name || name[0] == ' ') {
+ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ default: fprintf(stderr,
+ "%s: unexpected @%c in macro name (%s, %d)\n",
+ command_name, c, source_name, start_line);
+ exit(-1);
+ }
+ }
+ break;
+ case '\t':
+ case ' ': *p++ = ' ';
+ do
+ c = source_get();
+ while (c == ' ' || c == '\t');
+ break;
+ case '\n': {
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c == '@' && source_get() == '{')
+ {
+ if (p > name && p[-1] == ' ')
+ p--;
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ if (p == name || name[0] == ' ') {
+ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ else {
+ fprintf(stderr, "%s: expected @{ after macro name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ }
+ default: *p++ = c;
+ c = source_get();
+ break;
+ }
+ }
+ fprintf(stderr, "%s: expected macro name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+}
+Name *collect_scrap_name()
+{
+ char name[100];
+ char *p = name;
+ int c = source_get();
+ while (c == ' ' || c == '\t')
+ c = source_get();
+ while (c != EOF) {
+ switch (c) {
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': *p++ = c;
+ c = source_get();
+ break;
+ case '>': {
+ if (p > name && p[-1] == ' ')
+ p--;
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ if (p == name || name[0] == ' ') {
+ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ default: fprintf(stderr,
+ "%s: unexpected @%c in macro name (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+ }
+ break;
+ case '\t':
+ case ' ': *p++ = ' ';
+ do
+ c = source_get();
+ while (c == ' ' || c == '\t');
+ break;
+ default: if (isgraph(c)) {
+ *p++ = c;
+ c = source_get();
+ }
+ else {
+ fprintf(stderr,
+ "%s: unexpected character in macro name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ break;
+ }
+ }
+ fprintf(stderr, "%s: unexpected end of file (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+}
+static Scrap_Node *reverse(); /* a forward declaration */
+
+void reverse_lists(names)
+ Name *names;
+{
+ while (names) {
+ reverse_lists(names->llink);
+ names->defs = reverse(names->defs);
+ names->uses = reverse(names->uses);
+ names = names->rlink;
+ }
+}
+static Scrap_Node *reverse(a)
+ Scrap_Node *a;
+{
+ if (a) {
+ Scrap_Node *b = a->next;
+ a->next = NULL;
+ while (b) {
+ Scrap_Node *c = b->next;
+ b->next = a;
+ a = b;
+ b = c;
+ }
+ }
+ return a;
+}
diff --git a/web/nuweb/msdos/nuweb.1 b/web/nuweb/msdos/nuweb.1
new file mode 100644
index 0000000000..5fbc0df273
--- /dev/null
+++ b/web/nuweb/msdos/nuweb.1
@@ -0,0 +1,107 @@
+.TH NUWEB 1 "local 2/26/93"
+.SH NAME
+Nuweb, a literate programming tool
+.SH SYNOPSIS
+.B nuweb
+.br
+\fBnuweb\fP [\fB-t\fP|\fB-c\fP|\fB-o\fP] [file] ...
+.SH DESCRIPTION
+.I Nuweb
+is a literate programming tool like Knuth's
+.I WEB,
+only simpler.
+A
+.I nuweb
+file contains program source code interleaved with documentation.
+When
+.I nuweb
+is given a
+.I nuweb
+file, it writes the program file(s),
+and also
+produces,
+.I LaTeX
+source for typeset documentation.
+.SH COMMAND LINE OPTIONS
+.br
+\fB-t\fP Suppress generation of the \fB.tex\fP file.
+.br
+\fB-o\fP Suppress generation of the output file(s).
+.br
+\fB-c\fP Avoid testing output files for change before updating them.
+.br
+.SH FORMAT OF NUWEB FILES
+A
+.I nuweb
+file contains mostly ordinary
+.I LaTeX.
+The file is read and copied to output (.tex file) unless a
+.I nuweb
+command is encountered. All
+.I nuweb
+commands start with an ``at-sign'' (@).
+Files and macros are defined with the following commands:
+.PP
+@o \fIfile-name flags scrap\fP where scrap is smaller than one page.
+.br
+@O \fIfile-name flags scrap\fP where scrap is bigger than one page.
+.br
+@d \fImacro-name scrap\fP. Where scrap is smallar than one page.
+.br
+@D \fImacro-name scrap\fP. Where scrap is bigger than one page.
+.PP
+Scraps have specific begin and end
+markers: \fB@{\fP and \fB@}\fP.
+Any amount of whitespace
+(including carriage returns) may appear between a name and the
+begining of a scrap.
+.PP
+Several code/file scraps may have the same name;
+.I nuweb
+concatenates their definitions to produce a single scrap.
+Code scrap definitions are like macro definitions;
+.I nuweb
+extracts a program by expanding one scrap.
+The definition of that scrap contains references to other scraps, which are
+themselves expanded, and so on.
+\fINuweb\fP's output is readable; it preserves the indentation of expanded
+scraps with respect to the scraps in which they appear.
+.PP
+.SH PER FILE OPTIONS
+When defining an output file, the programmer has the option of using flags
+to control the output.
+.PP
+\fB-d\fR option,
+.I Nuweb
+will emit line number indications at scrap boundaries.
+.br
+\fB-i\fR option,
+.I Nuweb
+supresses the indentation of macros (useful for \fBFortran\fR).
+.br
+\fB-t\fP option makes \fInuweb\fP
+copy tabs untouched from input to output.
+.PP
+.SH MINOR COMMANDS
+.br
+@@ Causes a single ``at-sign'' to be copied into the output.
+.br
+@i \fBfilename\fR causes the file named to be included.
+.br
+@f Creates an index of output files.
+.br
+@m Creates an index of macros.
+.br
+@u Creates an index of user-specified identifiers.
+.PP
+To mark an identifier for inclusion in the index, it must be mentioned
+at the end of the scrap it was defined in. The line starts
+with @| and ends with the \fBend of scrap\fP mark \fB@}\fP.
+.PP
+.SH ERROR MESSAGES
+.PP
+.SH BUGS
+.PP
+.SH AUTHOR
+Preston Briggs.
+Internet address \fBpreston@cs.rice.edu\fP.
diff --git a/web/nuweb/msdos/nuweb.bbl b/web/nuweb/msdos/nuweb.bbl
new file mode 100644
index 0000000000..224d2050b3
--- /dev/null
+++ b/web/nuweb/msdos/nuweb.bbl
@@ -0,0 +1,58 @@
+\begin{thebibliography}{10}
+
+\bibitem{aho:75}
+Alfred~V. Aho and Margaret~J. Corasick.
+\newblock Efficient string matching: An aid to bibliographic search.
+\newblock {\em Communications of the ACM}, 18(6):333--340, June 1975.
+
+\bibitem{hanson:90}
+David~R. Hanson.
+\newblock Fast allocation and deallocation of memory based on object lifetimes.
+\newblock {\em Software -- Practice and Experience}, 20(1):5--12, January 1990.
+
+\bibitem{knuth:84}
+Donald~E. Knuth.
+\newblock Literate programming.
+\newblock {\em The Computer Journal}, 27(2):97--111, May 1984.
+
+\bibitem{metafont:program}
+Donald~E. Knuth.
+\newblock {\em {{\small\sf METAFONT:}} The Program}.
+\newblock Computers \& Typesetting. Addison-Wesley, 1986.
+
+\bibitem{tex:program}
+Donald~E. Knuth.
+\newblock {\em {{\TeX}}: The Program}.
+\newblock Computers \& Typesetting. Addison-Wesley, 1986.
+
+\bibitem{texbook}
+Donald~E. Knuth.
+\newblock {\em The {{\TeX}}book}.
+\newblock Computers \& Typesetting. Addison-Wesley, 1986.
+
+\bibitem{latex}
+Leslie Lamport.
+\newblock {\em {{\LaTeX:}} A Document Preparation System}.
+\newblock Addison-Wesley, 1986.
+
+\bibitem{levy:90}
+Silvio Levy and Donald~E. Knuth.
+\newblock {{\tt CWEB}} user manual: The {{\small CWEB}} system of structured
+ documentation.
+\newblock Technical Report {\small STAN}-{\small CS}-83-977, Stanford
+ University, October 1990.
+\newblock Available for anonymous ftp from {\tt labrea.stanford.edu} in
+ directory {\tt pub/cweb}.
+
+\bibitem{noweb}
+Norman Ramsey.
+\newblock Literate-programming tools need not be complex.
+\newblock Submitted to IEEE Software, August 1992.
+
+\bibitem{funnelweb}
+Ross~N. Williams.
+\newblock {FunnelWeb} user's manual, May 1992.
+\newblock Available for anonymous ftp from {\tt sirius.itd.adelaide.edu.au} in
+ directory {\tt pub/funnelweb}.
+
+\end{thebibliography}
diff --git a/web/nuweb/msdos/nuweb.tex b/web/nuweb/msdos/nuweb.tex
new file mode 100644
index 0000000000..3f3c3906d7
--- /dev/null
+++ b/web/nuweb/msdos/nuweb.tex
@@ -0,0 +1,3897 @@
+\documentstyle{report}
+
+\setlength{\oddsidemargin}{0in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.5in}
+\setlength{\marginparwidth}{0.5in}
+
+\title{Nuweb \\ A Simple Literate Programming Tool}
+\author{\sl Preston Briggs}
+\date{(Version 0.6pc)}
+
+\begin{document}
+\maketitle
+\tableofcontents
+
+\chapter{Introduction}
+
+In 1984, Knuth introduced the idea of {\em literate programming\/} and
+described a pair of tools to support the practise~\cite{knuth:84}.
+His approach was to combine Pascal code with \TeX\ documentation to
+produce a new language, {\tt WEB}, that offered programmers a superior
+approach to programming. He wrote several programs in {\tt WEB},
+including {\tt weave} and {\tt tangle}, the programs used to support
+literate programming.
+The idea was that a programmer wrote one document, the web file, that
+combined documentation (written in \TeX~\cite{texbook}) with code
+(written in Pascal).
+
+Running {\tt tangle} on the web file would produce a complete
+Pascal program, ready for compilation by an ordinary Pascal compiler.
+The primary function of {\tt tangle} is to allow the programmer to
+present elements of the program in any desired order, regardless of
+the restrictions imposed by the programming language. Thus, the
+programmer is free to present his program in a top-down fashion,
+bottom-up fashion, or whatever seems best in terms of promoting
+understanding and maintenance.
+
+Running {\tt weave} on the web file would produce a \TeX\ file, ready
+to be processed by \TeX\@. The resulting document included a variety of
+automatically generated indices and cross-references that made it much
+easier to navigate the code. Additionally, all of the code sections
+were automatically pretty printed, resulting in a quite impressive
+document.
+
+Knuth also wrote the programs for \TeX\ and {\small\sf METAFONT}
+entirely in {\tt WEB}, eventually publishing them in book
+form~\cite{tex:program,metafont:program}. These are probably the
+largest programs ever published in a readable form.
+
+Inspired by Knuth's example, many people have experimented with
+{\tt WEB}\@. Some people have even built web-like tools for their own
+favorite combinations of programming language and typesetting
+language. For example, {\tt CWEB}, Knuth's current system of choice,
+works with a combination of C and \TeX~\cite{levy:90}. Another system,
+FunnelWeb, is independent of any programming language and only mildly
+dependent on \TeX~\cite{funnelweb}. Inspired by the versatility
+of FunnelWeb and by the daunting size of its documentation, I decided
+to write my own, very simple, tool for literate programming.%
+\footnote{There is another system similar to mine, written by Norman
+Ramsey, called {\em noweb}~\cite{noweb}. It perhaps suffers from being
+overly Unix-dependent and requiring several programs to use. On the
+other hand, its command syntax is very nice. In any
+case, nuweb certainly owes its name to his inspiration.}
+
+
+\section{Nuweb}
+
+Nuweb works with any programming language and \LaTeX~\cite{latex}. I
+wanted to use \LaTeX\ because it supports a multi-level sectioning
+scheme and has facilities for drawing figures. I wanted to be able to
+work with arbitrary programming languages because my friends and I
+write programs in many languages (and sometimes combinations of
+several languages), {\em e.g.,} C, Fortran, C++, yacc, lex, Scheme,
+assembly, Postscript, and so forth. The need to support arbitrary
+programming languages has many consequences:
+\begin{description}
+\item[No pretty printing] Both {\tt WEB} and {\tt CWEB} are able to
+ pretty print the code sections of their documents because they
+ understand the language well enough to parse it. Since we want to use
+ {\em any\/} language, we've got to abandon this feature.
+\item[No index of identifiers] Because {\tt WEB} knows about Pascal,
+ it is able to construct an index of all the identifiers occurring in
+ the code sections (filtering out keywords and the standard type
+ identifiers). Unfortunately, this isn't as easy in our case. We don't
+ know what an identifiers looks like in each language and we certainly
+ don't know all the keywords. (On the other hand, see the end of
+ Section~1.3)
+\end{description}
+Of course, we've got to have some compensation for our losses or the
+whole idea would be a waste. Here are the advantages I can see:
+\begin{description}
+\item[Simplicity] The majority of the commands in {\tt WEB} are
+ concerned with control of the automatic pretty printing. Since we
+ don't pretty print, many commands are eliminated. A further set of
+ commands is subsumed by \LaTeX\ and may also be eliminated. As a
+ result, our set of commands is reduced to only four members (explained
+ in the next section). This simplicity is also reflected in
+ the size of this tool, which is quite a bit smaller than the tools
+ used with other approaches.
+\item[No pretty printing] Everyone disagrees about how their code
+ should look, so automatic formatting annoys many people. One approach
+ is to provide ways to control the formatting. Our approach is simpler
+ -- we perform no automatic formatting and therefore allow the
+ programmer complete control of code layout.
+\item[Control] We also offer the programmer complete control of the
+ layout of his output files (the files generated during tangling). Of
+ course, this is essential for languages that are sensitive to layout;
+ but it is also important in many practical situations, {\em e.g.,}
+ debugging.
+\item[Speed] Since nuweb doesn't do to much, the nuweb tool runs
+ quickly. I combine the functions of {\tt tangle} and {\tt weave} into
+ a single program that performs both functions at once.
+\item[Multiple file output] The programmer may specify more than one
+ output file in a single nuweb file. This is required when constructing
+ programs in a combination of languages (say, Fortran and C)\@. It's also
+ an advantage when constructing very large programs that would require
+ a lot of compile time.
+\end{description}
+This last point is very important. By allowing the creation of
+multiple output files, we avoid the need for monolithic programs.
+Thus we support the creation of very large programs by groups of
+people.
+
+A further reduction in compilation time is achieved by first
+writing each output file to a temporary location, then comparing the
+temporary file with the old version of the file. If there is no
+difference, the temporary file can be deleted. If the files differ,
+the old version is deleted and the temporary file renamed. This
+approach works well in combination with {\tt make} (or similar tools),
+since {\tt make} will avoid recompiling untouched output files.
+
+
+\section{Writing Nuweb}
+
+The bulk of a nuweb file will be ordinary \LaTeX\@. In fact, any \LaTeX\
+file can serve as input to nuweb and will be simply copied through
+unchanged to the {\tt .tex} file -- unless a nuweb command is
+discovered. All nuweb commands begin with an ``at-sign'' ({\tt @}).
+Therefore, a file without at-signs will be copied unchanged.
+Nuweb commands are used to specify {\em output files,} define
+{\em macros,} and delimit {\em scraps}. These are the basic features
+of interest to the nuweb tool -- all else is simply text to be copied
+to the {\tt .tex} file.
+
+\subsection{The Major Commands}
+
+Files and macros are defined with the following commands:
+\begin{description}
+\item[\tt @o {\em file-name flags scrap\/}] Output a file. The file name is
+ terminated by whitespace.
+\item[\tt @d {\em macro-name scrap\/}] Define a macro. The macro name
+ is terminated by a return or the beginning of a scrap.
+\end{description}
+A specific file may be specified several times, with each definition
+being written out, one after the other, in the order they appear.
+The definitions of macros may be similarly divided.
+
+\subsubsection{Scraps}
+
+Scraps have specific begin markers and end markers to allow precise
+control over the contents and layout. Note that any amount of
+whitespace (including carriage returns) may appear between a name and
+the beginning of a scrap.
+\begin{description}
+\item[\tt @\{{\em anything\/}@\}] where the scrap body includes every
+ character in {\em anything\/} -- all the blanks, all the tabs, all the
+ carriage returns.
+\end{description}
+Inside a scrap, we may invoke a macro.
+\begin{description}
+\item[\tt @<{\em macro-name\/}@>] Causes the macro {\em macro-name\/}
+ to be expanded inline as the code is written out to a file. It is an
+ error to specify recursive macro invocations.
+\end{description}
+Note that macro names may be abbreviated, either during invocation or
+definition. For example, it would be very tedious to have to
+repeatedly type the macro name
+\begin{quote}
+{\tt @d Check for terminating at-sequence and return name if found}
+\end{quote}
+Therefore, we provide a mechanism (stolen from Knuth) of indicating
+abbreviated names.
+\begin{quote}
+{\tt @d Check for terminating...}
+\end{quote}
+Basically, the programmer need only type enough characters to uniquely
+identify the macro name, followed by three periods. An abbreviation
+may even occur before the full version; nuweb simply preserves the
+longest version of a macro name. Note also that blanks and tabs are
+insignificant in a macro name; any string of them are replaced by a
+single blank.
+
+When scraps are written to an output or {\tt .tex} file, tabs are
+expanded into spaces by default. Currently, I assume tab stops are set
+every eight characters. Furthermore, when a macro is expanded in a scrap,
+the body of the macro is indented to match the indentation of the
+macro invocation. Therefore, care must be taken with languages
+({\em e.g.,} Fortran) that are sensitive to indentation.
+These default behaviors may be changed for each output file (see
+below).
+
+\subsubsection{Flags}
+
+When defining an output file, the programmer has the option of using
+flags to control output of a particular file. The flags are intended
+to make life a little easier for programmers using certain languages.
+They introduce little language dependences; however, they do so only
+for a particular file. Thus it is still easy to mix languages within a
+single document. There are three ``per-file'' flags:
+\begin{description}
+\item[\tt -d] Forces the creation of \verb|#line| directives in the
+ output file. These are useful with C (and sometimes C++ and Fortran) on
+ many Unix systems since they cause the compiler's error messages to
+ refer to the web file rather than the output file. Similarly, they
+ allow source debugging in terms of the web file.
+\item[\tt -i] Suppresses the indentation of macros. That is, when a
+ macro is expanded in a scrap, it will {\em not\/} be indented to
+ match the indentation of the macro invocation. This flag would seem
+ most useful for Fortran programmers.
+\item[\tt -t] Suppresses expansion of tabs in the output file. This
+ feature seems important when generating {\tt make} files.
+\end{description}
+
+
+\subsection{The Minor Commands}
+
+We have two very low-level utility commands that may appear anywhere
+in the web file.
+\begin{description}
+\item[\tt @@] Causes a single ``at sign'' to be copied into the output.
+\item[\tt @i {\em file-name\/}] Includes a file. Includes may be
+ nested, though there is currently a limit of 10~levels. The file name
+ should be complete (no extension will be appended) and should be
+ terminated by a carriage return.
+\end{description}
+Finally, there are three commands used to create indices to the macro
+names, file definitions, and user-specified identifiers.
+\begin{description}
+\item[\tt @f] Create an index of file names.
+\item[\tt @m] Create an index of macro name.
+\item[\tt @u] Create an index of user-specified identifiers.
+\end{description}
+I usually put these in their own section
+in the \LaTeX\ document; for example, see Chapter~\ref{indices}.
+
+Identifiers must be explicitely specified for inclusion in the
+{\tt @u} index. By convention, each identifier is marked at the point
+of its definition; all references to each identifier (inside scraps)
+will be discovered automatically. To ``mark'' an identifier for
+inclusion in the index, we must mention it at the end of a scrap.
+For example,
+\begin{quote}
+\begin{verbatim}
+@d a scrap @{
+Let's pretend we're declaring the variables FOO and BAR
+inside this scrap.
+@| FOO BAR @}
+\end{verbatim}
+\end{quote}
+I've used alphabetic identifiers in this example, but any string of
+characters (not including whitespace) will do. Therefore, it's
+possible to add index entries for things like {\tt <<=} if desired.
+An identifier may be declared in more than one scrap.
+
+In the generated index, each identifier appears with a list of all the
+scraps using and defining it, where the defining scraps are
+distinguished by underlining. Note that the identifier doesn't
+actually have to appear in the defining scrap; it just has to be in
+the list of definitions at the end of a scrap.
+
+
+\section{Running Nuweb}
+
+Nuweb is invoked using the following command:
+\begin{quote}
+{\tt nuweb} {\em flags file-name}\ldots
+\end{quote}
+One or more files may be processed at a time. If a file name has no
+extension, {\tt .w} will be appended. While a file name may specify a
+file in another directory, the resulting {\tt .tex} file will always
+be created in the current directory. For example,
+\begin{quote}
+{\tt nuweb /foo/bar/quux}
+\end{quote}
+will take as input the file {\tt /foo/bar/quux.w} and will create the
+file {\tt quux.tex} in the current directory.
+
+By default, nuweb performs both tangling and weaving at the same time.
+Normally, this is not a bottleneck in the compilation process;
+however, it's possible to achieve slightly faster throughput by
+avoiding one or another of the default functions using command-line
+flags. There are currently three possible flags:
+\begin{description}
+\item[\tt -t] Suppress generation of the {\tt .tex} file.
+\item[\tt -o] Suppress generation of the output files.
+\item[\tt -c] Avoid testing output files for change before updating them.
+\end{description}
+Thus, the command
+\begin{quote}
+{\tt nuweb -to /foo/bar/quux}
+\end{quote}
+would simply scan the input and produce no output at all.
+
+
+\section{Restrictions and Extensions}
+
+Because nuweb is intended to be a simple tool, I've established a few
+restrictions. Over time, some of these may be eliminated; others seem
+fundamental.
+\begin{itemize}
+\item The scraps don't print well with older versions of \TeX\
+ (pre~3.0). I'm not sure why and I'm not sure it's always true
+ (I don't have a version to experiment with).
+\item The handling of errors is not completely ideal. In some cases, I
+ simply warn of a problem and continue; in other cases I halt
+ immediately. This behavior should be regularized.
+\item I warn about references to macros that haven't been defined, but
+ don't halt. This seems most convenient for development, but may change
+ in the future.
+\item File names and index entries should not contain any {\tt @}
+ signs.
+\item Macro names may be (almost) any well-formed \TeX\ string.
+ It makes sense to change fonts or use math mode; however, care should
+ be taken to ensure matching braces, brackets, and dollar signs.
+\item Anything is allowed in the body of a scrap; however, very
+ long scraps (horizontally or vertically) may not typeset well.
+\end{itemize}
+Very long scraps may be allowed to break across a page if declared
+with {\tt @O} or {\tt @D} (instead of {\tt @o} or {\tt @d}).
+This doesn't work very well as a default, since far too many short
+scraps will be broken across pages; however, as a user-controlled
+option, it seems very useful.
+
+
+\chapter{The Overall Structure}
+
+Processing a web requires three major steps:
+\begin{enumerate}
+\item Read the source, accumulating file names, macro names, scraps,
+and lists of cross-references.
+\item Reread the source, copying out to the {\tt .tex} file, with
+protection and cross-reference information for all the scraps.
+\item Traverse the list of files names. For each file name:
+\begin{enumerate}
+\item Dump all the defining scraps into a temporary file.
+\item If the file already exists and is unchanged, delete the
+temporary file; otherwise, rename the temporary file.
+\end{enumerate}
+\end{enumerate}
+
+
+\section{Files}
+
+I have divided the program into several files for quicker
+recompilation during development. Rather than use {\tt .h} files
+for shared declarations, I'll simply create a shared scrap containing
+all the global declarations. This isn't really best from the point of
+view of disk space; but it does simplify the makefile (and allow me to
+play with my new toy).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Shared declarations {\footnotesize 1}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Include files {\footnotesize 2}$\rangle$\verb@@\\
+\verb@@$\langle$Type declarations {\footnotesize 3}$\rangle$\verb@@\\
+\verb@@$\langle$Global variables {\footnotesize 13}$\rangle$\verb@@\\
+\verb@@$\langle$Function prototypes {\footnotesize 23}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 4, 5, 6, 7, 8, 9 and~10.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We'll need at least two of the standard system include files.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Include files {\footnotesize 2}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@#include <stdio.h>@\\
+\verb@#include <string.h>@\\
+\verb@#include <ctype.h>@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 1 and~11.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+I also like to use {\tt TRUE} and {\tt FALSE} in my code.
+I'd use an {\tt enum} here, except that some systems seem to provide
+definitions of {\tt TRUE} and {\tt FALSE} be default. The following
+code seems to work on all the local systems.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Type declarations {\footnotesize 3}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@#ifndef FALSE@\\
+\verb@#define FALSE 0@\\
+\verb@#endif@\\
+\verb@#ifndef TRUE@\\
+\verb@#define TRUE (!0)@\\
+\verb@#endif@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 3, 100 and~101.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{The Main Files}
+
+The code is divided into four main files (introduced here) and five
+support files (introduced in the next section).
+The file {\tt main.c} will contain the driver for the whole program
+(see Section~\ref{main-routine}).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"main.c"@ {\footnotesize 4 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Shared declarations {\footnotesize 1}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 4 and~12.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The first pass over the source file is contained in {\tt pass1.c}.
+It handles collection of all the file names, macros names, and scraps
+(see Section~\ref{pass-one}).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"pass1.c"@ {\footnotesize 5 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Shared declarations {\footnotesize 1}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 5 and~24.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The {\tt .tex} file is created during a second pass over the source
+file. The file {\tt latex.c} contains the code controlling the
+construction of the {\tt .tex} file
+(see Section~\ref{latex-file}).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"latex.c"@ {\footnotesize 6 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Shared declarations {\footnotesize 1}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 6, 32, 33, 44, 45, 52 and~58.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The code controlling the creation of the output files is in {\tt output.c}
+(see Section~\ref{output-files}).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"output.c"@ {\footnotesize 7 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Shared declarations {\footnotesize 1}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 7 and~61.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Support Files}
+
+The support files contain a variety of support routines used to define
+and manipulate the major data abstractions.
+The file {\tt input.c} holds all the routines used for referring to
+source files (see Section~\ref{source-files}).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"input.c"@ {\footnotesize 8 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Shared declarations {\footnotesize 1}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 8, 66, 67, 68 and~73.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Creation and lookup of scraps is handled by routines in {\tt scraps.c}
+(see Section~\ref{scraps}).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 9 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Shared declarations {\footnotesize 1}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The handling of file names and macro names is detailed in {\tt names.c}
+(see Section~\ref{names}).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 10 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Shared declarations {\footnotesize 1}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Memory allocation and deallocation is handled by routines in {\tt arena.c}
+(see Section~\ref{memory-management}). I don't bother including all
+the shared declarations since they aren't required.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"arena.c"@ {\footnotesize 11 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@$\langle$Include files {\footnotesize 2}$\rangle$\verb@@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 11, 131, 132, 133 and~136.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{The Main Routine} \label{main-routine}
+
+The main routine is quite simple in structure.
+It wades through the optional command-line arguments,
+then handles any files listed on the command line.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"main.c"@ {\footnotesize 12 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void main(argc, argv)@\\
+\verb@ int argc;@\\
+\verb@ char **argv;@\\
+\verb@{@\\
+\verb@ int arg = 1;@\\
+\verb@ @$\langle$Interpret command-line arguments {\footnotesize 14}$\rangle$\verb@@\\
+\verb@ @$\langle$Process the remaining arguments (file names) {\footnotesize 19}$\rangle$\verb@@\\
+\verb@ exit(0);@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 4 and~12.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Command-Line Arguments}
+
+There are three possible command-line arguments:
+\begin{description}
+\item[{\tt -t}] Suppresses generation of the {\tt .tex} file.
+\item[{\tt -o}] Suppresses generation of the output files.
+\item[{\tt -c}] Forces output files to overwrite old files of the same
+name without comparing for equality first.
+\item[{\tt -v}] Prints the current version of {\tt nuweb}.
+\end{description}
+Global flags are declared for each of the arguments.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Global variables {\footnotesize 13}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@int tex_flag; /* if FALSE, don't emit the .tex file */@\\
+\verb@int output_flag; /* if FALSE, don't emit the output files */@\\
+\verb@int compare_flag; /* if FALSE, overwrite without comparison */@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 13, 15, 65 and~102.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+The flags are all initialized to {\tt TRUE} for correct default behavior.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Interpret command-line arguments {\footnotesize 14}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@tex_flag = TRUE;@\\
+\verb@output_flag = TRUE;@\\
+\verb@compare_flag = TRUE;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 14, 16 and~17.\\[-1ex]
+Macro referenced in scrap 12.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We save the invocation name of the command in a global variable
+{\tt command\_name} for use in error messages.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Global variables {\footnotesize 15}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@char *command_name;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 13, 15, 65 and~102.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The invocation name is conventionally passed in {\tt argv[0]}.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Interpret command-line arguments {\footnotesize 16}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@command_name = argv[0];@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 14, 16 and~17.\\[-1ex]
+Macro referenced in scrap 12.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We need to examine the remaining entries in {\tt argv}, looking for
+command-line arguments.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Interpret command-line arguments {\footnotesize 17}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@while (arg < argc) {@\\
+\verb@ char *s = argv[arg];@\\
+\verb@ if (*s++ == '-') {@\\
+\verb@ @$\langle$Interpret the argument string {\tt s} {\footnotesize 18}$\rangle$\verb@@\\
+\verb@ arg++;@\\
+\verb@ }@\\
+\verb@ else break;@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 14, 16 and~17.\\[-1ex]
+Macro referenced in scrap 12.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+Several flags can be stacked behind a single minus sign; therefore,
+we've got to loop through the string, handling them all.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Interpret the argument string {\tt s} {\footnotesize 18}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ char c = *s++;@\\
+\verb@ while (c) {@\\
+\verb@ switch (c) {@\\
+\verb@ case 'c': compare_flag = FALSE;@\\
+\verb@ break;@\\
+\verb@ case 'o': output_flag = FALSE;@\\
+\verb@ break;@\\
+\verb@ case 't': tex_flag = FALSE;@\\
+\verb@ break;@\\
+\verb@ case 'v': printf("nuweb version 0.6\n");@\\
+\verb@ break;@\\
+\verb@ default: fprintf(stderr, "%s: unexpected argument ignored. ",@\\
+\verb@ command_name);@\\
+\verb@ fprintf(stderr, "Usage is: %s [-cot] file...\n",@\\
+\verb@ command_name);@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@ c = *s++;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 17.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{File Names}
+
+We expect at least one file name. While a missing file name might be
+ignored without causing any problems, we take the opportunity to report
+the usage convention.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Process the remaining arguments (file names) {\footnotesize 19}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@if (arg < argc)@\\
+\verb@ do {@\\
+\verb@ @$\langle$Handle the file name in {\tt argv[arg]} {\footnotesize 20}$\rangle$\verb@@\\
+\verb@ arg++;@\\
+\verb@ } while (arg < argc);@\\
+\verb@else {@\\
+\verb@ fprintf(stderr, "%s: expected a file name. ", command_name);@\\
+\verb@ fprintf(stderr, "Usage is: %s [-cot] file-name...\n", command_name);@\\
+\verb@ exit(-1);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 12.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+The code to handle a particular file name is rather more tedious than
+the actual processing of the file. A file name may be an arbitrarily
+complicated path name, with an optional extension. If no extension is
+present, we add {\tt .w} as a default. The extended path name will be
+kept in a local variable {\tt source\_name}. The resulting {\tt .tex}
+file will be written in the current directory; its name will be kept
+in the variable {\tt tex\_name}.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Handle the file name in {\tt argv[arg]} {\footnotesize 20}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ char source_name[100];@\\
+\verb@ char tex_name[100];@\\
+\verb@ @$\langle$Build {\tt source\_name} and {\tt tex\_name} {\footnotesize 21}$\rangle$\verb@@\\
+\verb@ @$\langle$Process a file {\footnotesize 22}$\rangle$\verb@@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 19.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+I bump the pointer {\tt p} through all the characters in {\tt argv[arg]},
+copying all the characters into {\tt source\_name} (via the pointer
+{\tt q}).
+
+At each slash, I update {\tt trim} to point just past the
+slash in {\tt source\_name}. The effect is that {\tt trim} will point
+at the file name without any leading directory specifications.
+
+The pointer {\tt dot} is made to point at the file name extension, if
+present. If there is no extension, we add {\tt .w} to the source name.
+In any case, we create the {\tt tex\_name} from {\tt trim}, taking
+care to get the correct extension.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Build {\tt source\_name} and {\tt tex\_name} {\footnotesize 21}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ char *p = argv[arg];@\\
+\verb@ char *q = source_name;@\\
+\verb@ char *trim = q;@\\
+\verb@ char *dot = NULL;@\\
+\verb@ char c = *p++;@\\
+\verb@ while (c) {@\\
+\verb@ *q++ = c;@\\
+\verb@ if (c == '/') {@\\
+\verb@ trim = q;@\\
+\verb@ dot = NULL;@\\
+\verb@ }@\\
+\verb@ else if (c == '.')@\\
+\verb@ dot = q - 1;@\\
+\verb@ c = *p++;@\\
+\verb@ }@\\
+\verb@ *q = '\0';@\\
+\verb@ if (dot) {@\\
+\verb@ *dot = '\0';@\\
+\verb@ sprintf(tex_name, "%s.tex", trim);@\\
+\verb@ *dot = '.';@\\
+\verb@ }@\\
+\verb@ else {@\\
+\verb@ sprintf(tex_name, "%s.tex", trim);@\\
+\verb@ *q++ = '.';@\\
+\verb@ *q++ = 'w';@\\
+\verb@ *q = '\0';@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 20.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Now that we're finally ready to process a file, it's not really too
+complex. We bundle most of the work into three routines {\tt pass1}
+(see Section~\ref{pass-one}), {\tt write\_tex} (see
+Section~\ref{latex-file}), and {\tt write\_files} (see
+Section~\ref{output-files}). After we're finished with a
+particular file, we must remember to release its storage (see
+Section~\ref{memory-management}).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Process a file {\footnotesize 22}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ pass1(source_name);@\\
+\verb@ if (tex_flag)@\\
+\verb@ write_tex(source_name, tex_name);@\\
+\verb@ if (output_flag)@\\
+\verb@ write_files(file_names);@\\
+\verb@ arena_free();@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 20.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Pass One} \label{pass-one}
+
+During the first pass, we scan the file, recording the definitions of
+each macro and file and accumulating all the scraps.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Function prototypes {\footnotesize 23}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void pass1();@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 23, 31, 60, 64, 77, 103 and~130.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The routine {\tt pass1} takes a single argument, the name of the
+source file. It opens the file, then initializes the scrap structures
+(see Section~\ref{scraps}) and the roots of the file-name tree, the
+macro-name tree, and the tree of user-specified index entries (see
+Section~\ref{names}). After completing all the
+necessary preparation, we make a pass over the file, filling in all
+our data structures. Next, we seach all the scraps for references to
+the user-specified index entries. Finally, we must reverse all the
+cross-reference lists accumulated while scanning the scraps.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"pass1.c"@ {\footnotesize 24 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void pass1(file_name)@\\
+\verb@ char *file_name;@\\
+\verb@{@\\
+\verb@ source_open(file_name);@\\
+\verb@ init_scraps();@\\
+\verb@ macro_names = NULL;@\\
+\verb@ file_names = NULL;@\\
+\verb@ user_names = NULL;@\\
+\verb@ @$\langle$Scan the source file, looking for at-sequences {\footnotesize 25}$\rangle$\verb@@\\
+\verb@ if (tex_flag)@\\
+\verb@ search();@\\
+\verb@ @$\langle$Reverse cross-reference lists {\footnotesize 30}$\rangle$\verb@@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 5 and~24.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+The only thing we look for in the first pass are the command
+sequences. All ordinary text is skipped entirely.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Scan the source file, looking for at-sequences {\footnotesize 25}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ int c = source_get();@\\
+\verb@ while (c != EOF) {@\\
+\verb@ if (c == '@{\tt @}\verb@')@\\
+\verb@ @$\langle$Scan at-sequence {\footnotesize 26}$\rangle$\verb@@\\
+\verb@ c = source_get();@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 24.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Only four of the at-sequences are interesting during the first pass.
+We skip past others immediately; warning if unexpected sequences are
+discovered.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Scan at-sequence {\footnotesize 26}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = source_get();@\\
+\verb@ switch (c) {@\\
+\verb@ case 'O':@\\
+\verb@ case 'o': @$\langle$Build output file definition {\footnotesize 27}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case 'D':@\\
+\verb@ case 'd': @$\langle$Build macro definition {\footnotesize 28}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case '@{\tt @}\verb@':@\\
+\verb@ case 'u':@\\
+\verb@ case 'm':@\\
+\verb@ case 'f': /* ignore during this pass */@\\
+\verb@ break;@\\
+\verb@ default: fprintf(stderr,@\\
+\verb@ "%s: unexpected @{\tt @}\verb@ sequence ignored (%s, line %d)\n",@\\
+\verb@ command_name, source_name, source_line);@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 25.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Accumulating Definitions}
+
+There are three steps required to handle a definition:
+\begin{enumerate}
+\item Build an entry for the name so we can look it up later.
+\item Collect the scrap and save it in the table of scraps.
+\item Attach the scrap to the name.
+\end{enumerate}
+We go through the same steps for both file names and macro names.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Build output file definition {\footnotesize 27}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Name *name = collect_file_name(); /* returns a pointer to the name entry */@\\
+\verb@ int scrap = collect_scrap(); /* returns an index to the scrap */@\\
+\verb@ @$\langle$Add {\tt scrap} to {\tt name}'s definition list {\footnotesize 29}$\rangle$\verb@@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 26.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Build macro definition {\footnotesize 28}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Name *name = collect_macro_name();@\\
+\verb@ int scrap = collect_scrap();@\\
+\verb@ @$\langle$Add {\tt scrap} to {\tt name}'s definition list {\footnotesize 29}$\rangle$\verb@@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 26.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Since a file or macro may be defined by many scraps, we maintain them
+in a simple linked list. The list is actually built in reverse order,
+with each new definition being added to the head of the list.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Add {\tt scrap} to {\tt name}'s definition list {\footnotesize 29}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));@\\
+\verb@ def->scrap = scrap;@\\
+\verb@ def->next = name->defs;@\\
+\verb@ name->defs = def;@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 27 and~28.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Fixing the Cross References}
+
+Since the definition and reference lists for each name are accumulated
+in reverse order, we take the time at the end of {\tt pass1} to
+reverse them all so they'll be simpler to print out prettily.
+The code for {\tt reverse\_lists} appears in Section~\ref{names}.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Reverse cross-reference lists {\footnotesize 30}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ reverse_lists(file_names);@\\
+\verb@ reverse_lists(macro_names);@\\
+\verb@ reverse_lists(user_names);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 24.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Writing the Latex File} \label{latex-file}
+
+The second pass (invoked via a call to {\tt write\_tex}) copies most of
+the text from the source file straight into a {\tt .tex} file.
+Definitions are formatted slightly and cross-reference information is
+printed out.
+
+Note that all the formatting is handled in this section.
+If you don't like the format of definitions or indices or whatever,
+it'll be in this section somewhere. Similarly, if someone wanted to
+modify nuweb to work with a different typesetting system, this would
+be the place to look.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Function prototypes {\footnotesize 31}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void write_tex();@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 23, 31, 60, 64, 77, 103 and~130.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+We need a few local function declarations before we get into the body
+of {\tt write\_tex}.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"latex.c"@ {\footnotesize 32 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static void copy_scrap(); /* formats the body of a scrap */@\\
+\verb@static void print_scrap_numbers(); /* formats a list of scrap numbers */@\\
+\verb@static void format_entry(); /* formats an index entry */@\\
+\verb@static void format_user_entry();@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 6, 32, 33, 44, 45, 52 and~58.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The routine {\tt write\_tex} takes two file names as parameters: the
+name of the web source file and the name of the {\tt .tex} output file.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"latex.c"@ {\footnotesize 33 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void write_tex(file_name, tex_name)@\\
+\verb@ char *file_name;@\\
+\verb@ char *tex_name;@\\
+\verb@{@\\
+\verb@ FILE *tex_file = fopen(tex_name, "w");@\\
+\verb@ if (tex_file) {@\\
+\verb@ source_open(file_name);@\\
+\verb@ @$\langle$Copy {\tt source\_file} into {\tt tex\_file} {\footnotesize 34}$\rangle$\verb@@\\
+\verb@ fclose(tex_file);@\\
+\verb@ }@\\
+\verb@ else@\\
+\verb@ fprintf(stderr, "%s: can't open %s\n", command_name, tex_name);@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 6, 32, 33, 44, 45, 52 and~58.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We make our second (and final) pass through the source web, this time
+copying characters straight into the {\tt .tex} file. However, we keep
+an eye peeled for {\tt @}~characters, which signal a command sequence.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Copy {\tt source\_file} into {\tt tex\_file} {\footnotesize 34}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ int scraps = 1;@\\
+\verb@ int c = source_get();@\\
+\verb@ while (c != EOF) {@\\
+\verb@ if (c == '@{\tt @}\verb@')@\\
+\verb@ @$\langle$Interpret at-sequence {\footnotesize 35}$\rangle$\verb@@\\
+\verb@ else {@\\
+\verb@ putc(c, tex_file);@\\
+\verb@ c = source_get();@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 33.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Interpret at-sequence {\footnotesize 35}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ int big_definition = FALSE;@\\
+\verb@ c = source_get();@\\
+\verb@ switch (c) {@\\
+\verb@ case 'O': big_definition = TRUE;@\\
+\verb@ case 'o': @$\langle$Write output file definition {\footnotesize 36}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case 'D': big_definition = TRUE;@\\
+\verb@ case 'd': @$\langle$Write macro definition {\footnotesize 37}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case 'f': @$\langle$Write index of file names {\footnotesize 50}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case 'm': @$\langle$Write index of macro names {\footnotesize 51}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case 'u': @$\langle$Write index of user-specified names {\footnotesize 57}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case '@{\tt @}\verb@': putc(c, tex_file);@\\
+\verb@ default: c = source_get();@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 34.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Formatting Definitions}
+
+We go through a fair amount of effort to format a file definition.
+I've derived most of the \LaTeX\ commands experimentally; it's quite
+likely that an expert could do a better job. The \LaTeX\ for
+the previous macro definition should look like this (perhaps modulo
+the scrap numbers):
+\begin{verbatim}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Interpret at-sequence {\footnotesize 35}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = source_get();@\\
+\verb@ switch (c) {@\\
+\verb@ case 'O': big_definition = TRUE;@\\
+\verb@ case 'o': @$\langle$Write output file definition {\footnotesize 36}$\rangle$\verb@@\\
+\end{verbatim}
+\vdots
+\begin{verbatim}
+\verb@ case '@{\tt @}\verb@': putc(c, tex_file);@\\
+\verb@ default: c = source_get();@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 34.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\end{verbatim}
+The {\em flushleft\/} environment is used to avoid \LaTeX\ warnings
+about underful lines. The {\em minipage\/} environment is used to
+avoid page breaks in the middle of scraps. The {\em verb\/} command
+allows arbitrary characters to be printed (however, note the special
+handling of the {\tt @} case in the switch statement).
+
+Macro and file definitions are formatted nearly identically.
+I've factored the common parts out into separate scraps.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write output file definition {\footnotesize 36}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Name *name = collect_file_name();@\\
+\verb@ @$\langle$Begin the scrap environment {\footnotesize 38}$\rangle$\verb@@\\
+\verb@ fprintf(tex_file, "\\verb@{\tt @}\verb@\"%s\"@{\tt @}\verb@", name->spelling);@\\
+\verb@ fprintf(tex_file, " {\\footnotesize %d }$\\equiv$\n", scraps++);@\\
+\verb@ @$\langle$Fill in the middle of the scrap environment {\footnotesize 39}$\rangle$\verb@@\\
+\verb@ @$\langle$Write file defs {\footnotesize 41}$\rangle$\verb@@\\
+\verb@ @$\langle$Finish the scrap environment {\footnotesize 40}$\rangle$\verb@@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 35.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+I don't format a macro name at all specially, figuring the programmer
+might want to use italics or bold face in the midst of the name.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write macro definition {\footnotesize 37}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Name *name = collect_macro_name();@\\
+\verb@ @$\langle$Begin the scrap environment {\footnotesize 38}$\rangle$\verb@@\\
+\verb@ fprintf(tex_file, "$\\langle$%s", name->spelling);@\\
+\verb@ fprintf(tex_file, " {\\footnotesize %d}$\\rangle\\equiv$\n", scraps++);@\\
+\verb@ @$\langle$Fill in the middle of the scrap environment {\footnotesize 39}$\rangle$\verb@@\\
+\verb@ @$\langle$Write macro defs {\footnotesize 42}$\rangle$\verb@@\\
+\verb@ @$\langle$Write macro refs {\footnotesize 43}$\rangle$\verb@@\\
+\verb@ @$\langle$Finish the scrap environment {\footnotesize 40}$\rangle$\verb@@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 35.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Begin the scrap environment {\footnotesize 38}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ fputs("\\begin{flushleft}\n", tex_file);@\\
+\verb@ if (!big_definition)@\\
+\verb@ fputs("\\begin{minipage}{\\linewidth}\n", tex_file);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 36 and~37.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The interesting things here are the $\Diamond$ inserted at the end of
+each scrap and the various spacing commands. The diamond helps to
+clearly indicate the end of a scrap. The spacing commands were derived
+empirically; they may be adjusted to taste.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Fill in the middle of the scrap environment {\footnotesize 39}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ fputs("\\vspace{-1.5ex}\n\\begin{quote}\n", tex_file);@\\
+\verb@ copy_scrap(tex_file);@\\
+\verb@ fputs("$\\Diamond$\n\\end{quote}\n\\vspace{-2ex}\n", tex_file);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 36 and~37.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+We've got one last spacing command, controlling the amount of white
+space after a scrap.
+
+Note also the whitespace eater. I use it to remove any blank lines
+that appear after a scrap in the source file. This way, text following
+a scrap will not be indented. Again, this is a matter of personal taste.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Finish the scrap environment {\footnotesize 40}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (!big_definition)@\\
+\verb@ fputs("\\end{minipage}\\\\[4ex]\n", tex_file);@\\
+\verb@ fputs("\\end{flushleft}\n", tex_file);@\\
+\verb@ do@\\
+\verb@ c = source_get();@\\
+\verb@ while (isspace(c));@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 36 and~37.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Formatting Cross References}
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write file defs {\footnotesize 41}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (name->defs->next) {@\\
+\verb@ fputs("{\\footnotesize File defined by scraps ", tex_file);@\\
+\verb@ print_scrap_numbers(tex_file, name->defs);@\\
+\verb@ fputs("}\n", tex_file);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 36.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write macro defs {\footnotesize 42}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ fputs("{\\footnotesize ", tex_file);@\\
+\verb@ if (name->defs->next) {@\\
+\verb@ fputs("Macro defined by scraps ", tex_file);@\\
+\verb@ print_scrap_numbers(tex_file, name->defs);@\\
+\verb@ fputs("\\\\[-1ex]\n", tex_file);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 37.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write macro refs {\footnotesize 43}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (name->uses) {@\\
+\verb@ if (name->uses->next) {@\\
+\verb@ fputs("Macro referenced in scraps ", tex_file);@\\
+\verb@ print_scrap_numbers(tex_file, name->uses);@\\
+\verb@ fputs("}\n", tex_file);@\\
+\verb@ }@\\
+\verb@ else@\\
+\verb@ fprintf(tex_file, "Macro referenced in scrap %d.}\n", name->uses->scrap);@\\
+\verb@ }@\\
+\verb@ else {@\\
+\verb@ fputs("Macro never referenced.}\n", tex_file);@\\
+\verb@ fprintf(stderr, "%s: <%s> never referenced.\n",@\\
+\verb@ command_name, name->spelling);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 37.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"latex.c"@ {\footnotesize 44 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static void print_scrap_numbers(tex_file, scraps)@\\
+\verb@ FILE *tex_file;@\\
+\verb@ Scrap_Node *scraps;@\\
+\verb@{@\\
+\verb@ fprintf(tex_file, "%d", scraps->scrap);@\\
+\verb@ scraps = scraps->next;@\\
+\verb@ while (scraps->next) {@\\
+\verb@ fprintf(tex_file, ", %d", scraps->scrap);@\\
+\verb@ scraps = scraps->next;@\\
+\verb@ }@\\
+\verb@ fprintf(tex_file, " and~%d.", scraps->scrap);@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 6, 32, 33, 44, 45, 52 and~58.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Formatting a Scrap}
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"latex.c"@ {\footnotesize 45 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static void copy_scrap(file)@\\
+\verb@ FILE *file;@\\
+\verb@{@\\
+\verb@ int indent = 0;@\\
+\verb@ int c = source_get();@\\
+\verb@ fputs("\\verb@{\tt @}\verb@", file);@\\
+\verb@ while (1) {@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': @$\langle$Check at-sequence for end-of-scrap {\footnotesize 47}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case '\n': fputs("@{\tt @}\verb@\\\\\n\\verb@{\tt @}\verb@", file);@\\
+\verb@ indent = 0;@\\
+\verb@ break;@\\
+\verb@ case '\t': @$\langle$Expand tab into spaces {\footnotesize 46}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ default: putc(c, file);@\\
+\verb@ indent++;@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@ c = source_get();@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 6, 32, 33, 44, 45, 52 and~58.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Expand tab into spaces {\footnotesize 46}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ int delta = 8 - (indent % 8);@\\
+\verb@ indent += delta;@\\
+\verb@ while (delta > 0) {@\\
+\verb@ putc(' ', file);@\\
+\verb@ delta--;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 45 and~97.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Check at-sequence for end-of-scrap {\footnotesize 47}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = source_get();@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': fputs("@{\tt @}\verb@{\\tt @{\tt @}\verb@}\\verb@{\tt @}\verb@", file);@\\
+\verb@ break;@\\
+\verb@ case '|': @$\langle$Skip over index entries {\footnotesize 48}$\rangle$\verb@@\\
+\verb@ case '}': putc('@{\tt @}\verb@', file);@\\
+\verb@ return;@\\
+\verb@ case '<': @$\langle$Format macro name {\footnotesize 49}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ default: /* ignore these since pass1 will have warned about them */@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 45.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+There's no need to check for errors here, since we will have already
+pointed out any during the first pass.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Skip over index entries {\footnotesize 48}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ do {@\\
+\verb@ do@\\
+\verb@ c = source_get();@\\
+\verb@ while (c != '@{\tt @}\verb@');@\\
+\verb@ c = source_get();@\\
+\verb@ } while (c != '}');@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 47.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Format macro name {\footnotesize 49}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Name *name = collect_scrap_name();@\\
+\verb@ fprintf(file, "@{\tt @}\verb@$\\langle$%s {\\footnotesize ", name->spelling);@\\
+\verb@ if (name->defs)@\\
+\verb@ fprintf(file, "%d", name->defs->scrap);@\\
+\verb@ else {@\\
+\verb@ putc('?', file);@\\
+\verb@ fprintf(stderr, "%s: scrap never defined <%s>\n",@\\
+\verb@ command_name, name->spelling);@\\
+\verb@ }@\\
+\verb@ fputs("}$\\rangle$\\verb@{\tt @}\verb@", file);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 47.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Generating the Indices}
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write index of file names {\footnotesize 50}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (file_names) {@\\
+\verb@ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);@\\
+\verb@ format_entry(file_names, tex_file, TRUE);@\\
+\verb@ fputs("\\end{list}", tex_file);@\\
+\verb@ }@\\
+\verb@ c = source_get();@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 35.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write index of macro names {\footnotesize 51}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (macro_names) {@\\
+\verb@ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);@\\
+\verb@ format_entry(macro_names, tex_file, FALSE);@\\
+\verb@ fputs("\\end{list}", tex_file);@\\
+\verb@ }@\\
+\verb@ c = source_get();@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 35.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"latex.c"@ {\footnotesize 52 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static void format_entry(name, tex_file, file_flag)@\\
+\verb@ Name *name;@\\
+\verb@ FILE *tex_file;@\\
+\verb@ int file_flag;@\\
+\verb@{@\\
+\verb@ while (name) {@\\
+\verb@ format_entry(name->llink, tex_file, file_flag);@\\
+\verb@ @$\langle$Format an index entry {\footnotesize 53}$\rangle$\verb@@\\
+\verb@ name = name->rlink;@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 6, 32, 33, 44, 45, 52 and~58.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Format an index entry {\footnotesize 53}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ fputs("\\item \\hspace{-\\leftmargin}", tex_file);@\\
+\verb@ if (file_flag) {@\\
+\verb@ fprintf(tex_file, "\\verb@{\tt @}\verb@\"%s\"@{\tt @}\verb@ ", name->spelling);@\\
+\verb@ @$\langle$Write file's defining scrap numbers {\footnotesize 54}$\rangle$\verb@@\\
+\verb@ }@\\
+\verb@ else {@\\
+\verb@ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);@\\
+\verb@ @$\langle$Write defining scrap numbers {\footnotesize 55}$\rangle$\verb@@\\
+\verb@ fputs("}$\\rangle$ ", tex_file);@\\
+\verb@ @$\langle$Write referencing scrap numbers {\footnotesize 56}$\rangle$\verb@@\\
+\verb@ }@\\
+\verb@ putc('\n', tex_file);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 52.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write file's defining scrap numbers {\footnotesize 54}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Scrap_Node *p = name->defs;@\\
+\verb@ fputs("{\\footnotesize Defined by scrap", tex_file);@\\
+\verb@ if (p->next) {@\\
+\verb@ fputs("s ", tex_file);@\\
+\verb@ print_scrap_numbers(tex_file, p);@\\
+\verb@ }@\\
+\verb@ else@\\
+\verb@ fprintf(tex_file, " %d.", p->scrap);@\\
+\verb@ putc('}', tex_file);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 53.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write defining scrap numbers {\footnotesize 55}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Scrap_Node *p = name->defs;@\\
+\verb@ if (p) {@\\
+\verb@ while (1) {@\\
+\verb@ fprintf(tex_file, "%d", p->scrap);@\\
+\verb@ p = p->next;@\\
+\verb@ if (!p) break;@\\
+\verb@ fputs(", ", tex_file);@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@ else@\\
+\verb@ putc('?', tex_file);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 53.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write referencing scrap numbers {\footnotesize 56}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Scrap_Node *p = name->uses;@\\
+\verb@ fputs("{\\footnotesize ", tex_file);@\\
+\verb@ if (p) {@\\
+\verb@ fputs("Referenced in scrap", tex_file);@\\
+\verb@ if (p->next) {@\\
+\verb@ fputs("s ", tex_file);@\\
+\verb@ print_scrap_numbers(tex_file, p);@\\
+\verb@ }@\\
+\verb@ else@\\
+\verb@ fprintf(tex_file, " %d.", p->scrap);@\\
+\verb@ }@\\
+\verb@ else@\\
+\verb@ fputs("Not referenced.", tex_file);@\\
+\verb@ putc('}', tex_file);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 53.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write index of user-specified names {\footnotesize 57}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (user_names) {@\\
+\verb@ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);@\\
+\verb@ format_user_entry(user_names, tex_file);@\\
+\verb@ fputs("\\end{list}", tex_file);@\\
+\verb@ }@\\
+\verb@ c = source_get();@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 35.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"latex.c"@ {\footnotesize 58 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static void format_user_entry(name, tex_file)@\\
+\verb@ Name *name;@\\
+\verb@ FILE *tex_file;@\\
+\verb@{@\\
+\verb@ while (name) {@\\
+\verb@ format_user_entry(name->llink, tex_file);@\\
+\verb@ @$\langle$Format a user index entry {\footnotesize 59}$\rangle$\verb@@\\
+\verb@ name = name->rlink;@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 6, 32, 33, 44, 45, 52 and~58.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Format a user index entry {\footnotesize 59}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Scrap_Node *uses = name->uses;@\\
+\verb@ Scrap_Node *defs = name->defs;@\\
+\verb@ fprintf(tex_file, "\\item \\hspace{-\\leftmargin}\\verb@{\tt @}\verb@%s@{\tt @}\verb@: ",@\\
+\verb@ name->spelling);@\\
+\verb@ do {@\\
+\verb@ if (uses && (!defs || uses->scrap < defs->scrap)) {@\\
+\verb@ fprintf(tex_file, "%d", uses->scrap);@\\
+\verb@ uses = uses->next;@\\
+\verb@ }@\\
+\verb@ else if (defs && (!uses || defs->scrap <= uses->scrap)) {@\\
+\verb@ if (uses && defs->scrap == uses->scrap)@\\
+\verb@ uses = uses->next;@\\
+\verb@ fprintf(tex_file, "\\underline{%d}", defs->scrap);@\\
+\verb@ defs = defs->next;@\\
+\verb@ }@\\
+\verb@ if (uses || defs) fputs(", ", tex_file);@\\
+\verb@ } while (uses || defs);@\\
+\verb@ fputs(".\n", tex_file);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 58.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Writing the Output Files} \label{output-files}
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Function prototypes {\footnotesize 60}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void write_files();@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 23, 31, 60, 64, 77, 103 and~130.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"output.c"@ {\footnotesize 61 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void write_files(files)@\\
+\verb@ Name *files;@\\
+\verb@{@\\
+\verb@ while (files) {@\\
+\verb@ write_files(files->llink);@\\
+\verb@ @$\langle$Write out {\tt files->spelling} {\footnotesize 62}$\rangle$\verb@@\\
+\verb@ files = files->rlink;@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 7 and~61.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Due to the filename restrictions on the PC, just use {\tt nuweb~~~.tmp} as
+the temporary filename. Since files are processed serially, this should
+cause any harm to unix platforms.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Write out {\tt files->spelling} {\footnotesize 62}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ FILE *temp_file;@\\
+\verb@ char temp_name[12]="nuweb~~~.tmp";@\\
+\verb@/* sprintf(temp_name, "%s~", files->spelling); */@\\
+\verb@ temp_file = fopen(temp_name, "w");@\\
+\verb@ if (temp_file) {@\\
+\verb@ char indent_chars[500];@\\
+\verb@ write_scraps(temp_file, files->defs, 0, indent_chars,@\\
+\verb@ files->debug_flag, files->tab_flag, files->indent_flag);@\\
+\verb@ fclose(temp_file);@\\
+\verb@ if (compare_flag)@\\
+\verb@ @$\langle$Compare the temp file and the old file {\footnotesize 63}$\rangle$\verb@@\\
+\verb@ else@\\
+\verb@ rename(temp_name, files->spelling);@\\
+\verb@ }@\\
+\verb@ else {@\\
+\verb@ fprintf(stderr, "%s: can't open %s\n", command_name, temp_name);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 61.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Compare the temp file and the old file {\footnotesize 63}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ FILE *old_file = fopen(files->spelling, "r");@\\
+\verb@ if (old_file) {@\\
+\verb@ int x, y;@\\
+\verb@ temp_file = fopen(temp_name, "r");@\\
+\verb@ do {@\\
+\verb@ x = getc(old_file);@\\
+\verb@ y = getc(temp_file);@\\
+\verb@ } while (x == y && x != EOF);@\\
+\verb@ fclose(old_file);@\\
+\verb@ fclose(temp_file);@\\
+\verb@ if (x == y)@\\
+\verb@ unlink(temp_name);@\\
+\verb@ else@\\
+\verb@ rename(temp_name, files->spelling);@\\
+\verb@ }@\\
+\verb@ else@\\
+\verb@ rename(temp_name, files->spelling);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 62.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\chapter{The Support Routines}
+
+\section{Source Files} \label{source-files}
+
+\subsection{Global Declarations}
+
+We need two routines to handle reading the source files.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Function prototypes {\footnotesize 64}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void source_open(); /* pass in the name of the source file */@\\
+\verb@int source_get(); /* no args; returns the next char or EOF */@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 23, 31, 60, 64, 77, 103 and~130.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+There are also two global variables maintained for use in error
+messages and such.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Global variables {\footnotesize 65}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@char *source_name; /* name of the current file */@\\
+\verb@int source_line; /* current line in the source file */@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 13, 15, 65 and~102.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Local Declarations}
+
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"input.c"@ {\footnotesize 66 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static FILE *source_file; /* the current input file */@\\
+\verb@static int source_peek;@\\
+\verb@static int double_at;@\\
+\verb@static int include_depth;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 8, 66, 67, 68 and~73.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"input.c"@ {\footnotesize 67 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@struct {@\\
+\verb@ FILE *file;@\\
+\verb@ char *name;@\\
+\verb@ int line;@\\
+\verb@} stack[10];@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 8, 66, 67, 68 and~73.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Reading a File}
+
+The routine {\tt source\_get} returns the next character from the
+current source file. It notices newlines and keeps the line counter
+{\tt source\_line} up to date. It also catches {\tt EOF} and watches
+for {\tt @} characters. All other characters are immediately returned.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"input.c"@ {\footnotesize 68 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@int source_get()@\\
+\verb@{@\\
+\verb@ int c = source_peek;@\\
+\verb@ switch (c) {@\\
+\verb@ case EOF: @$\langle$Handle {\tt EOF} {\footnotesize 72}$\rangle$\verb@@\\
+\verb@ return c;@\\
+\verb@ case '@{\tt @}\verb@': @$\langle$Handle an ``at'' character {\footnotesize 69}$\rangle$\verb@@\\
+\verb@ return c;@\\
+\verb@ case '\n': source_line++;@\\
+\verb@ default: source_peek = getc(source_file);@\\
+\verb@ return c;@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 8, 66, 67, 68 and~73.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+This whole {\tt @}~character handling mess is pretty annoying.
+I want to recognize {\tt @i} so I can handle include files correctly.
+At the same time, it makes sense to recognize illegal {\tt @}~sequences
+and complain; this avoids ever having to check anywhere else.
+Unfortunately, I need to avoid tripping over the {\tt @@}~sequence;
+hence this whole unsatisfactory {\tt double\_at} business.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Handle an ``at'' character {\footnotesize 69}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = getc(source_file);@\\
+\verb@ if (double_at) {@\\
+\verb@ source_peek = c;@\\
+\verb@ double_at = FALSE;@\\
+\verb@ c = '@{\tt @}\verb@';@\\
+\verb@ }@\\
+\verb@ else@\\
+\verb@ switch (c) {@\\
+\verb@ case 'i': @$\langle$Open an include file {\footnotesize 70}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case 'f': case 'm': case 'u':@\\
+\verb@ case 'd': case 'o': case 'D': case 'O':@\\
+\verb@ case '{': case '}': case '<': case '>': case '|':@\\
+\verb@ source_peek = c;@\\
+\verb@ c = '@{\tt @}\verb@';@\\
+\verb@ break;@\\
+\verb@ case '@{\tt @}\verb@': source_peek = c;@\\
+\verb@ double_at = TRUE;@\\
+\verb@ break;@\\
+\verb@ default: fprintf(stderr, "%s: bad @{\tt @}\verb@ sequence (%s, line %d)\n",@\\
+\verb@ command_name, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 68.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Open an include file {\footnotesize 70}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (include_depth < 10) {@\\
+\verb@ char name[100];@\\
+\verb@ @$\langle$Collect include-file name {\footnotesize 71}$\rangle$\verb@@\\
+\verb@ stack[include_depth].name = source_name;@\\
+\verb@ stack[include_depth].file = source_file;@\\
+\verb@ stack[include_depth].line = source_line + 1;@\\
+\verb@ include_depth++;@\\
+\verb@ source_line = 1;@\\
+\verb@ source_name = save_string(name);@\\
+\verb@ source_file = fopen(source_name, "r");@\\
+\verb@ if (!source_file) {@\\
+\verb@ fprintf(stderr, "%s: can't open include file %s\n",@\\
+\verb@ command_name, source_name);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@ source_peek = getc(source_file);@\\
+\verb@ c = source_get();@\\
+\verb@ }@\\
+\verb@ else {@\\
+\verb@ fprintf(stderr, "%s: include nesting too deep (%s, %d)\n",@\\
+\verb@ command_name, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 69.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Collect include-file name {\footnotesize 71}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ char *p = name;@\\
+\verb@ do @\\
+\verb@ c = getc(source_file);@\\
+\verb@ while (c == ' ' || c == '\t');@\\
+\verb@ while (isgraph(c)) {@\\
+\verb@ *p++ = c;@\\
+\verb@ c = getc(source_file);@\\
+\verb@ }@\\
+\verb@ *p = '\0';@\\
+\verb@ if (c != '\n') {@\\
+\verb@ fprintf(stderr, "%s: unexpected characters after file name (%s, %d)\n",@\\
+\verb@ command_name, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 70.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+If an {\tt EOF} is discovered, the current file must be closed and
+input from the next stacked file must be resumed. If no more files are
+on the stack, the {\tt EOF} is returned.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Handle {\tt EOF} {\footnotesize 72}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ fclose(source_file);@\\
+\verb@ if (include_depth) {@\\
+\verb@ include_depth--;@\\
+\verb@ source_file = stack[include_depth].file;@\\
+\verb@ source_line = stack[include_depth].line;@\\
+\verb@ source_name = stack[include_depth].name;@\\
+\verb@ source_peek = getc(source_file);@\\
+\verb@ c = source_get();@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 68.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Opening a File}
+
+The routine {\tt source\_open} takes a file name and tries to open the
+file. If unsuccessful, it complains and halts. Otherwise, it sets
+{\tt source\_name}, {\tt source\_line}, and {\tt double\_at}.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"input.c"@ {\footnotesize 73 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void source_open(name)@\\
+\verb@ char *name;@\\
+\verb@{@\\
+\verb@ source_file = fopen(name, "r");@\\
+\verb@ if (!source_file) {@\\
+\verb@ fprintf(stderr, "%s: couldn't open %s\n", command_name, name);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@ source_name = name;@\\
+\verb@ source_line = 1;@\\
+\verb@ source_peek = getc(source_file);@\\
+\verb@ double_at = FALSE;@\\
+\verb@ include_depth = 0;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 8, 66, 67, 68 and~73.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Scraps} \label{scraps}
+
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 74 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@#define SLAB_SIZE 500@\\
+\verb@@\\
+\verb@typedef struct slab {@\\
+\verb@ struct slab *next;@\\
+\verb@ char chars[SLAB_SIZE];@\\
+\verb@} Slab;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 75 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@typedef struct {@\\
+\verb@ char *file_name;@\\
+\verb@ int file_line;@\\
+\verb@ Slab *slab;@\\
+\verb@} ScrapEntry;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 76 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@ScrapEntry *SCRAP[256];@\\
+\verb@@\\
+\verb@#define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]@\\
+\verb@@\\
+\verb@int scraps;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Function prototypes {\footnotesize 77}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void init_scraps();@\\
+\verb@int collect_scrap();@\\
+\verb@int write_scraps();@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 23, 31, 60, 64, 77, 103 and~130.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 78 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void init_scraps()@\\
+\verb@{@\\
+\verb@ scraps = 1;@\\
+\verb@ SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 79 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@typedef struct {@\\
+\verb@ Slab *scrap;@\\
+\verb@ int index;@\\
+\verb@} Manager;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 80 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static void push(c, manager)@\\
+\verb@ char c;@\\
+\verb@ Manager *manager;@\\
+\verb@{@\\
+\verb@ Slab *scrap = manager->scrap;@\\
+\verb@ int index = manager->index;@\\
+\verb@ scrap->chars[index++] = c;@\\
+\verb@ if (index == SLAB_SIZE) {@\\
+\verb@ Slab *new = (Slab *) arena_getmem(sizeof(Slab));@\\
+\verb@ scrap->next = new;@\\
+\verb@ manager->scrap = new;@\\
+\verb@ index = 0;@\\
+\verb@ }@\\
+\verb@ manager->index = index;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 81 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static void pushs(s, manager)@\\
+\verb@ char *s;@\\
+\verb@ Manager *manager;@\\
+\verb@{@\\
+\verb@ while (*s)@\\
+\verb@ push(*s++, manager);@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 82 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@int collect_scrap()@\\
+\verb@{@\\
+\verb@ Manager writer;@\\
+\verb@ @$\langle$Create new scrap, managed by {\tt writer} {\footnotesize 83}$\rangle$\verb@@\\
+\verb@ @$\langle$Accumulate scrap and return {\tt scraps++} {\footnotesize 84}$\rangle$\verb@@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Create new scrap, managed by {\tt writer} {\footnotesize 83}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));@\\
+\verb@ if ((scraps & 255) == 0)@\\
+\verb@ SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));@\\
+\verb@ scrap_array(scraps).slab = scrap;@\\
+\verb@ scrap_array(scraps).file_name = save_string(source_name);@\\
+\verb@ scrap_array(scraps).file_line = source_line;@\\
+\verb@ writer.scrap = scrap;@\\
+\verb@ writer.index = 0;@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 82.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Accumulate scrap and return {\tt scraps++} {\footnotesize 84}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ int c = source_get();@\\
+\verb@ while (1) {@\\
+\verb@ switch (c) {@\\
+\verb@ case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",@\\
+\verb@ command_name, scrap_array(scraps).file_name,@\\
+\verb@ scrap_array(scraps).file_line);@\\
+\verb@ exit(-1);@\\
+\verb@ case '@{\tt @}\verb@': @$\langle$Handle at-sign during scrap accumulation {\footnotesize 85}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ default: push(c, &writer);@\\
+\verb@ c = source_get();@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 82.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Handle at-sign during scrap accumulation {\footnotesize 85}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = source_get();@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': pushs("@{\tt @}\verb@@{\tt @}\verb@", &writer);@\\
+\verb@ c = source_get();@\\
+\verb@ break;@\\
+\verb@ case '|': @$\langle$Collect user-specified index entries {\footnotesize 86}$\rangle$\verb@@\\
+\verb@ case '}': push('\0', &writer);@\\
+\verb@ return scraps++;@\\
+\verb@ case '<': @$\langle$Handle macro invocation in scrap {\footnotesize 87}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ default : fprintf(stderr, "%s: unexpected @{\tt @}\verb@%c in scrap (%s, %d)\n",@\\
+\verb@ command_name, c, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 84.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Collect user-specified index entries {\footnotesize 86}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ do {@\\
+\verb@ char new_name[100];@\\
+\verb@ char *p = new_name;@\\
+\verb@ do @\\
+\verb@ c = source_get();@\\
+\verb@ while (isspace(c));@\\
+\verb@ if (c != '@{\tt @}\verb@') {@\\
+\verb@ Name *name;@\\
+\verb@ do {@\\
+\verb@ *p++ = c;@\\
+\verb@ c = source_get();@\\
+\verb@ } while (c != '@{\tt @}\verb@' && !isspace(c));@\\
+\verb@ *p = '\0';@\\
+\verb@ name = name_add(&user_names, new_name);@\\
+\verb@ if (!name->defs || name->defs->scrap != scraps) {@\\
+\verb@ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));@\\
+\verb@ def->scrap = scraps;@\\
+\verb@ def->next = name->defs;@\\
+\verb@ name->defs = def;@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@ } while (c != '@{\tt @}\verb@');@\\
+\verb@ c = source_get();@\\
+\verb@ if (c != '}') {@\\
+\verb@ fprintf(stderr, "%s: unexpected @{\tt @}\verb@%c in scrap (%s, %d)\n",@\\
+\verb@ command_name, c, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 85.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Handle macro invocation in scrap {\footnotesize 87}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Name *name = collect_scrap_name();@\\
+\verb@ @$\langle$Save macro name {\footnotesize 88}$\rangle$\verb@@\\
+\verb@ @$\langle$Add current scrap to {\tt name}'s uses {\footnotesize 89}$\rangle$\verb@@\\
+\verb@ c = source_get();@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 85.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Save macro name {\footnotesize 88}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ char *s = name->spelling;@\\
+\verb@ int len = strlen(s) - 1;@\\
+\verb@ pushs("@{\tt @}\verb@<", &writer);@\\
+\verb@ while (len > 0) {@\\
+\verb@ push(*s++, &writer);@\\
+\verb@ len--;@\\
+\verb@ }@\\
+\verb@ if (*s == ' ')@\\
+\verb@ pushs("...", &writer);@\\
+\verb@ else@\\
+\verb@ push(*s, &writer);@\\
+\verb@ pushs("@{\tt @}\verb@>", &writer);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 87.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Add current scrap to {\tt name}'s uses {\footnotesize 89}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (!name->uses || name->uses->scrap != scraps) {@\\
+\verb@ Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));@\\
+\verb@ use->scrap = scraps;@\\
+\verb@ use->next = name->uses;@\\
+\verb@ name->uses = use;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 87.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 90 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static char pop(manager)@\\
+\verb@ Manager *manager;@\\
+\verb@{@\\
+\verb@ Slab *scrap = manager->scrap;@\\
+\verb@ int index = manager->index;@\\
+\verb@ char c = scrap->chars[index++];@\\
+\verb@ if (index == SLAB_SIZE) {@\\
+\verb@ manager->scrap = scrap->next;@\\
+\verb@ index = 0;@\\
+\verb@ }@\\
+\verb@ manager->index = index;@\\
+\verb@ return c;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 91 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static Name *pop_scrap_name(manager)@\\
+\verb@ Manager *manager;@\\
+\verb@{@\\
+\verb@ char name[100];@\\
+\verb@ char *p = name;@\\
+\verb@ int c = pop(manager);@\\
+\verb@ while (TRUE) {@\\
+\verb@ if (c == '@{\tt @}\verb@')@\\
+\verb@ @$\langle$Check for end of scrap name and return {\footnotesize 92}$\rangle$\verb@@\\
+\verb@ else {@\\
+\verb@ *p++ = c;@\\
+\verb@ c = pop(manager);@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Check for end of scrap name and return {\footnotesize 92}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = pop(manager);@\\
+\verb@ if (c == '@{\tt @}\verb@') {@\\
+\verb@ *p++ = c;@\\
+\verb@ c = pop(manager);@\\
+\verb@ }@\\
+\verb@ else if (c == '>') {@\\
+\verb@ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {@\\
+\verb@ p[-3] = ' ';@\\
+\verb@ p -= 2;@\\
+\verb@ }@\\
+\verb@ *p = '\0';@\\
+\verb@ return prefix_add(&macro_names, name);@\\
+\verb@ }@\\
+\verb@ else {@\\
+\verb@ fprintf(stderr, "%s: found an internal problem (1)\n", command_name);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 91.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 93 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@int write_scraps(file, defs, global_indent, indent_chars,@\\
+\verb@ debug_flag, tab_flag, indent_flag)@\\
+\verb@ FILE *file;@\\
+\verb@ Scrap_Node *defs;@\\
+\verb@ int global_indent;@\\
+\verb@ char *indent_chars;@\\
+\verb@ char debug_flag;@\\
+\verb@ char tab_flag;@\\
+\verb@ char indent_flag;@\\
+\verb@{@\\
+\verb@ int indent = 0;@\\
+\verb@ while (defs) {@\\
+\verb@ @$\langle$Copy {\tt defs->scrap} to {\tt file} {\footnotesize 94}$\rangle$\verb@@\\
+\verb@ defs = defs->next;@\\
+\verb@ }@\\
+\verb@ return indent + global_indent;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Copy {\tt defs->scrap} to {\tt file} {\footnotesize 94}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ char c;@\\
+\verb@ Manager reader;@\\
+\verb@ int line_number = scrap_array(defs->scrap).file_line;@\\
+\verb@ @$\langle$Insert debugging information if required {\footnotesize 95}$\rangle$\verb@@\\
+\verb@ reader.scrap = scrap_array(defs->scrap).slab;@\\
+\verb@ reader.index = 0;@\\
+\verb@ c = pop(&reader);@\\
+\verb@ while (c) {@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': @$\langle$Check for macro invocation in scrap {\footnotesize 98}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case '\n': putc(c, file);@\\
+\verb@ line_number++;@\\
+\verb@ @$\langle$Insert appropriate indentation {\footnotesize 96}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case '\t': @$\langle$Handle tab characters on output {\footnotesize 97}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ default: putc(c, file);@\\
+\verb@ indent_chars[global_indent + indent] = ' ';@\\
+\verb@ indent++;@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@ c = pop(&reader);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 93.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Insert debugging information if required {\footnotesize 95}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@if (debug_flag) {@\\
+\verb@ fprintf(file, "\n#line %d \"%s\"\n",@\\
+\verb@ line_number, scrap_array(defs->scrap).file_name);@\\
+\verb@ @$\langle$Insert appropriate indentation {\footnotesize 96}$\rangle$\verb@@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 94 and~98.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Insert appropriate indentation {\footnotesize 96}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (indent_flag) {@\\
+\verb@ if (tab_flag)@\\
+\verb@ for (indent=0; indent<global_indent; indent++)@\\
+\verb@ putc(' ', file);@\\
+\verb@ else@\\
+\verb@ for (indent=0; indent<global_indent; indent++)@\\
+\verb@ putc(indent_chars[indent], file);@\\
+\verb@ }@\\
+\verb@ indent = 0;@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 94 and~95.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Handle tab characters on output {\footnotesize 97}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (tab_flag)@\\
+\verb@ @$\langle$Expand tab into spaces {\footnotesize 46}$\rangle$\verb@@\\
+\verb@ else {@\\
+\verb@ putc('\t', file);@\\
+\verb@ indent_chars[global_indent + indent] = '\t';@\\
+\verb@ indent++;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 94.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Check for macro invocation in scrap {\footnotesize 98}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = pop(&reader);@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': putc(c, file);@\\
+\verb@ indent_chars[global_indent + indent] = ' ';@\\
+\verb@ indent++;@\\
+\verb@ break;@\\
+\verb@ case '<': @$\langle$Copy macro into {\tt file} {\footnotesize 99}$\rangle$\verb@@\\
+\verb@ @$\langle$Insert debugging information if required {\footnotesize 95}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ default: /* ignore, since we should already have a warning */@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 94.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Copy macro into {\tt file} {\footnotesize 99}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Name *name = pop_scrap_name(&reader);@\\
+\verb@ if (name->mark) {@\\
+\verb@ fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",@\\
+\verb@ command_name, name->spelling);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@ if (name->defs) {@\\
+\verb@ name->mark = TRUE;@\\
+\verb@ indent = write_scraps(file, name->defs, global_indent + indent,@\\
+\verb@ indent_chars, debug_flag, tab_flag, indent_flag);@\\
+\verb@ indent -= global_indent;@\\
+\verb@ name->mark = FALSE;@\\
+\verb@ }@\\
+\verb@ else if (!tex_flag)@\\
+\verb@ fprintf(stderr, "%s: macro never defined <%s>\n",@\\
+\verb@ command_name, name->spelling);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 98.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Names} \label{names}
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Type declarations {\footnotesize 100}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@typedef struct scrap_node {@\\
+\verb@ struct scrap_node *next;@\\
+\verb@ int scrap;@\\
+\verb@} Scrap_Node;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 3, 100 and~101.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Type declarations {\footnotesize 101}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@typedef struct name {@\\
+\verb@ char *spelling;@\\
+\verb@ struct name *llink;@\\
+\verb@ struct name *rlink;@\\
+\verb@ Scrap_Node *defs;@\\
+\verb@ Scrap_Node *uses;@\\
+\verb@ int mark;@\\
+\verb@ char tab_flag;@\\
+\verb@ char indent_flag;@\\
+\verb@ char debug_flag;@\\
+\verb@} Name;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 3, 100 and~101.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Global variables {\footnotesize 102}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@Name *file_names;@\\
+\verb@Name *macro_names;@\\
+\verb@Name *user_names;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 13, 15, 65 and~102.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Function prototypes {\footnotesize 103}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@Name *collect_file_name();@\\
+\verb@Name *collect_macro_name();@\\
+\verb@Name *collect_scrap_name();@\\
+\verb@Name *name_add();@\\
+\verb@Name *prefix_add();@\\
+\verb@char *save_string();@\\
+\verb@void reverse_lists();@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 23, 31, 60, 64, 77, 103 and~130.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 104 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@enum { LESS, GREATER, EQUAL, PREFIX, EXTENSION };@\\
+\verb@@\\
+\verb@static int compare(x, y)@\\
+\verb@ char *x;@\\
+\verb@ char *y;@\\
+\verb@{@\\
+\verb@ int len, result;@\\
+\verb@ int xl = strlen(x);@\\
+\verb@ int yl = strlen(y);@\\
+\verb@ int xp = x[xl - 1] == ' ';@\\
+\verb@ int yp = y[yl - 1] == ' ';@\\
+\verb@ if (xp) xl--;@\\
+\verb@ if (yp) yl--;@\\
+\verb@ len = xl < yl ? xl : yl;@\\
+\verb@ result = strncmp(x, y, len);@\\
+\verb@ if (result < 0) return GREATER;@\\
+\verb@ else if (result > 0) return LESS;@\\
+\verb@ else if (xl < yl) {@\\
+\verb@ if (xp) return EXTENSION;@\\
+\verb@ else return LESS;@\\
+\verb@ }@\\
+\verb@ else if (xl > yl) {@\\
+\verb@ if (yp) return PREFIX;@\\
+\verb@ else return GREATER;@\\
+\verb@ }@\\
+\verb@ else return EQUAL;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 105 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@char *save_string(s)@\\
+\verb@ char *s;@\\
+\verb@{@\\
+\verb@ char *new = (char *) arena_getmem((strlen(s) + 1) * sizeof(char));@\\
+\verb@ strcpy(new, s);@\\
+\verb@ return new;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 106 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@Name *prefix_add(root, spelling)@\\
+\verb@ Name **root;@\\
+\verb@ char *spelling;@\\
+\verb@{@\\
+\verb@ Name *node = *root;@\\
+\verb@ while (node) {@\\
+\verb@ switch (compare(node->spelling, spelling)) {@\\
+\verb@ case GREATER: root = &node->rlink;@\\
+\verb@ break;@\\
+\verb@ case LESS: root = &node->llink;@\\
+\verb@ break;@\\
+\verb@ case EQUAL: return node;@\\
+\verb@ case EXTENSION: node->spelling = save_string(spelling);@\\
+\verb@ return node;@\\
+\verb@ case PREFIX: @$\langle$Check for ambiguous prefix {\footnotesize 107}$\rangle$\verb@@\\
+\verb@ return node;@\\
+\verb@ }@\\
+\verb@ node = *root;@\\
+\verb@ }@\\
+\verb@ @$\langle$Create new name entry {\footnotesize 111}$\rangle$\verb@@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Since a very short prefix might match more than one macro name, I need
+to check for other matches to avoid mistakes. Basically, I simply
+continue the search down {\em both\/} branches of the tree.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Check for ambiguous prefix {\footnotesize 107}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (ambiguous_prefix(node->llink, spelling) ||@\\
+\verb@ ambiguous_prefix(node->rlink, spelling))@\\
+\verb@ fprintf(stderr,@\\
+\verb@ "%s: ambiguous prefix @{\tt @}\verb@<%s...@{\tt @}\verb@> (%s, line %d)\n",@\\
+\verb@ command_name, spelling, source_name, source_line);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 106.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 108 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static int ambiguous_prefix(node, spelling)@\\
+\verb@ Name *node;@\\
+\verb@ char *spelling;@\\
+\verb@{@\\
+\verb@ while (node) {@\\
+\verb@ switch (compare(node->spelling, spelling)) {@\\
+\verb@ case GREATER: node = node->rlink;@\\
+\verb@ break;@\\
+\verb@ case LESS: node = node->llink;@\\
+\verb@ break;@\\
+\verb@ case EQUAL:@\\
+\verb@ case EXTENSION:@\\
+\verb@ case PREFIX: return TRUE;@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@ return FALSE;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Rob Shillingsburg suggested that I organize the index of
+user-specified identifiers more traditionally; that is, not relying on
+strict {\small ASCII} comparisons via {\tt strcmp}. Ideally, we'd like
+to see the index ordered like this:
+\begin{quote}
+\begin{flushleft}
+aardvark \\
+Adam \\
+atom \\
+Atomic \\
+atoms
+\end{flushleft}
+\end{quote}
+The function {\tt robs\_strcmp} implements the desired predicate.
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 109 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static int robs_strcmp(x, y)@\\
+\verb@ char *x;@\\
+\verb@ char *y;@\\
+\verb@{@\\
+\verb@ char *xx = x;@\\
+\verb@ char *yy = y;@\\
+\verb@ int xc = toupper(*xx);@\\
+\verb@ int yc = toupper(*yy);@\\
+\verb@ while (xc == yc && xc) {@\\
+\verb@ xx++;@\\
+\verb@ yy++;@\\
+\verb@ xc = toupper(*xx);@\\
+\verb@ yc = toupper(*yy);@\\
+\verb@ }@\\
+\verb@ if (xc != yc) return xc - yc;@\\
+\verb@ xc = *x;@\\
+\verb@ yc = *y;@\\
+\verb@ while (xc == yc && xc) {@\\
+\verb@ x++;@\\
+\verb@ y++;@\\
+\verb@ xc = *x;@\\
+\verb@ yc = *y;@\\
+\verb@ }@\\
+\verb@ if (isupper(xc) && islower(yc))@\\
+\verb@ return xc * 2 - (toupper(yc) * 2 + 1);@\\
+\verb@ if (islower(xc) && isupper(yc))@\\
+\verb@ return toupper(xc) * 2 + 1 - yc * 2;@\\
+\verb@ return xc - yc;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 110 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@Name *name_add(root, spelling)@\\
+\verb@ Name **root;@\\
+\verb@ char *spelling;@\\
+\verb@{@\\
+\verb@ Name *node = *root;@\\
+\verb@ while (node) {@\\
+\verb@ int result = robs_strcmp(node->spelling, spelling);@\\
+\verb@ if (result > 0)@\\
+\verb@ root = &node->llink;@\\
+\verb@ else if (result < 0)@\\
+\verb@ root = &node->rlink;@\\
+\verb@ else@\\
+\verb@ return node;@\\
+\verb@ node = *root;@\\
+\verb@ }@\\
+\verb@ @$\langle$Create new name entry {\footnotesize 111}$\rangle$\verb@@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Create new name entry {\footnotesize 111}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ node = (Name *) arena_getmem(sizeof(Name));@\\
+\verb@ node->spelling = save_string(spelling);@\\
+\verb@ node->mark = FALSE;@\\
+\verb@ node->llink = NULL;@\\
+\verb@ node->rlink = NULL;@\\
+\verb@ node->uses = NULL;@\\
+\verb@ node->defs = NULL;@\\
+\verb@ node->tab_flag = TRUE;@\\
+\verb@ node->indent_flag = TRUE;@\\
+\verb@ node->debug_flag = FALSE;@\\
+\verb@ *root = node;@\\
+\verb@ return node;@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 106 and~110.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Name terminated by whitespace. Also check for ``per-file'' flags. Keep
+skipping white space until we reach scrap.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 112 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@Name *collect_file_name()@\\
+\verb@{@\\
+\verb@ Name *new_name;@\\
+\verb@ char name[100];@\\
+\verb@ char *p = name;@\\
+\verb@ int start_line = source_line;@\\
+\verb@ int c = source_get();@\\
+\verb@ while (isspace(c))@\\
+\verb@ c = source_get();@\\
+\verb@ while (isgraph(c)) {@\\
+\verb@ *p++ = c;@\\
+\verb@ c = source_get();@\\
+\verb@ }@\\
+\verb@ if (p == name) {@\\
+\verb@ fprintf(stderr, "%s: expected file name (%s, %d)\n",@\\
+\verb@ command_name, source_name, start_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@ *p = '\0';@\\
+\verb@ new_name = name_add(&file_names, name);@\\
+\verb@ @$\langle$Handle optional per-file flags {\footnotesize 113}$\rangle$\verb@@\\
+\verb@ if (c == '@{\tt @}\verb@' && source_get() == '{')@\\
+\verb@ return new_name;@\\
+\verb@ else {@\\
+\verb@ fprintf(stderr, "%s: expected @{\tt @}\verb@{ after file name (%s, %d)\n",@\\
+\verb@ command_name, source_name, start_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Handle optional per-file flags {\footnotesize 113}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ while (1) {@\\
+\verb@ while (isspace(c))@\\
+\verb@ c = source_get();@\\
+\verb@ if (c == '-') {@\\
+\verb@ c = source_get();@\\
+\verb@ do {@\\
+\verb@ switch (c) {@\\
+\verb@ case 't': new_name->tab_flag = FALSE;@\\
+\verb@ break;@\\
+\verb@ case 'd': new_name->debug_flag = TRUE;@\\
+\verb@ break;@\\
+\verb@ case 'i': new_name->indent_flag = FALSE;@\\
+\verb@ break;@\\
+\verb@ default : fprintf(stderr, "%s: unexpected per-file flag (%s, %d)\n",@\\
+\verb@ command_name, source_name, source_line);@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@ c = source_get();@\\
+\verb@ } while (!isspace(c));@\\
+\verb@ }@\\
+\verb@ else break;@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 112.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Name terminated by \verb+\n+ or \verb+@{+; but keep skipping until \verb+@{+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 114 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@Name *collect_macro_name()@\\
+\verb@{@\\
+\verb@ char name[100];@\\
+\verb@ char *p = name;@\\
+\verb@ int start_line = source_line;@\\
+\verb@ int c = source_get();@\\
+\verb@ while (isspace(c))@\\
+\verb@ c = source_get();@\\
+\verb@ while (c != EOF) {@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': @$\langle$Check for terminating at-sequence and return name {\footnotesize 115}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case '\t':@\\
+\verb@ case ' ': *p++ = ' ';@\\
+\verb@ do@\\
+\verb@ c = source_get();@\\
+\verb@ while (c == ' ' || c == '\t');@\\
+\verb@ break;@\\
+\verb@ case '\n': @$\langle$Skip until scrap begins, then return name {\footnotesize 117}$\rangle$\verb@@\\
+\verb@ default: *p++ = c;@\\
+\verb@ c = source_get();@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@ fprintf(stderr, "%s: expected macro name (%s, %d)\n",@\\
+\verb@ command_name, source_name, start_line);@\\
+\verb@ exit(-1);@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Check for terminating at-sequence and return name {\footnotesize 115}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = source_get();@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': *p++ = c;@\\
+\verb@ break;@\\
+\verb@ case '{': @$\langle$Cleanup and install name {\footnotesize 116}$\rangle$\verb@@\\
+\verb@ default: fprintf(stderr,@\\
+\verb@ "%s: unexpected @{\tt @}\verb@%c in macro name (%s, %d)\n",@\\
+\verb@ command_name, c, source_name, start_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 114.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Cleanup and install name {\footnotesize 116}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ if (p > name && p[-1] == ' ')@\\
+\verb@ p--;@\\
+\verb@ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {@\\
+\verb@ p[-3] = ' ';@\\
+\verb@ p -= 2;@\\
+\verb@ }@\\
+\verb@ if (p == name || name[0] == ' ') {@\\
+\verb@ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",@\\
+\verb@ command_name, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@ *p = '\0';@\\
+\verb@ return prefix_add(&macro_names, name);@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scraps 115, 117 and~119.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Skip until scrap begins, then return name {\footnotesize 117}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ do@\\
+\verb@ c = source_get();@\\
+\verb@ while (isspace(c));@\\
+\verb@ if (c == '@{\tt @}\verb@' && source_get() == '{')@\\
+\verb@ @$\langle$Cleanup and install name {\footnotesize 116}$\rangle$\verb@@\\
+\verb@ else {@\\
+\verb@ fprintf(stderr, "%s: expected @{\tt @}\verb@{ after macro name (%s, %d)\n",@\\
+\verb@ command_name, source_name, start_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 114.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Terminated by \verb+@>+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 118 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@Name *collect_scrap_name()@\\
+\verb@{@\\
+\verb@ char name[100];@\\
+\verb@ char *p = name;@\\
+\verb@ int c = source_get();@\\
+\verb@ while (c == ' ' || c == '\t')@\\
+\verb@ c = source_get();@\\
+\verb@ while (c != EOF) {@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': @$\langle$Look for end of scrap name and return {\footnotesize 119}$\rangle$\verb@@\\
+\verb@ break;@\\
+\verb@ case '\t':@\\
+\verb@ case ' ': *p++ = ' ';@\\
+\verb@ do@\\
+\verb@ c = source_get();@\\
+\verb@ while (c == ' ' || c == '\t');@\\
+\verb@ break;@\\
+\verb@ default: if (isgraph(c)) {@\\
+\verb@ *p++ = c;@\\
+\verb@ c = source_get();@\\
+\verb@ }@\\
+\verb@ else {@\\
+\verb@ fprintf(stderr,@\\
+\verb@ "%s: unexpected character in macro name (%s, %d)\n",@\\
+\verb@ command_name, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@ break;@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@ fprintf(stderr, "%s: unexpected end of file (%s, %d)\n",@\\
+\verb@ command_name, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Look for end of scrap name and return {\footnotesize 119}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ c = source_get();@\\
+\verb@ switch (c) {@\\
+\verb@ case '@{\tt @}\verb@': *p++ = c;@\\
+\verb@ c = source_get();@\\
+\verb@ break;@\\
+\verb@ case '>': @$\langle$Cleanup and install name {\footnotesize 116}$\rangle$\verb@@\\
+\verb@ default: fprintf(stderr,@\\
+\verb@ "%s: unexpected @{\tt @}\verb@%c in macro name (%s, %d)\n",@\\
+\verb@ command_name, c, source_name, source_line);@\\
+\verb@ exit(-1);@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 118.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 120 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static Scrap_Node *reverse(); /* a forward declaration */@\\
+\verb@@\\
+\verb@void reverse_lists(names)@\\
+\verb@ Name *names;@\\
+\verb@{@\\
+\verb@ while (names) {@\\
+\verb@ reverse_lists(names->llink);@\\
+\verb@ names->defs = reverse(names->defs);@\\
+\verb@ names->uses = reverse(names->uses);@\\
+\verb@ names = names->rlink;@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Just for fun, here's a non-recursive version of the traditional list
+reversal code. Note that it reverses the list in place; that is, it
+does no new allocations.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"names.c"@ {\footnotesize 121 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static Scrap_Node *reverse(a)@\\
+\verb@ Scrap_Node *a;@\\
+\verb@{@\\
+\verb@ if (a) {@\\
+\verb@ Scrap_Node *b = a->next;@\\
+\verb@ a->next = NULL;@\\
+\verb@ while (b) {@\\
+\verb@ Scrap_Node *c = b->next;@\\
+\verb@ b->next = a;@\\
+\verb@ a = b;@\\
+\verb@ b = c;@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@ return a;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Searching for Index Entries} \label{search}
+
+Given the array of scraps and a set of index entries, we need to
+search all the scraps for occurences of each entry. The obvious
+approach to this problem would be quite expensive for large documents;
+however, there is an interesting paper describing an efficient
+solution~\cite{aho:75}.
+
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 122 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@\\
+\verb@typedef struct name_node {@\\
+\verb@ struct name_node *next;@\\
+\verb@ Name *name;@\\
+\verb@} Name_Node;@\\
+\verb@@\\
+\verb@typedef struct goto_node {@\\
+\verb@ struct goto_node *next; /* next goto node with same depth */@\\
+\verb@ struct goto_node *fail;@\\
+\verb@ struct move_node *moves;@\\
+\verb@ Name_Node *output;@\\
+\verb@} Goto_Node;@\\
+\verb@@\\
+\verb@typedef struct move_node {@\\
+\verb@ struct move_node *next;@\\
+\verb@ Goto_Node *state;@\\
+\verb@ char c;@\\
+\verb@} Move_Node;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 123 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@\\
+\verb@static Goto_Node *root[128];@\\
+\verb@static int max_depth;@\\
+\verb@static Goto_Node **depths;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 124 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static Goto_Node *goto_lookup(c, g)@\\
+\verb@ char c;@\\
+\verb@ Goto_Node *g;@\\
+\verb@{@\\
+\verb@ Move_Node *m = g->moves;@\\
+\verb@ while (m && m->c != c)@\\
+\verb@ m = m->next;@\\
+\verb@ if (m)@\\
+\verb@ return m->state;@\\
+\verb@ else@\\
+\verb@ return NULL;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Building the Automata}
+
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 125 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@\\
+\verb@static void build_gotos();@\\
+\verb@@\\
+\verb@void search()@\\
+\verb@{@\\
+\verb@ int i;@\\
+\verb@ for (i=0; i<128; i++)@\\
+\verb@ root[i] = NULL;@\\
+\verb@ max_depth = 10;@\\
+\verb@ depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));@\\
+\verb@ for (i=0; i<max_depth; i++)@\\
+\verb@ depths[i] = NULL;@\\
+\verb@ build_gotos(user_names);@\\
+\verb@ @$\langle$Build failure functions {\footnotesize 128}$\rangle$\verb@@\\
+\verb@ @$\langle$Search scraps {\footnotesize 129}$\rangle$\verb@@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"scraps.c"@ {\footnotesize 126 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@static void build_gotos(tree)@\\
+\verb@ Name *tree;@\\
+\verb@{@\\
+\verb@ while (tree) {@\\
+\verb@ @$\langle$Extend goto graph with {\tt tree->spelling} {\footnotesize 127}$\rangle$\verb@@\\
+\verb@ build_gotos(tree->rlink);@\\
+\verb@ tree = tree->llink;@\\
+\verb@ }@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Extend goto graph with {\tt tree->spelling} {\footnotesize 127}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ int depth = 2;@\\
+\verb@ char *p = tree->spelling;@\\
+\verb@ char c = *p++;@\\
+\verb@ Goto_Node *q = root[c];@\\
+\verb@ if (!q) {@\\
+\verb@ q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));@\\
+\verb@ root[c] = q;@\\
+\verb@ q->moves = NULL;@\\
+\verb@ q->fail = NULL;@\\
+\verb@ q->moves = NULL;@\\
+\verb@ q->output = NULL;@\\
+\verb@ q->next = depths[1];@\\
+\verb@ depths[1] = q;@\\
+\verb@ }@\\
+\verb@ while (c = *p++) {@\\
+\verb@ Goto_Node *new = goto_lookup(c, q);@\\
+\verb@ if (!new) {@\\
+\verb@ Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));@\\
+\verb@ new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));@\\
+\verb@ new->moves = NULL;@\\
+\verb@ new->fail = NULL;@\\
+\verb@ new->moves = NULL;@\\
+\verb@ new->output = NULL;@\\
+\verb@ new_move->state = new;@\\
+\verb@ new_move->c = c;@\\
+\verb@ new_move->next = q->moves;@\\
+\verb@ q->moves = new_move;@\\
+\verb@ if (depth == max_depth) {@\\
+\verb@ int i;@\\
+\verb@ Goto_Node **new_depths =@\\
+\verb@ (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));@\\
+\verb@ max_depth = 2 * depth;@\\
+\verb@ for (i=0; i<depth; i++)@\\
+\verb@ new_depths[i] = depths[i];@\\
+\verb@ depths = new_depths;@\\
+\verb@ for (i=depth; i<max_depth; i++)@\\
+\verb@ depths[i] = NULL;@\\
+\verb@ }@\\
+\verb@ new->next = depths[depth];@\\
+\verb@ depths[depth] = new;@\\
+\verb@ }@\\
+\verb@ q = new;@\\
+\verb@ depth++;@\\
+\verb@ }@\\
+\verb@ q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));@\\
+\verb@ q->output->next = NULL;@\\
+\verb@ q->output->name = tree;@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 126.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Build failure functions {\footnotesize 128}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ int depth;@\\
+\verb@ for (depth=1; depth<max_depth; depth++) {@\\
+\verb@ Goto_Node *r = depths[depth];@\\
+\verb@ while (r) {@\\
+\verb@ Move_Node *m = r->moves;@\\
+\verb@ while (m) {@\\
+\verb@ char a = m->c;@\\
+\verb@ Goto_Node *s = m->state;@\\
+\verb@ Goto_Node *state = r->fail;@\\
+\verb@ while (state && !goto_lookup(a, state))@\\
+\verb@ state = state->fail;@\\
+\verb@ if (state)@\\
+\verb@ s->fail = goto_lookup(a, state);@\\
+\verb@ else@\\
+\verb@ s->fail = root[a];@\\
+\verb@ if (s->fail) {@\\
+\verb@ Name_Node *p = s->fail->output;@\\
+\verb@ while (p) {@\\
+\verb@ Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));@\\
+\verb@ q->name = p->name;@\\
+\verb@ q->next = s->output;@\\
+\verb@ s->output = q;@\\
+\verb@ p = p->next;@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@ m = m->next;@\\
+\verb@ }@\\
+\verb@ r = r->next;@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 125.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Searching the Scraps}
+
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Search scraps {\footnotesize 129}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ for (i=1; i<scraps; i++) {@\\
+\verb@ char c;@\\
+\verb@ Manager reader;@\\
+\verb@ Goto_Node *state = NULL;@\\
+\verb@ reader.scrap = scrap_array(i).slab;@\\
+\verb@ reader.index = 0;@\\
+\verb@ c = pop(&reader);@\\
+\verb@ while (c) {@\\
+\verb@ while (state && !goto_lookup(c, state))@\\
+\verb@ state = state->fail;@\\
+\verb@ if (state)@\\
+\verb@ state = goto_lookup(c, state);@\\
+\verb@ else@\\
+\verb@ state = root[c];@\\
+\verb@ if (state && state->output) {@\\
+\verb@ Name_Node *p = state->output;@\\
+\verb@ do {@\\
+\verb@ Name *name = p->name;@\\
+\verb@ if (!name->uses || name->uses->scrap != i) {@\\
+\verb@ Scrap_Node *new_use =@\\
+\verb@ (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));@\\
+\verb@ new_use->scrap = i;@\\
+\verb@ new_use->next = name->uses;@\\
+\verb@ name->uses = new_use;@\\
+\verb@ }@\\
+\verb@ p = p->next;@\\
+\verb@ } while (p);@\\
+\verb@ }@\\
+\verb@ c = pop(&reader);@\\
+\verb@ }@\\
+\verb@ }@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 125.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Memory Management} \label{memory-management}
+
+I manage memory using a simple scheme inspired by Hanson's idea of
+{\em arenas\/}~\cite{hanson:90}.
+Basically, I allocate all the storage required when processing a
+source file (primarily for names and scraps) using calls to
+{\tt arena\_getmem(n)}, where {\tt n} specifies the number of bytes to
+be allocated. When the storage is no longer required, the entire arena
+is freed with a single call to {\tt arena\_free()}. Both operations
+are quite fast.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Function prototypes {\footnotesize 130}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void *arena_getmem();@\\
+\verb@void arena_free();@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro defined by scraps 23, 31, 60, 64, 77, 103 and~130.\\[-1ex]
+Macro referenced in scrap 1.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"arena.c"@ {\footnotesize 131 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@typedef struct chunk {@\\
+\verb@ struct chunk *next;@\\
+\verb@ char *limit;@\\
+\verb@ char *avail;@\\
+\verb@} Chunk;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 11, 131, 132, 133 and~136.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We define an empty chunk called {\tt first}. The variable {\tt arena} points
+at the current chunk of memory; it's initially pointed at {\tt first}.
+As soon as some storage is required, a ``real'' chunk of memory will
+be allocated and attached to {\tt first->next}; storage will be
+allocated from the new chunk (and later chunks if necessary).
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"arena.c"@ {\footnotesize 132 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@Chunk first = { NULL, NULL, NULL };@\\
+\verb@Chunk *arena = &first;@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 11, 131, 132, 133 and~136.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Allocating Memory}
+
+The routine {\tt arena\_getmem(n)} returns a pointer to (at least)
+{\tt n} bytes of memory. Note that {\tt n} is rounded up to ensure
+that returned pointers are always aligned.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"arena.c"@ {\footnotesize 133 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void *arena_getmem(n)@\\
+\verb@ int n;@\\
+\verb@{@\\
+\verb@ char *q;@\\
+\verb@ char *p = arena->avail;@\\
+\verb@ n = (n + 3) & ~3; /* ensuring alignment to 4 bytes */@\\
+\verb@ q = p + n;@\\
+\verb@ if (q <= arena->limit) {@\\
+\verb@ arena->avail = q;@\\
+\verb@ return p;@\\
+\verb@ }@\\
+\verb@ @$\langle$Find a new chunk of memory {\footnotesize 134}$\rangle$\verb@@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 11, 131, 132, 133 and~136.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+If the current chunk doesn't have adequate space (at least {\tt n}
+bytes) we examine the rest of the list of chunks (starting at
+{\tt arena->next}) looking for a chunk with adequate space. If {\tt n}
+is very large, we may not find it right away or we may not find a
+suitable chunk at all.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Find a new chunk of memory {\footnotesize 134}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ Chunk *ap = arena;@\\
+\verb@ Chunk *np = ap->next;@\\
+\verb@ while (np) {@\\
+\verb@ char *v = sizeof(Chunk) + (char *) np;@\\
+\verb@ if (v + n <= np->limit) {@\\
+\verb@ np->avail = v + n;@\\
+\verb@ arena = np;@\\
+\verb@ return v;@\\
+\verb@ }@\\
+\verb@ ap = np;@\\
+\verb@ np = ap->next;@\\
+\verb@ }@\\
+\verb@ @$\langle$Allocate a new chunk of memory {\footnotesize 135}$\rangle$\verb@@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 133.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+If there isn't a suitable chunk of memory on the free list, then we
+need to allocate a new one.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Allocate a new chunk of memory {\footnotesize 135}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@{@\\
+\verb@ int m = n + 10000;@\\
+\verb@ np = (Chunk *) malloc(m);@\\
+\verb@ np->limit = m + (char *) np;@\\
+\verb@ np->avail = n + sizeof(Chunk) + (char *) np;@\\
+\verb@ np->next = NULL;@\\
+\verb@ ap->next = np;@\\
+\verb@ arena = np;@\\
+\verb@ return sizeof(Chunk) + (char *) np;@\\
+\verb@}@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 134.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Freeing Memory}
+
+To free all the memory in the arena, we need only point {\tt arena}
+back to the first empty chunk.
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+\verb@"arena.c"@ {\footnotesize 136 }$\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@void arena_free()@\\
+\verb@{@\\
+\verb@ arena = &first;@\\
+\verb@}@\\
+\verb@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize File defined by scraps 11, 131, 132, 133 and~136.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\chapter{Indices} \label{indices}
+
+Three sets of indices can be created automatically: an index of file
+names, an index of macro names, and an index of user-specified
+identifiers. An index entry includes the name of the entry, where it
+was defined, and where it was referenced.
+
+
+
+\section{Files}
+
+
+\begin{list}{}{\setlength{\itemsep}{-\parsep}}
+\item \hspace{-\leftmargin}\verb@"arena.c"@ {\footnotesize Defined by scraps 11, 131, 132, 133 and~136.}
+\item \hspace{-\leftmargin}\verb@"input.c"@ {\footnotesize Defined by scraps 8, 66, 67, 68 and~73.}
+\item \hspace{-\leftmargin}\verb@"latex.c"@ {\footnotesize Defined by scraps 6, 32, 33, 44, 45, 52 and~58.}
+\item \hspace{-\leftmargin}\verb@"main.c"@ {\footnotesize Defined by scraps 4 and~12.}
+\item \hspace{-\leftmargin}\verb@"names.c"@ {\footnotesize Defined by scraps 10, 104, 105, 106, 108, 109, 110, 112, 114, 118, 120 and~121.}
+\item \hspace{-\leftmargin}\verb@"output.c"@ {\footnotesize Defined by scraps 7 and~61.}
+\item \hspace{-\leftmargin}\verb@"pass1.c"@ {\footnotesize Defined by scraps 5 and~24.}
+\item \hspace{-\leftmargin}\verb@"scraps.c"@ {\footnotesize Defined by scraps 9, 74, 75, 76, 78, 79, 80, 81, 82, 90, 91, 93, 122, 123, 124, 125 and~126.}
+\end{list}
+
+\section{Macros}
+
+
+\begin{list}{}{\setlength{\itemsep}{-\parsep}}
+\item \hspace{-\leftmargin}$\langle$Accumulate scrap and return {\tt scraps++} {\footnotesize 84}$\rangle$ {\footnotesize Referenced in scrap 82.}
+\item \hspace{-\leftmargin}$\langle$Add current scrap to {\tt name}'s uses {\footnotesize 89}$\rangle$ {\footnotesize Referenced in scrap 87.}
+\item \hspace{-\leftmargin}$\langle$Add {\tt scrap} to {\tt name}'s definition list {\footnotesize 29}$\rangle$ {\footnotesize Referenced in scraps 27 and~28.}
+\item \hspace{-\leftmargin}$\langle$Allocate a new chunk of memory {\footnotesize 135}$\rangle$ {\footnotesize Referenced in scrap 134.}
+\item \hspace{-\leftmargin}$\langle$Begin the scrap environment {\footnotesize 38}$\rangle$ {\footnotesize Referenced in scraps 36 and~37.}
+\item \hspace{-\leftmargin}$\langle$Build failure functions {\footnotesize 128}$\rangle$ {\footnotesize Referenced in scrap 125.}
+\item \hspace{-\leftmargin}$\langle$Build macro definition {\footnotesize 28}$\rangle$ {\footnotesize Referenced in scrap 26.}
+\item \hspace{-\leftmargin}$\langle$Build output file definition {\footnotesize 27}$\rangle$ {\footnotesize Referenced in scrap 26.}
+\item \hspace{-\leftmargin}$\langle$Build {\tt source\_name} and {\tt tex\_name} {\footnotesize 21}$\rangle$ {\footnotesize Referenced in scrap 20.}
+\item \hspace{-\leftmargin}$\langle$Check at-sequence for end-of-scrap {\footnotesize 47}$\rangle$ {\footnotesize Referenced in scrap 45.}
+\item \hspace{-\leftmargin}$\langle$Check for ambiguous prefix {\footnotesize 107}$\rangle$ {\footnotesize Referenced in scrap 106.}
+\item \hspace{-\leftmargin}$\langle$Check for end of scrap name and return {\footnotesize 92}$\rangle$ {\footnotesize Referenced in scrap 91.}
+\item \hspace{-\leftmargin}$\langle$Check for macro invocation in scrap {\footnotesize 98}$\rangle$ {\footnotesize Referenced in scrap 94.}
+\item \hspace{-\leftmargin}$\langle$Check for terminating at-sequence and return name {\footnotesize 115}$\rangle$ {\footnotesize Referenced in scrap 114.}
+\item \hspace{-\leftmargin}$\langle$Cleanup and install name {\footnotesize 116}$\rangle$ {\footnotesize Referenced in scraps 115, 117 and~119.}
+\item \hspace{-\leftmargin}$\langle$Collect include-file name {\footnotesize 71}$\rangle$ {\footnotesize Referenced in scrap 70.}
+\item \hspace{-\leftmargin}$\langle$Collect user-specified index entries {\footnotesize 86}$\rangle$ {\footnotesize Referenced in scrap 85.}
+\item \hspace{-\leftmargin}$\langle$Compare the temp file and the old file {\footnotesize 63}$\rangle$ {\footnotesize Referenced in scrap 62.}
+\item \hspace{-\leftmargin}$\langle$Copy macro into {\tt file} {\footnotesize 99}$\rangle$ {\footnotesize Referenced in scrap 98.}
+\item \hspace{-\leftmargin}$\langle$Copy {\tt defs->scrap} to {\tt file} {\footnotesize 94}$\rangle$ {\footnotesize Referenced in scrap 93.}
+\item \hspace{-\leftmargin}$\langle$Copy {\tt source\_file} into {\tt tex\_file} {\footnotesize 34}$\rangle$ {\footnotesize Referenced in scrap 33.}
+\item \hspace{-\leftmargin}$\langle$Create new name entry {\footnotesize 111}$\rangle$ {\footnotesize Referenced in scraps 106 and~110.}
+\item \hspace{-\leftmargin}$\langle$Create new scrap, managed by {\tt writer} {\footnotesize 83}$\rangle$ {\footnotesize Referenced in scrap 82.}
+\item \hspace{-\leftmargin}$\langle$Expand tab into spaces {\footnotesize 46}$\rangle$ {\footnotesize Referenced in scraps 45 and~97.}
+\item \hspace{-\leftmargin}$\langle$Extend goto graph with {\tt tree->spelling} {\footnotesize 127}$\rangle$ {\footnotesize Referenced in scrap 126.}
+\item \hspace{-\leftmargin}$\langle$Fill in the middle of the scrap environment {\footnotesize 39}$\rangle$ {\footnotesize Referenced in scraps 36 and~37.}
+\item \hspace{-\leftmargin}$\langle$Find a new chunk of memory {\footnotesize 134}$\rangle$ {\footnotesize Referenced in scrap 133.}
+\item \hspace{-\leftmargin}$\langle$Finish the scrap environment {\footnotesize 40}$\rangle$ {\footnotesize Referenced in scraps 36 and~37.}
+\item \hspace{-\leftmargin}$\langle$Format a user index entry {\footnotesize 59}$\rangle$ {\footnotesize Referenced in scrap 58.}
+\item \hspace{-\leftmargin}$\langle$Format an index entry {\footnotesize 53}$\rangle$ {\footnotesize Referenced in scrap 52.}
+\item \hspace{-\leftmargin}$\langle$Format macro name {\footnotesize 49}$\rangle$ {\footnotesize Referenced in scrap 47.}
+\item \hspace{-\leftmargin}$\langle$Function prototypes {\footnotesize 23, 31, 60, 64, 77, 103, 130}$\rangle$ {\footnotesize Referenced in scrap 1.}
+\item \hspace{-\leftmargin}$\langle$Global variables {\footnotesize 13, 15, 65, 102}$\rangle$ {\footnotesize Referenced in scrap 1.}
+\item \hspace{-\leftmargin}$\langle$Handle an ``at'' character {\footnotesize 69}$\rangle$ {\footnotesize Referenced in scrap 68.}
+\item \hspace{-\leftmargin}$\langle$Handle at-sign during scrap accumulation {\footnotesize 85}$\rangle$ {\footnotesize Referenced in scrap 84.}
+\item \hspace{-\leftmargin}$\langle$Handle macro invocation in scrap {\footnotesize 87}$\rangle$ {\footnotesize Referenced in scrap 85.}
+\item \hspace{-\leftmargin}$\langle$Handle optional per-file flags {\footnotesize 113}$\rangle$ {\footnotesize Referenced in scrap 112.}
+\item \hspace{-\leftmargin}$\langle$Handle tab characters on output {\footnotesize 97}$\rangle$ {\footnotesize Referenced in scrap 94.}
+\item \hspace{-\leftmargin}$\langle$Handle the file name in {\tt argv[arg]} {\footnotesize 20}$\rangle$ {\footnotesize Referenced in scrap 19.}
+\item \hspace{-\leftmargin}$\langle$Handle {\tt EOF} {\footnotesize 72}$\rangle$ {\footnotesize Referenced in scrap 68.}
+\item \hspace{-\leftmargin}$\langle$Include files {\footnotesize 2}$\rangle$ {\footnotesize Referenced in scraps 1 and~11.}
+\item \hspace{-\leftmargin}$\langle$Insert appropriate indentation {\footnotesize 96}$\rangle$ {\footnotesize Referenced in scraps 94 and~95.}
+\item \hspace{-\leftmargin}$\langle$Insert debugging information if required {\footnotesize 95}$\rangle$ {\footnotesize Referenced in scraps 94 and~98.}
+\item \hspace{-\leftmargin}$\langle$Interpret at-sequence {\footnotesize 35}$\rangle$ {\footnotesize Referenced in scrap 34.}
+\item \hspace{-\leftmargin}$\langle$Interpret command-line arguments {\footnotesize 14, 16, 17}$\rangle$ {\footnotesize Referenced in scrap 12.}
+\item \hspace{-\leftmargin}$\langle$Interpret the argument string {\tt s} {\footnotesize 18}$\rangle$ {\footnotesize Referenced in scrap 17.}
+\item \hspace{-\leftmargin}$\langle$Look for end of scrap name and return {\footnotesize 119}$\rangle$ {\footnotesize Referenced in scrap 118.}
+\item \hspace{-\leftmargin}$\langle$Open an include file {\footnotesize 70}$\rangle$ {\footnotesize Referenced in scrap 69.}
+\item \hspace{-\leftmargin}$\langle$Process a file {\footnotesize 22}$\rangle$ {\footnotesize Referenced in scrap 20.}
+\item \hspace{-\leftmargin}$\langle$Process the remaining arguments (file names) {\footnotesize 19}$\rangle$ {\footnotesize Referenced in scrap 12.}
+\item \hspace{-\leftmargin}$\langle$Reverse cross-reference lists {\footnotesize 30}$\rangle$ {\footnotesize Referenced in scrap 24.}
+\item \hspace{-\leftmargin}$\langle$Save macro name {\footnotesize 88}$\rangle$ {\footnotesize Referenced in scrap 87.}
+\item \hspace{-\leftmargin}$\langle$Scan at-sequence {\footnotesize 26}$\rangle$ {\footnotesize Referenced in scrap 25.}
+\item \hspace{-\leftmargin}$\langle$Scan the source file, looking for at-sequences {\footnotesize 25}$\rangle$ {\footnotesize Referenced in scrap 24.}
+\item \hspace{-\leftmargin}$\langle$Search scraps {\footnotesize 129}$\rangle$ {\footnotesize Referenced in scrap 125.}
+\item \hspace{-\leftmargin}$\langle$Shared declarations {\footnotesize 1}$\rangle$ {\footnotesize Referenced in scraps 4, 5, 6, 7, 8, 9 and~10.}
+\item \hspace{-\leftmargin}$\langle$Skip over index entries {\footnotesize 48}$\rangle$ {\footnotesize Referenced in scrap 47.}
+\item \hspace{-\leftmargin}$\langle$Skip until scrap begins, then return name {\footnotesize 117}$\rangle$ {\footnotesize Referenced in scrap 114.}
+\item \hspace{-\leftmargin}$\langle$Type declarations {\footnotesize 3, 100, 101}$\rangle$ {\footnotesize Referenced in scrap 1.}
+\item \hspace{-\leftmargin}$\langle$Write defining scrap numbers {\footnotesize 55}$\rangle$ {\footnotesize Referenced in scrap 53.}
+\item \hspace{-\leftmargin}$\langle$Write file defs {\footnotesize 41}$\rangle$ {\footnotesize Referenced in scrap 36.}
+\item \hspace{-\leftmargin}$\langle$Write file's defining scrap numbers {\footnotesize 54}$\rangle$ {\footnotesize Referenced in scrap 53.}
+\item \hspace{-\leftmargin}$\langle$Write index of file names {\footnotesize 50}$\rangle$ {\footnotesize Referenced in scrap 35.}
+\item \hspace{-\leftmargin}$\langle$Write index of macro names {\footnotesize 51}$\rangle$ {\footnotesize Referenced in scrap 35.}
+\item \hspace{-\leftmargin}$\langle$Write index of user-specified names {\footnotesize 57}$\rangle$ {\footnotesize Referenced in scrap 35.}
+\item \hspace{-\leftmargin}$\langle$Write macro definition {\footnotesize 37}$\rangle$ {\footnotesize Referenced in scrap 35.}
+\item \hspace{-\leftmargin}$\langle$Write macro defs {\footnotesize 42}$\rangle$ {\footnotesize Referenced in scrap 37.}
+\item \hspace{-\leftmargin}$\langle$Write macro refs {\footnotesize 43}$\rangle$ {\footnotesize Referenced in scrap 37.}
+\item \hspace{-\leftmargin}$\langle$Write out {\tt files->spelling} {\footnotesize 62}$\rangle$ {\footnotesize Referenced in scrap 61.}
+\item \hspace{-\leftmargin}$\langle$Write output file definition {\footnotesize 36}$\rangle$ {\footnotesize Referenced in scrap 35.}
+\item \hspace{-\leftmargin}$\langle$Write referencing scrap numbers {\footnotesize 56}$\rangle$ {\footnotesize Referenced in scrap 53.}
+\end{list}
+
+\section{Identifiers}
+
+Knuth prints his index of indentifiers in a two-column format.
+I could force this automatically by emitting the \verb|\twocolumn|
+command; but this has the side effect of forcing a new page.
+Therefore, it seems better to leave it this up to the user.
+
+
+\begin{list}{}{\setlength{\itemsep}{-\parsep}}
+\item \hspace{-\leftmargin}\verb@arena@: 22, 29, 78, 80, 83, 86, 89, 105, 111, 125, 127, 128, 129, 130, \underline{132}, 133, 134, 135, 136.
+\item \hspace{-\leftmargin}\verb@arena_free@: 22, 130, \underline{136}.
+\item \hspace{-\leftmargin}\verb@arena_getmem@: 29, 78, 80, 83, 86, 89, 105, 111, 125, 127, 128, 129, 130, \underline{133}.
+\item \hspace{-\leftmargin}\verb@build_gotos@: 125, \underline{126}.
+\item \hspace{-\leftmargin}\verb@Chunk@: \underline{131}, 132, 134, 135.
+\item \hspace{-\leftmargin}\verb@collect_file_name@: 27, 36, 103, \underline{112}.
+\item \hspace{-\leftmargin}\verb@collect_macro_name@: 28, 37, 103, \underline{114}.
+\item \hspace{-\leftmargin}\verb@collect_scrap@: 27, 28, 49, 77, \underline{82}, 87, 103, 118.
+\item \hspace{-\leftmargin}\verb@collect_scrap_name@: 49, 87, 103, \underline{118}.
+\item \hspace{-\leftmargin}\verb@command_name@: \underline{15}, 16, 18, 19, 26, 33, 43, 49, 62, 69, 70, 71, 73, 84, 85, 86, 92, 99, 107, 112, 113, 114, 115, 116, 117, 118, 119.
+\item \hspace{-\leftmargin}\verb@compare@: 13, 14, 18, 62, \underline{104}, 106, 108.
+\item \hspace{-\leftmargin}\verb@compare_flag@: \underline{13}, 14, 18, 62.
+\item \hspace{-\leftmargin}\verb@copy_scrap@: 32, 39, \underline{45}.
+\item \hspace{-\leftmargin}\verb@double_at@: \underline{66}, 69, 73.
+\item \hspace{-\leftmargin}\verb@EQUAL@: \underline{104}, 106, 108.
+\item \hspace{-\leftmargin}\verb@exit@: \underline{2}, 12, 19, 62, 69, 70, 71, 73, 84, 85, 86, 92, 99, 112, 114, 115, 116, 117, 118, 119.
+\item \hspace{-\leftmargin}\verb@EXTENSION@: \underline{104}, 106, 108.
+\item \hspace{-\leftmargin}\verb@FALSE@: \underline{3}, 13, 18, 35, 51, 69, 73, 99, 108, 111, 113.
+\item \hspace{-\leftmargin}\verb@fclose@: \underline{2}, 33, 62, 63, 72.
+\item \hspace{-\leftmargin}\verb@FILE@: \underline{2}, 33, 44, 45, 52, 58, 62, 63, 66, 67, 93.
+\item \hspace{-\leftmargin}\verb@file_names@: 22, 24, 30, 50, \underline{102}, 112.
+\item \hspace{-\leftmargin}\verb@first@: \underline{132}, 136.
+\item \hspace{-\leftmargin}\verb@fopen@: \underline{2}, 33, 62, 63, 70, 73.
+\item \hspace{-\leftmargin}\verb@format_entry@: 32, 50, 51, \underline{52}.
+\item \hspace{-\leftmargin}\verb@format_user_entry@: 32, 57, \underline{58}.
+\item \hspace{-\leftmargin}\verb@fprintf@: \underline{2}, 18, 19, 26, 33, 36, 37, 43, 44, 49, 53, 54, 55, 56, 59, 62, 69, 70, 71, 73, 84, 85, 86, 92, 95, 99, 107, 112, 113, 114, 115, 116, 117, 118, 119.
+\item \hspace{-\leftmargin}\verb@fputs@: \underline{2}, 38, 39, 40, 41, 42, 43, 45, 47, 49, 50, 51, 53, 54, 55, 56, 57, 59.
+\item \hspace{-\leftmargin}\verb@getc@: \underline{2}, 63, 68, 69, 70, 71, 72, 73.
+\item \hspace{-\leftmargin}\verb@goto_lookup@: \underline{124}, 127, 128, 129.
+\item \hspace{-\leftmargin}\verb@Goto_Node@: \underline{122}, 123, 124, 125, 127, 128, 129.
+\item \hspace{-\leftmargin}\verb@GREATER@: \underline{104}, 106, 108.
+\item \hspace{-\leftmargin}\verb@include_depth@: \underline{66}, 70, 72, 73.
+\item \hspace{-\leftmargin}\verb@init_scraps@: 24, 77, \underline{78}.
+\item \hspace{-\leftmargin}\verb@isgraph@: \underline{2}, 71, 112, 118.
+\item \hspace{-\leftmargin}\verb@islower@: \underline{2}, 109.
+\item \hspace{-\leftmargin}\verb@isspace@: \underline{2}, 40, 86, 112, 113, 114, 117.
+\item \hspace{-\leftmargin}\verb@isupper@: \underline{2}, 109.
+\item \hspace{-\leftmargin}\verb@LESS@: \underline{104}, 106, 108.
+\item \hspace{-\leftmargin}\verb@macro_names@: 24, 30, 51, 92, \underline{102}, 116.
+\item \hspace{-\leftmargin}\verb@main@: \underline{12}.
+\item \hspace{-\leftmargin}\verb@Manager@: \underline{79}, 80, 81, 82, 90, 91, 94, 129.
+\item \hspace{-\leftmargin}\verb@max_depth@: \underline{123}, 125, 127, 128.
+\item \hspace{-\leftmargin}\verb@Move_Node@: \underline{122}, 124, 127, 128.
+\item \hspace{-\leftmargin}\verb@Name@: 27, 28, 36, 37, 49, 52, 58, 61, 86, 87, 91, 99, \underline{101}, 102, 103, 106, 108, 110, 111, 112, 114, 118, 120, 122, 126, 127, 128, 129.
+\item \hspace{-\leftmargin}\verb@name_add@: 86, 103, \underline{110}, 112.
+\item \hspace{-\leftmargin}\verb@Name_Node@: \underline{122}, 127, 128, 129.
+\item \hspace{-\leftmargin}\verb@output_flag@: \underline{13}, 14, 18, 22.
+\item \hspace{-\leftmargin}\verb@pass1@: 22, 23, \underline{24}, 47.
+\item \hspace{-\leftmargin}\verb@pop@: \underline{90}, 91, 92, 94, 98, 99, 129.
+\item \hspace{-\leftmargin}\verb@pop_scrap_name@: \underline{91}, 99.
+\item \hspace{-\leftmargin}\verb@PREFIX@: \underline{104}, 106, 108.
+\item \hspace{-\leftmargin}\verb@prefix_add@: 92, 103, \underline{106}, 116.
+\item \hspace{-\leftmargin}\verb@print_scrap_numbers@: 32, 41, 42, 43, \underline{44}, 54, 56.
+\item \hspace{-\leftmargin}\verb@push@: \underline{80}, 81, 84, 85, 88.
+\item \hspace{-\leftmargin}\verb@pushs@: \underline{81}, 85, 88.
+\item \hspace{-\leftmargin}\verb@putc@: \underline{2}, 34, 35, 45, 46, 47, 49, 53, 54, 55, 56, 94, 96, 97, 98.
+\item \hspace{-\leftmargin}\verb@reverse@: 30, 103, 120, \underline{121}.
+\item \hspace{-\leftmargin}\verb@reverse_lists@: 30, 103, \underline{120}.
+\item \hspace{-\leftmargin}\verb@robs_strcmp@: \underline{109}, 110.
+\item \hspace{-\leftmargin}\verb@root@: 106, 110, 111, \underline{123}, 125, 127, 128, 129.
+\item \hspace{-\leftmargin}\verb@save_string@: 70, 83, 103, \underline{105}, 106, 111.
+\item \hspace{-\leftmargin}\verb@SCRAP@: \underline{76}, 78, 83.
+\item \hspace{-\leftmargin}\verb@ScrapEntry@: \underline{75}, 76, 78, 83.
+\item \hspace{-\leftmargin}\verb@scraps@: 24, 34, 36, 37, 41, 42, 43, 44, 62, \underline{76}, 77, 78, 82, 83, 84, 85, 86, 89, 93, 99, 125, 129.
+\item \hspace{-\leftmargin}\verb@scrap_array@: \underline{76}, 83, 84, 94, 95, 129.
+\item \hspace{-\leftmargin}\verb@Scrap_Node@: 29, 44, 54, 55, 56, 59, 86, 89, 93, \underline{100}, 101, 120, 121, 129.
+\item \hspace{-\leftmargin}\verb@search@: 24, \underline{125}.
+\item \hspace{-\leftmargin}\verb@Slab@: \underline{74}, 75, 79, 80, 83, 90.
+\item \hspace{-\leftmargin}\verb@SLAB_SIZE@: \underline{74}, 80, 90.
+\item \hspace{-\leftmargin}\verb@source_file@: \underline{66}, 68, 69, 70, 71, 72, 73.
+\item \hspace{-\leftmargin}\verb@source_get@: 25, 26, 34, 35, 40, 45, 47, 48, 50, 51, 57, 64, \underline{68}, 70, 72, 84, 85, 86, 87, 112, 113, 114, 115, 117, 118, 119.
+\item \hspace{-\leftmargin}\verb@source_line@: 26, \underline{65}, 68, 69, 70, 71, 72, 73, 83, 85, 86, 107, 112, 113, 114, 116, 118, 119.
+\item \hspace{-\leftmargin}\verb@source_name@: 20, 21, 22, 26, \underline{65}, 69, 70, 71, 72, 73, 83, 85, 86, 107, 112, 113, 114, 115, 116, 117, 118, 119.
+\item \hspace{-\leftmargin}\verb@source_open@: 24, 33, 64, \underline{73}.
+\item \hspace{-\leftmargin}\verb@source_peek@: \underline{66}, 68, 69, 70, 72, 73.
+\item \hspace{-\leftmargin}\verb@stack@: \underline{67}, 70, 72.
+\item \hspace{-\leftmargin}\verb@stderr@: \underline{2}, 18, 19, 26, 33, 43, 49, 62, 69, 70, 71, 73, 84, 85, 86, 92, 99, 107, 112, 113, 114, 115, 116, 117, 118, 119.
+\item \hspace{-\leftmargin}\verb@strlen@: \underline{2}, 88, 104, 105.
+\item \hspace{-\leftmargin}\verb@tex_flag@: \underline{13}, 14, 18, 22, 24, 99.
+\item \hspace{-\leftmargin}\verb@toupper@: \underline{2}, 109.
+\item \hspace{-\leftmargin}\verb@TRUE@: \underline{3}, 14, 35, 50, 69, 91, 99, 108, 111, 113.
+\item \hspace{-\leftmargin}\verb@user_names@: 24, 30, 57, 86, \underline{102}, 125.
+\item \hspace{-\leftmargin}\verb@write_files@: 22, 60, \underline{61}.
+\item \hspace{-\leftmargin}\verb@write_scraps@: 62, 77, \underline{93}, 99.
+\item \hspace{-\leftmargin}\verb@write_tex@: 22, 31, \underline{33}.
+\end{list}
+
+\bibliographystyle{plain}
+\bibliography{literate}
+
+\end{document}
diff --git a/web/nuweb/msdos/nuweb.toc b/web/nuweb/msdos/nuweb.toc
new file mode 100644
index 0000000000..fae9cbb274
--- /dev/null
+++ b/web/nuweb/msdos/nuweb.toc
@@ -0,0 +1,43 @@
+\contentsline {chapter}{\numberline {1}Introduction}{3}
+\contentsline {section}{\numberline {1.1}Nuweb}{3}
+\contentsline {section}{\numberline {1.2}Writing Nuweb}{4}
+\contentsline {subsection}{\numberline {1.2.1}The Major Commands}{4}
+\contentsline {subsubsection}{Scraps}{5}
+\contentsline {subsubsection}{Flags}{5}
+\contentsline {subsection}{\numberline {1.2.2}The Minor Commands}{5}
+\contentsline {section}{\numberline {1.3}Running Nuweb}{6}
+\contentsline {section}{\numberline {1.4}Restrictions and Extensions}{7}
+\contentsline {chapter}{\numberline {2}The Overall Structure}{8}
+\contentsline {section}{\numberline {2.1}Files}{8}
+\contentsline {subsection}{\numberline {2.1.1}The Main Files}{9}
+\contentsline {subsection}{\numberline {2.1.2}Support Files}{9}
+\contentsline {section}{\numberline {2.2}The Main Routine}{10}
+\contentsline {subsection}{\numberline {2.2.1}Command-Line Arguments}{10}
+\contentsline {subsection}{\numberline {2.2.2}File Names}{12}
+\contentsline {section}{\numberline {2.3}Pass One}{14}
+\contentsline {subsection}{\numberline {2.3.1}Accumulating Definitions}{15}
+\contentsline {subsection}{\numberline {2.3.2}Fixing the Cross References}{16}
+\contentsline {section}{\numberline {2.4}Writing the Latex File}{16}
+\contentsline {subsection}{\numberline {2.4.1}Formatting Definitions}{18}
+\contentsline {subsubsection}{Formatting Cross References}{20}
+\contentsline {subsubsection}{Formatting a Scrap}{22}
+\contentsline {subsection}{\numberline {2.4.2}Generating the Indices}{24}
+\contentsline {section}{\numberline {2.5}Writing the Output Files}{27}
+\contentsline {chapter}{\numberline {3}The Support Routines}{29}
+\contentsline {section}{\numberline {3.1}Source Files}{29}
+\contentsline {subsection}{\numberline {3.1.1}Global Declarations}{29}
+\contentsline {subsection}{\numberline {3.1.2}Local Declarations}{29}
+\contentsline {subsection}{\numberline {3.1.3}Reading a File}{30}
+\contentsline {subsection}{\numberline {3.1.4}Opening a File}{32}
+\contentsline {section}{\numberline {3.2}Scraps}{32}
+\contentsline {section}{\numberline {3.3}Names}{41}
+\contentsline {section}{\numberline {3.4}Searching for Index Entries}{51}
+\contentsline {subsection}{\numberline {3.4.1}Building the Automata}{53}
+\contentsline {subsection}{\numberline {3.4.2}Searching the Scraps}{56}
+\contentsline {section}{\numberline {3.5}Memory Management}{56}
+\contentsline {subsection}{\numberline {3.5.1}Allocating Memory}{57}
+\contentsline {subsection}{\numberline {3.5.2}Freeing Memory}{58}
+\contentsline {chapter}{\numberline {4}Indices}{59}
+\contentsline {section}{\numberline {4.1}Files}{59}
+\contentsline {section}{\numberline {4.2}Macros}{59}
+\contentsline {section}{\numberline {4.3}Identifiers}{61}
diff --git a/web/nuweb/msdos/nuweb.w b/web/nuweb/msdos/nuweb.w
new file mode 100644
index 0000000000..751e87e3ec
--- /dev/null
+++ b/web/nuweb/msdos/nuweb.w
@@ -0,0 +1,2723 @@
+\documentstyle{report}
+
+\setlength{\oddsidemargin}{0in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.5in}
+\setlength{\marginparwidth}{0.5in}
+
+\title{Nuweb \\ A Simple Literate Programming Tool}
+\author{\sl Preston Briggs}
+\date{(Version 0.6pc)}
+
+\begin{document}
+\maketitle
+\tableofcontents
+
+\chapter{Introduction}
+
+In 1984, Knuth introduced the idea of {\em literate programming\/} and
+described a pair of tools to support the practise~\cite{knuth:84}.
+His approach was to combine Pascal code with \TeX\ documentation to
+produce a new language, {\tt WEB}, that offered programmers a superior
+approach to programming. He wrote several programs in {\tt WEB},
+including {\tt weave} and {\tt tangle}, the programs used to support
+literate programming.
+The idea was that a programmer wrote one document, the web file, that
+combined documentation (written in \TeX~\cite{texbook}) with code
+(written in Pascal).
+
+Running {\tt tangle} on the web file would produce a complete
+Pascal program, ready for compilation by an ordinary Pascal compiler.
+The primary function of {\tt tangle} is to allow the programmer to
+present elements of the program in any desired order, regardless of
+the restrictions imposed by the programming language. Thus, the
+programmer is free to present his program in a top-down fashion,
+bottom-up fashion, or whatever seems best in terms of promoting
+understanding and maintenance.
+
+Running {\tt weave} on the web file would produce a \TeX\ file, ready
+to be processed by \TeX\@@. The resulting document included a variety of
+automatically generated indices and cross-references that made it much
+easier to navigate the code. Additionally, all of the code sections
+were automatically pretty printed, resulting in a quite impressive
+document.
+
+Knuth also wrote the programs for \TeX\ and {\small\sf METAFONT}
+entirely in {\tt WEB}, eventually publishing them in book
+form~\cite{tex:program,metafont:program}. These are probably the
+largest programs ever published in a readable form.
+
+Inspired by Knuth's example, many people have experimented with
+{\tt WEB}\@@. Some people have even built web-like tools for their own
+favorite combinations of programming language and typesetting
+language. For example, {\tt CWEB}, Knuth's current system of choice,
+works with a combination of C and \TeX~\cite{levy:90}. Another system,
+FunnelWeb, is independent of any programming language and only mildly
+dependent on \TeX~\cite{funnelweb}. Inspired by the versatility
+of FunnelWeb and by the daunting size of its documentation, I decided
+to write my own, very simple, tool for literate programming.%
+\footnote{There is another system similar to mine, written by Norman
+Ramsey, called {\em noweb}~\cite{noweb}. It perhaps suffers from being
+overly Unix-dependent and requiring several programs to use. On the
+other hand, its command syntax is very nice. In any
+case, nuweb certainly owes its name to his inspiration.}
+
+
+\section{Nuweb}
+
+Nuweb works with any programming language and \LaTeX~\cite{latex}. I
+wanted to use \LaTeX\ because it supports a multi-level sectioning
+scheme and has facilities for drawing figures. I wanted to be able to
+work with arbitrary programming languages because my friends and I
+write programs in many languages (and sometimes combinations of
+several languages), {\em e.g.,} C, Fortran, C++, yacc, lex, Scheme,
+assembly, Postscript, and so forth. The need to support arbitrary
+programming languages has many consequences:
+\begin{description}
+\item[No pretty printing] Both {\tt WEB} and {\tt CWEB} are able to
+ pretty print the code sections of their documents because they
+ understand the language well enough to parse it. Since we want to use
+ {\em any\/} language, we've got to abandon this feature.
+\item[No index of identifiers] Because {\tt WEB} knows about Pascal,
+ it is able to construct an index of all the identifiers occurring in
+ the code sections (filtering out keywords and the standard type
+ identifiers). Unfortunately, this isn't as easy in our case. We don't
+ know what an identifiers looks like in each language and we certainly
+ don't know all the keywords. (On the other hand, see the end of
+ Section~1.3)
+\end{description}
+Of course, we've got to have some compensation for our losses or the
+whole idea would be a waste. Here are the advantages I can see:
+\begin{description}
+\item[Simplicity] The majority of the commands in {\tt WEB} are
+ concerned with control of the automatic pretty printing. Since we
+ don't pretty print, many commands are eliminated. A further set of
+ commands is subsumed by \LaTeX\ and may also be eliminated. As a
+ result, our set of commands is reduced to only four members (explained
+ in the next section). This simplicity is also reflected in
+ the size of this tool, which is quite a bit smaller than the tools
+ used with other approaches.
+\item[No pretty printing] Everyone disagrees about how their code
+ should look, so automatic formatting annoys many people. One approach
+ is to provide ways to control the formatting. Our approach is simpler
+ -- we perform no automatic formatting and therefore allow the
+ programmer complete control of code layout.
+\item[Control] We also offer the programmer complete control of the
+ layout of his output files (the files generated during tangling). Of
+ course, this is essential for languages that are sensitive to layout;
+ but it is also important in many practical situations, {\em e.g.,}
+ debugging.
+\item[Speed] Since nuweb doesn't do to much, the nuweb tool runs
+ quickly. I combine the functions of {\tt tangle} and {\tt weave} into
+ a single program that performs both functions at once.
+\item[Multiple file output] The programmer may specify more than one
+ output file in a single nuweb file. This is required when constructing
+ programs in a combination of languages (say, Fortran and C)\@@. It's also
+ an advantage when constructing very large programs that would require
+ a lot of compile time.
+\end{description}
+This last point is very important. By allowing the creation of
+multiple output files, we avoid the need for monolithic programs.
+Thus we support the creation of very large programs by groups of
+people.
+
+A further reduction in compilation time is achieved by first
+writing each output file to a temporary location, then comparing the
+temporary file with the old version of the file. If there is no
+difference, the temporary file can be deleted. If the files differ,
+the old version is deleted and the temporary file renamed. This
+approach works well in combination with {\tt make} (or similar tools),
+since {\tt make} will avoid recompiling untouched output files.
+
+
+\section{Writing Nuweb}
+
+The bulk of a nuweb file will be ordinary \LaTeX\@@. In fact, any \LaTeX\
+file can serve as input to nuweb and will be simply copied through
+unchanged to the {\tt .tex} file -- unless a nuweb command is
+discovered. All nuweb commands begin with an ``at-sign'' ({\tt @@}).
+Therefore, a file without at-signs will be copied unchanged.
+Nuweb commands are used to specify {\em output files,} define
+{\em macros,} and delimit {\em scraps}. These are the basic features
+of interest to the nuweb tool -- all else is simply text to be copied
+to the {\tt .tex} file.
+
+\subsection{The Major Commands}
+
+Files and macros are defined with the following commands:
+\begin{description}
+\item[\tt @@o {\em file-name flags scrap\/}] Output a file. The file name is
+ terminated by whitespace.
+\item[\tt @@d {\em macro-name scrap\/}] Define a macro. The macro name
+ is terminated by a return or the beginning of a scrap.
+\end{description}
+A specific file may be specified several times, with each definition
+being written out, one after the other, in the order they appear.
+The definitions of macros may be similarly divided.
+
+\subsubsection{Scraps}
+
+Scraps have specific begin markers and end markers to allow precise
+control over the contents and layout. Note that any amount of
+whitespace (including carriage returns) may appear between a name and
+the beginning of a scrap.
+\begin{description}
+\item[\tt @@\{{\em anything\/}@@\}] where the scrap body includes every
+ character in {\em anything\/} -- all the blanks, all the tabs, all the
+ carriage returns.
+\end{description}
+Inside a scrap, we may invoke a macro.
+\begin{description}
+\item[\tt @@<{\em macro-name\/}@@>] Causes the macro {\em macro-name\/}
+ to be expanded inline as the code is written out to a file. It is an
+ error to specify recursive macro invocations.
+\end{description}
+Note that macro names may be abbreviated, either during invocation or
+definition. For example, it would be very tedious to have to
+repeatedly type the macro name
+\begin{quote}
+{\tt @@d Check for terminating at-sequence and return name if found}
+\end{quote}
+Therefore, we provide a mechanism (stolen from Knuth) of indicating
+abbreviated names.
+\begin{quote}
+{\tt @@d Check for terminating...}
+\end{quote}
+Basically, the programmer need only type enough characters to uniquely
+identify the macro name, followed by three periods. An abbreviation
+may even occur before the full version; nuweb simply preserves the
+longest version of a macro name. Note also that blanks and tabs are
+insignificant in a macro name; any string of them are replaced by a
+single blank.
+
+When scraps are written to an output or {\tt .tex} file, tabs are
+expanded into spaces by default. Currently, I assume tab stops are set
+every eight characters. Furthermore, when a macro is expanded in a scrap,
+the body of the macro is indented to match the indentation of the
+macro invocation. Therefore, care must be taken with languages
+({\em e.g.,} Fortran) that are sensitive to indentation.
+These default behaviors may be changed for each output file (see
+below).
+
+\subsubsection{Flags}
+
+When defining an output file, the programmer has the option of using
+flags to control output of a particular file. The flags are intended
+to make life a little easier for programmers using certain languages.
+They introduce little language dependences; however, they do so only
+for a particular file. Thus it is still easy to mix languages within a
+single document. There are three ``per-file'' flags:
+\begin{description}
+\item[\tt -d] Forces the creation of \verb|#line| directives in the
+ output file. These are useful with C (and sometimes C++ and Fortran) on
+ many Unix systems since they cause the compiler's error messages to
+ refer to the web file rather than the output file. Similarly, they
+ allow source debugging in terms of the web file.
+\item[\tt -i] Suppresses the indentation of macros. That is, when a
+ macro is expanded in a scrap, it will {\em not\/} be indented to
+ match the indentation of the macro invocation. This flag would seem
+ most useful for Fortran programmers.
+\item[\tt -t] Suppresses expansion of tabs in the output file. This
+ feature seems important when generating {\tt make} files.
+\end{description}
+
+
+\subsection{The Minor Commands}
+
+We have two very low-level utility commands that may appear anywhere
+in the web file.
+\begin{description}
+\item[\tt @@@@] Causes a single ``at sign'' to be copied into the output.
+\item[\tt @@i {\em file-name\/}] Includes a file. Includes may be
+ nested, though there is currently a limit of 10~levels. The file name
+ should be complete (no extension will be appended) and should be
+ terminated by a carriage return.
+\end{description}
+Finally, there are three commands used to create indices to the macro
+names, file definitions, and user-specified identifiers.
+\begin{description}
+\item[\tt @@f] Create an index of file names.
+\item[\tt @@m] Create an index of macro name.
+\item[\tt @@u] Create an index of user-specified identifiers.
+\end{description}
+I usually put these in their own section
+in the \LaTeX\ document; for example, see Chapter~\ref{indices}.
+
+Identifiers must be explicitely specified for inclusion in the
+{\tt @@u} index. By convention, each identifier is marked at the point
+of its definition; all references to each identifier (inside scraps)
+will be discovered automatically. To ``mark'' an identifier for
+inclusion in the index, we must mention it at the end of a scrap.
+For example,
+\begin{quote}
+\begin{verbatim}
+@@d a scrap @@{
+Let's pretend we're declaring the variables FOO and BAR
+inside this scrap.
+@@| FOO BAR @@}
+\end{verbatim}
+\end{quote}
+I've used alphabetic identifiers in this example, but any string of
+characters (not including whitespace) will do. Therefore, it's
+possible to add index entries for things like {\tt <<=} if desired.
+An identifier may be declared in more than one scrap.
+
+In the generated index, each identifier appears with a list of all the
+scraps using and defining it, where the defining scraps are
+distinguished by underlining. Note that the identifier doesn't
+actually have to appear in the defining scrap; it just has to be in
+the list of definitions at the end of a scrap.
+
+
+\section{Running Nuweb}
+
+Nuweb is invoked using the following command:
+\begin{quote}
+{\tt nuweb} {\em flags file-name}\ldots
+\end{quote}
+One or more files may be processed at a time. If a file name has no
+extension, {\tt .w} will be appended. While a file name may specify a
+file in another directory, the resulting {\tt .tex} file will always
+be created in the current directory. For example,
+\begin{quote}
+{\tt nuweb /foo/bar/quux}
+\end{quote}
+will take as input the file {\tt /foo/bar/quux.w} and will create the
+file {\tt quux.tex} in the current directory.
+
+By default, nuweb performs both tangling and weaving at the same time.
+Normally, this is not a bottleneck in the compilation process;
+however, it's possible to achieve slightly faster throughput by
+avoiding one or another of the default functions using command-line
+flags. There are currently three possible flags:
+\begin{description}
+\item[\tt -t] Suppress generation of the {\tt .tex} file.
+\item[\tt -o] Suppress generation of the output files.
+\item[\tt -c] Avoid testing output files for change before updating them.
+\end{description}
+Thus, the command
+\begin{quote}
+{\tt nuweb -to /foo/bar/quux}
+\end{quote}
+would simply scan the input and produce no output at all.
+
+
+\section{Restrictions and Extensions}
+
+Because nuweb is intended to be a simple tool, I've established a few
+restrictions. Over time, some of these may be eliminated; others seem
+fundamental.
+\begin{itemize}
+\item The scraps don't print well with older versions of \TeX\
+ (pre~3.0). I'm not sure why and I'm not sure it's always true
+ (I don't have a version to experiment with).
+\item The handling of errors is not completely ideal. In some cases, I
+ simply warn of a problem and continue; in other cases I halt
+ immediately. This behavior should be regularized.
+\item I warn about references to macros that haven't been defined, but
+ don't halt. This seems most convenient for development, but may change
+ in the future.
+\item File names and index entries should not contain any {\tt @@}
+ signs.
+\item Macro names may be (almost) any well-formed \TeX\ string.
+ It makes sense to change fonts or use math mode; however, care should
+ be taken to ensure matching braces, brackets, and dollar signs.
+\item Anything is allowed in the body of a scrap; however, very
+ long scraps (horizontally or vertically) may not typeset well.
+\end{itemize}
+Very long scraps may be allowed to break across a page if declared
+with {\tt @@O} or {\tt @@D} (instead of {\tt @@o} or {\tt @@d}).
+This doesn't work very well as a default, since far too many short
+scraps will be broken across pages; however, as a user-controlled
+option, it seems very useful.
+
+
+\chapter{The Overall Structure}
+
+Processing a web requires three major steps:
+\begin{enumerate}
+\item Read the source, accumulating file names, macro names, scraps,
+and lists of cross-references.
+\item Reread the source, copying out to the {\tt .tex} file, with
+protection and cross-reference information for all the scraps.
+\item Traverse the list of files names. For each file name:
+\begin{enumerate}
+\item Dump all the defining scraps into a temporary file.
+\item If the file already exists and is unchanged, delete the
+temporary file; otherwise, rename the temporary file.
+\end{enumerate}
+\end{enumerate}
+
+
+\section{Files}
+
+I have divided the program into several files for quicker
+recompilation during development. Rather than use {\tt .h} files
+for shared declarations, I'll simply create a shared scrap containing
+all the global declarations. This isn't really best from the point of
+view of disk space; but it does simplify the makefile (and allow me to
+play with my new toy).
+@d Shared declarations
+@{@<Include files@>
+@<Type declarations@>
+@<Global variables@>
+@<Function prototypes@>
+@}
+
+We'll need at least two of the standard system include files.
+@d Include files
+@{#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+@| FILE stderr exit fprintf fputs fopen fclose getc putc strlen
+toupper isupper islower isgraph isspace @}
+
+\newpage
+\noindent
+I also like to use {\tt TRUE} and {\tt FALSE} in my code.
+I'd use an {\tt enum} here, except that some systems seem to provide
+definitions of {\tt TRUE} and {\tt FALSE} be default. The following
+code seems to work on all the local systems.
+@d Type dec...
+@{#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!0)
+#endif
+@| FALSE TRUE @}
+
+
+\subsection{The Main Files}
+
+The code is divided into four main files (introduced here) and five
+support files (introduced in the next section).
+The file {\tt main.c} will contain the driver for the whole program
+(see Section~\ref{main-routine}).
+@o main.c
+@{@<Shared...@>
+@}
+
+
+The first pass over the source file is contained in {\tt pass1.c}.
+It handles collection of all the file names, macros names, and scraps
+(see Section~\ref{pass-one}).
+@o pass1.c
+@{@<Shared...@>
+@}
+
+The {\tt .tex} file is created during a second pass over the source
+file. The file {\tt latex.c} contains the code controlling the
+construction of the {\tt .tex} file
+(see Section~\ref{latex-file}).
+@o latex.c
+@{@<Shared...@>
+@}
+
+
+The code controlling the creation of the output files is in {\tt output.c}
+(see Section~\ref{output-files}).
+@o output.c
+@{@<Shared...@>
+@}
+
+
+\subsection{Support Files}
+
+The support files contain a variety of support routines used to define
+and manipulate the major data abstractions.
+The file {\tt input.c} holds all the routines used for referring to
+source files (see Section~\ref{source-files}).
+@o input.c
+@{@<Shared...@>
+@}
+
+Creation and lookup of scraps is handled by routines in {\tt scraps.c}
+(see Section~\ref{scraps}).
+@o scraps.c
+@{@<Shared...@>
+@}
+
+
+The handling of file names and macro names is detailed in {\tt names.c}
+(see Section~\ref{names}).
+@o names.c
+@{@<Shared...@>
+@}
+
+Memory allocation and deallocation is handled by routines in {\tt arena.c}
+(see Section~\ref{memory-management}). I don't bother including all
+the shared declarations since they aren't required.
+@o arena.c
+@{@<Include...@>
+@}
+
+
+\section{The Main Routine} \label{main-routine}
+
+The main routine is quite simple in structure.
+It wades through the optional command-line arguments,
+then handles any files listed on the command line.
+@o main.c
+@{void main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int arg = 1;
+ @<Interpret command-line arguments@>
+ @<Process the remaining arguments (file names)@>
+ exit(0);
+}
+@| main @}
+
+
+\subsection{Command-Line Arguments}
+
+There are three possible command-line arguments:
+\begin{description}
+\item[{\tt -t}] Suppresses generation of the {\tt .tex} file.
+\item[{\tt -o}] Suppresses generation of the output files.
+\item[{\tt -c}] Forces output files to overwrite old files of the same
+name without comparing for equality first.
+\item[{\tt -v}] Prints the current version of {\tt nuweb}.
+\end{description}
+Global flags are declared for each of the arguments.
+@d Global...
+@{int tex_flag; /* if FALSE, don't emit the .tex file */
+int output_flag; /* if FALSE, don't emit the output files */
+int compare_flag; /* if FALSE, overwrite without comparison */
+@| tex_flag output_flag compare_flag @}
+
+\newpage
+\noindent
+The flags are all initialized to {\tt TRUE} for correct default behavior.
+@d Interpret com...
+@{tex_flag = TRUE;
+output_flag = TRUE;
+compare_flag = TRUE;
+@}
+
+
+We save the invocation name of the command in a global variable
+{\tt command\_name} for use in error messages.
+@d Global...
+@{char *command_name;
+@| command_name @}
+
+The invocation name is conventionally passed in {\tt argv[0]}.
+@d Interpret com...
+@{command_name = argv[0];
+@}
+
+
+We need to examine the remaining entries in {\tt argv}, looking for
+command-line arguments.
+@d Interpret com...
+@{while (arg < argc) {
+ char *s = argv[arg];
+ if (*s++ == '-') {
+ @<Interpret the argument string {\tt s}@>
+ arg++;
+ }
+ else break;
+}@}
+
+\newpage
+\noindent
+Several flags can be stacked behind a single minus sign; therefore,
+we've got to loop through the string, handling them all.
+@d Interpret the...
+@{{
+ char c = *s++;
+ while (c) {
+ switch (c) {
+ case 'c': compare_flag = FALSE;
+ break;
+ case 'o': output_flag = FALSE;
+ break;
+ case 't': tex_flag = FALSE;
+ break;
+ case 'v': printf("nuweb version 0.6\n");
+ break;
+ default: fprintf(stderr, "%s: unexpected argument ignored. ",
+ command_name);
+ fprintf(stderr, "Usage is: %s [-cot] file...\n",
+ command_name);
+ break;
+ }
+ c = *s++;
+ }
+}@}
+
+
+\subsection{File Names}
+
+We expect at least one file name. While a missing file name might be
+ignored without causing any problems, we take the opportunity to report
+the usage convention.
+@d Process the remaining...
+@{if (arg < argc)
+ do {
+ @<Handle the file name in {\tt argv[arg]}@>
+ arg++;
+ } while (arg < argc);
+else {
+ fprintf(stderr, "%s: expected a file name. ", command_name);
+ fprintf(stderr, "Usage is: %s [-cot] file-name...\n", command_name);
+ exit(-1);
+}@}
+
+\newpage
+\noindent
+The code to handle a particular file name is rather more tedious than
+the actual processing of the file. A file name may be an arbitrarily
+complicated path name, with an optional extension. If no extension is
+present, we add {\tt .w} as a default. The extended path name will be
+kept in a local variable {\tt source\_name}. The resulting {\tt .tex}
+file will be written in the current directory; its name will be kept
+in the variable {\tt tex\_name}.
+@d Handle the file...
+@{{
+ char source_name[100];
+ char tex_name[100];
+ @<Build {\tt source\_name} and {\tt tex\_name}@>
+ @<Process a file@>
+}@}
+
+
+I bump the pointer {\tt p} through all the characters in {\tt argv[arg]},
+copying all the characters into {\tt source\_name} (via the pointer
+{\tt q}).
+
+At each slash, I update {\tt trim} to point just past the
+slash in {\tt source\_name}. The effect is that {\tt trim} will point
+at the file name without any leading directory specifications.
+
+The pointer {\tt dot} is made to point at the file name extension, if
+present. If there is no extension, we add {\tt .w} to the source name.
+In any case, we create the {\tt tex\_name} from {\tt trim}, taking
+care to get the correct extension.
+@d Build {\tt sou...
+@{{
+ char *p = argv[arg];
+ char *q = source_name;
+ char *trim = q;
+ char *dot = NULL;
+ char c = *p++;
+ while (c) {
+ *q++ = c;
+ if (c == '/') {
+ trim = q;
+ dot = NULL;
+ }
+ else if (c == '.')
+ dot = q - 1;
+ c = *p++;
+ }
+ *q = '\0';
+ if (dot) {
+ *dot = '\0';
+ sprintf(tex_name, "%s.tex", trim);
+ *dot = '.';
+ }
+ else {
+ sprintf(tex_name, "%s.tex", trim);
+ *q++ = '.';
+ *q++ = 'w';
+ *q = '\0';
+ }
+}@}
+
+Now that we're finally ready to process a file, it's not really too
+complex. We bundle most of the work into three routines {\tt pass1}
+(see Section~\ref{pass-one}), {\tt write\_tex} (see
+Section~\ref{latex-file}), and {\tt write\_files} (see
+Section~\ref{output-files}). After we're finished with a
+particular file, we must remember to release its storage (see
+Section~\ref{memory-management}).
+@d Process a file
+@{{
+ pass1(source_name);
+ if (tex_flag)
+ write_tex(source_name, tex_name);
+ if (output_flag)
+ write_files(file_names);
+ arena_free();
+}@}
+
+
+\section{Pass One} \label{pass-one}
+
+During the first pass, we scan the file, recording the definitions of
+each macro and file and accumulating all the scraps.
+
+@d Function pro...
+@{void pass1();
+@}
+
+
+The routine {\tt pass1} takes a single argument, the name of the
+source file. It opens the file, then initializes the scrap structures
+(see Section~\ref{scraps}) and the roots of the file-name tree, the
+macro-name tree, and the tree of user-specified index entries (see
+Section~\ref{names}). After completing all the
+necessary preparation, we make a pass over the file, filling in all
+our data structures. Next, we seach all the scraps for references to
+the user-specified index entries. Finally, we must reverse all the
+cross-reference lists accumulated while scanning the scraps.
+@o pass1.c
+@{void pass1(file_name)
+ char *file_name;
+{
+ source_open(file_name);
+ init_scraps();
+ macro_names = NULL;
+ file_names = NULL;
+ user_names = NULL;
+ @<Scan the source file, looking for at-sequences@>
+ if (tex_flag)
+ search();
+ @<Reverse cross-reference lists@>
+}
+@| pass1 @}
+
+\newpage
+\noindent
+The only thing we look for in the first pass are the command
+sequences. All ordinary text is skipped entirely.
+@d Scan the source file, look...
+@{{
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@@')
+ @<Scan at-sequence@>
+ c = source_get();
+ }
+}@}
+
+Only four of the at-sequences are interesting during the first pass.
+We skip past others immediately; warning if unexpected sequences are
+discovered.
+@d Scan at-sequence
+@{{
+ c = source_get();
+ switch (c) {
+ case 'O':
+ case 'o': @<Build output file definition@>
+ break;
+ case 'D':
+ case 'd': @<Build macro definition@>
+ break;
+ case '@@':
+ case 'u':
+ case 'm':
+ case 'f': /* ignore during this pass */
+ break;
+ default: fprintf(stderr,
+ "%s: unexpected @@ sequence ignored (%s, line %d)\n",
+ command_name, source_name, source_line);
+ break;
+ }
+}@}
+
+
+\subsection{Accumulating Definitions}
+
+There are three steps required to handle a definition:
+\begin{enumerate}
+\item Build an entry for the name so we can look it up later.
+\item Collect the scrap and save it in the table of scraps.
+\item Attach the scrap to the name.
+\end{enumerate}
+We go through the same steps for both file names and macro names.
+@d Build output file definition
+@{{
+ Name *name = collect_file_name(); /* returns a pointer to the name entry */
+ int scrap = collect_scrap(); /* returns an index to the scrap */
+ @<Add {\tt scrap} to...@>
+}@}
+
+
+@d Build macro definition
+@{{
+ Name *name = collect_macro_name();
+ int scrap = collect_scrap();
+ @<Add {\tt scrap} to...@>
+}@}
+
+Since a file or macro may be defined by many scraps, we maintain them
+in a simple linked list. The list is actually built in reverse order,
+with each new definition being added to the head of the list.
+@d Add {\tt scrap} to {\tt name}'s definition list
+@{{
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scrap;
+ def->next = name->defs;
+ name->defs = def;
+}@}
+
+
+\subsection{Fixing the Cross References}
+
+Since the definition and reference lists for each name are accumulated
+in reverse order, we take the time at the end of {\tt pass1} to
+reverse them all so they'll be simpler to print out prettily.
+The code for {\tt reverse\_lists} appears in Section~\ref{names}.
+@d Reverse cross-reference lists
+@{{
+ reverse_lists(file_names);
+ reverse_lists(macro_names);
+ reverse_lists(user_names);
+}@}
+
+
+
+\section{Writing the Latex File} \label{latex-file}
+
+The second pass (invoked via a call to {\tt write\_tex}) copies most of
+the text from the source file straight into a {\tt .tex} file.
+Definitions are formatted slightly and cross-reference information is
+printed out.
+
+Note that all the formatting is handled in this section.
+If you don't like the format of definitions or indices or whatever,
+it'll be in this section somewhere. Similarly, if someone wanted to
+modify nuweb to work with a different typesetting system, this would
+be the place to look.
+
+@d Function...
+@{void write_tex();
+@}
+
+\newpage
+\noindent
+We need a few local function declarations before we get into the body
+of {\tt write\_tex}.
+
+@o latex.c
+@{static void copy_scrap(); /* formats the body of a scrap */
+static void print_scrap_numbers(); /* formats a list of scrap numbers */
+static void format_entry(); /* formats an index entry */
+static void format_user_entry();
+@}
+
+The routine {\tt write\_tex} takes two file names as parameters: the
+name of the web source file and the name of the {\tt .tex} output file.
+@o latex.c
+@{void write_tex(file_name, tex_name)
+ char *file_name;
+ char *tex_name;
+{
+ FILE *tex_file = fopen(tex_name, "w");
+ if (tex_file) {
+ source_open(file_name);
+ @<Copy {\tt source\_file} into {\tt tex\_file}@>
+ fclose(tex_file);
+ }
+ else
+ fprintf(stderr, "%s: can't open %s\n", command_name, tex_name);
+}
+@| write_tex @}
+
+We make our second (and final) pass through the source web, this time
+copying characters straight into the {\tt .tex} file. However, we keep
+an eye peeled for {\tt @@}~characters, which signal a command sequence.
+
+@d Copy {\tt source\_file}...
+@{{
+ int scraps = 1;
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@@')
+ @<Interpret at-sequence@>
+ else {
+ putc(c, tex_file);
+ c = source_get();
+ }
+ }
+}@}
+
+@d Interpret at-sequence
+@{{
+ int big_definition = FALSE;
+ c = source_get();
+ switch (c) {
+ case 'O': big_definition = TRUE;
+ case 'o': @<Write output file definition@>
+ break;
+ case 'D': big_definition = TRUE;
+ case 'd': @<Write macro definition@>
+ break;
+ case 'f': @<Write index of file names@>
+ break;
+ case 'm': @<Write index of macro names@>
+ break;
+ case 'u': @<Write index of user-specified names@>
+ break;
+ case '@@': putc(c, tex_file);
+ default: c = source_get();
+ break;
+ }
+}@}
+
+
+\subsection{Formatting Definitions}
+
+We go through a fair amount of effort to format a file definition.
+I've derived most of the \LaTeX\ commands experimentally; it's quite
+likely that an expert could do a better job. The \LaTeX\ for
+the previous macro definition should look like this (perhaps modulo
+the scrap numbers):
+\begin{verbatim}
+\begin{flushleft}
+\begin{minipage}{\linewidth}
+$\langle$Interpret at-sequence {\footnotesize 35}$\rangle\equiv$
+\vspace{-1.5ex}
+\begin{quote}
+\verb@@{@@\\
+\verb@@ c = source_get();@@\\
+\verb@@ switch (c) {@@\\
+\verb@@ case 'O': big_definition = TRUE;@@\\
+\verb@@ case 'o': @@$\langle$Write output file definition {\footnotesize 36}$\rangle$\verb@@@@\\
+\end{verbatim}
+\vdots
+\begin{verbatim}
+\verb@@ case '@@{\tt @@}\verb@@': putc(c, tex_file);@@\\
+\verb@@ default: c = source_get();@@\\
+\verb@@ break;@@\\
+\verb@@ }@@\\
+\verb@@}@@$\Diamond$
+\end{quote}
+\vspace{-2ex}
+{\footnotesize Macro referenced in scrap 34.}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\end{verbatim}
+The {\em flushleft\/} environment is used to avoid \LaTeX\ warnings
+about underful lines. The {\em minipage\/} environment is used to
+avoid page breaks in the middle of scraps. The {\em verb\/} command
+allows arbitrary characters to be printed (however, note the special
+handling of the {\tt @@} case in the switch statement).
+
+Macro and file definitions are formatted nearly identically.
+I've factored the common parts out into separate scraps.
+
+@d Write output file definition
+@{{
+ Name *name = collect_file_name();
+ @<Begin the scrap environment@>
+ fprintf(tex_file, "\\verb@@\"%s\"@@", name->spelling);
+ fprintf(tex_file, " {\\footnotesize %d }$\\equiv$\n", scraps++);
+ @<Fill in the middle of the scrap environment@>
+ @<Write file defs@>
+ @<Finish the scrap environment@>
+}@}
+
+I don't format a macro name at all specially, figuring the programmer
+might want to use italics or bold face in the midst of the name.
+
+@d Write macro definition
+@{{
+ Name *name = collect_macro_name();
+ @<Begin the scrap environment@>
+ fprintf(tex_file, "$\\langle$%s", name->spelling);
+ fprintf(tex_file, " {\\footnotesize %d}$\\rangle\\equiv$\n", scraps++);
+ @<Fill in the middle of the scrap environment@>
+ @<Write macro defs@>
+ @<Write macro refs@>
+ @<Finish the scrap environment@>
+}@}
+
+
+@d Begin the scrap environment
+@{{
+ fputs("\\begin{flushleft}\n", tex_file);
+ if (!big_definition)
+ fputs("\\begin{minipage}{\\linewidth}\n", tex_file);
+}@}
+
+The interesting things here are the $\Diamond$ inserted at the end of
+each scrap and the various spacing commands. The diamond helps to
+clearly indicate the end of a scrap. The spacing commands were derived
+empirically; they may be adjusted to taste.
+
+@d Fill in the middle of the scrap environment
+@{{
+ fputs("\\vspace{-1.5ex}\n\\begin{quote}\n", tex_file);
+ copy_scrap(tex_file);
+ fputs("$\\Diamond$\n\\end{quote}\n\\vspace{-2ex}\n", tex_file);
+}@}
+
+\newpage
+\noindent
+We've got one last spacing command, controlling the amount of white
+space after a scrap.
+
+Note also the whitespace eater. I use it to remove any blank lines
+that appear after a scrap in the source file. This way, text following
+a scrap will not be indented. Again, this is a matter of personal taste.
+
+@d Finish the scrap environment
+@{{
+ if (!big_definition)
+ fputs("\\end{minipage}\\\\[4ex]\n", tex_file);
+ fputs("\\end{flushleft}\n", tex_file);
+ do
+ c = source_get();
+ while (isspace(c));
+}@}
+
+
+\subsubsection{Formatting Cross References}
+
+@d Write file defs
+@{{
+ if (name->defs->next) {
+ fputs("{\\footnotesize File defined by scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->defs);
+ fputs("}\n", tex_file);
+ }
+}@}
+
+@d Write macro defs
+@{{
+ fputs("{\\footnotesize ", tex_file);
+ if (name->defs->next) {
+ fputs("Macro defined by scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->defs);
+ fputs("\\\\[-1ex]\n", tex_file);
+ }
+}@}
+
+@d Write macro refs
+@{{
+ if (name->uses) {
+ if (name->uses->next) {
+ fputs("Macro referenced in scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->uses);
+ fputs("}\n", tex_file);
+ }
+ else
+ fprintf(tex_file, "Macro referenced in scrap %d.}\n", name->uses->scrap);
+ }
+ else {
+ fputs("Macro never referenced.}\n", tex_file);
+ fprintf(stderr, "%s: <%s> never referenced.\n",
+ command_name, name->spelling);
+ }
+}@}
+
+
+@o latex.c
+@{static void print_scrap_numbers(tex_file, scraps)
+ FILE *tex_file;
+ Scrap_Node *scraps;
+{
+ fprintf(tex_file, "%d", scraps->scrap);
+ scraps = scraps->next;
+ while (scraps->next) {
+ fprintf(tex_file, ", %d", scraps->scrap);
+ scraps = scraps->next;
+ }
+ fprintf(tex_file, " and~%d.", scraps->scrap);
+}
+@| print_scrap_numbers @}
+
+
+\subsubsection{Formatting a Scrap}
+
+@o latex.c
+@{static void copy_scrap(file)
+ FILE *file;
+{
+ int indent = 0;
+ int c = source_get();
+ fputs("\\verb@@", file);
+ while (1) {
+ switch (c) {
+ case '@@': @<Check at-sequence for end-of-scrap@>
+ break;
+ case '\n': fputs("@@\\\\\n\\verb@@", file);
+ indent = 0;
+ break;
+ case '\t': @<Expand tab into spaces@>
+ break;
+ default: putc(c, file);
+ indent++;
+ break;
+ }
+ c = source_get();
+ }
+}
+@| copy_scrap @}
+
+
+@d Expand tab into spaces
+@{{
+ int delta = 8 - (indent % 8);
+ indent += delta;
+ while (delta > 0) {
+ putc(' ', file);
+ delta--;
+ }
+}@}
+
+@d Check at-sequence...
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': fputs("@@{\\tt @@}\\verb@@", file);
+ break;
+ case '|': @<Skip over index entries@>
+ case '}': putc('@@', file);
+ return;
+ case '<': @<Format macro name@>
+ break;
+ default: /* ignore these since pass1 will have warned about them */
+ break;
+ }
+}@}
+
+There's no need to check for errors here, since we will have already
+pointed out any during the first pass.
+@d Skip over index entries
+@{{
+ do {
+ do
+ c = source_get();
+ while (c != '@@');
+ c = source_get();
+ } while (c != '}');
+}@}
+
+
+@d Format macro name
+@{{
+ Name *name = collect_scrap_name();
+ fprintf(file, "@@$\\langle$%s {\\footnotesize ", name->spelling);
+ if (name->defs)
+ fprintf(file, "%d", name->defs->scrap);
+ else {
+ putc('?', file);
+ fprintf(stderr, "%s: scrap never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ fputs("}$\\rangle$\\verb@@", file);
+}@}
+
+
+
+\subsection{Generating the Indices}
+
+@d Write index of file names
+@{{
+ if (file_names) {
+ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);
+ format_entry(file_names, tex_file, TRUE);
+ fputs("\\end{list}", tex_file);
+ }
+ c = source_get();
+}@}
+
+
+@d Write index of macro names
+@{{
+ if (macro_names) {
+ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);
+ format_entry(macro_names, tex_file, FALSE);
+ fputs("\\end{list}", tex_file);
+ }
+ c = source_get();
+}@}
+
+
+@o latex.c
+@{static void format_entry(name, tex_file, file_flag)
+ Name *name;
+ FILE *tex_file;
+ int file_flag;
+{
+ while (name) {
+ format_entry(name->llink, tex_file, file_flag);
+ @<Format an index entry@>
+ name = name->rlink;
+ }
+}
+@| format_entry @}
+
+
+@d Format an index entry
+@{{
+ fputs("\\item \\hspace{-\\leftmargin}", tex_file);
+ if (file_flag) {
+ fprintf(tex_file, "\\verb@@\"%s\"@@ ", name->spelling);
+ @<Write file's defining scrap numbers@>
+ }
+ else {
+ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);
+ @<Write defining scrap numbers@>
+ fputs("}$\\rangle$ ", tex_file);
+ @<Write referencing scrap numbers@>
+ }
+ putc('\n', tex_file);
+}@}
+
+
+@d Write file's defining scrap numbers
+@{{
+ Scrap_Node *p = name->defs;
+ fputs("{\\footnotesize Defined by scrap", tex_file);
+ if (p->next) {
+ fputs("s ", tex_file);
+ print_scrap_numbers(tex_file, p);
+ }
+ else
+ fprintf(tex_file, " %d.", p->scrap);
+ putc('}', tex_file);
+}@}
+
+@d Write defining scrap numbers
+@{{
+ Scrap_Node *p = name->defs;
+ if (p) {
+ while (1) {
+ fprintf(tex_file, "%d", p->scrap);
+ p = p->next;
+ if (!p) break;
+ fputs(", ", tex_file);
+ }
+ }
+ else
+ putc('?', tex_file);
+}@}
+
+@d Write referencing scrap numbers
+@{{
+ Scrap_Node *p = name->uses;
+ fputs("{\\footnotesize ", tex_file);
+ if (p) {
+ fputs("Referenced in scrap", tex_file);
+ if (p->next) {
+ fputs("s ", tex_file);
+ print_scrap_numbers(tex_file, p);
+ }
+ else
+ fprintf(tex_file, " %d.", p->scrap);
+ }
+ else
+ fputs("Not referenced.", tex_file);
+ putc('}', tex_file);
+}@}
+
+
+@d Write index of user-specified names
+@{{
+ if (user_names) {
+ fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file);
+ format_user_entry(user_names, tex_file);
+ fputs("\\end{list}", tex_file);
+ }
+ c = source_get();
+}@}
+
+
+@o latex.c
+@{static void format_user_entry(name, tex_file)
+ Name *name;
+ FILE *tex_file;
+{
+ while (name) {
+ format_user_entry(name->llink, tex_file);
+ @<Format a user index entry@>
+ name = name->rlink;
+ }
+}
+@| format_user_entry @}
+
+
+@d Format a user index entry
+@{{
+ Scrap_Node *uses = name->uses;
+ Scrap_Node *defs = name->defs;
+ fprintf(tex_file, "\\item \\hspace{-\\leftmargin}\\verb@@%s@@: ",
+ name->spelling);
+ do {
+ if (uses && (!defs || uses->scrap < defs->scrap)) {
+ fprintf(tex_file, "%d", uses->scrap);
+ uses = uses->next;
+ }
+ else if (defs && (!uses || defs->scrap <= uses->scrap)) {
+ if (uses && defs->scrap == uses->scrap)
+ uses = uses->next;
+ fprintf(tex_file, "\\underline{%d}", defs->scrap);
+ defs = defs->next;
+ }
+ if (uses || defs) fputs(", ", tex_file);
+ } while (uses || defs);
+ fputs(".\n", tex_file);
+}@}
+
+
+
+\section{Writing the Output Files} \label{output-files}
+
+@d Function pro...
+@{void write_files();
+@}
+
+@o output.c
+@{void write_files(files)
+ Name *files;
+{
+ while (files) {
+ write_files(files->llink);
+ @<Write out {\tt files->spelling}@>
+ files = files->rlink;
+ }
+}
+@| write_files @}
+
+Due to the filename restrictions on the PC, just use {\tt nuweb~~~.tmp} as
+the temporary filename. Since files are processed serially, this should
+cause any harm to unix platforms.
+
+@d Write out {\tt files->spelling}
+@{{
+ FILE *temp_file;
+ char temp_name[12]="nuweb~~~.tmp";
+/* sprintf(temp_name, "%s~", files->spelling); */
+ temp_file = fopen(temp_name, "w");
+ if (temp_file) {
+ char indent_chars[500];
+ write_scraps(temp_file, files->defs, 0, indent_chars,
+ files->debug_flag, files->tab_flag, files->indent_flag);
+ fclose(temp_file);
+ if (compare_flag)
+ @<Compare the temp file and the old file@>
+ else
+ rename(temp_name, files->spelling);
+ }
+ else {
+ fprintf(stderr, "%s: can't open %s\n", command_name, temp_name);
+ exit(-1);
+ }
+}@}
+
+
+@d Compare the temp file...
+@{{
+ FILE *old_file = fopen(files->spelling, "r");
+ if (old_file) {
+ int x, y;
+ temp_file = fopen(temp_name, "r");
+ do {
+ x = getc(old_file);
+ y = getc(temp_file);
+ } while (x == y && x != EOF);
+ fclose(old_file);
+ fclose(temp_file);
+ if (x == y)
+ unlink(temp_name);
+ else
+ rename(temp_name, files->spelling);
+ }
+ else
+ rename(temp_name, files->spelling);
+}@}
+
+
+
+\chapter{The Support Routines}
+
+\section{Source Files} \label{source-files}
+
+\subsection{Global Declarations}
+
+We need two routines to handle reading the source files.
+@d Function pro...
+@{void source_open(); /* pass in the name of the source file */
+int source_get(); /* no args; returns the next char or EOF */
+@}
+
+
+There are also two global variables maintained for use in error
+messages and such.
+@d Global...
+@{char *source_name; /* name of the current file */
+int source_line; /* current line in the source file */
+@| source_name source_line @}
+
+\subsection{Local Declarations}
+
+
+@o input.c
+@{static FILE *source_file; /* the current input file */
+static int source_peek;
+static int double_at;
+static int include_depth;
+@| source_peek source_file double_at include_depth @}
+
+
+@o input.c
+@{struct {
+ FILE *file;
+ char *name;
+ int line;
+} stack[10];
+@| stack @}
+
+
+\subsection{Reading a File}
+
+The routine {\tt source\_get} returns the next character from the
+current source file. It notices newlines and keeps the line counter
+{\tt source\_line} up to date. It also catches {\tt EOF} and watches
+for {\tt @@} characters. All other characters are immediately returned.
+@o input.c
+@{int source_get()
+{
+ int c = source_peek;
+ switch (c) {
+ case EOF: @<Handle {\tt EOF}@>
+ return c;
+ case '@@': @<Handle an ``at'' character@>
+ return c;
+ case '\n': source_line++;
+ default: source_peek = getc(source_file);
+ return c;
+ }
+}
+@| source_get @}
+
+
+This whole {\tt @@}~character handling mess is pretty annoying.
+I want to recognize {\tt @@i} so I can handle include files correctly.
+At the same time, it makes sense to recognize illegal {\tt @@}~sequences
+and complain; this avoids ever having to check anywhere else.
+Unfortunately, I need to avoid tripping over the {\tt @@@@}~sequence;
+hence this whole unsatisfactory {\tt double\_at} business.
+@d Handle an ``at''...
+@{{
+ c = getc(source_file);
+ if (double_at) {
+ source_peek = c;
+ double_at = FALSE;
+ c = '@@';
+ }
+ else
+ switch (c) {
+ case 'i': @<Open an include file@>
+ break;
+ case 'f': case 'm': case 'u':
+ case 'd': case 'o': case 'D': case 'O':
+ case '{': case '}': case '<': case '>': case '|':
+ source_peek = c;
+ c = '@@';
+ break;
+ case '@@': source_peek = c;
+ double_at = TRUE;
+ break;
+ default: fprintf(stderr, "%s: bad @@ sequence (%s, line %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+@d Open an include file
+@{{
+ if (include_depth < 10) {
+ char name[100];
+ @<Collect include-file name@>
+ stack[include_depth].name = source_name;
+ stack[include_depth].file = source_file;
+ stack[include_depth].line = source_line + 1;
+ include_depth++;
+ source_line = 1;
+ source_name = save_string(name);
+ source_file = fopen(source_name, "r");
+ if (!source_file) {
+ fprintf(stderr, "%s: can't open include file %s\n",
+ command_name, source_name);
+ exit(-1);
+ }
+ source_peek = getc(source_file);
+ c = source_get();
+ }
+ else {
+ fprintf(stderr, "%s: include nesting too deep (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+@d Collect include-file name
+@{{
+ char *p = name;
+ do
+ c = getc(source_file);
+ while (c == ' ' || c == '\t');
+ while (isgraph(c)) {
+ *p++ = c;
+ c = getc(source_file);
+ }
+ *p = '\0';
+ if (c != '\n') {
+ fprintf(stderr, "%s: unexpected characters after file name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+If an {\tt EOF} is discovered, the current file must be closed and
+input from the next stacked file must be resumed. If no more files are
+on the stack, the {\tt EOF} is returned.
+@d Handle {\tt EOF}
+@{{
+ fclose(source_file);
+ if (include_depth) {
+ include_depth--;
+ source_file = stack[include_depth].file;
+ source_line = stack[include_depth].line;
+ source_name = stack[include_depth].name;
+ source_peek = getc(source_file);
+ c = source_get();
+ }
+}@}
+
+
+\subsection{Opening a File}
+
+The routine {\tt source\_open} takes a file name and tries to open the
+file. If unsuccessful, it complains and halts. Otherwise, it sets
+{\tt source\_name}, {\tt source\_line}, and {\tt double\_at}.
+@o input.c
+@{void source_open(name)
+ char *name;
+{
+ source_file = fopen(name, "r");
+ if (!source_file) {
+ fprintf(stderr, "%s: couldn't open %s\n", command_name, name);
+ exit(-1);
+ }
+ source_name = name;
+ source_line = 1;
+ source_peek = getc(source_file);
+ double_at = FALSE;
+ include_depth = 0;
+}
+@| source_open @}
+
+
+
+
+\section{Scraps} \label{scraps}
+
+
+@o scraps.c
+@{#define SLAB_SIZE 500
+
+typedef struct slab {
+ struct slab *next;
+ char chars[SLAB_SIZE];
+} Slab;
+@| Slab SLAB_SIZE @}
+
+
+@o scraps.c
+@{typedef struct {
+ char *file_name;
+ int file_line;
+ Slab *slab;
+} ScrapEntry;
+@| ScrapEntry @}
+
+@o scraps.c
+@{ScrapEntry *SCRAP[256];
+
+#define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
+
+int scraps;
+@| scraps scrap_array SCRAP @}
+
+
+@d Function pro...
+@{void init_scraps();
+int collect_scrap();
+int write_scraps();
+@}
+
+
+@o scraps.c
+@{void init_scraps()
+{
+ scraps = 1;
+ SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+}
+@| init_scraps @}
+
+
+@o scraps.c
+@{typedef struct {
+ Slab *scrap;
+ int index;
+} Manager;
+@| Manager @}
+
+
+
+@o scraps.c
+@{static void push(c, manager)
+ char c;
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ scrap->chars[index++] = c;
+ if (index == SLAB_SIZE) {
+ Slab *new = (Slab *) arena_getmem(sizeof(Slab));
+ scrap->next = new;
+ manager->scrap = new;
+ index = 0;
+ }
+ manager->index = index;
+}
+@| push @}
+
+@o scraps.c
+@{static void pushs(s, manager)
+ char *s;
+ Manager *manager;
+{
+ while (*s)
+ push(*s++, manager);
+}
+@| pushs @}
+
+
+@o scraps.c
+@{int collect_scrap()
+{
+ Manager writer;
+ @<Create new scrap...@>
+ @<Accumulate scrap and return {\tt scraps++}@>
+}
+@| collect_scrap @}
+
+@d Create new scrap, managed by {\tt writer}
+@{{
+ Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
+ if ((scraps & 255) == 0)
+ SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+ scrap_array(scraps).slab = scrap;
+ scrap_array(scraps).file_name = save_string(source_name);
+ scrap_array(scraps).file_line = source_line;
+ writer.scrap = scrap;
+ writer.index = 0;
+}@}
+
+
+@d Accumulate scrap...
+@{{
+ int c = source_get();
+ while (1) {
+ switch (c) {
+ case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
+ command_name, scrap_array(scraps).file_name,
+ scrap_array(scraps).file_line);
+ exit(-1);
+ case '@@': @<Handle at-sign during scrap accumulation@>
+ break;
+ default: push(c, &writer);
+ c = source_get();
+ break;
+ }
+ }
+}@}
+
+
+@d Handle at-sign during scrap accumulation
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': pushs("@@@@", &writer);
+ c = source_get();
+ break;
+ case '|': @<Collect user-specified index entries@>
+ case '}': push('\0', &writer);
+ return scraps++;
+ case '<': @<Handle macro invocation in scrap@>
+ break;
+ default : fprintf(stderr, "%s: unexpected @@%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+
+@d Collect user-specified index entries
+@{{
+ do {
+ char new_name[100];
+ char *p = new_name;
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c != '@@') {
+ Name *name;
+ do {
+ *p++ = c;
+ c = source_get();
+ } while (c != '@@' && !isspace(c));
+ *p = '\0';
+ name = name_add(&user_names, new_name);
+ if (!name->defs || name->defs->scrap != scraps) {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scraps;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ } while (c != '@@');
+ c = source_get();
+ if (c != '}') {
+ fprintf(stderr, "%s: unexpected @@%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+
+@d Handle macro invocation in scrap
+@{{
+ Name *name = collect_scrap_name();
+ @<Save macro name@>
+ @<Add current scrap to {\tt name}'s uses@>
+ c = source_get();
+}@}
+
+
+@d Save macro name
+@{{
+ char *s = name->spelling;
+ int len = strlen(s) - 1;
+ pushs("@@<", &writer);
+ while (len > 0) {
+ push(*s++, &writer);
+ len--;
+ }
+ if (*s == ' ')
+ pushs("...", &writer);
+ else
+ push(*s, &writer);
+ pushs("@@>", &writer);
+}@}
+
+
+@d Add current scrap to...
+@{{
+ if (!name->uses || name->uses->scrap != scraps) {
+ Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ use->scrap = scraps;
+ use->next = name->uses;
+ name->uses = use;
+ }
+}@}
+
+
+@o scraps.c
+@{static char pop(manager)
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ char c = scrap->chars[index++];
+ if (index == SLAB_SIZE) {
+ manager->scrap = scrap->next;
+ index = 0;
+ }
+ manager->index = index;
+ return c;
+}
+@| pop @}
+
+
+
+@o scraps.c
+@{static Name *pop_scrap_name(manager)
+ Manager *manager;
+{
+ char name[100];
+ char *p = name;
+ int c = pop(manager);
+ while (TRUE) {
+ if (c == '@@')
+ @<Check for end of scrap name and return@>
+ else {
+ *p++ = c;
+ c = pop(manager);
+ }
+ }
+}
+@| pop_scrap_name @}
+
+
+@d Check for end of scrap name...
+@{{
+ c = pop(manager);
+ if (c == '@@') {
+ *p++ = c;
+ c = pop(manager);
+ }
+ else if (c == '>') {
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ else {
+ fprintf(stderr, "%s: found an internal problem (1)\n", command_name);
+ exit(-1);
+ }
+}@}
+
+
+@o scraps.c
+@{int write_scraps(file, defs, global_indent, indent_chars,
+ debug_flag, tab_flag, indent_flag)
+ FILE *file;
+ Scrap_Node *defs;
+ int global_indent;
+ char *indent_chars;
+ char debug_flag;
+ char tab_flag;
+ char indent_flag;
+{
+ int indent = 0;
+ while (defs) {
+ @<Copy {\tt defs->scrap} to {\tt file}@>
+ defs = defs->next;
+ }
+ return indent + global_indent;
+}
+@| write_scraps @}
+
+
+@d Copy {\tt defs->scrap}...
+@{{
+ char c;
+ Manager reader;
+ int line_number = scrap_array(defs->scrap).file_line;
+ @<Insert debugging information if required@>
+ reader.scrap = scrap_array(defs->scrap).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ switch (c) {
+ case '@@': @<Check for macro invocation in scrap@>
+ break;
+ case '\n': putc(c, file);
+ line_number++;
+ @<Insert appropriate indentation@>
+ break;
+ case '\t': @<Handle tab...@>
+ break;
+ default: putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ }
+ c = pop(&reader);
+ }
+}@}
+
+
+@d Insert debugging information if required
+@{if (debug_flag) {
+ fprintf(file, "\n#line %d \"%s\"\n",
+ line_number, scrap_array(defs->scrap).file_name);
+ @<Insert appropr...@>
+}@}
+
+
+@d Insert approp...
+@{{
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+}@}
+
+
+@d Handle tab characters on output
+@{{
+ if (tab_flag)
+ @<Expand tab...@>
+ else {
+ putc('\t', file);
+ indent_chars[global_indent + indent] = '\t';
+ indent++;
+ }
+}@}
+
+
+
+@d Check for macro invocation...
+@{{
+ c = pop(&reader);
+ switch (c) {
+ case '@@': putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ case '<': @<Copy macro into {\tt file}@>
+ @<Insert debugging information if required@>
+ break;
+ default: /* ignore, since we should already have a warning */
+ break;
+ }
+}@}
+
+
+@d Copy macro into...
+@{{
+ Name *name = pop_scrap_name(&reader);
+ if (name->mark) {
+ fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
+ command_name, name->spelling);
+ exit(-1);
+ }
+ if (name->defs) {
+ name->mark = TRUE;
+ indent = write_scraps(file, name->defs, global_indent + indent,
+ indent_chars, debug_flag, tab_flag, indent_flag);
+ indent -= global_indent;
+ name->mark = FALSE;
+ }
+ else if (!tex_flag)
+ fprintf(stderr, "%s: macro never defined <%s>\n",
+ command_name, name->spelling);
+}@}
+
+
+\section{Names} \label{names}
+
+@d Type de...
+@{typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+@| Scrap_Node @}
+
+
+@d Type de...
+@{typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+@| Name @}
+
+@d Global...
+@{Name *file_names;
+Name *macro_names;
+Name *user_names;
+@| file_names macro_names user_names @}
+
+@d Function pro...
+@{Name *collect_file_name();
+Name *collect_macro_name();
+Name *collect_scrap_name();
+Name *name_add();
+Name *prefix_add();
+char *save_string();
+void reverse_lists();
+@}
+
+@o names.c
+@{enum { LESS, GREATER, EQUAL, PREFIX, EXTENSION };
+
+static int compare(x, y)
+ char *x;
+ char *y;
+{
+ int len, result;
+ int xl = strlen(x);
+ int yl = strlen(y);
+ int xp = x[xl - 1] == ' ';
+ int yp = y[yl - 1] == ' ';
+ if (xp) xl--;
+ if (yp) yl--;
+ len = xl < yl ? xl : yl;
+ result = strncmp(x, y, len);
+ if (result < 0) return GREATER;
+ else if (result > 0) return LESS;
+ else if (xl < yl) {
+ if (xp) return EXTENSION;
+ else return LESS;
+ }
+ else if (xl > yl) {
+ if (yp) return PREFIX;
+ else return GREATER;
+ }
+ else return EQUAL;
+}
+@| compare LESS GREATER EQUAL PREFIX EXTENSION @}
+
+
+@o names.c
+@{char *save_string(s)
+ char *s;
+{
+ char *new = (char *) arena_getmem((strlen(s) + 1) * sizeof(char));
+ strcpy(new, s);
+ return new;
+}
+@| save_string @}
+
+@o names.c
+@{Name *prefix_add(root, spelling)
+ Name **root;
+ char *spelling;
+{
+ Name *node = *root;
+ while (node) {
+ switch (compare(node->spelling, spelling)) {
+ case GREATER: root = &node->rlink;
+ break;
+ case LESS: root = &node->llink;
+ break;
+ case EQUAL: return node;
+ case EXTENSION: node->spelling = save_string(spelling);
+ return node;
+ case PREFIX: @<Check for ambiguous prefix@>
+ return node;
+ }
+ node = *root;
+ }
+ @<Create new name entry@>
+}
+@| prefix_add @}
+
+Since a very short prefix might match more than one macro name, I need
+to check for other matches to avoid mistakes. Basically, I simply
+continue the search down {\em both\/} branches of the tree.
+
+@d Check for ambiguous prefix
+@{{
+ if (ambiguous_prefix(node->llink, spelling) ||
+ ambiguous_prefix(node->rlink, spelling))
+ fprintf(stderr,
+ "%s: ambiguous prefix @@<%s...@@> (%s, line %d)\n",
+ command_name, spelling, source_name, source_line);
+}@}
+
+@o names.c
+@{static int ambiguous_prefix(node, spelling)
+ Name *node;
+ char *spelling;
+{
+ while (node) {
+ switch (compare(node->spelling, spelling)) {
+ case GREATER: node = node->rlink;
+ break;
+ case LESS: node = node->llink;
+ break;
+ case EQUAL:
+ case EXTENSION:
+ case PREFIX: return TRUE;
+ }
+ }
+ return FALSE;
+}
+@}
+
+Rob Shillingsburg suggested that I organize the index of
+user-specified identifiers more traditionally; that is, not relying on
+strict {\small ASCII} comparisons via {\tt strcmp}. Ideally, we'd like
+to see the index ordered like this:
+\begin{quote}
+\begin{flushleft}
+aardvark \\
+Adam \\
+atom \\
+Atomic \\
+atoms
+\end{flushleft}
+\end{quote}
+The function {\tt robs\_strcmp} implements the desired predicate.
+
+@o names.c
+@{static int robs_strcmp(x, y)
+ char *x;
+ char *y;
+{
+ char *xx = x;
+ char *yy = y;
+ int xc = toupper(*xx);
+ int yc = toupper(*yy);
+ while (xc == yc && xc) {
+ xx++;
+ yy++;
+ xc = toupper(*xx);
+ yc = toupper(*yy);
+ }
+ if (xc != yc) return xc - yc;
+ xc = *x;
+ yc = *y;
+ while (xc == yc && xc) {
+ x++;
+ y++;
+ xc = *x;
+ yc = *y;
+ }
+ if (isupper(xc) && islower(yc))
+ return xc * 2 - (toupper(yc) * 2 + 1);
+ if (islower(xc) && isupper(yc))
+ return toupper(xc) * 2 + 1 - yc * 2;
+ return xc - yc;
+}
+@| robs_strcmp @}
+
+@o names.c
+@{Name *name_add(root, spelling)
+ Name **root;
+ char *spelling;
+{
+ Name *node = *root;
+ while (node) {
+ int result = robs_strcmp(node->spelling, spelling);
+ if (result > 0)
+ root = &node->llink;
+ else if (result < 0)
+ root = &node->rlink;
+ else
+ return node;
+ node = *root;
+ }
+ @<Create new name entry@>
+}
+@| name_add @}
+
+
+@d Create new name...
+@{{
+ node = (Name *) arena_getmem(sizeof(Name));
+ node->spelling = save_string(spelling);
+ node->mark = FALSE;
+ node->llink = NULL;
+ node->rlink = NULL;
+ node->uses = NULL;
+ node->defs = NULL;
+ node->tab_flag = TRUE;
+ node->indent_flag = TRUE;
+ node->debug_flag = FALSE;
+ *root = node;
+ return node;
+}@}
+
+
+Name terminated by whitespace. Also check for ``per-file'' flags. Keep
+skipping white space until we reach scrap.
+@o names.c
+@{Name *collect_file_name()
+{
+ Name *new_name;
+ char name[100];
+ char *p = name;
+ int start_line = source_line;
+ int c = source_get();
+ while (isspace(c))
+ c = source_get();
+ while (isgraph(c)) {
+ *p++ = c;
+ c = source_get();
+ }
+ if (p == name) {
+ fprintf(stderr, "%s: expected file name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ *p = '\0';
+ new_name = name_add(&file_names, name);
+ @<Handle optional per-file flags@>
+ if (c == '@@' && source_get() == '{')
+ return new_name;
+ else {
+ fprintf(stderr, "%s: expected @@{ after file name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+}
+@| collect_file_name @}
+
+@d Handle optional per-file flags
+@{{
+ while (1) {
+ while (isspace(c))
+ c = source_get();
+ if (c == '-') {
+ c = source_get();
+ do {
+ switch (c) {
+ case 't': new_name->tab_flag = FALSE;
+ break;
+ case 'd': new_name->debug_flag = TRUE;
+ break;
+ case 'i': new_name->indent_flag = FALSE;
+ break;
+ default : fprintf(stderr, "%s: unexpected per-file flag (%s, %d)\n",
+ command_name, source_name, source_line);
+ break;
+ }
+ c = source_get();
+ } while (!isspace(c));
+ }
+ else break;
+ }
+}@}
+
+
+
+Name terminated by \verb+\n+ or \verb+@@{+; but keep skipping until \verb+@@{+
+@o names.c
+@{Name *collect_macro_name()
+{
+ char name[100];
+ char *p = name;
+ int start_line = source_line;
+ int c = source_get();
+ while (isspace(c))
+ c = source_get();
+ while (c != EOF) {
+ switch (c) {
+ case '@@': @<Check for terminating at-sequence and return name@>
+ break;
+ case '\t':
+ case ' ': *p++ = ' ';
+ do
+ c = source_get();
+ while (c == ' ' || c == '\t');
+ break;
+ case '\n': @<Skip until scrap begins, then return name@>
+ default: *p++ = c;
+ c = source_get();
+ break;
+ }
+ }
+ fprintf(stderr, "%s: expected macro name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+}
+@| collect_macro_name @}
+
+
+@d Check for termina...
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': *p++ = c;
+ break;
+ case '{': @<Cleanup and install name@>
+ default: fprintf(stderr,
+ "%s: unexpected @@%c in macro name (%s, %d)\n",
+ command_name, c, source_name, start_line);
+ exit(-1);
+ }
+}@}
+
+
+@d Cleanup and install name
+@{{
+ if (p > name && p[-1] == ' ')
+ p--;
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ if (p == name || name[0] == ' ') {
+ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+}@}
+
+
+@d Skip until scrap...
+@{{
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c == '@@' && source_get() == '{')
+ @<Cleanup and install name@>
+ else {
+ fprintf(stderr, "%s: expected @@{ after macro name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+}@}
+
+
+Terminated by \verb+@@>+
+@o names.c
+@{Name *collect_scrap_name()
+{
+ char name[100];
+ char *p = name;
+ int c = source_get();
+ while (c == ' ' || c == '\t')
+ c = source_get();
+ while (c != EOF) {
+ switch (c) {
+ case '@@': @<Look for end of scrap name and return@>
+ break;
+ case '\t':
+ case ' ': *p++ = ' ';
+ do
+ c = source_get();
+ while (c == ' ' || c == '\t');
+ break;
+ default: if (isgraph(c)) {
+ *p++ = c;
+ c = source_get();
+ }
+ else {
+ fprintf(stderr,
+ "%s: unexpected character in macro name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ break;
+ }
+ }
+ fprintf(stderr, "%s: unexpected end of file (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+}
+@| collect_scrap_name @}
+
+
+@d Look for end of scrap name...
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': *p++ = c;
+ c = source_get();
+ break;
+ case '>': @<Cleanup and install name@>
+ default: fprintf(stderr,
+ "%s: unexpected @@%c in macro name (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+
+@o names.c
+@{static Scrap_Node *reverse(); /* a forward declaration */
+
+void reverse_lists(names)
+ Name *names;
+{
+ while (names) {
+ reverse_lists(names->llink);
+ names->defs = reverse(names->defs);
+ names->uses = reverse(names->uses);
+ names = names->rlink;
+ }
+}
+@| reverse_lists @}
+
+Just for fun, here's a non-recursive version of the traditional list
+reversal code. Note that it reverses the list in place; that is, it
+does no new allocations.
+@o names.c
+@{static Scrap_Node *reverse(a)
+ Scrap_Node *a;
+{
+ if (a) {
+ Scrap_Node *b = a->next;
+ a->next = NULL;
+ while (b) {
+ Scrap_Node *c = b->next;
+ b->next = a;
+ a = b;
+ b = c;
+ }
+ }
+ return a;
+}
+@| reverse @}
+
+
+\section{Searching for Index Entries} \label{search}
+
+Given the array of scraps and a set of index entries, we need to
+search all the scraps for occurences of each entry. The obvious
+approach to this problem would be quite expensive for large documents;
+however, there is an interesting paper describing an efficient
+solution~\cite{aho:75}.
+
+
+@o scraps.c
+@{
+typedef struct name_node {
+ struct name_node *next;
+ Name *name;
+} Name_Node;
+
+typedef struct goto_node {
+ struct goto_node *next; /* next goto node with same depth */
+ struct goto_node *fail;
+ struct move_node *moves;
+ Name_Node *output;
+} Goto_Node;
+
+typedef struct move_node {
+ struct move_node *next;
+ Goto_Node *state;
+ char c;
+} Move_Node;
+@| Goto_Node Move_Node Name_Node @}
+
+@o scraps.c
+@{
+static Goto_Node *root[128];
+static int max_depth;
+static Goto_Node **depths;
+@| root max_depth @}
+
+
+@o scraps.c
+@{static Goto_Node *goto_lookup(c, g)
+ char c;
+ Goto_Node *g;
+{
+ Move_Node *m = g->moves;
+ while (m && m->c != c)
+ m = m->next;
+ if (m)
+ return m->state;
+ else
+ return NULL;
+}
+@| goto_lookup @}
+
+
+\subsection{Building the Automata}
+
+
+@o scraps.c
+@{
+static void build_gotos();
+
+void search()
+{
+ int i;
+ for (i=0; i<128; i++)
+ root[i] = NULL;
+ max_depth = 10;
+ depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
+ for (i=0; i<max_depth; i++)
+ depths[i] = NULL;
+ build_gotos(user_names);
+ @<Build failure functions@>
+ @<Search scraps@>
+}
+@| search @}
+
+
+
+@o scraps.c
+@{static void build_gotos(tree)
+ Name *tree;
+{
+ while (tree) {
+ @<Extend goto graph with {\tt tree->spelling}@>
+ build_gotos(tree->rlink);
+ tree = tree->llink;
+ }
+}
+@| build_gotos @}
+
+@d Extend goto...
+@{{
+ int depth = 2;
+ char *p = tree->spelling;
+ char c = *p++;
+ Goto_Node *q = root[c];
+ if (!q) {
+ q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ root[c] = q;
+ q->moves = NULL;
+ q->fail = NULL;
+ q->moves = NULL;
+ q->output = NULL;
+ q->next = depths[1];
+ depths[1] = q;
+ }
+ while (c = *p++) {
+ Goto_Node *new = goto_lookup(c, q);
+ if (!new) {
+ Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
+ new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ new->moves = NULL;
+ new->fail = NULL;
+ new->moves = NULL;
+ new->output = NULL;
+ new_move->state = new;
+ new_move->c = c;
+ new_move->next = q->moves;
+ q->moves = new_move;
+ if (depth == max_depth) {
+ int i;
+ Goto_Node **new_depths =
+ (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
+ max_depth = 2 * depth;
+ for (i=0; i<depth; i++)
+ new_depths[i] = depths[i];
+ depths = new_depths;
+ for (i=depth; i<max_depth; i++)
+ depths[i] = NULL;
+ }
+ new->next = depths[depth];
+ depths[depth] = new;
+ }
+ q = new;
+ depth++;
+ }
+ q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->output->next = NULL;
+ q->output->name = tree;
+}@}
+
+
+@d Build failure functions
+@{{
+ int depth;
+ for (depth=1; depth<max_depth; depth++) {
+ Goto_Node *r = depths[depth];
+ while (r) {
+ Move_Node *m = r->moves;
+ while (m) {
+ char a = m->c;
+ Goto_Node *s = m->state;
+ Goto_Node *state = r->fail;
+ while (state && !goto_lookup(a, state))
+ state = state->fail;
+ if (state)
+ s->fail = goto_lookup(a, state);
+ else
+ s->fail = root[a];
+ if (s->fail) {
+ Name_Node *p = s->fail->output;
+ while (p) {
+ Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->name = p->name;
+ q->next = s->output;
+ s->output = q;
+ p = p->next;
+ }
+ }
+ m = m->next;
+ }
+ r = r->next;
+ }
+ }
+}@}
+
+
+\subsection{Searching the Scraps}
+
+@d Search scraps
+@{{
+ for (i=1; i<scraps; i++) {
+ char c;
+ Manager reader;
+ Goto_Node *state = NULL;
+ reader.scrap = scrap_array(i).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ while (state && !goto_lookup(c, state))
+ state = state->fail;
+ if (state)
+ state = goto_lookup(c, state);
+ else
+ state = root[c];
+ if (state && state->output) {
+ Name_Node *p = state->output;
+ do {
+ Name *name = p->name;
+ if (!name->uses || name->uses->scrap != i) {
+ Scrap_Node *new_use =
+ (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ new_use->scrap = i;
+ new_use->next = name->uses;
+ name->uses = new_use;
+ }
+ p = p->next;
+ } while (p);
+ }
+ c = pop(&reader);
+ }
+ }
+}@}
+
+
+\section{Memory Management} \label{memory-management}
+
+I manage memory using a simple scheme inspired by Hanson's idea of
+{\em arenas\/}~\cite{hanson:90}.
+Basically, I allocate all the storage required when processing a
+source file (primarily for names and scraps) using calls to
+{\tt arena\_getmem(n)}, where {\tt n} specifies the number of bytes to
+be allocated. When the storage is no longer required, the entire arena
+is freed with a single call to {\tt arena\_free()}. Both operations
+are quite fast.
+@d Function p...
+@{void *arena_getmem();
+void arena_free();
+@}
+
+
+@o arena.c
+@{typedef struct chunk {
+ struct chunk *next;
+ char *limit;
+ char *avail;
+} Chunk;
+@| Chunk @}
+
+
+We define an empty chunk called {\tt first}. The variable {\tt arena} points
+at the current chunk of memory; it's initially pointed at {\tt first}.
+As soon as some storage is required, a ``real'' chunk of memory will
+be allocated and attached to {\tt first->next}; storage will be
+allocated from the new chunk (and later chunks if necessary).
+@o arena.c
+@{Chunk first = { NULL, NULL, NULL };
+Chunk *arena = &first;
+@| first arena @}
+
+
+\subsection{Allocating Memory}
+
+The routine {\tt arena\_getmem(n)} returns a pointer to (at least)
+{\tt n} bytes of memory. Note that {\tt n} is rounded up to ensure
+that returned pointers are always aligned.
+@o arena.c
+@{void *arena_getmem(n)
+ int n;
+{
+ char *q;
+ char *p = arena->avail;
+ n = (n + 3) & ~3; /* ensuring alignment to 4 bytes */
+ q = p + n;
+ if (q <= arena->limit) {
+ arena->avail = q;
+ return p;
+ }
+ @<Find a new chunk of memory@>
+}
+@| arena_getmem @}
+
+
+If the current chunk doesn't have adequate space (at least {\tt n}
+bytes) we examine the rest of the list of chunks (starting at
+{\tt arena->next}) looking for a chunk with adequate space. If {\tt n}
+is very large, we may not find it right away or we may not find a
+suitable chunk at all.
+@d Find a new chunk...
+@{{
+ Chunk *ap = arena;
+ Chunk *np = ap->next;
+ while (np) {
+ char *v = sizeof(Chunk) + (char *) np;
+ if (v + n <= np->limit) {
+ np->avail = v + n;
+ arena = np;
+ return v;
+ }
+ ap = np;
+ np = ap->next;
+ }
+ @<Allocate a new chunk of memory@>
+}@}
+
+
+If there isn't a suitable chunk of memory on the free list, then we
+need to allocate a new one.
+@d Allocate a new ch...
+@{{
+ int m = n + 10000;
+ np = (Chunk *) malloc(m);
+ np->limit = m + (char *) np;
+ np->avail = n + sizeof(Chunk) + (char *) np;
+ np->next = NULL;
+ ap->next = np;
+ arena = np;
+ return sizeof(Chunk) + (char *) np;
+}@}
+
+
+\subsection{Freeing Memory}
+
+To free all the memory in the arena, we need only point {\tt arena}
+back to the first empty chunk.
+@o arena.c
+@{void arena_free()
+{
+ arena = &first;
+}
+@| arena_free @}
+
+
+\chapter{Indices} \label{indices}
+
+Three sets of indices can be created automatically: an index of file
+names, an index of macro names, and an index of user-specified
+identifiers. An index entry includes the name of the entry, where it
+was defined, and where it was referenced.
+
+
+
+\section{Files}
+
+@f
+
+\section{Macros}
+
+@m
+
+\section{Identifiers}
+
+Knuth prints his index of indentifiers in a two-column format.
+I could force this automatically by emitting the \verb|\twocolumn|
+command; but this has the side effect of forcing a new page.
+Therefore, it seems better to leave it this up to the user.
+
+@u
+
+\bibliographystyle{plain}
+\bibliography{literate}
+
+\end{document}
diff --git a/web/nuweb/msdos/output.c b/web/nuweb/msdos/output.c
new file mode 100644
index 0000000000..150722ca71
--- /dev/null
+++ b/web/nuweb/msdos/output.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!0)
+#endif
+typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+
+int tex_flag; /* if FALSE, don't emit the .tex file */
+int output_flag; /* if FALSE, don't emit the output files */
+int compare_flag; /* if FALSE, overwrite without comparison */
+char *command_name;
+char *source_name; /* name of the current file */
+int source_line; /* current line in the source file */
+Name *file_names;
+Name *macro_names;
+Name *user_names;
+
+void pass1();
+void write_tex();
+void write_files();
+void source_open(); /* pass in the name of the source file */
+int source_get(); /* no args; returns the next char or EOF */
+void init_scraps();
+int collect_scrap();
+int write_scraps();
+Name *collect_file_name();
+Name *collect_macro_name();
+Name *collect_scrap_name();
+Name *name_add();
+Name *prefix_add();
+char *save_string();
+void reverse_lists();
+void *arena_getmem();
+void arena_free();
+
+
+void write_files(files)
+ Name *files;
+{
+ while (files) {
+ write_files(files->llink);
+ {
+ FILE *temp_file;
+ char temp_name[12]="nuweb~~~.tmp";
+ /* sprintf(temp_name, "%s~", files->spelling); */
+ temp_file = fopen(temp_name, "w");
+ if (temp_file) {
+ char indent_chars[500];
+ write_scraps(temp_file, files->defs, 0, indent_chars,
+ files->debug_flag, files->tab_flag, files->indent_flag);
+ fclose(temp_file);
+ if (compare_flag)
+ {
+ FILE *old_file = fopen(files->spelling, "r");
+ if (old_file) {
+ int x, y;
+ temp_file = fopen(temp_name, "r");
+ do {
+ x = getc(old_file);
+ y = getc(temp_file);
+ } while (x == y && x != EOF);
+ fclose(old_file);
+ fclose(temp_file);
+ if (x == y)
+ unlink(temp_name);
+ else
+ rename(temp_name, files->spelling);
+ }
+ else
+ rename(temp_name, files->spelling);
+ }
+ else
+ rename(temp_name, files->spelling);
+ }
+ else {
+ fprintf(stderr, "%s: can't open %s\n", command_name, temp_name);
+ exit(-1);
+ }
+ }
+ files = files->rlink;
+ }
+}
diff --git a/web/nuweb/msdos/pass1.c b/web/nuweb/msdos/pass1.c
new file mode 100644
index 0000000000..1c8edcf9c4
--- /dev/null
+++ b/web/nuweb/msdos/pass1.c
@@ -0,0 +1,116 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!0)
+#endif
+typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+
+int tex_flag; /* if FALSE, don't emit the .tex file */
+int output_flag; /* if FALSE, don't emit the output files */
+int compare_flag; /* if FALSE, overwrite without comparison */
+char *command_name;
+char *source_name; /* name of the current file */
+int source_line; /* current line in the source file */
+Name *file_names;
+Name *macro_names;
+Name *user_names;
+
+void pass1();
+void write_tex();
+void write_files();
+void source_open(); /* pass in the name of the source file */
+int source_get(); /* no args; returns the next char or EOF */
+void init_scraps();
+int collect_scrap();
+int write_scraps();
+Name *collect_file_name();
+Name *collect_macro_name();
+Name *collect_scrap_name();
+Name *name_add();
+Name *prefix_add();
+char *save_string();
+void reverse_lists();
+void *arena_getmem();
+void arena_free();
+
+
+void pass1(file_name)
+ char *file_name;
+{
+ source_open(file_name);
+ init_scraps();
+ macro_names = NULL;
+ file_names = NULL;
+ user_names = NULL;
+ {
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@')
+ {
+ c = source_get();
+ switch (c) {
+ case 'O':
+ case 'o': {
+ Name *name = collect_file_name(); /* returns a pointer to the name entry */
+ int scrap = collect_scrap(); /* returns an index to the scrap */
+ {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scrap;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ break;
+ case 'D':
+ case 'd': {
+ Name *name = collect_macro_name();
+ int scrap = collect_scrap();
+ {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scrap;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ break;
+ case '@':
+ case 'u':
+ case 'm':
+ case 'f': /* ignore during this pass */
+ break;
+ default: fprintf(stderr,
+ "%s: unexpected @ sequence ignored (%s, line %d)\n",
+ command_name, source_name, source_line);
+ break;
+ }
+ }
+ c = source_get();
+ }
+ }
+ if (tex_flag)
+ search();
+ {
+ reverse_lists(file_names);
+ reverse_lists(macro_names);
+ reverse_lists(user_names);
+ }
+}
diff --git a/web/nuweb/msdos/readme b/web/nuweb/msdos/readme
new file mode 100644
index 0000000000..605ae53c90
--- /dev/null
+++ b/web/nuweb/msdos/readme
@@ -0,0 +1,28 @@
+Here's an intermediate version of nuweb.
+I've simply bundled up the web source (nuweb.w),
+the generated .c files, the generated nuweb.tex file,
+and the assorted auxiliary files for latex'ing.
+
+The "user's manual" and sales pitch is in Chapter 1 of the
+web. If you latex up the nuweb.tex and print pages 0-6
+(or the whole thing), you can read about it.
+
+To actually build the thing, first
+
+ touch nuweb.tex
+
+Then
+
+ make
+
+should build an executable file called "nuweb".
+After that, you should be able to use the makefile
+to control everything very nicely.
+
+If you have questions or comments
+(or just want the latest), please let me know.
+I'm going to continue working on the documentation for
+at least a week or two. Eventually, I'll put it out
+for ftp access.
+
+My e-mail address is preston@cs.rice.edu
diff --git a/web/nuweb/msdos/readme.txt b/web/nuweb/msdos/readme.txt
new file mode 100644
index 0000000000..21916808cf
--- /dev/null
+++ b/web/nuweb/msdos/readme.txt
@@ -0,0 +1,14 @@
+This is a direct installation of Preston Briggs' Nuweb Program, Version
+0.6 for PC. It is compiled with the DJGPP GCC Compiler and combined
+with the GO32 extender. Up to now I recognized only the following
+restrictions:
+ - Due to the GO32 extender it will not run under windows. A new go32
+ is in the making with DMI support (will run in windows dos box).
+ - The program only will run on 386/486 PCs
+ - The output filenames specified with the @o command should conform
+ with the DOS filename restrictions.
+ - I made a small change to the scrap 62 to fix temporary file name
+ foulup in PCs. Now any regular dos filename should work.
+ - Also included nuweb.1 man page. On the pc use either groff or
+ cawf to process it.
+Osman Buyukisik
diff --git a/web/nuweb/msdos/scraps.c b/web/nuweb/msdos/scraps.c
new file mode 100644
index 0000000000..ecc35ea856
--- /dev/null
+++ b/web/nuweb/msdos/scraps.c
@@ -0,0 +1,542 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!0)
+#endif
+typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+
+int tex_flag; /* if FALSE, don't emit the .tex file */
+int output_flag; /* if FALSE, don't emit the output files */
+int compare_flag; /* if FALSE, overwrite without comparison */
+char *command_name;
+char *source_name; /* name of the current file */
+int source_line; /* current line in the source file */
+Name *file_names;
+Name *macro_names;
+Name *user_names;
+
+void pass1();
+void write_tex();
+void write_files();
+void source_open(); /* pass in the name of the source file */
+int source_get(); /* no args; returns the next char or EOF */
+void init_scraps();
+int collect_scrap();
+int write_scraps();
+Name *collect_file_name();
+Name *collect_macro_name();
+Name *collect_scrap_name();
+Name *name_add();
+Name *prefix_add();
+char *save_string();
+void reverse_lists();
+void *arena_getmem();
+void arena_free();
+
+
+#define SLAB_SIZE 500
+
+typedef struct slab {
+ struct slab *next;
+ char chars[SLAB_SIZE];
+} Slab;
+typedef struct {
+ char *file_name;
+ int file_line;
+ Slab *slab;
+} ScrapEntry;
+ScrapEntry *SCRAP[256];
+
+#define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
+
+int scraps;
+void init_scraps()
+{
+ scraps = 1;
+ SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+}
+typedef struct {
+ Slab *scrap;
+ int index;
+} Manager;
+static void push(c, manager)
+ char c;
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ scrap->chars[index++] = c;
+ if (index == SLAB_SIZE) {
+ Slab *new = (Slab *) arena_getmem(sizeof(Slab));
+ scrap->next = new;
+ manager->scrap = new;
+ index = 0;
+ }
+ manager->index = index;
+}
+static void pushs(s, manager)
+ char *s;
+ Manager *manager;
+{
+ while (*s)
+ push(*s++, manager);
+}
+int collect_scrap()
+{
+ Manager writer;
+ {
+ Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
+ if ((scraps & 255) == 0)
+ SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+ scrap_array(scraps).slab = scrap;
+ scrap_array(scraps).file_name = save_string(source_name);
+ scrap_array(scraps).file_line = source_line;
+ writer.scrap = scrap;
+ writer.index = 0;
+ }
+ {
+ int c = source_get();
+ while (1) {
+ switch (c) {
+ case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
+ command_name, scrap_array(scraps).file_name,
+ scrap_array(scraps).file_line);
+ exit(-1);
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': pushs("@@", &writer);
+ c = source_get();
+ break;
+ case '|': {
+ do {
+ char new_name[100];
+ char *p = new_name;
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c != '@') {
+ Name *name;
+ do {
+ *p++ = c;
+ c = source_get();
+ } while (c != '@' && !isspace(c));
+ *p = '\0';
+ name = name_add(&user_names, new_name);
+ if (!name->defs || name->defs->scrap != scraps) {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scraps;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ } while (c != '@');
+ c = source_get();
+ if (c != '}') {
+ fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+ }
+ case '}': push('\0', &writer);
+ return scraps++;
+ case '<': {
+ Name *name = collect_scrap_name();
+ {
+ char *s = name->spelling;
+ int len = strlen(s) - 1;
+ pushs("@<", &writer);
+ while (len > 0) {
+ push(*s++, &writer);
+ len--;
+ }
+ if (*s == ' ')
+ pushs("...", &writer);
+ else
+ push(*s, &writer);
+ pushs("@>", &writer);
+ }
+ {
+ if (!name->uses || name->uses->scrap != scraps) {
+ Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ use->scrap = scraps;
+ use->next = name->uses;
+ name->uses = use;
+ }
+ }
+ c = source_get();
+ }
+ break;
+ default : fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+ }
+ break;
+ default: push(c, &writer);
+ c = source_get();
+ break;
+ }
+ }
+ }
+}
+static char pop(manager)
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ char c = scrap->chars[index++];
+ if (index == SLAB_SIZE) {
+ manager->scrap = scrap->next;
+ index = 0;
+ }
+ manager->index = index;
+ return c;
+}
+static Name *pop_scrap_name(manager)
+ Manager *manager;
+{
+ char name[100];
+ char *p = name;
+ int c = pop(manager);
+ while (TRUE) {
+ if (c == '@')
+ {
+ c = pop(manager);
+ if (c == '@') {
+ *p++ = c;
+ c = pop(manager);
+ }
+ else if (c == '>') {
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ else {
+ fprintf(stderr, "%s: found an internal problem (1)\n", command_name);
+ exit(-1);
+ }
+ }
+ else {
+ *p++ = c;
+ c = pop(manager);
+ }
+ }
+}
+int write_scraps(file, defs, global_indent, indent_chars,
+ debug_flag, tab_flag, indent_flag)
+ FILE *file;
+ Scrap_Node *defs;
+ int global_indent;
+ char *indent_chars;
+ char debug_flag;
+ char tab_flag;
+ char indent_flag;
+{
+ int indent = 0;
+ while (defs) {
+ {
+ char c;
+ Manager reader;
+ int line_number = scrap_array(defs->scrap).file_line;
+ if (debug_flag) {
+ fprintf(file, "\n#line %d \"%s\"\n",
+ line_number, scrap_array(defs->scrap).file_name);
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ }
+ reader.scrap = scrap_array(defs->scrap).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ switch (c) {
+ case '@': {
+ c = pop(&reader);
+ switch (c) {
+ case '@': putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ case '<': {
+ Name *name = pop_scrap_name(&reader);
+ if (name->mark) {
+ fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
+ command_name, name->spelling);
+ exit(-1);
+ }
+ if (name->defs) {
+ name->mark = TRUE;
+ indent = write_scraps(file, name->defs, global_indent + indent,
+ indent_chars, debug_flag, tab_flag, indent_flag);
+ indent -= global_indent;
+ name->mark = FALSE;
+ }
+ else if (!tex_flag)
+ fprintf(stderr, "%s: macro never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ if (debug_flag) {
+ fprintf(file, "\n#line %d \"%s\"\n",
+ line_number, scrap_array(defs->scrap).file_name);
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ }
+ break;
+ default: /* ignore, since we should already have a warning */
+ break;
+ }
+ }
+ break;
+ case '\n': putc(c, file);
+ line_number++;
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ break;
+ case '\t': {
+ if (tab_flag)
+ {
+ int delta = 8 - (indent % 8);
+ indent += delta;
+ while (delta > 0) {
+ putc(' ', file);
+ delta--;
+ }
+ }
+ else {
+ putc('\t', file);
+ indent_chars[global_indent + indent] = '\t';
+ indent++;
+ }
+ }
+ break;
+ default: putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ }
+ c = pop(&reader);
+ }
+ }
+ defs = defs->next;
+ }
+ return indent + global_indent;
+}
+
+typedef struct name_node {
+ struct name_node *next;
+ Name *name;
+} Name_Node;
+
+typedef struct goto_node {
+ struct goto_node *next; /* next goto node with same depth */
+ struct goto_node *fail;
+ struct move_node *moves;
+ Name_Node *output;
+} Goto_Node;
+
+typedef struct move_node {
+ struct move_node *next;
+ Goto_Node *state;
+ char c;
+} Move_Node;
+
+static Goto_Node *root[128];
+static int max_depth;
+static Goto_Node **depths;
+static Goto_Node *goto_lookup(c, g)
+ char c;
+ Goto_Node *g;
+{
+ Move_Node *m = g->moves;
+ while (m && m->c != c)
+ m = m->next;
+ if (m)
+ return m->state;
+ else
+ return NULL;
+}
+
+static void build_gotos();
+
+void search()
+{
+ int i;
+ for (i=0; i<128; i++)
+ root[i] = NULL;
+ max_depth = 10;
+ depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
+ for (i=0; i<max_depth; i++)
+ depths[i] = NULL;
+ build_gotos(user_names);
+ {
+ int depth;
+ for (depth=1; depth<max_depth; depth++) {
+ Goto_Node *r = depths[depth];
+ while (r) {
+ Move_Node *m = r->moves;
+ while (m) {
+ char a = m->c;
+ Goto_Node *s = m->state;
+ Goto_Node *state = r->fail;
+ while (state && !goto_lookup(a, state))
+ state = state->fail;
+ if (state)
+ s->fail = goto_lookup(a, state);
+ else
+ s->fail = root[a];
+ if (s->fail) {
+ Name_Node *p = s->fail->output;
+ while (p) {
+ Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->name = p->name;
+ q->next = s->output;
+ s->output = q;
+ p = p->next;
+ }
+ }
+ m = m->next;
+ }
+ r = r->next;
+ }
+ }
+ }
+ {
+ for (i=1; i<scraps; i++) {
+ char c;
+ Manager reader;
+ Goto_Node *state = NULL;
+ reader.scrap = scrap_array(i).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ while (state && !goto_lookup(c, state))
+ state = state->fail;
+ if (state)
+ state = goto_lookup(c, state);
+ else
+ state = root[c];
+ if (state && state->output) {
+ Name_Node *p = state->output;
+ do {
+ Name *name = p->name;
+ if (!name->uses || name->uses->scrap != i) {
+ Scrap_Node *new_use =
+ (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ new_use->scrap = i;
+ new_use->next = name->uses;
+ name->uses = new_use;
+ }
+ p = p->next;
+ } while (p);
+ }
+ c = pop(&reader);
+ }
+ }
+ }
+}
+static void build_gotos(tree)
+ Name *tree;
+{
+ while (tree) {
+ {
+ int depth = 2;
+ char *p = tree->spelling;
+ char c = *p++;
+ Goto_Node *q = root[c];
+ if (!q) {
+ q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ root[c] = q;
+ q->moves = NULL;
+ q->fail = NULL;
+ q->moves = NULL;
+ q->output = NULL;
+ q->next = depths[1];
+ depths[1] = q;
+ }
+ while (c = *p++) {
+ Goto_Node *new = goto_lookup(c, q);
+ if (!new) {
+ Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
+ new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ new->moves = NULL;
+ new->fail = NULL;
+ new->moves = NULL;
+ new->output = NULL;
+ new_move->state = new;
+ new_move->c = c;
+ new_move->next = q->moves;
+ q->moves = new_move;
+ if (depth == max_depth) {
+ int i;
+ Goto_Node **new_depths =
+ (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
+ max_depth = 2 * depth;
+ for (i=0; i<depth; i++)
+ new_depths[i] = depths[i];
+ depths = new_depths;
+ for (i=depth; i<max_depth; i++)
+ depths[i] = NULL;
+ }
+ new->next = depths[depth];
+ depths[depth] = new;
+ }
+ q = new;
+ depth++;
+ }
+ q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->output->next = NULL;
+ q->output->name = tree;
+ }
+ build_gotos(tree->rlink);
+ tree = tree->llink;
+ }
+}
diff --git a/web/nuweb/nuweb0.87b/Makefile b/web/nuweb/nuweb0.87b/Makefile
new file mode 100644
index 0000000000..38b337e475
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/Makefile
@@ -0,0 +1,63 @@
+CC = cc
+
+CFLAGS = -O
+
+TARGET = nuweb
+VERSION = 0.87b
+
+OBJS = main.o pass1.o latex.o html.o output.o input.o scraps.o names.o \
+ arena.o global.o
+
+SRCS = main.c pass1.c latex.c html.c output.c input.c scraps.c names.c \
+ arena.c global.c
+
+.SUFFIXES: .dvi .tex .w .hw
+
+.w.tex:
+ nuweb $*.w
+
+.hw.tex:
+ nuweb $*.hw
+
+.tex.dvi:
+ latex $*.tex
+
+.w.dvi:
+ $(MAKE) $*.tex
+ $(MAKE) $*.dvi
+
+all:
+ $(MAKE) $(TARGET).tex
+ $(MAKE) $(TARGET)
+
+shar: $(TARGET)doc.tex
+ shar Makefile README literate.bib nuweb.w \
+ $(TARGET)doc.tex $(SRCS) global.h \
+ > $(TARGET)$(VERSION).sh
+
+tar: $(TARGET)doc.tex
+ tar -cf $(TARGET)$(VERSION).tar Makefile README literate.bib nuweb.w \
+ $(TARGET)doc.tex $(SRCS) global.h
+
+$(TARGET)doc.tex: $(TARGET).tex
+ sed 's/\\showcodetrue/\\showcodefalse/' $(TARGET).tex > $@
+
+clean:
+ -rm -f *.tex *.log *.dvi *~ *.blg *.lint
+
+veryclean:
+ -rm -f *.o *.c *.h *.tex *.log *.dvi *~ *.blg *.lint
+
+view: $(TARGET).dvi
+ xdvi $(TARGET).dvi
+
+print: $(TARGET).dvi
+ lpr -d $(TARGET).dvi
+
+lint:
+ lint $(SRCS) > nuweb.lint
+
+$(OBJS): global.h
+
+$(TARGET): $(OBJS)
+ $(CC) -o $(TARGET) $(OBJS)
diff --git a/web/nuweb/nuweb0.87b/README b/web/nuweb/nuweb0.87b/README
new file mode 100644
index 0000000000..93c08f3262
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/README
@@ -0,0 +1,36 @@
+Here's an intermediate version of nuweb. I've simply bundled up the
+web source (nuweb.w), the generated .c files, an abbreviated nuweb.tex
+file, and the assorted auxiliary files for latex'ing.
+
+Note that it's still not completely portable to every system without
+change. In particular, it expect file-names to use '/' to delimit
+directories and it still thinks tab stops are set every eight spaces.
+It also uses tempnam() which may not be available everywhere.
+tmpnam() might be made to work in some systems. If all else fails,
+just use some adequately unlikely filename.
+
+To print the documentation, you must first run latex on the file
+nuwebdoc.tex. To fix up all the citations, you'll need several runs.
+
+ latex nuwebdoc
+ bibtex nuwebdoc
+ latex nuwebdoc
+ latex nuwebdoc
+
+Note that the distributed nuwebdoc.tex is basically Chapter 1 of the
+complete nuweb.tex generated by running nuweb against itself.
+
+To actually build the nuweb executable, type "make nuweb" which should build
+an executable file called "nuweb". After that, you should be able to
+use the makefile to control everything very nicely.
+
+To view the nuweb sources using an HTML viewer, copy nuweb.w to
+nuweb.hw, and then add the html document-style option to nuweb.hw.
+After producing the LaTeX source file nuweb.tex, convert it to HTML
+using LaTeX2HTML.
+
+If you have questions or comments (or just want the latest version),
+please let me know. I expect to continue working on the documentation
+for quite a while.
+
+My e-mail address is preston@cs.rice.edu
diff --git a/web/nuweb/nuweb0.87b/arena.c b/web/nuweb/nuweb0.87b/arena.c
new file mode 100644
index 0000000000..09224f21db
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/arena.c
@@ -0,0 +1,48 @@
+#include "global.h"
+typedef struct chunk {
+ struct chunk *next;
+ char *limit;
+ char *avail;
+} Chunk;
+static Chunk first = { NULL, NULL, NULL };
+static Chunk *arena = &first;
+void *arena_getmem(n)
+ size_t n;
+{
+ char *q;
+ char *p = arena->avail;
+ n = (n + 7) & ~7; /* ensuring alignment to 8 bytes */
+ q = p + n;
+ if (q <= arena->limit) {
+ arena->avail = q;
+ return p;
+ }
+ {
+ Chunk *ap = arena;
+ Chunk *np = ap->next;
+ while (np) {
+ char *v = sizeof(Chunk) + (char *) np;
+ if (v + n <= np->limit) {
+ np->avail = v + n;
+ arena = np;
+ return v;
+ }
+ ap = np;
+ np = ap->next;
+ }
+ {
+ size_t m = n + 10000;
+ np = (Chunk *) malloc(m);
+ np->limit = m + (char *) np;
+ np->avail = n + sizeof(Chunk) + (char *) np;
+ np->next = NULL;
+ ap->next = np;
+ arena = np;
+ return sizeof(Chunk) + (char *) np;
+ }
+ }
+}
+void arena_free()
+{
+ arena = &first;
+}
diff --git a/web/nuweb/nuweb0.87b/global.c b/web/nuweb/nuweb0.87b/global.c
new file mode 100644
index 0000000000..6c6e872de8
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/global.c
@@ -0,0 +1,15 @@
+#include "global.h"
+int tex_flag = TRUE;
+int html_flag = FALSE;
+int output_flag = TRUE;
+int compare_flag = TRUE;
+int verbose_flag = FALSE;
+int number_flag = FALSE;
+char *command_name = NULL;
+char *source_name = NULL;
+int source_line = 0;
+int already_warned = 0;
+Name *file_names = NULL;
+Name *macro_names = NULL;
+Name *user_names = NULL;
+
diff --git a/web/nuweb/nuweb0.87b/global.h b/web/nuweb/nuweb0.87b/global.h
new file mode 100644
index 0000000000..c811c5a8b7
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/global.h
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+
+extern int tex_flag; /* if FALSE, don't emit the documentation file */
+extern int html_flag; /* if TRUE, emit HTML instead of LaTeX scraps. */
+extern int output_flag; /* if FALSE, don't emit the output files */
+extern int compare_flag; /* if FALSE, overwrite without comparison */
+extern int verbose_flag; /* if TRUE, write progress information */
+extern int number_flag; /* if TRUE, use a sequential numbering scheme */
+extern char *command_name;
+extern char *source_name; /* name of the current file */
+extern int source_line; /* current line in the source file */
+extern int already_warned;
+extern Name *file_names;
+extern Name *macro_names;
+extern Name *user_names;
+
+extern void pass1();
+extern void write_tex();
+extern void write_html();
+extern void write_files();
+extern void source_open(); /* pass in the name of the source file */
+extern int source_get(); /* no args; returns the next char or EOF */
+extern void init_scraps();
+extern int collect_scrap();
+extern int write_scraps();
+extern void write_scrap_ref();
+extern void write_single_scrap_ref();
+extern void collect_numbers();
+extern Name *collect_file_name();
+extern Name *collect_macro_name();
+extern Name *collect_scrap_name();
+extern Name *name_add();
+extern Name *prefix_add();
+extern char *save_string();
+extern void reverse_lists();
+extern void search();
+extern void *arena_getmem();
+extern void arena_free();
+
diff --git a/web/nuweb/nuweb0.87b/html.c b/web/nuweb/nuweb0.87b/html.c
new file mode 100644
index 0000000000..b48a61e95e
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/html.c
@@ -0,0 +1,335 @@
+#include "global.h"
+static void copy_scrap(); /* formats the body of a scrap */
+static void display_scrap_ref(); /* formats a scrap reference */
+static void display_scrap_numbers(); /* formats a list of scrap numbers */
+static void print_scrap_numbers(); /* pluralizes scrap formats list */
+static void format_entry(); /* formats an index entry */
+static void format_user_entry();
+void write_html(file_name, html_name)
+ char *file_name;
+ char *html_name;
+{
+ FILE *html_file = fopen(html_name, "w");
+ if (html_file) {
+ if (verbose_flag)
+ fprintf(stderr, "writing %s\n", html_name);
+ source_open(file_name);
+ {
+ int scraps = 1;
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@')
+ {
+ c = source_get();
+ switch (c) {
+ case 'O':
+ case 'o': {
+ Name *name = collect_file_name();
+ {
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<pre>\n", html_file);
+ }
+ fputs("<a name=\"nuweb", html_file);
+ write_single_scrap_ref(html_file, scraps);
+ fprintf(html_file, "\"><code>\"%s\"</code> ", name->spelling);
+ write_single_scrap_ref(html_file, scraps);
+ fputs("</a> =\n", html_file);
+
+ scraps++;
+ {
+ copy_scrap(html_file);
+ fputs("&lt;&gt;</pre>\n", html_file);
+ }
+ {
+ if (name->defs->next) {
+ fputs("File defined by ", html_file);
+ print_scrap_numbers(html_file, name->defs);
+ fputs("<br>\n", html_file);
+ }
+ }
+ {
+ fputs("\\end{rawhtml}\n", html_file);
+ c = source_get(); /* Get rid of current at command. */
+ }
+ }
+ break;
+ case 'D':
+ case 'd': {
+ Name *name = collect_macro_name();
+ {
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<pre>\n", html_file);
+ }
+ fputs("<a name=\"nuweb", html_file);
+ write_single_scrap_ref(html_file, scraps);
+ fprintf(html_file, "\">&lt;%s ", name->spelling);
+ write_single_scrap_ref(html_file, scraps);
+ fputs("&gt;</a> =\n", html_file);
+
+ scraps++;
+ {
+ copy_scrap(html_file);
+ fputs("&lt;&gt;</pre>\n", html_file);
+ }
+ {
+ if (name->defs->next) {
+ fputs("Macro defined by ", html_file);
+ print_scrap_numbers(html_file, name->defs);
+ fputs("<br>\n", html_file);
+ }
+ }
+ {
+ if (name->uses) {
+ fputs("Macro referenced in ", html_file);
+ print_scrap_numbers(html_file, name->uses);
+ }
+ else {
+ fputs("Macro never referenced.\n", html_file);
+ fprintf(stderr, "%s: <%s> never referenced.\n",
+ command_name, name->spelling);
+ }
+ fputs("<br>\n", html_file);
+ }
+ {
+ fputs("\\end{rawhtml}\n", html_file);
+ c = source_get(); /* Get rid of current at command. */
+ }
+ }
+ break;
+ case 'f': {
+ if (file_names) {
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<dl compact>\n", html_file);
+ format_entry(file_names, html_file, TRUE);
+ fputs("</dl>\n", html_file);
+ fputs("\\end{rawhtml}\n", html_file);
+ }
+ c = source_get();
+ }
+ break;
+ case 'm': {
+ if (macro_names) {
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<dl compact>\n", html_file);
+ format_entry(macro_names, html_file, FALSE);
+ fputs("</dl>\n", html_file);
+ fputs("\\end{rawhtml}\n", html_file);
+ }
+ c = source_get();
+ }
+ break;
+ case 'u': {
+ if (user_names) {
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<dl compact>\n", html_file);
+ format_user_entry(user_names, html_file);
+ fputs("</dl>\n", html_file);
+ fputs("\\end{rawhtml}\n", html_file);
+ }
+ c = source_get();
+ }
+ break;
+ case '@': putc(c, html_file);
+ default: c = source_get();
+ break;
+ }
+ }
+ else {
+ putc(c, html_file);
+ c = source_get();
+ }
+ }
+ }
+ fclose(html_file);
+ }
+ else
+ fprintf(stderr, "%s: can't open %s\n", command_name, html_name);
+}
+static void display_scrap_ref(html_file, num)
+ FILE *html_file;
+ int num;
+{
+ fputs("<a href=\"#nuweb", html_file);
+ write_single_scrap_ref(html_file, num);
+ fputs("\">", html_file);
+ write_single_scrap_ref(html_file, num);
+ fputs("</a>", html_file);
+}
+static void display_scrap_numbers(html_file, scraps)
+ FILE *html_file;
+ Scrap_Node *scraps;
+{
+ display_scrap_ref(html_file, scraps->scrap);
+ scraps = scraps->next;
+ while (scraps) {
+ fputs(", ", html_file);
+ display_scrap_ref(html_file, scraps->scrap);
+ scraps = scraps->next;
+ }
+}
+static void print_scrap_numbers(html_file, scraps)
+ FILE *html_file;
+ Scrap_Node *scraps;
+{
+ fputs("scrap", html_file);
+ if (scraps->next) fputc('s', html_file);
+ fputc(' ', html_file);
+ display_scrap_numbers(html_file, scraps);
+ fputs(".\n", html_file);
+}
+static void copy_scrap(file)
+ FILE *file;
+{
+ int indent = 0;
+ int c = source_get();
+ while (1) {
+ switch (c) {
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': fputc(c, file);
+ break;
+ case '|': {
+ do {
+ do
+ c = source_get();
+ while (c != '@');
+ c = source_get();
+ } while (c != '}');
+ }
+ case '}': return;
+ case '<': {
+ Name *name = collect_scrap_name();
+ fprintf(file, "&lt;%s ", name->spelling);
+ if (name->defs)
+ {
+ Scrap_Node *p = name->defs;
+ display_scrap_ref(file, p->scrap);
+ if (p->next)
+ fputs(", ... ", file);
+ }
+ else {
+ putc('?', file);
+ fprintf(stderr, "%s: scrap never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ fputs("&gt;", file);
+ }
+ break;
+ default: /* ignore these since pass1 will have warned about them */
+ break;
+ }
+ }
+ break;
+ case '<' : fputs("&lt;", file);
+ indent++;
+ break;
+ case '>' : fputs("&gt;", file);
+ indent++;
+ break;
+ case '&' : fputs("&amp;", file);
+ indent++;
+ break;
+ case '\n': fputc(c, file);
+ indent = 0;
+ break;
+ case '\t': {
+ int delta = 8 - (indent % 8);
+ indent += delta;
+ while (delta > 0) {
+ putc(' ', file);
+ delta--;
+ }
+ }
+ break;
+ default: putc(c, file);
+ indent++;
+ break;
+ }
+ c = source_get();
+ }
+}
+static void format_entry(name, html_file, file_flag)
+ Name *name;
+ FILE *html_file;
+ int file_flag;
+{
+ while (name) {
+ format_entry(name->llink, html_file, file_flag);
+ {
+ fputs("<dt> ", html_file);
+ if (file_flag) {
+ fprintf(html_file, "<code>\"%s\"</code>\n<dd> ", name->spelling);
+ {
+ fputs("Defined by ", html_file);
+ print_scrap_numbers(html_file, name->defs);
+ }
+ }
+ else {
+ fprintf(html_file, "&lt;%s ", name->spelling);
+ {
+ if (name->defs)
+ display_scrap_numbers(html_file, name->defs);
+ else
+ putc('?', html_file);
+ }
+ fputs("&gt;\n<dd> ", html_file);
+ {
+ Scrap_Node *p = name->uses;
+ if (p) {
+ fputs("Referenced in ", html_file);
+ print_scrap_numbers(html_file, p);
+ }
+ else
+ fputs("Not referenced.\n", html_file);
+ }
+ }
+ putc('\n', html_file);
+ }
+ name = name->rlink;
+ }
+}
+static void format_user_entry(name, html_file)
+ Name *name;
+ FILE *html_file;
+{
+ while (name) {
+ format_user_entry(name->llink, html_file);
+ {
+ Scrap_Node *uses = name->uses;
+ if (uses) {
+ Scrap_Node *defs = name->defs;
+ fprintf(html_file, "<dt><code>%s</code>:\n<dd> ", name->spelling);
+ if (uses->scrap < defs->scrap) {
+ display_scrap_ref(html_file, uses->scrap);
+ uses = uses->next;
+ }
+ else {
+ if (defs->scrap == uses->scrap)
+ uses = uses->next;
+ fputs("<strong>", html_file);
+ display_scrap_ref(html_file, defs->scrap);
+ fputs("</strong>", html_file);
+ defs = defs->next;
+ }
+ while (uses || defs) {
+ fputs(", ", html_file);
+ if (uses && (!defs || uses->scrap < defs->scrap)) {
+ display_scrap_ref(html_file, uses->scrap);
+ uses = uses->next;
+ }
+ else {
+ if (uses && defs->scrap == uses->scrap)
+ uses = uses->next;
+ fputs("<strong>", html_file);
+ display_scrap_ref(html_file, defs->scrap);
+ fputs("</strong>", html_file);
+ defs = defs->next;
+ }
+ }
+ fputs(".\n", html_file);
+ }
+ }
+ name = name->rlink;
+ }
+}
diff --git a/web/nuweb/nuweb0.87b/input.c b/web/nuweb/nuweb0.87b/input.c
new file mode 100644
index 0000000000..90843e5cc7
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/input.c
@@ -0,0 +1,108 @@
+#include "global.h"
+static FILE *source_file; /* the current input file */
+static int source_peek;
+static int double_at;
+static int include_depth;
+static struct {
+ FILE *file;
+ char *name;
+ int line;
+} stack[10];
+int source_get()
+{
+ int c = source_peek;
+ switch (c) {
+ case EOF: {
+ fclose(source_file);
+ if (include_depth) {
+ include_depth--;
+ source_file = stack[include_depth].file;
+ source_line = stack[include_depth].line;
+ source_name = stack[include_depth].name;
+ source_peek = getc(source_file);
+ c = source_get();
+ }
+ }
+ return c;
+ case '@': {
+ c = getc(source_file);
+ if (double_at) {
+ source_peek = c;
+ double_at = FALSE;
+ c = '@';
+ }
+ else
+ switch (c) {
+ case 'i': {
+ char name[100];
+ if (include_depth >= 10) {
+ fprintf(stderr, "%s: include nesting too deep (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ {
+ char *p = name;
+ do
+ c = getc(source_file);
+ while (c == ' ' || c == '\t');
+ while (isgraph(c)) {
+ *p++ = c;
+ c = getc(source_file);
+ }
+ *p = '\0';
+ if (c != '\n') {
+ fprintf(stderr, "%s: unexpected characters after file name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ }
+ stack[include_depth].name = source_name;
+ stack[include_depth].file = source_file;
+ stack[include_depth].line = source_line + 1;
+ include_depth++;
+ source_line = 1;
+ source_name = save_string(name);
+ source_file = fopen(source_name, "r");
+ if (!source_file) {
+ fprintf(stderr, "%s: can't open include file %s\n",
+ command_name, source_name);
+ exit(-1);
+ }
+ source_peek = getc(source_file);
+ c = source_get();
+ }
+ break;
+ case 'f': case 'm': case 'u':
+ case 'd': case 'o': case 'D': case 'O':
+ case '{': case '}': case '<': case '>': case '|':
+ source_peek = c;
+ c = '@';
+ break;
+ case '@': source_peek = c;
+ double_at = TRUE;
+ break;
+ default: fprintf(stderr, "%s: bad @ sequence (%s, line %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ }
+ return c;
+ case '\n': source_line++;
+ default: source_peek = getc(source_file);
+ return c;
+ }
+}
+void source_open(name)
+ char *name;
+{
+ source_file = fopen(name, "r");
+ if (!source_file) {
+ fprintf(stderr, "%s: couldn't open %s\n", command_name, name);
+ exit(-1);
+ }
+ source_name = name;
+ source_line = 1;
+ source_peek = getc(source_file);
+ double_at = FALSE;
+ include_depth = 0;
+}
diff --git a/web/nuweb/nuweb0.87b/latex.c b/web/nuweb/nuweb0.87b/latex.c
new file mode 100644
index 0000000000..1d4aeec03b
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/latex.c
@@ -0,0 +1,361 @@
+#include "global.h"
+static void copy_scrap(); /* formats the body of a scrap */
+static void print_scrap_numbers(); /* formats a list of scrap numbers */
+static void format_entry(); /* formats an index entry */
+static void format_user_entry();
+void write_tex(file_name, tex_name)
+ char *file_name;
+ char *tex_name;
+{
+ FILE *tex_file = fopen(tex_name, "w");
+ if (tex_file) {
+ if (verbose_flag)
+ fprintf(stderr, "writing %s\n", tex_name);
+ source_open(file_name);
+ {
+ int scraps = 1;
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@')
+ {
+ int big_definition = FALSE;
+ c = source_get();
+ switch (c) {
+ case 'O': big_definition = TRUE;
+ case 'o': {
+ Name *name = collect_file_name();
+ {
+ fputs("\\begin{flushleft} \\small", tex_file);
+ if (!big_definition)
+ fputs("\n\\begin{minipage}{\\linewidth}", tex_file);
+ fprintf(tex_file, " \\label{scrap%d}\n", scraps);
+ }
+ fprintf(tex_file, "\\verb@\"%s\"@ {\\footnotesize ", name->spelling);
+ write_single_scrap_ref(tex_file, scraps++);
+ fputs(" }$\\equiv$\n", tex_file);
+ {
+ fputs("\\vspace{-1ex}\n\\begin{list}{}{} \\item\n", tex_file);
+ copy_scrap(tex_file);
+ fputs("$\\Diamond$\n\\end{list}\n", tex_file);
+ }
+ {
+ if (name->defs->next) {
+ fputs("\\vspace{-1ex}\n", tex_file);
+ fputs("\\footnotesize\\addtolength{\\baselineskip}{-1ex}\n", tex_file);
+ fputs("\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}", tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ fputs("\\item File defined by scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->defs);
+ fputs("\\end{list}\n", tex_file);
+ }
+ else
+ fputs("\\vspace{-2ex}\n", tex_file);
+ }
+ {
+ if (!big_definition)
+ fputs("\\end{minipage}\\\\[4ex]\n", tex_file);
+ fputs("\\end{flushleft}\n", tex_file);
+ do
+ c = source_get();
+ while (isspace(c));
+ }
+ }
+ break;
+ case 'D': big_definition = TRUE;
+ case 'd': {
+ Name *name = collect_macro_name();
+ {
+ fputs("\\begin{flushleft} \\small", tex_file);
+ if (!big_definition)
+ fputs("\n\\begin{minipage}{\\linewidth}", tex_file);
+ fprintf(tex_file, " \\label{scrap%d}\n", scraps);
+ }
+ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);
+ write_single_scrap_ref(tex_file, scraps++);
+ fputs("}$\\rangle\\equiv$\n", tex_file);
+ {
+ fputs("\\vspace{-1ex}\n\\begin{list}{}{} \\item\n", tex_file);
+ copy_scrap(tex_file);
+ fputs("$\\Diamond$\n\\end{list}\n", tex_file);
+ }
+ {
+ fputs("\\vspace{-1ex}\n", tex_file);
+ fputs("\\footnotesize\\addtolength{\\baselineskip}{-1ex}\n", tex_file);
+ fputs("\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}", tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ if (name->defs->next) {
+ fputs("\\item Macro defined by scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->defs);
+ }
+ }
+ {
+ if (name->uses) {
+ if (name->uses->next) {
+ fputs("\\item Macro referenced in scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->uses);
+ }
+ else {
+ fputs("\\item Macro referenced in scrap ", tex_file);
+ write_single_scrap_ref(tex_file, name->uses->scrap);
+ fputs(".\n", tex_file);
+ }
+ }
+ else {
+ fputs("\\item Macro never referenced.\n", tex_file);
+ fprintf(stderr, "%s: <%s> never referenced.\n",
+ command_name, name->spelling);
+ }
+ fputs("\\end{list}\n", tex_file);
+ }
+ {
+ if (!big_definition)
+ fputs("\\end{minipage}\\\\[4ex]\n", tex_file);
+ fputs("\\end{flushleft}\n", tex_file);
+ do
+ c = source_get();
+ while (isspace(c));
+ }
+ }
+ break;
+ case 'f': {
+ if (file_names) {
+ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",
+ tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ format_entry(file_names, tex_file, TRUE);
+ fputs("\\end{list}}", tex_file);
+ }
+ c = source_get();
+ }
+ break;
+ case 'm': {
+ if (macro_names) {
+ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",
+ tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ format_entry(macro_names, tex_file, FALSE);
+ fputs("\\end{list}}", tex_file);
+ }
+ c = source_get();
+ }
+ break;
+ case 'u': {
+ if (user_names) {
+ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",
+ tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ format_user_entry(user_names, tex_file);
+ fputs("\\end{list}}", tex_file);
+ }
+ c = source_get();
+ }
+ break;
+ case '@': putc(c, tex_file);
+ default: c = source_get();
+ break;
+ }
+ }
+ else {
+ putc(c, tex_file);
+ c = source_get();
+ }
+ }
+ }
+ fclose(tex_file);
+ }
+ else
+ fprintf(stderr, "%s: can't open %s\n", command_name, tex_name);
+}
+static void print_scrap_numbers(tex_file, scraps)
+ FILE *tex_file;
+ Scrap_Node *scraps;
+{
+ int page;
+ write_scrap_ref(tex_file, scraps->scrap, TRUE, &page);
+ scraps = scraps->next;
+ while (scraps) {
+ write_scrap_ref(tex_file, scraps->scrap, FALSE, &page);
+ scraps = scraps->next;
+ }
+ fputs(".\n", tex_file);
+}
+static void copy_scrap(file)
+ FILE *file;
+{
+ int indent = 0;
+ int c = source_get();
+ fputs("\\mbox{}\\verb@", file);
+ while (1) {
+ switch (c) {
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': fputs("@{\\tt @}\\verb@", file);
+ break;
+ case '|': {
+ do {
+ do
+ c = source_get();
+ while (c != '@');
+ c = source_get();
+ } while (c != '}');
+ }
+ case '}': putc('@', file);
+ return;
+ case '<': {
+ Name *name = collect_scrap_name();
+ fprintf(file, "@$\\langle$%s {\\footnotesize ", name->spelling);
+ if (name->defs)
+ {
+ Scrap_Node *p = name->defs;
+ write_single_scrap_ref(file, p->scrap);
+ p = p->next;
+ if (p)
+ fputs(", \\ldots\\ ", file);
+ }
+ else {
+ putc('?', file);
+ fprintf(stderr, "%s: scrap never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ fputs("}$\\rangle$\\verb@", file);
+ }
+ break;
+ default: /* ignore these since pass1 will have warned about them */
+ break;
+ }
+ }
+ break;
+ case '\n': fputs("@\\\\\n\\mbox{}\\verb@", file);
+ indent = 0;
+ break;
+ case '\t': {
+ int delta = 8 - (indent % 8);
+ indent += delta;
+ while (delta > 0) {
+ putc(' ', file);
+ delta--;
+ }
+ }
+ break;
+ default: putc(c, file);
+ indent++;
+ break;
+ }
+ c = source_get();
+ }
+}
+static void format_entry(name, tex_file, file_flag)
+ Name *name;
+ FILE *tex_file;
+ int file_flag;
+{
+ while (name) {
+ format_entry(name->llink, tex_file, file_flag);
+ {
+ fputs("\\item ", tex_file);
+ if (file_flag) {
+ fprintf(tex_file, "\\verb@\"%s\"@ ", name->spelling);
+ {
+ Scrap_Node *p = name->defs;
+ fputs("{\\footnotesize Defined by scrap", tex_file);
+ if (p->next) {
+ fputs("s ", tex_file);
+ print_scrap_numbers(tex_file, p);
+ }
+ else {
+ putc(' ', tex_file);
+ write_single_scrap_ref(tex_file, p->scrap);
+ putc('.', tex_file);
+ }
+ putc('}', tex_file);
+ }
+ }
+ else {
+ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);
+ {
+ Scrap_Node *p = name->defs;
+ if (p) {
+ int page;
+ write_scrap_ref(tex_file, p->scrap, TRUE, &page);
+ p = p->next;
+ while (p) {
+ write_scrap_ref(tex_file, p->scrap, FALSE, &page);
+ p = p->next;
+ }
+ }
+ else
+ putc('?', tex_file);
+ }
+ fputs("}$\\rangle$ ", tex_file);
+ {
+ Scrap_Node *p = name->uses;
+ fputs("{\\footnotesize ", tex_file);
+ if (p) {
+ fputs("Referenced in scrap", tex_file);
+ if (p->next) {
+ fputs("s ", tex_file);
+ print_scrap_numbers(tex_file, p);
+ }
+ else {
+ putc(' ', tex_file);
+ write_single_scrap_ref(tex_file, p->scrap);
+ putc('.', tex_file);
+ }
+ }
+ else
+ fputs("Not referenced.", tex_file);
+ putc('}', tex_file);
+ }
+ }
+ putc('\n', tex_file);
+ }
+ name = name->rlink;
+ }
+}
+static void format_user_entry(name, tex_file)
+ Name *name;
+ FILE *tex_file;
+{
+ while (name) {
+ format_user_entry(name->llink, tex_file);
+ {
+ Scrap_Node *uses = name->uses;
+ if (uses) {
+ int page;
+ Scrap_Node *defs = name->defs;
+ fprintf(tex_file, "\\item \\verb@%s@: ", name->spelling);
+ if (uses->scrap < defs->scrap) {
+ write_scrap_ref(tex_file, uses->scrap, TRUE, &page);
+ uses = uses->next;
+ }
+ else {
+ if (defs->scrap == uses->scrap)
+ uses = uses->next;
+ fputs("\\underline{", tex_file);
+ write_single_scrap_ref(tex_file, defs->scrap);
+ putc('}', tex_file);
+ page = -2;
+ defs = defs->next;
+ }
+ while (uses || defs) {
+ if (uses && (!defs || uses->scrap < defs->scrap)) {
+ write_scrap_ref(tex_file, uses->scrap, FALSE, &page);
+ uses = uses->next;
+ }
+ else {
+ if (uses && defs->scrap == uses->scrap)
+ uses = uses->next;
+ fputs(", \\underline{", tex_file);
+ write_single_scrap_ref(tex_file, defs->scrap);
+ putc('}', tex_file);
+ page = -2;
+ defs = defs->next;
+ }
+ }
+ fputs(".\n", tex_file);
+ }
+ }
+ name = name->rlink;
+ }
+}
diff --git a/web/nuweb/nuweb0.87b/literate.bib b/web/nuweb/nuweb0.87b/literate.bib
new file mode 100644
index 0000000000..dd454a041d
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/literate.bib
@@ -0,0 +1,129 @@
+
+% abbreviations known to bibtex 0.99c
+% acms ACM Computing Surveys
+% acta Acta Informatica
+% cacm Communications of the ACM
+% ibmjrd IBM Journal of Research and Development
+% ibmsj IBM Systems Journal
+% ieeese IEEE Transactions on Software Engineering
+% ieeetc IEEE Transactions on Computers
+% ieeetcad IEEE Transactions on Computer-Aided Design of ICs
+% ipl Information Processing Letters
+% jacm Journal of the ACM
+% jcss Journal of Computer and System Sciences
+% scp Science of Computer Programming
+% sicomp SIAM Journal on Computing
+% tocs ACM Transactions on Computer Systems
+% tods ACM Transactions on Database Systems
+% tog ACM Transactions on Graphics
+% toms ACM Transactions on Mathematical Software
+% toois ACM Transactions on Office Information Systems
+% toplas ACM Transactions on Programming Languages and Systems
+% tcs Theoretical Computer Science
+
+@string{spe="Software -- Practice and Experience"}
+
+
+@unpublished{noweb,
+ author="Norman Ramsey",
+ title="Literate-Programming Tools Need Not Be Complex",
+ month=aug,
+ year=1992,
+ note="Submitted to IEEE Software"
+}
+
+@article{aho:75,
+ author="Alfred V. Aho and Margaret J. Corasick",
+ title="Efficient String Matching: An Aid to Bibliographic Search",
+ pages="333--340",
+ journal=cacm,
+ year=1975,
+ month=jun,
+ volume=18,
+ number=6
+}
+
+
+@article{knuth:84,
+ author="Donald E. Knuth",
+ title="Literate Programming",
+ pages="97--111",
+ journal="The Computer Journal",
+ year="1984",
+ month=may,
+ volume=27,
+ number=2
+}
+
+@techreport{levy:90,
+ author="Silvio Levy and Donald E. Knuth",
+ title="{{\tt CWEB}} User Manual: The {{\small CWEB}} System of
+ Structured Documentation",
+ year="1990",
+ month=oct,
+ institution="Stanford University",
+ number="{\small STAN}-{\small CS}-83-977",
+ note="Available for anonymous ftp from {\tt labrea.stanford.edu} in
+ directory {\tt pub/cweb}"
+}
+
+@book{texbook,
+ author="Donald E. Knuth",
+ title="The {{\TeX}}book",
+ publisher="Addison-Wesley",
+ year=1986,
+ series="Computers \& Typesetting"
+}
+
+@book{tex:program,
+ author="Donald E. Knuth",
+ title="{{\TeX}}: The Program",
+ publisher="Addison-Wesley",
+ year=1986,
+ series="Computers \& Typesetting"
+}
+
+@book{metafont:program,
+ author="Donald E. Knuth",
+ title="{{\small\sf METAFONT:}} The Program",
+ publisher="Addison-Wesley",
+ year=1986,
+ series="Computers \& Typesetting"
+}
+
+@book{latex,
+ author="Leslie Lamport",
+ title="{{\LaTeX:}} A Document Preparation System",
+ publisher="Addison-Wesley",
+ year=1986
+}
+
+@booklet{funnelweb,
+ title="{FunnelWeb} User's Manual",
+ author="Ross N. Williams",
+ note="Available for anonymous ftp from {\tt sirius.itd.adelaide.edu.au}
+ in directory {\tt pub/funnelweb}",
+ month=may,
+ year=1992
+}
+
+@article{hanson:90,
+ title="Fast Allocation and Deallocation of Memory Based on Object Lifetimes",
+ author="David R. Hanson",
+ journal=spe,
+ year=1990,
+ month=jan,
+ volume=20,
+ number=1,
+ pages="5--12"
+}
+
+@booklet{drakos:94,
+ title="The {LaTeX2HTML} Translator",
+ author="Nikos Drakos",
+ note="Available from
+ {\tt http://clb.leeds.ac.uk/nikos/tex2html/latex2html.tar}",
+ month=jan,
+ year=1994
+}
+
diff --git a/web/nuweb/nuweb0.87b/main.c b/web/nuweb/nuweb0.87b/main.c
new file mode 100644
index 0000000000..e792ffc8cd
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/main.c
@@ -0,0 +1,105 @@
+#include "global.h"
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int arg = 1;
+ command_name = argv[0];
+ while (arg < argc) {
+ char *s = argv[arg];
+ if (*s++ == '-') {
+ {
+ char c = *s++;
+ while (c) {
+ switch (c) {
+ case 'c': compare_flag = FALSE;
+ break;
+ case 'n': number_flag = TRUE;
+ break;
+ case 'o': output_flag = FALSE;
+ break;
+ case 't': tex_flag = FALSE;
+ break;
+ case 'v': verbose_flag = TRUE;
+ break;
+ default: fprintf(stderr, "%s: unexpected argument ignored. ",
+ command_name);
+ fprintf(stderr, "Usage is: %s [-cnotv] file...\n",
+ command_name);
+ break;
+ }
+ c = *s++;
+ }
+ }
+ arg++;
+ }
+ else break;
+ }
+ {
+ if (arg >= argc) {
+ fprintf(stderr, "%s: expected a file name. ", command_name);
+ fprintf(stderr, "Usage is: %s [-cnotv] file-name...\n", command_name);
+ exit(-1);
+ }
+ do {
+ {
+ char source_name[100];
+ char tex_name[100];
+ char aux_name[100];
+ {
+ char *p = argv[arg];
+ char *q = source_name;
+ char *trim = q;
+ char *dot = NULL;
+ char c = *p++;
+ while (c) {
+ *q++ = c;
+ if (c == '/') {
+ trim = q;
+ dot = NULL;
+ }
+ else if (c == '.')
+ dot = q - 1;
+ c = *p++;
+ }
+ *q = '\0';
+ if (dot) {
+ *dot = '\0'; /* produce HTML when the file extension is ".hw" */
+ html_flag = dot[1] == 'h' && dot[2] == 'w' && dot[3] == '\0';
+ sprintf(tex_name, "%s.tex", trim);
+ sprintf(aux_name, "%s.aux", trim);
+ *dot = '.';
+ }
+ else {
+ sprintf(tex_name, "%s.tex", trim);
+ sprintf(aux_name, "%s.aux", trim);
+ *q++ = '.';
+ *q++ = 'w';
+ *q = '\0';
+ }
+ }
+ {
+ pass1(source_name);
+ if (tex_flag) {
+ if (html_flag) {
+ int saved_number_flag = number_flag;
+ number_flag = TRUE;
+ collect_numbers(aux_name);
+ write_html(source_name, tex_name);
+ number_flag = saved_number_flag;
+ }
+ else {
+ collect_numbers(aux_name);
+ write_tex(source_name, tex_name);
+ }
+ }
+ if (output_flag)
+ write_files(file_names);
+ arena_free();
+ }
+ }
+ arg++;
+ } while (arg < argc);
+ }
+ exit(0);
+}
diff --git a/web/nuweb/nuweb0.87b/names.c b/web/nuweb/nuweb0.87b/names.c
new file mode 100644
index 0000000000..448d209113
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/names.c
@@ -0,0 +1,368 @@
+#include "global.h"
+enum { LESS, GREATER, EQUAL, PREFIX, EXTENSION };
+
+static int compare(x, y)
+ char *x;
+ char *y;
+{
+ int len, result;
+ int xl = strlen(x);
+ int yl = strlen(y);
+ int xp = x[xl - 1] == ' ';
+ int yp = y[yl - 1] == ' ';
+ if (xp) xl--;
+ if (yp) yl--;
+ len = xl < yl ? xl : yl;
+ result = strncmp(x, y, len);
+ if (result < 0) return GREATER;
+ else if (result > 0) return LESS;
+ else if (xl < yl) {
+ if (xp) return EXTENSION;
+ else return LESS;
+ }
+ else if (xl > yl) {
+ if (yp) return PREFIX;
+ else return GREATER;
+ }
+ else return EQUAL;
+}
+char *save_string(s)
+ char *s;
+{
+ char *new = (char *) arena_getmem((strlen(s) + 1) * sizeof(char));
+ strcpy(new, s);
+ return new;
+}
+static int ambiguous_prefix();
+
+Name *prefix_add(root, spelling)
+ Name **root;
+ char *spelling;
+{
+ Name *node = *root;
+ while (node) {
+ switch (compare(node->spelling, spelling)) {
+ case GREATER: root = &node->rlink;
+ break;
+ case LESS: root = &node->llink;
+ break;
+ case EQUAL: return node;
+ case EXTENSION: node->spelling = save_string(spelling);
+ return node;
+ case PREFIX: {
+ if (ambiguous_prefix(node->llink, spelling) ||
+ ambiguous_prefix(node->rlink, spelling))
+ fprintf(stderr,
+ "%s: ambiguous prefix @<%s...@> (%s, line %d)\n",
+ command_name, spelling, source_name, source_line);
+ }
+ return node;
+ }
+ node = *root;
+ }
+ {
+ node = (Name *) arena_getmem(sizeof(Name));
+ node->spelling = save_string(spelling);
+ node->mark = FALSE;
+ node->llink = NULL;
+ node->rlink = NULL;
+ node->uses = NULL;
+ node->defs = NULL;
+ node->tab_flag = TRUE;
+ node->indent_flag = TRUE;
+ node->debug_flag = FALSE;
+ *root = node;
+ return node;
+ }
+}
+static int ambiguous_prefix(node, spelling)
+ Name *node;
+ char *spelling;
+{
+ while (node) {
+ switch (compare(node->spelling, spelling)) {
+ case GREATER: node = node->rlink;
+ break;
+ case LESS: node = node->llink;
+ break;
+ case EQUAL:
+ case EXTENSION:
+ case PREFIX: return TRUE;
+ }
+ }
+ return FALSE;
+}
+static int robs_strcmp(x, y)
+ char *x;
+ char *y;
+{
+ char *xx = x;
+ char *yy = y;
+ int xc = toupper(*xx);
+ int yc = toupper(*yy);
+ while (xc == yc && xc) {
+ xx++;
+ yy++;
+ xc = toupper(*xx);
+ yc = toupper(*yy);
+ }
+ if (xc != yc) return xc - yc;
+ xc = *x;
+ yc = *y;
+ while (xc == yc && xc) {
+ x++;
+ y++;
+ xc = *x;
+ yc = *y;
+ }
+ if (isupper(xc) && islower(yc))
+ return xc * 2 - (toupper(yc) * 2 + 1);
+ if (islower(xc) && isupper(yc))
+ return toupper(xc) * 2 + 1 - yc * 2;
+ return xc - yc;
+}
+Name *name_add(root, spelling)
+ Name **root;
+ char *spelling;
+{
+ Name *node = *root;
+ while (node) {
+ int result = robs_strcmp(node->spelling, spelling);
+ if (result > 0)
+ root = &node->llink;
+ else if (result < 0)
+ root = &node->rlink;
+ else
+ return node;
+ node = *root;
+ }
+ {
+ node = (Name *) arena_getmem(sizeof(Name));
+ node->spelling = save_string(spelling);
+ node->mark = FALSE;
+ node->llink = NULL;
+ node->rlink = NULL;
+ node->uses = NULL;
+ node->defs = NULL;
+ node->tab_flag = TRUE;
+ node->indent_flag = TRUE;
+ node->debug_flag = FALSE;
+ *root = node;
+ return node;
+ }
+}
+Name *collect_file_name()
+{
+ Name *new_name;
+ char name[100];
+ char *p = name;
+ int start_line = source_line;
+ int c = source_get();
+ while (isspace(c))
+ c = source_get();
+ while (isgraph(c)) {
+ *p++ = c;
+ c = source_get();
+ }
+ if (p == name) {
+ fprintf(stderr, "%s: expected file name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ *p = '\0';
+ new_name = name_add(&file_names, name);
+ {
+ while (1) {
+ while (isspace(c))
+ c = source_get();
+ if (c == '-') {
+ c = source_get();
+ do {
+ switch (c) {
+ case 't': new_name->tab_flag = FALSE;
+ break;
+ case 'd': new_name->debug_flag = TRUE;
+ break;
+ case 'i': new_name->indent_flag = FALSE;
+ break;
+ default : fprintf(stderr, "%s: unexpected per-file flag (%s, %d)\n",
+ command_name, source_name, source_line);
+ break;
+ }
+ c = source_get();
+ } while (!isspace(c));
+ }
+ else break;
+ }
+ }
+ if (c != '@' || source_get() != '{') {
+ fprintf(stderr, "%s: expected @{ after file name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ return new_name;
+}
+Name *collect_macro_name()
+{
+ char name[100];
+ char *p = name;
+ int start_line = source_line;
+ int c = source_get();
+ while (isspace(c))
+ c = source_get();
+ while (c != EOF) {
+ switch (c) {
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': *p++ = c;
+ break;
+ case '{': {
+ if (p > name && p[-1] == ' ')
+ p--;
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ if (p == name || name[0] == ' ') {
+ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ default: fprintf(stderr,
+ "%s: unexpected @%c in macro name (%s, %d)\n",
+ command_name, c, source_name, start_line);
+ exit(-1);
+ }
+ }
+ break;
+ case '\t':
+ case ' ': *p++ = ' ';
+ do
+ c = source_get();
+ while (c == ' ' || c == '\t');
+ break;
+ case '\n': {
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c != '@' || source_get() != '{') {
+ fprintf(stderr, "%s: expected @{ after macro name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ {
+ if (p > name && p[-1] == ' ')
+ p--;
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ if (p == name || name[0] == ' ') {
+ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ }
+ default: *p++ = c;
+ c = source_get();
+ break;
+ }
+ }
+ fprintf(stderr, "%s: expected macro name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ return NULL; /* unreachable return to avoid warnings on some compilers */
+}
+Name *collect_scrap_name()
+{
+ char name[100];
+ char *p = name;
+ int c = source_get();
+ while (c == ' ' || c == '\t')
+ c = source_get();
+ while (c != EOF) {
+ switch (c) {
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': *p++ = c;
+ c = source_get();
+ break;
+ case '>': {
+ if (p > name && p[-1] == ' ')
+ p--;
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ if (p == name || name[0] == ' ') {
+ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ default: fprintf(stderr,
+ "%s: unexpected @%c in macro name (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+ }
+ break;
+ case '\t':
+ case ' ': *p++ = ' ';
+ do
+ c = source_get();
+ while (c == ' ' || c == '\t');
+ break;
+ default: if (!isgraph(c)) {
+ fprintf(stderr,
+ "%s: unexpected character in macro name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p++ = c;
+ c = source_get();
+ break;
+ }
+ }
+ fprintf(stderr, "%s: unexpected end of file (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ return NULL; /* unreachable return to avoid warnings on some compilers */
+}
+static Scrap_Node *reverse(); /* a forward declaration */
+
+void reverse_lists(names)
+ Name *names;
+{
+ while (names) {
+ reverse_lists(names->llink);
+ names->defs = reverse(names->defs);
+ names->uses = reverse(names->uses);
+ names = names->rlink;
+ }
+}
+static Scrap_Node *reverse(a)
+ Scrap_Node *a;
+{
+ if (a) {
+ Scrap_Node *b = a->next;
+ a->next = NULL;
+ while (b) {
+ Scrap_Node *c = b->next;
+ b->next = a;
+ a = b;
+ b = c;
+ }
+ }
+ return a;
+}
diff --git a/web/nuweb/nuweb0.87b/nuweb.w b/web/nuweb/nuweb0.87b/nuweb.w
new file mode 100644
index 0000000000..1ecda0c408
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/nuweb.w
@@ -0,0 +1,3599 @@
+\documentstyle{report}
+\newif\ifshowcode
+\showcodetrue
+
+\setlength{\oddsidemargin}{0in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.5in}
+\setlength{\marginparwidth}{0.5in}
+
+\title{Nuweb Version 0.87b \\ A Simple Literate Programming Tool}
+\date{}
+\author{Preston Briggs\thanks{This work has been supported by ARPA,
+through ONR grant N00014-91-J-1989.}
+\\ \sl preston@@cs.rice.edu
+\\ HTML scrap generator by John D. Ramsdell
+\\ \sl ramsdell@@mitre.org}
+
+\begin{document}
+\pagenumbering{roman}
+\maketitle
+\tableofcontents
+
+\chapter{Introduction}
+\pagenumbering{arabic}
+
+In 1984, Knuth introduced the idea of {\em literate programming\/} and
+described a pair of tools to support the practise~\cite{knuth:84}.
+His approach was to combine Pascal code with \TeX\ documentation to
+produce a new language, \verb|WEB|, that offered programmers a superior
+approach to programming. He wrote several programs in \verb|WEB|,
+including \verb|weave| and \verb|tangle|, the programs used to support
+literate programming.
+The idea was that a programmer wrote one document, the web file, that
+combined documentation (written in \TeX~\cite{texbook}) with code
+(written in Pascal).
+
+Running \verb|tangle| on the web file would produce a complete
+Pascal program, ready for compilation by an ordinary Pascal compiler.
+The primary function of \verb|tangle| is to allow the programmer to
+present elements of the program in any desired order, regardless of
+the restrictions imposed by the programming language. Thus, the
+programmer is free to present his program in a top-down fashion,
+bottom-up fashion, or whatever seems best in terms of promoting
+understanding and maintenance.
+
+Running \verb|weave| on the web file would produce a \TeX\ file, ready
+to be processed by \TeX\@@. The resulting document included a variety of
+automatically generated indices and cross-references that made it much
+easier to navigate the code. Additionally, all of the code sections
+were automatically pretty printed, resulting in a quite impressive
+document.
+
+Knuth also wrote the programs for \TeX\ and {\small\sf METAFONT}
+entirely in \verb|WEB|, eventually publishing them in book
+form~\cite{tex:program,metafont:program}. These are probably the
+largest programs ever published in a readable form.
+
+Inspired by Knuth's example, many people have experimented with
+\verb|WEB|\@@. Some people have even built web-like tools for their
+own favorite combinations of programming language and typesetting
+language. For example, \verb|CWEB|, Knuth's current system of choice,
+works with a combination of C (or C++) and \TeX~\cite{levy:90}.
+Another system, FunnelWeb, is independent of any programming language
+and only mildly dependent on \TeX~\cite{funnelweb}. Inspired by the
+versatility of FunnelWeb and by the daunting size of its
+documentation, I decided to write my own, very simple, tool for
+literate programming.%
+\footnote{There is another system similar to
+mine, written by Norman Ramsey, called {\em noweb}~\cite{noweb}. It
+perhaps suffers from being overly Unix-dependent and requiring several
+programs to use. On the other hand, its command syntax is very nice.
+In any case, nuweb certainly owes its name and a number of features to
+his inspiration.}
+
+
+\section{Nuweb}
+
+Nuweb works with any programming language and \LaTeX~\cite{latex}. I
+wanted to use \LaTeX\ because it supports a multi-level sectioning
+scheme and has facilities for drawing figures. I wanted to be able to
+work with arbitrary programming languages because my friends and I
+write programs in many languages (and sometimes combinations of
+several languages), {\em e.g.,} C, Fortran, C++, yacc, lex, Scheme,
+assembly, Postscript, and so forth. The need to support arbitrary
+programming languages has many consequences:
+\begin{description}
+\item[No pretty printing] Both \verb|WEB| and \verb|CWEB| are able to
+ pretty print the code sections of their documents because they
+ understand the language well enough to parse it. Since we want to use
+ {\em any\/} language, we've got to abandon this feature.
+\item[No index of identifiers] Because \verb|WEB| knows about Pascal,
+ it is able to construct an index of all the identifiers occurring in
+ the code sections (filtering out keywords and the standard type
+ identifiers). Unfortunately, this isn't as easy in our case. We don't
+ know what an identifiers looks like in each language and we certainly
+ don't know all the keywords. (On the other hand, see the end of
+ Section~1.3)
+\end{description}
+Of course, we've got to have some compensation for our losses or the
+whole idea would be a waste. Here are the advantages I can see:
+\begin{description}
+\item[Simplicity] The majority of the commands in \verb|WEB| are
+ concerned with control of the automatic pretty printing. Since we
+ don't pretty print, many commands are eliminated. A further set of
+ commands is subsumed by \LaTeX\ and may also be eliminated. As a
+ result, our set of commands is reduced to only four members (explained
+ in the next section). This simplicity is also reflected in
+ the size of this tool, which is quite a bit smaller than the tools
+ used with other approaches.
+\item[No pretty printing] Everyone disagrees about how their code
+ should look, so automatic formatting annoys many people. One approach
+ is to provide ways to control the formatting. Our approach is
+ simpler---we perform no automatic formatting and therefore allow the
+ programmer complete control of code layout.
+\item[Control] We also offer the programmer complete control of the
+ layout of his output files (the files generated during tangling). Of
+ course, this is essential for languages that are sensitive to layout;
+ but it is also important in many practical situations, {\em e.g.,}
+ debugging.
+\item[Speed] Since nuweb doesn't do to much, the nuweb tool runs
+ quickly. I combine the functions of \verb|tangle| and \verb|weave| into
+ a single program that performs both functions at once.
+\item[Page numbers] Inspired by the example of noweb, nuweb refers to
+ all scraps by page number to simplify navigation. If there are
+ multiple scraps on a page (say page~17), they are distinguished by
+ lower-case letters ({\em e.g.,} 17a, 17b, and so forth).
+\item[Multiple file output] The programmer may specify more than one
+ output file in a single nuweb file. This is required when constructing
+ programs in a combination of languages (say, Fortran and C)\@@. It's also
+ an advantage when constructing very large programs that would require
+ a lot of compile time.
+\end{description}
+This last point is very important. By allowing the creation of
+multiple output files, we avoid the need for monolithic programs.
+Thus we support the creation of very large programs by groups of
+people.
+
+A further reduction in compilation time is achieved by first
+writing each output file to a temporary location, then comparing the
+temporary file with the old version of the file. If there is no
+difference, the temporary file can be deleted. If the files differ,
+the old version is deleted and the temporary file renamed. This
+approach works well in combination with \verb|make| (or similar tools),
+since \verb|make| will avoid recompiling untouched output files.
+
+\subsection{Nuweb and HTML}
+
+In addition to producing {\LaTeX} source, nuweb can be used to
+generate HyperText Markup Language (HTML), the markup language used by
+the World Wide Web. HTML provides hypertext links. When a HTML
+document is viewed online, a user can navigate within the document by
+activating the links. The tools which generate HTML automatically
+produce hypertext links from a nuweb source.
+
+
+\section{Writing Nuweb}
+
+The bulk of a nuweb file will be ordinary \LaTeX\@@. In fact, any
+{\LaTeX} file can serve as input to nuweb and will be simply copied
+through unchanged to the documentation file---unless a nuweb command
+is discovered. All nuweb commands begin with an ``at-sign''
+(\verb|@@|). Therefore, a file without at-signs will be copied
+unchanged. Nuweb commands are used to specify {\em output files,}
+define {\em macros,} and delimit {\em scraps}. These are the basic
+features of interest to the nuweb tool---all else is simply text to be
+copied to the documentation file.
+
+\subsection{The Major Commands}
+
+Files and macros are defined with the following commands:
+\begin{description}
+\item[{\tt @@o} {\em file-name flags scrap\/}] Output a file. The file name is
+ terminated by whitespace.
+\item[{\tt @@d} {\em macro-name scrap\/}] Define a macro. The macro name
+ is terminated by a return or the beginning of a scrap.
+\end{description}
+A specific file may be specified several times, with each definition
+being written out, one after the other, in the order they appear.
+The definitions of macros may be similarly divided.
+
+\subsubsection{Scraps}
+
+Scraps have specific begin markers and end markers to allow precise
+control over the contents and layout. Note that any amount of
+whitespace (including carriage returns) may appear between a name and
+the beginning of a scrap.
+\begin{description}
+\item[\tt @@\{{\em anything\/}@@\}] where the scrap body includes every
+ character in {\em anything\/}---all the blanks, all the tabs, all the
+ carriage returns.
+\end{description}
+Inside a scrap, we may invoke a macro.
+\begin{description}
+\item[\tt @@<{\em macro-name\/}@@>] Causes the macro
+ {\em macro-name\/} to be expanded inline as the code is written out
+ to a file. It is an error to specify recursive macro invocations.
+\end{description}
+Note that macro names may be abbreviated, either during invocation or
+definition. For example, it would be very tedious to have to
+repeatedly type the macro name
+\begin{quote}
+\verb|@@d Check for terminating at-sequence and return name if found|
+\end{quote}
+Therefore, we provide a mechanism (stolen from Knuth) of indicating
+abbreviated names.
+\begin{quote}
+\verb|@@d Check for terminating...|
+\end{quote}
+Basically, the programmer need only type enough characters to uniquely
+identify the macro name, followed by three periods. An abbreviation
+may even occur before the full version; nuweb simply preserves the
+longest version of a macro name. Note also that blanks and tabs are
+insignificant in a macro name; any string of them are replaced by a
+single blank.
+
+When scraps are written to a program file or a documentation file, tabs are
+expanded into spaces by default. Currently, I assume tab stops are set
+every eight characters. Furthermore, when a macro is expanded in a scrap,
+the body of the macro is indented to match the indentation of the
+macro invocation. Therefore, care must be taken with languages
+({\em e.g.,} Fortran) that are sensitive to indentation.
+These default behaviors may be changed for each output file (see
+below).
+
+\subsubsection{Flags}
+
+When defining an output file, the programmer has the option of using
+flags to control output of a particular file. The flags are intended
+to make life a little easier for programmers using certain languages.
+They introduce little language dependences; however, they do so only
+for a particular file. Thus it is still easy to mix languages within a
+single document. There are three ``per-file'' flags:
+\begin{description}
+\item[\tt -d] Forces the creation of \verb|#line| directives in the
+ output file. These are useful with C (and sometimes C++ and Fortran) on
+ many Unix systems since they cause the compiler's error messages to
+ refer to the web file rather than the output file. Similarly, they
+ allow source debugging in terms of the web file.
+\item[\tt -i] Suppresses the indentation of macros. That is, when a
+ macro is expanded in a scrap, it will {\em not\/} be indented to
+ match the indentation of the macro invocation. This flag would seem
+ most useful for Fortran programmers.
+\item[\tt -t] Suppresses expansion of tabs in the output file. This
+ feature seems important when generating \verb|make| files.
+\end{description}
+
+
+\subsection{The Minor Commands}
+
+We have two very low-level utility commands that may appear anywhere
+in the web file.
+\begin{description}
+\item[\tt @@@@] Causes a single ``at sign'' to be copied into the output.
+\item[\tt @@i {\em file-name\/}] Includes a file. Includes may be
+ nested, though there is currently a limit of 10~levels. The file name
+ should be complete (no extension will be appended) and should be
+ terminated by a carriage return.
+\end{description}
+Finally, there are three commands used to create indices to the macro
+names, file definitions, and user-specified identifiers.
+\begin{description}
+\item[\tt @@f] Create an index of file names.
+\item[\tt @@m] Create an index of macro name.
+\item[\tt @@u] Create an index of user-specified identifiers.
+\end{description}
+I usually put these in their own section
+in the \LaTeX\ document; for example, see Chapter~\ref{indices}.
+
+Identifiers must be explicitly specified for inclusion in the
+\verb|@@u| index. By convention, each identifier is marked at the
+point of its definition; all references to each identifier (inside
+scraps) will be discovered automatically. To ``mark'' an identifier
+for inclusion in the index, we must mention it at the end of a scrap.
+For example,
+\begin{quote}
+\begin{verbatim}
+@@d a scrap @@{
+Let's pretend we're declaring the variables FOO and BAR
+inside this scrap.
+@@| FOO BAR @@}
+\end{verbatim}
+\end{quote}
+I've used alphabetic identifiers in this example, but any string of
+characters (not including whitespace or \verb|@@| characters) will do.
+Therefore, it's possible to add index entries for things like
+\verb|<<=| if desired. An identifier may be declared in more than one
+scrap.
+
+In the generated index, each identifier appears with a list of all the
+scraps using and defining it, where the defining scraps are
+distinguished by underlining. Note that the identifier doesn't
+actually have to appear in the defining scrap; it just has to be in
+the list of definitions at the end of a scrap.
+
+
+\section{Running Nuweb}
+
+Nuweb is invoked using the following command:
+\begin{quote}
+{\tt nuweb} {\em flags file-name}\ldots
+\end{quote}
+One or more files may be processed at a time. If a file name has no
+extension, \verb|.w| will be appended. {\LaTeX} suitable for
+translation into HTML by {\LaTeX}2HTML will be produced from
+files whose name ends with \verb|.hw|, otherwise, ordinary {\LaTeX} will be
+produced. While a file name may specify a file in another directory,
+the resulting documentation file will always be created in the current
+directory. For example,
+\begin{quote}
+{\tt nuweb /foo/bar/quux}
+\end{quote}
+will take as input the file \verb|/foo/bar/quux.w| and will create the
+file \verb|quux.tex| in the current directory.
+
+By default, nuweb performs both tangling and weaving at the same time.
+Normally, this is not a bottleneck in the compilation process;
+however, it's possible to achieve slightly faster throughput by
+avoiding one or another of the default functions using command-line
+flags. There are currently three possible flags:
+\begin{description}
+\item[\tt -t] Suppress generation of the documentation file.
+\item[\tt -o] Suppress generation of the output files.
+\item[\tt -c] Avoid testing output files for change before updating them.
+\end{description}
+Thus, the command
+\begin{quote}
+\verb|nuweb -to /foo/bar/quux|
+\end{quote}
+would simply scan the input and produce no output at all.
+
+There are two additional command-line flags:
+\begin{description}
+\item[\tt -v] For ``verbose,'' causes nuweb to write information about
+ its progress to \verb|stderr|.
+\item[\tt -n] Forces scraps to be numbered sequentially from~1
+ (instead of using page numbers). This form is perhaps more desirable
+ for small webs.
+\end{description}
+
+\section{Generating HTML}
+
+Nikos Drakos' {\LaTeX}2HTML Version 0.5.3~\cite{drakos:94} can be used
+to translate {\LaTeX} with embedded HTML scraps into HTML\@@. Be sure
+to include the document-style option \verb|html| so that {\LaTeX} will
+understand the hypertext commands. When translating into HTML, do not
+allow a document to be split by specifying ``\verb|-split 0|''.
+You need not generate navigation links, so also specify
+``\verb|-no_navigation|''.
+
+While preparing a web, you may want to view the program's scraps without
+taking the time to run {\LaTeX}2HTML\@@. Simply rename the generated
+{\LaTeX} source so that its file name ends with \verb|.html|, and view
+that file. The documentations section will be jumbled, but the
+scraps will be clear.
+
+\section{Restrictions}
+
+Because nuweb is intended to be a simple tool, I've established a few
+restrictions. Over time, some of these may be eliminated; others seem
+fundamental.
+\begin{itemize}
+\item The handling of errors is not completely ideal. In some cases, I
+ simply warn of a problem and continue; in other cases I halt
+ immediately. This behavior should be regularized.
+\item I warn about references to macros that haven't been defined, but
+ don't halt. This seems most convenient for development, but may change
+ in the future.
+\item File names and index entries should not contain any \verb|@@|
+ signs.
+\item Macro names may be (almost) any well-formed \TeX\ string.
+ It makes sense to change fonts or use math mode; however, care should
+ be taken to ensure matching braces, brackets, and dollar signs.
+ When producing HTML, macros are displayed in a preformatted element
+ (PRE), so macros may contain one or more A, B, I, U, or P elements
+ or data characters.
+\item Anything is allowed in the body of a scrap; however, very
+ long scraps (horizontally or vertically) may not typeset well.
+\item Temporary files (created for comparison to the eventual
+ output files) are placed in the current directory. Since they may be
+ renamed to an output file name, all the output files should be on the
+ same file system as the current directory.
+\item Because page numbers cannot be determined until the document has
+ been typeset, we have to rerun nuweb after \LaTeX\ to obtain a clean
+ version of the document (very similar to the way we sometimes have
+ to rerun \LaTeX\ to obtain an up-to-date table of contents after
+ significant edits). Nuweb will warn (in most cases) when this needs
+ to be done; in the remaining cases, \LaTeX\ will warn that labels
+ may have changed.
+\end{itemize}
+Very long scraps may be allowed to break across a page if declared
+with \verb|@@O| or \verb|@@D| (instead of \verb|@@o| and \verb|@@d|).
+This doesn't work very well as a default, since far too many short
+scraps will be broken across pages; however, as a user-controlled
+option, it seems very useful. No distinction is made between the
+upper case and lower case forms of these commands when generating
+HTML\@@.
+
+\section{Acknowledgements}
+
+Several people have contributed their times, ideas, and debugging
+skills. In particular, I'd like to acknowledge the contributions of
+Osman Buyukisik, Manuel Carriba, Adrian Clarke, Tim Harvey, Michael
+Lewis, Walter Ravenek, Rob Shillingsburg, Kayvan Sylvan, Dominique
+de~Waleffe, and Scott Warren. Of course, most of these people would
+never have heard or nuweb (or many other tools) without the efforts of
+George Greenwade.
+
+
+\ifshowcode
+\chapter{The Overall Structure}
+
+Processing a web requires three major steps:
+\begin{enumerate}
+\item Read the source, accumulating file names, macro names, scraps,
+and lists of cross-references.
+\item Reread the source, copying out to the documentation file, with
+protection and cross-reference information for all the scraps.
+\item Traverse the list of files names. For each file name:
+\begin{enumerate}
+\item Dump all the defining scraps into a temporary file.
+\item If the file already exists and is unchanged, delete the
+temporary file; otherwise, rename the temporary file.
+\end{enumerate}
+\end{enumerate}
+
+
+\section{Files}
+
+I have divided the program into several files for quicker
+recompilation during development.
+@o global.h
+@{@<Include files@>
+@<Type declarations@>
+@<Global variable declarations@>
+@<Function prototypes@>
+@}
+
+We'll need at least three of the standard system include files.
+@d Include files
+@{#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+@| FILE stderr exit fprintf fputs fopen fclose getc putc strlen
+toupper isupper islower isgraph isspace tempnam remove malloc size_t @}
+
+\newpage
+\noindent
+I also like to use \verb|TRUE| and \verb|FALSE| in my code.
+I'd use an \verb|enum| here, except that some systems seem to provide
+definitions of \verb|TRUE| and \verb|FALSE| be default. The following
+code seems to work on all the local systems.
+@d Type dec...
+@{#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+@| FALSE TRUE @}
+
+
+\subsection{The Main Files}
+
+The code is divided into four main files (introduced here) and five
+support files (introduced in the next section).
+The file \verb|main.c| will contain the driver for the whole program
+(see Section~\ref{main-routine}).
+@o main.c
+@{#include "global.h"
+@}
+
+The first pass over the source file is contained in \verb|pass1.c|.
+It handles collection of all the file names, macros names, and scraps
+(see Section~\ref{pass-one}).
+@o pass1.c
+@{#include "global.h"
+@}
+
+The \verb|.tex| file is created during a second pass over the source
+file. The file \verb|latex.c| contains the code controlling the
+construction of the \verb|.tex| file
+(see Section~\ref{latex-file}).
+@o latex.c
+@{#include "global.h"
+@}
+
+The file \verb|html.c| contains the code controlling the
+construction of the \verb|.tex| file appropriate for use with {\LaTeX}2HTML
+(see Section~\ref{html-file}).
+@o html.c
+@{#include "global.h"
+@}
+
+The code controlling the creation of the output files is in \verb|output.c|
+(see Section~\ref{output-files}).
+@o output.c
+@{#include "global.h"
+@}
+
+\newpage
+\subsection{Support Files}
+
+The support files contain a variety of support routines used to define
+and manipulate the major data abstractions.
+The file \verb|input.c| holds all the routines used for referring to
+source files (see Section~\ref{source-files}).
+@o input.c
+@{#include "global.h"
+@}
+
+Creation and lookup of scraps is handled by routines in \verb|scraps.c|
+(see Section~\ref{scraps}).
+@o scraps.c
+@{#include "global.h"
+@}
+
+
+The handling of file names and macro names is detailed in \verb|names.c|
+(see Section~\ref{names}).
+@o names.c
+@{#include "global.h"
+@}
+
+Memory allocation and deallocation is handled by routines in \verb|arena.c|
+(see Section~\ref{memory-management}).
+@o arena.c
+@{#include "global.h"
+@}
+
+Finally, for best portability, I seem to need a file containing
+(useless!) definitions of all the global variables.
+@o global.c
+@{#include "global.h"
+@<Global variable definitions@>
+@}
+
+\section{The Main Routine} \label{main-routine}
+
+The main routine is quite simple in structure.
+It wades through the optional command-line arguments,
+then handles any files listed on the command line.
+@o main.c
+@{int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int arg = 1;
+ @<Interpret command-line arguments@>
+ @<Process the remaining arguments (file names)@>
+ exit(0);
+}
+@| main @}
+
+
+\subsection{Command-Line Arguments}
+
+There are five possible command-line arguments:
+\begin{description}
+\item[\tt -t] Suppresses generation of the {\tt .tex} file.
+\item[\tt -o] Suppresses generation of the output files.
+\item[\tt -c] Forces output files to overwrite old files of the same
+ name without comparing for equality first.
+\item[\tt -v] The verbose flag. Forces output of progress reports.
+\item[\tt -n] Forces sequential numbering of scraps (instead of page
+ numbers).
+\end{description}
+
+\noindent
+Global flags are declared for each of the arguments.
+@d Global variable dec...
+@{extern int tex_flag; /* if FALSE, don't emit the documentation file */
+extern int html_flag; /* if TRUE, emit HTML instead of LaTeX scraps. */
+extern int output_flag; /* if FALSE, don't emit the output files */
+extern int compare_flag; /* if FALSE, overwrite without comparison */
+extern int verbose_flag; /* if TRUE, write progress information */
+extern int number_flag; /* if TRUE, use a sequential numbering scheme */
+@| tex_flag html_flag output_flag compare_flag verbose_flag number_flag @}
+
+The flags are all initialized for correct default behavior.
+
+@d Global variable def...
+@{int tex_flag = TRUE;
+int html_flag = FALSE;
+int output_flag = TRUE;
+int compare_flag = TRUE;
+int verbose_flag = FALSE;
+int number_flag = FALSE;
+@}
+
+
+We save the invocation name of the command in a global variable
+\verb|command_name| for use in error messages.
+@d Global variable dec...
+@{extern char *command_name;
+@| command_name @}
+
+@d Global variable def...
+@{char *command_name = NULL;
+@}
+
+The invocation name is conventionally passed in \verb|argv[0]|.
+@d Interpret com...
+@{command_name = argv[0];
+@}
+
+We need to examine the remaining entries in \verb|argv|, looking for
+command-line arguments.
+@d Interpret com...
+@{while (arg < argc) {
+ char *s = argv[arg];
+ if (*s++ == '-') {
+ @<Interpret the argument string \verb|s|@>
+ arg++;
+ }
+ else break;
+}@}
+
+
+Several flags can be stacked behind a single minus sign; therefore,
+we've got to loop through the string, handling them all.
+@d Interpret the...
+@{{
+ char c = *s++;
+ while (c) {
+ switch (c) {
+ case 'c': compare_flag = FALSE;
+ break;
+ case 'n': number_flag = TRUE;
+ break;
+ case 'o': output_flag = FALSE;
+ break;
+ case 't': tex_flag = FALSE;
+ break;
+ case 'v': verbose_flag = TRUE;
+ break;
+ default: fprintf(stderr, "%s: unexpected argument ignored. ",
+ command_name);
+ fprintf(stderr, "Usage is: %s [-cnotv] file...\n",
+ command_name);
+ break;
+ }
+ c = *s++;
+ }
+}@}
+
+\subsection{File Names}
+
+We expect at least one file name. While a missing file name might be
+ignored without causing any problems, we take the opportunity to report
+the usage convention.
+@d Process the remaining...
+@{{
+ if (arg >= argc) {
+ fprintf(stderr, "%s: expected a file name. ", command_name);
+ fprintf(stderr, "Usage is: %s [-cnotv] file-name...\n", command_name);
+ exit(-1);
+ }
+ do {
+ @<Handle the file name in \verb|argv[arg]|@>
+ arg++;
+ } while (arg < argc);
+}@}
+
+\newpage
+\noindent
+The code to handle a particular file name is rather more tedious than
+the actual processing of the file. A file name may be an arbitrarily
+complicated path name, with an optional extension. If no extension is
+present, we add \verb|.w| as a default. The extended path name will be
+kept in a local variable \verb|source_name|. The resulting documentation
+file will be written in the current directory; its name will be kept
+in the variable \verb|tex_name|.
+@d Handle the file...
+@{{
+ char source_name[100];
+ char tex_name[100];
+ char aux_name[100];
+ @<Build \verb|source_name| and \verb|tex_name|@>
+ @<Process a file@>
+}@}
+
+
+I bump the pointer \verb|p| through all the characters in \verb|argv[arg]|,
+copying all the characters into \verb|source_name| (via the pointer
+\verb|q|).
+
+At each slash, I update \verb|trim| to point just past the
+slash in \verb|source_name|. The effect is that \verb|trim| will point
+at the file name without any leading directory specifications.
+
+The pointer \verb|dot| is made to point at the file name extension, if
+present. If there is no extension, we add \verb|.w| to the source name.
+In any case, we create the \verb|tex_name| from \verb|trim|, taking
+care to get the correct extension. The \verb|html_flag| is set in
+this scrap.
+@d Build \verb|sou...
+@{{
+ char *p = argv[arg];
+ char *q = source_name;
+ char *trim = q;
+ char *dot = NULL;
+ char c = *p++;
+ while (c) {
+ *q++ = c;
+ if (c == '/') {
+ trim = q;
+ dot = NULL;
+ }
+ else if (c == '.')
+ dot = q - 1;
+ c = *p++;
+ }
+ *q = '\0';
+ if (dot) {
+ *dot = '\0'; /* produce HTML when the file extension is ".hw" */
+ html_flag = dot[1] == 'h' && dot[2] == 'w' && dot[3] == '\0';
+ sprintf(tex_name, "%s.tex", trim);
+ sprintf(aux_name, "%s.aux", trim);
+ *dot = '.';
+ }
+ else {
+ sprintf(tex_name, "%s.tex", trim);
+ sprintf(aux_name, "%s.aux", trim);
+ *q++ = '.';
+ *q++ = 'w';
+ *q = '\0';
+ }
+}@}
+
+Now that we're finally ready to process a file, it's not really too
+complex. We bundle most of the work into four routines \verb|pass1|
+(see Section~\ref{pass-one}), \verb|write_tex| (see
+Section~\ref{latex-file}), \verb|write_html| (see
+Section~\ref{html-file}), and \verb|write_files| (see
+Section~\ref{output-files}). After we're finished with a
+particular file, we must remember to release its storage (see
+Section~\ref{memory-management}). The sequential numbering of scraps
+is forced when generating HTML.
+@d Process a file
+@{{
+ pass1(source_name);
+ if (tex_flag) {
+ if (html_flag) {
+ int saved_number_flag = number_flag;
+ number_flag = TRUE;
+ collect_numbers(aux_name);
+ write_html(source_name, tex_name);
+ number_flag = saved_number_flag;
+ }
+ else {
+ collect_numbers(aux_name);
+ write_tex(source_name, tex_name);
+ }
+ }
+ if (output_flag)
+ write_files(file_names);
+ arena_free();
+}@}
+
+
+\newpage
+\section{Pass One} \label{pass-one}
+
+During the first pass, we scan the file, recording the definitions of
+each macro and file and accumulating all the scraps.
+
+@d Function pro...
+@{extern void pass1();
+@}
+
+
+The routine \verb|pass1| takes a single argument, the name of the
+source file. It opens the file, then initializes the scrap structures
+(see Section~\ref{scraps}) and the roots of the file-name tree, the
+macro-name tree, and the tree of user-specified index entries (see
+Section~\ref{names}). After completing all the
+necessary preparation, we make a pass over the file, filling in all
+our data structures. Next, we seach all the scraps for references to
+the user-specified index entries. Finally, we must reverse all the
+cross-reference lists accumulated while scanning the scraps.
+@o pass1.c
+@{void pass1(file_name)
+ char *file_name;
+{
+ if (verbose_flag)
+ fprintf(stderr, "reading %s\n", file_name);
+ source_open(file_name);
+ init_scraps();
+ macro_names = NULL;
+ file_names = NULL;
+ user_names = NULL;
+ @<Scan the source file, looking for at-sequences@>
+ if (tex_flag)
+ search();
+ @<Reverse cross-reference lists@>
+}
+@| pass1 @}
+
+The only thing we look for in the first pass are the command
+sequences. All ordinary text is skipped entirely.
+@d Scan the source file, look...
+@{{
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@@')
+ @<Scan at-sequence@>
+ c = source_get();
+ }
+}@}
+
+
+Only four of the at-sequences are interesting during the first pass.
+We skip past others immediately; warning if unexpected sequences are
+discovered.
+@d Scan at-sequence
+@{{
+ c = source_get();
+ switch (c) {
+ case 'O':
+ case 'o': @<Build output file definition@>
+ break;
+ case 'D':
+ case 'd': @<Build macro definition@>
+ break;
+ case '@@':
+ case 'u':
+ case 'm':
+ case 'f': /* ignore during this pass */
+ break;
+ default: fprintf(stderr,
+ "%s: unexpected @@ sequence ignored (%s, line %d)\n",
+ command_name, source_name, source_line);
+ break;
+ }
+}@}
+
+\subsection{Accumulating Definitions}
+
+There are three steps required to handle a definition:
+\begin{enumerate}
+\item Build an entry for the name so we can look it up later.
+\item Collect the scrap and save it in the table of scraps.
+\item Attach the scrap to the name.
+\end{enumerate}
+We go through the same steps for both file names and macro names.
+@d Build output file definition
+@{{
+ Name *name = collect_file_name(); /* returns a pointer to the name entry */
+ int scrap = collect_scrap(); /* returns an index to the scrap */
+ @<Add \verb|scrap| to...@>
+}@}
+
+
+@d Build macro definition
+@{{
+ Name *name = collect_macro_name();
+ int scrap = collect_scrap();
+ @<Add \verb|scrap| to...@>
+}@}
+
+
+Since a file or macro may be defined by many scraps, we maintain them
+in a simple linked list. The list is actually built in reverse order,
+with each new definition being added to the head of the list.
+@d Add \verb|scrap| to \verb|name|'s definition list
+@{{
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scrap;
+ def->next = name->defs;
+ name->defs = def;
+}@}
+
+
+\subsection{Fixing the Cross References}
+
+Since the definition and reference lists for each name are accumulated
+in reverse order, we take the time at the end of \verb|pass1| to
+reverse them all so they'll be simpler to print out prettily.
+The code for \verb|reverse_lists| appears in Section~\ref{names}.
+@d Reverse cross-reference lists
+@{{
+ reverse_lists(file_names);
+ reverse_lists(macro_names);
+ reverse_lists(user_names);
+}@}
+
+
+
+\section{Writing the Latex File} \label{latex-file}
+
+The second pass (invoked via a call to \verb|write_tex|) copies most of
+the text from the source file straight into a \verb|.tex| file.
+Definitions are formatted slightly and cross-reference information is
+printed out.
+
+Note that all the formatting is handled in this section.
+If you don't like the format of definitions or indices or whatever,
+it'll be in this section somewhere. Similarly, if someone wanted to
+modify nuweb to work with a different typesetting system, this would
+be the place to look.
+
+@d Function...
+@{extern void write_tex();
+@}
+
+We need a few local function declarations before we get into the body
+of \verb|write_tex|.
+
+@o latex.c
+@{static void copy_scrap(); /* formats the body of a scrap */
+static void print_scrap_numbers(); /* formats a list of scrap numbers */
+static void format_entry(); /* formats an index entry */
+static void format_user_entry();
+@}
+
+
+The routine \verb|write_tex| takes two file names as parameters: the
+name of the web source file and the name of the \verb|.tex| output file.
+@o latex.c
+@{void write_tex(file_name, tex_name)
+ char *file_name;
+ char *tex_name;
+{
+ FILE *tex_file = fopen(tex_name, "w");
+ if (tex_file) {
+ if (verbose_flag)
+ fprintf(stderr, "writing %s\n", tex_name);
+ source_open(file_name);
+ @<Copy \verb|source_file| into \verb|tex_file|@>
+ fclose(tex_file);
+ }
+ else
+ fprintf(stderr, "%s: can't open %s\n", command_name, tex_name);
+}
+@| write_tex @}
+
+
+We make our second (and final) pass through the source web, this time
+copying characters straight into the \verb|.tex| file. However, we keep
+an eye peeled for \verb|@@|~characters, which signal a command sequence.
+
+@d Copy \verb|source_file| into \verb|tex_file|
+@{{
+ int scraps = 1;
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@@')
+ @<Interpret at-sequence@>
+ else {
+ putc(c, tex_file);
+ c = source_get();
+ }
+ }
+}@}
+
+@d Interpret at-sequence
+@{{
+ int big_definition = FALSE;
+ c = source_get();
+ switch (c) {
+ case 'O': big_definition = TRUE;
+ case 'o': @<Write output file definition@>
+ break;
+ case 'D': big_definition = TRUE;
+ case 'd': @<Write macro definition@>
+ break;
+ case 'f': @<Write index of file names@>
+ break;
+ case 'm': @<Write index of macro names@>
+ break;
+ case 'u': @<Write index of user-specified names@>
+ break;
+ case '@@': putc(c, tex_file);
+ default: c = source_get();
+ break;
+ }
+}@}
+
+
+\subsection{Formatting Definitions}
+
+We go through a fair amount of effort to format a file definition.
+I've derived most of the \LaTeX\ commands experimentally; it's quite
+likely that an expert could do a better job. The \LaTeX\ for
+the previous macro definition should look like this (perhaps modulo
+the scrap references):
+{\small
+\begin{verbatim}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap37}
+$\langle$Interpret at-sequence {\footnotesize 18}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@{@@\\
+\mbox{}\verb@@ int big_definition = FALSE;@@\\
+\mbox{}\verb@@ c = source_get();@@\\
+\mbox{}\verb@@ switch (c) {@@\\
+\mbox{}\verb@@ case 'O': big_definition = TRUE;@@\\
+\mbox{}\verb@@ case 'o': @@$\langle$Write output file definition {\footnotesize 19a}$\rangle$\verb@@@@\\
+\end{verbatim}
+\vdots
+\begin{verbatim}
+\mbox{}\verb@@ case '@@{\tt @@}\verb@@': putc(c, tex_file);@@\\
+\mbox{}\verb@@ default: c = source_get();@@\\
+\mbox{}\verb@@ break;@@\\
+\mbox{}\verb@@ }@@\\
+\mbox{}\verb@@}@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 17b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\end{verbatim}}
+
+\noindent
+The {\em flushleft\/} environment is used to avoid \LaTeX\ warnings
+about underful lines. The {\em minipage\/} environment is used to
+avoid page breaks in the middle of scraps. The {\em verb\/} command
+allows arbitrary characters to be printed (however, note the special
+handling of the \verb|@@| case in the switch statement).
+
+Macro and file definitions are formatted nearly identically.
+I've factored the common parts out into separate scraps.
+
+@d Write output file definition
+@{{
+ Name *name = collect_file_name();
+ @<Begin the scrap environment@>
+ fprintf(tex_file, "\\verb@@\"%s\"@@ {\\footnotesize ", name->spelling);
+ write_single_scrap_ref(tex_file, scraps++);
+ fputs(" }$\\equiv$\n", tex_file);
+ @<Fill in the middle of the scrap environment@>
+ @<Write file defs@>
+ @<Finish the scrap environment@>
+}@}
+
+
+I don't format a macro name at all specially, figuring the programmer
+might want to use italics or bold face in the midst of the name.
+
+@d Write macro definition
+@{{
+ Name *name = collect_macro_name();
+ @<Begin the scrap environment@>
+ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);
+ write_single_scrap_ref(tex_file, scraps++);
+ fputs("}$\\rangle\\equiv$\n", tex_file);
+ @<Fill in the middle of the scrap environment@>
+ @<Write macro defs@>
+ @<Write macro refs@>
+ @<Finish the scrap environment@>
+}@}
+
+
+@d Begin the scrap environment
+@{{
+ fputs("\\begin{flushleft} \\small", tex_file);
+ if (!big_definition)
+ fputs("\n\\begin{minipage}{\\linewidth}", tex_file);
+ fprintf(tex_file, " \\label{scrap%d}\n", scraps);
+}@}
+
+The interesting things here are the $\Diamond$ inserted at the end of
+each scrap and the various spacing commands. The diamond helps to
+clearly indicate the end of a scrap. The spacing commands were derived
+empirically; they may be adjusted to taste.
+
+@d Fill in the middle of the scrap environment
+@{{
+ fputs("\\vspace{-1ex}\n\\begin{list}{}{} \\item\n", tex_file);
+ copy_scrap(tex_file);
+ fputs("$\\Diamond$\n\\end{list}\n", tex_file);
+}@}
+
+\newpage
+\noindent
+We've got one last spacing command, controlling the amount of white
+space after a scrap.
+
+Note also the whitespace eater. I use it to remove any blank lines
+that appear after a scrap in the source file. This way, text following
+a scrap will not be indented. Again, this is a matter of personal taste.
+
+@d Finish the scrap environment
+@{{
+ if (!big_definition)
+ fputs("\\end{minipage}\\\\[4ex]\n", tex_file);
+ fputs("\\end{flushleft}\n", tex_file);
+ do
+ c = source_get();
+ while (isspace(c));
+}@}
+
+
+\subsubsection{Formatting Cross References}
+
+@d Write file defs
+@{{
+ if (name->defs->next) {
+ fputs("\\vspace{-1ex}\n", tex_file);
+ fputs("\\footnotesize\\addtolength{\\baselineskip}{-1ex}\n", tex_file);
+ fputs("\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}", tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ fputs("\\item File defined by scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->defs);
+ fputs("\\end{list}\n", tex_file);
+ }
+ else
+ fputs("\\vspace{-2ex}\n", tex_file);
+}@}
+
+@d Write macro defs
+@{{
+ fputs("\\vspace{-1ex}\n", tex_file);
+ fputs("\\footnotesize\\addtolength{\\baselineskip}{-1ex}\n", tex_file);
+ fputs("\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}", tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ if (name->defs->next) {
+ fputs("\\item Macro defined by scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->defs);
+ }
+}@}
+
+@d Write macro refs
+@{{
+ if (name->uses) {
+ if (name->uses->next) {
+ fputs("\\item Macro referenced in scraps ", tex_file);
+ print_scrap_numbers(tex_file, name->uses);
+ }
+ else {
+ fputs("\\item Macro referenced in scrap ", tex_file);
+ write_single_scrap_ref(tex_file, name->uses->scrap);
+ fputs(".\n", tex_file);
+ }
+ }
+ else {
+ fputs("\\item Macro never referenced.\n", tex_file);
+ fprintf(stderr, "%s: <%s> never referenced.\n",
+ command_name, name->spelling);
+ }
+ fputs("\\end{list}\n", tex_file);
+}@}
+
+
+@o latex.c
+@{static void print_scrap_numbers(tex_file, scraps)
+ FILE *tex_file;
+ Scrap_Node *scraps;
+{
+ int page;
+ write_scrap_ref(tex_file, scraps->scrap, TRUE, &page);
+ scraps = scraps->next;
+ while (scraps) {
+ write_scrap_ref(tex_file, scraps->scrap, FALSE, &page);
+ scraps = scraps->next;
+ }
+ fputs(".\n", tex_file);
+}
+@| print_scrap_numbers @}
+
+
+\subsubsection{Formatting a Scrap}
+
+We add a \verb|\mbox{}| at the beginning of each line to avoid
+problems with older versions of \TeX.
+
+@o latex.c
+@{static void copy_scrap(file)
+ FILE *file;
+{
+ int indent = 0;
+ int c = source_get();
+ fputs("\\mbox{}\\verb@@", file);
+ while (1) {
+ switch (c) {
+ case '@@': @<Check at-sequence for end-of-scrap@>
+ break;
+ case '\n': fputs("@@\\\\\n\\mbox{}\\verb@@", file);
+ indent = 0;
+ break;
+ case '\t': @<Expand tab into spaces@>
+ break;
+ default: putc(c, file);
+ indent++;
+ break;
+ }
+ c = source_get();
+ }
+}
+@| copy_scrap @}
+
+
+@d Expand tab into spaces
+@{{
+ int delta = 8 - (indent % 8);
+ indent += delta;
+ while (delta > 0) {
+ putc(' ', file);
+ delta--;
+ }
+}@}
+
+@d Check at-sequence...
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': fputs("@@{\\tt @@}\\verb@@", file);
+ break;
+ case '|': @<Skip over index entries@>
+ case '}': putc('@@', file);
+ return;
+ case '<': @<Format macro name@>
+ break;
+ default: /* ignore these since pass1 will have warned about them */
+ break;
+ }
+}@}
+
+There's no need to check for errors here, since we will have already
+pointed out any during the first pass.
+@d Skip over index entries
+@{{
+ do {
+ do
+ c = source_get();
+ while (c != '@@');
+ c = source_get();
+ } while (c != '}');
+}@}
+
+
+@d Format macro name
+@{{
+ Name *name = collect_scrap_name();
+ fprintf(file, "@@$\\langle$%s {\\footnotesize ", name->spelling);
+ if (name->defs)
+ @<Write abbreviated definition list@>
+ else {
+ putc('?', file);
+ fprintf(stderr, "%s: scrap never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ fputs("}$\\rangle$\\verb@@", file);
+}@}
+
+
+@d Write abbreviated definition list
+@{{
+ Scrap_Node *p = name->defs;
+ write_single_scrap_ref(file, p->scrap);
+ p = p->next;
+ if (p)
+ fputs(", \\ldots\\ ", file);
+}@}
+
+
+\subsection{Generating the Indices}
+
+@d Write index of file names
+@{{
+ if (file_names) {
+ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",
+ tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ format_entry(file_names, tex_file, TRUE);
+ fputs("\\end{list}}", tex_file);
+ }
+ c = source_get();
+}@}
+
+
+@d Write index of macro names
+@{{
+ if (macro_names) {
+ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",
+ tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ format_entry(macro_names, tex_file, FALSE);
+ fputs("\\end{list}}", tex_file);
+ }
+ c = source_get();
+}@}
+
+
+@o latex.c
+@{static void format_entry(name, tex_file, file_flag)
+ Name *name;
+ FILE *tex_file;
+ int file_flag;
+{
+ while (name) {
+ format_entry(name->llink, tex_file, file_flag);
+ @<Format an index entry@>
+ name = name->rlink;
+ }
+}
+@| format_entry @}
+
+
+@d Format an index entry
+@{{
+ fputs("\\item ", tex_file);
+ if (file_flag) {
+ fprintf(tex_file, "\\verb@@\"%s\"@@ ", name->spelling);
+ @<Write file's defining scrap numbers@>
+ }
+ else {
+ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);
+ @<Write defining scrap numbers@>
+ fputs("}$\\rangle$ ", tex_file);
+ @<Write referencing scrap numbers@>
+ }
+ putc('\n', tex_file);
+}@}
+
+
+@d Write file's defining scrap numbers
+@{{
+ Scrap_Node *p = name->defs;
+ fputs("{\\footnotesize Defined by scrap", tex_file);
+ if (p->next) {
+ fputs("s ", tex_file);
+ print_scrap_numbers(tex_file, p);
+ }
+ else {
+ putc(' ', tex_file);
+ write_single_scrap_ref(tex_file, p->scrap);
+ putc('.', tex_file);
+ }
+ putc('}', tex_file);
+}@}
+
+@d Write defining scrap numbers
+@{{
+ Scrap_Node *p = name->defs;
+ if (p) {
+ int page;
+ write_scrap_ref(tex_file, p->scrap, TRUE, &page);
+ p = p->next;
+ while (p) {
+ write_scrap_ref(tex_file, p->scrap, FALSE, &page);
+ p = p->next;
+ }
+ }
+ else
+ putc('?', tex_file);
+}@}
+
+@d Write referencing scrap numbers
+@{{
+ Scrap_Node *p = name->uses;
+ fputs("{\\footnotesize ", tex_file);
+ if (p) {
+ fputs("Referenced in scrap", tex_file);
+ if (p->next) {
+ fputs("s ", tex_file);
+ print_scrap_numbers(tex_file, p);
+ }
+ else {
+ putc(' ', tex_file);
+ write_single_scrap_ref(tex_file, p->scrap);
+ putc('.', tex_file);
+ }
+ }
+ else
+ fputs("Not referenced.", tex_file);
+ putc('}', tex_file);
+}@}
+
+
+@d Write index of user-specified names
+@{{
+ if (user_names) {
+ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",
+ tex_file);
+ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);
+ format_user_entry(user_names, tex_file);
+ fputs("\\end{list}}", tex_file);
+ }
+ c = source_get();
+}@}
+
+
+@o latex.c
+@{static void format_user_entry(name, tex_file)
+ Name *name;
+ FILE *tex_file;
+{
+ while (name) {
+ format_user_entry(name->llink, tex_file);
+ @<Format a user index entry@>
+ name = name->rlink;
+ }
+}
+@| format_user_entry @}
+
+
+@d Format a user index entry
+@{{
+ Scrap_Node *uses = name->uses;
+ if (uses) {
+ int page;
+ Scrap_Node *defs = name->defs;
+ fprintf(tex_file, "\\item \\verb@@%s@@: ", name->spelling);
+ if (uses->scrap < defs->scrap) {
+ write_scrap_ref(tex_file, uses->scrap, TRUE, &page);
+ uses = uses->next;
+ }
+ else {
+ if (defs->scrap == uses->scrap)
+ uses = uses->next;
+ fputs("\\underline{", tex_file);
+ write_single_scrap_ref(tex_file, defs->scrap);
+ putc('}', tex_file);
+ page = -2;
+ defs = defs->next;
+ }
+ while (uses || defs) {
+ if (uses && (!defs || uses->scrap < defs->scrap)) {
+ write_scrap_ref(tex_file, uses->scrap, FALSE, &page);
+ uses = uses->next;
+ }
+ else {
+ if (uses && defs->scrap == uses->scrap)
+ uses = uses->next;
+ fputs(", \\underline{", tex_file);
+ write_single_scrap_ref(tex_file, defs->scrap);
+ putc('}', tex_file);
+ page = -2;
+ defs = defs->next;
+ }
+ }
+ fputs(".\n", tex_file);
+ }
+}@}
+
+\section{Writing the LaTeX File with HTML Scraps} \label{html-file}
+
+The HTML generated is patterned closely upon the {\LaTeX} generated in
+the previous section.\footnote{\relax While writing this section, I
+tried to follow Preston's style as displayed in
+Section~\ref{latex-file}---J. D. R.} When a file name ends in
+\verb|.hw|, the second pass (invoked via a call to \verb|write_html|)
+copies most of the text from the source file straight into a
+\verb|.tex| file. Definitions are formatted slightly and
+cross-reference information is printed out.
+
+@d Function...
+@{extern void write_html();
+@}
+
+We need a few local function declarations before we get into the body
+of \verb|write_html|.
+
+@o html.c
+@{static void copy_scrap(); /* formats the body of a scrap */
+static void display_scrap_ref(); /* formats a scrap reference */
+static void display_scrap_numbers(); /* formats a list of scrap numbers */
+static void print_scrap_numbers(); /* pluralizes scrap formats list */
+static void format_entry(); /* formats an index entry */
+static void format_user_entry();
+@}
+
+
+The routine \verb|write_html| takes two file names as parameters: the
+name of the web source file and the name of the \verb|.tex| output file.
+@o html.c
+@{void write_html(file_name, html_name)
+ char *file_name;
+ char *html_name;
+{
+ FILE *html_file = fopen(html_name, "w");
+ if (html_file) {
+ if (verbose_flag)
+ fprintf(stderr, "writing %s\n", html_name);
+ source_open(file_name);
+ @<Copy \verb|source_file| into \verb|html_file|@>
+ fclose(html_file);
+ }
+ else
+ fprintf(stderr, "%s: can't open %s\n", command_name, html_name);
+}
+@| write_html @}
+
+
+We make our second (and final) pass through the source web, this time
+copying characters straight into the \verb|.tex| file. However, we keep
+an eye peeled for \verb|@@|~characters, which signal a command sequence.
+
+@d Copy \verb|source_file| into \verb|html_file|
+@{{
+ int scraps = 1;
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@@')
+ @<Interpret HTML at-sequence@>
+ else {
+ putc(c, html_file);
+ c = source_get();
+ }
+ }
+}@}
+
+@d Interpret HTML at-sequence
+@{{
+ c = source_get();
+ switch (c) {
+ case 'O':
+ case 'o': @<Write HTML output file definition@>
+ break;
+ case 'D':
+ case 'd': @<Write HTML macro definition@>
+ break;
+ case 'f': @<Write HTML index of file names@>
+ break;
+ case 'm': @<Write HTML index of macro names@>
+ break;
+ case 'u': @<Write HTML index of user-specified names@>
+ break;
+ case '@@': putc(c, html_file);
+ default: c = source_get();
+ break;
+ }
+}@}
+
+
+\subsection{Formatting Definitions}
+
+We go through only a little amount of effort to format a definition.
+The HTML for the previous macro definition should look like this
+(perhaps modulo the scrap references):
+
+\begin{verbatim}
+<pre>
+<a name="nuweb68">&lt;Interpret HTML at-sequence 68&gt;</a> =
+{
+ c = source_get();
+ switch (c) {
+ case 'O':
+ case 'o': &lt;Write HTML output file definition <a href="#nuweb69">69</a>&gt;
+ break;
+ case 'D':
+ case 'd': &lt;Write HTML macro definition <a href="#nuweb71">71</a>&gt;
+ break;
+ case 'f': &lt;Write HTML index of file names <a href="#nuweb86">86</a>&gt;
+ break;
+ case 'm': &lt;Write HTML index of macro names <a href="#nuweb87">87</a>&gt;
+ break;
+ case 'u': &lt;Write HTML index of user-specified names <a href="#nuweb93">93</a>&gt;
+ break;
+ case '@@': putc(c, html_file);
+ default: c = source_get();
+ break;
+ }
+}&lt;&gt;</pre>
+Macro referenced in scrap <a href="#nuweb67">67</a>.
+<br>
+\end{verbatim}
+
+Macro and file definitions are formatted nearly identically.
+I've factored the common parts out into separate scraps.
+
+@d Write HTML output file definition
+@{{
+ Name *name = collect_file_name();
+ @<Begin HTML scrap environment@>
+ @<Write HTML output file declaration@>
+ scraps++;
+ @<Fill in the middle of HTML scrap environment@>
+ @<Write HTML file defs@>
+ @<Finish HTML scrap environment@>
+}@}
+
+@d Write HTML output file declaration
+@{ fputs("<a name=\"nuweb", html_file);
+ write_single_scrap_ref(html_file, scraps);
+ fprintf(html_file, "\"><code>\"%s\"</code> ", name->spelling);
+ write_single_scrap_ref(html_file, scraps);
+ fputs("</a> =\n", html_file);
+@}
+
+@d Write HTML macro definition
+@{{
+ Name *name = collect_macro_name();
+ @<Begin HTML scrap environment@>
+ @<Write HTML macro declaration@>
+ scraps++;
+ @<Fill in the middle of HTML scrap environment@>
+ @<Write HTML macro defs@>
+ @<Write HTML macro refs@>
+ @<Finish HTML scrap environment@>
+}@}
+
+I don't format a macro name at all specially, figuring the programmer
+might want to use italics or bold face in the midst of the name. Note
+that in this implementation, programmers may only use directives in
+macro names that are recognized in preformatted text elements (PRE).
+
+@d Write HTML macro declaration
+@{ fputs("<a name=\"nuweb", html_file);
+ write_single_scrap_ref(html_file, scraps);
+ fprintf(html_file, "\">&lt;%s ", name->spelling);
+ write_single_scrap_ref(html_file, scraps);
+ fputs("&gt;</a> =\n", html_file);
+@}
+
+@d Begin HTML scrap environment
+@{{
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<pre>\n", html_file);
+}@}
+
+The end of a scrap is marked with the characters \verb|<>|.
+@d Fill in the middle of HTML scrap environment
+@{{
+ copy_scrap(html_file);
+ fputs("&lt;&gt;</pre>\n", html_file);
+}@}
+
+The only task remaining is to get rid of the current at command and
+end the paragraph.
+
+@d Finish HTML scrap environment
+@{{
+ fputs("\\end{rawhtml}\n", html_file);
+ c = source_get(); /* Get rid of current at command. */
+}@}
+
+
+\subsubsection{Formatting Cross References}
+
+@d Write HTML file defs
+@{{
+ if (name->defs->next) {
+ fputs("File defined by ", html_file);
+ print_scrap_numbers(html_file, name->defs);
+ fputs("<br>\n", html_file);
+ }
+}@}
+
+@d Write HTML macro defs
+@{{
+ if (name->defs->next) {
+ fputs("Macro defined by ", html_file);
+ print_scrap_numbers(html_file, name->defs);
+ fputs("<br>\n", html_file);
+ }
+}@}
+
+@d Write HTML macro refs
+@{{
+ if (name->uses) {
+ fputs("Macro referenced in ", html_file);
+ print_scrap_numbers(html_file, name->uses);
+ }
+ else {
+ fputs("Macro never referenced.\n", html_file);
+ fprintf(stderr, "%s: <%s> never referenced.\n",
+ command_name, name->spelling);
+ }
+ fputs("<br>\n", html_file);
+}@}
+
+@o html.c
+@{static void display_scrap_ref(html_file, num)
+ FILE *html_file;
+ int num;
+{
+ fputs("<a href=\"#nuweb", html_file);
+ write_single_scrap_ref(html_file, num);
+ fputs("\">", html_file);
+ write_single_scrap_ref(html_file, num);
+ fputs("</a>", html_file);
+}
+@| display_scrap_ref @}
+
+@o html.c
+@{static void display_scrap_numbers(html_file, scraps)
+ FILE *html_file;
+ Scrap_Node *scraps;
+{
+ display_scrap_ref(html_file, scraps->scrap);
+ scraps = scraps->next;
+ while (scraps) {
+ fputs(", ", html_file);
+ display_scrap_ref(html_file, scraps->scrap);
+ scraps = scraps->next;
+ }
+}
+@| display_scrap_numbers @}
+
+@o html.c
+@{static void print_scrap_numbers(html_file, scraps)
+ FILE *html_file;
+ Scrap_Node *scraps;
+{
+ fputs("scrap", html_file);
+ if (scraps->next) fputc('s', html_file);
+ fputc(' ', html_file);
+ display_scrap_numbers(html_file, scraps);
+ fputs(".\n", html_file);
+}
+@| print_scrap_numbers @}
+
+
+\subsubsection{Formatting a Scrap}
+
+We must translate HTML special keywords into entities in scraps.
+
+@o html.c
+@{static void copy_scrap(file)
+ FILE *file;
+{
+ int indent = 0;
+ int c = source_get();
+ while (1) {
+ switch (c) {
+ case '@@': @<Check HTML at-sequence for end-of-scrap@>
+ break;
+ case '<' : fputs("&lt;", file);
+ indent++;
+ break;
+ case '>' : fputs("&gt;", file);
+ indent++;
+ break;
+ case '&' : fputs("&amp;", file);
+ indent++;
+ break;
+ case '\n': fputc(c, file);
+ indent = 0;
+ break;
+ case '\t': @<Expand tab into spaces@>
+ break;
+ default: putc(c, file);
+ indent++;
+ break;
+ }
+ c = source_get();
+ }
+}
+@| copy_scrap @}
+
+@d Check HTML at-sequence...
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': fputc(c, file);
+ break;
+ case '|': @<Skip over index entries@>
+ case '}': return;
+ case '<': @<Format HTML macro name@>
+ break;
+ default: /* ignore these since pass1 will have warned about them */
+ break;
+ }
+}@}
+
+There's no need to check for errors here, since we will have already
+pointed out any during the first pass.
+
+@d Format HTML macro name
+@{{
+ Name *name = collect_scrap_name();
+ fprintf(file, "&lt;%s ", name->spelling);
+ if (name->defs)
+ @<Write HTML abbreviated definition list@>
+ else {
+ putc('?', file);
+ fprintf(stderr, "%s: scrap never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ fputs("&gt;", file);
+}@}
+
+
+@d Write HTML abbreviated definition list
+@{{
+ Scrap_Node *p = name->defs;
+ display_scrap_ref(file, p->scrap);
+ if (p->next)
+ fputs(", ... ", file);
+}@}
+
+
+\subsection{Generating the Indices}
+
+@d Write HTML index of file names
+@{{
+ if (file_names) {
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<dl compact>\n", html_file);
+ format_entry(file_names, html_file, TRUE);
+ fputs("</dl>\n", html_file);
+ fputs("\\end{rawhtml}\n", html_file);
+ }
+ c = source_get();
+}@}
+
+
+@d Write HTML index of macro names
+@{{
+ if (macro_names) {
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<dl compact>\n", html_file);
+ format_entry(macro_names, html_file, FALSE);
+ fputs("</dl>\n", html_file);
+ fputs("\\end{rawhtml}\n", html_file);
+ }
+ c = source_get();
+}@}
+
+
+@o html.c
+@{static void format_entry(name, html_file, file_flag)
+ Name *name;
+ FILE *html_file;
+ int file_flag;
+{
+ while (name) {
+ format_entry(name->llink, html_file, file_flag);
+ @<Format an HTML index entry@>
+ name = name->rlink;
+ }
+}
+@| format_entry @}
+
+
+@d Format an HTML index entry
+@{{
+ fputs("<dt> ", html_file);
+ if (file_flag) {
+ fprintf(html_file, "<code>\"%s\"</code>\n<dd> ", name->spelling);
+ @<Write HTML file's defining scrap numbers@>
+ }
+ else {
+ fprintf(html_file, "&lt;%s ", name->spelling);
+ @<Write HTML defining scrap numbers@>
+ fputs("&gt;\n<dd> ", html_file);
+ @<Write HTML referencing scrap numbers@>
+ }
+ putc('\n', html_file);
+}@}
+
+
+@d Write HTML file's defining scrap numbers
+@{{
+ fputs("Defined by ", html_file);
+ print_scrap_numbers(html_file, name->defs);
+}@}
+
+@d Write HTML defining scrap numbers
+@{{
+ if (name->defs)
+ display_scrap_numbers(html_file, name->defs);
+ else
+ putc('?', html_file);
+}@}
+
+@d Write HTML referencing scrap numbers
+@{{
+ Scrap_Node *p = name->uses;
+ if (p) {
+ fputs("Referenced in ", html_file);
+ print_scrap_numbers(html_file, p);
+ }
+ else
+ fputs("Not referenced.\n", html_file);
+}@}
+
+
+@d Write HTML index of user-specified names
+@{{
+ if (user_names) {
+ fputs("\\begin{rawhtml}\n", html_file);
+ fputs("<dl compact>\n", html_file);
+ format_user_entry(user_names, html_file);
+ fputs("</dl>\n", html_file);
+ fputs("\\end{rawhtml}\n", html_file);
+ }
+ c = source_get();
+}@}
+
+
+@o html.c
+@{static void format_user_entry(name, html_file)
+ Name *name;
+ FILE *html_file;
+{
+ while (name) {
+ format_user_entry(name->llink, html_file);
+ @<Format a user HTML index entry@>
+ name = name->rlink;
+ }
+}
+@| format_user_entry @}
+
+
+@d Format a user HTML index entry
+@{{
+ Scrap_Node *uses = name->uses;
+ if (uses) {
+ Scrap_Node *defs = name->defs;
+ fprintf(html_file, "<dt><code>%s</code>:\n<dd> ", name->spelling);
+ if (uses->scrap < defs->scrap) {
+ display_scrap_ref(html_file, uses->scrap);
+ uses = uses->next;
+ }
+ else {
+ if (defs->scrap == uses->scrap)
+ uses = uses->next;
+ fputs("<strong>", html_file);
+ display_scrap_ref(html_file, defs->scrap);
+ fputs("</strong>", html_file);
+ defs = defs->next;
+ }
+ while (uses || defs) {
+ fputs(", ", html_file);
+ if (uses && (!defs || uses->scrap < defs->scrap)) {
+ display_scrap_ref(html_file, uses->scrap);
+ uses = uses->next;
+ }
+ else {
+ if (uses && defs->scrap == uses->scrap)
+ uses = uses->next;
+ fputs("<strong>", html_file);
+ display_scrap_ref(html_file, defs->scrap);
+ fputs("</strong>", html_file);
+ defs = defs->next;
+ }
+ }
+ fputs(".\n", html_file);
+ }
+}@}
+
+\section{Writing the Output Files} \label{output-files}
+
+@d Function pro...
+@{extern void write_files();
+@}
+
+@o output.c
+@{void write_files(files)
+ Name *files;
+{
+ while (files) {
+ write_files(files->llink);
+ @<Write out \verb|files->spelling|@>
+ files = files->rlink;
+ }
+}
+@| write_files @}
+
+We call \verb|tempnam|, causing it to create a file name in the
+current directory. This could cause a problem for \verb|rename| if
+the eventual output file will reside on a different file system.
+Perhaps it would be better to examine \verb|files->spelling| to find
+any directory information.
+
+Note the superfluous call to \verb|remove| before \verb|rename|.
+We're using it get around a bug in some implementations of
+\verb|rename|.
+
+@d Write out \verb|files->spelling|
+@{{
+ char indent_chars[500];
+ FILE *temp_file;
+ char *temp_name = tempnam(".", 0);
+ temp_file = fopen(temp_name, "w");
+ if (!temp_file) {
+ fprintf(stderr, "%s: can't create %s for a temporary file\n",
+ command_name, temp_name);
+ exit(-1);
+ }
+ if (verbose_flag)
+ fprintf(stderr, "writing %s\n", files->spelling);
+ write_scraps(temp_file, files->defs, 0, indent_chars,
+ files->debug_flag, files->tab_flag, files->indent_flag);
+ fclose(temp_file);
+ if (compare_flag)
+ @<Compare the temp file and the old file@>
+ else {
+ remove(files->spelling);
+ rename(temp_name, files->spelling);
+ }
+}@}
+
+Again, we use a call to \verb|remove| before \verb|rename|.
+@d Compare the temp file...
+@{{
+ FILE *old_file = fopen(files->spelling, "r");
+ if (old_file) {
+ int x, y;
+ temp_file = fopen(temp_name, "r");
+ do {
+ x = getc(old_file);
+ y = getc(temp_file);
+ } while (x == y && x != EOF);
+ fclose(old_file);
+ fclose(temp_file);
+ if (x == y)
+ remove(temp_name);
+ else {
+ remove(files->spelling);
+ rename(temp_name, files->spelling);
+ }
+ }
+ else
+ rename(temp_name, files->spelling);
+}@}
+
+
+
+\chapter{The Support Routines}
+
+\section{Source Files} \label{source-files}
+
+\subsection{Global Declarations}
+
+We need two routines to handle reading the source files.
+@d Function pro...
+@{extern void source_open(); /* pass in the name of the source file */
+extern int source_get(); /* no args; returns the next char or EOF */
+@}
+
+
+There are also two global variables maintained for use in error
+messages and such.
+@d Global variable dec...
+@{extern char *source_name; /* name of the current file */
+extern int source_line; /* current line in the source file */
+@| source_name source_line @}
+
+@d Global variable def...
+@{char *source_name = NULL;
+int source_line = 0;
+@}
+
+\subsection{Local Declarations}
+
+
+@o input.c
+@{static FILE *source_file; /* the current input file */
+static int source_peek;
+static int double_at;
+static int include_depth;
+@| source_peek source_file double_at include_depth @}
+
+
+@o input.c
+@{static struct {
+ FILE *file;
+ char *name;
+ int line;
+} stack[10];
+@| stack @}
+
+
+\subsection{Reading a File}
+
+The routine \verb|source_get| returns the next character from the
+current source file. It notices newlines and keeps the line counter
+\verb|source_line| up to date. It also catches \verb|EOF| and watches
+for \verb|@@|~characters. All other characters are immediately returned.
+@o input.c
+@{int source_get()
+{
+ int c = source_peek;
+ switch (c) {
+ case EOF: @<Handle \verb|EOF|@>
+ return c;
+ case '@@': @<Handle an ``at'' character@>
+ return c;
+ case '\n': source_line++;
+ default: source_peek = getc(source_file);
+ return c;
+ }
+}
+@| source_get @}
+
+
+This whole \verb|@@|~character handling mess is pretty annoying.
+I want to recognize \verb|@@i| so I can handle include files correctly.
+At the same time, it makes sense to recognize illegal \verb|@@|~sequences
+and complain; this avoids ever having to check anywhere else.
+Unfortunately, I need to avoid tripping over the \verb|@@@@|~sequence;
+hence this whole unsatisfactory \verb|double_at| business.
+@d Handle an ``at''...
+@{{
+ c = getc(source_file);
+ if (double_at) {
+ source_peek = c;
+ double_at = FALSE;
+ c = '@@';
+ }
+ else
+ switch (c) {
+ case 'i': @<Open an include file@>
+ break;
+ case 'f': case 'm': case 'u':
+ case 'd': case 'o': case 'D': case 'O':
+ case '{': case '}': case '<': case '>': case '|':
+ source_peek = c;
+ c = '@@';
+ break;
+ case '@@': source_peek = c;
+ double_at = TRUE;
+ break;
+ default: fprintf(stderr, "%s: bad @@ sequence (%s, line %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+@d Open an include file
+@{{
+ char name[100];
+ if (include_depth >= 10) {
+ fprintf(stderr, "%s: include nesting too deep (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ @<Collect include-file name@>
+ stack[include_depth].name = source_name;
+ stack[include_depth].file = source_file;
+ stack[include_depth].line = source_line + 1;
+ include_depth++;
+ source_line = 1;
+ source_name = save_string(name);
+ source_file = fopen(source_name, "r");
+ if (!source_file) {
+ fprintf(stderr, "%s: can't open include file %s\n",
+ command_name, source_name);
+ exit(-1);
+ }
+ source_peek = getc(source_file);
+ c = source_get();
+}@}
+
+@d Collect include-file name
+@{{
+ char *p = name;
+ do
+ c = getc(source_file);
+ while (c == ' ' || c == '\t');
+ while (isgraph(c)) {
+ *p++ = c;
+ c = getc(source_file);
+ }
+ *p = '\0';
+ if (c != '\n') {
+ fprintf(stderr, "%s: unexpected characters after file name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+If an \verb|EOF| is discovered, the current file must be closed and
+input from the next stacked file must be resumed. If no more files are
+on the stack, the \verb|EOF| is returned.
+@d Handle \verb|EOF|
+@{{
+ fclose(source_file);
+ if (include_depth) {
+ include_depth--;
+ source_file = stack[include_depth].file;
+ source_line = stack[include_depth].line;
+ source_name = stack[include_depth].name;
+ source_peek = getc(source_file);
+ c = source_get();
+ }
+}@}
+
+
+\subsection{Opening a File}
+
+The routine \verb|source_open| takes a file name and tries to open the
+file. If unsuccessful, it complains and halts. Otherwise, it sets
+\verb|source_name|, \verb|source_line|, and \verb|double_at|.
+@o input.c
+@{void source_open(name)
+ char *name;
+{
+ source_file = fopen(name, "r");
+ if (!source_file) {
+ fprintf(stderr, "%s: couldn't open %s\n", command_name, name);
+ exit(-1);
+ }
+ source_name = name;
+ source_line = 1;
+ source_peek = getc(source_file);
+ double_at = FALSE;
+ include_depth = 0;
+}
+@| source_open @}
+
+
+
+
+\section{Scraps} \label{scraps}
+
+
+@o scraps.c
+@{#define SLAB_SIZE 500
+
+typedef struct slab {
+ struct slab *next;
+ char chars[SLAB_SIZE];
+} Slab;
+@| Slab SLAB_SIZE @}
+
+
+@o scraps.c
+@{typedef struct {
+ char *file_name;
+ int file_line;
+ int page;
+ char letter;
+ Slab *slab;
+} ScrapEntry;
+@| ScrapEntry @}
+
+@o scraps.c
+@{static ScrapEntry *SCRAP[256];
+
+#define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
+
+static int scraps;
+@| scraps scrap_array SCRAP @}
+
+
+@d Function pro...
+@{extern void init_scraps();
+extern int collect_scrap();
+extern int write_scraps();
+extern void write_scrap_ref();
+extern void write_single_scrap_ref();
+@}
+
+
+@o scraps.c
+@{void init_scraps()
+{
+ scraps = 1;
+ SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+}
+@| init_scraps @}
+
+
+@o scraps.c
+@{void write_scrap_ref(file, num, first, page)
+ FILE *file;
+ int num;
+ int first;
+ int *page;
+{
+ if (scrap_array(num).page >= 0) {
+ if (first)
+ fprintf(file, "%d", scrap_array(num).page);
+ else if (scrap_array(num).page != *page)
+ fprintf(file, ", %d", scrap_array(num).page);
+ if (scrap_array(num).letter > 0)
+ fputc(scrap_array(num).letter, file);
+ }
+ else {
+ if (first)
+ putc('?', file);
+ else
+ fputs(", ?", file);
+ @<Warn (only once) about needing to rerun after Latex@>
+ }
+ *page = scrap_array(num).page;
+}
+@| write_scrap_ref @}
+
+@o scraps.c
+@{void write_single_scrap_ref(file, num)
+ FILE *file;
+ int num;
+{
+ int page;
+ write_scrap_ref(file, num, TRUE, &page);
+}
+@| write_single_scrap_ref @}
+
+
+@d Warn (only once) about needing to...
+@{{
+ if (!already_warned) {
+ fprintf(stderr, "%s: you'll need to rerun nuweb after running latex\n",
+ command_name);
+ already_warned = TRUE;
+ }
+}@}
+
+@d Global variable dec...
+@{extern int already_warned;
+@| already_warned @}
+
+@d Global variable def...
+@{int already_warned = 0;
+@}
+
+@o scraps.c
+@{typedef struct {
+ Slab *scrap;
+ Slab *prev;
+ int index;
+} Manager;
+@| Manager @}
+
+
+
+@o scraps.c
+@{static void push(c, manager)
+ char c;
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ scrap->chars[index++] = c;
+ if (index == SLAB_SIZE) {
+ Slab *new = (Slab *) arena_getmem(sizeof(Slab));
+ scrap->next = new;
+ manager->scrap = new;
+ index = 0;
+ }
+ manager->index = index;
+}
+@| push @}
+
+@o scraps.c
+@{static void pushs(s, manager)
+ char *s;
+ Manager *manager;
+{
+ while (*s)
+ push(*s++, manager);
+}
+@| pushs @}
+
+
+@o scraps.c
+@{int collect_scrap()
+{
+ Manager writer;
+ @<Create new scrap...@>
+ @<Accumulate scrap and return \verb|scraps++|@>
+}
+@| collect_scrap @}
+
+@d Create new scrap, managed by \verb|writer|
+@{{
+ Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
+ if ((scraps & 255) == 0)
+ SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+ scrap_array(scraps).slab = scrap;
+ scrap_array(scraps).file_name = save_string(source_name);
+ scrap_array(scraps).file_line = source_line;
+ scrap_array(scraps).page = -1;
+ scrap_array(scraps).letter = 0;
+ writer.scrap = scrap;
+ writer.index = 0;
+}@}
+
+
+@d Accumulate scrap...
+@{{
+ int c = source_get();
+ while (1) {
+ switch (c) {
+ case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
+ command_name, scrap_array(scraps).file_name,
+ scrap_array(scraps).file_line);
+ exit(-1);
+ case '@@': @<Handle at-sign during scrap accumulation@>
+ break;
+ default: push(c, &writer);
+ c = source_get();
+ break;
+ }
+ }
+}@}
+
+
+@d Handle at-sign during scrap accumulation
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': pushs("@@@@", &writer);
+ c = source_get();
+ break;
+ case '|': @<Collect user-specified index entries@>
+ case '}': push('\0', &writer);
+ return scraps++;
+ case '<': @<Handle macro invocation in scrap@>
+ break;
+ default : fprintf(stderr, "%s: unexpected @@%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+
+@d Collect user-specified index entries
+@{{
+ do {
+ char new_name[100];
+ char *p = new_name;
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c != '@@') {
+ Name *name;
+ do {
+ *p++ = c;
+ c = source_get();
+ } while (c != '@@' && !isspace(c));
+ *p = '\0';
+ name = name_add(&user_names, new_name);
+ if (!name->defs || name->defs->scrap != scraps) {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scraps;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ } while (c != '@@');
+ c = source_get();
+ if (c != '}') {
+ fprintf(stderr, "%s: unexpected @@%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+
+@d Handle macro invocation in scrap
+@{{
+ Name *name = collect_scrap_name();
+ @<Save macro name@>
+ @<Add current scrap to \verb|name|'s uses@>
+ c = source_get();
+}@}
+
+
+@d Save macro name
+@{{
+ char *s = name->spelling;
+ int len = strlen(s) - 1;
+ pushs("@@<", &writer);
+ while (len > 0) {
+ push(*s++, &writer);
+ len--;
+ }
+ if (*s == ' ')
+ pushs("...", &writer);
+ else
+ push(*s, &writer);
+ pushs("@@>", &writer);
+}@}
+
+
+@d Add current scrap to...
+@{{
+ if (!name->uses || name->uses->scrap != scraps) {
+ Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ use->scrap = scraps;
+ use->next = name->uses;
+ name->uses = use;
+ }
+}@}
+
+
+@o scraps.c
+@{static char pop(manager)
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ char c = scrap->chars[index++];
+ if (index == SLAB_SIZE) {
+ manager->prev = scrap;
+ manager->scrap = scrap->next;
+ index = 0;
+ }
+ manager->index = index;
+ return c;
+}
+@| pop @}
+
+
+
+@o scraps.c
+@{static Name *pop_scrap_name(manager)
+ Manager *manager;
+{
+ char name[100];
+ char *p = name;
+ int c = pop(manager);
+ while (TRUE) {
+ if (c == '@@')
+ @<Check for end of scrap name and return@>
+ else {
+ *p++ = c;
+ c = pop(manager);
+ }
+ }
+}
+@| pop_scrap_name @}
+
+
+@d Check for end of scrap name...
+@{{
+ c = pop(manager);
+ if (c == '@@') {
+ *p++ = c;
+ c = pop(manager);
+ }
+ else if (c == '>') {
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ else {
+ fprintf(stderr, "%s: found an internal problem (1)\n", command_name);
+ exit(-1);
+ }
+}@}
+
+
+@o scraps.c
+@{int write_scraps(file, defs, global_indent, indent_chars,
+ debug_flag, tab_flag, indent_flag)
+ FILE *file;
+ Scrap_Node *defs;
+ int global_indent;
+ char *indent_chars;
+ char debug_flag;
+ char tab_flag;
+ char indent_flag;
+{
+ int indent = 0;
+ while (defs) {
+ @<Copy \verb|defs->scrap| to \verb|file|@>
+ defs = defs->next;
+ }
+ return indent + global_indent;
+}
+@| write_scraps @}
+
+
+@d Copy \verb|defs->scrap...
+@{{
+ char c;
+ Manager reader;
+ int line_number = scrap_array(defs->scrap).file_line;
+ @<Insert debugging information if required@>
+ reader.scrap = scrap_array(defs->scrap).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ switch (c) {
+ case '@@': @<Check for macro invocation in scrap@>
+ break;
+ case '\n': putc(c, file);
+ line_number++;
+ @<Insert appropriate indentation@>
+ break;
+ case '\t': @<Handle tab...@>
+ break;
+ default: putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ }
+ c = pop(&reader);
+ }
+}@}
+
+
+@d Insert debugging information if required
+@{if (debug_flag) {
+ fprintf(file, "\n#line %d \"%s\"\n",
+ line_number, scrap_array(defs->scrap).file_name);
+ @<Insert appropr...@>
+}@}
+
+
+@d Insert approp...
+@{{
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+}@}
+
+
+@d Handle tab characters on output
+@{{
+ if (tab_flag)
+ @<Expand tab...@>
+ else {
+ putc('\t', file);
+ indent_chars[global_indent + indent] = '\t';
+ indent++;
+ }
+}@}
+
+
+
+@d Check for macro invocation...
+@{{
+ c = pop(&reader);
+ switch (c) {
+ case '@@': putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ case '<': @<Copy macro into \verb|file|@>
+ @<Insert debugging information if required@>
+ break;
+ default: /* ignore, since we should already have a warning */
+ break;
+ }
+}@}
+
+
+@d Copy macro into...
+@{{
+ Name *name = pop_scrap_name(&reader);
+ if (name->mark) {
+ fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
+ command_name, name->spelling);
+ exit(-1);
+ }
+ if (name->defs) {
+ name->mark = TRUE;
+ indent = write_scraps(file, name->defs, global_indent + indent,
+ indent_chars, debug_flag, tab_flag, indent_flag);
+ indent -= global_indent;
+ name->mark = FALSE;
+ }
+ else if (!tex_flag)
+ fprintf(stderr, "%s: macro never defined <%s>\n",
+ command_name, name->spelling);
+}@}
+
+
+\subsection{Collecting Page Numbers}
+
+@d Function...
+@{extern void collect_numbers();
+@}
+
+@o scraps.c
+@{void collect_numbers(aux_name)
+ char *aux_name;
+{
+ if (number_flag) {
+ int i;
+ for (i=1; i<scraps; i++)
+ scrap_array(i).page = i;
+ }
+ else {
+ FILE *aux_file = fopen(aux_name, "r");
+ already_warned = FALSE;
+ if (aux_file) {
+ char aux_line[500];
+ while (fgets(aux_line, 500, aux_file)) {
+ int scrap_number;
+ int page_number;
+ char dummy[50];
+ if (3 == sscanf(aux_line, "\\newlabel{scrap%d}{%[^}]}{%d}",
+ &scrap_number, dummy, &page_number)) {
+ if (scrap_number < scraps)
+ scrap_array(scrap_number).page = page_number;
+ else
+ @<Warn...@>
+ }
+ }
+ fclose(aux_file);
+ @<Add letters to scraps with duplicate page numbers@>
+ }
+ }
+}
+@| collect_numbers @}
+
+@d Add letters to scraps with...
+@{{
+ int scrap;
+ for (scrap=2; scrap<scraps; scrap++) {
+ if (scrap_array(scrap-1).page == scrap_array(scrap).page) {
+ if (!scrap_array(scrap-1).letter)
+ scrap_array(scrap-1).letter = 'a';
+ scrap_array(scrap).letter = scrap_array(scrap-1).letter + 1;
+ }
+ }
+}@}
+
+
+\section{Names} \label{names}
+
+@d Type de...
+@{typedef struct scrap_node {
+ struct scrap_node *next;
+ int scrap;
+} Scrap_Node;
+@| Scrap_Node @}
+
+
+@d Type de...
+@{typedef struct name {
+ char *spelling;
+ struct name *llink;
+ struct name *rlink;
+ Scrap_Node *defs;
+ Scrap_Node *uses;
+ int mark;
+ char tab_flag;
+ char indent_flag;
+ char debug_flag;
+} Name;
+@| Name @}
+
+@d Global variable dec...
+@{extern Name *file_names;
+extern Name *macro_names;
+extern Name *user_names;
+@| file_names macro_names user_names @}
+
+@d Global variable def...
+@{Name *file_names = NULL;
+Name *macro_names = NULL;
+Name *user_names = NULL;
+@}
+
+@d Function pro...
+@{extern Name *collect_file_name();
+extern Name *collect_macro_name();
+extern Name *collect_scrap_name();
+extern Name *name_add();
+extern Name *prefix_add();
+extern char *save_string();
+extern void reverse_lists();
+@}
+
+@o names.c
+@{enum { LESS, GREATER, EQUAL, PREFIX, EXTENSION };
+
+static int compare(x, y)
+ char *x;
+ char *y;
+{
+ int len, result;
+ int xl = strlen(x);
+ int yl = strlen(y);
+ int xp = x[xl - 1] == ' ';
+ int yp = y[yl - 1] == ' ';
+ if (xp) xl--;
+ if (yp) yl--;
+ len = xl < yl ? xl : yl;
+ result = strncmp(x, y, len);
+ if (result < 0) return GREATER;
+ else if (result > 0) return LESS;
+ else if (xl < yl) {
+ if (xp) return EXTENSION;
+ else return LESS;
+ }
+ else if (xl > yl) {
+ if (yp) return PREFIX;
+ else return GREATER;
+ }
+ else return EQUAL;
+}
+@| compare LESS GREATER EQUAL PREFIX EXTENSION @}
+
+
+@o names.c
+@{char *save_string(s)
+ char *s;
+{
+ char *new = (char *) arena_getmem((strlen(s) + 1) * sizeof(char));
+ strcpy(new, s);
+ return new;
+}
+@| save_string @}
+
+@o names.c
+@{static int ambiguous_prefix();
+
+Name *prefix_add(root, spelling)
+ Name **root;
+ char *spelling;
+{
+ Name *node = *root;
+ while (node) {
+ switch (compare(node->spelling, spelling)) {
+ case GREATER: root = &node->rlink;
+ break;
+ case LESS: root = &node->llink;
+ break;
+ case EQUAL: return node;
+ case EXTENSION: node->spelling = save_string(spelling);
+ return node;
+ case PREFIX: @<Check for ambiguous prefix@>
+ return node;
+ }
+ node = *root;
+ }
+ @<Create new name entry@>
+}
+@| prefix_add @}
+
+Since a very short prefix might match more than one macro name, I need
+to check for other matches to avoid mistakes. Basically, I simply
+continue the search down {\em both\/} branches of the tree.
+
+@d Check for ambiguous prefix
+@{{
+ if (ambiguous_prefix(node->llink, spelling) ||
+ ambiguous_prefix(node->rlink, spelling))
+ fprintf(stderr,
+ "%s: ambiguous prefix @@<%s...@@> (%s, line %d)\n",
+ command_name, spelling, source_name, source_line);
+}@}
+
+@o names.c
+@{static int ambiguous_prefix(node, spelling)
+ Name *node;
+ char *spelling;
+{
+ while (node) {
+ switch (compare(node->spelling, spelling)) {
+ case GREATER: node = node->rlink;
+ break;
+ case LESS: node = node->llink;
+ break;
+ case EQUAL:
+ case EXTENSION:
+ case PREFIX: return TRUE;
+ }
+ }
+ return FALSE;
+}
+@}
+
+Rob Shillingsburg suggested that I organize the index of
+user-specified identifiers more traditionally; that is, not relying on
+strict {\small ASCII} comparisons via \verb|strcmp|. Ideally, we'd like
+to see the index ordered like this:
+\begin{quote}
+\begin{flushleft}
+aardvark \\
+Adam \\
+atom \\
+Atomic \\
+atoms
+\end{flushleft}
+\end{quote}
+The function \verb|robs_strcmp| implements the desired predicate.
+
+@o names.c
+@{static int robs_strcmp(x, y)
+ char *x;
+ char *y;
+{
+ char *xx = x;
+ char *yy = y;
+ int xc = toupper(*xx);
+ int yc = toupper(*yy);
+ while (xc == yc && xc) {
+ xx++;
+ yy++;
+ xc = toupper(*xx);
+ yc = toupper(*yy);
+ }
+ if (xc != yc) return xc - yc;
+ xc = *x;
+ yc = *y;
+ while (xc == yc && xc) {
+ x++;
+ y++;
+ xc = *x;
+ yc = *y;
+ }
+ if (isupper(xc) && islower(yc))
+ return xc * 2 - (toupper(yc) * 2 + 1);
+ if (islower(xc) && isupper(yc))
+ return toupper(xc) * 2 + 1 - yc * 2;
+ return xc - yc;
+}
+@| robs_strcmp @}
+
+@o names.c
+@{Name *name_add(root, spelling)
+ Name **root;
+ char *spelling;
+{
+ Name *node = *root;
+ while (node) {
+ int result = robs_strcmp(node->spelling, spelling);
+ if (result > 0)
+ root = &node->llink;
+ else if (result < 0)
+ root = &node->rlink;
+ else
+ return node;
+ node = *root;
+ }
+ @<Create new name entry@>
+}
+@| name_add @}
+
+
+@d Create new name...
+@{{
+ node = (Name *) arena_getmem(sizeof(Name));
+ node->spelling = save_string(spelling);
+ node->mark = FALSE;
+ node->llink = NULL;
+ node->rlink = NULL;
+ node->uses = NULL;
+ node->defs = NULL;
+ node->tab_flag = TRUE;
+ node->indent_flag = TRUE;
+ node->debug_flag = FALSE;
+ *root = node;
+ return node;
+}@}
+
+
+Name terminated by whitespace. Also check for ``per-file'' flags. Keep
+skipping white space until we reach scrap.
+@o names.c
+@{Name *collect_file_name()
+{
+ Name *new_name;
+ char name[100];
+ char *p = name;
+ int start_line = source_line;
+ int c = source_get();
+ while (isspace(c))
+ c = source_get();
+ while (isgraph(c)) {
+ *p++ = c;
+ c = source_get();
+ }
+ if (p == name) {
+ fprintf(stderr, "%s: expected file name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ *p = '\0';
+ new_name = name_add(&file_names, name);
+ @<Handle optional per-file flags@>
+ if (c != '@@' || source_get() != '{') {
+ fprintf(stderr, "%s: expected @@{ after file name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ return new_name;
+}
+@| collect_file_name @}
+
+@d Handle optional per-file flags
+@{{
+ while (1) {
+ while (isspace(c))
+ c = source_get();
+ if (c == '-') {
+ c = source_get();
+ do {
+ switch (c) {
+ case 't': new_name->tab_flag = FALSE;
+ break;
+ case 'd': new_name->debug_flag = TRUE;
+ break;
+ case 'i': new_name->indent_flag = FALSE;
+ break;
+ default : fprintf(stderr, "%s: unexpected per-file flag (%s, %d)\n",
+ command_name, source_name, source_line);
+ break;
+ }
+ c = source_get();
+ } while (!isspace(c));
+ }
+ else break;
+ }
+}@}
+
+
+
+Name terminated by \verb+\n+ or \verb+@@{+; but keep skipping until \verb+@@{+
+@o names.c
+@{Name *collect_macro_name()
+{
+ char name[100];
+ char *p = name;
+ int start_line = source_line;
+ int c = source_get();
+ while (isspace(c))
+ c = source_get();
+ while (c != EOF) {
+ switch (c) {
+ case '@@': @<Check for terminating at-sequence and return name@>
+ break;
+ case '\t':
+ case ' ': *p++ = ' ';
+ do
+ c = source_get();
+ while (c == ' ' || c == '\t');
+ break;
+ case '\n': @<Skip until scrap begins, then return name@>
+ default: *p++ = c;
+ c = source_get();
+ break;
+ }
+ }
+ fprintf(stderr, "%s: expected macro name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ return NULL; /* unreachable return to avoid warnings on some compilers */
+}
+@| collect_macro_name @}
+
+
+@d Check for termina...
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': *p++ = c;
+ break;
+ case '{': @<Cleanup and install name@>
+ default: fprintf(stderr,
+ "%s: unexpected @@%c in macro name (%s, %d)\n",
+ command_name, c, source_name, start_line);
+ exit(-1);
+ }
+}@}
+
+
+@d Cleanup and install name
+@{{
+ if (p > name && p[-1] == ' ')
+ p--;
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ if (p == name || name[0] == ' ') {
+ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+}@}
+
+
+@d Skip until scrap...
+@{{
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c != '@@' || source_get() != '{') {
+ fprintf(stderr, "%s: expected @@{ after macro name (%s, %d)\n",
+ command_name, source_name, start_line);
+ exit(-1);
+ }
+ @<Cleanup and install name@>
+}@}
+
+
+Terminated by \verb+@@>+
+@o names.c
+@{Name *collect_scrap_name()
+{
+ char name[100];
+ char *p = name;
+ int c = source_get();
+ while (c == ' ' || c == '\t')
+ c = source_get();
+ while (c != EOF) {
+ switch (c) {
+ case '@@': @<Look for end of scrap name and return@>
+ break;
+ case '\t':
+ case ' ': *p++ = ' ';
+ do
+ c = source_get();
+ while (c == ' ' || c == '\t');
+ break;
+ default: if (!isgraph(c)) {
+ fprintf(stderr,
+ "%s: unexpected character in macro name (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ }
+ *p++ = c;
+ c = source_get();
+ break;
+ }
+ }
+ fprintf(stderr, "%s: unexpected end of file (%s, %d)\n",
+ command_name, source_name, source_line);
+ exit(-1);
+ return NULL; /* unreachable return to avoid warnings on some compilers */
+}
+@| collect_scrap_name @}
+
+
+@d Look for end of scrap name...
+@{{
+ c = source_get();
+ switch (c) {
+ case '@@': *p++ = c;
+ c = source_get();
+ break;
+ case '>': @<Cleanup and install name@>
+ default: fprintf(stderr,
+ "%s: unexpected @@%c in macro name (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+}@}
+
+
+@o names.c
+@{static Scrap_Node *reverse(); /* a forward declaration */
+
+void reverse_lists(names)
+ Name *names;
+{
+ while (names) {
+ reverse_lists(names->llink);
+ names->defs = reverse(names->defs);
+ names->uses = reverse(names->uses);
+ names = names->rlink;
+ }
+}
+@| reverse_lists @}
+
+Just for fun, here's a non-recursive version of the traditional list
+reversal code. Note that it reverses the list in place; that is, it
+does no new allocations.
+@o names.c
+@{static Scrap_Node *reverse(a)
+ Scrap_Node *a;
+{
+ if (a) {
+ Scrap_Node *b = a->next;
+ a->next = NULL;
+ while (b) {
+ Scrap_Node *c = b->next;
+ b->next = a;
+ a = b;
+ b = c;
+ }
+ }
+ return a;
+}
+@| reverse @}
+
+
+\section{Searching for Index Entries} \label{search}
+
+Given the array of scraps and a set of index entries, we need to
+search all the scraps for occurrences of each entry. The obvious
+approach to this problem would be quite expensive for large documents;
+however, there is an interesting paper describing an efficient
+solution~\cite{aho:75}.
+
+
+@o scraps.c
+@{typedef struct name_node {
+ struct name_node *next;
+ Name *name;
+} Name_Node;
+@| Name_Node @}
+
+@o scraps.c
+@{typedef struct goto_node {
+ Name_Node *output; /* list of words ending in this state */
+ struct move_node *moves; /* list of possible moves */
+ struct goto_node *fail; /* and where to go when no move fits */
+ struct goto_node *next; /* next goto node with same depth */
+} Goto_Node;
+@| Goto_Node @}
+
+@o scraps.c
+@{typedef struct move_node {
+ struct move_node *next;
+ Goto_Node *state;
+ char c;
+} Move_Node;
+@| Move_Node @}
+
+@o scraps.c
+@{static Goto_Node *root[128];
+static int max_depth;
+static Goto_Node **depths;
+@| root max_depth depths @}
+
+
+@o scraps.c
+@{static Goto_Node *goto_lookup(c, g)
+ char c;
+ Goto_Node *g;
+{
+ Move_Node *m = g->moves;
+ while (m && m->c != c)
+ m = m->next;
+ if (m)
+ return m->state;
+ else
+ return NULL;
+}
+@| goto_lookup @}
+
+
+\subsection{Building the Automata}
+
+
+@d Function pro...
+@{extern void search();
+@}
+
+@o scraps.c
+@{static void build_gotos();
+static int reject_match();
+
+void search()
+{
+ int i;
+ for (i=0; i<128; i++)
+ root[i] = NULL;
+ max_depth = 10;
+ depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
+ for (i=0; i<max_depth; i++)
+ depths[i] = NULL;
+ build_gotos(user_names);
+ @<Build failure functions@>
+ @<Search scraps@>
+}
+@| search @}
+
+
+
+@o scraps.c
+@{static void build_gotos(tree)
+ Name *tree;
+{
+ while (tree) {
+ @<Extend goto graph with \verb|tree->spelling|@>
+ build_gotos(tree->rlink);
+ tree = tree->llink;
+ }
+}
+@| build_gotos @}
+
+@d Extend goto...
+@{{
+ int depth = 2;
+ char *p = tree->spelling;
+ char c = *p++;
+ Goto_Node *q = root[c];
+ if (!q) {
+ q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ root[c] = q;
+ q->moves = NULL;
+ q->fail = NULL;
+ q->moves = NULL;
+ q->output = NULL;
+ q->next = depths[1];
+ depths[1] = q;
+ }
+ while (c = *p++) {
+ Goto_Node *new = goto_lookup(c, q);
+ if (!new) {
+ Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
+ new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ new->moves = NULL;
+ new->fail = NULL;
+ new->moves = NULL;
+ new->output = NULL;
+ new_move->state = new;
+ new_move->c = c;
+ new_move->next = q->moves;
+ q->moves = new_move;
+ if (depth == max_depth) {
+ int i;
+ Goto_Node **new_depths =
+ (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
+ max_depth = 2 * depth;
+ for (i=0; i<depth; i++)
+ new_depths[i] = depths[i];
+ depths = new_depths;
+ for (i=depth; i<max_depth; i++)
+ depths[i] = NULL;
+ }
+ new->next = depths[depth];
+ depths[depth] = new;
+ }
+ q = new;
+ depth++;
+ }
+ q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->output->next = NULL;
+ q->output->name = tree;
+}@}
+
+
+@d Build failure functions
+@{{
+ int depth;
+ for (depth=1; depth<max_depth; depth++) {
+ Goto_Node *r = depths[depth];
+ while (r) {
+ Move_Node *m = r->moves;
+ while (m) {
+ char a = m->c;
+ Goto_Node *s = m->state;
+ Goto_Node *state = r->fail;
+ while (state && !goto_lookup(a, state))
+ state = state->fail;
+ if (state)
+ s->fail = goto_lookup(a, state);
+ else
+ s->fail = root[a];
+ if (s->fail) {
+ Name_Node *p = s->fail->output;
+ while (p) {
+ Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->name = p->name;
+ q->next = s->output;
+ s->output = q;
+ p = p->next;
+ }
+ }
+ m = m->next;
+ }
+ r = r->next;
+ }
+ }
+}@}
+
+
+\subsection{Searching the Scraps}
+
+@d Search scraps
+@{{
+ for (i=1; i<scraps; i++) {
+ char c;
+ Manager reader;
+ Goto_Node *state = NULL;
+ reader.prev = NULL;
+ reader.scrap = scrap_array(i).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ while (state && !goto_lookup(c, state))
+ state = state->fail;
+ if (state)
+ state = goto_lookup(c, state);
+ else
+ state = root[c];
+ c = pop(&reader);
+ if (state && state->output) {
+ Name_Node *p = state->output;
+ do {
+ Name *name = p->name;
+ if (!reject_match(name, c, &reader) &&
+ (!name->uses || name->uses->scrap != i)) {
+ Scrap_Node *new_use =
+ (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ new_use->scrap = i;
+ new_use->next = name->uses;
+ name->uses = new_use;
+ }
+ p = p->next;
+ } while (p);
+ }
+ }
+ }
+}@}
+
+
+\subsubsection{Rejecting Matches}
+
+A problem with simple substring matching is that the string ``he''
+would match longer strings like ``she'' and ``her.'' Norman Ramsey
+suggested examining the characters occurring immediately before and
+after a match and rejecting the match if it appears to be part of a
+longer token. Of course, the concept of {\sl token\/} is
+language-dependent, so we may be occasionally mistaken.
+For the present, we'll consider the mechanism an experiment.
+
+@o scraps.c
+@{#define sym_char(c) (isalnum(c) || (c) == '_')
+
+static int op_char(c)
+ char c;
+{
+ switch (c) {
+ case '!': case '@@': case '#': case '%': case '$': case '^':
+ case '&': case '*': case '-': case '+': case '=': case '/':
+ case '|': case '~': case '<': case '>':
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+@| sym_char op_char @}
+
+@o scraps.c
+@{static int reject_match(name, post, reader)
+ Name *name;
+ char post;
+ Manager *reader;
+{
+ int len = strlen(name->spelling);
+ char first = name->spelling[0];
+ char last = name->spelling[len - 1];
+ char prev = '\0';
+ len = reader->index - len - 2;
+ if (len >= 0)
+ prev = reader->scrap->chars[len];
+ else if (reader->prev)
+ prev = reader->scrap->chars[SLAB_SIZE - len];
+ if (sym_char(last) && sym_char(post)) return TRUE;
+ if (sym_char(first) && sym_char(prev)) return TRUE;
+ if (op_char(last) && op_char(post)) return TRUE;
+ if (op_char(first) && op_char(prev)) return TRUE;
+ return FALSE;
+}
+@| reject_match @}
+
+
+
+
+
+\section{Memory Management} \label{memory-management}
+
+I manage memory using a simple scheme inspired by Hanson's idea of
+{\em arenas\/}~\cite{hanson:90}.
+Basically, I allocate all the storage required when processing a
+source file (primarily for names and scraps) using calls to
+\verb|arena_getmem(n)|, where \verb|n| specifies the number of bytes to
+be allocated. When the storage is no longer required, the entire arena
+is freed with a single call to \verb|arena_free()|. Both operations
+are quite fast.
+@d Function p...
+@{extern void *arena_getmem();
+extern void arena_free();
+@}
+
+
+@o arena.c
+@{typedef struct chunk {
+ struct chunk *next;
+ char *limit;
+ char *avail;
+} Chunk;
+@| Chunk @}
+
+
+We define an empty chunk called \verb|first|. The variable \verb|arena| points
+at the current chunk of memory; it's initially pointed at \verb|first|.
+As soon as some storage is required, a ``real'' chunk of memory will
+be allocated and attached to \verb|first->next|; storage will be
+allocated from the new chunk (and later chunks if necessary).
+@o arena.c
+@{static Chunk first = { NULL, NULL, NULL };
+static Chunk *arena = &first;
+@| first arena @}
+
+
+\subsection{Allocating Memory}
+
+The routine \verb|arena_getmem(n)| returns a pointer to (at least)
+\verb|n| bytes of memory. Note that \verb|n| is rounded up to ensure
+that returned pointers are always aligned. We align to the nearest
+8~byte segment, since that'll satisfy the more common 2-byte and
+4-byte alignment restrictions too.
+
+@o arena.c
+@{void *arena_getmem(n)
+ size_t n;
+{
+ char *q;
+ char *p = arena->avail;
+ n = (n + 7) & ~7; /* ensuring alignment to 8 bytes */
+ q = p + n;
+ if (q <= arena->limit) {
+ arena->avail = q;
+ return p;
+ }
+ @<Find a new chunk of memory@>
+}
+@| arena_getmem @}
+
+
+If the current chunk doesn't have adequate space (at least \verb|n|
+bytes) we examine the rest of the list of chunks (starting at
+\verb|arena->next|) looking for a chunk with adequate space. If \verb|n|
+is very large, we may not find it right away or we may not find a
+suitable chunk at all.
+@d Find a new chunk...
+@{{
+ Chunk *ap = arena;
+ Chunk *np = ap->next;
+ while (np) {
+ char *v = sizeof(Chunk) + (char *) np;
+ if (v + n <= np->limit) {
+ np->avail = v + n;
+ arena = np;
+ return v;
+ }
+ ap = np;
+ np = ap->next;
+ }
+ @<Allocate a new chunk of memory@>
+}@}
+
+
+If there isn't a suitable chunk of memory on the free list, then we
+need to allocate a new one.
+@d Allocate a new ch...
+@{{
+ size_t m = n + 10000;
+ np = (Chunk *) malloc(m);
+ np->limit = m + (char *) np;
+ np->avail = n + sizeof(Chunk) + (char *) np;
+ np->next = NULL;
+ ap->next = np;
+ arena = np;
+ return sizeof(Chunk) + (char *) np;
+}@}
+
+
+\subsection{Freeing Memory}
+
+To free all the memory in the arena, we need only point \verb|arena|
+back to the first empty chunk.
+@o arena.c
+@{void arena_free()
+{
+ arena = &first;
+}
+@| arena_free @}
+
+
+\chapter{Indices} \label{indices}
+
+Three sets of indices can be created automatically: an index of file
+names, an index of macro names, and an index of user-specified
+identifiers. An index entry includes the name of the entry, where it
+was defined, and where it was referenced.
+
+\section{Files}
+
+@f
+
+\section{Macros}
+
+@m
+
+\section{Identifiers}
+
+Knuth prints his index of identifiers in a two-column format.
+I could force this automatically by emitting the \verb|\twocolumn|
+command; but this has the side effect of forcing a new page.
+Therefore, it seems better to leave it this up to the user.
+
+@u
+
+\fi
+
+\bibliographystyle{plain}
+\bibliography{literate}
+
+\end{document}
diff --git a/web/nuweb/nuweb0.87b/nuwebdoc.tex b/web/nuweb/nuweb0.87b/nuwebdoc.tex
new file mode 100644
index 0000000000..3d6a836d76
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/nuwebdoc.tex
@@ -0,0 +1,5796 @@
+\documentstyle{report}
+\newif\ifshowcode
+\showcodefalse
+
+\setlength{\oddsidemargin}{0in}
+\setlength{\evensidemargin}{0in}
+\setlength{\topmargin}{0in}
+\addtolength{\topmargin}{-\headheight}
+\addtolength{\topmargin}{-\headsep}
+\setlength{\textheight}{8.9in}
+\setlength{\textwidth}{6.5in}
+\setlength{\marginparwidth}{0.5in}
+
+\title{Nuweb Version 0.87b \\ A Simple Literate Programming Tool}
+\date{}
+\author{Preston Briggs\thanks{This work has been supported by ARPA,
+through ONR grant N00014-91-J-1989.}
+\\ \sl preston@cs.rice.edu
+\\ HTML scrap generator by John D. Ramsdell
+\\ \sl ramsdell@mitre.org}
+
+\begin{document}
+\pagenumbering{roman}
+\maketitle
+\tableofcontents
+
+\chapter{Introduction}
+\pagenumbering{arabic}
+
+In 1984, Knuth introduced the idea of {\em literate programming\/} and
+described a pair of tools to support the practise~\cite{knuth:84}.
+His approach was to combine Pascal code with \TeX\ documentation to
+produce a new language, \verb|WEB|, that offered programmers a superior
+approach to programming. He wrote several programs in \verb|WEB|,
+including \verb|weave| and \verb|tangle|, the programs used to support
+literate programming.
+The idea was that a programmer wrote one document, the web file, that
+combined documentation (written in \TeX~\cite{texbook}) with code
+(written in Pascal).
+
+Running \verb|tangle| on the web file would produce a complete
+Pascal program, ready for compilation by an ordinary Pascal compiler.
+The primary function of \verb|tangle| is to allow the programmer to
+present elements of the program in any desired order, regardless of
+the restrictions imposed by the programming language. Thus, the
+programmer is free to present his program in a top-down fashion,
+bottom-up fashion, or whatever seems best in terms of promoting
+understanding and maintenance.
+
+Running \verb|weave| on the web file would produce a \TeX\ file, ready
+to be processed by \TeX\@. The resulting document included a variety of
+automatically generated indices and cross-references that made it much
+easier to navigate the code. Additionally, all of the code sections
+were automatically pretty printed, resulting in a quite impressive
+document.
+
+Knuth also wrote the programs for \TeX\ and {\small\sf METAFONT}
+entirely in \verb|WEB|, eventually publishing them in book
+form~\cite{tex:program,metafont:program}. These are probably the
+largest programs ever published in a readable form.
+
+Inspired by Knuth's example, many people have experimented with
+\verb|WEB|\@. Some people have even built web-like tools for their
+own favorite combinations of programming language and typesetting
+language. For example, \verb|CWEB|, Knuth's current system of choice,
+works with a combination of C (or C++) and \TeX~\cite{levy:90}.
+Another system, FunnelWeb, is independent of any programming language
+and only mildly dependent on \TeX~\cite{funnelweb}. Inspired by the
+versatility of FunnelWeb and by the daunting size of its
+documentation, I decided to write my own, very simple, tool for
+literate programming.%
+\footnote{There is another system similar to
+mine, written by Norman Ramsey, called {\em noweb}~\cite{noweb}. It
+perhaps suffers from being overly Unix-dependent and requiring several
+programs to use. On the other hand, its command syntax is very nice.
+In any case, nuweb certainly owes its name and a number of features to
+his inspiration.}
+
+
+\section{Nuweb}
+
+Nuweb works with any programming language and \LaTeX~\cite{latex}. I
+wanted to use \LaTeX\ because it supports a multi-level sectioning
+scheme and has facilities for drawing figures. I wanted to be able to
+work with arbitrary programming languages because my friends and I
+write programs in many languages (and sometimes combinations of
+several languages), {\em e.g.,} C, Fortran, C++, yacc, lex, Scheme,
+assembly, Postscript, and so forth. The need to support arbitrary
+programming languages has many consequences:
+\begin{description}
+\item[No pretty printing] Both \verb|WEB| and \verb|CWEB| are able to
+ pretty print the code sections of their documents because they
+ understand the language well enough to parse it. Since we want to use
+ {\em any\/} language, we've got to abandon this feature.
+\item[No index of identifiers] Because \verb|WEB| knows about Pascal,
+ it is able to construct an index of all the identifiers occurring in
+ the code sections (filtering out keywords and the standard type
+ identifiers). Unfortunately, this isn't as easy in our case. We don't
+ know what an identifiers looks like in each language and we certainly
+ don't know all the keywords. (On the other hand, see the end of
+ Section~1.3)
+\end{description}
+Of course, we've got to have some compensation for our losses or the
+whole idea would be a waste. Here are the advantages I can see:
+\begin{description}
+\item[Simplicity] The majority of the commands in \verb|WEB| are
+ concerned with control of the automatic pretty printing. Since we
+ don't pretty print, many commands are eliminated. A further set of
+ commands is subsumed by \LaTeX\ and may also be eliminated. As a
+ result, our set of commands is reduced to only four members (explained
+ in the next section). This simplicity is also reflected in
+ the size of this tool, which is quite a bit smaller than the tools
+ used with other approaches.
+\item[No pretty printing] Everyone disagrees about how their code
+ should look, so automatic formatting annoys many people. One approach
+ is to provide ways to control the formatting. Our approach is
+ simpler---we perform no automatic formatting and therefore allow the
+ programmer complete control of code layout.
+\item[Control] We also offer the programmer complete control of the
+ layout of his output files (the files generated during tangling). Of
+ course, this is essential for languages that are sensitive to layout;
+ but it is also important in many practical situations, {\em e.g.,}
+ debugging.
+\item[Speed] Since nuweb doesn't do to much, the nuweb tool runs
+ quickly. I combine the functions of \verb|tangle| and \verb|weave| into
+ a single program that performs both functions at once.
+\item[Page numbers] Inspired by the example of noweb, nuweb refers to
+ all scraps by page number to simplify navigation. If there are
+ multiple scraps on a page (say page~17), they are distinguished by
+ lower-case letters ({\em e.g.,} 17a, 17b, and so forth).
+\item[Multiple file output] The programmer may specify more than one
+ output file in a single nuweb file. This is required when constructing
+ programs in a combination of languages (say, Fortran and C)\@. It's also
+ an advantage when constructing very large programs that would require
+ a lot of compile time.
+\end{description}
+This last point is very important. By allowing the creation of
+multiple output files, we avoid the need for monolithic programs.
+Thus we support the creation of very large programs by groups of
+people.
+
+A further reduction in compilation time is achieved by first
+writing each output file to a temporary location, then comparing the
+temporary file with the old version of the file. If there is no
+difference, the temporary file can be deleted. If the files differ,
+the old version is deleted and the temporary file renamed. This
+approach works well in combination with \verb|make| (or similar tools),
+since \verb|make| will avoid recompiling untouched output files.
+
+\subsection{Nuweb and HTML}
+
+In addition to producing {\LaTeX} source, nuweb can be used to
+generate HyperText Markup Language (HTML), the markup language used by
+the World Wide Web. HTML provides hypertext links. When a HTML
+document is viewed online, a user can navigate within the document by
+activating the links. The tools which generate HTML automatically
+produce hypertext links from a nuweb source.
+
+
+\section{Writing Nuweb}
+
+The bulk of a nuweb file will be ordinary \LaTeX\@. In fact, any
+{\LaTeX} file can serve as input to nuweb and will be simply copied
+through unchanged to the documentation file---unless a nuweb command
+is discovered. All nuweb commands begin with an ``at-sign''
+(\verb|@|). Therefore, a file without at-signs will be copied
+unchanged. Nuweb commands are used to specify {\em output files,}
+define {\em macros,} and delimit {\em scraps}. These are the basic
+features of interest to the nuweb tool---all else is simply text to be
+copied to the documentation file.
+
+\subsection{The Major Commands}
+
+Files and macros are defined with the following commands:
+\begin{description}
+\item[{\tt @o} {\em file-name flags scrap\/}] Output a file. The file name is
+ terminated by whitespace.
+\item[{\tt @d} {\em macro-name scrap\/}] Define a macro. The macro name
+ is terminated by a return or the beginning of a scrap.
+\end{description}
+A specific file may be specified several times, with each definition
+being written out, one after the other, in the order they appear.
+The definitions of macros may be similarly divided.
+
+\subsubsection{Scraps}
+
+Scraps have specific begin markers and end markers to allow precise
+control over the contents and layout. Note that any amount of
+whitespace (including carriage returns) may appear between a name and
+the beginning of a scrap.
+\begin{description}
+\item[\tt @\{{\em anything\/}@\}] where the scrap body includes every
+ character in {\em anything\/}---all the blanks, all the tabs, all the
+ carriage returns.
+\end{description}
+Inside a scrap, we may invoke a macro.
+\begin{description}
+\item[\tt @<{\em macro-name\/}@>] Causes the macro
+ {\em macro-name\/} to be expanded inline as the code is written out
+ to a file. It is an error to specify recursive macro invocations.
+\end{description}
+Note that macro names may be abbreviated, either during invocation or
+definition. For example, it would be very tedious to have to
+repeatedly type the macro name
+\begin{quote}
+\verb|@d Check for terminating at-sequence and return name if found|
+\end{quote}
+Therefore, we provide a mechanism (stolen from Knuth) of indicating
+abbreviated names.
+\begin{quote}
+\verb|@d Check for terminating...|
+\end{quote}
+Basically, the programmer need only type enough characters to uniquely
+identify the macro name, followed by three periods. An abbreviation
+may even occur before the full version; nuweb simply preserves the
+longest version of a macro name. Note also that blanks and tabs are
+insignificant in a macro name; any string of them are replaced by a
+single blank.
+
+When scraps are written to a program file or a documentation file, tabs are
+expanded into spaces by default. Currently, I assume tab stops are set
+every eight characters. Furthermore, when a macro is expanded in a scrap,
+the body of the macro is indented to match the indentation of the
+macro invocation. Therefore, care must be taken with languages
+({\em e.g.,} Fortran) that are sensitive to indentation.
+These default behaviors may be changed for each output file (see
+below).
+
+\subsubsection{Flags}
+
+When defining an output file, the programmer has the option of using
+flags to control output of a particular file. The flags are intended
+to make life a little easier for programmers using certain languages.
+They introduce little language dependences; however, they do so only
+for a particular file. Thus it is still easy to mix languages within a
+single document. There are three ``per-file'' flags:
+\begin{description}
+\item[\tt -d] Forces the creation of \verb|#line| directives in the
+ output file. These are useful with C (and sometimes C++ and Fortran) on
+ many Unix systems since they cause the compiler's error messages to
+ refer to the web file rather than the output file. Similarly, they
+ allow source debugging in terms of the web file.
+\item[\tt -i] Suppresses the indentation of macros. That is, when a
+ macro is expanded in a scrap, it will {\em not\/} be indented to
+ match the indentation of the macro invocation. This flag would seem
+ most useful for Fortran programmers.
+\item[\tt -t] Suppresses expansion of tabs in the output file. This
+ feature seems important when generating \verb|make| files.
+\end{description}
+
+
+\subsection{The Minor Commands}
+
+We have two very low-level utility commands that may appear anywhere
+in the web file.
+\begin{description}
+\item[\tt @@] Causes a single ``at sign'' to be copied into the output.
+\item[\tt @i {\em file-name\/}] Includes a file. Includes may be
+ nested, though there is currently a limit of 10~levels. The file name
+ should be complete (no extension will be appended) and should be
+ terminated by a carriage return.
+\end{description}
+Finally, there are three commands used to create indices to the macro
+names, file definitions, and user-specified identifiers.
+\begin{description}
+\item[\tt @f] Create an index of file names.
+\item[\tt @m] Create an index of macro name.
+\item[\tt @u] Create an index of user-specified identifiers.
+\end{description}
+I usually put these in their own section
+in the \LaTeX\ document; for example, see Chapter~\ref{indices}.
+
+Identifiers must be explicitly specified for inclusion in the
+\verb|@u| index. By convention, each identifier is marked at the
+point of its definition; all references to each identifier (inside
+scraps) will be discovered automatically. To ``mark'' an identifier
+for inclusion in the index, we must mention it at the end of a scrap.
+For example,
+\begin{quote}
+\begin{verbatim}
+@d a scrap @{
+Let's pretend we're declaring the variables FOO and BAR
+inside this scrap.
+@| FOO BAR @}
+\end{verbatim}
+\end{quote}
+I've used alphabetic identifiers in this example, but any string of
+characters (not including whitespace or \verb|@| characters) will do.
+Therefore, it's possible to add index entries for things like
+\verb|<<=| if desired. An identifier may be declared in more than one
+scrap.
+
+In the generated index, each identifier appears with a list of all the
+scraps using and defining it, where the defining scraps are
+distinguished by underlining. Note that the identifier doesn't
+actually have to appear in the defining scrap; it just has to be in
+the list of definitions at the end of a scrap.
+
+
+\section{Running Nuweb}
+
+Nuweb is invoked using the following command:
+\begin{quote}
+{\tt nuweb} {\em flags file-name}\ldots
+\end{quote}
+One or more files may be processed at a time. If a file name has no
+extension, \verb|.w| will be appended. {\LaTeX} suitable for
+translation into HTML by {\LaTeX}2HTML will be produced from
+files whose name ends with \verb|.hw|, otherwise, ordinary {\LaTeX} will be
+produced. While a file name may specify a file in another directory,
+the resulting documentation file will always be created in the current
+directory. For example,
+\begin{quote}
+{\tt nuweb /foo/bar/quux}
+\end{quote}
+will take as input the file \verb|/foo/bar/quux.w| and will create the
+file \verb|quux.tex| in the current directory.
+
+By default, nuweb performs both tangling and weaving at the same time.
+Normally, this is not a bottleneck in the compilation process;
+however, it's possible to achieve slightly faster throughput by
+avoiding one or another of the default functions using command-line
+flags. There are currently three possible flags:
+\begin{description}
+\item[\tt -t] Suppress generation of the documentation file.
+\item[\tt -o] Suppress generation of the output files.
+\item[\tt -c] Avoid testing output files for change before updating them.
+\end{description}
+Thus, the command
+\begin{quote}
+\verb|nuweb -to /foo/bar/quux|
+\end{quote}
+would simply scan the input and produce no output at all.
+
+There are two additional command-line flags:
+\begin{description}
+\item[\tt -v] For ``verbose,'' causes nuweb to write information about
+ its progress to \verb|stderr|.
+\item[\tt -n] Forces scraps to be numbered sequentially from~1
+ (instead of using page numbers). This form is perhaps more desirable
+ for small webs.
+\end{description}
+
+\section{Generating HTML}
+
+Nikos Drakos' {\LaTeX}2HTML Version 0.5.3~\cite{drakos:94} can be used
+to translate {\LaTeX} with embedded HTML scraps into HTML\@. Be sure
+to include the document-style option \verb|html| so that {\LaTeX} will
+understand the hypertext commands. When translating into HTML, do not
+allow a document to be split by specifying ``\verb|-split 0|''.
+You need not generate navigation links, so also specify
+``\verb|-no_navigation|''.
+
+While preparing a web, you may want to view the program's scraps without
+taking the time to run {\LaTeX}2HTML\@. Simply rename the generated
+{\LaTeX} source so that its file name ends with \verb|.html|, and view
+that file. The documentations section will be jumbled, but the
+scraps will be clear.
+
+\section{Restrictions}
+
+Because nuweb is intended to be a simple tool, I've established a few
+restrictions. Over time, some of these may be eliminated; others seem
+fundamental.
+\begin{itemize}
+\item The handling of errors is not completely ideal. In some cases, I
+ simply warn of a problem and continue; in other cases I halt
+ immediately. This behavior should be regularized.
+\item I warn about references to macros that haven't been defined, but
+ don't halt. This seems most convenient for development, but may change
+ in the future.
+\item File names and index entries should not contain any \verb|@|
+ signs.
+\item Macro names may be (almost) any well-formed \TeX\ string.
+ It makes sense to change fonts or use math mode; however, care should
+ be taken to ensure matching braces, brackets, and dollar signs.
+ When producing HTML, macros are displayed in a preformatted element
+ (PRE), so macros may contain one or more A, B, I, U, or P elements
+ or data characters.
+\item Anything is allowed in the body of a scrap; however, very
+ long scraps (horizontally or vertically) may not typeset well.
+\item Temporary files (created for comparison to the eventual
+ output files) are placed in the current directory. Since they may be
+ renamed to an output file name, all the output files should be on the
+ same file system as the current directory.
+\item Because page numbers cannot be determined until the document has
+ been typeset, we have to rerun nuweb after \LaTeX\ to obtain a clean
+ version of the document (very similar to the way we sometimes have
+ to rerun \LaTeX\ to obtain an up-to-date table of contents after
+ significant edits). Nuweb will warn (in most cases) when this needs
+ to be done; in the remaining cases, \LaTeX\ will warn that labels
+ may have changed.
+\end{itemize}
+Very long scraps may be allowed to break across a page if declared
+with \verb|@O| or \verb|@D| (instead of \verb|@o| and \verb|@d|).
+This doesn't work very well as a default, since far too many short
+scraps will be broken across pages; however, as a user-controlled
+option, it seems very useful. No distinction is made between the
+upper case and lower case forms of these commands when generating
+HTML\@.
+
+\section{Acknowledgements}
+
+Several people have contributed their times, ideas, and debugging
+skills. In particular, I'd like to acknowledge the contributions of
+Osman Buyukisik, Manuel Carriba, Adrian Clarke, Tim Harvey, Michael
+Lewis, Walter Ravenek, Rob Shillingsburg, Kayvan Sylvan, Dominique
+de~Waleffe, and Scott Warren. Of course, most of these people would
+never have heard or nuweb (or many other tools) without the efforts of
+George Greenwade.
+
+
+\ifshowcode
+\chapter{The Overall Structure}
+
+Processing a web requires three major steps:
+\begin{enumerate}
+\item Read the source, accumulating file names, macro names, scraps,
+and lists of cross-references.
+\item Reread the source, copying out to the documentation file, with
+protection and cross-reference information for all the scraps.
+\item Traverse the list of files names. For each file name:
+\begin{enumerate}
+\item Dump all the defining scraps into a temporary file.
+\item If the file already exists and is unchanged, delete the
+temporary file; otherwise, rename the temporary file.
+\end{enumerate}
+\end{enumerate}
+
+
+\section{Files}
+
+I have divided the program into several files for quicker
+recompilation during development.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap1}
+\verb@"global.h"@ {\footnotesize 7a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@@$\langle$Include files {\footnotesize 7b}$\rangle$\verb@@\\
+\mbox{}\verb@@$\langle$Type declarations {\footnotesize 8a, \ldots\ }$\rangle$\verb@@\\
+\mbox{}\verb@@$\langle$Global variable declarations {\footnotesize 10a, \ldots\ }$\rangle$\verb@@\\
+\mbox{}\verb@@$\langle$Function prototypes {\footnotesize 14a, \ldots\ }$\rangle$\verb@@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We'll need at least three of the standard system include files.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap2}
+$\langle$Include files {\footnotesize 7b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include <stdlib.h>@\\
+\mbox{}\verb@#include <stdio.h>@\\
+\mbox{}\verb@#include <string.h>@\\
+\mbox{}\verb@#include <ctype.h>@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+I also like to use \verb|TRUE| and \verb|FALSE| in my code.
+I'd use an \verb|enum| here, except that some systems seem to provide
+definitions of \verb|TRUE| and \verb|FALSE| be default. The following
+code seems to work on all the local systems.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap3}
+$\langle$Type declarations {\footnotesize 8a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#ifndef FALSE@\\
+\mbox{}\verb@#define FALSE 0@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@#ifndef TRUE@\\
+\mbox{}\verb@#define TRUE 1@\\
+\mbox{}\verb@#endif@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 8a, 52c, 53a.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{The Main Files}
+
+The code is divided into four main files (introduced here) and five
+support files (introduced in the next section).
+The file \verb|main.c| will contain the driver for the whole program
+(see Section~\ref{main-routine}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap4}
+\verb@"main.c"@ {\footnotesize 8b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8b, 9f.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The first pass over the source file is contained in \verb|pass1.c|.
+It handles collection of all the file names, macros names, and scraps
+(see Section~\ref{pass-one}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap5}
+\verb@"pass1.c"@ {\footnotesize 8c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8c, 14b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The \verb|.tex| file is created during a second pass over the source
+file. The file \verb|latex.c| contains the code controlling the
+construction of the \verb|.tex| file
+(see Section~\ref{latex-file}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap6}
+\verb@"latex.c"@ {\footnotesize 8d }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8d, 16d, 17a, 21b, 22a, 24b, 26b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The file \verb|html.c| contains the code controlling the
+construction of the \verb|.tex| file appropriate for use with {\LaTeX}2HTML
+(see Section~\ref{html-file}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap7}
+\verb@"html.c"@ {\footnotesize 8e }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The code controlling the creation of the output files is in \verb|output.c|
+(see Section~\ref{output-files}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap8}
+\verb@"output.c"@ {\footnotesize 8f }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8f, 37c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\subsection{Support Files}
+
+The support files contain a variety of support routines used to define
+and manipulate the major data abstractions.
+The file \verb|input.c| holds all the routines used for referring to
+source files (see Section~\ref{source-files}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap9}
+\verb@"input.c"@ {\footnotesize 9a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9a, 39d, 40ab, 42c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Creation and lookup of scraps is handled by routines in \verb|scraps.c|
+(see Section~\ref{scraps}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap10}
+\verb@"scraps.c"@ {\footnotesize 9b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The handling of file names and macro names is detailed in \verb|names.c|
+(see Section~\ref{names}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap11}
+\verb@"names.c"@ {\footnotesize 9c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Memory allocation and deallocation is handled by routines in \verb|arena.c|
+(see Section~\ref{memory-management}).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap12}
+\verb@"arena.c"@ {\footnotesize 9d }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9d, 70abc, 71c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Finally, for best portability, I seem to need a file containing
+(useless!) definitions of all the global variables.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap13}
+\verb@"global.c"@ {\footnotesize 9e }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#include "global.h"@\\
+\mbox{}\verb@@$\langle$Global variable definitions {\footnotesize 10b, \ldots\ }$\rangle$\verb@@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-2ex}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{The Main Routine} \label{main-routine}
+
+The main routine is quite simple in structure.
+It wades through the optional command-line arguments,
+then handles any files listed on the command line.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap14}
+\verb@"main.c"@ {\footnotesize 9f }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@int main(argc, argv)@\\
+\mbox{}\verb@ int argc;@\\
+\mbox{}\verb@ char **argv;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int arg = 1;@\\
+\mbox{}\verb@ @$\langle$Interpret command-line arguments {\footnotesize 10e, \ldots\ }$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Process the remaining arguments (file names) {\footnotesize 11c}$\rangle$\verb@@\\
+\mbox{}\verb@ exit(0);@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8b, 9f.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Command-Line Arguments}
+
+There are five possible command-line arguments:
+\begin{description}
+\item[\tt -t] Suppresses generation of the {\tt .tex} file.
+\item[\tt -o] Suppresses generation of the output files.
+\item[\tt -c] Forces output files to overwrite old files of the same
+ name without comparing for equality first.
+\item[\tt -v] The verbose flag. Forces output of progress reports.
+\item[\tt -n] Forces sequential numbering of scraps (instead of page
+ numbers).
+\end{description}
+
+\noindent
+Global flags are declared for each of the arguments.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap15}
+$\langle$Global variable declarations {\footnotesize 10a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern int tex_flag; /* if FALSE, don't emit the documentation file */@\\
+\mbox{}\verb@extern int html_flag; /* if TRUE, emit HTML instead of LaTeX scraps. */@\\
+\mbox{}\verb@extern int output_flag; /* if FALSE, don't emit the output files */@\\
+\mbox{}\verb@extern int compare_flag; /* if FALSE, overwrite without comparison */@\\
+\mbox{}\verb@extern int verbose_flag; /* if TRUE, write progress information */@\\
+\mbox{}\verb@extern int number_flag; /* if TRUE, use a sequential numbering scheme */@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10ac, 39b, 44d, 53b.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The flags are all initialized for correct default behavior.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap16}
+$\langle$Global variable definitions {\footnotesize 10b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@int tex_flag = TRUE;@\\
+\mbox{}\verb@int html_flag = FALSE;@\\
+\mbox{}\verb@int output_flag = TRUE;@\\
+\mbox{}\verb@int compare_flag = TRUE;@\\
+\mbox{}\verb@int verbose_flag = FALSE;@\\
+\mbox{}\verb@int number_flag = FALSE;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10bd, 39c, 45a, 53c.
+\item Macro referenced in scrap 9e.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We save the invocation name of the command in a global variable
+\verb|command_name| for use in error messages.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap17}
+$\langle$Global variable declarations {\footnotesize 10c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern char *command_name;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10ac, 39b, 44d, 53b.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap18}
+$\langle$Global variable definitions {\footnotesize 10d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@char *command_name = NULL;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10bd, 39c, 45a, 53c.
+\item Macro referenced in scrap 9e.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The invocation name is conventionally passed in \verb|argv[0]|.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap19}
+$\langle$Interpret command-line arguments {\footnotesize 10e}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@command_name = argv[0];@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10e, 11a.
+\item Macro referenced in scrap 9f.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We need to examine the remaining entries in \verb|argv|, looking for
+command-line arguments.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap20}
+$\langle$Interpret command-line arguments {\footnotesize 11a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@while (arg < argc) {@\\
+\mbox{}\verb@ char *s = argv[arg];@\\
+\mbox{}\verb@ if (*s++ == '-') {@\\
+\mbox{}\verb@ @$\langle$Interpret the argument string \verb|s| {\footnotesize 11b}$\rangle$\verb@@\\
+\mbox{}\verb@ arg++;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else break;@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10e, 11a.
+\item Macro referenced in scrap 9f.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Several flags can be stacked behind a single minus sign; therefore,
+we've got to loop through the string, handling them all.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap21}
+$\langle$Interpret the argument string \verb|s| {\footnotesize 11b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char c = *s++;@\\
+\mbox{}\verb@ while (c) {@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case 'c': compare_flag = FALSE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'n': number_flag = TRUE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'o': output_flag = FALSE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 't': tex_flag = FALSE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'v': verbose_flag = TRUE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: fprintf(stderr, "%s: unexpected argument ignored. ",@\\
+\mbox{}\verb@ command_name);@\\
+\mbox{}\verb@ fprintf(stderr, "Usage is: %s [-cnotv] file...\n",@\\
+\mbox{}\verb@ command_name);@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = *s++;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 11a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{File Names}
+
+We expect at least one file name. While a missing file name might be
+ignored without causing any problems, we take the opportunity to report
+the usage convention.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap22}
+$\langle$Process the remaining arguments (file names) {\footnotesize 11c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (arg >= argc) {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: expected a file name. ", command_name);@\\
+\mbox{}\verb@ fprintf(stderr, "Usage is: %s [-cnotv] file-name...\n", command_name);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ do {@\\
+\mbox{}\verb@ @$\langle$Handle the file name in \verb|argv[arg]| {\footnotesize 12a}$\rangle$\verb@@\\
+\mbox{}\verb@ arg++;@\\
+\mbox{}\verb@ } while (arg < argc);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 9f.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+The code to handle a particular file name is rather more tedious than
+the actual processing of the file. A file name may be an arbitrarily
+complicated path name, with an optional extension. If no extension is
+present, we add \verb|.w| as a default. The extended path name will be
+kept in a local variable \verb|source_name|. The resulting documentation
+file will be written in the current directory; its name will be kept
+in the variable \verb|tex_name|.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap23}
+$\langle$Handle the file name in \verb|argv[arg]| {\footnotesize 12a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char source_name[100];@\\
+\mbox{}\verb@ char tex_name[100];@\\
+\mbox{}\verb@ char aux_name[100];@\\
+\mbox{}\verb@ @$\langle$Build \verb|source_name| and \verb|tex_name| {\footnotesize 12b}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Process a file {\footnotesize 13}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 11c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+I bump the pointer \verb|p| through all the characters in \verb|argv[arg]|,
+copying all the characters into \verb|source_name| (via the pointer
+\verb|q|).
+
+At each slash, I update \verb|trim| to point just past the
+slash in \verb|source_name|. The effect is that \verb|trim| will point
+at the file name without any leading directory specifications.
+
+The pointer \verb|dot| is made to point at the file name extension, if
+present. If there is no extension, we add \verb|.w| to the source name.
+In any case, we create the \verb|tex_name| from \verb|trim|, taking
+care to get the correct extension. The \verb|html_flag| is set in
+this scrap.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap24}
+$\langle$Build \verb|source_name| and \verb|tex_name| {\footnotesize 12b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char *p = argv[arg];@\\
+\mbox{}\verb@ char *q = source_name;@\\
+\mbox{}\verb@ char *trim = q;@\\
+\mbox{}\verb@ char *dot = NULL;@\\
+\mbox{}\verb@ char c = *p++;@\\
+\mbox{}\verb@ while (c) {@\\
+\mbox{}\verb@ *q++ = c;@\\
+\mbox{}\verb@ if (c == '/') {@\\
+\mbox{}\verb@ trim = q;@\\
+\mbox{}\verb@ dot = NULL;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else if (c == '.')@\\
+\mbox{}\verb@ dot = q - 1;@\\
+\mbox{}\verb@ c = *p++;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ *q = '\0';@\\
+\mbox{}\verb@ if (dot) {@\\
+\mbox{}\verb@ *dot = '\0'; /* produce HTML when the file extension is ".hw" */@\\
+\mbox{}\verb@ html_flag = dot[1] == 'h' && dot[2] == 'w' && dot[3] == '\0';@\\
+\mbox{}\verb@ sprintf(tex_name, "%s.tex", trim);@\\
+\mbox{}\verb@ sprintf(aux_name, "%s.aux", trim);@\\
+\mbox{}\verb@ *dot = '.';@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ sprintf(tex_name, "%s.tex", trim);@\\
+\mbox{}\verb@ sprintf(aux_name, "%s.aux", trim);@\\
+\mbox{}\verb@ *q++ = '.';@\\
+\mbox{}\verb@ *q++ = 'w';@\\
+\mbox{}\verb@ *q = '\0';@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 12a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Now that we're finally ready to process a file, it's not really too
+complex. We bundle most of the work into four routines \verb|pass1|
+(see Section~\ref{pass-one}), \verb|write_tex| (see
+Section~\ref{latex-file}), \verb|write_html| (see
+Section~\ref{html-file}), and \verb|write_files| (see
+Section~\ref{output-files}). After we're finished with a
+particular file, we must remember to release its storage (see
+Section~\ref{memory-management}). The sequential numbering of scraps
+is forced when generating HTML.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap25}
+$\langle$Process a file {\footnotesize 13}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ pass1(source_name);@\\
+\mbox{}\verb@ if (tex_flag) {@\\
+\mbox{}\verb@ if (html_flag) {@\\
+\mbox{}\verb@ int saved_number_flag = number_flag; @\\
+\mbox{}\verb@ number_flag = TRUE;@\\
+\mbox{}\verb@ collect_numbers(aux_name);@\\
+\mbox{}\verb@ write_html(source_name, tex_name);@\\
+\mbox{}\verb@ number_flag = saved_number_flag;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ collect_numbers(aux_name);@\\
+\mbox{}\verb@ write_tex(source_name, tex_name);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ if (output_flag)@\\
+\mbox{}\verb@ write_files(file_names);@\\
+\mbox{}\verb@ arena_free();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 12a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\section{Pass One} \label{pass-one}
+
+During the first pass, we scan the file, recording the definitions of
+each macro and file and accumulating all the scraps.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap26}
+$\langle$Function prototypes {\footnotesize 14a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void pass1();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The routine \verb|pass1| takes a single argument, the name of the
+source file. It opens the file, then initializes the scrap structures
+(see Section~\ref{scraps}) and the roots of the file-name tree, the
+macro-name tree, and the tree of user-specified index entries (see
+Section~\ref{names}). After completing all the
+necessary preparation, we make a pass over the file, filling in all
+our data structures. Next, we seach all the scraps for references to
+the user-specified index entries. Finally, we must reverse all the
+cross-reference lists accumulated while scanning the scraps.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap27}
+\verb@"pass1.c"@ {\footnotesize 14b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void pass1(file_name)@\\
+\mbox{}\verb@ char *file_name;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (verbose_flag)@\\
+\mbox{}\verb@ fprintf(stderr, "reading %s\n", file_name);@\\
+\mbox{}\verb@ source_open(file_name);@\\
+\mbox{}\verb@ init_scraps();@\\
+\mbox{}\verb@ macro_names = NULL;@\\
+\mbox{}\verb@ file_names = NULL;@\\
+\mbox{}\verb@ user_names = NULL;@\\
+\mbox{}\verb@ @$\langle$Scan the source file, looking for at-sequences {\footnotesize 14c}$\rangle$\verb@@\\
+\mbox{}\verb@ if (tex_flag)@\\
+\mbox{}\verb@ search();@\\
+\mbox{}\verb@ @$\langle$Reverse cross-reference lists {\footnotesize 16b}$\rangle$\verb@@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8c, 14b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The only thing we look for in the first pass are the command
+sequences. All ordinary text is skipped entirely.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap28}
+$\langle$Scan the source file, looking for at-sequences {\footnotesize 14c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ while (c != EOF) {@\\
+\mbox{}\verb@ if (c == '@{\tt @}\verb@')@\\
+\mbox{}\verb@ @$\langle$Scan at-sequence {\footnotesize 15a}$\rangle$\verb@@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 14b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Only four of the at-sequences are interesting during the first pass.
+We skip past others immediately; warning if unexpected sequences are
+discovered.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap29}
+$\langle$Scan at-sequence {\footnotesize 15a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case 'O':@\\
+\mbox{}\verb@ case 'o': @$\langle$Build output file definition {\footnotesize 15b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'D':@\\
+\mbox{}\verb@ case 'd': @$\langle$Build macro definition {\footnotesize 15c}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '@{\tt @}\verb@':@\\
+\mbox{}\verb@ case 'u':@\\
+\mbox{}\verb@ case 'm':@\\
+\mbox{}\verb@ case 'f': /* ignore during this pass */@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: fprintf(stderr,@\\
+\mbox{}\verb@ "%s: unexpected @{\tt @}\verb@ sequence ignored (%s, line %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, source_line);@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 14c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Accumulating Definitions}
+
+There are three steps required to handle a definition:
+\begin{enumerate}
+\item Build an entry for the name so we can look it up later.
+\item Collect the scrap and save it in the table of scraps.
+\item Attach the scrap to the name.
+\end{enumerate}
+We go through the same steps for both file names and macro names.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap30}
+$\langle$Build output file definition {\footnotesize 15b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_file_name(); /* returns a pointer to the name entry */@\\
+\mbox{}\verb@ int scrap = collect_scrap(); /* returns an index to the scrap */@\\
+\mbox{}\verb@ @$\langle$Add \verb|scrap| to \verb|name|'s definition list {\footnotesize 16a}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 15a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap31}
+$\langle$Build macro definition {\footnotesize 15c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_macro_name();@\\
+\mbox{}\verb@ int scrap = collect_scrap();@\\
+\mbox{}\verb@ @$\langle$Add \verb|scrap| to \verb|name|'s definition list {\footnotesize 16a}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 15a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Since a file or macro may be defined by many scraps, we maintain them
+in a simple linked list. The list is actually built in reverse order,
+with each new definition being added to the head of the list.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap32}
+$\langle$Add \verb|scrap| to \verb|name|'s definition list {\footnotesize 16a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));@\\
+\mbox{}\verb@ def->scrap = scrap;@\\
+\mbox{}\verb@ def->next = name->defs;@\\
+\mbox{}\verb@ name->defs = def;@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 15bc.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Fixing the Cross References}
+
+Since the definition and reference lists for each name are accumulated
+in reverse order, we take the time at the end of \verb|pass1| to
+reverse them all so they'll be simpler to print out prettily.
+The code for \verb|reverse_lists| appears in Section~\ref{names}.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap33}
+$\langle$Reverse cross-reference lists {\footnotesize 16b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ reverse_lists(file_names);@\\
+\mbox{}\verb@ reverse_lists(macro_names);@\\
+\mbox{}\verb@ reverse_lists(user_names);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 14b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Writing the Latex File} \label{latex-file}
+
+The second pass (invoked via a call to \verb|write_tex|) copies most of
+the text from the source file straight into a \verb|.tex| file.
+Definitions are formatted slightly and cross-reference information is
+printed out.
+
+Note that all the formatting is handled in this section.
+If you don't like the format of definitions or indices or whatever,
+it'll be in this section somewhere. Similarly, if someone wanted to
+modify nuweb to work with a different typesetting system, this would
+be the place to look.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap34}
+$\langle$Function prototypes {\footnotesize 16c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void write_tex();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We need a few local function declarations before we get into the body
+of \verb|write_tex|.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap35}
+\verb@"latex.c"@ {\footnotesize 16d }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void copy_scrap(); /* formats the body of a scrap */@\\
+\mbox{}\verb@static void print_scrap_numbers(); /* formats a list of scrap numbers */@\\
+\mbox{}\verb@static void format_entry(); /* formats an index entry */@\\
+\mbox{}\verb@static void format_user_entry();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8d, 16d, 17a, 21b, 22a, 24b, 26b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The routine \verb|write_tex| takes two file names as parameters: the
+name of the web source file and the name of the \verb|.tex| output file.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap36}
+\verb@"latex.c"@ {\footnotesize 17a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void write_tex(file_name, tex_name)@\\
+\mbox{}\verb@ char *file_name;@\\
+\mbox{}\verb@ char *tex_name;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ FILE *tex_file = fopen(tex_name, "w");@\\
+\mbox{}\verb@ if (tex_file) {@\\
+\mbox{}\verb@ if (verbose_flag)@\\
+\mbox{}\verb@ fprintf(stderr, "writing %s\n", tex_name);@\\
+\mbox{}\verb@ source_open(file_name);@\\
+\mbox{}\verb@ @$\langle$Copy \verb|source_file| into \verb|tex_file| {\footnotesize 17b}$\rangle$\verb@@\\
+\mbox{}\verb@ fclose(tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ fprintf(stderr, "%s: can't open %s\n", command_name, tex_name);@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8d, 16d, 17a, 21b, 22a, 24b, 26b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We make our second (and final) pass through the source web, this time
+copying characters straight into the \verb|.tex| file. However, we keep
+an eye peeled for \verb|@|~characters, which signal a command sequence.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap37}
+$\langle$Copy \verb|source_file| into \verb|tex_file| {\footnotesize 17b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int scraps = 1;@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ while (c != EOF) {@\\
+\mbox{}\verb@ if (c == '@{\tt @}\verb@')@\\
+\mbox{}\verb@ @$\langle$Interpret at-sequence {\footnotesize 18}$\rangle$\verb@@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ putc(c, tex_file);@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 17a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap38}
+$\langle$Interpret at-sequence {\footnotesize 18}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int big_definition = FALSE;@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case 'O': big_definition = TRUE;@\\
+\mbox{}\verb@ case 'o': @$\langle$Write output file definition {\footnotesize 19a}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'D': big_definition = TRUE;@\\
+\mbox{}\verb@ case 'd': @$\langle$Write macro definition {\footnotesize 19b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'f': @$\langle$Write index of file names {\footnotesize 23d}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'm': @$\langle$Write index of macro names {\footnotesize 24a}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'u': @$\langle$Write index of user-specified names {\footnotesize 26a}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': putc(c, tex_file);@\\
+\mbox{}\verb@ default: c = source_get();@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 17b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Formatting Definitions}
+
+We go through a fair amount of effort to format a file definition.
+I've derived most of the \LaTeX\ commands experimentally; it's quite
+likely that an expert could do a better job. The \LaTeX\ for
+the previous macro definition should look like this (perhaps modulo
+the scrap references):
+{\small
+\begin{verbatim}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap37}
+$\langle$Interpret at-sequence {\footnotesize 18}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int big_definition = FALSE;@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case 'O': big_definition = TRUE;@\\
+\mbox{}\verb@ case 'o': @$\langle$Write output file definition {\footnotesize 19a}$\rangle$\verb@@\\
+\end{verbatim}
+\vdots
+\begin{verbatim}
+\mbox{}\verb@ case '@{\tt @}\verb@': putc(c, tex_file);@\\
+\mbox{}\verb@ default: c = source_get();@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 17b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\end{verbatim}}
+
+\noindent
+The {\em flushleft\/} environment is used to avoid \LaTeX\ warnings
+about underful lines. The {\em minipage\/} environment is used to
+avoid page breaks in the middle of scraps. The {\em verb\/} command
+allows arbitrary characters to be printed (however, note the special
+handling of the \verb|@| case in the switch statement).
+
+Macro and file definitions are formatted nearly identically.
+I've factored the common parts out into separate scraps.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap39}
+$\langle$Write output file definition {\footnotesize 19a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_file_name();@\\
+\mbox{}\verb@ @$\langle$Begin the scrap environment {\footnotesize 19c}$\rangle$\verb@@\\
+\mbox{}\verb@ fprintf(tex_file, "\\verb@{\tt @}\verb@\"%s\"@{\tt @}\verb@ {\\footnotesize ", name->spelling);@\\
+\mbox{}\verb@ write_single_scrap_ref(tex_file, scraps++);@\\
+\mbox{}\verb@ fputs(" }$\\equiv$\n", tex_file);@\\
+\mbox{}\verb@ @$\langle$Fill in the middle of the scrap environment {\footnotesize 19d}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Write file defs {\footnotesize 20b}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Finish the scrap environment {\footnotesize 20a}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 18.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+I don't format a macro name at all specially, figuring the programmer
+might want to use italics or bold face in the midst of the name.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap40}
+$\langle$Write macro definition {\footnotesize 19b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_macro_name();@\\
+\mbox{}\verb@ @$\langle$Begin the scrap environment {\footnotesize 19c}$\rangle$\verb@@\\
+\mbox{}\verb@ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);@\\
+\mbox{}\verb@ write_single_scrap_ref(tex_file, scraps++);@\\
+\mbox{}\verb@ fputs("}$\\rangle\\equiv$\n", tex_file);@\\
+\mbox{}\verb@ @$\langle$Fill in the middle of the scrap environment {\footnotesize 19d}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Write macro defs {\footnotesize 20c}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Write macro refs {\footnotesize 21a}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Finish the scrap environment {\footnotesize 20a}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 18.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap41}
+$\langle$Begin the scrap environment {\footnotesize 19c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("\\begin{flushleft} \\small", tex_file);@\\
+\mbox{}\verb@ if (!big_definition)@\\
+\mbox{}\verb@ fputs("\n\\begin{minipage}{\\linewidth}", tex_file);@\\
+\mbox{}\verb@ fprintf(tex_file, " \\label{scrap%d}\n", scraps);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 19ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The interesting things here are the $\Diamond$ inserted at the end of
+each scrap and the various spacing commands. The diamond helps to
+clearly indicate the end of a scrap. The spacing commands were derived
+empirically; they may be adjusted to taste.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap42}
+$\langle$Fill in the middle of the scrap environment {\footnotesize 19d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("\\vspace{-1ex}\n\\begin{list}{}{} \\item\n", tex_file);@\\
+\mbox{}\verb@ copy_scrap(tex_file);@\\
+\mbox{}\verb@ fputs("$\\Diamond$\n\\end{list}\n", tex_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 19ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\newpage
+\noindent
+We've got one last spacing command, controlling the amount of white
+space after a scrap.
+
+Note also the whitespace eater. I use it to remove any blank lines
+that appear after a scrap in the source file. This way, text following
+a scrap will not be indented. Again, this is a matter of personal taste.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap43}
+$\langle$Finish the scrap environment {\footnotesize 20a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (!big_definition)@\\
+\mbox{}\verb@ fputs("\\end{minipage}\\\\[4ex]\n", tex_file);@\\
+\mbox{}\verb@ fputs("\\end{flushleft}\n", tex_file);@\\
+\mbox{}\verb@ do@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (isspace(c));@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 19ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Formatting Cross References}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap44}
+$\langle$Write file defs {\footnotesize 20b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (name->defs->next) {@\\
+\mbox{}\verb@ fputs("\\vspace{-1ex}\n", tex_file);@\\
+\mbox{}\verb@ fputs("\\footnotesize\\addtolength{\\baselineskip}{-1ex}\n", tex_file);@\\
+\mbox{}\verb@ fputs("\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}", tex_file);@\\
+\mbox{}\verb@ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);@\\
+\mbox{}\verb@ fputs("\\item File defined by scraps ", tex_file);@\\
+\mbox{}\verb@ print_scrap_numbers(tex_file, name->defs);@\\
+\mbox{}\verb@ fputs("\\end{list}\n", tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ fputs("\\vspace{-2ex}\n", tex_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 19a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap45}
+$\langle$Write macro defs {\footnotesize 20c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("\\vspace{-1ex}\n", tex_file);@\\
+\mbox{}\verb@ fputs("\\footnotesize\\addtolength{\\baselineskip}{-1ex}\n", tex_file);@\\
+\mbox{}\verb@ fputs("\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}", tex_file);@\\
+\mbox{}\verb@ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);@\\
+\mbox{}\verb@ if (name->defs->next) {@\\
+\mbox{}\verb@ fputs("\\item Macro defined by scraps ", tex_file);@\\
+\mbox{}\verb@ print_scrap_numbers(tex_file, name->defs);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 19b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap46}
+$\langle$Write macro refs {\footnotesize 21a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (name->uses) {@\\
+\mbox{}\verb@ if (name->uses->next) {@\\
+\mbox{}\verb@ fputs("\\item Macro referenced in scraps ", tex_file);@\\
+\mbox{}\verb@ print_scrap_numbers(tex_file, name->uses);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ fputs("\\item Macro referenced in scrap ", tex_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(tex_file, name->uses->scrap);@\\
+\mbox{}\verb@ fputs(".\n", tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ fputs("\\item Macro never referenced.\n", tex_file);@\\
+\mbox{}\verb@ fprintf(stderr, "%s: <%s> never referenced.\n",@\\
+\mbox{}\verb@ command_name, name->spelling);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fputs("\\end{list}\n", tex_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 19b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap47}
+\verb@"latex.c"@ {\footnotesize 21b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void print_scrap_numbers(tex_file, scraps)@\\
+\mbox{}\verb@ FILE *tex_file;@\\
+\mbox{}\verb@ Scrap_Node *scraps;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int page;@\\
+\mbox{}\verb@ write_scrap_ref(tex_file, scraps->scrap, TRUE, &page);@\\
+\mbox{}\verb@ scraps = scraps->next;@\\
+\mbox{}\verb@ while (scraps) {@\\
+\mbox{}\verb@ write_scrap_ref(tex_file, scraps->scrap, FALSE, &page);@\\
+\mbox{}\verb@ scraps = scraps->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fputs(".\n", tex_file);@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8d, 16d, 17a, 21b, 22a, 24b, 26b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Formatting a Scrap}
+
+We add a \verb|\mbox{}| at the beginning of each line to avoid
+problems with older versions of \TeX.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap48}
+\verb@"latex.c"@ {\footnotesize 22a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void copy_scrap(file)@\\
+\mbox{}\verb@ FILE *file;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int indent = 0;@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ fputs("\\mbox{}\\verb@{\tt @}\verb@", file);@\\
+\mbox{}\verb@ while (1) {@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': @$\langle$Check at-sequence for end-of-scrap {\footnotesize 22c}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\n': fputs("@{\tt @}\verb@\\\\\n\\mbox{}\\verb@{\tt @}\verb@", file);@\\
+\mbox{}\verb@ indent = 0;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\t': @$\langle$Expand tab into spaces {\footnotesize 22b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: putc(c, file);@\\
+\mbox{}\verb@ indent++;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8d, 16d, 17a, 21b, 22a, 24b, 26b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap49}
+$\langle$Expand tab into spaces {\footnotesize 22b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int delta = 8 - (indent % 8);@\\
+\mbox{}\verb@ indent += delta;@\\
+\mbox{}\verb@ while (delta > 0) {@\\
+\mbox{}\verb@ putc(' ', file);@\\
+\mbox{}\verb@ delta--;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 22a, 33a, 51a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap50}
+$\langle$Check at-sequence for end-of-scrap {\footnotesize 22c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': fputs("@{\tt @}\verb@{\\tt @{\tt @}\verb@}\\verb@{\tt @}\verb@", file);@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '|': @$\langle$Skip over index entries {\footnotesize 23a}$\rangle$\verb@@\\
+\mbox{}\verb@ case '}': putc('@{\tt @}\verb@', file);@\\
+\mbox{}\verb@ return;@\\
+\mbox{}\verb@ case '<': @$\langle$Format macro name {\footnotesize 23b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: /* ignore these since pass1 will have warned about them */@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 22a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+There's no need to check for errors here, since we will have already
+pointed out any during the first pass.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap51}
+$\langle$Skip over index entries {\footnotesize 23a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ do {@\\
+\mbox{}\verb@ do@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (c != '@{\tt @}\verb@');@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ } while (c != '}');@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 22c, 33b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap52}
+$\langle$Format macro name {\footnotesize 23b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_scrap_name();@\\
+\mbox{}\verb@ fprintf(file, "@{\tt @}\verb@$\\langle$%s {\\footnotesize ", name->spelling);@\\
+\mbox{}\verb@ if (name->defs)@\\
+\mbox{}\verb@ @$\langle$Write abbreviated definition list {\footnotesize 23c}$\rangle$\verb@@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ putc('?', file);@\\
+\mbox{}\verb@ fprintf(stderr, "%s: scrap never defined <%s>\n",@\\
+\mbox{}\verb@ command_name, name->spelling);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fputs("}$\\rangle$\\verb@{\tt @}\verb@", file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 22c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap53}
+$\langle$Write abbreviated definition list {\footnotesize 23c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *p = name->defs;@\\
+\mbox{}\verb@ write_single_scrap_ref(file, p->scrap);@\\
+\mbox{}\verb@ p = p->next;@\\
+\mbox{}\verb@ if (p)@\\
+\mbox{}\verb@ fputs(", \\ldots\\ ", file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 23b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Generating the Indices}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap54}
+$\langle$Write index of file names {\footnotesize 23d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (file_names) {@\\
+\mbox{}\verb@ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",@\\
+\mbox{}\verb@ tex_file);@\\
+\mbox{}\verb@ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);@\\
+\mbox{}\verb@ format_entry(file_names, tex_file, TRUE);@\\
+\mbox{}\verb@ fputs("\\end{list}}", tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 18.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap55}
+$\langle$Write index of macro names {\footnotesize 24a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (macro_names) {@\\
+\mbox{}\verb@ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",@\\
+\mbox{}\verb@ tex_file);@\\
+\mbox{}\verb@ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);@\\
+\mbox{}\verb@ format_entry(macro_names, tex_file, FALSE);@\\
+\mbox{}\verb@ fputs("\\end{list}}", tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 18.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap56}
+\verb@"latex.c"@ {\footnotesize 24b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void format_entry(name, tex_file, file_flag)@\\
+\mbox{}\verb@ Name *name;@\\
+\mbox{}\verb@ FILE *tex_file;@\\
+\mbox{}\verb@ int file_flag;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (name) {@\\
+\mbox{}\verb@ format_entry(name->llink, tex_file, file_flag);@\\
+\mbox{}\verb@ @$\langle$Format an index entry {\footnotesize 24c}$\rangle$\verb@@\\
+\mbox{}\verb@ name = name->rlink;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8d, 16d, 17a, 21b, 22a, 24b, 26b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap57}
+$\langle$Format an index entry {\footnotesize 24c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("\\item ", tex_file);@\\
+\mbox{}\verb@ if (file_flag) {@\\
+\mbox{}\verb@ fprintf(tex_file, "\\verb@{\tt @}\verb@\"%s\"@{\tt @}\verb@ ", name->spelling);@\\
+\mbox{}\verb@ @$\langle$Write file's defining scrap numbers {\footnotesize 25a}$\rangle$\verb@@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling);@\\
+\mbox{}\verb@ @$\langle$Write defining scrap numbers {\footnotesize 25b}$\rangle$\verb@@\\
+\mbox{}\verb@ fputs("}$\\rangle$ ", tex_file);@\\
+\mbox{}\verb@ @$\langle$Write referencing scrap numbers {\footnotesize 25c}$\rangle$\verb@@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ putc('\n', tex_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 24b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap58}
+$\langle$Write file's defining scrap numbers {\footnotesize 25a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *p = name->defs;@\\
+\mbox{}\verb@ fputs("{\\footnotesize Defined by scrap", tex_file);@\\
+\mbox{}\verb@ if (p->next) {@\\
+\mbox{}\verb@ fputs("s ", tex_file);@\\
+\mbox{}\verb@ print_scrap_numbers(tex_file, p);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ putc(' ', tex_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(tex_file, p->scrap);@\\
+\mbox{}\verb@ putc('.', tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ putc('}', tex_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 24c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap59}
+$\langle$Write defining scrap numbers {\footnotesize 25b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *p = name->defs;@\\
+\mbox{}\verb@ if (p) {@\\
+\mbox{}\verb@ int page;@\\
+\mbox{}\verb@ write_scrap_ref(tex_file, p->scrap, TRUE, &page);@\\
+\mbox{}\verb@ p = p->next;@\\
+\mbox{}\verb@ while (p) {@\\
+\mbox{}\verb@ write_scrap_ref(tex_file, p->scrap, FALSE, &page);@\\
+\mbox{}\verb@ p = p->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ putc('?', tex_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 24c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap60}
+$\langle$Write referencing scrap numbers {\footnotesize 25c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *p = name->uses;@\\
+\mbox{}\verb@ fputs("{\\footnotesize ", tex_file);@\\
+\mbox{}\verb@ if (p) {@\\
+\mbox{}\verb@ fputs("Referenced in scrap", tex_file);@\\
+\mbox{}\verb@ if (p->next) {@\\
+\mbox{}\verb@ fputs("s ", tex_file);@\\
+\mbox{}\verb@ print_scrap_numbers(tex_file, p);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ putc(' ', tex_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(tex_file, p->scrap);@\\
+\mbox{}\verb@ putc('.', tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ fputs("Not referenced.", tex_file);@\\
+\mbox{}\verb@ putc('}', tex_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 24c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap61}
+$\langle$Write index of user-specified names {\footnotesize 26a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (user_names) {@\\
+\mbox{}\verb@ fputs("\n{\\small\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}",@\\
+\mbox{}\verb@ tex_file);@\\
+\mbox{}\verb@ fputs("\\setlength{\\itemindent}{-\\leftmargin}}\n", tex_file);@\\
+\mbox{}\verb@ format_user_entry(user_names, tex_file);@\\
+\mbox{}\verb@ fputs("\\end{list}}", tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 18.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap62}
+\verb@"latex.c"@ {\footnotesize 26b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void format_user_entry(name, tex_file)@\\
+\mbox{}\verb@ Name *name;@\\
+\mbox{}\verb@ FILE *tex_file;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (name) {@\\
+\mbox{}\verb@ format_user_entry(name->llink, tex_file);@\\
+\mbox{}\verb@ @$\langle$Format a user index entry {\footnotesize 27a}$\rangle$\verb@@\\
+\mbox{}\verb@ name = name->rlink;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8d, 16d, 17a, 21b, 22a, 24b, 26b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap63}
+$\langle$Format a user index entry {\footnotesize 27a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *uses = name->uses;@\\
+\mbox{}\verb@ if (uses) {@\\
+\mbox{}\verb@ int page;@\\
+\mbox{}\verb@ Scrap_Node *defs = name->defs;@\\
+\mbox{}\verb@ fprintf(tex_file, "\\item \\verb@{\tt @}\verb@%s@{\tt @}\verb@: ", name->spelling);@\\
+\mbox{}\verb@ if (uses->scrap < defs->scrap) {@\\
+\mbox{}\verb@ write_scrap_ref(tex_file, uses->scrap, TRUE, &page);@\\
+\mbox{}\verb@ uses = uses->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ if (defs->scrap == uses->scrap)@\\
+\mbox{}\verb@ uses = uses->next;@\\
+\mbox{}\verb@ fputs("\\underline{", tex_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(tex_file, defs->scrap);@\\
+\mbox{}\verb@ putc('}', tex_file);@\\
+\mbox{}\verb@ page = -2;@\\
+\mbox{}\verb@ defs = defs->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ while (uses || defs) {@\\
+\mbox{}\verb@ if (uses && (!defs || uses->scrap < defs->scrap)) {@\\
+\mbox{}\verb@ write_scrap_ref(tex_file, uses->scrap, FALSE, &page);@\\
+\mbox{}\verb@ uses = uses->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ if (uses && defs->scrap == uses->scrap)@\\
+\mbox{}\verb@ uses = uses->next;@\\
+\mbox{}\verb@ fputs(", \\underline{", tex_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(tex_file, defs->scrap);@\\
+\mbox{}\verb@ putc('}', tex_file);@\\
+\mbox{}\verb@ page = -2;@\\
+\mbox{}\verb@ defs = defs->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fputs(".\n", tex_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 26b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Writing the LaTeX File with HTML Scraps} \label{html-file}
+
+The HTML generated is patterned closely upon the {\LaTeX} generated in
+the previous section.\footnote{\relax While writing this section, I
+tried to follow Preston's style as displayed in
+Section~\ref{latex-file}---J. D. R.} When a file name ends in
+\verb|.hw|, the second pass (invoked via a call to \verb|write_html|)
+copies most of the text from the source file straight into a
+\verb|.tex| file. Definitions are formatted slightly and
+cross-reference information is printed out.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap64}
+$\langle$Function prototypes {\footnotesize 27b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void write_html();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We need a few local function declarations before we get into the body
+of \verb|write_html|.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap65}
+\verb@"html.c"@ {\footnotesize 28a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void copy_scrap(); /* formats the body of a scrap */@\\
+\mbox{}\verb@static void display_scrap_ref(); /* formats a scrap reference */@\\
+\mbox{}\verb@static void display_scrap_numbers(); /* formats a list of scrap numbers */@\\
+\mbox{}\verb@static void print_scrap_numbers(); /* pluralizes scrap formats list */@\\
+\mbox{}\verb@static void format_entry(); /* formats an index entry */@\\
+\mbox{}\verb@static void format_user_entry();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The routine \verb|write_html| takes two file names as parameters: the
+name of the web source file and the name of the \verb|.tex| output file.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap66}
+\verb@"html.c"@ {\footnotesize 28b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void write_html(file_name, html_name)@\\
+\mbox{}\verb@ char *file_name;@\\
+\mbox{}\verb@ char *html_name;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ FILE *html_file = fopen(html_name, "w");@\\
+\mbox{}\verb@ if (html_file) {@\\
+\mbox{}\verb@ if (verbose_flag)@\\
+\mbox{}\verb@ fprintf(stderr, "writing %s\n", html_name);@\\
+\mbox{}\verb@ source_open(file_name);@\\
+\mbox{}\verb@ @$\langle$Copy \verb|source_file| into \verb|html_file| {\footnotesize 28c}$\rangle$\verb@@\\
+\mbox{}\verb@ fclose(html_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ fprintf(stderr, "%s: can't open %s\n", command_name, html_name);@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We make our second (and final) pass through the source web, this time
+copying characters straight into the \verb|.tex| file. However, we keep
+an eye peeled for \verb|@|~characters, which signal a command sequence.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap67}
+$\langle$Copy \verb|source_file| into \verb|html_file| {\footnotesize 28c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int scraps = 1;@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ while (c != EOF) {@\\
+\mbox{}\verb@ if (c == '@{\tt @}\verb@')@\\
+\mbox{}\verb@ @$\langle$Interpret HTML at-sequence {\footnotesize 29}$\rangle$\verb@@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ putc(c, html_file);@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 28b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap68}
+$\langle$Interpret HTML at-sequence {\footnotesize 29}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case 'O': @\\
+\mbox{}\verb@ case 'o': @$\langle$Write HTML output file definition {\footnotesize 30a}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'D': @\\
+\mbox{}\verb@ case 'd': @$\langle$Write HTML macro definition {\footnotesize 30c}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'f': @$\langle$Write HTML index of file names {\footnotesize 34c}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'm': @$\langle$Write HTML index of macro names {\footnotesize 34d}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'u': @$\langle$Write HTML index of user-specified names {\footnotesize 36b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': putc(c, html_file);@\\
+\mbox{}\verb@ default: c = source_get();@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 28c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Formatting Definitions}
+
+We go through only a little amount of effort to format a definition.
+The HTML for the previous macro definition should look like this
+(perhaps modulo the scrap references):
+
+\begin{verbatim}
+<pre>
+<a name="nuweb68">&lt;Interpret HTML at-sequence 68&gt;</a> =
+{
+ c = source_get();
+ switch (c) {
+ case 'O':
+ case 'o': &lt;Write HTML output file definition <a href="#nuweb69">69</a>&gt;
+ break;
+ case 'D':
+ case 'd': &lt;Write HTML macro definition <a href="#nuweb71">71</a>&gt;
+ break;
+ case 'f': &lt;Write HTML index of file names <a href="#nuweb86">86</a>&gt;
+ break;
+ case 'm': &lt;Write HTML index of macro names <a href="#nuweb87">87</a>&gt;
+ break;
+ case 'u': &lt;Write HTML index of user-specified names <a href="#nuweb93">93</a>&gt;
+ break;
+ case '@': putc(c, html_file);
+ default: c = source_get();
+ break;
+ }
+}&lt;&gt;</pre>
+Macro referenced in scrap <a href="#nuweb67">67</a>.
+<br>
+\end{verbatim}
+
+Macro and file definitions are formatted nearly identically.
+I've factored the common parts out into separate scraps.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap69}
+$\langle$Write HTML output file definition {\footnotesize 30a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_file_name();@\\
+\mbox{}\verb@ @$\langle$Begin HTML scrap environment {\footnotesize 30e}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Write HTML output file declaration {\footnotesize 30b}$\rangle$\verb@@\\
+\mbox{}\verb@ scraps++;@\\
+\mbox{}\verb@ @$\langle$Fill in the middle of HTML scrap environment {\footnotesize 31a}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Write HTML file defs {\footnotesize 31c}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Finish HTML scrap environment {\footnotesize 31b}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 29.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap70}
+$\langle$Write HTML output file declaration {\footnotesize 30b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@ fputs("<a name=\"nuweb", html_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(html_file, scraps);@\\
+\mbox{}\verb@ fprintf(html_file, "\"><code>\"%s\"</code> ", name->spelling);@\\
+\mbox{}\verb@ write_single_scrap_ref(html_file, scraps);@\\
+\mbox{}\verb@ fputs("</a> =\n", html_file);@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 30a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap71}
+$\langle$Write HTML macro definition {\footnotesize 30c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_macro_name();@\\
+\mbox{}\verb@ @$\langle$Begin HTML scrap environment {\footnotesize 30e}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Write HTML macro declaration {\footnotesize 30d}$\rangle$\verb@@\\
+\mbox{}\verb@ scraps++;@\\
+\mbox{}\verb@ @$\langle$Fill in the middle of HTML scrap environment {\footnotesize 31a}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Write HTML macro defs {\footnotesize 31d}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Write HTML macro refs {\footnotesize 31e}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Finish HTML scrap environment {\footnotesize 31b}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 29.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+I don't format a macro name at all specially, figuring the programmer
+might want to use italics or bold face in the midst of the name. Note
+that in this implementation, programmers may only use directives in
+macro names that are recognized in preformatted text elements (PRE).
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap72}
+$\langle$Write HTML macro declaration {\footnotesize 30d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@ fputs("<a name=\"nuweb", html_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(html_file, scraps);@\\
+\mbox{}\verb@ fprintf(html_file, "\">&lt;%s ", name->spelling);@\\
+\mbox{}\verb@ write_single_scrap_ref(html_file, scraps);@\\
+\mbox{}\verb@ fputs("&gt;</a> =\n", html_file);@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 30c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap73}
+$\langle$Begin HTML scrap environment {\footnotesize 30e}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("\\begin{rawhtml}\n", html_file);@\\
+\mbox{}\verb@ fputs("<pre>\n", html_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 30ac.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The end of a scrap is marked with the characters \verb|<>|.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap74}
+$\langle$Fill in the middle of HTML scrap environment {\footnotesize 31a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ copy_scrap(html_file);@\\
+\mbox{}\verb@ fputs("&lt;&gt;</pre>\n", html_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 30ac.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+The only task remaining is to get rid of the current at command and
+end the paragraph.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap75}
+$\langle$Finish HTML scrap environment {\footnotesize 31b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("\\end{rawhtml}\n", html_file);@\\
+\mbox{}\verb@ c = source_get(); /* Get rid of current at command. */@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 30ac.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Formatting Cross References}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap76}
+$\langle$Write HTML file defs {\footnotesize 31c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (name->defs->next) {@\\
+\mbox{}\verb@ fputs("File defined by ", html_file);@\\
+\mbox{}\verb@ print_scrap_numbers(html_file, name->defs);@\\
+\mbox{}\verb@ fputs("<br>\n", html_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 30a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap77}
+$\langle$Write HTML macro defs {\footnotesize 31d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (name->defs->next) {@\\
+\mbox{}\verb@ fputs("Macro defined by ", html_file);@\\
+\mbox{}\verb@ print_scrap_numbers(html_file, name->defs);@\\
+\mbox{}\verb@ fputs("<br>\n", html_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 30c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap78}
+$\langle$Write HTML macro refs {\footnotesize 31e}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (name->uses) {@\\
+\mbox{}\verb@ fputs("Macro referenced in ", html_file);@\\
+\mbox{}\verb@ print_scrap_numbers(html_file, name->uses);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ fputs("Macro never referenced.\n", html_file);@\\
+\mbox{}\verb@ fprintf(stderr, "%s: <%s> never referenced.\n",@\\
+\mbox{}\verb@ command_name, name->spelling);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fputs("<br>\n", html_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 30c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap79}
+\verb@"html.c"@ {\footnotesize 32a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void display_scrap_ref(html_file, num)@\\
+\mbox{}\verb@ FILE *html_file;@\\
+\mbox{}\verb@ int num;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("<a href=\"#nuweb", html_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(html_file, num);@\\
+\mbox{}\verb@ fputs("\">", html_file);@\\
+\mbox{}\verb@ write_single_scrap_ref(html_file, num);@\\
+\mbox{}\verb@ fputs("</a>", html_file);@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap80}
+\verb@"html.c"@ {\footnotesize 32b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void display_scrap_numbers(html_file, scraps)@\\
+\mbox{}\verb@ FILE *html_file;@\\
+\mbox{}\verb@ Scrap_Node *scraps;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ display_scrap_ref(html_file, scraps->scrap);@\\
+\mbox{}\verb@ scraps = scraps->next;@\\
+\mbox{}\verb@ while (scraps) {@\\
+\mbox{}\verb@ fputs(", ", html_file);@\\
+\mbox{}\verb@ display_scrap_ref(html_file, scraps->scrap);@\\
+\mbox{}\verb@ scraps = scraps->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap81}
+\verb@"html.c"@ {\footnotesize 32c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void print_scrap_numbers(html_file, scraps)@\\
+\mbox{}\verb@ FILE *html_file;@\\
+\mbox{}\verb@ Scrap_Node *scraps;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("scrap", html_file);@\\
+\mbox{}\verb@ if (scraps->next) fputc('s', html_file);@\\
+\mbox{}\verb@ fputc(' ', html_file);@\\
+\mbox{}\verb@ display_scrap_numbers(html_file, scraps);@\\
+\mbox{}\verb@ fputs(".\n", html_file);@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Formatting a Scrap}
+
+We must translate HTML special keywords into entities in scraps.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap82}
+\verb@"html.c"@ {\footnotesize 33a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void copy_scrap(file)@\\
+\mbox{}\verb@ FILE *file;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int indent = 0;@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ while (1) {@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': @$\langle$Check HTML at-sequence for end-of-scrap {\footnotesize 33b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '<' : fputs("&lt;", file);@\\
+\mbox{}\verb@ indent++;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '>' : fputs("&gt;", file);@\\
+\mbox{}\verb@ indent++;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '&' : fputs("&amp;", file);@\\
+\mbox{}\verb@ indent++;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\n': fputc(c, file);@\\
+\mbox{}\verb@ indent = 0;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\t': @$\langle$Expand tab into spaces {\footnotesize 22b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: putc(c, file);@\\
+\mbox{}\verb@ indent++;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap83}
+$\langle$Check HTML at-sequence for end-of-scrap {\footnotesize 33b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': fputc(c, file);@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '|': @$\langle$Skip over index entries {\footnotesize 23a}$\rangle$\verb@@\\
+\mbox{}\verb@ case '}': return;@\\
+\mbox{}\verb@ case '<': @$\langle$Format HTML macro name {\footnotesize 34a}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: /* ignore these since pass1 will have warned about them */@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 33a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+There's no need to check for errors here, since we will have already
+pointed out any during the first pass.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap84}
+$\langle$Format HTML macro name {\footnotesize 34a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_scrap_name();@\\
+\mbox{}\verb@ fprintf(file, "&lt;%s ", name->spelling);@\\
+\mbox{}\verb@ if (name->defs)@\\
+\mbox{}\verb@ @$\langle$Write HTML abbreviated definition list {\footnotesize 34b}$\rangle$\verb@@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ putc('?', file);@\\
+\mbox{}\verb@ fprintf(stderr, "%s: scrap never defined <%s>\n",@\\
+\mbox{}\verb@ command_name, name->spelling);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fputs("&gt;", file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 33b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap85}
+$\langle$Write HTML abbreviated definition list {\footnotesize 34b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *p = name->defs;@\\
+\mbox{}\verb@ display_scrap_ref(file, p->scrap);@\\
+\mbox{}\verb@ if (p->next)@\\
+\mbox{}\verb@ fputs(", ... ", file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 34a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Generating the Indices}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap86}
+$\langle$Write HTML index of file names {\footnotesize 34c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (file_names) {@\\
+\mbox{}\verb@ fputs("\\begin{rawhtml}\n", html_file);@\\
+\mbox{}\verb@ fputs("<dl compact>\n", html_file);@\\
+\mbox{}\verb@ format_entry(file_names, html_file, TRUE);@\\
+\mbox{}\verb@ fputs("</dl>\n", html_file);@\\
+\mbox{}\verb@ fputs("\\end{rawhtml}\n", html_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 29.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap87}
+$\langle$Write HTML index of macro names {\footnotesize 34d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (macro_names) {@\\
+\mbox{}\verb@ fputs("\\begin{rawhtml}\n", html_file);@\\
+\mbox{}\verb@ fputs("<dl compact>\n", html_file);@\\
+\mbox{}\verb@ format_entry(macro_names, html_file, FALSE);@\\
+\mbox{}\verb@ fputs("</dl>\n", html_file);@\\
+\mbox{}\verb@ fputs("\\end{rawhtml}\n", html_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 29.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap88}
+\verb@"html.c"@ {\footnotesize 35a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void format_entry(name, html_file, file_flag)@\\
+\mbox{}\verb@ Name *name;@\\
+\mbox{}\verb@ FILE *html_file;@\\
+\mbox{}\verb@ int file_flag;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (name) {@\\
+\mbox{}\verb@ format_entry(name->llink, html_file, file_flag);@\\
+\mbox{}\verb@ @$\langle$Format an HTML index entry {\footnotesize 35b}$\rangle$\verb@@\\
+\mbox{}\verb@ name = name->rlink;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap89}
+$\langle$Format an HTML index entry {\footnotesize 35b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("<dt> ", html_file);@\\
+\mbox{}\verb@ if (file_flag) {@\\
+\mbox{}\verb@ fprintf(html_file, "<code>\"%s\"</code>\n<dd> ", name->spelling);@\\
+\mbox{}\verb@ @$\langle$Write HTML file's defining scrap numbers {\footnotesize 35c}$\rangle$\verb@@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ fprintf(html_file, "&lt;%s ", name->spelling);@\\
+\mbox{}\verb@ @$\langle$Write HTML defining scrap numbers {\footnotesize 35d}$\rangle$\verb@@\\
+\mbox{}\verb@ fputs("&gt;\n<dd> ", html_file);@\\
+\mbox{}\verb@ @$\langle$Write HTML referencing scrap numbers {\footnotesize 36a}$\rangle$\verb@@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ putc('\n', html_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 35a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap90}
+$\langle$Write HTML file's defining scrap numbers {\footnotesize 35c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fputs("Defined by ", html_file);@\\
+\mbox{}\verb@ print_scrap_numbers(html_file, name->defs);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 35b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap91}
+$\langle$Write HTML defining scrap numbers {\footnotesize 35d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (name->defs)@\\
+\mbox{}\verb@ display_scrap_numbers(html_file, name->defs);@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ putc('?', html_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 35b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap92}
+$\langle$Write HTML referencing scrap numbers {\footnotesize 36a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *p = name->uses;@\\
+\mbox{}\verb@ if (p) {@\\
+\mbox{}\verb@ fputs("Referenced in ", html_file);@\\
+\mbox{}\verb@ print_scrap_numbers(html_file, p);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ fputs("Not referenced.\n", html_file);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 35b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap93}
+$\langle$Write HTML index of user-specified names {\footnotesize 36b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (user_names) {@\\
+\mbox{}\verb@ fputs("\\begin{rawhtml}\n", html_file);@\\
+\mbox{}\verb@ fputs("<dl compact>\n", html_file);@\\
+\mbox{}\verb@ format_user_entry(user_names, html_file);@\\
+\mbox{}\verb@ fputs("</dl>\n", html_file);@\\
+\mbox{}\verb@ fputs("\\end{rawhtml}\n", html_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 29.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap94}
+\verb@"html.c"@ {\footnotesize 36c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void format_user_entry(name, html_file)@\\
+\mbox{}\verb@ Name *name;@\\
+\mbox{}\verb@ FILE *html_file;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (name) {@\\
+\mbox{}\verb@ format_user_entry(name->llink, html_file);@\\
+\mbox{}\verb@ @$\langle$Format a user HTML index entry {\footnotesize 37a}$\rangle$\verb@@\\
+\mbox{}\verb@ name = name->rlink;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap95}
+$\langle$Format a user HTML index entry {\footnotesize 37a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Scrap_Node *uses = name->uses;@\\
+\mbox{}\verb@ if (uses) {@\\
+\mbox{}\verb@ Scrap_Node *defs = name->defs;@\\
+\mbox{}\verb@ fprintf(html_file, "<dt><code>%s</code>:\n<dd> ", name->spelling);@\\
+\mbox{}\verb@ if (uses->scrap < defs->scrap) {@\\
+\mbox{}\verb@ display_scrap_ref(html_file, uses->scrap);@\\
+\mbox{}\verb@ uses = uses->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ if (defs->scrap == uses->scrap)@\\
+\mbox{}\verb@ uses = uses->next;@\\
+\mbox{}\verb@ fputs("<strong>", html_file);@\\
+\mbox{}\verb@ display_scrap_ref(html_file, defs->scrap);@\\
+\mbox{}\verb@ fputs("</strong>", html_file);@\\
+\mbox{}\verb@ defs = defs->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ while (uses || defs) {@\\
+\mbox{}\verb@ fputs(", ", html_file);@\\
+\mbox{}\verb@ if (uses && (!defs || uses->scrap < defs->scrap)) {@\\
+\mbox{}\verb@ display_scrap_ref(html_file, uses->scrap);@\\
+\mbox{}\verb@ uses = uses->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ if (uses && defs->scrap == uses->scrap)@\\
+\mbox{}\verb@ uses = uses->next;@\\
+\mbox{}\verb@ fputs("<strong>", html_file);@\\
+\mbox{}\verb@ display_scrap_ref(html_file, defs->scrap);@\\
+\mbox{}\verb@ fputs("</strong>", html_file);@\\
+\mbox{}\verb@ defs = defs->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fputs(".\n", html_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 36c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Writing the Output Files} \label{output-files}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap96}
+$\langle$Function prototypes {\footnotesize 37b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void write_files();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap97}
+\verb@"output.c"@ {\footnotesize 37c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void write_files(files)@\\
+\mbox{}\verb@ Name *files;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (files) {@\\
+\mbox{}\verb@ write_files(files->llink);@\\
+\mbox{}\verb@ @$\langle$Write out \verb|files->spelling| {\footnotesize 38a}$\rangle$\verb@@\\
+\mbox{}\verb@ files = files->rlink;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 8f, 37c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We call \verb|tempnam|, causing it to create a file name in the
+current directory. This could cause a problem for \verb|rename| if
+the eventual output file will reside on a different file system.
+Perhaps it would be better to examine \verb|files->spelling| to find
+any directory information.
+
+Note the superfluous call to \verb|remove| before \verb|rename|.
+We're using it get around a bug in some implementations of
+\verb|rename|.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap98}
+$\langle$Write out \verb|files->spelling| {\footnotesize 38a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char indent_chars[500];@\\
+\mbox{}\verb@ FILE *temp_file;@\\
+\mbox{}\verb@ char *temp_name = tempnam(".", 0);@\\
+\mbox{}\verb@ temp_file = fopen(temp_name, "w");@\\
+\mbox{}\verb@ if (!temp_file) {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: can't create %s for a temporary file\n",@\\
+\mbox{}\verb@ command_name, temp_name);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ } @\\
+\mbox{}\verb@ if (verbose_flag)@\\
+\mbox{}\verb@ fprintf(stderr, "writing %s\n", files->spelling);@\\
+\mbox{}\verb@ write_scraps(temp_file, files->defs, 0, indent_chars,@\\
+\mbox{}\verb@ files->debug_flag, files->tab_flag, files->indent_flag);@\\
+\mbox{}\verb@ fclose(temp_file);@\\
+\mbox{}\verb@ if (compare_flag)@\\
+\mbox{}\verb@ @$\langle$Compare the temp file and the old file {\footnotesize 38b}$\rangle$\verb@@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ remove(files->spelling);@\\
+\mbox{}\verb@ rename(temp_name, files->spelling);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 37c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Again, we use a call to \verb|remove| before \verb|rename|.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap99}
+$\langle$Compare the temp file and the old file {\footnotesize 38b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ FILE *old_file = fopen(files->spelling, "r");@\\
+\mbox{}\verb@ if (old_file) {@\\
+\mbox{}\verb@ int x, y;@\\
+\mbox{}\verb@ temp_file = fopen(temp_name, "r");@\\
+\mbox{}\verb@ do {@\\
+\mbox{}\verb@ x = getc(old_file);@\\
+\mbox{}\verb@ y = getc(temp_file);@\\
+\mbox{}\verb@ } while (x == y && x != EOF);@\\
+\mbox{}\verb@ fclose(old_file);@\\
+\mbox{}\verb@ fclose(temp_file);@\\
+\mbox{}\verb@ if (x == y)@\\
+\mbox{}\verb@ remove(temp_name);@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ remove(files->spelling);@\\
+\mbox{}\verb@ rename(temp_name, files->spelling);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ rename(temp_name, files->spelling);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 38a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\chapter{The Support Routines}
+
+\section{Source Files} \label{source-files}
+
+\subsection{Global Declarations}
+
+We need two routines to handle reading the source files.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap100}
+$\langle$Function prototypes {\footnotesize 39a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void source_open(); /* pass in the name of the source file */@\\
+\mbox{}\verb@extern int source_get(); /* no args; returns the next char or EOF */@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+There are also two global variables maintained for use in error
+messages and such.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap101}
+$\langle$Global variable declarations {\footnotesize 39b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern char *source_name; /* name of the current file */@\\
+\mbox{}\verb@extern int source_line; /* current line in the source file */@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10ac, 39b, 44d, 53b.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap102}
+$\langle$Global variable definitions {\footnotesize 39c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@char *source_name = NULL;@\\
+\mbox{}\verb@int source_line = 0;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10bd, 39c, 45a, 53c.
+\item Macro referenced in scrap 9e.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Local Declarations}
+
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap103}
+\verb@"input.c"@ {\footnotesize 39d }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static FILE *source_file; /* the current input file */@\\
+\mbox{}\verb@static int source_peek;@\\
+\mbox{}\verb@static int double_at;@\\
+\mbox{}\verb@static int include_depth;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9a, 39d, 40ab, 42c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap104}
+\verb@"input.c"@ {\footnotesize 40a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static struct {@\\
+\mbox{}\verb@ FILE *file;@\\
+\mbox{}\verb@ char *name;@\\
+\mbox{}\verb@ int line;@\\
+\mbox{}\verb@} stack[10];@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9a, 39d, 40ab, 42c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Reading a File}
+
+The routine \verb|source_get| returns the next character from the
+current source file. It notices newlines and keeps the line counter
+\verb|source_line| up to date. It also catches \verb|EOF| and watches
+for \verb|@|~characters. All other characters are immediately returned.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap105}
+\verb@"input.c"@ {\footnotesize 40b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@int source_get()@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int c = source_peek;@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case EOF: @$\langle$Handle \verb|EOF| {\footnotesize 42b}$\rangle$\verb@@\\
+\mbox{}\verb@ return c;@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': @$\langle$Handle an ``at'' character {\footnotesize 41a}$\rangle$\verb@@\\
+\mbox{}\verb@ return c;@\\
+\mbox{}\verb@ case '\n': source_line++;@\\
+\mbox{}\verb@ default: source_peek = getc(source_file);@\\
+\mbox{}\verb@ return c;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9a, 39d, 40ab, 42c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+This whole \verb|@|~character handling mess is pretty annoying.
+I want to recognize \verb|@i| so I can handle include files correctly.
+At the same time, it makes sense to recognize illegal \verb|@|~sequences
+and complain; this avoids ever having to check anywhere else.
+Unfortunately, I need to avoid tripping over the \verb|@@|~sequence;
+hence this whole unsatisfactory \verb|double_at| business.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap106}
+$\langle$Handle an ``at'' character {\footnotesize 41a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = getc(source_file);@\\
+\mbox{}\verb@ if (double_at) {@\\
+\mbox{}\verb@ source_peek = c;@\\
+\mbox{}\verb@ double_at = FALSE;@\\
+\mbox{}\verb@ c = '@{\tt @}\verb@';@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case 'i': @$\langle$Open an include file {\footnotesize 41b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'f': case 'm': case 'u':@\\
+\mbox{}\verb@ case 'd': case 'o': case 'D': case 'O':@\\
+\mbox{}\verb@ case '{': case '}': case '<': case '>': case '|':@\\
+\mbox{}\verb@ source_peek = c;@\\
+\mbox{}\verb@ c = '@{\tt @}\verb@';@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': source_peek = c;@\\
+\mbox{}\verb@ double_at = TRUE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: fprintf(stderr, "%s: bad @{\tt @}\verb@ sequence (%s, line %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 40b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap107}
+$\langle$Open an include file {\footnotesize 41b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char name[100];@\\
+\mbox{}\verb@ if (include_depth >= 10) {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: include nesting too deep (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ @$\langle$Collect include-file name {\footnotesize 42a}$\rangle$\verb@@\\
+\mbox{}\verb@ stack[include_depth].name = source_name;@\\
+\mbox{}\verb@ stack[include_depth].file = source_file;@\\
+\mbox{}\verb@ stack[include_depth].line = source_line + 1;@\\
+\mbox{}\verb@ include_depth++;@\\
+\mbox{}\verb@ source_line = 1;@\\
+\mbox{}\verb@ source_name = save_string(name);@\\
+\mbox{}\verb@ source_file = fopen(source_name, "r");@\\
+\mbox{}\verb@ if (!source_file) {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: can't open include file %s\n",@\\
+\mbox{}\verb@ command_name, source_name);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ source_peek = getc(source_file);@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 41a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap108}
+$\langle$Collect include-file name {\footnotesize 42a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char *p = name;@\\
+\mbox{}\verb@ do @\\
+\mbox{}\verb@ c = getc(source_file);@\\
+\mbox{}\verb@ while (c == ' ' || c == '\t');@\\
+\mbox{}\verb@ while (isgraph(c)) {@\\
+\mbox{}\verb@ *p++ = c;@\\
+\mbox{}\verb@ c = getc(source_file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ *p = '\0';@\\
+\mbox{}\verb@ if (c != '\n') {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: unexpected characters after file name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 41b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+If an \verb|EOF| is discovered, the current file must be closed and
+input from the next stacked file must be resumed. If no more files are
+on the stack, the \verb|EOF| is returned.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap109}
+$\langle$Handle \verb|EOF| {\footnotesize 42b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ fclose(source_file);@\\
+\mbox{}\verb@ if (include_depth) {@\\
+\mbox{}\verb@ include_depth--;@\\
+\mbox{}\verb@ source_file = stack[include_depth].file;@\\
+\mbox{}\verb@ source_line = stack[include_depth].line;@\\
+\mbox{}\verb@ source_name = stack[include_depth].name;@\\
+\mbox{}\verb@ source_peek = getc(source_file);@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 40b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Opening a File}
+
+The routine \verb|source_open| takes a file name and tries to open the
+file. If unsuccessful, it complains and halts. Otherwise, it sets
+\verb|source_name|, \verb|source_line|, and \verb|double_at|.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap110}
+\verb@"input.c"@ {\footnotesize 42c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void source_open(name)@\\
+\mbox{}\verb@ char *name;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ source_file = fopen(name, "r");@\\
+\mbox{}\verb@ if (!source_file) {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: couldn't open %s\n", command_name, name);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ source_name = name;@\\
+\mbox{}\verb@ source_line = 1;@\\
+\mbox{}\verb@ source_peek = getc(source_file);@\\
+\mbox{}\verb@ double_at = FALSE;@\\
+\mbox{}\verb@ include_depth = 0;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9a, 39d, 40ab, 42c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Scraps} \label{scraps}
+
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap111}
+\verb@"scraps.c"@ {\footnotesize 43a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#define SLAB_SIZE 500@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@typedef struct slab {@\\
+\mbox{}\verb@ struct slab *next;@\\
+\mbox{}\verb@ char chars[SLAB_SIZE];@\\
+\mbox{}\verb@} Slab;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap112}
+\verb@"scraps.c"@ {\footnotesize 43b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@typedef struct {@\\
+\mbox{}\verb@ char *file_name;@\\
+\mbox{}\verb@ int file_line;@\\
+\mbox{}\verb@ int page;@\\
+\mbox{}\verb@ char letter;@\\
+\mbox{}\verb@ Slab *slab;@\\
+\mbox{}\verb@} ScrapEntry;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap113}
+\verb@"scraps.c"@ {\footnotesize 43c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static ScrapEntry *SCRAP[256];@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@#define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@static int scraps;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap114}
+$\langle$Function prototypes {\footnotesize 43d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void init_scraps();@\\
+\mbox{}\verb@extern int collect_scrap();@\\
+\mbox{}\verb@extern int write_scraps();@\\
+\mbox{}\verb@extern void write_scrap_ref();@\\
+\mbox{}\verb@extern void write_single_scrap_ref();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap115}
+\verb@"scraps.c"@ {\footnotesize 43e }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void init_scraps()@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ scraps = 1;@\\
+\mbox{}\verb@ SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap116}
+\verb@"scraps.c"@ {\footnotesize 44a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void write_scrap_ref(file, num, first, page)@\\
+\mbox{}\verb@ FILE *file;@\\
+\mbox{}\verb@ int num;@\\
+\mbox{}\verb@ int first;@\\
+\mbox{}\verb@ int *page;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (scrap_array(num).page >= 0) {@\\
+\mbox{}\verb@ if (first)@\\
+\mbox{}\verb@ fprintf(file, "%d", scrap_array(num).page);@\\
+\mbox{}\verb@ else if (scrap_array(num).page != *page)@\\
+\mbox{}\verb@ fprintf(file, ", %d", scrap_array(num).page);@\\
+\mbox{}\verb@ if (scrap_array(num).letter > 0)@\\
+\mbox{}\verb@ fputc(scrap_array(num).letter, file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ if (first)@\\
+\mbox{}\verb@ putc('?', file);@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ fputs(", ?", file);@\\
+\mbox{}\verb@ @$\langle$Warn (only once) about needing to rerun after Latex {\footnotesize 44c}$\rangle$\verb@@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ *page = scrap_array(num).page;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap117}
+\verb@"scraps.c"@ {\footnotesize 44b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void write_single_scrap_ref(file, num)@\\
+\mbox{}\verb@ FILE *file;@\\
+\mbox{}\verb@ int num;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int page;@\\
+\mbox{}\verb@ write_scrap_ref(file, num, TRUE, &page);@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap118}
+$\langle$Warn (only once) about needing to rerun after Latex {\footnotesize 44c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (!already_warned) {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: you'll need to rerun nuweb after running latex\n",@\\
+\mbox{}\verb@ command_name);@\\
+\mbox{}\verb@ already_warned = TRUE;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 44a, 52a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap119}
+$\langle$Global variable declarations {\footnotesize 44d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern int already_warned;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10ac, 39b, 44d, 53b.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap120}
+$\langle$Global variable definitions {\footnotesize 45a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@int already_warned = 0;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10bd, 39c, 45a, 53c.
+\item Macro referenced in scrap 9e.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap121}
+\verb@"scraps.c"@ {\footnotesize 45b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@typedef struct {@\\
+\mbox{}\verb@ Slab *scrap;@\\
+\mbox{}\verb@ Slab *prev;@\\
+\mbox{}\verb@ int index;@\\
+\mbox{}\verb@} Manager;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap122}
+\verb@"scraps.c"@ {\footnotesize 45c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void push(c, manager)@\\
+\mbox{}\verb@ char c;@\\
+\mbox{}\verb@ Manager *manager;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Slab *scrap = manager->scrap;@\\
+\mbox{}\verb@ int index = manager->index;@\\
+\mbox{}\verb@ scrap->chars[index++] = c;@\\
+\mbox{}\verb@ if (index == SLAB_SIZE) {@\\
+\mbox{}\verb@ Slab *new = (Slab *) arena_getmem(sizeof(Slab));@\\
+\mbox{}\verb@ scrap->next = new;@\\
+\mbox{}\verb@ manager->scrap = new;@\\
+\mbox{}\verb@ index = 0;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ manager->index = index;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap123}
+\verb@"scraps.c"@ {\footnotesize 45d }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void pushs(s, manager)@\\
+\mbox{}\verb@ char *s;@\\
+\mbox{}\verb@ Manager *manager;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (*s)@\\
+\mbox{}\verb@ push(*s++, manager);@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap124}
+\verb@"scraps.c"@ {\footnotesize 45e }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@int collect_scrap()@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Manager writer;@\\
+\mbox{}\verb@ @$\langle$Create new scrap, managed by \verb|writer| {\footnotesize 46a}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Accumulate scrap and return \verb|scraps++| {\footnotesize 46b}$\rangle$\verb@@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap125}
+$\langle$Create new scrap, managed by \verb|writer| {\footnotesize 46a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));@\\
+\mbox{}\verb@ if ((scraps & 255) == 0)@\\
+\mbox{}\verb@ SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));@\\
+\mbox{}\verb@ scrap_array(scraps).slab = scrap;@\\
+\mbox{}\verb@ scrap_array(scraps).file_name = save_string(source_name);@\\
+\mbox{}\verb@ scrap_array(scraps).file_line = source_line;@\\
+\mbox{}\verb@ scrap_array(scraps).page = -1;@\\
+\mbox{}\verb@ scrap_array(scraps).letter = 0;@\\
+\mbox{}\verb@ writer.scrap = scrap;@\\
+\mbox{}\verb@ writer.index = 0;@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 45e.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap126}
+$\langle$Accumulate scrap and return \verb|scraps++| {\footnotesize 46b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ while (1) {@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, scrap_array(scraps).file_name,@\\
+\mbox{}\verb@ scrap_array(scraps).file_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': @$\langle$Handle at-sign during scrap accumulation {\footnotesize 46c}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: push(c, &writer);@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 45e.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap127}
+$\langle$Handle at-sign during scrap accumulation {\footnotesize 46c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': pushs("@{\tt @}\verb@@{\tt @}\verb@", &writer);@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '|': @$\langle$Collect user-specified index entries {\footnotesize 47a}$\rangle$\verb@@\\
+\mbox{}\verb@ case '}': push('\0', &writer);@\\
+\mbox{}\verb@ return scraps++;@\\
+\mbox{}\verb@ case '<': @$\langle$Handle macro invocation in scrap {\footnotesize 47b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default : fprintf(stderr, "%s: unexpected @{\tt @}\verb@%c in scrap (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, c, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 46b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap128}
+$\langle$Collect user-specified index entries {\footnotesize 47a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ do {@\\
+\mbox{}\verb@ char new_name[100];@\\
+\mbox{}\verb@ char *p = new_name;@\\
+\mbox{}\verb@ do @\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (isspace(c));@\\
+\mbox{}\verb@ if (c != '@{\tt @}\verb@') {@\\
+\mbox{}\verb@ Name *name;@\\
+\mbox{}\verb@ do {@\\
+\mbox{}\verb@ *p++ = c;@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ } while (c != '@{\tt @}\verb@' && !isspace(c));@\\
+\mbox{}\verb@ *p = '\0';@\\
+\mbox{}\verb@ name = name_add(&user_names, new_name);@\\
+\mbox{}\verb@ if (!name->defs || name->defs->scrap != scraps) {@\\
+\mbox{}\verb@ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));@\\
+\mbox{}\verb@ def->scrap = scraps;@\\
+\mbox{}\verb@ def->next = name->defs;@\\
+\mbox{}\verb@ name->defs = def;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ } while (c != '@{\tt @}\verb@');@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ if (c != '}') {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: unexpected @{\tt @}\verb@%c in scrap (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, c, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 46c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap129}
+$\langle$Handle macro invocation in scrap {\footnotesize 47b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = collect_scrap_name();@\\
+\mbox{}\verb@ @$\langle$Save macro name {\footnotesize 47c}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Add current scrap to \verb|name|'s uses {\footnotesize 48a}$\rangle$\verb@@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 46c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap130}
+$\langle$Save macro name {\footnotesize 47c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char *s = name->spelling;@\\
+\mbox{}\verb@ int len = strlen(s) - 1;@\\
+\mbox{}\verb@ pushs("@{\tt @}\verb@<", &writer);@\\
+\mbox{}\verb@ while (len > 0) {@\\
+\mbox{}\verb@ push(*s++, &writer);@\\
+\mbox{}\verb@ len--;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ if (*s == ' ')@\\
+\mbox{}\verb@ pushs("...", &writer);@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ push(*s, &writer);@\\
+\mbox{}\verb@ pushs("@{\tt @}\verb@>", &writer);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 47b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap131}
+$\langle$Add current scrap to \verb|name|'s uses {\footnotesize 48a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (!name->uses || name->uses->scrap != scraps) {@\\
+\mbox{}\verb@ Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));@\\
+\mbox{}\verb@ use->scrap = scraps;@\\
+\mbox{}\verb@ use->next = name->uses;@\\
+\mbox{}\verb@ name->uses = use;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 47b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap132}
+\verb@"scraps.c"@ {\footnotesize 48b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static char pop(manager)@\\
+\mbox{}\verb@ Manager *manager;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Slab *scrap = manager->scrap;@\\
+\mbox{}\verb@ int index = manager->index;@\\
+\mbox{}\verb@ char c = scrap->chars[index++];@\\
+\mbox{}\verb@ if (index == SLAB_SIZE) {@\\
+\mbox{}\verb@ manager->prev = scrap;@\\
+\mbox{}\verb@ manager->scrap = scrap->next;@\\
+\mbox{}\verb@ index = 0;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ manager->index = index;@\\
+\mbox{}\verb@ return c;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap133}
+\verb@"scraps.c"@ {\footnotesize 48c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static Name *pop_scrap_name(manager)@\\
+\mbox{}\verb@ Manager *manager;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char name[100];@\\
+\mbox{}\verb@ char *p = name;@\\
+\mbox{}\verb@ int c = pop(manager);@\\
+\mbox{}\verb@ while (TRUE) {@\\
+\mbox{}\verb@ if (c == '@{\tt @}\verb@')@\\
+\mbox{}\verb@ @$\langle$Check for end of scrap name and return {\footnotesize 49a}$\rangle$\verb@@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ *p++ = c;@\\
+\mbox{}\verb@ c = pop(manager);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap134}
+$\langle$Check for end of scrap name and return {\footnotesize 49a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = pop(manager);@\\
+\mbox{}\verb@ if (c == '@{\tt @}\verb@') {@\\
+\mbox{}\verb@ *p++ = c;@\\
+\mbox{}\verb@ c = pop(manager);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else if (c == '>') {@\\
+\mbox{}\verb@ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {@\\
+\mbox{}\verb@ p[-3] = ' ';@\\
+\mbox{}\verb@ p -= 2;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ *p = '\0';@\\
+\mbox{}\verb@ return prefix_add(&macro_names, name);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: found an internal problem (1)\n", command_name);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 48c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap135}
+\verb@"scraps.c"@ {\footnotesize 49b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@int write_scraps(file, defs, global_indent, indent_chars,@\\
+\mbox{}\verb@ debug_flag, tab_flag, indent_flag)@\\
+\mbox{}\verb@ FILE *file;@\\
+\mbox{}\verb@ Scrap_Node *defs;@\\
+\mbox{}\verb@ int global_indent;@\\
+\mbox{}\verb@ char *indent_chars;@\\
+\mbox{}\verb@ char debug_flag;@\\
+\mbox{}\verb@ char tab_flag;@\\
+\mbox{}\verb@ char indent_flag;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int indent = 0;@\\
+\mbox{}\verb@ while (defs) {@\\
+\mbox{}\verb@ @$\langle$Copy \verb|defs->scrap| to \verb|file| {\footnotesize 50a}$\rangle$\verb@@\\
+\mbox{}\verb@ defs = defs->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ return indent + global_indent;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap136}
+$\langle$Copy \verb|defs->scrap| to \verb|file| {\footnotesize 50a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char c;@\\
+\mbox{}\verb@ Manager reader;@\\
+\mbox{}\verb@ int line_number = scrap_array(defs->scrap).file_line;@\\
+\mbox{}\verb@ @$\langle$Insert debugging information if required {\footnotesize 50b}$\rangle$\verb@@\\
+\mbox{}\verb@ reader.scrap = scrap_array(defs->scrap).slab;@\\
+\mbox{}\verb@ reader.index = 0;@\\
+\mbox{}\verb@ c = pop(&reader);@\\
+\mbox{}\verb@ while (c) {@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': @$\langle$Check for macro invocation in scrap {\footnotesize 51b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\n': putc(c, file);@\\
+\mbox{}\verb@ line_number++;@\\
+\mbox{}\verb@ @$\langle$Insert appropriate indentation {\footnotesize 50c}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\t': @$\langle$Handle tab characters on output {\footnotesize 51a}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: putc(c, file);@\\
+\mbox{}\verb@ indent_chars[global_indent + indent] = ' ';@\\
+\mbox{}\verb@ indent++;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = pop(&reader);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 49b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap137}
+$\langle$Insert debugging information if required {\footnotesize 50b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@if (debug_flag) {@\\
+\mbox{}\verb@ fprintf(file, "\n#line %d \"%s\"\n",@\\
+\mbox{}\verb@ line_number, scrap_array(defs->scrap).file_name);@\\
+\mbox{}\verb@ @$\langle$Insert appropriate indentation {\footnotesize 50c}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 50a, 51b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap138}
+$\langle$Insert appropriate indentation {\footnotesize 50c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (indent_flag) {@\\
+\mbox{}\verb@ if (tab_flag)@\\
+\mbox{}\verb@ for (indent=0; indent<global_indent; indent++)@\\
+\mbox{}\verb@ putc(' ', file);@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ for (indent=0; indent<global_indent; indent++)@\\
+\mbox{}\verb@ putc(indent_chars[indent], file);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ indent = 0;@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 50ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap139}
+$\langle$Handle tab characters on output {\footnotesize 51a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (tab_flag)@\\
+\mbox{}\verb@ @$\langle$Expand tab into spaces {\footnotesize 22b}$\rangle$\verb@@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ putc('\t', file);@\\
+\mbox{}\verb@ indent_chars[global_indent + indent] = '\t';@\\
+\mbox{}\verb@ indent++;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 50a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap140}
+$\langle$Check for macro invocation in scrap {\footnotesize 51b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = pop(&reader);@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': putc(c, file);@\\
+\mbox{}\verb@ indent_chars[global_indent + indent] = ' ';@\\
+\mbox{}\verb@ indent++;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '<': @$\langle$Copy macro into \verb|file| {\footnotesize 51c}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Insert debugging information if required {\footnotesize 50b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: /* ignore, since we should already have a warning */@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 50a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap141}
+$\langle$Copy macro into \verb|file| {\footnotesize 51c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *name = pop_scrap_name(&reader);@\\
+\mbox{}\verb@ if (name->mark) {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",@\\
+\mbox{}\verb@ command_name, name->spelling);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ if (name->defs) {@\\
+\mbox{}\verb@ name->mark = TRUE;@\\
+\mbox{}\verb@ indent = write_scraps(file, name->defs, global_indent + indent,@\\
+\mbox{}\verb@ indent_chars, debug_flag, tab_flag, indent_flag);@\\
+\mbox{}\verb@ indent -= global_indent;@\\
+\mbox{}\verb@ name->mark = FALSE;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else if (!tex_flag)@\\
+\mbox{}\verb@ fprintf(stderr, "%s: macro never defined <%s>\n",@\\
+\mbox{}\verb@ command_name, name->spelling);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 51b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Collecting Page Numbers}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap142}
+$\langle$Function prototypes {\footnotesize 51d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void collect_numbers();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap143}
+\verb@"scraps.c"@ {\footnotesize 52a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void collect_numbers(aux_name)@\\
+\mbox{}\verb@ char *aux_name;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (number_flag) {@\\
+\mbox{}\verb@ int i;@\\
+\mbox{}\verb@ for (i=1; i<scraps; i++)@\\
+\mbox{}\verb@ scrap_array(i).page = i;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else {@\\
+\mbox{}\verb@ FILE *aux_file = fopen(aux_name, "r");@\\
+\mbox{}\verb@ already_warned = FALSE;@\\
+\mbox{}\verb@ if (aux_file) {@\\
+\mbox{}\verb@ char aux_line[500];@\\
+\mbox{}\verb@ while (fgets(aux_line, 500, aux_file)) {@\\
+\mbox{}\verb@ int scrap_number;@\\
+\mbox{}\verb@ int page_number;@\\
+\mbox{}\verb@ char dummy[50];@\\
+\mbox{}\verb@ if (3 == sscanf(aux_line, "\\newlabel{scrap%d}{%[^}]}{%d}",@\\
+\mbox{}\verb@ &scrap_number, dummy, &page_number)) {@\\
+\mbox{}\verb@ if (scrap_number < scraps)@\\
+\mbox{}\verb@ scrap_array(scrap_number).page = page_number;@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ @$\langle$Warn (only once) about needing to rerun after Latex {\footnotesize 44c}$\rangle$\verb@@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fclose(aux_file);@\\
+\mbox{}\verb@ @$\langle$Add letters to scraps with duplicate page numbers {\footnotesize 52b}$\rangle$\verb@@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap144}
+$\langle$Add letters to scraps with duplicate page numbers {\footnotesize 52b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int scrap;@\\
+\mbox{}\verb@ for (scrap=2; scrap<scraps; scrap++) {@\\
+\mbox{}\verb@ if (scrap_array(scrap-1).page == scrap_array(scrap).page) {@\\
+\mbox{}\verb@ if (!scrap_array(scrap-1).letter)@\\
+\mbox{}\verb@ scrap_array(scrap-1).letter = 'a';@\\
+\mbox{}\verb@ scrap_array(scrap).letter = scrap_array(scrap-1).letter + 1;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 52a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Names} \label{names}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap145}
+$\langle$Type declarations {\footnotesize 52c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@typedef struct scrap_node {@\\
+\mbox{}\verb@ struct scrap_node *next;@\\
+\mbox{}\verb@ int scrap;@\\
+\mbox{}\verb@} Scrap_Node;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 8a, 52c, 53a.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap146}
+$\langle$Type declarations {\footnotesize 53a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@typedef struct name {@\\
+\mbox{}\verb@ char *spelling;@\\
+\mbox{}\verb@ struct name *llink;@\\
+\mbox{}\verb@ struct name *rlink;@\\
+\mbox{}\verb@ Scrap_Node *defs;@\\
+\mbox{}\verb@ Scrap_Node *uses;@\\
+\mbox{}\verb@ int mark;@\\
+\mbox{}\verb@ char tab_flag;@\\
+\mbox{}\verb@ char indent_flag;@\\
+\mbox{}\verb@ char debug_flag;@\\
+\mbox{}\verb@} Name;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 8a, 52c, 53a.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap147}
+$\langle$Global variable declarations {\footnotesize 53b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern Name *file_names;@\\
+\mbox{}\verb@extern Name *macro_names;@\\
+\mbox{}\verb@extern Name *user_names;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10ac, 39b, 44d, 53b.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap148}
+$\langle$Global variable definitions {\footnotesize 53c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@Name *file_names = NULL;@\\
+\mbox{}\verb@Name *macro_names = NULL;@\\
+\mbox{}\verb@Name *user_names = NULL;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 10bd, 39c, 45a, 53c.
+\item Macro referenced in scrap 9e.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap149}
+$\langle$Function prototypes {\footnotesize 53d}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern Name *collect_file_name();@\\
+\mbox{}\verb@extern Name *collect_macro_name();@\\
+\mbox{}\verb@extern Name *collect_scrap_name();@\\
+\mbox{}\verb@extern Name *name_add();@\\
+\mbox{}\verb@extern Name *prefix_add();@\\
+\mbox{}\verb@extern char *save_string();@\\
+\mbox{}\verb@extern void reverse_lists();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap150}
+\verb@"names.c"@ {\footnotesize 54a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@enum { LESS, GREATER, EQUAL, PREFIX, EXTENSION };@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@static int compare(x, y)@\\
+\mbox{}\verb@ char *x;@\\
+\mbox{}\verb@ char *y;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int len, result;@\\
+\mbox{}\verb@ int xl = strlen(x);@\\
+\mbox{}\verb@ int yl = strlen(y);@\\
+\mbox{}\verb@ int xp = x[xl - 1] == ' ';@\\
+\mbox{}\verb@ int yp = y[yl - 1] == ' ';@\\
+\mbox{}\verb@ if (xp) xl--;@\\
+\mbox{}\verb@ if (yp) yl--;@\\
+\mbox{}\verb@ len = xl < yl ? xl : yl;@\\
+\mbox{}\verb@ result = strncmp(x, y, len);@\\
+\mbox{}\verb@ if (result < 0) return GREATER;@\\
+\mbox{}\verb@ else if (result > 0) return LESS;@\\
+\mbox{}\verb@ else if (xl < yl) {@\\
+\mbox{}\verb@ if (xp) return EXTENSION;@\\
+\mbox{}\verb@ else return LESS;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else if (xl > yl) {@\\
+\mbox{}\verb@ if (yp) return PREFIX;@\\
+\mbox{}\verb@ else return GREATER;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else return EQUAL;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap151}
+\verb@"names.c"@ {\footnotesize 54b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@char *save_string(s)@\\
+\mbox{}\verb@ char *s;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char *new = (char *) arena_getmem((strlen(s) + 1) * sizeof(char));@\\
+\mbox{}\verb@ strcpy(new, s);@\\
+\mbox{}\verb@ return new;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap152}
+\verb@"names.c"@ {\footnotesize 55a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static int ambiguous_prefix();@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@Name *prefix_add(root, spelling)@\\
+\mbox{}\verb@ Name **root;@\\
+\mbox{}\verb@ char *spelling;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *node = *root;@\\
+\mbox{}\verb@ while (node) {@\\
+\mbox{}\verb@ switch (compare(node->spelling, spelling)) {@\\
+\mbox{}\verb@ case GREATER: root = &node->rlink;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case LESS: root = &node->llink;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case EQUAL: return node;@\\
+\mbox{}\verb@ case EXTENSION: node->spelling = save_string(spelling);@\\
+\mbox{}\verb@ return node;@\\
+\mbox{}\verb@ case PREFIX: @$\langle$Check for ambiguous prefix {\footnotesize 55b}$\rangle$\verb@@\\
+\mbox{}\verb@ return node;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ node = *root;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ @$\langle$Create new name entry {\footnotesize 58a}$\rangle$\verb@@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Since a very short prefix might match more than one macro name, I need
+to check for other matches to avoid mistakes. Basically, I simply
+continue the search down {\em both\/} branches of the tree.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap153}
+$\langle$Check for ambiguous prefix {\footnotesize 55b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (ambiguous_prefix(node->llink, spelling) ||@\\
+\mbox{}\verb@ ambiguous_prefix(node->rlink, spelling))@\\
+\mbox{}\verb@ fprintf(stderr,@\\
+\mbox{}\verb@ "%s: ambiguous prefix @{\tt @}\verb@<%s...@{\tt @}\verb@> (%s, line %d)\n",@\\
+\mbox{}\verb@ command_name, spelling, source_name, source_line);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 55a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap154}
+\verb@"names.c"@ {\footnotesize 56 }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static int ambiguous_prefix(node, spelling)@\\
+\mbox{}\verb@ Name *node;@\\
+\mbox{}\verb@ char *spelling;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (node) {@\\
+\mbox{}\verb@ switch (compare(node->spelling, spelling)) {@\\
+\mbox{}\verb@ case GREATER: node = node->rlink;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case LESS: node = node->llink;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case EQUAL:@\\
+\mbox{}\verb@ case EXTENSION:@\\
+\mbox{}\verb@ case PREFIX: return TRUE;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ return FALSE;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Rob Shillingsburg suggested that I organize the index of
+user-specified identifiers more traditionally; that is, not relying on
+strict {\small ASCII} comparisons via \verb|strcmp|. Ideally, we'd like
+to see the index ordered like this:
+\begin{quote}
+\begin{flushleft}
+aardvark \\
+Adam \\
+atom \\
+Atomic \\
+atoms
+\end{flushleft}
+\end{quote}
+The function \verb|robs_strcmp| implements the desired predicate.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap155}
+\verb@"names.c"@ {\footnotesize 57a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static int robs_strcmp(x, y)@\\
+\mbox{}\verb@ char *x;@\\
+\mbox{}\verb@ char *y;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char *xx = x;@\\
+\mbox{}\verb@ char *yy = y;@\\
+\mbox{}\verb@ int xc = toupper(*xx);@\\
+\mbox{}\verb@ int yc = toupper(*yy);@\\
+\mbox{}\verb@ while (xc == yc && xc) {@\\
+\mbox{}\verb@ xx++;@\\
+\mbox{}\verb@ yy++;@\\
+\mbox{}\verb@ xc = toupper(*xx);@\\
+\mbox{}\verb@ yc = toupper(*yy);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ if (xc != yc) return xc - yc;@\\
+\mbox{}\verb@ xc = *x;@\\
+\mbox{}\verb@ yc = *y;@\\
+\mbox{}\verb@ while (xc == yc && xc) {@\\
+\mbox{}\verb@ x++;@\\
+\mbox{}\verb@ y++;@\\
+\mbox{}\verb@ xc = *x;@\\
+\mbox{}\verb@ yc = *y;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ if (isupper(xc) && islower(yc))@\\
+\mbox{}\verb@ return xc * 2 - (toupper(yc) * 2 + 1);@\\
+\mbox{}\verb@ if (islower(xc) && isupper(yc))@\\
+\mbox{}\verb@ return toupper(xc) * 2 + 1 - yc * 2;@\\
+\mbox{}\verb@ return xc - yc;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap156}
+\verb@"names.c"@ {\footnotesize 57b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@Name *name_add(root, spelling)@\\
+\mbox{}\verb@ Name **root;@\\
+\mbox{}\verb@ char *spelling;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *node = *root;@\\
+\mbox{}\verb@ while (node) {@\\
+\mbox{}\verb@ int result = robs_strcmp(node->spelling, spelling);@\\
+\mbox{}\verb@ if (result > 0)@\\
+\mbox{}\verb@ root = &node->llink;@\\
+\mbox{}\verb@ else if (result < 0)@\\
+\mbox{}\verb@ root = &node->rlink;@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ return node;@\\
+\mbox{}\verb@ node = *root;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ @$\langle$Create new name entry {\footnotesize 58a}$\rangle$\verb@@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap157}
+$\langle$Create new name entry {\footnotesize 58a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ node = (Name *) arena_getmem(sizeof(Name));@\\
+\mbox{}\verb@ node->spelling = save_string(spelling);@\\
+\mbox{}\verb@ node->mark = FALSE;@\\
+\mbox{}\verb@ node->llink = NULL;@\\
+\mbox{}\verb@ node->rlink = NULL;@\\
+\mbox{}\verb@ node->uses = NULL;@\\
+\mbox{}\verb@ node->defs = NULL;@\\
+\mbox{}\verb@ node->tab_flag = TRUE;@\\
+\mbox{}\verb@ node->indent_flag = TRUE;@\\
+\mbox{}\verb@ node->debug_flag = FALSE;@\\
+\mbox{}\verb@ *root = node;@\\
+\mbox{}\verb@ return node;@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 55a, 57b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Name terminated by whitespace. Also check for ``per-file'' flags. Keep
+skipping white space until we reach scrap.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap158}
+\verb@"names.c"@ {\footnotesize 58b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@Name *collect_file_name()@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Name *new_name;@\\
+\mbox{}\verb@ char name[100];@\\
+\mbox{}\verb@ char *p = name;@\\
+\mbox{}\verb@ int start_line = source_line;@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ while (isspace(c))@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (isgraph(c)) {@\\
+\mbox{}\verb@ *p++ = c;@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ if (p == name) {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: expected file name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, start_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ *p = '\0';@\\
+\mbox{}\verb@ new_name = name_add(&file_names, name);@\\
+\mbox{}\verb@ @$\langle$Handle optional per-file flags {\footnotesize 59}$\rangle$\verb@@\\
+\mbox{}\verb@ if (c != '@{\tt @}\verb@' || source_get() != '{') {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: expected @{\tt @}\verb@{ after file name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, start_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ return new_name;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap159}
+$\langle$Handle optional per-file flags {\footnotesize 59}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (1) {@\\
+\mbox{}\verb@ while (isspace(c))@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ if (c == '-') {@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ do {@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case 't': new_name->tab_flag = FALSE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'd': new_name->debug_flag = TRUE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case 'i': new_name->indent_flag = FALSE;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default : fprintf(stderr, "%s: unexpected per-file flag (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, source_line);@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ } while (!isspace(c));@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ else break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 58b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Name terminated by \verb+\n+ or \verb+@{+; but keep skipping until \verb+@{+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap160}
+\verb@"names.c"@ {\footnotesize 60a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@Name *collect_macro_name()@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char name[100];@\\
+\mbox{}\verb@ char *p = name;@\\
+\mbox{}\verb@ int start_line = source_line;@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ while (isspace(c))@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (c != EOF) {@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': @$\langle$Check for terminating at-sequence and return name {\footnotesize 60b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\t':@\\
+\mbox{}\verb@ case ' ': *p++ = ' ';@\\
+\mbox{}\verb@ do@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (c == ' ' || c == '\t');@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\n': @$\langle$Skip until scrap begins, then return name {\footnotesize 61b}$\rangle$\verb@@\\
+\mbox{}\verb@ default: *p++ = c;@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fprintf(stderr, "%s: expected macro name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, start_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ return NULL; /* unreachable return to avoid warnings on some compilers */@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap161}
+$\langle$Check for terminating at-sequence and return name {\footnotesize 60b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': *p++ = c;@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '{': @$\langle$Cleanup and install name {\footnotesize 61a}$\rangle$\verb@@\\
+\mbox{}\verb@ default: fprintf(stderr,@\\
+\mbox{}\verb@ "%s: unexpected @{\tt @}\verb@%c in macro name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, c, source_name, start_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 60a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap162}
+$\langle$Cleanup and install name {\footnotesize 61a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (p > name && p[-1] == ' ')@\\
+\mbox{}\verb@ p--;@\\
+\mbox{}\verb@ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {@\\
+\mbox{}\verb@ p[-3] = ' ';@\\
+\mbox{}\verb@ p -= 2;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ if (p == name || name[0] == ' ') {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: empty scrap name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ *p = '\0';@\\
+\mbox{}\verb@ return prefix_add(&macro_names, name);@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scraps 60b, 61b, 62b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap163}
+$\langle$Skip until scrap begins, then return name {\footnotesize 61b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ do@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (isspace(c));@\\
+\mbox{}\verb@ if (c != '@{\tt @}\verb@' || source_get() != '{') {@\\
+\mbox{}\verb@ fprintf(stderr, "%s: expected @{\tt @}\verb@{ after macro name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, start_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ @$\langle$Cleanup and install name {\footnotesize 61a}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 60a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Terminated by \verb+@>+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap164}
+\verb@"names.c"@ {\footnotesize 62a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@Name *collect_scrap_name()@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char name[100];@\\
+\mbox{}\verb@ char *p = name;@\\
+\mbox{}\verb@ int c = source_get();@\\
+\mbox{}\verb@ while (c == ' ' || c == '\t')@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (c != EOF) {@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': @$\langle$Look for end of scrap name and return {\footnotesize 62b}$\rangle$\verb@@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '\t':@\\
+\mbox{}\verb@ case ' ': *p++ = ' ';@\\
+\mbox{}\verb@ do@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ while (c == ' ' || c == '\t');@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ default: if (!isgraph(c)) {@\\
+\mbox{}\verb@ fprintf(stderr,@\\
+\mbox{}\verb@ "%s: unexpected character in macro name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ *p++ = c;@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ fprintf(stderr, "%s: unexpected end of file (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ return NULL; /* unreachable return to avoid warnings on some compilers */@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap165}
+$\langle$Look for end of scrap name and return {\footnotesize 62b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '@{\tt @}\verb@': *p++ = c;@\\
+\mbox{}\verb@ c = source_get();@\\
+\mbox{}\verb@ break;@\\
+\mbox{}\verb@ case '>': @$\langle$Cleanup and install name {\footnotesize 61a}$\rangle$\verb@@\\
+\mbox{}\verb@ default: fprintf(stderr,@\\
+\mbox{}\verb@ "%s: unexpected @{\tt @}\verb@%c in macro name (%s, %d)\n",@\\
+\mbox{}\verb@ command_name, c, source_name, source_line);@\\
+\mbox{}\verb@ exit(-1);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 62a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap166}
+\verb@"names.c"@ {\footnotesize 63a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static Scrap_Node *reverse(); /* a forward declaration */@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@void reverse_lists(names)@\\
+\mbox{}\verb@ Name *names;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (names) {@\\
+\mbox{}\verb@ reverse_lists(names->llink);@\\
+\mbox{}\verb@ names->defs = reverse(names->defs);@\\
+\mbox{}\verb@ names->uses = reverse(names->uses);@\\
+\mbox{}\verb@ names = names->rlink;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+Just for fun, here's a non-recursive version of the traditional list
+reversal code. Note that it reverses the list in place; that is, it
+does no new allocations.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap167}
+\verb@"names.c"@ {\footnotesize 63b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static Scrap_Node *reverse(a)@\\
+\mbox{}\verb@ Scrap_Node *a;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ if (a) {@\\
+\mbox{}\verb@ Scrap_Node *b = a->next;@\\
+\mbox{}\verb@ a->next = NULL;@\\
+\mbox{}\verb@ while (b) {@\\
+\mbox{}\verb@ Scrap_Node *c = b->next;@\\
+\mbox{}\verb@ b->next = a;@\\
+\mbox{}\verb@ a = b;@\\
+\mbox{}\verb@ b = c;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ return a;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Searching for Index Entries} \label{search}
+
+Given the array of scraps and a set of index entries, we need to
+search all the scraps for occurrences of each entry. The obvious
+approach to this problem would be quite expensive for large documents;
+however, there is an interesting paper describing an efficient
+solution~\cite{aho:75}.
+
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap168}
+\verb@"scraps.c"@ {\footnotesize 63c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@typedef struct name_node {@\\
+\mbox{}\verb@ struct name_node *next;@\\
+\mbox{}\verb@ Name *name;@\\
+\mbox{}\verb@} Name_Node;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap169}
+\verb@"scraps.c"@ {\footnotesize 64a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@typedef struct goto_node {@\\
+\mbox{}\verb@ Name_Node *output; /* list of words ending in this state */@\\
+\mbox{}\verb@ struct move_node *moves; /* list of possible moves */@\\
+\mbox{}\verb@ struct goto_node *fail; /* and where to go when no move fits */@\\
+\mbox{}\verb@ struct goto_node *next; /* next goto node with same depth */@\\
+\mbox{}\verb@} Goto_Node;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap170}
+\verb@"scraps.c"@ {\footnotesize 64b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@typedef struct move_node {@\\
+\mbox{}\verb@ struct move_node *next;@\\
+\mbox{}\verb@ Goto_Node *state;@\\
+\mbox{}\verb@ char c;@\\
+\mbox{}\verb@} Move_Node;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap171}
+\verb@"scraps.c"@ {\footnotesize 64c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static Goto_Node *root[128];@\\
+\mbox{}\verb@static int max_depth;@\\
+\mbox{}\verb@static Goto_Node **depths;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap172}
+\verb@"scraps.c"@ {\footnotesize 64d }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static Goto_Node *goto_lookup(c, g)@\\
+\mbox{}\verb@ char c;@\\
+\mbox{}\verb@ Goto_Node *g;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Move_Node *m = g->moves;@\\
+\mbox{}\verb@ while (m && m->c != c)@\\
+\mbox{}\verb@ m = m->next;@\\
+\mbox{}\verb@ if (m)@\\
+\mbox{}\verb@ return m->state;@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ return NULL;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Building the Automata}
+
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap173}
+$\langle$Function prototypes {\footnotesize 64e}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void search();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap174}
+\verb@"scraps.c"@ {\footnotesize 65a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void build_gotos();@\\
+\mbox{}\verb@static int reject_match();@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@void search()@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int i;@\\
+\mbox{}\verb@ for (i=0; i<128; i++)@\\
+\mbox{}\verb@ root[i] = NULL;@\\
+\mbox{}\verb@ max_depth = 10;@\\
+\mbox{}\verb@ depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));@\\
+\mbox{}\verb@ for (i=0; i<max_depth; i++)@\\
+\mbox{}\verb@ depths[i] = NULL;@\\
+\mbox{}\verb@ build_gotos(user_names);@\\
+\mbox{}\verb@ @$\langle$Build failure functions {\footnotesize 67}$\rangle$\verb@@\\
+\mbox{}\verb@ @$\langle$Search scraps {\footnotesize 68}$\rangle$\verb@@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap175}
+\verb@"scraps.c"@ {\footnotesize 65b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static void build_gotos(tree)@\\
+\mbox{}\verb@ Name *tree;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ while (tree) {@\\
+\mbox{}\verb@ @$\langle$Extend goto graph with \verb|tree->spelling| {\footnotesize 66}$\rangle$\verb@@\\
+\mbox{}\verb@ build_gotos(tree->rlink);@\\
+\mbox{}\verb@ tree = tree->llink;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap176}
+$\langle$Extend goto graph with \verb|tree->spelling| {\footnotesize 66}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int depth = 2;@\\
+\mbox{}\verb@ char *p = tree->spelling;@\\
+\mbox{}\verb@ char c = *p++;@\\
+\mbox{}\verb@ Goto_Node *q = root[c];@\\
+\mbox{}\verb@ if (!q) {@\\
+\mbox{}\verb@ q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));@\\
+\mbox{}\verb@ root[c] = q;@\\
+\mbox{}\verb@ q->moves = NULL;@\\
+\mbox{}\verb@ q->fail = NULL;@\\
+\mbox{}\verb@ q->moves = NULL;@\\
+\mbox{}\verb@ q->output = NULL;@\\
+\mbox{}\verb@ q->next = depths[1];@\\
+\mbox{}\verb@ depths[1] = q;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ while (c = *p++) {@\\
+\mbox{}\verb@ Goto_Node *new = goto_lookup(c, q);@\\
+\mbox{}\verb@ if (!new) {@\\
+\mbox{}\verb@ Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));@\\
+\mbox{}\verb@ new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));@\\
+\mbox{}\verb@ new->moves = NULL;@\\
+\mbox{}\verb@ new->fail = NULL;@\\
+\mbox{}\verb@ new->moves = NULL;@\\
+\mbox{}\verb@ new->output = NULL;@\\
+\mbox{}\verb@ new_move->state = new;@\\
+\mbox{}\verb@ new_move->c = c;@\\
+\mbox{}\verb@ new_move->next = q->moves;@\\
+\mbox{}\verb@ q->moves = new_move;@\\
+\mbox{}\verb@ if (depth == max_depth) {@\\
+\mbox{}\verb@ int i;@\\
+\mbox{}\verb@ Goto_Node **new_depths =@\\
+\mbox{}\verb@ (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));@\\
+\mbox{}\verb@ max_depth = 2 * depth;@\\
+\mbox{}\verb@ for (i=0; i<depth; i++)@\\
+\mbox{}\verb@ new_depths[i] = depths[i];@\\
+\mbox{}\verb@ depths = new_depths;@\\
+\mbox{}\verb@ for (i=depth; i<max_depth; i++)@\\
+\mbox{}\verb@ depths[i] = NULL;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ new->next = depths[depth];@\\
+\mbox{}\verb@ depths[depth] = new;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ q = new;@\\
+\mbox{}\verb@ depth++;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));@\\
+\mbox{}\verb@ q->output->next = NULL;@\\
+\mbox{}\verb@ q->output->name = tree;@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 65b.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap177}
+$\langle$Build failure functions {\footnotesize 67}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int depth;@\\
+\mbox{}\verb@ for (depth=1; depth<max_depth; depth++) {@\\
+\mbox{}\verb@ Goto_Node *r = depths[depth];@\\
+\mbox{}\verb@ while (r) {@\\
+\mbox{}\verb@ Move_Node *m = r->moves;@\\
+\mbox{}\verb@ while (m) {@\\
+\mbox{}\verb@ char a = m->c;@\\
+\mbox{}\verb@ Goto_Node *s = m->state;@\\
+\mbox{}\verb@ Goto_Node *state = r->fail;@\\
+\mbox{}\verb@ while (state && !goto_lookup(a, state))@\\
+\mbox{}\verb@ state = state->fail;@\\
+\mbox{}\verb@ if (state)@\\
+\mbox{}\verb@ s->fail = goto_lookup(a, state);@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ s->fail = root[a];@\\
+\mbox{}\verb@ if (s->fail) {@\\
+\mbox{}\verb@ Name_Node *p = s->fail->output;@\\
+\mbox{}\verb@ while (p) {@\\
+\mbox{}\verb@ Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));@\\
+\mbox{}\verb@ q->name = p->name;@\\
+\mbox{}\verb@ q->next = s->output;@\\
+\mbox{}\verb@ s->output = q;@\\
+\mbox{}\verb@ p = p->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ m = m->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ r = r->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 65a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Searching the Scraps}
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap178}
+$\langle$Search scraps {\footnotesize 68}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ for (i=1; i<scraps; i++) {@\\
+\mbox{}\verb@ char c;@\\
+\mbox{}\verb@ Manager reader;@\\
+\mbox{}\verb@ Goto_Node *state = NULL;@\\
+\mbox{}\verb@ reader.prev = NULL;@\\
+\mbox{}\verb@ reader.scrap = scrap_array(i).slab;@\\
+\mbox{}\verb@ reader.index = 0;@\\
+\mbox{}\verb@ c = pop(&reader);@\\
+\mbox{}\verb@ while (c) {@\\
+\mbox{}\verb@ while (state && !goto_lookup(c, state))@\\
+\mbox{}\verb@ state = state->fail;@\\
+\mbox{}\verb@ if (state)@\\
+\mbox{}\verb@ state = goto_lookup(c, state);@\\
+\mbox{}\verb@ else@\\
+\mbox{}\verb@ state = root[c];@\\
+\mbox{}\verb@ c = pop(&reader);@\\
+\mbox{}\verb@ if (state && state->output) {@\\
+\mbox{}\verb@ Name_Node *p = state->output;@\\
+\mbox{}\verb@ do {@\\
+\mbox{}\verb@ Name *name = p->name;@\\
+\mbox{}\verb@ if (!reject_match(name, c, &reader) &&@\\
+\mbox{}\verb@ (!name->uses || name->uses->scrap != i)) {@\\
+\mbox{}\verb@ Scrap_Node *new_use =@\\
+\mbox{}\verb@ (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));@\\
+\mbox{}\verb@ new_use->scrap = i;@\\
+\mbox{}\verb@ new_use->next = name->uses;@\\
+\mbox{}\verb@ name->uses = new_use;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ p = p->next;@\\
+\mbox{}\verb@ } while (p);@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 65a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsubsection{Rejecting Matches}
+
+A problem with simple substring matching is that the string ``he''
+would match longer strings like ``she'' and ``her.'' Norman Ramsey
+suggested examining the characters occurring immediately before and
+after a match and rejecting the match if it appears to be part of a
+longer token. Of course, the concept of {\sl token\/} is
+language-dependent, so we may be occasionally mistaken.
+For the present, we'll consider the mechanism an experiment.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap179}
+\verb@"scraps.c"@ {\footnotesize 69a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@#define sym_char(c) (isalnum(c) || (c) == '_')@\\
+\mbox{}\verb@@\\
+\mbox{}\verb@static int op_char(c)@\\
+\mbox{}\verb@ char c;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ switch (c) {@\\
+\mbox{}\verb@ case '!': case '@{\tt @}\verb@': case '#': case '%': case '$': case '^': @\\
+\mbox{}\verb@ case '&': case '*': case '-': case '+': case '=': case '/':@\\
+\mbox{}\verb@ case '|': case '~': case '<': case '>':@\\
+\mbox{}\verb@ return TRUE;@\\
+\mbox{}\verb@ default:@\\
+\mbox{}\verb@ return FALSE;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap180}
+\verb@"scraps.c"@ {\footnotesize 69b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static int reject_match(name, post, reader)@\\
+\mbox{}\verb@ Name *name;@\\
+\mbox{}\verb@ char post;@\\
+\mbox{}\verb@ Manager *reader;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ int len = strlen(name->spelling);@\\
+\mbox{}\verb@ char first = name->spelling[0];@\\
+\mbox{}\verb@ char last = name->spelling[len - 1];@\\
+\mbox{}\verb@ char prev = '\0';@\\
+\mbox{}\verb@ len = reader->index - len - 2;@\\
+\mbox{}\verb@ if (len >= 0)@\\
+\mbox{}\verb@ prev = reader->scrap->chars[len];@\\
+\mbox{}\verb@ else if (reader->prev)@\\
+\mbox{}\verb@ prev = reader->scrap->chars[SLAB_SIZE - len];@\\
+\mbox{}\verb@ if (sym_char(last) && sym_char(post)) return TRUE;@\\
+\mbox{}\verb@ if (sym_char(first) && sym_char(prev)) return TRUE;@\\
+\mbox{}\verb@ if (op_char(last) && op_char(post)) return TRUE;@\\
+\mbox{}\verb@ if (op_char(first) && op_char(prev)) return TRUE;@\\
+\mbox{}\verb@ return FALSE;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\section{Memory Management} \label{memory-management}
+
+I manage memory using a simple scheme inspired by Hanson's idea of
+{\em arenas\/}~\cite{hanson:90}.
+Basically, I allocate all the storage required when processing a
+source file (primarily for names and scraps) using calls to
+\verb|arena_getmem(n)|, where \verb|n| specifies the number of bytes to
+be allocated. When the storage is no longer required, the entire arena
+is freed with a single call to \verb|arena_free()|. Both operations
+are quite fast.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap181}
+$\langle$Function prototypes {\footnotesize 69c}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@extern void *arena_getmem();@\\
+\mbox{}\verb@extern void arena_free();@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro defined by scraps 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c.
+\item Macro referenced in scrap 7a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap182}
+\verb@"arena.c"@ {\footnotesize 70a }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@typedef struct chunk {@\\
+\mbox{}\verb@ struct chunk *next;@\\
+\mbox{}\verb@ char *limit;@\\
+\mbox{}\verb@ char *avail;@\\
+\mbox{}\verb@} Chunk;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9d, 70abc, 71c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+We define an empty chunk called \verb|first|. The variable \verb|arena| points
+at the current chunk of memory; it's initially pointed at \verb|first|.
+As soon as some storage is required, a ``real'' chunk of memory will
+be allocated and attached to \verb|first->next|; storage will be
+allocated from the new chunk (and later chunks if necessary).
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap183}
+\verb@"arena.c"@ {\footnotesize 70b }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@static Chunk first = { NULL, NULL, NULL };@\\
+\mbox{}\verb@static Chunk *arena = &first;@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9d, 70abc, 71c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Allocating Memory}
+
+The routine \verb|arena_getmem(n)| returns a pointer to (at least)
+\verb|n| bytes of memory. Note that \verb|n| is rounded up to ensure
+that returned pointers are always aligned. We align to the nearest
+8~byte segment, since that'll satisfy the more common 2-byte and
+4-byte alignment restrictions too.
+
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap184}
+\verb@"arena.c"@ {\footnotesize 70c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void *arena_getmem(n)@\\
+\mbox{}\verb@ size_t n;@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ char *q;@\\
+\mbox{}\verb@ char *p = arena->avail;@\\
+\mbox{}\verb@ n = (n + 7) & ~7; /* ensuring alignment to 8 bytes */@\\
+\mbox{}\verb@ q = p + n;@\\
+\mbox{}\verb@ if (q <= arena->limit) {@\\
+\mbox{}\verb@ arena->avail = q;@\\
+\mbox{}\verb@ return p;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ @$\langle$Find a new chunk of memory {\footnotesize 71a}$\rangle$\verb@@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9d, 70abc, 71c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+If the current chunk doesn't have adequate space (at least \verb|n|
+bytes) we examine the rest of the list of chunks (starting at
+\verb|arena->next|) looking for a chunk with adequate space. If \verb|n|
+is very large, we may not find it right away or we may not find a
+suitable chunk at all.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap185}
+$\langle$Find a new chunk of memory {\footnotesize 71a}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ Chunk *ap = arena;@\\
+\mbox{}\verb@ Chunk *np = ap->next;@\\
+\mbox{}\verb@ while (np) {@\\
+\mbox{}\verb@ char *v = sizeof(Chunk) + (char *) np;@\\
+\mbox{}\verb@ if (v + n <= np->limit) {@\\
+\mbox{}\verb@ np->avail = v + n;@\\
+\mbox{}\verb@ arena = np;@\\
+\mbox{}\verb@ return v;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ ap = np;@\\
+\mbox{}\verb@ np = ap->next;@\\
+\mbox{}\verb@ }@\\
+\mbox{}\verb@ @$\langle$Allocate a new chunk of memory {\footnotesize 71b}$\rangle$\verb@@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 70c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+If there isn't a suitable chunk of memory on the free list, then we
+need to allocate a new one.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap186}
+$\langle$Allocate a new chunk of memory {\footnotesize 71b}$\rangle\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@{@\\
+\mbox{}\verb@ size_t m = n + 10000;@\\
+\mbox{}\verb@ np = (Chunk *) malloc(m);@\\
+\mbox{}\verb@ np->limit = m + (char *) np;@\\
+\mbox{}\verb@ np->avail = n + sizeof(Chunk) + (char *) np;@\\
+\mbox{}\verb@ np->next = NULL;@\\
+\mbox{}\verb@ ap->next = np;@\\
+\mbox{}\verb@ arena = np;@\\
+\mbox{}\verb@ return sizeof(Chunk) + (char *) np;@\\
+\mbox{}\verb@}@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item Macro referenced in scrap 71a.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\subsection{Freeing Memory}
+
+To free all the memory in the arena, we need only point \verb|arena|
+back to the first empty chunk.
+\begin{flushleft} \small
+\begin{minipage}{\linewidth} \label{scrap187}
+\verb@"arena.c"@ {\footnotesize 71c }$\equiv$
+\vspace{-1ex}
+\begin{list}{}{} \item
+\mbox{}\verb@void arena_free()@\\
+\mbox{}\verb@{@\\
+\mbox{}\verb@ arena = &first;@\\
+\mbox{}\verb@}@\\
+\mbox{}\verb@@$\Diamond$
+\end{list}
+\vspace{-1ex}
+\footnotesize\addtolength{\baselineskip}{-1ex}
+\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item File defined by scraps 9d, 70abc, 71c.
+\end{list}
+\end{minipage}\\[4ex]
+\end{flushleft}
+\chapter{Indices} \label{indices}
+
+Three sets of indices can be created automatically: an index of file
+names, an index of macro names, and an index of user-specified
+identifiers. An index entry includes the name of the entry, where it
+was defined, and where it was referenced.
+
+\section{Files}
+
+
+{\small\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item \verb@"arena.c"@ {\footnotesize Defined by scraps 9d, 70abc, 71c.
+}
+\item \verb@"global.c"@ {\footnotesize Defined by scrap 9e.}
+\item \verb@"global.h"@ {\footnotesize Defined by scrap 7a.}
+\item \verb@"html.c"@ {\footnotesize Defined by scraps 8e, 28ab, 32abc, 33a, 35a, 36c.
+}
+\item \verb@"input.c"@ {\footnotesize Defined by scraps 9a, 39d, 40ab, 42c.
+}
+\item \verb@"latex.c"@ {\footnotesize Defined by scraps 8d, 16d, 17a, 21b, 22a, 24b, 26b.
+}
+\item \verb@"main.c"@ {\footnotesize Defined by scraps 8b, 9f.
+}
+\item \verb@"names.c"@ {\footnotesize Defined by scraps 9c, 54ab, 55a, 56, 57ab, 58b, 60a, 62a, 63ab.
+}
+\item \verb@"output.c"@ {\footnotesize Defined by scraps 8f, 37c.
+}
+\item \verb@"pass1.c"@ {\footnotesize Defined by scraps 8c, 14b.
+}
+\item \verb@"scraps.c"@ {\footnotesize Defined by scraps 9b, 43abce, 44ab, 45bcde, 48bc, 49b, 52a, 63c, 64abcd, 65ab, 69ab.
+}
+\end{list}}
+
+\section{Macros}
+
+
+{\small\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item $\langle$Accumulate scrap and return \verb|scraps++| {\footnotesize 46b}$\rangle$ {\footnotesize Referenced in scrap 45e.}
+\item $\langle$Add \verb|scrap| to \verb|name|'s definition list {\footnotesize 16a}$\rangle$ {\footnotesize Referenced in scraps 15bc.
+}
+\item $\langle$Add current scrap to \verb|name|'s uses {\footnotesize 48a}$\rangle$ {\footnotesize Referenced in scrap 47b.}
+\item $\langle$Add letters to scraps with duplicate page numbers {\footnotesize 52b}$\rangle$ {\footnotesize Referenced in scrap 52a.}
+\item $\langle$Allocate a new chunk of memory {\footnotesize 71b}$\rangle$ {\footnotesize Referenced in scrap 71a.}
+\item $\langle$Begin HTML scrap environment {\footnotesize 30e}$\rangle$ {\footnotesize Referenced in scraps 30ac.
+}
+\item $\langle$Begin the scrap environment {\footnotesize 19c}$\rangle$ {\footnotesize Referenced in scraps 19ab.
+}
+\item $\langle$Build \verb|source_name| and \verb|tex_name| {\footnotesize 12b}$\rangle$ {\footnotesize Referenced in scrap 12a.}
+\item $\langle$Build failure functions {\footnotesize 67}$\rangle$ {\footnotesize Referenced in scrap 65a.}
+\item $\langle$Build macro definition {\footnotesize 15c}$\rangle$ {\footnotesize Referenced in scrap 15a.}
+\item $\langle$Build output file definition {\footnotesize 15b}$\rangle$ {\footnotesize Referenced in scrap 15a.}
+\item $\langle$Check HTML at-sequence for end-of-scrap {\footnotesize 33b}$\rangle$ {\footnotesize Referenced in scrap 33a.}
+\item $\langle$Check at-sequence for end-of-scrap {\footnotesize 22c}$\rangle$ {\footnotesize Referenced in scrap 22a.}
+\item $\langle$Check for ambiguous prefix {\footnotesize 55b}$\rangle$ {\footnotesize Referenced in scrap 55a.}
+\item $\langle$Check for end of scrap name and return {\footnotesize 49a}$\rangle$ {\footnotesize Referenced in scrap 48c.}
+\item $\langle$Check for macro invocation in scrap {\footnotesize 51b}$\rangle$ {\footnotesize Referenced in scrap 50a.}
+\item $\langle$Check for terminating at-sequence and return name {\footnotesize 60b}$\rangle$ {\footnotesize Referenced in scrap 60a.}
+\item $\langle$Cleanup and install name {\footnotesize 61a}$\rangle$ {\footnotesize Referenced in scraps 60b, 61b, 62b.
+}
+\item $\langle$Collect include-file name {\footnotesize 42a}$\rangle$ {\footnotesize Referenced in scrap 41b.}
+\item $\langle$Collect user-specified index entries {\footnotesize 47a}$\rangle$ {\footnotesize Referenced in scrap 46c.}
+\item $\langle$Compare the temp file and the old file {\footnotesize 38b}$\rangle$ {\footnotesize Referenced in scrap 38a.}
+\item $\langle$Copy \verb|defs->scrap| to \verb|file| {\footnotesize 50a}$\rangle$ {\footnotesize Referenced in scrap 49b.}
+\item $\langle$Copy \verb|source_file| into \verb|html_file| {\footnotesize 28c}$\rangle$ {\footnotesize Referenced in scrap 28b.}
+\item $\langle$Copy \verb|source_file| into \verb|tex_file| {\footnotesize 17b}$\rangle$ {\footnotesize Referenced in scrap 17a.}
+\item $\langle$Copy macro into \verb|file| {\footnotesize 51c}$\rangle$ {\footnotesize Referenced in scrap 51b.}
+\item $\langle$Create new name entry {\footnotesize 58a}$\rangle$ {\footnotesize Referenced in scraps 55a, 57b.
+}
+\item $\langle$Create new scrap, managed by \verb|writer| {\footnotesize 46a}$\rangle$ {\footnotesize Referenced in scrap 45e.}
+\item $\langle$Expand tab into spaces {\footnotesize 22b}$\rangle$ {\footnotesize Referenced in scraps 22a, 33a, 51a.
+}
+\item $\langle$Extend goto graph with \verb|tree->spelling| {\footnotesize 66}$\rangle$ {\footnotesize Referenced in scrap 65b.}
+\item $\langle$Fill in the middle of HTML scrap environment {\footnotesize 31a}$\rangle$ {\footnotesize Referenced in scraps 30ac.
+}
+\item $\langle$Fill in the middle of the scrap environment {\footnotesize 19d}$\rangle$ {\footnotesize Referenced in scraps 19ab.
+}
+\item $\langle$Find a new chunk of memory {\footnotesize 71a}$\rangle$ {\footnotesize Referenced in scrap 70c.}
+\item $\langle$Finish HTML scrap environment {\footnotesize 31b}$\rangle$ {\footnotesize Referenced in scraps 30ac.
+}
+\item $\langle$Finish the scrap environment {\footnotesize 20a}$\rangle$ {\footnotesize Referenced in scraps 19ab.
+}
+\item $\langle$Format HTML macro name {\footnotesize 34a}$\rangle$ {\footnotesize Referenced in scrap 33b.}
+\item $\langle$Format a user HTML index entry {\footnotesize 37a}$\rangle$ {\footnotesize Referenced in scrap 36c.}
+\item $\langle$Format a user index entry {\footnotesize 27a}$\rangle$ {\footnotesize Referenced in scrap 26b.}
+\item $\langle$Format an HTML index entry {\footnotesize 35b}$\rangle$ {\footnotesize Referenced in scrap 35a.}
+\item $\langle$Format an index entry {\footnotesize 24c}$\rangle$ {\footnotesize Referenced in scrap 24b.}
+\item $\langle$Format macro name {\footnotesize 23b}$\rangle$ {\footnotesize Referenced in scrap 22c.}
+\item $\langle$Function prototypes {\footnotesize 14a, 16c, 27b, 37b, 39a, 43d, 51d, 53d, 64e, 69c}$\rangle$ {\footnotesize Referenced in scrap 7a.}
+\item $\langle$Global variable declarations {\footnotesize 10ac, 39b, 44d, 53b}$\rangle$ {\footnotesize Referenced in scrap 7a.}
+\item $\langle$Global variable definitions {\footnotesize 10bd, 39c, 45a, 53c}$\rangle$ {\footnotesize Referenced in scrap 9e.}
+\item $\langle$Handle \verb|EOF| {\footnotesize 42b}$\rangle$ {\footnotesize Referenced in scrap 40b.}
+\item $\langle$Handle an ``at'' character {\footnotesize 41a}$\rangle$ {\footnotesize Referenced in scrap 40b.}
+\item $\langle$Handle at-sign during scrap accumulation {\footnotesize 46c}$\rangle$ {\footnotesize Referenced in scrap 46b.}
+\item $\langle$Handle macro invocation in scrap {\footnotesize 47b}$\rangle$ {\footnotesize Referenced in scrap 46c.}
+\item $\langle$Handle optional per-file flags {\footnotesize 59}$\rangle$ {\footnotesize Referenced in scrap 58b.}
+\item $\langle$Handle tab characters on output {\footnotesize 51a}$\rangle$ {\footnotesize Referenced in scrap 50a.}
+\item $\langle$Handle the file name in \verb|argv[arg]| {\footnotesize 12a}$\rangle$ {\footnotesize Referenced in scrap 11c.}
+\item $\langle$Include files {\footnotesize 7b}$\rangle$ {\footnotesize Referenced in scrap 7a.}
+\item $\langle$Insert appropriate indentation {\footnotesize 50c}$\rangle$ {\footnotesize Referenced in scraps 50ab.
+}
+\item $\langle$Insert debugging information if required {\footnotesize 50b}$\rangle$ {\footnotesize Referenced in scraps 50a, 51b.
+}
+\item $\langle$Interpret HTML at-sequence {\footnotesize 29}$\rangle$ {\footnotesize Referenced in scrap 28c.}
+\item $\langle$Interpret at-sequence {\footnotesize 18}$\rangle$ {\footnotesize Referenced in scrap 17b.}
+\item $\langle$Interpret command-line arguments {\footnotesize 10e, 11a}$\rangle$ {\footnotesize Referenced in scrap 9f.}
+\item $\langle$Interpret the argument string \verb|s| {\footnotesize 11b}$\rangle$ {\footnotesize Referenced in scrap 11a.}
+\item $\langle$Look for end of scrap name and return {\footnotesize 62b}$\rangle$ {\footnotesize Referenced in scrap 62a.}
+\item $\langle$Open an include file {\footnotesize 41b}$\rangle$ {\footnotesize Referenced in scrap 41a.}
+\item $\langle$Process a file {\footnotesize 13}$\rangle$ {\footnotesize Referenced in scrap 12a.}
+\item $\langle$Process the remaining arguments (file names) {\footnotesize 11c}$\rangle$ {\footnotesize Referenced in scrap 9f.}
+\item $\langle$Reverse cross-reference lists {\footnotesize 16b}$\rangle$ {\footnotesize Referenced in scrap 14b.}
+\item $\langle$Save macro name {\footnotesize 47c}$\rangle$ {\footnotesize Referenced in scrap 47b.}
+\item $\langle$Scan at-sequence {\footnotesize 15a}$\rangle$ {\footnotesize Referenced in scrap 14c.}
+\item $\langle$Scan the source file, looking for at-sequences {\footnotesize 14c}$\rangle$ {\footnotesize Referenced in scrap 14b.}
+\item $\langle$Search scraps {\footnotesize 68}$\rangle$ {\footnotesize Referenced in scrap 65a.}
+\item $\langle$Skip over index entries {\footnotesize 23a}$\rangle$ {\footnotesize Referenced in scraps 22c, 33b.
+}
+\item $\langle$Skip until scrap begins, then return name {\footnotesize 61b}$\rangle$ {\footnotesize Referenced in scrap 60a.}
+\item $\langle$Type declarations {\footnotesize 8a, 52c, 53a}$\rangle$ {\footnotesize Referenced in scrap 7a.}
+\item $\langle$Warn (only once) about needing to rerun after Latex {\footnotesize 44c}$\rangle$ {\footnotesize Referenced in scraps 44a, 52a.
+}
+\item $\langle$Write HTML abbreviated definition list {\footnotesize 34b}$\rangle$ {\footnotesize Referenced in scrap 34a.}
+\item $\langle$Write HTML defining scrap numbers {\footnotesize 35d}$\rangle$ {\footnotesize Referenced in scrap 35b.}
+\item $\langle$Write HTML file defs {\footnotesize 31c}$\rangle$ {\footnotesize Referenced in scrap 30a.}
+\item $\langle$Write HTML file's defining scrap numbers {\footnotesize 35c}$\rangle$ {\footnotesize Referenced in scrap 35b.}
+\item $\langle$Write HTML index of file names {\footnotesize 34c}$\rangle$ {\footnotesize Referenced in scrap 29.}
+\item $\langle$Write HTML index of macro names {\footnotesize 34d}$\rangle$ {\footnotesize Referenced in scrap 29.}
+\item $\langle$Write HTML index of user-specified names {\footnotesize 36b}$\rangle$ {\footnotesize Referenced in scrap 29.}
+\item $\langle$Write HTML macro declaration {\footnotesize 30d}$\rangle$ {\footnotesize Referenced in scrap 30c.}
+\item $\langle$Write HTML macro definition {\footnotesize 30c}$\rangle$ {\footnotesize Referenced in scrap 29.}
+\item $\langle$Write HTML macro defs {\footnotesize 31d}$\rangle$ {\footnotesize Referenced in scrap 30c.}
+\item $\langle$Write HTML macro refs {\footnotesize 31e}$\rangle$ {\footnotesize Referenced in scrap 30c.}
+\item $\langle$Write HTML output file declaration {\footnotesize 30b}$\rangle$ {\footnotesize Referenced in scrap 30a.}
+\item $\langle$Write HTML output file definition {\footnotesize 30a}$\rangle$ {\footnotesize Referenced in scrap 29.}
+\item $\langle$Write HTML referencing scrap numbers {\footnotesize 36a}$\rangle$ {\footnotesize Referenced in scrap 35b.}
+\item $\langle$Write abbreviated definition list {\footnotesize 23c}$\rangle$ {\footnotesize Referenced in scrap 23b.}
+\item $\langle$Write defining scrap numbers {\footnotesize 25b}$\rangle$ {\footnotesize Referenced in scrap 24c.}
+\item $\langle$Write file defs {\footnotesize 20b}$\rangle$ {\footnotesize Referenced in scrap 19a.}
+\item $\langle$Write file's defining scrap numbers {\footnotesize 25a}$\rangle$ {\footnotesize Referenced in scrap 24c.}
+\item $\langle$Write index of file names {\footnotesize 23d}$\rangle$ {\footnotesize Referenced in scrap 18.}
+\item $\langle$Write index of macro names {\footnotesize 24a}$\rangle$ {\footnotesize Referenced in scrap 18.}
+\item $\langle$Write index of user-specified names {\footnotesize 26a}$\rangle$ {\footnotesize Referenced in scrap 18.}
+\item $\langle$Write macro definition {\footnotesize 19b}$\rangle$ {\footnotesize Referenced in scrap 18.}
+\item $\langle$Write macro defs {\footnotesize 20c}$\rangle$ {\footnotesize Referenced in scrap 19b.}
+\item $\langle$Write macro refs {\footnotesize 21a}$\rangle$ {\footnotesize Referenced in scrap 19b.}
+\item $\langle$Write out \verb|files->spelling| {\footnotesize 38a}$\rangle$ {\footnotesize Referenced in scrap 37c.}
+\item $\langle$Write output file definition {\footnotesize 19a}$\rangle$ {\footnotesize Referenced in scrap 18.}
+\item $\langle$Write referencing scrap numbers {\footnotesize 25c}$\rangle$ {\footnotesize Referenced in scrap 24c.}
+\end{list}}
+
+\section{Identifiers}
+
+Knuth prints his index of identifiers in a two-column format.
+I could force this automatically by emitting the \verb|\twocolumn|
+command; but this has the side effect of forcing a new page.
+Therefore, it seems better to leave it this up to the user.
+
+
+{\small\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
+\item \verb@already_warned@: 44c, \underline{44d}, 45a, 52a.
+\item \verb@arena@: \underline{70b}, 70c, 71abc.
+\item \verb@arena_free@: 13, 69c, \underline{71c}.
+\item \verb@arena_getmem@: 16a, 43e, 45c, 46a, 47a, 48a, 54b, 58a, 65a, 66, 67, 68, 69c, \underline{70c}.
+\item \verb@build_gotos@: 65a, \underline{65b}.
+\item \verb@Chunk@: \underline{70a}, 70b, 71ab.
+\item \verb@collect_file_name@: 15b, 19a, 30a, 53d, \underline{58b}.
+\item \verb@collect_macro_name@: 15c, 19b, 30c, 53d, \underline{60a}.
+\item \verb@collect_numbers@: 13, 51d, \underline{52a}.
+\item \verb@collect_scrap@: 15bc, 43d, \underline{45e}.
+\item \verb@collect_scrap_name@: 23b, 34a, 47b, 53d, \underline{62a}.
+\item \verb@command_name@: \underline{10c}, 10de, 11bc, 15a, 17a, 21a, 23b, 28b, 31e, 34a, 38a, 41ab, 42ac, 44c, 46bc, 47a, 49a, 51c, 55b, 58b, 59, 60ab, 61ab, 62ab.
+\item \verb@compare@: \underline{54a}, 55a, 56.
+\item \verb@compare_flag@: \underline{10a}, 10b, 11b, 38a.
+\item \verb@copy_scrap@: 16d, 19d, \underline{22a}, 28a, 31a, \underline{33a}.
+\item \verb@depths@: \underline{64c}, 65a, 66, 67.
+\item \verb@display_scrap_numbers@: 28a, \underline{32b}, 32c, 35d.
+\item \verb@display_scrap_ref@: 28a, \underline{32a}, 32b, 34b, 37a.
+\item \verb@double_at@: \underline{39d}, 41a, 42c.
+\item \verb@EQUAL@: \underline{54a}, 55a, 56.
+\item \verb@exit@: \underline{7b}, 9f, 11c, 38a, 41ab, 42ac, 46bc, 47a, 49a, 51c, 58b, 60ab, 61ab, 62ab.
+\item \verb@EXTENSION@: \underline{54a}, 55a, 56.
+\item \verb@FALSE@: \underline{8a}, 10ab, 11b, 18, 21b, 24a, 25b, 27a, 34d, 41a, 42c, 51c, 52a, 56, 58a, 59, 69ab.
+\item \verb@fclose@: \underline{7b}, 17a, 28b, 38ab, 42b, 52a.
+\item \verb@FILE@: \underline{7b}, 17a, 21b, 22a, 24b, 26b, 28b, 32abc, 33a, 35a, 36c, 38ab, 39d, 40a, 44ab, 49b, 52a.
+\item \verb@file_names@: 13, 14b, 16b, 23d, 34c, \underline{53b}, 53c, 58b.
+\item \verb@first@: 44a, 69b, \underline{70b}, 71c.
+\item \verb@fopen@: \underline{7b}, 17a, 28b, 38ab, 41b, 42c, 52a.
+\item \verb@format_entry@: 16d, 23d, 24a, \underline{24b}, 28a, 34cd, \underline{35a}.
+\item \verb@format_user_entry@: 16d, 26a, \underline{26b}, 28a, 36b, \underline{36c}.
+\item \verb@fprintf@: \underline{7b}, 11bc, 14b, 15a, 17a, 19abc, 21a, 23b, 24c, 27a, 28b, 30bd, 31e, 34a, 35b, 37a, 38a, 41ab, 42ac, 44ac, 46bc, 47a, 49a, 50b, 51c, 55b, 58b, 59, 60ab, 61ab, 62ab.
+\item \verb@fputs@: \underline{7b}, 19abcd, 20abc, 21ab, 22ac, 23bcd, 24ac, 25ac, 26a, 27a, 30bde, 31abcde, 32abc, 33a, 34abcd, 35bc, 36ab, 37a, 44a.
+\item \verb@getc@: \underline{7b}, 38b, 40b, 41ab, 42abc.
+\item \verb@goto_lookup@: \underline{64d}, 66, 67, 68.
+\item \verb@Goto_Node@: \underline{64a}, 64bcd, 65a, 66, 67, 68.
+\item \verb@GREATER@: \underline{54a}, 55a, 56.
+\item \verb@html_flag@: \underline{10a}, 10b, 12b, 13.
+\item \verb@include_depth@: \underline{39d}, 41b, 42bc.
+\item \verb@init_scraps@: 14b, 43d, \underline{43e}.
+\item \verb@isgraph@: \underline{7b}, 42a, 58b, 62a.
+\item \verb@islower@: \underline{7b}, 57a.
+\item \verb@isspace@: \underline{7b}, 20a, 47a, 58b, 59, 60a, 61b.
+\item \verb@isupper@: \underline{7b}, 57a.
+\item \verb@LESS@: \underline{54a}, 55a, 56.
+\item \verb@macro_names@: 14b, 16b, 24a, 34d, 49a, \underline{53b}, 53c, 61a.
+\item \verb@main@: \underline{9f}.
+\item \verb@malloc@: \underline{7b}, 71b.
+\item \verb@Manager@: \underline{45b}, 45cde, 48bc, 50a, 68, 69b.
+\item \verb@max_depth@: \underline{64c}, 65a, 66, 67.
+\item \verb@Move_Node@: \underline{64b}, 64d, 66, 67.
+\item \verb@Name@: 15bc, 19ab, 23b, 24b, 26b, 30ac, 34a, 35a, 36c, 37c, 47ab, 48c, 51c, \underline{53a}, 53bcd, 55a, 56, 57b, 58ab, 60a, 62a, 63ac, 65b, 68, 69b.
+\item \verb@name_add@: 47a, 53d, \underline{57b}, 58b.
+\item \verb@Name_Node@: \underline{63c}, 64a, 66, 67, 68.
+\item \verb@number_flag@: \underline{10a}, 10b, 11b, 13, 52a.
+\item \verb@op_char@: \underline{69a}, 69b.
+\item \verb@output_flag@: \underline{10a}, 10b, 11b, 13.
+\item \verb@pass1@: 13, 14a, \underline{14b}, 22c, 33b.
+\item \verb@pop@: \underline{48b}, 48c, 49a, 50a, 51b, 68.
+\item \verb@pop_scrap_name@: \underline{48c}, 51c.
+\item \verb@PREFIX@: \underline{54a}, 55a, 56.
+\item \verb@prefix_add@: 49a, 53d, \underline{55a}, 61a.
+\item \verb@print_scrap_numbers@: 16d, 20bc, 21a, \underline{21b}, 25ac, 28a, 31cde, \underline{32c}, 35c, 36a.
+\item \verb@push@: \underline{45c}, 45d, 46bc, 47c.
+\item \verb@pushs@: \underline{45d}, 46c, 47c.
+\item \verb@putc@: \underline{7b}, 17b, 18, 22abc, 23b, 24c, 25abc, 27a, 28c, 29, 33a, 34a, 35bd, 44a, 50ac, 51ab.
+\item \verb@reject_match@: 65a, 68, \underline{69b}.
+\item \verb@remove@: \underline{7b}, 38ab.
+\item \verb@reverse@: 63a, \underline{63b}.
+\item \verb@reverse_lists@: 16b, 53d, \underline{63a}.
+\item \verb@robs_strcmp@: \underline{57a}, 57b.
+\item \verb@root@: 55a, 57b, 58a, \underline{64c}, 65a, 66, 67, 68.
+\item \verb@save_string@: 41b, 46a, 53d, \underline{54b}, 55a, 58a.
+\item \verb@SCRAP@: \underline{43c}, 43e, 46a.
+\item \verb@ScrapEntry@: \underline{43b}, 43ce, 46a.
+\item \verb@scraps@: 10a, 17b, 19abc, 20bc, 21ab, 28c, 30abcd, 32bc, \underline{43c}, 43e, 45e, 46abc, 47a, 48a, 52ab, 65a, 68.
+\item \verb@scrap_array@: \underline{43c}, 44a, 46ab, 50ab, 52ab, 68.
+\item \verb@Scrap_Node@: 16a, 21b, 23c, 25abc, 27a, 32bc, 34b, 36a, 37a, 47a, 48a, 49b, \underline{52c}, 53a, 63ab, 68.
+\item \verb@search@: 14b, 64e, \underline{65a}.
+\item \verb@size_t@: \underline{7b}, 70c, 71b.
+\item \verb@Slab@: \underline{43a}, 43b, 45bc, 46a, 48b.
+\item \verb@SLAB_SIZE@: \underline{43a}, 45c, 48b, 69b.
+\item \verb@source_file@: 17a, 28b, \underline{39d}, 40b, 41ab, 42abc.
+\item \verb@source_get@: 14c, 15a, 17b, 18, 20a, 22ac, 23ad, 24a, 26a, 28c, 29, 31b, 33ab, 34cd, 36b, 39a, \underline{40b}, 41b, 42b, 46bc, 47ab, 58b, 59, 60ab, 61b, 62ab.
+\item \verb@source_line@: 15a, \underline{39b}, 39c, 40b, 41ab, 42abc, 46ac, 47a, 55b, 58b, 59, 60a, 61a, 62ab.
+\item \verb@source_name@: 12ab, 13, 15a, \underline{39b}, 39c, 41ab, 42abc, 46ac, 47a, 55b, 58b, 59, 60ab, 61ab, 62ab.
+\item \verb@source_open@: 14b, 17a, 28b, 39a, \underline{42c}.
+\item \verb@source_peek@: \underline{39d}, 40b, 41ab, 42bc.
+\item \verb@stack@: \underline{40a}, 41b, 42b.
+\item \verb@stderr@: \underline{7b}, 11bc, 14b, 15a, 17a, 21a, 23b, 28b, 31e, 34a, 38a, 41ab, 42ac, 44c, 46bc, 47a, 49a, 51c, 55b, 58b, 59, 60ab, 61ab, 62ab.
+\item \verb@strlen@: \underline{7b}, 47c, 54ab, 69b.
+\item \verb@sym_char@: \underline{69a}, 69b.
+\item \verb@tempnam@: \underline{7b}, 38a.
+\item \verb@tex_flag@: \underline{10a}, 10b, 11b, 13, 14b, 51c.
+\item \verb@toupper@: \underline{7b}, 57a.
+\item \verb@TRUE@: \underline{8a}, 10ab, 11b, 13, 18, 21b, 23d, 25b, 27a, 34c, 41a, 44bc, 48c, 51c, 56, 58a, 59, 69ab.
+\item \verb@user_names@: 14b, 16b, 26a, 36b, 47a, \underline{53b}, 53c, 65a.
+\item \verb@verbose_flag@: \underline{10a}, 10b, 11b, 14b, 17a, 28b, 38a.
+\item \verb@write_files@: 13, 37b, \underline{37c}.
+\item \verb@write_html@: 13, 27b, \underline{28b}.
+\item \verb@write_scraps@: 38a, 43d, \underline{49b}, 51c.
+\item \verb@write_scrap_ref@: 21b, 25b, 27a, 43d, \underline{44a}, 44b.
+\item \verb@write_single_scrap_ref@: 19ab, 21a, 23c, 25ac, 27a, 30bd, 32a, 43d, \underline{44b}.
+\item \verb@write_tex@: 13, 16c, \underline{17a}.
+\end{list}}
+
+\fi
+
+\bibliographystyle{plain}
+\bibliography{literate}
+
+\end{document}
diff --git a/web/nuweb/nuweb0.87b/output.c b/web/nuweb/nuweb0.87b/output.c
new file mode 100644
index 0000000000..7277fe7104
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/output.c
@@ -0,0 +1,51 @@
+#include "global.h"
+void write_files(files)
+ Name *files;
+{
+ while (files) {
+ write_files(files->llink);
+ {
+ char indent_chars[500];
+ FILE *temp_file;
+ char *temp_name = tempnam(".", 0);
+ temp_file = fopen(temp_name, "w");
+ if (!temp_file) {
+ fprintf(stderr, "%s: can't create %s for a temporary file\n",
+ command_name, temp_name);
+ exit(-1);
+ }
+ if (verbose_flag)
+ fprintf(stderr, "writing %s\n", files->spelling);
+ write_scraps(temp_file, files->defs, 0, indent_chars,
+ files->debug_flag, files->tab_flag, files->indent_flag);
+ fclose(temp_file);
+ if (compare_flag)
+ {
+ FILE *old_file = fopen(files->spelling, "r");
+ if (old_file) {
+ int x, y;
+ temp_file = fopen(temp_name, "r");
+ do {
+ x = getc(old_file);
+ y = getc(temp_file);
+ } while (x == y && x != EOF);
+ fclose(old_file);
+ fclose(temp_file);
+ if (x == y)
+ remove(temp_name);
+ else {
+ remove(files->spelling);
+ rename(temp_name, files->spelling);
+ }
+ }
+ else
+ rename(temp_name, files->spelling);
+ }
+ else {
+ remove(files->spelling);
+ rename(temp_name, files->spelling);
+ }
+ }
+ files = files->rlink;
+ }
+}
diff --git a/web/nuweb/nuweb0.87b/pass1.c b/web/nuweb/nuweb0.87b/pass1.c
new file mode 100644
index 0000000000..0d9d140f75
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/pass1.c
@@ -0,0 +1,64 @@
+#include "global.h"
+void pass1(file_name)
+ char *file_name;
+{
+ if (verbose_flag)
+ fprintf(stderr, "reading %s\n", file_name);
+ source_open(file_name);
+ init_scraps();
+ macro_names = NULL;
+ file_names = NULL;
+ user_names = NULL;
+ {
+ int c = source_get();
+ while (c != EOF) {
+ if (c == '@')
+ {
+ c = source_get();
+ switch (c) {
+ case 'O':
+ case 'o': {
+ Name *name = collect_file_name(); /* returns a pointer to the name entry */
+ int scrap = collect_scrap(); /* returns an index to the scrap */
+ {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scrap;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ break;
+ case 'D':
+ case 'd': {
+ Name *name = collect_macro_name();
+ int scrap = collect_scrap();
+ {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scrap;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ break;
+ case '@':
+ case 'u':
+ case 'm':
+ case 'f': /* ignore during this pass */
+ break;
+ default: fprintf(stderr,
+ "%s: unexpected @ sequence ignored (%s, line %d)\n",
+ command_name, source_name, source_line);
+ break;
+ }
+ }
+ c = source_get();
+ }
+ }
+ if (tex_flag)
+ search();
+ {
+ reverse_lists(file_names);
+ reverse_lists(macro_names);
+ reverse_lists(user_names);
+ }
+}
diff --git a/web/nuweb/nuweb0.87b/scraps.c b/web/nuweb/nuweb0.87b/scraps.c
new file mode 100644
index 0000000000..dfa94db636
--- /dev/null
+++ b/web/nuweb/nuweb0.87b/scraps.c
@@ -0,0 +1,607 @@
+#include "global.h"
+#define SLAB_SIZE 500
+
+typedef struct slab {
+ struct slab *next;
+ char chars[SLAB_SIZE];
+} Slab;
+typedef struct {
+ char *file_name;
+ int file_line;
+ int page;
+ char letter;
+ Slab *slab;
+} ScrapEntry;
+static ScrapEntry *SCRAP[256];
+
+#define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
+
+static int scraps;
+void init_scraps()
+{
+ scraps = 1;
+ SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+}
+void write_scrap_ref(file, num, first, page)
+ FILE *file;
+ int num;
+ int first;
+ int *page;
+{
+ if (scrap_array(num).page >= 0) {
+ if (first)
+ fprintf(file, "%d", scrap_array(num).page);
+ else if (scrap_array(num).page != *page)
+ fprintf(file, ", %d", scrap_array(num).page);
+ if (scrap_array(num).letter > 0)
+ fputc(scrap_array(num).letter, file);
+ }
+ else {
+ if (first)
+ putc('?', file);
+ else
+ fputs(", ?", file);
+ {
+ if (!already_warned) {
+ fprintf(stderr, "%s: you'll need to rerun nuweb after running latex\n",
+ command_name);
+ already_warned = TRUE;
+ }
+ }
+ }
+ *page = scrap_array(num).page;
+}
+void write_single_scrap_ref(file, num)
+ FILE *file;
+ int num;
+{
+ int page;
+ write_scrap_ref(file, num, TRUE, &page);
+}
+typedef struct {
+ Slab *scrap;
+ Slab *prev;
+ int index;
+} Manager;
+static void push(c, manager)
+ char c;
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ scrap->chars[index++] = c;
+ if (index == SLAB_SIZE) {
+ Slab *new = (Slab *) arena_getmem(sizeof(Slab));
+ scrap->next = new;
+ manager->scrap = new;
+ index = 0;
+ }
+ manager->index = index;
+}
+static void pushs(s, manager)
+ char *s;
+ Manager *manager;
+{
+ while (*s)
+ push(*s++, manager);
+}
+int collect_scrap()
+{
+ Manager writer;
+ {
+ Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
+ if ((scraps & 255) == 0)
+ SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+ scrap_array(scraps).slab = scrap;
+ scrap_array(scraps).file_name = save_string(source_name);
+ scrap_array(scraps).file_line = source_line;
+ scrap_array(scraps).page = -1;
+ scrap_array(scraps).letter = 0;
+ writer.scrap = scrap;
+ writer.index = 0;
+ }
+ {
+ int c = source_get();
+ while (1) {
+ switch (c) {
+ case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
+ command_name, scrap_array(scraps).file_name,
+ scrap_array(scraps).file_line);
+ exit(-1);
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': pushs("@@", &writer);
+ c = source_get();
+ break;
+ case '|': {
+ do {
+ char new_name[100];
+ char *p = new_name;
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c != '@') {
+ Name *name;
+ do {
+ *p++ = c;
+ c = source_get();
+ } while (c != '@' && !isspace(c));
+ *p = '\0';
+ name = name_add(&user_names, new_name);
+ if (!name->defs || name->defs->scrap != scraps) {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scraps;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ } while (c != '@');
+ c = source_get();
+ if (c != '}') {
+ fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+ }
+ case '}': push('\0', &writer);
+ return scraps++;
+ case '<': {
+ Name *name = collect_scrap_name();
+ {
+ char *s = name->spelling;
+ int len = strlen(s) - 1;
+ pushs("@<", &writer);
+ while (len > 0) {
+ push(*s++, &writer);
+ len--;
+ }
+ if (*s == ' ')
+ pushs("...", &writer);
+ else
+ push(*s, &writer);
+ pushs("@>", &writer);
+ }
+ {
+ if (!name->uses || name->uses->scrap != scraps) {
+ Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ use->scrap = scraps;
+ use->next = name->uses;
+ name->uses = use;
+ }
+ }
+ c = source_get();
+ }
+ break;
+ default : fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+ }
+ break;
+ default: push(c, &writer);
+ c = source_get();
+ break;
+ }
+ }
+ }
+}
+static char pop(manager)
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ char c = scrap->chars[index++];
+ if (index == SLAB_SIZE) {
+ manager->prev = scrap;
+ manager->scrap = scrap->next;
+ index = 0;
+ }
+ manager->index = index;
+ return c;
+}
+static Name *pop_scrap_name(manager)
+ Manager *manager;
+{
+ char name[100];
+ char *p = name;
+ int c = pop(manager);
+ while (TRUE) {
+ if (c == '@')
+ {
+ c = pop(manager);
+ if (c == '@') {
+ *p++ = c;
+ c = pop(manager);
+ }
+ else if (c == '>') {
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ else {
+ fprintf(stderr, "%s: found an internal problem (1)\n", command_name);
+ exit(-1);
+ }
+ }
+ else {
+ *p++ = c;
+ c = pop(manager);
+ }
+ }
+}
+int write_scraps(file, defs, global_indent, indent_chars,
+ debug_flag, tab_flag, indent_flag)
+ FILE *file;
+ Scrap_Node *defs;
+ int global_indent;
+ char *indent_chars;
+ char debug_flag;
+ char tab_flag;
+ char indent_flag;
+{
+ int indent = 0;
+ while (defs) {
+ {
+ char c;
+ Manager reader;
+ int line_number = scrap_array(defs->scrap).file_line;
+ if (debug_flag) {
+ fprintf(file, "\n#line %d \"%s\"\n",
+ line_number, scrap_array(defs->scrap).file_name);
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ }
+ reader.scrap = scrap_array(defs->scrap).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ switch (c) {
+ case '@': {
+ c = pop(&reader);
+ switch (c) {
+ case '@': putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ case '<': {
+ Name *name = pop_scrap_name(&reader);
+ if (name->mark) {
+ fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
+ command_name, name->spelling);
+ exit(-1);
+ }
+ if (name->defs) {
+ name->mark = TRUE;
+ indent = write_scraps(file, name->defs, global_indent + indent,
+ indent_chars, debug_flag, tab_flag, indent_flag);
+ indent -= global_indent;
+ name->mark = FALSE;
+ }
+ else if (!tex_flag)
+ fprintf(stderr, "%s: macro never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ if (debug_flag) {
+ fprintf(file, "\n#line %d \"%s\"\n",
+ line_number, scrap_array(defs->scrap).file_name);
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ }
+ break;
+ default: /* ignore, since we should already have a warning */
+ break;
+ }
+ }
+ break;
+ case '\n': putc(c, file);
+ line_number++;
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ break;
+ case '\t': {
+ if (tab_flag)
+ {
+ int delta = 8 - (indent % 8);
+ indent += delta;
+ while (delta > 0) {
+ putc(' ', file);
+ delta--;
+ }
+ }
+ else {
+ putc('\t', file);
+ indent_chars[global_indent + indent] = '\t';
+ indent++;
+ }
+ }
+ break;
+ default: putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ }
+ c = pop(&reader);
+ }
+ }
+ defs = defs->next;
+ }
+ return indent + global_indent;
+}
+void collect_numbers(aux_name)
+ char *aux_name;
+{
+ if (number_flag) {
+ int i;
+ for (i=1; i<scraps; i++)
+ scrap_array(i).page = i;
+ }
+ else {
+ FILE *aux_file = fopen(aux_name, "r");
+ already_warned = FALSE;
+ if (aux_file) {
+ char aux_line[500];
+ while (fgets(aux_line, 500, aux_file)) {
+ int scrap_number;
+ int page_number;
+ char dummy[50];
+ if (3 == sscanf(aux_line, "\\newlabel{scrap%d}{%[^}]}{%d}",
+ &scrap_number, dummy, &page_number)) {
+ if (scrap_number < scraps)
+ scrap_array(scrap_number).page = page_number;
+ else
+ {
+ if (!already_warned) {
+ fprintf(stderr, "%s: you'll need to rerun nuweb after running latex\n",
+ command_name);
+ already_warned = TRUE;
+ }
+ }
+ }
+ }
+ fclose(aux_file);
+ {
+ int scrap;
+ for (scrap=2; scrap<scraps; scrap++) {
+ if (scrap_array(scrap-1).page == scrap_array(scrap).page) {
+ if (!scrap_array(scrap-1).letter)
+ scrap_array(scrap-1).letter = 'a';
+ scrap_array(scrap).letter = scrap_array(scrap-1).letter + 1;
+ }
+ }
+ }
+ }
+ }
+}
+typedef struct name_node {
+ struct name_node *next;
+ Name *name;
+} Name_Node;
+typedef struct goto_node {
+ Name_Node *output; /* list of words ending in this state */
+ struct move_node *moves; /* list of possible moves */
+ struct goto_node *fail; /* and where to go when no move fits */
+ struct goto_node *next; /* next goto node with same depth */
+} Goto_Node;
+typedef struct move_node {
+ struct move_node *next;
+ Goto_Node *state;
+ char c;
+} Move_Node;
+static Goto_Node *root[128];
+static int max_depth;
+static Goto_Node **depths;
+static Goto_Node *goto_lookup(c, g)
+ char c;
+ Goto_Node *g;
+{
+ Move_Node *m = g->moves;
+ while (m && m->c != c)
+ m = m->next;
+ if (m)
+ return m->state;
+ else
+ return NULL;
+}
+static void build_gotos();
+static int reject_match();
+
+void search()
+{
+ int i;
+ for (i=0; i<128; i++)
+ root[i] = NULL;
+ max_depth = 10;
+ depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
+ for (i=0; i<max_depth; i++)
+ depths[i] = NULL;
+ build_gotos(user_names);
+ {
+ int depth;
+ for (depth=1; depth<max_depth; depth++) {
+ Goto_Node *r = depths[depth];
+ while (r) {
+ Move_Node *m = r->moves;
+ while (m) {
+ char a = m->c;
+ Goto_Node *s = m->state;
+ Goto_Node *state = r->fail;
+ while (state && !goto_lookup(a, state))
+ state = state->fail;
+ if (state)
+ s->fail = goto_lookup(a, state);
+ else
+ s->fail = root[a];
+ if (s->fail) {
+ Name_Node *p = s->fail->output;
+ while (p) {
+ Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->name = p->name;
+ q->next = s->output;
+ s->output = q;
+ p = p->next;
+ }
+ }
+ m = m->next;
+ }
+ r = r->next;
+ }
+ }
+ }
+ {
+ for (i=1; i<scraps; i++) {
+ char c;
+ Manager reader;
+ Goto_Node *state = NULL;
+ reader.prev = NULL;
+ reader.scrap = scrap_array(i).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ while (state && !goto_lookup(c, state))
+ state = state->fail;
+ if (state)
+ state = goto_lookup(c, state);
+ else
+ state = root[c];
+ c = pop(&reader);
+ if (state && state->output) {
+ Name_Node *p = state->output;
+ do {
+ Name *name = p->name;
+ if (!reject_match(name, c, &reader) &&
+ (!name->uses || name->uses->scrap != i)) {
+ Scrap_Node *new_use =
+ (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ new_use->scrap = i;
+ new_use->next = name->uses;
+ name->uses = new_use;
+ }
+ p = p->next;
+ } while (p);
+ }
+ }
+ }
+ }
+}
+static void build_gotos(tree)
+ Name *tree;
+{
+ while (tree) {
+ {
+ int depth = 2;
+ char *p = tree->spelling;
+ char c = *p++;
+ Goto_Node *q = root[c];
+ if (!q) {
+ q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ root[c] = q;
+ q->moves = NULL;
+ q->fail = NULL;
+ q->moves = NULL;
+ q->output = NULL;
+ q->next = depths[1];
+ depths[1] = q;
+ }
+ while (c = *p++) {
+ Goto_Node *new = goto_lookup(c, q);
+ if (!new) {
+ Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
+ new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ new->moves = NULL;
+ new->fail = NULL;
+ new->moves = NULL;
+ new->output = NULL;
+ new_move->state = new;
+ new_move->c = c;
+ new_move->next = q->moves;
+ q->moves = new_move;
+ if (depth == max_depth) {
+ int i;
+ Goto_Node **new_depths =
+ (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
+ max_depth = 2 * depth;
+ for (i=0; i<depth; i++)
+ new_depths[i] = depths[i];
+ depths = new_depths;
+ for (i=depth; i<max_depth; i++)
+ depths[i] = NULL;
+ }
+ new->next = depths[depth];
+ depths[depth] = new;
+ }
+ q = new;
+ depth++;
+ }
+ q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->output->next = NULL;
+ q->output->name = tree;
+ }
+ build_gotos(tree->rlink);
+ tree = tree->llink;
+ }
+}
+#define sym_char(c) (isalnum(c) || (c) == '_')
+
+static int op_char(c)
+ char c;
+{
+ switch (c) {
+ case '!': case '@': case '#': case '%': case '$': case '^':
+ case '&': case '*': case '-': case '+': case '=': case '/':
+ case '|': case '~': case '<': case '>':
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+static int reject_match(name, post, reader)
+ Name *name;
+ char post;
+ Manager *reader;
+{
+ int len = strlen(name->spelling);
+ char first = name->spelling[0];
+ char last = name->spelling[len - 1];
+ char prev = '\0';
+ len = reader->index - len - 2;
+ if (len >= 0)
+ prev = reader->scrap->chars[len];
+ else if (reader->prev)
+ prev = reader->scrap->chars[SLAB_SIZE - len];
+ if (sym_char(last) && sym_char(post)) return TRUE;
+ if (sym_char(first) && sym_char(prev)) return TRUE;
+ if (op_char(last) && op_char(post)) return TRUE;
+ if (op_char(first) && op_char(prev)) return TRUE;
+ return FALSE;
+}
diff --git a/web/nuweb/nuweb_ami/ami_nuweb0.90.lha b/web/nuweb/nuweb_ami/ami_nuweb0.90.lha
new file mode 100644
index 0000000000..78f1fe31f2
--- /dev/null
+++ b/web/nuweb/nuweb_ami/ami_nuweb0.90.lha
Binary files differ
diff --git a/web/nuweb/nuweb_ami/ami_nuweb0.90.readme b/web/nuweb/nuweb_ami/ami_nuweb0.90.readme
new file mode 100644
index 0000000000..0bbdd7d12d
--- /dev/null
+++ b/web/nuweb/nuweb_ami/ami_nuweb0.90.readme
@@ -0,0 +1,61 @@
+Short: NUWEB 0.90 - a simple literate programming language and tool
+Type: dev/misc
+Files: ami_nuweb0.90.lha, ami_nuweb0.90.readme
+Uploader: Andreas Scherer (scherer@genesis.informatik.rwth-aachen.de)
+Author: Preston Briggs (preston@cs.rice.edu)
+
+This is a version of Preston Briggs's NUWEB system, a simple literate
+programming language and tool.
+
+Here is what Preston says:
+
+ NUWEB works with any programming language and LaTeX. I wanted
+ to use LaTeX because it supports a multi-level sectioning scheme
+ and has facilities for drawing figures. I wanted to be able to
+ work with arbitrary programming languages because my friends and
+ I write programs in many languages (and sometimes combinations
+ of several languages), e.g., C, Fortran, C++, yacc, lex, Scheme,
+ assembly, Postscript, and so forth.
+
+This is revision 0.90, for the Commodore Amiga.
+
+This distribution includes the Ami_NuWeb executable, all source files
+(web and C), documentation and the (short) .dvi output of the user manual.
+
+Contents:
+ Ami_NuWeb The executable for any Amiga hardware, supports coprocessor
+ Makefile The original UNIX Makefile, unmodified for historic reasons
+ SMakefile The Makefile for SAS/C++ 6.55
+ README Preston Briggs's original README file
+ ami_nuweb0.90.readme This file
+ literate.bib A BibTeX bibliography of literate programming references
+ nuweb.w The NUWEB source for NUWEB
+ nuweb.ch A change file for better ANSI compliance and Amiga support
+ nuweb.1 troff manual by Marc Mengel
+ ami_nuweb.w The merged result of nuweb.w and nuweb.ch
+ ami_nuwebdoc.dvi The short-form NUWEB user manual in .dvi form
+ global.h A header file used globally
+ main.c pass1.c latex.c html.c output.c input.c scraps.c
+ names.c arena.c global.c
+ Source files generated by NUWEB
+ catalogs/nuweb.cd Catalog description with the English texts
+ catalogs/nuweb.d.ct Catalog translation with the German texts
+ catalogs/nuweb.h Header file with the English texts
+ catalogs/deutsch/nuweb.catalog German system catalog
+ wc.w UNIX word-count utility as an example of NUWEB programming
+
+This port was done and completely tested with SAS/C++ 6.55 on an Amiga 2000
+by Andreas Scherer, Roland-Straße 16, 52070 Aachen, Germany.
+I started from Tomas Willis' work, switched to NUWEB 0.87b, and added some
+parts on my own. The current version 0.90 is based on the distribution
+maintained by Marc Mengel. Thanks to Preston Briggs for NUWEB and to
+Tomas Willis for the (S)Makefile and the `temp_file+=2' hack (this has
+been superseded due to compatibility problems with DEC Ultrix 4.4 CC).
+
+Concerning the use of NUWEB with other human languages than English, I
+implemented full localization of all strings used for terminal output as
+well as LaTeX output for the Amiga version of NUWEB only. Should someone
+create translations for other languages as well, I would appreciate to
+receive a copy for inclusion in future distributions.
+
+March 28, 1995
diff --git a/web/nuweb/os2/nuweb087.txt b/web/nuweb/os2/nuweb087.txt
new file mode 100644
index 0000000000..376c0dd0fa
--- /dev/null
+++ b/web/nuweb/os2/nuweb087.txt
@@ -0,0 +1,81 @@
+
+I have uploaded nuweb087.zip including sources by Preson Briggs and
+the os/2 binary to :
+
+hobbes (ftp-os2.nmsu.edu),
+now: /incoming
+suggested: /os2/unix/tex
+
+cdrom (ftp-os2.cdrom.com),
+now: /os2/incoming
+suggested: /os2/tex
+
+and CTAN (ftp.shsu.edu):
+now: /incoming
+suggested: tex-archive/web/nuweb/os2/ (needs to be created).
+
+Replaces: Nothing really, except hopefully DOS versions of nuweb,
+ running on some OS/2 machines.
+
+Brief description:
+
+I was looking in news groups for a tool for literate programming (web)
+that'd allow me to use Fortran. (Extended) Pascal, and C and was portable
+to or available for OS/2. I came accross an interesting FAQ for the
+comp.literate.programming, and I got his personal reply:
+
+------------------------------------------------------------------------
+Preston Briggs (preston@cs.rice.edu) wrote:
+: >Also, my desire to have a version that (i) runs on OS/2 and (ii)
+: >possibly incorporates Extended ANSI Pasal, while (iii) being based on
+: >fweb to allow also g77 and gcc codes, made me think the -- for me very
+: >unusual -- cross posting would enlarge my cross section and hence the
+: >chance for an event ...
+
+: Lots of us have given up on the idea of pretty printing all our code,
+: and use language-independent tools. For OS/2, you might check out
+: nuweb and funnelweb. I wrote nuweb and unsurprisingly prefer it. I
+: use it with C, C++, Fortran, Scheme, and Makefiles. Others have used
+: it with Perl and such, but since it's language independent, you won't
+: have any trouble with any flavor of Pascal, etc.
+
+: You can grab a copy via anonymous ftp from cs.rice.edu, in the
+: directory public/preston.
+------------------------------------------------------------------------
+
+
+To make it short: here is the working OS/2 version, with executable,
+sources, and docs.
+
+All you need to use it is:
+a) LaTeX installed on your system (2.09 or 2e are fine)
+b) print the nuwebman.dvi or nuwebman.ps files, read them
+c) an editor
+d) the emx runtime system (emxrt.zip, from ftp-os2.cdrom.com, or
+ ftp-os2.nmsu.edu, for instance), version 0.9a fix pack 06 or
+ later installed. If you don't have it already installed
+ fetch the index of one of these sites, and search (grep) for
+ the pattern "emxrt.zip", or, if you can use regular expressions,
+ "^emxrt.zip". Then download and istall it. It contains the runtime
+ system in a dynamic link library which is shared by many other
+ programmes (say, gnu file utils, vi, emacs, less, probably even
+ emTeX programmes). This allows the executables to stay small and lean
+ but they won't run without it.
+e) put nuweb.exe in your path.
+
+It seems that this is the right tool for cs people who don't crave nice,
+mathematical pretty print stuff (like some physicists prefer), and for
+projects that involve mixing of languages, or involve languages that
+other webs don't know about. (I like fweb, too, but fweb can't do
+Extended Pascal, as an example, and so nuweb seems to be it for that
+case.)
+
+===============================================================================
+Stefan A. Deutscher 8-Mar-1996 | (+1-423-) voice fax
+The University of Tennessee, Knoxville | UTK : 974-7838 974-7843
+Department of Physics and Astronomy | ORNL : 574-5897 574-1118
+401, A. H. Nielsen Building | home : 522-7845 522-7845
+Knoxville, T.N. 37996-1200, USA | email: sad@utk.edu
+ ... in Germany: | stefand@elphy.irz.hu-berlin.de
+===============================================================================
+