Back to index

tetex-bin  3.0
Defines | Functions | Variables
node.c File Reference
#include "system.h"
#include "cmds.h"
#include "files.h"
#include "float.h"
#include "footnote.h"
#include "macro.h"
#include "makeinfo.h"
#include "node.h"
#include "html.h"
#include "sectioning.h"
#include "insertion.h"
#include "xml.h"

Go to the source code of this file.

Defines

#define MENU_STARTER   "* "

Functions

void init_tag_table (void)
static void write_tag_table_internal (int indirect_p)
void write_tag_table (char *filename)
static void write_tag_table_indirect (void)
static void normalize_node_name (char *string)
static char * get_node_token (int expand)
char * expand_node_name (char *node)
TAG_ENTRYfind_node (char *name)
static TAG_ENTRYfind_node_by_fname (char *fname)
static void remember_node_node_reference (char *node)
static void remember_node (char *node, char *prev, char *next, char *up, int position, int line_no, char *fname, int flags)
void remember_node_reference (char *node, int line, enum reftype type)
static void isolate_nodename (char *nodename)
char * glean_node_from_menu (int remember_ref, enum reftype ref_type)
void set_current_output_filename (const char *fname)
static void add_html_names (char *node)
void cm_node (void)
void cm_anchor (int arg)
static NODE_REFfind_node_reference (char *node, NODE_REF *ref_list)
void free_node_references (void)
void free_node_node_references (void)
int number_of_node (char *node)
static int validate (char *tag, int line, const char *label)
static const char * reftype_type_string (enum reftype type)
static void validate_other_references (NODE_REF *ref_list)
void validate_file (TAG_ENTRY *tag_table)
static int last_node_p (TAG_ENTRY *tags)
static char * enumerate_filename (char *pathname, char *basename, int number)
void clean_old_split_files (char *filename)
void split_file (char *filename, int size)

Variables

NODE_REFnode_references = NULL
NODE_REFnode_node_references = NULL
TAG_ENTRYtag_table = NULL
int node_number = -1
int node_order = 0
int current_section = 0
int outstanding_node = 0

Define Documentation

#define MENU_STARTER   "* "

Definition at line 422 of file node.c.


Function Documentation

static void add_html_names ( char *  node) [static]

Definition at line 491 of file node.c.

{
  char *tem = expand_node_name (node);
  char *otem = xstrdup (tem);

  /* Determine if the old and new schemes come up with different names;
     only output the old scheme if that is so.  We don't want to output
     the same name twice.  */
  canon_white (otem);
  {
    char *optr = otem;
    int need_old = 0;
    
    for (; *optr; optr++)
      {
        if (!cr_or_whitespace (*optr) && !URL_SAFE_CHAR (*optr))
          {
            need_old = 1;
            break;
          }
      }
    
    if (need_old)
      {
        add_word ("<a name=\"");
        add_anchor_name (otem, -1);  /* old anchor name conversion */
        add_word ("\"></a>\n");
      }
    free (otem);
  }

  /* Always output the new scheme.  */
  canon_white (tem);
  add_word ("<a name=\"");
  add_anchor_name (tem, 0);
  add_word ("\"></a>\n");

  free (tem);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void clean_old_split_files ( char *  filename)

Definition at line 1704 of file node.c.

{
  char *root_filename = filename_part (filename);
  char *root_pathname = pathname_part (filename);
  int i;

  /* We break as soon as we hit an inexistent file,
     so looping until large numbers is harmless.  */
  for (i = 1; i < 1000; i++)
    {
      struct stat st;
      char *check_file = enumerate_filename (root_pathname, root_filename, i);

      if (stat (check_file, &st) != 0)
        break;
      else if (!S_ISDIR (st.st_mode))
        {
          /* Give feedback if requested, removing a file is important.  */
          if (verbose_mode)
            printf (_("Removing %s\n"), check_file);

          /* Warn user that we cannot remove the file.  */
          if (unlink (check_file) != 0)
            warning (_("Can't remove file `%s': %s"), check_file, strerror (errno));
        }

      free (check_file);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void cm_anchor ( int  arg)

Definition at line 1099 of file node.c.

{
  char *anchor;
  char *fname_for_anchor = NULL;

  if (arg == END)
    return;

  /* Parse the anchor text.  */
  anchor = get_xref_token (1);

  /* Force all versions of "top" to be "Top". */
  normalize_node_name (anchor);

  /* In HTML mode, need to actually produce some output.  */
  if (html)
    {
      /* If this anchor is at the beginning of a new paragraph, make
        sure a new paragraph is indeed started.  */
      if (!paragraph_is_open)
       {
         if (!executing_string && html)
           html_output_head ();
         start_paragraph ();
         if (!in_fixed_width_font || in_menu || in_detailmenu)
           {
             insert_string ("<p>");
             in_paragraph = 1;
           }
       }
      add_word ("<a name=\"");
      add_anchor_name (anchor, 0);
      add_word ("\"></a>");
      if (splitting)
       {
         /* If we are splitting, cm_xref will produce a reference to
            a file whose name is derived from the anchor name.  So we
            must create a file when we see an @anchor, otherwise
            xref's to anchors won't work.  The file we create simply
            redirects to the file of this anchor's node.  */
         TAG_ENTRY *tag;

         fname_for_anchor = nodename_to_filename (anchor);
         /* See if the anchor name converted to a file name clashes
            with other anchors or nodes.  */
         tag = find_node_by_fname (fname_for_anchor);
         if (tag)
           {
             if ((tag->flags & TAG_FLAG_ANCHOR) != 0)
              line_error (_("Anchors `%s' and `%s' map to the same file name"),
                         anchor, tag->node);
             else
              line_error (_("Anchor `%s' and node `%s' map to the same file name"),
                         anchor, tag->node);
             line_error (_("@anchor command ignored; references to it will not work"));
             line_error (_("Rename this anchor or use the `--no-split' option"));
             free (fname_for_anchor);
             /* We will not be creating a file for this anchor, so
               set its name to NULL, so that remember_node stores a
               NULL and find_node_by_fname won't consider this
               anchor for clashes.  */
             fname_for_anchor = NULL;
           }
         else
           {
             char *dirname, *p;
             char filename[PATH_MAX];
             FILE *anchor_stream;

             dirname = pathname_part (current_output_filename);
             strcpy (filename, dirname);
             strcat (filename, fname_for_anchor);
             free (dirname);

             anchor_stream = fopen (filename, "w");
             if (anchor_stream == NULL)
              {
                fs_error (filename);
                xexit (1);
              }
             /* The HTML magic below will cause the browser to
               immediately go to the anchor's node's file.  Lynx
               seems not to support this redirection, but it looks
               like a bug in Lynx, and they can work around it by
               clicking on the link once more.  */
             fputs ("<meta http-equiv=\"refresh\" content=\"0; url=",
                   anchor_stream);
             /* Make the indirect link point to the current node's
               file and anchor's "<a name" label.  If we don't have
               a valid node name, refer to the current output file
               instead.  */
             if (current_node && *current_node)
              {
                char *fn, *tem;

                tem = expand_node_name (current_node);
                fn = nodename_to_filename (tem);
                free (tem);
                fputs (fn, anchor_stream);
                free (fn);
              }
             else
              {
                char *base = filename_part (current_output_filename);

                fputs (base, anchor_stream);
                free (base);
              }
             fputs ("#", anchor_stream);
             for (p = anchor; *p; p++)
              {
                if (*p == '&')
                  fputs ("&amp;", anchor_stream);
                else if (!URL_SAFE_CHAR (*p))
                  fprintf (anchor_stream, "%%%x", (unsigned char) *p);
                else
                  fputc (*p, anchor_stream);
              }
             fputs ("\">\n", anchor_stream);
             fclose (anchor_stream);
           }
       }
    }
  else if (xml)
    {
      xml_insert_element_with_attribute (ANCHOR, START, "name=\"%s\"", anchor);
      xml_insert_element (ANCHOR, END);
    }
  /* Save it in the tag table.  */
  remember_node (anchor, NULL, NULL, NULL,
                 output_position + output_paragraph_offset,
                 line_number, fname_for_anchor, TAG_FLAG_ANCHOR);
}

Here is the call graph for this function:

void cm_node ( void  )

Definition at line 539 of file node.c.

{
  static long epilogue_len = 0L;
  char *node, *prev, *next, *up;
  int new_node_pos, defaulting, this_section;
  int no_warn = 0;
  char *fname_for_this_node = NULL;
  char *tem;
  TAG_ENTRY *tag = NULL;

  if (strcmp (command, "nwnode") == 0)
    no_warn = TAG_FLAG_NO_WARN;

  /* Get rid of unmatched brace arguments from previous commands. */
  discard_braces ();

  /* There also might be insertions left lying around that haven't been
     ended yet.  Do that also. */
  discard_insertions (1);

  if (!html && !already_outputting_pending_notes)
    {
      close_paragraph ();
      output_pending_notes ();
    }

  new_node_pos = output_position;

  if (macro_expansion_output_stream && !executing_string)
    append_to_expansion_output (input_text_offset + 1);

  /* Do not collapse -- to -, etc., in node names.  */
  in_fixed_width_font++;

  /* While expanding the @node line, leave any non-macros
     intact, so that the macro-expanded output includes them.  */
  only_macro_expansion++;
  node = get_node_token (1);
  only_macro_expansion--;
  next = get_node_token (0);
  prev = get_node_token (0);
  up = get_node_token (0);

  if (html && splitting
      /* If there is a Top node, it always goes into index.html.  So
        don't start a new HTML file for Top.  */
      && (top_node_seen || strcasecmp (node, "Top") != 0))
    {
      /* We test *node here so that @node without a valid name won't
        start a new file name with a bogus name such as ".html".
        This could happen if we run under "--force", where we cannot
        simply bail out.  Continuing to use the same file sounds like
        the best we can do in such cases.  */
      if (current_output_filename && output_stream && *node)
       {
         char *fname_for_prev_node;

         if (current_node)
           {
             /* NOTE: current_node at this point still holds the name
               of the previous node.  */
             tem = expand_node_name (current_node);
             fname_for_prev_node = nodename_to_filename (tem);
             free (tem);
           }
         else /* could happen if their top node isn't named "Top" */
           fname_for_prev_node = filename_part (current_output_filename);
         tem = expand_node_name (node);
         fname_for_this_node = nodename_to_filename (tem);
         free (tem);
         /* Don't close current output file, if next output file is
             to have the same name.  This may happen at top level, or
             if two nodes produce the same file name under --split.  */
         if (FILENAME_CMP (fname_for_this_node, fname_for_prev_node) != 0)
           {
             long pos1 = 0;

             /* End the current split output file. */
             close_paragraph ();
             output_pending_notes ();
             start_paragraph ();
             /* Compute the length of the HTML file's epilogue.  We
               cannot know the value until run time, due to the
               text/binary nuisance on DOS/Windows platforms, where
               2 `\r' characters could be added to the epilogue when
               it is written in text mode.  */
             if (epilogue_len == 0)
              {
                flush_output ();
                pos1 = ftell (output_stream);
              }
             add_word ("</body></html>\n");
             close_paragraph ();
             if (epilogue_len == 0)
              epilogue_len = ftell (output_stream) - pos1;
             fclose (output_stream);
             output_stream = NULL;
              output_position = 0;
             tag = find_node_by_fname (fname_for_this_node);
           }
         free (fname_for_prev_node);
       }
    }

  filling_enabled = indented_fill = 0;
  if (!html || (html && splitting))
    current_footnote_number = 1;

  if (verbose_mode)
    printf (_("Formatting node %s...\n"), node);

  if (macro_expansion_output_stream && !executing_string)
    remember_itext (input_text, input_text_offset);

  /* Reset the line number in each node for Info output, so that
     index entries will save the line numbers of parent node.  */
  node_line_number = 0;

  no_indent = 1;
  if (xml)
    {
      xml_begin_document (current_output_filename);
      xml_begin_node ();
      if (!docbook)
       {
         xml_insert_element (NODENAME, START);
         if (macro_expansion_output_stream && !executing_string)
           me_execute_string (node);
         else
           execute_string ("%s", node);
         xml_insert_element (NODENAME, END);
       }
      else
       xml_node_id = xml_id (node);
    }
  else if (!no_headers && !html)
    {
      /* Emacs Info reader cannot grok indented escape sequence.  */
      kill_self_indent (-1);

      add_word_args ("\037\nFile: %s,  Node: ", pretty_output_filename);

      if (macro_expansion_output_stream && !executing_string)
        me_execute_string (node);
      else
        execute_string ("%s", node);
      filling_enabled = indented_fill = 0;
    }

  /* Check for defaulting of this node's next, prev, and up fields. */
  defaulting = (*next == 0 && *prev == 0 && *up == 0);

  this_section = what_section (input_text + input_text_offset, NULL);

  /* If we are defaulting, then look at the immediately following
     sectioning command (error if none) to determine the node's
     level.  Find the node that contains the menu mentioning this node
     that is one level up (error if not found).  That node is the "Up"
     of this node.  Default the "Next" and "Prev" from the menu. */
  if (defaulting)
    {
      NODE_REF *last_ref = NULL;
      NODE_REF *ref = node_references;

      if (this_section < 0 && !STREQ (node, "Top"))
        {
          char *polite_section_name = "top";
          int i;

          for (i = 0; section_alist[i].name; i++)
            if (section_alist[i].level == current_section + 1)
              {
                polite_section_name = section_alist[i].name;
                break;
              }

          line_error
            (_("Node `%s' requires a sectioning command (e.g., %c%s)"),
             node, COMMAND_PREFIX, polite_section_name);
        }
      else
        {
          if (strcmp (node, "Top") == 0)
            {
              /* Default the NEXT pointer to be the first menu item in
                 this node, if there is a menu in this node.  We have to
                 try very hard to find the menu, as it may be obscured
                 by execution_strings which are on the filestack.  For
                 every member of the filestack which has a FILENAME
                 member which is identical to the current INPUT_FILENAME,
                 search forward from that offset. */
              int saved_input_text_offset = input_text_offset;
              int saved_input_text_length = input_text_length;
              char *saved_input_text = input_text;
              FSTACK *next_file = filestack;

              int orig_offset, orig_size;

              int bye_offset = search_forward ("\n@bye", input_text_offset);

              /* No matter what, make this file point back at `(dir)'. */
              free (up);
              up = xstrdup ("(dir)"); /* html fixxme */

              while (1)
                {
                  orig_offset = input_text_offset;
                  orig_size =
                    search_forward (node_search_string, orig_offset);

                  if (orig_size < 0)
                    orig_size = input_text_length;

                  input_text_offset = search_forward ("\n@menu", orig_offset);
                  if (input_text_offset > -1
                      && (bye_offset > -1 && input_text_offset < bye_offset)
                      && cr_or_whitespace (input_text[input_text_offset + 6]))
                    {
                      char *nodename_from_menu = NULL;

                      input_text_offset =
                        search_forward ("\n* ", input_text_offset);

                      if (input_text_offset != -1)
                        nodename_from_menu = glean_node_from_menu (0, 0);

                      if (nodename_from_menu)
                        {
                          free (next);
                          next = nodename_from_menu;
                          break;
                        }
                    }

                  /* We got here, so it hasn't been found yet.  Try
                     the next file on the filestack if there is one. */
                  if (next_file
                      && FILENAME_CMP (next_file->filename, input_filename)
                          == 0)
                    {
                      input_text = next_file->text;
                      input_text_offset = next_file->offset;
                      input_text_length = next_file->size;
                      next_file = next_file->next;
                    }
                  else
                    { /* No more input files to check. */
                      break;
                    }
                }

              input_text = saved_input_text;
              input_text_offset = saved_input_text_offset;
              input_text_length = saved_input_text_length;
            }
        }

      /* Fix the level of the menu references in the Top node, iff it
         was declared with @top, and no subsequent reference was found. */
      if (top_node_seen && !non_top_node_seen)
        {
          /* Then this is the first non-@top node seen. */
          int level;

          level = set_top_section_level (this_section - 1);
          non_top_node_seen = 1;

          while (ref)
            {
              if (ref->section == level)
                ref->section = this_section - 1;
              ref = ref->next;
            }

          ref = node_references;
        }

      while (ref)
        {
          if (ref->section == (this_section - 1)
              && ref->type == menu_reference
              && strcmp (ref->node, node) == 0)
            {
              char *containing_node = ref->containing_node;

              free (up);
              up = xstrdup (containing_node);

              if (last_ref
                  && last_ref->type == menu_reference
                  && strcmp (last_ref->containing_node, containing_node) == 0)
                {
                  free (next);
                  next = xstrdup (last_ref->node);
                }

              while (ref->section == this_section - 1
                     && ref->next
                     && ref->next->type != menu_reference)
                ref = ref->next;

              if (ref->next && ref->type == menu_reference
                  && strcmp (ref->next->containing_node, containing_node) == 0)
                {
                  free (prev);
                  prev = xstrdup (ref->next->node);
                }
              else if (!ref->next
                       && strcasecmp (ref->containing_node, "Top") == 0)
                {
                  free (prev);
                  prev = xstrdup (ref->containing_node);
                }
              break;
            }
          last_ref = ref;
          ref = ref->next;
        }
    }

  /* Insert the correct args if we are expanding macros, and the node's
     pointers weren't defaulted. */
  if (macro_expansion_output_stream && !executing_string && !defaulting)
    {
      char *temp;
      int op_orig = output_paragraph_offset;
      int meta_pos_orig = meta_char_pos;
      int extra = html ? strlen (node) : 0;

      temp = xmalloc (7 + extra + strlen (next) + strlen (prev) + strlen (up));
      sprintf (temp, "%s, %s, %s, %s", html ? node : "", next, prev, up);
      me_execute_string (temp);
      free (temp);

      output_paragraph_offset = op_orig;
      meta_char_pos = meta_pos_orig;
    }

  if (!*node)
    {
      line_error (_("No node name specified for `%c%s' command"),
                  COMMAND_PREFIX, command);
      free (node);
      free (next); next = NULL;
      free (prev); prev= NULL;
      free (up);   up = NULL;
      node_number++;            /* else it doesn't get bumped */
    }
  else
    {
      if (!*next) { free (next); next = NULL; }
      if (!*prev) { free (prev); prev = NULL; }
      if (!*up)   { free (up);   up = NULL;   }
      remember_node (node, prev, next, up, new_node_pos, line_number,
                   fname_for_this_node, no_warn);
      outstanding_node = 1;
    }

  if (html)
    {
      if (splitting && *node && output_stream == NULL)
        {
         char *dirname;
         char filename[PATH_MAX];

         dirname = pathname_part (current_output_filename);
         strcpy (filename, dirname);
         strcat (filename, fname_for_this_node);
         free (dirname);

         /* See if the node name converted to a file name clashes
            with other nodes or anchors.  If it clashes with an
            anchor, we complain and nuke that anchor's file.  */
         if (!tag)
           {
             output_stream = fopen (filename, "w");
             html_output_head_p = 0; /* so that we generate HTML preamble */
             html_output_head ();
           }
         else if ((tag->flags & TAG_FLAG_ANCHOR) != 0)
           {
             line_error (_("Anchor `%s' and node `%s' map to the same file name"),
                       tag->node, node);
             file_line_error (tag->filename, tag->line_no,
                            _("This @anchor command ignored; references to it will not work"));
             file_line_error (tag->filename, tag->line_no,
                            _("Rename this anchor or use the `--no-split' option"));
             /* Nuke the file name recorded in anchor's tag.
               Since we are about to nuke the file itself, we
               don't want find_node_by_fname to consider this
               anchor anymore.  */
             free (tag->html_fname);
             tag->html_fname = NULL;
             output_stream = fopen (filename, "w");
             html_output_head_p = 0; /* so that we generate HTML preamble */
             html_output_head ();
           }
         else
           {
             /* This node's file name clashes with another node.
               We put them both on the same file.  */
             output_stream = fopen (filename, "r+");
             if (output_stream)
              {
                static char html_end[] = "</body></html>\n";
                char end_line[sizeof(html_end)];
                int fpos = fseek (output_stream, -epilogue_len,
                                SEEK_END);

                if (fpos < 0
                    || fgets (end_line, sizeof (html_end),
                            output_stream) == NULL
                    /* Paranoia: did someone change the way HTML
                      files are finished up?  */
                    || strcasecmp (end_line, html_end) != 0)
                  {
                    line_error (_("Unexpected string at end of split-HTML file `%s'"),
                              fname_for_this_node);
                    fclose (output_stream);
                    xexit (1);
                  }
                fseek (output_stream, -epilogue_len, SEEK_END);
              }
           }
          if (output_stream == NULL)
            {
              fs_error (filename);
              xexit (1);
            }
          set_current_output_filename (filename);
        }

      if (!splitting && no_headers)
       { /* cross refs need a name="#anchor" even if not writing headers */ 
          add_html_names (node);
       }

      if (splitting || !no_headers)
        { /* Navigation bar. */
          add_html_block_elt ("<div class=\"node\">\n");
          /* The <p> avoids the links area running on with old Lynxen. */
          add_word_args ("<p>%s\n", splitting ? "" : "<hr>");

          /* In the split HTML case, the filename is wrong for the 
             old-style converted names, but we'll add them anyway, for
             consistency.  (And we need them in the normal (not
             no_headers) nonsplit case.)  */
          add_html_names (node);

          if (next)
            {
              tem = expansion (next, 0);
             add_word ((char *) _("Next:"));
              add_word ("&nbsp;");
              
             add_word ("<a rel=\"next\" accesskey=\"n\" href=\"");
             add_anchor_name (tem, 1);
              tem = escape_string (tem);
             add_word_args ("\">%s</a>", tem);
             
              free (tem);

             if (prev || up)
              add_word (",\n");
            }
          if (prev)
            {
              tem = expansion (prev, 0);
             add_word ((char *) _("Previous:"));
              add_word ("&nbsp;");
             add_word ("<a rel=\"previous\" accesskey=\"p\" href=\"");
             add_anchor_name (tem, 1);
              tem = escape_string (tem);
             add_word_args ("\">%s</a>", tem);
              free (tem);

             if (up)
              add_word (",\n");
            }
          if (up)
            {
              tem = expansion (up, 0);
             add_word ((char *) _("Up:"));
              add_word ("&nbsp;");
             add_word ("<a rel=\"up\" accesskey=\"u\" href=\"");
             add_anchor_name (tem, 1);
              tem = escape_string (tem);
             add_word_args ("\">%s</a>", tem);
              free (tem);
            }
          /* html fixxme: we want a `top' or `contents' link here.  */

          add_word_args ("\n%s\n", splitting ? "<hr>" : "");
         add_word ("</div>\n");
        }
    }
  else if (docbook)
    ;
  else if (xml)
    {
      if (next)
       {
         xml_insert_element (NODENEXT, START);
         execute_string ("%s", next);
         xml_insert_element (NODENEXT, END);
       }
      if (prev)
       {
         xml_insert_element (NODEPREV, START);
         execute_string ("%s", prev);
         xml_insert_element (NODEPREV, END);
       }
      if (up)
       {
         xml_insert_element (NODEUP, START);
         execute_string ("%s", up);
         xml_insert_element (NODEUP, END);
       }
    }
  else if (!no_headers)
    {
      if (macro_expansion_output_stream)
        me_inhibit_expansion++;

      /* These strings are not translatable.  */
      if (next)
        {
          execute_string (",  Next: %s", next);
          filling_enabled = indented_fill = 0;
        }
      if (prev)
        {
          execute_string (",  Prev: %s", prev);
          filling_enabled = indented_fill = 0;
        }
      if (up)
        {
          execute_string (",  Up: %s", up);
          filling_enabled = indented_fill = 0;
        }
      if (macro_expansion_output_stream)
        me_inhibit_expansion--;
    }

  close_paragraph ();
  no_indent = 0;

  /* Change the section only if there was a sectioning command. */
  if (this_section >= 0)
    current_section = this_section;

  if (current_node && STREQ (current_node, "Top"))
    top_node_seen = 1;

  filling_enabled = 1;
  in_fixed_width_font--;
}
static char* enumerate_filename ( char *  pathname,
char *  basename,
int  number 
) [static]

Definition at line 1665 of file node.c.

{
  /* Do we need to generate names of subfiles which don't exceed 8+3 limits? */
  const int dos_file_names = !HAVE_LONG_FILENAMES (pathname ? pathname : ".");
  unsigned name_len = strlen (basename);
  char *filename = xmalloc (10 + strlen (pathname) + name_len);
  char *base_filename = xmalloc (10 + name_len);

  sprintf (base_filename, "%s-%d", basename, number);

  if (dos_file_names)
    {
      char *dot = strchr (base_filename, '.');
      unsigned base_len = strlen (base_filename);

      if (dot)
        { /* Make foobar.i1, .., foobar.i99, foobar.100, ... */
          dot[1] = 'i';
          memmove (number <= 99 ? dot + 2 : dot + 1,
              base_filename + name_len + 1,
              strlen (base_filename + name_len + 1) + 1);
        }
      else if (base_len > 8)
        {
          /* Make foobar-1, .., fooba-10, .., foob-100, ... */
          unsigned numlen = base_len - name_len;

          memmove (base_filename + 8 - numlen, base_filename + name_len, numlen + 1);
        }
    }

  sprintf (filename, "%s%s", pathname, base_filename);

  return filename;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* expand_node_name ( char *  node)

Definition at line 165 of file node.c.

{
  char *result = node;

  if (node)
    {
      /* Don't expand --, `` etc., in case somebody will want
         to print the result.  */
      in_fixed_width_font++;
      result = expansion (node, 0);
      in_fixed_width_font--;
      fix_whitespace (result);
      normalize_node_name (result);
    }
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

TAG_ENTRY* find_node ( char *  name)

Definition at line 185 of file node.c.

{
  TAG_ENTRY *tag = tag_table;
  char *expanded_name;
  char n1 = name[0];

  while (tag)
    {
      if (tag->node[0] == n1 && strcmp (tag->node, name) == 0)
        return tag;
      tag = tag->next_ent;
    }

  if (!expensive_validation)
    return NULL;

  /* Try harder.  Maybe TAG_TABLE has the expanded NAME, or maybe NAME
     is expanded while TAG_TABLE has its unexpanded form.  This may
     slow down the search, but if they want this feature, let them
     pay!  If they want it fast, they should write every node name
     consistently (either always expanded or always unexpaned).  */
  expanded_name = expand_node_name (name);
  for (tag = tag_table; tag; tag = tag->next_ent)
    {
      if (STREQ (tag->node, expanded_name))
        break;
      /* If the tag name doesn't have the command prefix, there's no
         chance it could expand into anything but itself.  */
      if (strchr (tag->node, COMMAND_PREFIX))
        {
          char *expanded_node = expand_node_name (tag->node);

          if (STREQ (expanded_node, expanded_name))
            {
              free (expanded_node);
              break;
            }
          free (expanded_node);
        }
    }
  free (expanded_name);
  return tag;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static TAG_ENTRY* find_node_by_fname ( char *  fname) [static]

Definition at line 233 of file node.c.

{
  TAG_ENTRY *tag = tag_table;
  while (tag)
    {
      if (tag->html_fname && FILENAME_CMP (tag->html_fname, fname) == 0)
       return tag;
      tag = tag->next_ent;
    }

  return tag;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static NODE_REF* find_node_reference ( char *  node,
NODE_REF ref_list 
) [static]

Definition at line 1235 of file node.c.

{
  NODE_REF *orig_ref_list = ref_list;
  char *expanded_node;

  while (ref_list)
    {
      if (strcmp (node, ref_list->node) == 0)
        break;
      ref_list = ref_list->next;
    }

  if (ref_list || !expensive_validation)
    return ref_list;

  /* Maybe NODE is not expanded yet.  This may be SLOW.  */
  expanded_node = expand_node_name (node);
  for (ref_list = orig_ref_list; ref_list; ref_list = ref_list->next)
    {
      if (STREQ (expanded_node, ref_list->node))
        break;
      if (strchr (ref_list->node, COMMAND_PREFIX))
        {
          char *expanded_ref = expand_node_name (ref_list->node);

          if (STREQ (expanded_node, expanded_ref))
            {
              free (expanded_ref);
              break;
            }
          free (expanded_ref);
        }
    }
  free (expanded_node);
  return ref_list;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1291 of file node.c.

{
  NODE_REF *list, *temp;

  list = node_references;

  while (list)
    {
      temp = list;
      free (list->node);
      list = list->next;
      free (temp);
    }
  node_node_references = NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1273 of file node.c.

{
  NODE_REF *list, *temp;

  list = node_references;

  while (list)
    {
      temp = list;
      free (list->node);
      free (list->containing_node);
      list = list->next;
      free (temp);
    }
  node_references = NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* get_node_token ( int  expand) [static]

Definition at line 145 of file node.c.

{
  char *string;

  get_until_in_line (expand, ",", &string);

  if (curchar () == ',')
    input_text_offset++;

  fix_whitespace (string);

  /* Force all versions of "top" to be "Top". */
  normalize_node_name (string);

  return string;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* glean_node_from_menu ( int  remember_ref,
enum reftype  ref_type 
)

Definition at line 424 of file node.c.

{
  int i, orig_offset = input_text_offset;
  char *nodename;
  char *line, *expanded_line;
  char *old_input = input_text;
  int old_size = input_text_length;

  if (strncmp (&input_text[input_text_offset + 1],
               MENU_STARTER,
               strlen (MENU_STARTER)) != 0)
    return NULL;
  else
    input_text_offset += strlen (MENU_STARTER) + 1;

  /* The menu entry might include macro calls, so we need to expand them.  */
  get_until ("\n", &line);
  only_macro_expansion++;       /* only expand macros in menu entries */
  expanded_line = expansion (line, 0);
  only_macro_expansion--;
  free (line);
  input_text = expanded_line;
  input_text_offset = 0;
  input_text_length = strlen (expanded_line);

  get_until_in_line (0, ":", &nodename);
  if (curchar () == ':')
    input_text_offset++;

  if (curchar () != ':')
    {
      free (nodename);
      get_until_in_line (0, "\n", &nodename);
      isolate_nodename (nodename);
    }

  input_text = old_input;
  input_text_offset = orig_offset;
  input_text_length = old_size;
  free (expanded_line);
  fix_whitespace (nodename);
  normalize_node_name (nodename);
  i = strlen (nodename);
  if (i && nodename[i - 1] == ':')
    nodename[i - 1] = 0;

  if (remember_ref)
    remember_node_reference (nodename, line_number, ref_type);

  return nodename;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 47 of file node.c.

{
  while (tag_table)
    {
      TAG_ENTRY *temp = tag_table;
      free (temp->node);
      free (temp->prev);
      free (temp->next);
      free (temp->up);
      tag_table = tag_table->next_ent;
      free (temp);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void isolate_nodename ( char *  nodename) [static]

Definition at line 365 of file node.c.

{
  int i, c;
  int paren_seen, paren;

  if (!nodename)
    return;

  canon_white (nodename);
  paren_seen = paren = i = 0;

  if (*nodename == '.' || !*nodename)
    {
      *nodename = 0;
      return;
    }

  if (*nodename == '(')
    {
      paren++;
      paren_seen++;
      i++;
    }

  for (; (c = nodename[i]); i++)
    {
      if (paren)
        {
          if (c == '(')
            paren++;
          else if (c == ')')
            paren--;

          continue;
        }

      /* If the character following the close paren is a space, then this
         node has no more characters associated with it. */
      if (c == '\t' ||
          c == '\n' ||
          c == ','  ||
          ((paren_seen && nodename[i - 1] == ')') &&
           (c == ' ' || c == '.')) ||
          (c == '.' &&
           ((!nodename[i + 1] ||
             (cr_or_whitespace (nodename[i + 1])) ||
             (nodename[i + 1] == ')')))))
        break;
    }
  nodename[i] = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int last_node_p ( TAG_ENTRY tags) [static]

Definition at line 1646 of file node.c.

{
  int last = 1;
  while (tags->next_ent) {
    tags = tags->next_ent;
    if (tags->flags & TAG_FLAG_ANCHOR)
      ;
    else
      {
        last = 0;
        break;
      }
  }

  return last;
}

Here is the caller graph for this function:

static void normalize_node_name ( char *  string) [static]

Definition at line 138 of file node.c.

{
  if (strcasecmp (string, "Top") == 0)
    strcpy (string, "Top");
}

Here is the call graph for this function:

Here is the caller graph for this function:

int number_of_node ( char *  node)

Definition at line 1310 of file node.c.

{
  NODE_REF *temp_ref;
  TAG_ENTRY *temp_node = find_node (node);

  if (temp_node)
    return temp_node->number;
  else if ((temp_ref = find_node_reference (node, node_references)))
    return temp_ref->number;
  else if ((temp_ref = find_node_reference (node, node_node_references)))
    return temp_ref->number;
  else
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static const char* reftype_type_string ( enum reftype  type) [static]

Definition at line 1358 of file node.c.

{
  switch (type)
    {
    case menu_reference:
      return _("Menu");
    case followed_reference:
      return _("Cross");
    default:
      return "Internal-bad-reference-type";
    }
}

Here is the caller graph for this function:

static void remember_node ( char *  node,
char *  prev,
char *  next,
char *  up,
int  position,
int  line_no,
char *  fname,
int  flags 
) [static]

Definition at line 271 of file node.c.

{
  /* Check for existence of this tag already. */
  if (validating)
    {
      TAG_ENTRY *tag = find_node (node);
      if (tag)
        {
          line_error (_("Node `%s' previously defined at line %d"),
                      node, tag->line_no);
          return;
        }
    }

  if (!(flags & TAG_FLAG_ANCHOR))
    {
      /* Make this the current node. */
      current_node = node;
    }

  /* Add it to the list. */
  {
    int number = number_of_node (node);

    TAG_ENTRY *new = xmalloc (sizeof (TAG_ENTRY));
    new->node = node;
    new->prev = prev;
    new->next = next;
    new->up = up;
    new->position = position;
    new->line_no = line_no;
    new->filename = node_filename;
    new->touched = 0;
    new->flags = flags;
    if (number)
      new->number = number;     /* Already assigned. */
    else
      {
        node_number++;
        new->number = node_number;
      }
    if (fname)
      new->html_fname = fname;
    else
      /* This happens for Top node under split-HTML, for example.  */
      new->html_fname
       = normalize_filename (filename_part (current_output_filename));
    new->next_ent = tag_table;

    /* Increment the order counter, and save it.  */
    node_order++;
    new->order = node_order;

    tag_table = new;
  }

  if (html)
    { /* Note the references to the next etc. nodes too.  */
      remember_node_node_reference (next);
      remember_node_node_reference (prev);
      remember_node_node_reference (up);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void remember_node_node_reference ( char *  node) [static]

Definition at line 249 of file node.c.

{
  NODE_REF *temp = xmalloc (sizeof (NODE_REF));
  int number;

  if (!node) return;
  temp->next = node_node_references;
  temp->node = xstrdup (node);
  temp->type = followed_reference;
  number = number_of_node (node);
  if (number)
    temp->number = number;      /* Already assigned. */
  else
    {
      node_number++;
      temp->number = node_number;
    }
  node_node_references = temp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void remember_node_reference ( char *  node,
int  line,
enum reftype  type 
)

Definition at line 341 of file node.c.

{
  NODE_REF *temp = xmalloc (sizeof (NODE_REF));
  int number = number_of_node (node);

  temp->next = node_references;
  temp->node = xstrdup (node);
  temp->line_no = line;
  temp->section = current_section;
  temp->type = type;
  temp->containing_node = xstrdup (current_node ? current_node : "");
  temp->filename = node_filename;
  if (number)
    temp->number = number;      /* Already assigned. */
  else
    {
      node_number++;
      temp->number = node_number;
    }

  node_references = temp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 478 of file node.c.

{
  if (current_output_filename)
    free (current_output_filename);
  current_output_filename = xstrdup (fname);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void split_file ( char *  filename,
int  size 
)

Definition at line 1741 of file node.c.

{
  char *root_filename, *root_pathname;
  char *the_file;
  struct stat fileinfo;
  long file_size;
  char *the_header;
  int header_size;

  /* Can only do this to files with tag tables. */
  if (!tag_table)
    return;

  if (size == 0)
    size = DEFAULT_SPLIT_SIZE;

  if ((stat (filename, &fileinfo) != 0)
      || (((long) fileinfo.st_size) < size))
    return;
  file_size = (long) fileinfo.st_size;

  the_file = find_and_load (filename, 0);
  if (!the_file)
    return;

  root_filename = filename_part (filename);
  root_pathname = pathname_part (filename);

  if (!root_pathname)
    root_pathname = xstrdup ("");

  /* Start splitting the file.  Walk along the tag table
     outputting sections of the file.  When we have written
     all of the nodes in the tag table, make the top-level
     pointer file, which contains indirect pointers and
     tags for the nodes. */
  {
    int which_file = 1;
    TAG_ENTRY *tags = tag_table;
    char *indirect_info = NULL;

    /* Maybe we want a Local Variables section.  */
    char *trailer = info_trailer ();
    int trailer_len = trailer ? strlen (trailer) : 0;

    /* Remember the `header' of this file.  The first tag in the file is
       the bottom of the header; the top of the file is the start. */
    the_header = xmalloc (1 + (header_size = tags->position));
    memcpy (the_header, the_file, header_size);

    while (tags)
      {
        int file_top, file_bot, limit;

        /* Have to include the Control-_. */
        file_top = file_bot = tags->position;
        limit = file_top + size;

        /* If the rest of this file is only one node, then
           that is the entire subfile. */
        if (last_node_p (tags))
          {
            int i = tags->position + 1;
            char last_char = the_file[i];

            while (i < file_size)
              {
                if ((the_file[i] == '\037') &&
                    ((last_char == '\n') ||
                     (last_char == '\014')))
                  break;
                else
                  last_char = the_file[i];
                i++;
              }
            file_bot = i;
            tags = tags->next_ent;
            goto write_region;
          }

        /* Otherwise, find the largest number of nodes that can fit in
           this subfile. */
        for (; tags; tags = tags->next_ent)
          {
            if (last_node_p (tags))
              {
                /* This entry is the last node.  Search forward for the end
                   of this node, and that is the end of this file. */
                int i = tags->position + 1;
                char last_char = the_file[i];

                while (i < file_size)
                  {
                    if ((the_file[i] == '\037') &&
                        ((last_char == '\n') ||
                         (last_char == '\014')))
                      break;
                    else
                      last_char = the_file[i];
                    i++;
                  }
                file_bot = i;

                if (file_bot < limit)
                  {
                    tags = tags->next_ent;
                    goto write_region;
                  }
                else
                  {
                    /* Here we want to write out everything before the last
                       node, and then write the last node out in a file
                       by itself. */
                    file_bot = tags->position;
                    goto write_region;
                  }
              }

            /* Write region only if this was a node, not an anchor.  */
            if (tags->next_ent->position > limit
                && !(tags->flags & TAG_FLAG_ANCHOR))
              {
                if (tags->position == file_top)
                  tags = tags->next_ent;

                file_bot = tags->position;

              write_region:
                {
                  int fd;
                  char *split_filename = enumerate_filename (root_pathname,
                      root_filename, which_file);
                  char *split_basename = filename_part (split_filename);

                  fd = open (split_filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
                  if (fd < 0
                      || write (fd, the_header, header_size) != header_size
                      || write (fd, the_file + file_top, file_bot - file_top)
                         != (file_bot - file_top)
                      || (trailer_len
                          && write (fd, trailer, trailer_len) != trailer_len)
                      || close (fd) < 0)
                    {
                      perror (split_filename);
                      if (fd != -1)
                        close (fd);
                      xexit (1);
                    }

                  if (!indirect_info)
                    {
                      indirect_info = the_file + file_top;
                      sprintf (indirect_info, "\037\nIndirect:\n");
                      indirect_info += strlen (indirect_info);
                    }

                  sprintf (indirect_info, "%s: %d\n",
                           split_basename, file_top);

                  free (split_basename);
                  free (split_filename);
                  indirect_info += strlen (indirect_info);
                  which_file++;
                  break;
                }
              }
          }
      }

    /* We have sucessfully created the subfiles.  Now write out the
       original again.  We must use `output_stream', or
       write_tag_table_indirect () won't know where to place the output. */
    output_stream = fopen (filename, "w");
    if (!output_stream)
      {
        perror (filename);
        xexit (1);
      }

    {
      int distance = indirect_info - the_file;
      fwrite (the_file, 1, distance, output_stream);

      /* Inhibit newlines. */
      paragraph_is_open = 0;

      /* Write the indirect tag table.  */
      write_tag_table_indirect ();

      /* preserve local variables in info output.  */
      if (trailer)
        {
          fwrite (trailer, 1, trailer_len, output_stream);
          free (trailer);
        }

      fclose (output_stream);
      free (the_header);
      free (the_file);
      return;
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int validate ( char *  tag,
int  line,
const char *  label 
) [static]

Definition at line 1332 of file node.c.

{
  TAG_ENTRY *result;

  /* If there isn't a tag to verify, or if the tag is in another file,
     then it must be okay. */
  if (!tag || !*tag || *tag == '(')
    return 1;

  /* Otherwise, the tag must exist. */
  result = find_node (tag);

  if (!result)
    {
      line_number = line;
      line_error (_("%s reference to nonexistent node `%s' (perhaps incorrect sectioning?)"), label, tag);
      return 0;
    }
  result->touched++;
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void validate_file ( TAG_ENTRY tag_table)

Definition at line 1401 of file node.c.

{
  char *old_input_filename = input_filename;
  TAG_ENTRY *tags = tag_table;

  while (tags)
    {
      TAG_ENTRY *temp_tag;
      char *tem1, *tem2;

      input_filename = tags->filename;
      line_number = tags->line_no;

      /* If this is a "no warn" node, don't validate it in any way. */
      if (tags->flags & TAG_FLAG_NO_WARN)
        {
          tags = tags->next_ent;
          continue;
        }

      /* If this node has a Next, then make sure that the Next exists. */
      if (tags->next)
        {
          validate (tags->next, tags->line_no, _("Next"));

          /* If the Next node exists, and there is no Up, then make sure
             that the Prev of the Next points back.  But do nothing if
             we aren't supposed to issue warnings about this node. */
          temp_tag = find_node (tags->next);
          if (temp_tag && !(temp_tag->flags & TAG_FLAG_NO_WARN))
            {
              char *prev = temp_tag->prev;
              int you_lose = !prev || !STREQ (prev, tags->node);

              if (you_lose && expensive_validation)
                {
                  tem1 = expand_node_name (prev);
                  tem2 = expand_node_name (tags->node);

                  if (tem1 && tem2 && STREQ (tem1, tem2))
                    you_lose = 0;
                  free (tem1);
                  free (tem2);
                }
              if (you_lose)
                {
                  line_error (_("Next field of node `%s' not pointed to (perhaps incorrect sectioning?)"),
                              tags->node);
                  file_line_error (temp_tag->filename, temp_tag->line_no,
                               _("This node (%s) has the bad Prev"),
                               temp_tag->node);
                  temp_tag->flags |= TAG_FLAG_PREV_ERROR;
                }
            }
        }

      /* Validate the Prev field if there is one, and we haven't already
         complained about it in some way.  You don't have to have a Prev
         field at this stage. */
      if (!(tags->flags & TAG_FLAG_PREV_ERROR) && tags->prev)
        {
          int valid_p = validate (tags->prev, tags->line_no, _("Prev"));

          if (!valid_p)
            tags->flags |= TAG_FLAG_PREV_ERROR;
          else
            { /* If the Prev field is not the same as the Up field,
                 then the node pointed to by the Prev field must have
                 a Next field which points to this node. */
              int prev_equals_up = !tags->up || STREQ (tags->prev, tags->up);

              if (!prev_equals_up && expensive_validation)
                {
                  tem1 = expand_node_name (tags->prev);
                  tem2 = expand_node_name (tags->up);
                  prev_equals_up = STREQ (tem1, tem2);
                  free (tem1);
                  free (tem2);
                }
              if (!prev_equals_up)
                {
                  temp_tag = find_node (tags->prev);

                  /* If we aren't supposed to issue warnings about the
                     target node, do nothing. */
                  if (!temp_tag || (temp_tag->flags & TAG_FLAG_NO_WARN))
                    /* Do nothing. */ ;
                  else
                    {
                      int you_lose = !temp_tag->next
                        || !STREQ (temp_tag->next, tags->node);

                      if (temp_tag->next && you_lose && expensive_validation)
                        {
                          tem1 = expand_node_name (temp_tag->next);
                          tem2 = expand_node_name (tags->node);
                          if (STREQ (tem1, tem2))
                            you_lose = 0;
                          free (tem1);
                          free (tem2);
                        }
                      if (you_lose)
                        {
                          line_error
                            (_("Prev field of node `%s' not pointed to"),
                             tags->node);
                          file_line_error (temp_tag->filename,
                                      temp_tag->line_no,
                                      _("This node (%s) has the bad Next"),
                                      temp_tag->node);
                          temp_tag->flags |= TAG_FLAG_NEXT_ERROR;
                        }
                    }
                }
            }
        }

      if (!tags->up
          && !(tags->flags & TAG_FLAG_ANCHOR)
          && strcasecmp (tags->node, "Top") != 0)
        line_error (_("`%s' has no Up field (perhaps incorrect sectioning?)"), tags->node);
      else if (tags->up)
        {
          int valid_p = validate (tags->up, tags->line_no, _("Up"));

          /* If node X has Up: Y, then warn if Y fails to have a menu item
             or note pointing at X, if Y isn't of the form "(Y)". */
          if (valid_p && *tags->up != '(')
            {
              NODE_REF *nref;
              NODE_REF *tref = NULL;
              NODE_REF *list = node_references;

              for (;;)
                {
                  nref = find_node_reference (tags->node, list);
                  if (!nref)
                    break;

                  if (strcmp (nref->containing_node, tags->up) == 0)
                    {
                      if (nref->type != menu_reference)
                        {
                          tref = nref;
                          list = nref->next;
                        }
                      else
                        break;
                    }
                  list = nref->next;
                }

              if (!nref)
                {
                if (!tref && expensive_validation)
                  {
                    /* Sigh...  This might be AWFULLY slow, but if
                       they want this feature, they'll have to pay!
                       We do all the loop again expanding each
                       containing_node reference as we go.  */
                    char *tags_up = expand_node_name (tags->up);
                    char *tem;

                    list = node_references;

                    for (;;)
                     {
                       nref = find_node_reference (tags->node, list);
                       if (!nref)
                         break;
                       tem = expand_node_name (nref->containing_node);
                       if (STREQ (tem, tags_up))
                         {
                           if (nref->type != menu_reference)
                            tref = nref;
                           else
                            {
                              free (tem);
                              break;
                            }
                         }
                       free (tem);
                       list = nref->next;
                     }
                  }
                  if (!nref && !tref)
                    {
                      temp_tag = find_node (tags->up);
                      file_line_error (temp_tag->filename, temp_tag->line_no,
           _("Node `%s' lacks menu item for `%s' despite being its Up target"),
                                  tags->up, tags->node);
                    }
                }
            }
        }
      tags = tags->next_ent;
    }

  validate_other_references (node_references);
  /* We have told the user about the references which didn't exist.
     Now tell him about the nodes which aren't referenced. */

  for (tags = tag_table; tags; tags = tags->next_ent)
    {
      /* If this node is a "no warn" node, do nothing. */
      if (tags->flags & TAG_FLAG_NO_WARN)
        {
          tags = tags->next_ent;
          continue;
        }

      /* Special hack.  If the node in question appears to have
         been referenced more than REFERENCE_WARNING_LIMIT times,
         give a warning. */
      if (tags->touched > reference_warning_limit)
        {
          input_filename = tags->filename;
          line_number = tags->line_no;
          warning (_("node `%s' has been referenced %d times"),
                   tags->node, tags->touched);
        }

      if (tags->touched == 0)
        {
          input_filename = tags->filename;
          line_number = tags->line_no;

          /* Notice that the node "Top" is special, and doesn't have to
             be referenced.   Anchors don't have to be referenced
             either, you might define them for another document.  */
          if (strcasecmp (tags->node, "Top") != 0
              && !(tags->flags & TAG_FLAG_ANCHOR))
            warning (_("unreferenced node `%s'"), tags->node);
        }
    }
  input_filename = old_input_filename;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void validate_other_references ( NODE_REF ref_list) [static]

Definition at line 1372 of file node.c.

{
  char *old_input_filename = input_filename;

  while (ref_list)
    {
      input_filename = ref_list->filename;
      validate (ref_list->node, ref_list->line_no,
                reftype_type_string (ref_list->type));
      ref_list = ref_list->next;
    }
  input_filename = old_input_filename;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void write_tag_table ( char *  filename)

Definition at line 115 of file node.c.

{
  output_stream = fopen (filename, "a");
  if (!output_stream)
    {
      fs_error (filename);
      return;
    }

  write_tag_table_internal (0); /* Not indirect. */

  if (fclose (output_stream) != 0)
    fs_error (filename);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void write_tag_table_indirect ( void  ) [static]

Definition at line 131 of file node.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void write_tag_table_internal ( int  indirect_p) [static]

Definition at line 65 of file node.c.

{
  TAG_ENTRY *node;
  int old_indent = no_indent;

  if (xml)
    {
      flush_output ();
      return;
    }

  no_indent = 1;
  filling_enabled = 0;
  must_start_paragraph = 0;
  close_paragraph ();

  if (!indirect_p)
    {
      no_indent = 1;
      insert ('\n');
    }

  add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");

  /* Do not collapse -- to -, etc., in node names.  */
  in_fixed_width_font++;

  for (node = tag_table; node; node = node->next_ent)
    {
      if (node->flags & TAG_FLAG_ANCHOR)
        { /* This reference is to an anchor.  */
          execute_string ("Ref: %s", node->node);
        }
      else
        { /* This reference is to a node.  */
          execute_string ("Node: %s", node->node);
        }
      add_word_args ("\177%d\n", node->position);
    }

  add_word ("\037\nEnd Tag Table\n");

  /* Do not collapse -- to -, etc., in node names.  */
  in_fixed_width_font--;

  flush_output ();
  no_indent = old_indent;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 40 of file node.c.

Definition at line 36 of file node.c.

Definition at line 38 of file node.c.

Definition at line 39 of file node.c.

Definition at line 35 of file node.c.

Definition at line 41 of file node.c.

Definition at line 37 of file node.c.