home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / lang / sgmls / src / catalog.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-10  |  19.8 KB  |  926 lines

  1. /* Normalize public identifiers to handle ISO 8879[-:]1986 problem.
  2. What should happen if there's a duplicate in a single catalog entry file? */
  3.  
  4. #include "config.h"
  5. #include "std.h"
  6. #include "catalog.h"
  7.  
  8. #ifdef USE_PROTOTYPES
  9. #define P(parms) parms
  10. #else
  11. #define P(parms) ()
  12. #endif
  13.  
  14. #include "alloc.h"
  15.  
  16. #define MINIMUM_DATA_CHARS \
  17. "abcdefghijklmnopqrstuvwxyz\
  18. ABCDEFGHIJKLMNOPQRSTUVWXYZ\
  19. 0123456789-.'()+,/:=?"
  20.  
  21. #define N_DECL_TYPE 3
  22. #define PUBLIC_ID_MAP N_DECL_TYPE
  23. #define N_TABLES (N_DECL_TYPE + 1)
  24.  
  25. enum literal_type {
  26.   NORMAL_LITERAL,
  27.   MINIMUM_LITERAL
  28. };
  29.  
  30. typedef enum {
  31.   EOF_PARAM,
  32.   NAME_PARAM,
  33.   LITERAL_PARAM
  34. } PARAM_TYPE;
  35.  
  36. enum catalog_error {
  37.   E_NAME_EXPECTED,
  38.   E_LITERAL_EXPECTED,
  39.   E_ARG_EXPECTED,
  40.   E_MINIMUM_DATA,
  41.   E_EOF_COMMENT,
  42.   E_EOF_LITERAL,
  43.   E_NUL_CHAR,
  44.   E_CANNOT_OPEN,
  45.   E_GETC,
  46.   E_FCLOSE
  47. };
  48.  
  49. #define FIRST_SYSTEM_ERROR E_CANNOT_OPEN
  50.  
  51. #define HASH_TABLE_INITIAL_SIZE 8
  52. #define HASH_TABLE_MAX_SIZE (((SIZE_T)-1)/sizeof(struct hash_table_entry *))
  53.  
  54. struct hash_table_entry {
  55.   int file_index;
  56.   const char *key;
  57.   const char *system_id;
  58. };
  59.  
  60. /* Number of bytes per string block. */
  61. #define BLOCK_SIZE 1000
  62.  
  63. /* Bytes follow the struct. */
  64.  
  65. struct string_block {
  66.   struct string_block *next;
  67. };
  68.  
  69. struct hash_table {
  70.   struct hash_table_entry **v;
  71.   SIZE_T size;            /* must be power of 2 */
  72.   SIZE_T used;
  73.   SIZE_T used_limit;
  74. };
  75.  
  76. struct catalog {
  77.   struct hash_table tables[N_TABLES];
  78.   char **files;
  79.   int n_files;
  80.   struct string_block *blocks;
  81.   char *block_ptr;
  82.   SIZE_T block_spare;
  83.   CATALOG_ERROR_HANDLER error_handler;
  84.   int loaded;
  85. };
  86.  
  87. struct parser {
  88.   FILE *fp;
  89.   struct catalog *cat;
  90.   char *param;
  91.   SIZE_T param_length;
  92.   SIZE_T param_alloc;
  93.   int file_index;
  94.   const char *filename;
  95.   unsigned long newline_count;
  96.   char minimum_data[256];
  97. };
  98.  
  99. static
  100. VOID add_catalog_file P((struct catalog *cat, const char *filename,
  101.              SIZE_T length));
  102. static
  103. VOID load P((struct catalog *cat));
  104. static
  105. VOID parse_file P((struct parser *parser));
  106. static
  107. VOID parse_public P((struct parser *parser));
  108. static
  109. VOID parse_name_map P((struct parser *parser,
  110.                int decl_type));
  111. static
  112. int parse_arg P((struct parser *parser));
  113. static
  114. PARAM_TYPE parse_param P((struct parser *parser, enum literal_type));
  115. static
  116. VOID skip_comment P((struct parser *parser));
  117. static
  118. PARAM_TYPE parse_literal P((struct parser *parser, int lit,
  119.                 enum literal_type));
  120. static
  121. PARAM_TYPE parse_name P((struct parser *parser, int first_char));
  122. static
  123. VOID param_grow P((struct parser *parser));
  124. static
  125. const char *param_save P((struct parser *parser));
  126. static
  127. char *alloc_bytes P((struct catalog *catalog, SIZE_T n));
  128. static
  129. int param_equal P((struct parser *parser, const char *key));
  130. static
  131. int hash_table_add P((struct hash_table *table, const char *s,
  132.               const char *system_id, int file_index));
  133. static
  134. struct hash_table_entry *hash_table_lookup P((struct hash_table *table,
  135.                           const char *s));
  136. static
  137. struct hash_table_entry *hash_table_lookup_subst P((struct hash_table *table,
  138.                             const char *subst_table,
  139.                             const char *s));
  140. static
  141. VOID hash_table_init P((struct hash_table *p));
  142. static
  143. VOID hash_table_delete P((struct hash_table *p));
  144. static
  145. SIZE_T hash_table_start_index P((struct hash_table *p, const char *s));
  146. static
  147. int subst_equal P((const char *subst_table, const char *s1, const char *s2));
  148. static
  149. VOID error P((struct parser *parser, enum catalog_error err));
  150.  
  151. #define param_char(parser, c) \
  152.   ((((parser)->param_length < (parser)->param_alloc) \
  153.      || (param_grow(parser), 1)), \
  154.   ((parser)->param[(parser)->param_length] = (c)), \
  155.   ((parser)->param_length += 1))
  156.  
  157. #define param_init(parser) ((parser)->param_length = 0)
  158. #define param_chop(parser) \
  159.   ((parser)->param_length = (parser)->param_length - 1)
  160.  
  161. const char *catalog_error_text(error_number)
  162.      int error_number;
  163. {
  164.   static const char *text[] = {
  165.     "Name expected",
  166.     "Literal expected",
  167.     "Missing argument",
  168.     "Only minimum data characters allowed in a public identifier",
  169.     "End of file in comment",
  170.     "End of file in literal",
  171.     "Nul character is not allowed",
  172.     "Cannot open `%s': %s",
  173.     "Error reading `%s': %s",
  174.     "Error closing `%s': %s"
  175.   };
  176.   if (error_number >= 0 && error_number < sizeof(text)/sizeof(text[0]))
  177.     return text[error_number];
  178.   else
  179.     return "(invalid error number)";
  180. }
  181.  
  182.  
  183. CATALOG catalog_create(error_handler)
  184.      CATALOG_ERROR_HANDLER error_handler;
  185. {
  186.   int i;
  187.   struct catalog *p = (struct catalog *)xmalloc(sizeof(struct catalog));
  188.   p->loaded = 0;
  189.   p->n_files = 0;
  190.   p->files = 0;
  191.   p->error_handler = error_handler;
  192.   p->blocks = 0;
  193.   p->block_spare = 0;
  194.   p->block_ptr = 0;
  195.   for (i = 0; i < N_TABLES; i++)
  196.     hash_table_init(p->tables + i);
  197.   return (CATALOG)p;
  198. }
  199.  
  200. VOID catalog_delete(cat)
  201.      CATALOG cat;
  202. {
  203.   int i;
  204.   struct string_block *block;
  205.   struct catalog *catalog = (struct catalog *)cat;
  206.   for (i = 0; i < 4; i++)
  207.     hash_table_delete(catalog->tables + i);
  208.   if (catalog->files)
  209.     free(catalog->files);
  210.   block = catalog->blocks;
  211.   while (block) {
  212.     struct string_block *tem = block;
  213.     block = block->next;
  214.     free((UNIV)tem);
  215.   }
  216.   catalog->blocks = 0;
  217.   free((UNIV)catalog);
  218. }
  219.  
  220. VOID catalog_load_file(p, filename)
  221.      CATALOG p;
  222.      const char *filename;
  223. {
  224.   add_catalog_file((struct catalog *)p, filename, strlen(filename));
  225. }
  226.  
  227. int catalog_lookup_entity(cat, public_id, name, decl_type, subst_table,
  228.               system_id, catalog_file)
  229.      CATALOG cat;
  230.      const char *public_id;
  231.      const char *name;
  232.      enum catalog_decl_type decl_type;
  233.      const char *subst_table;
  234.      const char **system_id;
  235.      const char **catalog_file;
  236. {
  237.   struct catalog *catalog = (struct catalog *)cat;
  238.   const struct hash_table_entry *entry = 0;
  239.   if (!catalog->loaded)
  240.     load(catalog);
  241.   if (public_id)
  242.     entry = hash_table_lookup(catalog->tables + PUBLIC_ID_MAP, public_id);
  243.   if (name
  244.       && decl_type >= 0
  245.       && decl_type < N_DECL_TYPE
  246.       && (!entry || entry->file_index > 0)) {
  247.     const struct hash_table_entry *entity_entry = 0;
  248.     if (!subst_table)
  249.       entity_entry = hash_table_lookup(catalog->tables + decl_type, name);
  250.     else
  251.       entity_entry = hash_table_lookup_subst(catalog->tables + decl_type,
  252.                          subst_table, name);
  253.     if (!entry
  254.     || (entity_entry
  255.         && entity_entry->file_index < entry->file_index))
  256.       entry = entity_entry;
  257.   }
  258.   if (!entry)
  259.     return 0;
  260.   *system_id = entry->system_id;
  261.   *catalog_file = catalog->files[entry->file_index];
  262.   return 1;
  263. }
  264.  
  265. static
  266. VOID add_catalog_file(cat, filename, length)
  267.      struct catalog *cat;
  268.      const char *filename;
  269.      SIZE_T length;
  270. {
  271.   char *s;
  272.   if (!cat->files)
  273.     cat->files = (char **)xmalloc(sizeof(char *));
  274.   else
  275.     cat->files
  276.       = (char **)xrealloc(cat->files, (cat->n_files + 1)*sizeof(char *));
  277.   s = alloc_bytes(cat, length + 1);
  278.   memcpy(s, filename, length);
  279.   s[length] = '\0';
  280.   cat->files[cat->n_files] = s;
  281.   cat->n_files += 1;
  282. }
  283.  
  284. static
  285. VOID load(cat)
  286.      struct catalog *cat;
  287. {
  288.   int i;
  289.   const char *p;
  290.   struct parser parser;
  291.   const char *env_var;
  292.   int optional_file_index = cat->n_files;
  293.  
  294.   cat->loaded = 1;
  295.   parser.param = 0;
  296.   parser.param_alloc = 0;
  297.   parser.cat = cat;
  298.   for (i = 0; i < 256; i++)
  299.     parser.minimum_data[i] = 0;
  300.   for (p = MINIMUM_DATA_CHARS; *p; p++)
  301.     parser.minimum_data[(unsigned char)*p] = 1;
  302.   env_var = getenv(CATALOG_FILES_ENV_VAR);
  303.   if (!env_var || *env_var == '\0')
  304.     env_var = DEFAULT_CATALOG_FILES;
  305.   for (;;) {
  306.     for (p = env_var; *p && *p != PATH_FILE_SEP; p++)
  307.       ;
  308.     if (p > env_var)
  309.       add_catalog_file(cat, env_var, p - env_var);
  310.     if (!*p)
  311.       break;
  312.     env_var = p + 1;
  313.   }
  314.   for (i = 0; i < cat->n_files; i++) {
  315.     parser.filename = cat->files[i];
  316.     parser.newline_count = 0;
  317.     parser.fp = fopen(cat->files[i], "r");
  318.     if (!parser.fp) {
  319.       if (i < optional_file_index)
  320.     error(&parser, E_CANNOT_OPEN);
  321.     }
  322.     else {
  323.       parser.file_index = i;
  324.       parse_file(&parser);
  325.       errno = 0;
  326.       if (fclose(parser.fp) < 0)
  327.     error(&parser, E_FCLOSE);
  328.     }
  329.   }
  330.   if (parser.param)
  331.     free(parser.param);
  332. }
  333.  
  334. static
  335. VOID parse_file(parser)
  336.      struct parser *parser;
  337. {
  338.   int skipping = 0;
  339.   for (;;) {
  340.     PARAM_TYPE type = parse_param(parser, NORMAL_LITERAL);
  341.     if (type == NAME_PARAM) {
  342.       if (param_equal(parser, "PUBLIC"))
  343.     parse_public(parser);
  344.       else if (param_equal(parser, "ENTITY"))
  345.     parse_name_map(parser, CATALOG_ENTITY_DECL);
  346.       else if (param_equal(parser, "DOCTYPE"))
  347.     parse_name_map(parser, CATALOG_DOCTYPE_DECL);
  348.       else if (param_equal(parser, "LINKTYPE"))
  349.     parse_name_map(parser, CATALOG_LINKTYPE_DECL);
  350.       else
  351.     skipping = 1;
  352.     }
  353.     else if (type == EOF_PARAM)
  354.       break;
  355.     else if (!skipping) {
  356.       skipping = 1;
  357.       error(parser, E_NAME_EXPECTED);
  358.     }
  359.   }
  360. }
  361.  
  362. static
  363. VOID parse_public(parser)
  364.      struct parser *parser;
  365. {
  366.   const char *public_id;
  367.  
  368.   if (parse_param(parser, MINIMUM_LITERAL) != LITERAL_PARAM)
  369.     error(parser, E_LITERAL_EXPECTED);
  370.   public_id = param_save(parser);
  371.   if (!parse_arg(parser))
  372.     return;
  373.   hash_table_add(parser->cat->tables + PUBLIC_ID_MAP,
  374.          public_id, param_save(parser), parser->file_index);
  375. }
  376.  
  377. static
  378. VOID parse_name_map(parser, decl_type)
  379.      struct parser *parser;
  380.      int decl_type;
  381. {
  382.   const char *name;
  383.  
  384.   if (!parse_arg(parser))
  385.     return;
  386.   name = param_save(parser);
  387.   if (!parse_arg(parser))
  388.     return;
  389.   hash_table_add(parser->cat->tables + decl_type,
  390.          name, param_save(parser), parser->file_index);
  391. }
  392.  
  393. static
  394. int parse_arg(parser)
  395.      struct parser *parser;
  396. {
  397.   PARAM_TYPE parm = parse_param(parser, NORMAL_LITERAL);
  398.   if (parm != NAME_PARAM && parm != LITERAL_PARAM) {
  399.     error(parser, E_ARG_EXPECTED);
  400.     return 0;
  401.   }
  402.   return 1;
  403. }
  404.  
  405. static
  406. PARAM_TYPE parse_param(parser, lit_type)
  407.      struct parser *parser;
  408.      enum literal_type lit_type;
  409. {
  410.   for (;;) {
  411.     int c = getc(parser->fp);
  412.     switch (c) {
  413.     case EOF:
  414.       if (ferror(parser->fp))
  415.     error(parser, E_GETC);
  416.       return EOF_PARAM;
  417.     case '"':
  418.     case '\'':
  419.       return parse_literal(parser, c, lit_type);
  420.     case '\n':
  421.       parser->newline_count += 1;
  422.       break;
  423.     case '\t':
  424.     case ' ':
  425.       break;
  426.     case '\0':
  427.       error(parser, E_NUL_CHAR);
  428.       break;
  429.     case '-':
  430.       c = getc(parser->fp);
  431.       if (c == '-') {
  432.     skip_comment(parser);
  433.     break;
  434.       }
  435.       ungetc(c, parser->fp);
  436.       c = '-';
  437.       /* fall through */
  438.     default:
  439.       return parse_name(parser, c);
  440.     }
  441.   }
  442. }
  443.  
  444. static
  445. VOID skip_comment(parser)
  446.      struct parser *parser;
  447. {
  448.   FILE *fp = parser->fp;
  449.   for (;;) {
  450.     int c = getc(fp);
  451.     if (c == '-') {
  452.       c = getc(fp);
  453.       if (c == '-')
  454.     return;
  455.     }
  456.     if (c == EOF) {
  457.       if (ferror(fp))
  458.     error(parser, E_GETC);
  459.       error(parser, E_EOF_COMMENT);
  460.       return;
  461.     }
  462.     if (c == '\n')
  463.       parser->newline_count += 1;
  464.   }
  465. }
  466.  
  467. static
  468. PARAM_TYPE parse_literal(parser, lit, lit_type)
  469.      struct parser *parser;
  470.      int lit;
  471.      enum literal_type lit_type;
  472. {
  473.   enum { no, yes_begin, yes_middle } skipping = yes_begin;
  474.   FILE *fp = parser->fp;
  475.   param_init(parser);
  476.   for (;;) {
  477.     int c = getc(fp);
  478.     if (c == lit)
  479.       break;
  480.     switch (c) {
  481.     case '\0':
  482.       error(parser, E_NUL_CHAR);
  483.       break;
  484.     case EOF:
  485.       if (ferror(fp))
  486.     error(parser, E_GETC);
  487.       error(parser, E_EOF_LITERAL);
  488.       return LITERAL_PARAM;
  489.     case '\n':
  490.       parser->newline_count += 1;
  491.       /* fall through */
  492.     case ' ':
  493.       if (lit_type == MINIMUM_LITERAL) {
  494.     if (skipping == no) {
  495.       param_char(parser, ' ');
  496.       skipping = yes_middle;
  497.     }
  498.       }
  499.       else
  500.     param_char(parser, c);
  501.       break;
  502.     default:
  503.       if (lit_type == MINIMUM_LITERAL) {
  504.     if (!parser->minimum_data[c])
  505.       error(parser, E_MINIMUM_DATA);
  506.     else {
  507.       skipping = no;
  508.       param_char(parser, c);
  509.     }
  510.       }
  511.       else
  512.     param_char(parser, c);
  513.       break;
  514.     }
  515.   }
  516.   if (skipping == yes_middle)
  517.     param_chop(parser);
  518.   return LITERAL_PARAM;
  519. }
  520.  
  521. static
  522. PARAM_TYPE parse_name(parser, first_char)
  523.      struct parser *parser;
  524.      int first_char;
  525. {
  526.   FILE *fp = parser->fp;
  527.   param_init(parser);
  528.   param_char(parser, first_char);
  529.   for (;;) {
  530.     int c = getc(fp);
  531.     switch (c) {
  532.     case '\0':
  533.       error(parser, E_NUL_CHAR);
  534.       break;
  535.     case EOF:
  536.       if (ferror(fp))
  537.     error(parser, E_GETC);
  538.       goto done;
  539.     case '\n':
  540.       parser->newline_count += 1;
  541.       goto done;
  542.     case ' ':
  543.     case '\t':
  544.       goto done;
  545.     case '"':
  546.     case '\'':
  547.       ungetc(c, fp);
  548.       goto done;
  549.     default:
  550.       param_char(parser, c);
  551.     }
  552.   }
  553.  done:
  554.   return NAME_PARAM;
  555. }
  556.  
  557. static
  558. VOID param_grow(parser)
  559.      struct parser *parser;
  560. {
  561.   if (parser->param_alloc == 0) {
  562.     parser->param_alloc = 256;
  563.     parser->param = xmalloc(parser->param_alloc);
  564.   }
  565.   else {
  566.     parser->param_alloc *= 2;
  567.     parser->param = xrealloc(parser->param, parser->param_alloc);
  568.   }
  569. }
  570.  
  571. static
  572. const char *param_save(parser)
  573.      struct parser *parser;
  574. {
  575.   char *s = alloc_bytes(parser->cat, parser->param_length + 1);
  576.   memcpy(s, parser->param, parser->param_length);
  577.   s[parser->param_length] = '\0';
  578.   return s;
  579. }
  580.  
  581. static
  582. char *alloc_bytes(catalog, n)
  583.      struct catalog *catalog;
  584.      SIZE_T n;
  585. {
  586.   char *tem;
  587.   if (n > catalog->block_spare) {
  588.     struct string_block *block;
  589.     SIZE_T block_size = n > BLOCK_SIZE ? n : BLOCK_SIZE;
  590.     block
  591.       = (struct string_block *)xmalloc(sizeof(struct string_block)
  592.                        + block_size);
  593.     block->next = catalog->blocks;
  594.     catalog->blocks = block;
  595.     catalog->block_ptr = (char *)(block + 1);
  596.     catalog->block_spare = block_size;
  597.   }
  598.   tem = catalog->block_ptr;
  599.   catalog->block_ptr += n;
  600.   catalog->block_spare -= n;
  601.   return tem;
  602. }
  603.  
  604.  
  605. /* Return 1 if the current parameter is equal to key. */
  606.  
  607. static
  608. int param_equal(parser, key)
  609.      struct parser *parser;
  610.      const char *key;
  611. {
  612.   const char *param = parser->param;
  613.   SIZE_T param_length = parser->param_length;
  614.   for (; param_length > 0; param++, param_length--, key++) {
  615.     unsigned char c;
  616.     if (*key == '\0')
  617.       return 0;
  618.     c = *param;
  619.     if (islower(c))
  620.       c = toupper(c);
  621.     if (c != (unsigned char)*key)
  622.       return 0;
  623.   }
  624.   return *key == '\0';
  625. }
  626.  
  627. /* Return 0 if it was a duplicate. */
  628.  
  629. static
  630. int hash_table_add(table, s, system_id, file_index)
  631.      struct hash_table *table;
  632.      const char *s;
  633.      const char *system_id;
  634.      int file_index;
  635. {
  636.   SIZE_T i;
  637.   struct hash_table_entry *p;
  638.  
  639.   if (table->size > 0) {
  640.     i = hash_table_start_index(table, s);
  641.     while (table->v[i] != 0)  {
  642.       if (strcmp(table->v[i]->key, s) == 0)
  643.     return 0;
  644.       if (i == 0)
  645.     i = table->size;
  646.       i--;
  647.     }
  648.   }
  649.   if (table->used >= table->used_limit) {
  650.     SIZE_T j;
  651.     struct hash_table_entry **old_table = table->v;
  652.     SIZE_T old_size = table->size;
  653.     if (old_size == 0) {
  654.       table->size = HASH_TABLE_INITIAL_SIZE;
  655.       table->used_limit = table->size/2;
  656.     }
  657.     else {
  658.       if (old_size > HASH_TABLE_MAX_SIZE/2) {
  659.     if (old_size == HASH_TABLE_MAX_SIZE)
  660.       return 0;        /* FIXME: give an error? */
  661.     table->size = HASH_TABLE_MAX_SIZE;
  662.     table->used_limit = HASH_TABLE_MAX_SIZE - 1;
  663.       }
  664.       else {
  665.     table->size = (old_size << 1);
  666.     table->used_limit = table->size/2;
  667.       }
  668.     }
  669.     table->v
  670.       = (struct hash_table_entry **)xmalloc(sizeof(struct hash_table_entry *)
  671.                         * table->size);
  672.     for (j = 0; j < table->size; j++)
  673.       table->v[j] = 0;
  674.     for (j = 0; j < old_size; j++)
  675.       if (old_table[j]) {
  676.     SIZE_T k = hash_table_start_index(table, old_table[j]->key);
  677.     while (table->v[k] != 0) {
  678.       if (k == 0)
  679.         k = table->size;
  680.       k--;
  681.     }
  682.     table->v[k] = old_table[j];
  683.       }
  684.     if (old_table)
  685.       free((UNIV)old_table);
  686.     i = hash_table_start_index(table, s);
  687.     while (table->v[i] != 0) {
  688.       if (i == 0)
  689.     i = table->size;
  690.       i--;
  691.     }
  692.   }
  693.   p = (struct hash_table_entry *)xmalloc(sizeof(struct hash_table_entry));
  694.   p->key = s;
  695.   p->system_id = system_id;
  696.   p->file_index = file_index;
  697.   table->v[i] = p;
  698.   table->used += 1;
  699.   return 1;
  700. }
  701.  
  702. static
  703. struct hash_table_entry *hash_table_lookup(table, s)
  704.      struct hash_table *table;
  705.      const char *s;
  706. {
  707.   if (table->size > 0) {
  708.     SIZE_T i;
  709.     i = hash_table_start_index(table, s);
  710.     while (table->v[i] != 0)  {
  711.       if (strcmp(table->v[i]->key, s) == 0)
  712.     return table->v[i];
  713.       if (i == 0)
  714.     i = table->size;
  715.       i--;
  716.     }
  717.   }
  718.   return 0;
  719. }
  720.  
  721. static
  722. struct hash_table_entry *hash_table_lookup_subst(table, subst_table, s)
  723.      struct hash_table *table;
  724.      const char *subst_table;
  725.      const char *s;
  726. {
  727.   SIZE_T i;
  728.   for (i = 0;  i < table->size; i++) {
  729.     struct hash_table_entry *p = table->v[i];
  730.     if (p && subst_equal(subst_table, s, p->key))
  731.       return p;
  732.   }
  733.   return 0;
  734. }
  735.  
  736. static
  737. VOID hash_table_init(p)
  738.      struct hash_table *p;
  739. {
  740.   p->v = 0;
  741.   p->size = 0;
  742.   p->used = 0;
  743.   p->used_limit = 0;
  744. }
  745.  
  746. static
  747. VOID hash_table_delete(p)
  748.      struct hash_table *p;
  749. {
  750.   if (p->v) {
  751.     SIZE_T i;
  752.     for (i = 0; i < p->size; i++)
  753.       if (p->v[i])
  754.     free(p->v[i]);
  755.     free(p->v);
  756.   }
  757. }
  758.  
  759. static
  760. SIZE_T hash_table_start_index(p, s)
  761.      struct hash_table *p;
  762.      const char *s;
  763. {
  764.   unsigned long h = 0;
  765.   while (*s)
  766.     h = (h << 5) + h + (unsigned char)*s++;
  767.   return (h & (p->size - 1));
  768. }
  769.  
  770. /* s1 has already been substituted; s2 has not */
  771.  
  772. static
  773. int subst_equal(subst_table, s1, s2)
  774.      const char *subst_table;
  775.      const char *s1;
  776.      const char *s2;
  777. {
  778.   for (; *s1 == subst_table[(unsigned char)*s2]; s1++, s2++)
  779.     if (*s1 == '\0')
  780.       return 1;
  781.   return 0;
  782. }
  783.  
  784. static
  785. VOID error(parser, err)
  786.      struct parser *parser;
  787.      enum catalog_error err;
  788. {
  789.   (*parser->cat->error_handler)(parser->filename,
  790.                 parser->newline_count + 1,
  791.                 err,
  792.                 (err >= FIRST_SYSTEM_ERROR
  793.                  ? CATALOG_SYSTEM_ERROR
  794.                  : 0),
  795.                 (err >= FIRST_SYSTEM_ERROR
  796.                  ? errno
  797.                  : 0));
  798. }
  799.  
  800. #ifdef MAIN
  801.  
  802. static const char *program_name;
  803.  
  804. #include "getopt.h"
  805.  
  806. static VOID usage P((void));
  807. static VOID out_of_memory P((void));
  808. static VOID handle_catalog_error P((const char *filename,
  809.                     unsigned long lineno,
  810.                     int error_number,
  811.                     unsigned flags,
  812.                     int sys_errno));
  813.  
  814. int main(argc, argv)
  815.      int argc;
  816.      char **argv;
  817. {
  818.   int entity_flag = 0;
  819.   enum catalog_decl_type entity_type = CATALOG_NO_DECL;
  820.   char *public_id = 0;
  821.   char *name = 0;
  822.   int exit_status;
  823.   int opt;
  824.   CATALOG catalog;
  825.   int i;
  826.   const char *file;
  827.   const char *system_id;
  828.  
  829.   program_name = argv[0];
  830.  
  831.   while ((opt = getopt(argc, argv, "edl")) != EOF)
  832.     switch (opt) {
  833.     case 'e':
  834.       entity_flag = 1;
  835.       entity_type = CATALOG_ENTITY_DECL;
  836.       break;
  837.     case 'd':
  838.       entity_flag = 1;
  839.       entity_type = CATALOG_DOCTYPE_DECL;
  840.       break;
  841.     case 'l':
  842.       entity_flag = 1;
  843.       entity_type = CATALOG_LINKTYPE_DECL;
  844.       break;
  845.     case '?':
  846.       usage();
  847.     }
  848.   if (argc - optind < 2)
  849.     usage();
  850.   if (entity_flag)
  851.     name = argv[optind];
  852.   else
  853.     public_id = argv[optind];
  854.  
  855.   catalog = catalog_create(handle_catalog_error);
  856.   for (i = optind + 1; i < argc; i++)
  857.     catalog_load_file(catalog, argv[i]);
  858.   if (catalog_lookup_entity(catalog, public_id, name, entity_type, (char *)0,
  859.                 &system_id, &file)) {
  860.     exit_status = 0;
  861.     fprintf(stderr, "%s (%s)\n", system_id, file);
  862.   }
  863.   else {
  864.     fprintf(stderr, "not found\n");
  865.     exit_status = 1;
  866.   }
  867.   catalog_delete(catalog);
  868.   return exit_status;
  869. }
  870.  
  871. static
  872. VOID usage()
  873. {
  874.   fprintf(stderr, "usage: %s [-e] [-d] [-l] id file ...\n",
  875.       program_name);
  876.   exit(1);
  877. }
  878.  
  879. static
  880. VOID handle_catalog_error(filename, lineno, error_number, flags, sys_errno)
  881.      const char *filename;
  882.      unsigned long lineno;
  883.      int error_number;
  884.      unsigned flags;
  885.      int sys_errno;
  886. {
  887.   fprintf(stderr, "%s:", program_name);
  888.   if (flags & CATALOG_SYSTEM_ERROR) {
  889.     putc(' ', stderr);
  890.     fprintf(stderr, catalog_error_text(error_number), filename);
  891.     putc('\n', stderr);
  892.   }
  893.   else
  894.     fprintf(stderr, "%s:%lu: %s\n", filename, lineno,
  895.         catalog_error_text(error_number));
  896.   fflush(stderr);
  897. }
  898.  
  899. UNIV xmalloc(n)
  900.      SIZE_T n;
  901. {
  902.   UNIV p = malloc(n);
  903.   if (!p)
  904.     out_of_memory();
  905.   return p;
  906. }
  907.  
  908. UNIV xrealloc(p, n)
  909.      UNIV p;
  910.      SIZE_T n;
  911. {
  912.   p = realloc(p, n);
  913.   if (!p)
  914.     out_of_memory();
  915.   return p;
  916. }
  917.  
  918. static
  919. VOID out_of_memory()
  920. {
  921.   fprintf(stderr, "%s: out of memory\n", program_name);
  922.   exit(1);
  923. }
  924.  
  925. #endif /* MAIN */
  926.