home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / nuweb087.zip / scraps.c < prev    next >
C/C++ Source or Header  |  1996-02-28  |  19KB  |  608 lines

  1. #include "global.h"
  2. #define SLAB_SIZE 500
  3.  
  4. typedef struct slab {
  5.   struct slab *next;
  6.   char chars[SLAB_SIZE];
  7. } Slab;
  8. typedef struct {
  9.   char *file_name;
  10.   int file_line;
  11.   int page;
  12.   char letter;
  13.   Slab *slab;
  14. } ScrapEntry;
  15. static ScrapEntry *SCRAP[256];
  16.  
  17. #define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
  18.  
  19. static int scraps;
  20. void init_scraps()
  21. {
  22.   scraps = 1;
  23.   SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
  24. }
  25. void write_scrap_ref(file, num, first, page)
  26.      FILE *file;
  27.      int num;
  28.      int first;
  29.      int *page;
  30. {
  31.   if (scrap_array(num).page >= 0) {
  32.     if (first)
  33.       fprintf(file, "%d", scrap_array(num).page);
  34.     else if (scrap_array(num).page != *page)
  35.       fprintf(file, ", %d", scrap_array(num).page);
  36.     if (scrap_array(num).letter > 0)
  37.       fputc(scrap_array(num).letter, file);
  38.   }
  39.   else {
  40.     if (first)
  41.       putc('?', file);
  42.     else
  43.       fputs(", ?", file);
  44.     {
  45.       if (!already_warned) {
  46.         fprintf(stderr, "%s: you'll need to rerun nuweb after running latex\n",
  47.                 command_name);
  48.         already_warned = TRUE;
  49.       }
  50.     }
  51.   }
  52.   *page = scrap_array(num).page;
  53. }
  54. void write_single_scrap_ref(file, num)
  55.      FILE *file;
  56.      int num;
  57. {
  58.   int page;
  59.   write_scrap_ref(file, num, TRUE, &page);
  60. }
  61. typedef struct {
  62.   Slab *scrap;
  63.   Slab *prev;
  64.   int index;
  65. } Manager;
  66. static void push(c, manager)
  67.      char c;
  68.      Manager *manager;
  69. {
  70.   Slab *scrap = manager->scrap;
  71.   int index = manager->index;
  72.   scrap->chars[index++] = c;
  73.   if (index == SLAB_SIZE) {
  74.     Slab *new = (Slab *) arena_getmem(sizeof(Slab));
  75.     scrap->next = new;
  76.     manager->scrap = new;
  77.     index = 0;
  78.   }
  79.   manager->index = index;
  80. }
  81. static void pushs(s, manager)
  82.      char *s;
  83.      Manager *manager;
  84. {
  85.   while (*s)
  86.     push(*s++, manager);
  87. }
  88. int collect_scrap()
  89. {
  90.   Manager writer;
  91.   {
  92.     Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
  93.     if ((scraps & 255) == 0)
  94.       SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
  95.     scrap_array(scraps).slab = scrap;
  96.     scrap_array(scraps).file_name = save_string(source_name);
  97.     scrap_array(scraps).file_line = source_line;
  98.     scrap_array(scraps).page = -1;
  99.     scrap_array(scraps).letter = 0;
  100.     writer.scrap = scrap;
  101.     writer.index = 0;
  102.   }
  103.   {
  104.     int c = source_get();
  105.     while (1) {
  106.       switch (c) {
  107.         case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
  108.                           command_name, scrap_array(scraps).file_name,
  109.                           scrap_array(scraps).file_line);
  110.                   exit(-1);
  111.         case '@': {
  112.                     c = source_get();
  113.                     switch (c) {
  114.                       case '@': pushs("@@", &writer);
  115.                                 c = source_get();
  116.                                 break;
  117.                       case '|': {
  118.                                   do {
  119.                                     char new_name[100];
  120.                                     char *p = new_name;
  121.                                     do 
  122.                                       c = source_get();
  123.                                     while (isspace(c));
  124.                                     if (c != '@') {
  125.                                       Name *name;
  126.                                       do {
  127.                                         *p++ = c;
  128.                                         c = source_get();
  129.                                       } while (c != '@' && !isspace(c));
  130.                                       *p = '\0';
  131.                                       name = name_add(&user_names, new_name);
  132.                                       if (!name->defs || name->defs->scrap != scraps) {
  133.                                         Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  134.                                         def->scrap = scraps;
  135.                                         def->next = name->defs;
  136.                                         name->defs = def;
  137.                                       }
  138.                                     }
  139.                                   } while (c != '@');
  140.                                   c = source_get();
  141.                                   if (c != '}') {
  142.                                     fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
  143.                                             command_name, c, source_name, source_line);
  144.                                     exit(-1);
  145.                                   }
  146.                                 }
  147.                       case '}': push('\0', &writer);
  148.                                 return scraps++;
  149.                       case '<': {
  150.                                   Name *name = collect_scrap_name();
  151.                                   {
  152.                                     char *s = name->spelling;
  153.                                     int len = strlen(s) - 1;
  154.                                     pushs("@<", &writer);
  155.                                     while (len > 0) {
  156.                                       push(*s++, &writer);
  157.                                       len--;
  158.                                     }
  159.                                     if (*s == ' ')
  160.                                       pushs("...", &writer);
  161.                                     else
  162.                                       push(*s, &writer);
  163.                                     pushs("@>", &writer);
  164.                                   }
  165.                                   {
  166.                                     if (!name->uses || name->uses->scrap != scraps) {
  167.                                       Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  168.                                       use->scrap = scraps;
  169.                                       use->next = name->uses;
  170.                                       name->uses = use;
  171.                                     }
  172.                                   }
  173.                                   c = source_get();
  174.                                 }
  175.                                 break;
  176.                       default : fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
  177.                                         command_name, c, source_name, source_line);
  178.                                 exit(-1);
  179.                     }
  180.                   }
  181.                   break;
  182.         default:  push(c, &writer);
  183.                   c = source_get();
  184.                   break;
  185.       }
  186.     }
  187.   }
  188. }
  189. static char pop(manager)
  190.      Manager *manager;
  191. {
  192.   Slab *scrap = manager->scrap;
  193.   int index = manager->index;
  194.   char c = scrap->chars[index++];
  195.   if (index == SLAB_SIZE) {
  196.     manager->prev = scrap;
  197.     manager->scrap = scrap->next;
  198.     index = 0;
  199.   }
  200.   manager->index = index;
  201.   return c;
  202. }
  203. static Name *pop_scrap_name(manager)
  204.      Manager *manager;
  205. {
  206.   char name[100];
  207.   char *p = name;
  208.   int c = pop(manager);
  209.   while (TRUE) {
  210.     if (c == '@')
  211.       {
  212.         c = pop(manager);
  213.         if (c == '@') {
  214.           *p++ = c;
  215.           c = pop(manager);
  216.         }
  217.         else if (c == '>') {
  218.           if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
  219.             p[-3] = ' ';
  220.             p -= 2;
  221.           }
  222.           *p = '\0';
  223.           return prefix_add(¯o_names, name);
  224.         }
  225.         else {
  226.           fprintf(stderr, "%s: found an internal problem (1)\n", command_name);
  227.           exit(-1);
  228.         }
  229.       }
  230.     else {
  231.       *p++ = c;
  232.       c = pop(manager);
  233.     }
  234.   }
  235. }
  236. int write_scraps(file, defs, global_indent, indent_chars,
  237.                    debug_flag, tab_flag, indent_flag)
  238.      FILE *file;
  239.      Scrap_Node *defs;
  240.      int global_indent;
  241.      char *indent_chars;
  242.      char debug_flag;
  243.      char tab_flag;
  244.      char indent_flag;
  245. {
  246.   int indent = 0;
  247.   while (defs) {
  248.     {
  249.       char c;
  250.       Manager reader;
  251.       int line_number = scrap_array(defs->scrap).file_line;
  252.       if (debug_flag) {
  253.         fprintf(file, "\n#line %d \"%s\"\n",
  254.                 line_number, scrap_array(defs->scrap).file_name);
  255.         {
  256.           if (indent_flag) {
  257.             if (tab_flag)
  258.               for (indent=0; indent<global_indent; indent++)
  259.                 putc(' ', file);
  260.             else
  261.               for (indent=0; indent<global_indent; indent++)
  262.                 putc(indent_chars[indent], file);
  263.           }
  264.           indent = 0;
  265.         }
  266.       }
  267.       reader.scrap = scrap_array(defs->scrap).slab;
  268.       reader.index = 0;
  269.       c = pop(&reader);
  270.       while (c) {
  271.         switch (c) {
  272.           case '@':  {
  273.                        c = pop(&reader);
  274.                        switch (c) {
  275.                          case '@': putc(c, file);
  276.                                    indent_chars[global_indent + indent] = ' ';
  277.                                    indent++;
  278.                                    break;
  279.                          case '<': {
  280.                                      Name *name = pop_scrap_name(&reader);
  281.                                      if (name->mark) {
  282.                                        fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
  283.                                                command_name, name->spelling);
  284.                                        exit(-1);
  285.                                      }
  286.                                      if (name->defs) {
  287.                                        name->mark = TRUE;
  288.                                        indent = write_scraps(file, name->defs, global_indent + indent,
  289.                                                              indent_chars, debug_flag, tab_flag, indent_flag);
  290.                                        indent -= global_indent;
  291.                                        name->mark = FALSE;
  292.                                      }
  293.                                      else if (!tex_flag)
  294.                                        fprintf(stderr, "%s: macro never defined <%s>\n",
  295.                                                command_name, name->spelling);
  296.                                    }
  297.                                    if (debug_flag) {
  298.                                      fprintf(file, "\n#line %d \"%s\"\n",
  299.                                              line_number, scrap_array(defs->scrap).file_name);
  300.                                      {
  301.                                        if (indent_flag) {
  302.                                          if (tab_flag)
  303.                                            for (indent=0; indent<global_indent; indent++)
  304.                                              putc(' ', file);
  305.                                          else
  306.                                            for (indent=0; indent<global_indent; indent++)
  307.                                              putc(indent_chars[indent], file);
  308.                                        }
  309.                                        indent = 0;
  310.                                      }
  311.                                    }
  312.                                    break;
  313.                          default:  /* ignore, since we should already have a warning */
  314.                                    break;
  315.                        }
  316.                      }
  317.                      break;
  318.           case '\n': putc(c, file);
  319.                      line_number++;
  320.                      {
  321.                        if (indent_flag) {
  322.                          if (tab_flag)
  323.                            for (indent=0; indent<global_indent; indent++)
  324.                              putc(' ', file);
  325.                          else
  326.                            for (indent=0; indent<global_indent; indent++)
  327.                              putc(indent_chars[indent], file);
  328.                        }
  329.                        indent = 0;
  330.                      }
  331.                      break;
  332.           case '\t': {
  333.                        if (tab_flag)
  334.                          {
  335.                            int delta = 8 - (indent % 8);
  336.                            indent += delta;
  337.                            while (delta > 0) {
  338.                              putc(' ', file);
  339.                              delta--;
  340.                            }
  341.                          }
  342.                        else {
  343.                          putc('\t', file);
  344.                          indent_chars[global_indent + indent] = '\t';
  345.                          indent++;
  346.                        }
  347.                      }
  348.                      break;
  349.           default:   putc(c, file);
  350.                      indent_chars[global_indent + indent] = ' ';
  351.                      indent++;
  352.                      break;
  353.         }
  354.         c = pop(&reader);
  355.       }
  356.     }
  357.     defs = defs->next;
  358.   }
  359.   return indent + global_indent;
  360. }
  361. void collect_numbers(aux_name)
  362.      char *aux_name;
  363. {
  364.   if (number_flag) {
  365.     int i;
  366.     for (i=1; i<scraps; i++)
  367.       scrap_array(i).page = i;
  368.   }
  369.   else {
  370.     FILE *aux_file = fopen(aux_name, "r");
  371.     already_warned = FALSE;
  372.     if (aux_file) {
  373.       char aux_line[500];
  374.       while (fgets(aux_line, 500, aux_file)) {
  375.         int scrap_number;
  376.         int page_number;
  377.         char dummy[50];
  378.         if (3 == sscanf(aux_line, "\\newlabel{scrap%d}{%[^}]}{%d}",
  379.                         &scrap_number, dummy, &page_number)) {
  380.           if (scrap_number < scraps)
  381.             scrap_array(scrap_number).page = page_number;
  382.           else
  383.             {
  384.               if (!already_warned) {
  385.                 fprintf(stderr, "%s: you'll need to rerun nuweb after running latex\n",
  386.                         command_name);
  387.                 already_warned = TRUE;
  388.               }
  389.             }
  390.         }
  391.       }
  392.       fclose(aux_file);
  393.       {
  394.         int scrap;
  395.         for (scrap=2; scrap<scraps; scrap++) {
  396.           if (scrap_array(scrap-1).page == scrap_array(scrap).page) {
  397.             if (!scrap_array(scrap-1).letter)
  398.               scrap_array(scrap-1).letter = 'a';
  399.             scrap_array(scrap).letter = scrap_array(scrap-1).letter + 1;
  400.           }
  401.         }
  402.       }
  403.     }
  404.   }
  405. }
  406. typedef struct name_node {
  407.   struct name_node *next;
  408.   Name *name;
  409. } Name_Node;
  410. typedef struct goto_node {
  411.   Name_Node *output;            /* list of words ending in this state */
  412.   struct move_node *moves;      /* list of possible moves */
  413.   struct goto_node *fail;       /* and where to go when no move fits */
  414.   struct goto_node *next;       /* next goto node with same depth */
  415. } Goto_Node;
  416. typedef struct move_node {
  417.   struct move_node *next;
  418.   Goto_Node *state;
  419.   char c;
  420. } Move_Node;
  421. static Goto_Node *root[128];
  422. static int max_depth;
  423. static Goto_Node **depths;
  424. static Goto_Node *goto_lookup(c, g)
  425.      char c;
  426.      Goto_Node *g;
  427. {
  428.   Move_Node *m = g->moves;
  429.   while (m && m->c != c)
  430.     m = m->next;
  431.   if (m)
  432.     return m->state;
  433.   else
  434.     return NULL;
  435. }
  436. static void build_gotos();
  437. static int reject_match();
  438.  
  439. void search()
  440. {
  441.   int i;
  442.   for (i=0; i<128; i++)
  443.     root[i] = NULL;
  444.   max_depth = 10;
  445.   depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
  446.   for (i=0; i<max_depth; i++)
  447.     depths[i] = NULL;
  448.   build_gotos(user_names);
  449.   {
  450.     int depth;
  451.     for (depth=1; depth<max_depth; depth++) {
  452.       Goto_Node *r = depths[depth];
  453.       while (r) {
  454.         Move_Node *m = r->moves;
  455.         while (m) {
  456.           char a = m->c;
  457.           Goto_Node *s = m->state;
  458.           Goto_Node *state = r->fail;
  459.           while (state && !goto_lookup(a, state))
  460.             state = state->fail;
  461.           if (state)
  462.             s->fail = goto_lookup(a, state);
  463.           else
  464.             s->fail = root[a];
  465.           if (s->fail) {
  466.             Name_Node *p = s->fail->output;
  467.             while (p) {
  468.               Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
  469.               q->name = p->name;
  470.               q->next = s->output;
  471.               s->output = q;
  472.               p = p->next;
  473.             }
  474.           }
  475.           m = m->next;
  476.         }
  477.         r = r->next;
  478.       }
  479.     }
  480.   }
  481.   {
  482.     for (i=1; i<scraps; i++) {
  483.       char c;
  484.       Manager reader;
  485.       Goto_Node *state = NULL;
  486.       reader.prev = NULL;
  487.       reader.scrap = scrap_array(i).slab;
  488.       reader.index = 0;
  489.       c = pop(&reader);
  490.       while (c) {
  491.         while (state && !goto_lookup(c, state))
  492.           state = state->fail;
  493.         if (state)
  494.           state = goto_lookup(c, state);
  495.         else
  496.           state = root[c];
  497.         c = pop(&reader);
  498.         if (state && state->output) {
  499.           Name_Node *p = state->output;
  500.           do {
  501.             Name *name = p->name;
  502.             if (!reject_match(name, c, &reader) &&
  503.                 (!name->uses || name->uses->scrap != i)) {
  504.               Scrap_Node *new_use =
  505.                   (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
  506.               new_use->scrap = i;
  507.               new_use->next = name->uses;
  508.               name->uses = new_use;
  509.             }
  510.             p = p->next;
  511.           } while (p);
  512.         }
  513.       }
  514.     }
  515.   }
  516. }
  517. static void build_gotos(tree)
  518.      Name *tree;
  519. {
  520.   while (tree) {
  521.     {
  522.       int depth = 2;
  523.       char *p = tree->spelling;
  524.       char c = *p++;
  525.       Goto_Node *q = root[c];
  526.       if (!q) {
  527.         q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
  528.         root[c] = q;
  529.         q->moves = NULL;
  530.         q->fail = NULL;
  531.         q->moves = NULL;
  532.         q->output = NULL;
  533.         q->next = depths[1];
  534.         depths[1] = q;
  535.       }
  536.       while (c = *p++) {
  537.         Goto_Node *new = goto_lookup(c, q);
  538.         if (!new) {
  539.           Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
  540.           new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
  541.           new->moves = NULL;
  542.           new->fail = NULL;
  543.           new->moves = NULL;
  544.           new->output = NULL;
  545.           new_move->state = new;
  546.           new_move->c = c;
  547.           new_move->next = q->moves;
  548.           q->moves = new_move;
  549.           if (depth == max_depth) {
  550.             int i;
  551.             Goto_Node **new_depths =
  552.                 (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
  553.             max_depth = 2 * depth;
  554.             for (i=0; i<depth; i++)
  555.               new_depths[i] = depths[i];
  556.             depths = new_depths;
  557.             for (i=depth; i<max_depth; i++)
  558.               depths[i] = NULL;
  559.           }
  560.           new->next = depths[depth];
  561.           depths[depth] = new;
  562.         }
  563.         q = new;
  564.         depth++;
  565.       }
  566.       q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
  567.       q->output->next = NULL;
  568.       q->output->name = tree;
  569.     }
  570.     build_gotos(tree->rlink);
  571.     tree = tree->llink;
  572.   }
  573. }
  574. #define sym_char(c) (isalnum(c) || (c) == '_')
  575.  
  576. static int op_char(c)
  577.      char c;
  578. {
  579.   switch (c) {
  580.     case '!': case '@': case '#': case '%': case '$': case '^': 
  581.     case '&': case '*': case '-': case '+': case '=': case '/':
  582.     case '|': case '~': case '<': case '>':
  583.       return TRUE;
  584.     default:
  585.       return FALSE;
  586.   }
  587. }
  588. static int reject_match(name, post, reader)
  589.      Name *name;
  590.      char post;
  591.      Manager *reader;
  592. {
  593.   int len = strlen(name->spelling);
  594.   char first = name->spelling[0];
  595.   char last = name->spelling[len - 1];
  596.   char prev = '\0';
  597.   len = reader->index - len - 2;
  598.   if (len >= 0)
  599.     prev = reader->scrap->chars[len];
  600.   else if (reader->prev)
  601.     prev = reader->scrap->chars[SLAB_SIZE - len];
  602.   if (sym_char(last) && sym_char(post)) return TRUE;
  603.   if (sym_char(first) && sym_char(prev)) return TRUE;
  604.   if (op_char(last) && op_char(post)) return TRUE;
  605.   if (op_char(first) && op_char(prev)) return TRUE;
  606.   return FALSE;
  607. }
  608.