Back to index

tetex-bin  3.0
Classes | Defines | Typedefs | Functions | Variables
node.h File Reference
#include "xref.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  tentry
struct  node_ref

Defines

#define TAG_FLAG_PREV_ERROR   1
#define TAG_FLAG_NEXT_ERROR   2
#define TAG_FLAG_UP_ERROR   4
#define TAG_FLAG_NO_WARN   8
#define TAG_FLAG_IS_TOP   16
#define TAG_FLAG_ANCHOR   32

Typedefs

typedef struct tentry TAG_ENTRY
typedef struct node_ref NODE_REF

Functions

TAG_ENTRYfind_node (char *name)
 DECLARE (char *, node_search_string,"\n@node ")
char * glean_node_from_menu (int remember_ref, enum reftype ref_type)
void remember_node_reference (char *node, int line, enum reftype type)
void set_current_output_filename (const char *fname)
char * expand_node_name (char *node)
int number_of_node (char *node)
void init_tag_table (void)
void write_tag_table (char *filename)
void free_node_references (void)
void free_node_node_references (void)
void validate_file (TAG_ENTRY *tag_table)
void split_file (char *filename, int size)
void clean_old_split_files (char *filename)

Variables

NODE_REFnode_references
NODE_REFnode_node_references
TAG_ENTRYtag_table
int node_number
int node_order
int current_section
int outstanding_node

Class Documentation

struct tentry

Definition at line 29 of file node.h.

Collaboration diagram for tentry:
Class Members
char * filename
int flags
char * html_fname
int line_no
char * next
struct tentry * next_ent
char * node
int number
int order
int position
char * prev
int touched
char * up
struct node_ref

Definition at line 64 of file node.h.

Collaboration diagram for node_ref:
Class Members
char * containing_node
char * filename
int line_no
struct node_ref * next
char * node
int section

Define Documentation

#define TAG_FLAG_ANCHOR   32

Definition at line 58 of file node.h.

#define TAG_FLAG_IS_TOP   16

Definition at line 57 of file node.h.

#define TAG_FLAG_NEXT_ERROR   2

Definition at line 54 of file node.h.

#define TAG_FLAG_NO_WARN   8

Definition at line 56 of file node.h.

#define TAG_FLAG_PREV_ERROR   1

Definition at line 53 of file node.h.

#define TAG_FLAG_UP_ERROR   4

Definition at line 55 of file node.h.


Typedef Documentation

typedef struct node_ref NODE_REF
typedef struct tentry TAG_ENTRY

Function Documentation

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:

DECLARE ( char *  ,
node_search_string  ,
"\n@node  
)
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:

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:

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:

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:

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:

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:

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:


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.