summaryrefslogtreecommitdiff
path: root/web/nuweb/nuweb0.87b/scraps.c
diff options
context:
space:
mode:
Diffstat (limited to 'web/nuweb/nuweb0.87b/scraps.c')
-rw-r--r--web/nuweb/nuweb0.87b/scraps.c607
1 files changed, 607 insertions, 0 deletions
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;
+}