+traverse_enum_types (htab_trav callback, void *info)
+{
+ htab_traverse (enum_types, callback, info);
+}
+
+/* Process an "include" directive, starting with the optional space
+ after the "include". Read in the file and use HANDLE_DIRECTIVE
+ to process each unknown directive. LINENO is the line number on
+ which the "include" occured. */
+
+static void
+handle_include (int lineno, directive_handler_t handle_directive)
+{
+ const char *filename;
+ const char *old_filename;
+ int old_lineno;
+ char *pathname;
+ FILE *input_file, *old_file;
+
+ filename = read_string (false);
+ input_file = NULL;
+
+ /* If the specified file name is absolute, skip the include stack. */
+ if (!IS_ABSOLUTE_PATH (filename))
+ {
+ struct file_name_list *stackp;
+
+ /* Search the directory path, trying to open the file. */
+ for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
+ {
+ static const char sep[2] = { DIR_SEPARATOR, '\0' };
+
+ pathname = concat (stackp->fname, sep, filename, NULL);
+ input_file = fopen (pathname, "r");
+ if (input_file != NULL)
+ break;
+ free (pathname);
+ }
+ }
+
+ /* If we haven't managed to open the file yet, try combining the
+ filename with BASE_DIR. */
+ if (input_file == NULL)
+ {
+ if (base_dir)
+ pathname = concat (base_dir, filename, NULL);
+ else
+ pathname = xstrdup (filename);
+ input_file = fopen (pathname, "r");
+ }
+
+ if (input_file == NULL)
+ {
+ free (pathname);
+ error_with_line (lineno, "include file `%s' not found", filename);
+ return;
+ }
+
+ /* Save the old cursor. Note that the LINENO argument to this
+ function is the beginning of the include statement, while
+ read_md_lineno has already been advanced. */
+ old_file = read_md_file;
+ old_filename = read_md_filename;
+ old_lineno = read_md_lineno;
+
+ if (include_callback)
+ include_callback (pathname);
+
+ read_md_file = input_file;
+ read_md_filename = pathname;
+ handle_file (handle_directive);
+
+ /* Restore the old cursor. */
+ read_md_file = old_file;
+ read_md_filename = old_filename;
+ read_md_lineno = old_lineno;
+
+ /* Do not free the pathname. It is attached to the various rtx
+ queue elements. */
+}
+
+/* Process the current file, assuming that read_md_file and
+ read_md_filename are valid. Use HANDLE_DIRECTIVE to handle
+ unknown directives. */
+
+static void
+handle_file (directive_handler_t handle_directive)
+{
+ struct md_name directive;
+ int c, lineno;
+
+ read_md_lineno = 1;
+ while ((c = read_skip_spaces ()) != EOF)
+ {
+ lineno = read_md_lineno;
+ if (c != '(')
+ fatal_expected_char ('(', c);
+
+ read_name (&directive);
+ if (strcmp (directive.string, "define_constants") == 0)
+ handle_constants ();
+ else if (strcmp (directive.string, "define_enum") == 0)
+ handle_enum (lineno, true);
+ else if (strcmp (directive.string, "define_c_enum") == 0)
+ handle_enum (lineno, false);
+ else if (strcmp (directive.string, "include") == 0)
+ handle_include (lineno, handle_directive);
+ else if (handle_directive)
+ handle_directive (lineno, directive.string);
+ else
+ read_skip_construct (1, lineno);
+
+ c = read_skip_spaces ();
+ if (c != ')')
+ fatal_expected_char (')', c);
+ }
+ fclose (read_md_file);
+}
+
+/* Like handle_file, but for top-level files. Set up in_fname and
+ base_dir accordingly. */
+
+static void
+handle_toplevel_file (directive_handler_t handle_directive)
+{
+ const char *base;
+
+ in_fname = read_md_filename;
+ base = lbasename (in_fname);
+ if (base == in_fname)
+ base_dir = NULL;
+ else
+ base_dir = xstrndup (in_fname, base - in_fname);
+
+ handle_file (handle_directive);
+}
+
+/* Parse a -I option with argument ARG. */
+
+static void
+parse_include (const char *arg)
+{
+ struct file_name_list *dirtmp;
+
+ dirtmp = XNEW (struct file_name_list);
+ dirtmp->next = 0;
+ dirtmp->fname = arg;
+ *last_dir_md_include_ptr = dirtmp;
+ last_dir_md_include_ptr = &dirtmp->next;
+ if (strlen (dirtmp->fname) > max_include_len)
+ max_include_len = strlen (dirtmp->fname);
+}
+
+/* The main routine for reading .md files. Try to process all the .md
+ files specified on the command line and return true if no error occured.
+
+ ARGC and ARGV are the arguments to main.
+
+ PARSE_OPT, if nonnull, is passed all unknown command-line arguments.
+ It should return true if it recognizes the argument or false if a
+ generic error should be reported.
+
+ If HANDLE_DIRECTIVE is nonnull, the parser calls it for each
+ unknown directive, otherwise it just skips such directives.
+ See the comment above the directive_handler_t definition for
+ details about the callback's interface. */
+
+bool
+read_md_files (int argc, char **argv, bool (*parse_opt) (const char *),
+ directive_handler_t handle_directive)