texinfo-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[5818] reorder in session.c to avoid some forward function declarations


From: Gavin D. Smith
Subject: [5818] reorder in session.c to avoid some forward function declarations
Date: Fri, 12 Sep 2014 10:59:39 +0000

Revision: 5818
          http://svn.sv.gnu.org/viewvc/?view=rev&root=texinfo&revision=5818
Author:   gavin
Date:     2014-09-12 10:59:35 +0000 (Fri, 12 Sep 2014)
Log Message:
-----------
reorder in session.c to avoid some forward function declarations

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/info/info-utils.c
    trunk/info/info-utils.h
    trunk/info/session.c

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog     2014-09-10 19:46:09 UTC (rev 5817)
+++ trunk/ChangeLog     2014-09-12 10:59:35 UTC (rev 5818)
@@ -1,3 +1,11 @@
+2014-09-12  Gavin Smith  <address@hidden>
+
+       * info/session.c: Move "Garbage Collection" and "Navigation of
+       document structure" sections to reduce need for forward function
+       declarations.
+       * info/session.c (file_buffer_of_window, node_printed_rep): Moved
+       between files.
+
 2014-09-10  Gavin Smith  <address@hidden>
 
        * info/display.c (display_scroll_region): New function.

Modified: trunk/info/info-utils.c
===================================================================
--- trunk/info/info-utils.c     2014-09-10 19:46:09 UTC (rev 5817)
+++ trunk/info/info-utils.c     2014-09-12 10:59:35 UTC (rev 5818)
@@ -1751,6 +1751,41 @@
 }
 
 
+/* Various utility functions */
+
+/* Return the file buffer which belongs to WINDOW's node. */
+FILE_BUFFER *
+file_buffer_of_window (WINDOW *window)
+{
+  /* If this window has no node, then it has no file buffer. */
+  if (!window->node)
+    return NULL;
+
+  if (window->node->fullpath)
+    return info_find_file (window->node->fullpath);
+
+  return NULL;
+}
+
+/* Return "(FILENAME)NODENAME" for NODE, or just "NODENAME" if NODE's
+   filename is not set.  Return value should not be freed. */
+char *
+node_printed_rep (NODE *node)
+{
+  static char *rep;
+
+  if (node->fullpath)
+    {
+      char *filename = filename_non_directory (node->fullpath);
+      rep = xrealloc (rep, 1 + strlen (filename) + 1 + strlen (node->nodename) 
+ 1);
+      sprintf (rep, "(%s)%s", filename, node->nodename);
+      return rep;
+    }
+  else
+    return node->nodename;
+}
+
+
 /* Return a pointer to the part of PATHNAME that simply defines the file. */
 char *
 filename_non_directory (char *pathname)

Modified: trunk/info/info-utils.h
===================================================================
--- trunk/info/info-utils.h     2014-09-10 19:46:09 UTC (rev 5817)
+++ trunk/info/info-utils.h     2014-09-12 10:59:35 UTC (rev 5818)
@@ -93,6 +93,10 @@
                                      int *delim, size_t pl_chars,
                                      size_t *pchars, size_t *pbytes);
 
+FILE_BUFFER *file_buffer_of_window (WINDOW *window);
+
+char *node_printed_rep (NODE *node);
+
 /* Return a pointer to the part of PATHNAME that simply defines the file. */
 extern char *filename_non_directory (char *pathname);
 

Modified: trunk/info/session.c
===================================================================
--- trunk/info/session.c        2014-09-10 19:46:09 UTC (rev 5817)
+++ trunk/info/session.c        2014-09-12 10:59:35 UTC (rev 5818)
@@ -37,13 +37,6 @@
 #  define HAVE_STRUCT_TIMEVAL
 #endif /* HAVE_SYS_TIME_H */
 
-static void display_info_keyseq (int expecting_future_input);
-char *node_printed_rep (NODE *node);
-static int get_byte_from_input_buffer (unsigned char *key);
-
-static REFERENCE *select_menu_digit (WINDOW *window, unsigned char key);
-static void gc_file_buffers_and_nodes (void);
-
 /* **************************************************************** */
 /*                                                                  */
 /*                   Running an Info Session                        */
@@ -58,10 +51,6 @@
 /* Becomes non-zero when 'q' is typed to an Info window. */
 static int quit_info_immediately = 0;
 
-/* Minimal length of a search string */
-int min_search_length = 1;
-
-
 /* Defined in indices.c */
 extern NODE *allfiles_node;
 
@@ -103,8 +92,6 @@
   scan_node_contents (0, &allfiles_node);
 }
 
-
-
 /* Begin an info session finding the nodes specified by REFERENCES.  For
    each loaded node, create a new window.  Always split the largest of the
    available windows.  Display ERROR in echo area if non-null. */
@@ -1545,7 +1532,160 @@
   info_scroll_other_window (window, -count, key);
 }
 
+
+/* **************************************************************** */
+/*                                                                  */
+/*                      Garbage collection                          */
+/*                                                                  */
+/* **************************************************************** */
 
+
+/* Contents of displayed nodes with no corresponding file buffer. */
+static char **gcable_pointers = NULL;
+static size_t gcable_pointers_index = 0;
+static size_t gcable_pointers_slots = 0;
+
+/* Add POINTER to the list of garbage collectible pointers.  A pointer
+   is not garbage collected until no window contains a node whose contents
+   member is equal to the pointer. */
+void
+add_gcable_pointer (char *pointer)
+{
+  add_pointer_to_array (pointer, gcable_pointers_index, gcable_pointers,
+                       gcable_pointers_slots, 10);
+}
+
+/* Free contents of rewritten nodes in the file's tag table.  This will
+   do nothing for a subfile of a split file. */
+static void
+free_node_contents (FILE_BUFFER *fb)
+{
+  NODE **entry;
+
+  if (!fb->tags)
+    return;
+
+  for (entry = fb->tags; *entry; entry++)
+    if ((*entry)->flags & N_WasRewritten)
+      {
+        free ((*entry)->contents);
+        (*entry)->contents = 0;
+        (*entry)->flags &= ~N_WasRewritten;
+      }
+}
+
+static void
+gc_file_buffers_and_nodes (void)
+{
+  /* Array to record whether each file buffer was referenced or not. */
+  int *fb_referenced = xcalloc (info_loaded_files_index, sizeof (int));
+  WINDOW *win;
+  int i, j;
+  int fb_index, nc_index;
+
+  /* New value of gcable_pointers. */
+  char **new = NULL;
+  size_t new_index = 0;
+  size_t new_slots = 0;
+
+  /* Loop over nodes in the history of displayed windows recording which
+     nodes and file buffers were referenced. */
+  for (win = windows; win; win = win->next)
+    {
+      if (!win->hist)
+        continue;
+      for (i = 0; win->hist[i]; i++)
+        {
+          NODE *n = win->hist[i]->node;
+
+          /* Loop over file buffers. */
+          for (fb_index = 0; fb_index < info_loaded_files_index; fb_index++)
+            {
+              FILE_BUFFER *fb = info_loaded_files[fb_index];
+
+              if (fb->flags & N_Subfile)
+                {
+                  if (n->subfile && !FILENAME_CMP (fb->fullpath, n->subfile))
+                    {
+                      fb_referenced[fb_index] = 1;
+                      break;
+                    }
+                }
+              else
+                {
+                  if (n->fullpath && !FILENAME_CMP (fb->fullpath, n->fullpath))
+                    {
+                      fb_referenced[fb_index] = 1;
+                      break;
+                    }
+                }
+            }
+
+          /* Loop over gcable_pointers. */
+          for (nc_index = 0; nc_index < gcable_pointers_index; nc_index++)
+            if (n->contents == gcable_pointers[nc_index])
+              {
+                add_pointer_to_array (n->contents, new_index, new, 
+                                      new_slots, 10);
+                break;
+              }
+        }
+    }
+
+  /* Free unreferenced file buffers. */
+  for (i = 0; i < info_loaded_files_index; i++)
+    {
+      if (!fb_referenced[i])
+        {
+          FILE_BUFFER *fb = info_loaded_files[i];
+
+          if (fb->flags & N_TagsIndirect)
+            {
+              free_node_contents (fb);
+              continue;
+            }
+
+          /* If already gc-ed, do nothing. */
+          if (!fb->contents)
+            continue;
+
+          /* If this file had to be uncompressed, check to see if we should
+             gc it.  This means that the user-variable "gc-compressed-files"
+             is non-zero. */
+          if ((fb->flags & N_IsCompressed) && !gc_compressed_files)
+            continue;
+
+          /* If this file's contents are not gc-able, move on. */
+          if (fb->flags & N_CannotGC)
+            continue;
+
+          free_node_contents (fb);
+          free (fb->contents);
+          fb->contents = 0;
+        }
+    }
+
+  /* Free unreferenced node contents and update gcable_pointers. */
+  for (i = 0; i < gcable_pointers_index; i++)
+    {
+      for (j = 0; j < new_index; j++)
+       if (gcable_pointers[i] == new[j])
+         break;
+
+      /* If we got all the way through the new list, then the old pointer
+        can be garbage collected. */
+      if (!new || j == new_index)
+       free (gcable_pointers[i]);
+    }
+
+  free (gcable_pointers);
+  gcable_pointers = new;
+  gcable_pointers_slots = new_slots;
+  gcable_pointers_index = new_index;
+
+  free (fb_referenced);
+}
+
 
 /* **************************************************************** */
 /*                                                                  */
@@ -1775,377 +1915,7 @@
 {
   window_toggle_wrap (window);
 }
-
-/* **************************************************************** */
-/*                                                                  */
-/*                 Navigation of document structure                 */
-/*                                                                  */
-/* **************************************************************** */
 
-/* Get the node pointed to by the LABEL pointer of WINDOW->node into WINDOW.
-   Display error message if there is no such pointer, and return zero. */
-static int
-info_handle_pointer (char *label, WINDOW *window)
-{
-  char *description;
-  NODE *node;
-
-  if (!strcmp (label, "Up"))
-    description = window->node->up;
-  else if (!strcmp (label, "Next"))
-    description = window->node->next;
-  else if (!strcmp (label, "Prev"))
-    description = window->node->prev;
-
-  if (!description)
-    {
-      info_error (msg_no_pointer, label);
-      return 0;
-    }
-
-  node = info_get_node_with_defaults (0, description, window->node);
-  if (!node)
-    {
-      if (info_recent_file_error)
-        info_error ("%s", info_recent_file_error);
-      else
-        info_error (msg_cant_find_node, description);
-      return 0;
-    }
-
-  /* If we are going up, set the cursor position to the last place it
-     was in the node. */
-  if (strcmp (label, "Up") == 0)
-    {
-      int i;
-
-      for (i = window->hist_index - 1; i >= 0; i--)
-        {
-          NODE *p = window->hist[i]->node;
-
-          if (p->fullpath && !strcmp (p->fullpath, node->fullpath)
-              && p->nodename && !strcmp (p->nodename, node->nodename))
-            break;
-        }
-
-      if (i >= 0)
-        node->display_pos = window->hist[i]->point;
-    }
-
-  info_set_node_of_window (window, node);
-  return 1;
-}
-
-/* Make WINDOW display the "Next:" node of the node currently being
-   displayed. */
-DECLARE_INFO_COMMAND (info_next_node, _("Select the Next node"))
-{
-  info_handle_pointer ("Next", window);
-}
-
-/* Make WINDOW display the "Prev:" node of the node currently being
-   displayed. */
-DECLARE_INFO_COMMAND (info_prev_node, _("Select the Prev node"))
-{
-  info_handle_pointer ("Prev", window);
-}
-
-/* Make WINDOW display the "Up:" node of the node currently being
-   displayed. */
-DECLARE_INFO_COMMAND (info_up_node, _("Select the Up node"))
-{
-  info_handle_pointer ("Up", window);
-}
-
-/* Make WINDOW display the last node of this info file. */
-DECLARE_INFO_COMMAND (info_last_node, _("Select the last node in this file"))
-{
-  register int i;
-  FILE_BUFFER *fb = file_buffer_of_window (window);
-  NODE *node = NULL;
-
-  if (fb && fb->tags)
-    {
-      int last_node_tag_idx = -1;
-
-      /* If no explicit argument, or argument of zero, default to the
-         last node.  */
-      if (count == 0 || (count == 1 && !info_explicit_arg))
-        count = -1;
-      for (i = 0; count && fb->tags[i]; i++)
-        if (fb->tags[i]->nodelen != 0) /* don't count anchor tags */
-          {
-            count--;
-            last_node_tag_idx = i;
-          }
-      if (count > 0)
-        i = last_node_tag_idx + 1;
-      if (i > 0)
-        node = info_get_node (fb->filename, fb->tags[i - 1]->nodename);
-    }
-
-  if (!node)
-    info_error ("%s", _("This window has no additional nodes"));
-  else
-    info_set_node_of_window (window, node);
-}
-
-/* Make WINDOW display the first node of this info file. */
-DECLARE_INFO_COMMAND (info_first_node, _("Select the first node in this file"))
-{
-  FILE_BUFFER *fb = file_buffer_of_window (window);
-  NODE *node = NULL;
-
-  /* If no explicit argument, or argument of zero, default to the
-     first node.  */
-  if (count == 0)
-    count = 1;
-  if (fb && fb->tags)
-    {
-      register int i;
-      int last_node_tag_idx = -1;
-
-      for (i = 0; count && fb->tags[i]; i++)
-        if (fb->tags[i]->nodelen != 0) /* don't count anchor tags */
-          {
-            count--;
-            last_node_tag_idx = i;
-          }
-      if (count > 0)
-        i = last_node_tag_idx + 1;
-      if (i > 0)
-        node = info_get_node (fb->filename, fb->tags[i - 1]->nodename);
-    }
-
-  if (!node)
-    info_error ("%s", _("This window has no additional nodes"));
-  else
-    info_set_node_of_window (window, node);
-}
-
-/* Choices for the scroll-last-node variable */
-char *scroll_last_node_choices[] = {
-  "Stop", "Top", NULL
-};
-
-/* Controls what to do when a scrolling command is issued at the end of the
-   last node. */
-int scroll_last_node = SLN_Stop;
-
-/* Move to 1st menu item, Next, Up/Next, or error in this window. Return
-   non-zero on error, 0 on success.  Display an error message if there is an
-   error. */
-static int
-forward_move_node_structure (WINDOW *window, int behaviour)
-{
-  if (window->node->flags & N_IsInternal)
-    return 1;
-
-  switch (behaviour)
-    {
-    case IS_PageOnly:
-      info_error ("%s", msg_at_node_bottom);
-      return 1;
-
-    case IS_NextOnly:
-      return !info_handle_pointer ("Next", window);
-      break;
-
-    case IS_Continuous:
-      {
-        /* If this node contains a menu, select its first entry.  Indices
-           are an exception, as their menus lead nowhere meaningful. */
-        if (!(window->node->flags & N_IsIndex))
-          {
-            REFERENCE *entry;
-
-            if (entry = select_menu_digit (window, '1'))
-              {
-                info_select_reference (window, entry);
-                return 0;
-              }
-          }
-
-        /* Okay, this node does not contain a menu.  If it contains a
-           "Next:" pointer, use that. */
-        if (window->node->next)
-          {
-            info_handle_pointer ("Next", window);
-            return 0;
-          }
-
-        /* Okay, there wasn't a "Next:" for this node.  Move "Up:" until we
-           can move "Next:".  If that isn't possible, complain that there
-           are no more nodes. */
-        {
-          int up_counter;
-
-          /* Back up through the "Up:" pointers until we have found a "Next:"
-             that isn't the same as the first menu item found in that node. */
-          up_counter = 0;
-          while (1)
-            {
-              if (window->node->up)
-                {
-                  REFERENCE *entry;
-
-                  if (!info_handle_pointer ("Up", window))
-                    return 1;
-
-                  up_counter++;
-
-                  /* If no "Next" pointer, keep backing up. */
-                  if (!window->node->next)
-                    continue;
-
-                  /* If this node's first menu item is the same as this node's
-                     Next pointer, keep backing up. */
-                  entry = select_menu_digit (window, '1');
-                  if (entry && !strcmp (window->node->next, entry->nodename))
-                    continue;
-
-                  /* This node has a "Next" pointer, and it is not the
-                     same as the first menu item found in this node. */
-                  info_handle_pointer ("Next", window);
-                  return 0;
-                }
-              else
-                {
-                  /* No more "Up" pointers.  We are at the last node in the
-                     file. */
-                  register int i;
-
-                  for (i = 0; i < up_counter; i++)
-                    forget_node (window);
-
-                  switch (scroll_last_node)
-                    {
-                    case SLN_Stop:
-                      info_error ("%s",
-                                  _("No more nodes within this document."));
-                      return 1;
-                      
-                    case SLN_Top:
-                      info_top_node (window, 1, 0);
-                      return 0;
-                      
-                    default:
-                      abort ();
-                    }
-                }
-            }
-        }
-        break;
-      }
-    }
-  return 0;
-}
-
-/* Move to earlier node in node hierarchy in WINDOW depending on BEHAVIOUR.
-   Display an error message if node wasn't changed. */
-static int
-backward_move_node_structure (WINDOW *window, int behaviour)
-{
-  if (window->node->flags & N_IsInternal)
-    return 1;
-
-  switch (behaviour)
-    {
-    case IS_PageOnly:
-      info_error ("%s", msg_at_node_top);
-      return 1;
-
-    case IS_NextOnly:
-      return !info_handle_pointer ("Prev", window);
-      break;
-
-    case IS_Continuous:
-      if (window->node->up)
-        {
-          /* If up is the dir node, we are at the top node.
-             Don't do anything. */
-          if (   !strcmp ("(dir)", window->node->up)
-              || !strcmp ("(DIR)", window->node->up))
-            {
-              info_error ("%s", 
-                    _("No 'Prev' or 'Up' for this node within this 
document."));
-              return 1;
-            }
-          /* If 'Prev' and 'Up' are the same, we are at the first node
-             of the 'Up' node's menu. Go to up node. */
-          else if (window->node->prev
-              && !strcmp(window->node->prev, window->node->up))
-            {
-              info_handle_pointer ("Up", window);
-            }
-          /* Otherwise, go to 'Prev' node and go down the last entry
-             in the menus as far as possible. */
-          else if (window->node->prev)
-            {
-              info_handle_pointer ("Prev", window);
-              if (!(window->node->flags & N_IsIndex))
-                {
-                  while (1)
-                    {
-                      REFERENCE *entry = select_menu_digit (window, '0');
-                      if (!entry)
-                        break;
-                      if (!info_select_reference (window, entry))
-                        break;
-                    }
-                }
-            }
-          else /* 'Up' but no 'Prev' */
-            info_handle_pointer ("Up", window);
-        }
-      else if (window->node->prev) /* 'Prev' but no 'Up' */
-        info_handle_pointer ("Prev", window);
-      else
-        {
-          info_error ("%s", 
-                _("No 'Prev' or 'Up' for this node within this document."));
-          return 1;
-        }
-
-      break; /* case IS_Continuous: */
-    }
-  return 0;
-}
-
-/* Move continuously forward through the node structure of this info file. */
-DECLARE_INFO_COMMAND (info_global_next_node,
-                      _("Move forwards or down through node structure"))
-{
-  if (count < 0)
-    info_global_prev_node (window, -count, key);
-  else
-    {
-      while (count)
-        {
-          if (forward_move_node_structure (window, IS_Continuous))
-            break;
-          count--;
-        }
-    }
-}
-
-/* Move continuously backward through the node structure of this info file. */
-DECLARE_INFO_COMMAND (info_global_prev_node,
-                      _("Move backwards or up through node structure"))
-{
-  if (count < 0)
-    info_global_next_node (window, -count, key);
-  else
-    {
-      while (count)
-        {
-          if (backward_move_node_structure (window, IS_Continuous))
-            break;
-          count--;
-        }
-    }
-}
-
 
 /* **************************************************************** */
 /*                                                                  */
@@ -2914,28 +2684,381 @@
 
 /* **************************************************************** */
 /*                                                                  */
-/*                      Info Node Commands                          */
+/*                 Navigation of document structure                 */
 /*                                                                  */
 /* **************************************************************** */
 
-/* Return (FILENAME)NODENAME for NODE, or just NODENAME if NODE's
-   filename is not set. */
-char *
-node_printed_rep (NODE *node)
+/* Get the node pointed to by the LABEL pointer of WINDOW->node into WINDOW.
+   Display error message if there is no such pointer, and return zero. */
+static int
+info_handle_pointer (char *label, WINDOW *window)
 {
-  static char *rep;
+  char *description;
+  NODE *node;
 
-  if (node->fullpath)
+  if (!strcmp (label, "Up"))
+    description = window->node->up;
+  else if (!strcmp (label, "Next"))
+    description = window->node->next;
+  else if (!strcmp (label, "Prev"))
+    description = window->node->prev;
+
+  if (!description)
     {
-      char *filename = filename_non_directory (node->fullpath);
-      rep = xrealloc (rep, 1 + strlen (filename) + 1 + strlen (node->nodename) 
+ 1);
-      sprintf (rep, "(%s)%s", filename, node->nodename);
-      return rep;
+      info_error (msg_no_pointer, label);
+      return 0;
     }
+
+  node = info_get_node_with_defaults (0, description, window->node);
+  if (!node)
+    {
+      if (info_recent_file_error)
+        info_error ("%s", info_recent_file_error);
+      else
+        info_error (msg_cant_find_node, description);
+      return 0;
+    }
+
+  /* If we are going up, set the cursor position to the last place it
+     was in the node. */
+  if (strcmp (label, "Up") == 0)
+    {
+      int i;
+
+      for (i = window->hist_index - 1; i >= 0; i--)
+        {
+          NODE *p = window->hist[i]->node;
+
+          if (p->fullpath && !strcmp (p->fullpath, node->fullpath)
+              && p->nodename && !strcmp (p->nodename, node->nodename))
+            break;
+        }
+
+      if (i >= 0)
+        node->display_pos = window->hist[i]->point;
+    }
+
+  info_set_node_of_window (window, node);
+  return 1;
+}
+
+/* Make WINDOW display the "Next:" node of the node currently being
+   displayed. */
+DECLARE_INFO_COMMAND (info_next_node, _("Select the Next node"))
+{
+  info_handle_pointer ("Next", window);
+}
+
+/* Make WINDOW display the "Prev:" node of the node currently being
+   displayed. */
+DECLARE_INFO_COMMAND (info_prev_node, _("Select the Prev node"))
+{
+  info_handle_pointer ("Prev", window);
+}
+
+/* Make WINDOW display the "Up:" node of the node currently being
+   displayed. */
+DECLARE_INFO_COMMAND (info_up_node, _("Select the Up node"))
+{
+  info_handle_pointer ("Up", window);
+}
+
+/* Make WINDOW display the last node of this info file. */
+DECLARE_INFO_COMMAND (info_last_node, _("Select the last node in this file"))
+{
+  register int i;
+  FILE_BUFFER *fb = file_buffer_of_window (window);
+  NODE *node = NULL;
+
+  if (fb && fb->tags)
+    {
+      int last_node_tag_idx = -1;
+
+      /* If no explicit argument, or argument of zero, default to the
+         last node.  */
+      if (count == 0 || (count == 1 && !info_explicit_arg))
+        count = -1;
+      for (i = 0; count && fb->tags[i]; i++)
+        if (fb->tags[i]->nodelen != 0) /* don't count anchor tags */
+          {
+            count--;
+            last_node_tag_idx = i;
+          }
+      if (count > 0)
+        i = last_node_tag_idx + 1;
+      if (i > 0)
+        node = info_get_node (fb->filename, fb->tags[i - 1]->nodename);
+    }
+
+  if (!node)
+    info_error ("%s", _("This window has no additional nodes"));
   else
-    return node->nodename;
+    info_set_node_of_window (window, node);
 }
 
+/* Make WINDOW display the first node of this info file. */
+DECLARE_INFO_COMMAND (info_first_node, _("Select the first node in this file"))
+{
+  FILE_BUFFER *fb = file_buffer_of_window (window);
+  NODE *node = NULL;
+
+  /* If no explicit argument, or argument of zero, default to the
+     first node.  */
+  if (count == 0)
+    count = 1;
+  if (fb && fb->tags)
+    {
+      register int i;
+      int last_node_tag_idx = -1;
+
+      for (i = 0; count && fb->tags[i]; i++)
+        if (fb->tags[i]->nodelen != 0) /* don't count anchor tags */
+          {
+            count--;
+            last_node_tag_idx = i;
+          }
+      if (count > 0)
+        i = last_node_tag_idx + 1;
+      if (i > 0)
+        node = info_get_node (fb->filename, fb->tags[i - 1]->nodename);
+    }
+
+  if (!node)
+    info_error ("%s", _("This window has no additional nodes"));
+  else
+    info_set_node_of_window (window, node);
+}
+
+/* Choices for the scroll-last-node variable */
+char *scroll_last_node_choices[] = {
+  "Stop", "Top", NULL
+};
+
+/* Controls what to do when a scrolling command is issued at the end of the
+   last node. */
+int scroll_last_node = SLN_Stop;
+
+/* Move to 1st menu item, Next, Up/Next, or error in this window. Return
+   non-zero on error, 0 on success.  Display an error message if there is an
+   error. */
+static int
+forward_move_node_structure (WINDOW *window, int behaviour)
+{
+  if (window->node->flags & N_IsInternal)
+    return 1;
+
+  switch (behaviour)
+    {
+    case IS_PageOnly:
+      info_error ("%s", msg_at_node_bottom);
+      return 1;
+
+    case IS_NextOnly:
+      return !info_handle_pointer ("Next", window);
+      break;
+
+    case IS_Continuous:
+      {
+        /* If this node contains a menu, select its first entry.  Indices
+           are an exception, as their menus lead nowhere meaningful. */
+        if (!(window->node->flags & N_IsIndex))
+          {
+            REFERENCE *entry;
+
+            if (entry = select_menu_digit (window, '1'))
+              {
+                info_select_reference (window, entry);
+                return 0;
+              }
+          }
+
+        /* Okay, this node does not contain a menu.  If it contains a
+           "Next:" pointer, use that. */
+        if (window->node->next)
+          {
+            info_handle_pointer ("Next", window);
+            return 0;
+          }
+
+        /* Okay, there wasn't a "Next:" for this node.  Move "Up:" until we
+           can move "Next:".  If that isn't possible, complain that there
+           are no more nodes. */
+        {
+          int up_counter;
+
+          /* Back up through the "Up:" pointers until we have found a "Next:"
+             that isn't the same as the first menu item found in that node. */
+          up_counter = 0;
+          while (1)
+            {
+              if (window->node->up)
+                {
+                  REFERENCE *entry;
+
+                  if (!info_handle_pointer ("Up", window))
+                    return 1;
+
+                  up_counter++;
+
+                  /* If no "Next" pointer, keep backing up. */
+                  if (!window->node->next)
+                    continue;
+
+                  /* If this node's first menu item is the same as this node's
+                     Next pointer, keep backing up. */
+                  entry = select_menu_digit (window, '1');
+                  if (entry && !strcmp (window->node->next, entry->nodename))
+                    continue;
+
+                  /* This node has a "Next" pointer, and it is not the
+                     same as the first menu item found in this node. */
+                  info_handle_pointer ("Next", window);
+                  return 0;
+                }
+              else
+                {
+                  /* No more "Up" pointers.  We are at the last node in the
+                     file. */
+                  register int i;
+
+                  for (i = 0; i < up_counter; i++)
+                    forget_node (window);
+
+                  switch (scroll_last_node)
+                    {
+                    case SLN_Stop:
+                      info_error ("%s",
+                                  _("No more nodes within this document."));
+                      return 1;
+                      
+                    case SLN_Top:
+                      info_top_node (window, 1, 0);
+                      return 0;
+                      
+                    default:
+                      abort ();
+                    }
+                }
+            }
+        }
+        break;
+      }
+    }
+  return 0;
+}
+
+/* Move to earlier node in node hierarchy in WINDOW depending on BEHAVIOUR.
+   Display an error message if node wasn't changed. */
+static int
+backward_move_node_structure (WINDOW *window, int behaviour)
+{
+  if (window->node->flags & N_IsInternal)
+    return 1;
+
+  switch (behaviour)
+    {
+    case IS_PageOnly:
+      info_error ("%s", msg_at_node_top);
+      return 1;
+
+    case IS_NextOnly:
+      return !info_handle_pointer ("Prev", window);
+      break;
+
+    case IS_Continuous:
+      if (window->node->up)
+        {
+          /* If up is the dir node, we are at the top node.
+             Don't do anything. */
+          if (   !strcmp ("(dir)", window->node->up)
+              || !strcmp ("(DIR)", window->node->up))
+            {
+              info_error ("%s", 
+                    _("No 'Prev' or 'Up' for this node within this 
document."));
+              return 1;
+            }
+          /* If 'Prev' and 'Up' are the same, we are at the first node
+             of the 'Up' node's menu. Go to up node. */
+          else if (window->node->prev
+              && !strcmp(window->node->prev, window->node->up))
+            {
+              info_handle_pointer ("Up", window);
+            }
+          /* Otherwise, go to 'Prev' node and go down the last entry
+             in the menus as far as possible. */
+          else if (window->node->prev)
+            {
+              info_handle_pointer ("Prev", window);
+              if (!(window->node->flags & N_IsIndex))
+                {
+                  while (1)
+                    {
+                      REFERENCE *entry = select_menu_digit (window, '0');
+                      if (!entry)
+                        break;
+                      if (!info_select_reference (window, entry))
+                        break;
+                    }
+                }
+            }
+          else /* 'Up' but no 'Prev' */
+            info_handle_pointer ("Up", window);
+        }
+      else if (window->node->prev) /* 'Prev' but no 'Up' */
+        info_handle_pointer ("Prev", window);
+      else
+        {
+          info_error ("%s", 
+                _("No 'Prev' or 'Up' for this node within this document."));
+          return 1;
+        }
+
+      break; /* case IS_Continuous: */
+    }
+  return 0;
+}
+
+/* Move continuously forward through the node structure of this info file. */
+DECLARE_INFO_COMMAND (info_global_next_node,
+                      _("Move forwards or down through node structure"))
+{
+  if (count < 0)
+    info_global_prev_node (window, -count, key);
+  else
+    {
+      while (count)
+        {
+          if (forward_move_node_structure (window, IS_Continuous))
+            break;
+          count--;
+        }
+    }
+}
+
+/* Move continuously backward through the node structure of this info file. */
+DECLARE_INFO_COMMAND (info_global_prev_node,
+                      _("Move backwards or up through node structure"))
+{
+  if (count < 0)
+    info_global_next_node (window, -count, key);
+  else
+    {
+      while (count)
+        {
+          if (backward_move_node_structure (window, IS_Continuous))
+            break;
+          count--;
+        }
+    }
+}
+
+
+/* **************************************************************** */
+/*                                                                  */
+/*                      Info Node Commands                          */
+/*                                                                  */
+/* **************************************************************** */
+
 /* Read a line of input which is a node name, and go to that node. */
 DECLARE_INFO_COMMAND (info_goto_node, _("Read a node name and select it"))
 {
@@ -3498,20 +3621,6 @@
                                : _("Using literal strings for searches."));
 }
 
-/* Return the file buffer which belongs to WINDOW's node. */
-FILE_BUFFER *
-file_buffer_of_window (WINDOW *window)
-{
-  /* If this window has no node, then it has no file buffer. */
-  if (!window->node)
-    return NULL;
-
-  if (window->node->fullpath)
-    return info_find_file (window->node->fullpath);
-
-  return NULL;
-}
-
 /* Search forwards or backwards for entries in MATCHES that start within
    the search area.  The search is forwards if START_IN is greater than
    END_IN.  Return offset of match in *MATCH_INDEX. */
@@ -3822,6 +3931,9 @@
   return -1;
 }
 
+/* Minimal length of a search string */
+int min_search_length = 1;
+
 /* Read a string from the user. */
 static int
 ask_for_search_string (int case_sensitive, int use_regex, int direction)
@@ -4468,160 +4580,6 @@
 
 /* **************************************************************** */
 /*                                                                  */
-/*                      Garbage collection                          */
-/*                                                                  */
-/* **************************************************************** */
-
-
-/* Contents of displayed nodes with no corresponding file buffer. */
-static char **gcable_pointers = NULL;
-static size_t gcable_pointers_index = 0;
-static size_t gcable_pointers_slots = 0;
-
-/* Add POINTER to the list of garbage collectible pointers.  A pointer
-   is not garbage collected until no window contains a node whose contents
-   member is equal to the pointer. */
-void
-add_gcable_pointer (char *pointer)
-{
-  add_pointer_to_array (pointer, gcable_pointers_index, gcable_pointers,
-                       gcable_pointers_slots, 10);
-}
-
-/* Free contents of rewritten nodes in the file's tag table.  This will
-   do nothing for a subfile of a split file. */
-static void
-free_node_contents (FILE_BUFFER *fb)
-{
-  NODE **entry;
-
-  if (!fb->tags)
-    return;
-
-  for (entry = fb->tags; *entry; entry++)
-    if ((*entry)->flags & N_WasRewritten)
-      {
-        free ((*entry)->contents);
-        (*entry)->contents = 0;
-        (*entry)->flags &= ~N_WasRewritten;
-      }
-}
-
-static void
-gc_file_buffers_and_nodes (void)
-{
-  /* Array to record whether each file buffer was referenced or not. */
-  int *fb_referenced = xcalloc (info_loaded_files_index, sizeof (int));
-  WINDOW *win;
-  int i, j;
-  int fb_index, nc_index;
-
-  /* New value of gcable_pointers. */
-  char **new = NULL;
-  size_t new_index = 0;
-  size_t new_slots = 0;
-
-  /* Loop over nodes in the history of displayed windows recording which
-     nodes and file buffers were referenced. */
-  for (win = windows; win; win = win->next)
-    {
-      if (!win->hist)
-        continue;
-      for (i = 0; win->hist[i]; i++)
-        {
-          NODE *n = win->hist[i]->node;
-
-          /* Loop over file buffers. */
-          for (fb_index = 0; fb_index < info_loaded_files_index; fb_index++)
-            {
-              FILE_BUFFER *fb = info_loaded_files[fb_index];
-
-              if (fb->flags & N_Subfile)
-                {
-                  if (n->subfile && !FILENAME_CMP (fb->fullpath, n->subfile))
-                    {
-                      fb_referenced[fb_index] = 1;
-                      break;
-                    }
-                }
-              else
-                {
-                  if (n->fullpath && !FILENAME_CMP (fb->fullpath, n->fullpath))
-                    {
-                      fb_referenced[fb_index] = 1;
-                      break;
-                    }
-                }
-            }
-
-          /* Loop over gcable_pointers. */
-          for (nc_index = 0; nc_index < gcable_pointers_index; nc_index++)
-            if (n->contents == gcable_pointers[nc_index])
-              {
-                add_pointer_to_array (n->contents, new_index, new, 
-                                      new_slots, 10);
-                break;
-              }
-        }
-    }
-
-  /* Free unreferenced file buffers. */
-  for (i = 0; i < info_loaded_files_index; i++)
-    {
-      if (!fb_referenced[i])
-        {
-          FILE_BUFFER *fb = info_loaded_files[i];
-
-          if (fb->flags & N_TagsIndirect)
-            {
-              free_node_contents (fb);
-              continue;
-            }
-
-          /* If already gc-ed, do nothing. */
-          if (!fb->contents)
-            continue;
-
-          /* If this file had to be uncompressed, check to see if we should
-             gc it.  This means that the user-variable "gc-compressed-files"
-             is non-zero. */
-          if ((fb->flags & N_IsCompressed) && !gc_compressed_files)
-            continue;
-
-          /* If this file's contents are not gc-able, move on. */
-          if (fb->flags & N_CannotGC)
-            continue;
-
-          free_node_contents (fb);
-          free (fb->contents);
-          fb->contents = 0;
-        }
-    }
-
-  /* Free unreferenced node contents and update gcable_pointers. */
-  for (i = 0; i < gcable_pointers_index; i++)
-    {
-      for (j = 0; j < new_index; j++)
-       if (gcable_pointers[i] == new[j])
-         break;
-
-      /* If we got all the way through the new list, then the old pointer
-        can be garbage collected. */
-      if (!new || j == new_index)
-       free (gcable_pointers[i]);
-    }
-
-  free (gcable_pointers);
-  gcable_pointers = new;
-  gcable_pointers_slots = new_slots;
-  gcable_pointers_index = new_index;
-
-  free (fb_referenced);
-}
-
-
-/* **************************************************************** */
-/*                                                                  */
 /*                  Miscellaneous Info Commands                     */
 /*                                                                  */
 /* **************************************************************** */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]