1998-06-26  Eli Zaretskii  <eliz@is.elta.co.il>

	* makeinfo/makeinfo.c: (only_macro_expansion): New variable,
	suppresses all expansions except macros.
	(replace_with_expansion): New function, replaces a portion of
	input text with its expansion.  Avoids moving the text around if
	we are positive it will expand into itself.  If the length of the
	expanded text is the same as the length of the original text, just
	replaces the original text without moving the rest.  Resyncs the
	remembered text pointers with the realloc'ed input_text, when it
	is realloc'ed.
	(reader_loop): When only_macro_expansion is non-zero, only handle
	macros, but leave the rest of input intact.
	(read_command): Now returns an int, zero means no known command or
	macro is found after the prefix character; all callers changed.
	Support operation under non-zero only_macro_expansion.
	(cm_node): Expand only the macros in the @node line.  Allocate and
	generate the macro-expanded @node line in one swell whoop.
	(glean_node_from_menu): Expand macros in menu entries.
	(get_xref_token): A new argument EXPAND, when non-zero, means
	expand macros in the entire brace-delimited argument before
	looking for the next comma; all callers changed.
	(expansion): Save and restore additional state variables important
	for output generation machinery.  Disable indentation and filling
	during the recursive expansion, so that the output buffer offset
	is not invalidated by filling.
	(me_execute_string_keep_state): New function, calls
	me_execute_string, but saves and restores state variables
	important for output generation, so that -E doesn't change the
	generated Info output.
	(index_add_arg, cm_footnote): Call me_execute_string_keep_state.
	(expand_macro): New function, returns the macro expansion as a
	malloc'ed string.
	(execute_macro): Call expand_macro.
	(me_execute_string): Avoid memory leak by freeing input_filename.
	(get_until_in_braces, replace_with_expansion, add_char,
	cm_footnote, cm_macro, cm_unmacro, get_brace_args,
	extract_colon_unit): Use the faster memcpy/memmove instead of
	strncpy.

*** makeinfo/makeinfo.c~2	Sat May 23 13:13:02 1998
--- makeinfo/makeinfo.c	Fri Jun 26 14:17:38 1998
*************** static int executing_string = 0;
*** 128,133 ****
--- 128,137 ----
  /* Nonzero means a macro string is in execution, as opposed to a file. */
  static int me_executing_string = 0;
  
+ /* Nonzero means we want only to expand macros and
+    leave everything else intact.  */
+ static int only_macro_expansion = 0;
+ 
  #if defined (HAVE_MACROS)
  /* If non-NULL, this is an output stream to write the full macro expansion
     of the input text to.  The result is another texinfo file, but
*************** ITEXT *remember_itext ();
*** 154,159 ****
--- 158,164 ----
  void forget_itext (), me_append_before_this_command ();
  void append_to_expansion_output (), write_region_to_macro_output ();
  void maybe_write_itext (), me_execute_string ();
+ void me_execute_string_keep_state ();
  #endif /* HAVE_MACROS */
  
  
*************** typedef struct {
*** 337,342 ****
--- 342,348 ----
  
  void add_macro (), execute_macro ();
  MACRO_DEF *find_macro (), *delete_macro ();
+ char *expand_macro ();
  #endif /* HAVE_MACROS */
  
  /* Menu reference, *note reference, and validation hacking. */
*************** int array_len ();
*** 449,455 ****
  void free_array ();
  static int end_of_sentence_p ();
  static void isolate_nodename ();
! void reader_loop (), read_command ();
  void remember_brace (), remember_brace_1 ();
  void pop_and_call_brace (), discard_braces ();
  void add_word (), add_char (), insert (), flush_output ();
--- 455,462 ----
  void free_array ();
  static int end_of_sentence_p ();
  static void isolate_nodename ();
! void reader_loop ();
! int read_command ();
  void remember_brace (), remember_brace_1 ();
  void pop_and_call_brace (), discard_braces ();
  void add_word (), add_char (), insert (), flush_output ();
*************** get_until (match, string)
*** 1815,1822 ****
    return (new_point);
  }
  
  /* Read characters from the file until we are at MATCH or end of line.
!    Place the characters read into STRING.  */
  void
  get_until_in_line (expand, match, string)
       int expand;
--- 1822,1895 ----
    return (new_point);
  }
  
+ /* Replace input_text[FROM .. TO] with its expansion.  */
+ void
+ replace_with_expansion (from, to)
+      int from, *to;
+ {
+   char *xp;
+   unsigned xp_len, new_len;
+   char *old_input = input_text;
+   unsigned raw_len = *to - from;
+   char *str;
+ 
+   /* The rest of the code here moves large buffers, so let's
+      not waste time if the input cannot possibly expand
+      into anything.  Unfortunately, we cannot avoid expansion
+      when we see things like @code etc., even if they only
+      asked for expansion of macros, since any Texinfo command
+      can be potentially redefined with a macro.  */
+   if (only_macro_expansion &&
+       memchr (input_text + from, COMMAND_PREFIX, raw_len) == 0)
+     return;
+ 
+   /* Get original string from input.  */
+   str = xmalloc (raw_len + 1);
+   memcpy (str, input_text + from, raw_len);
+   str[raw_len] = 0;
+ 
+ #if defined (HAVE_MACROS)
+   /* We are going to relocate input_text, so we had better output
+      pending portion of input_text now, before the pointer changes.  */
+   if (macro_expansion_output_stream && !executing_string &&
+       !me_inhibit_expansion)
+     append_to_expansion_output (from);
+ #endif
+       
+   /* Expand it.  */
+   xp = expansion (str, 0);
+   xp_len = strlen (xp);
+   free (str);
+       
+   /* Plunk the expansion into the middle of `input_text' --
+      which is terminated by a newline, not a null.  Avoid
+      expensive move of the rest of the input if the expansion
+      has the same length as the original string.  */
+   if (xp_len != raw_len)
+     {
+       new_len = from + xp_len + size_of_input_text - *to + 1;
+       input_text = xrealloc (input_text, new_len);
+       memmove (input_text + from + xp_len,
+ 	       input_text + *to, size_of_input_text - *to + 1);
+       
+       *to += xp_len - raw_len;
+       size_of_input_text += xp_len - raw_len;
+     }
+   memcpy (input_text + from, xp, xp_len);
+   free (xp);
+ 
+ #if defined (HAVE_MACROS)
+   /* Synchronize the macro-expansion pointers with our new input_text.  */
+   if (input_text != old_input)
+     forget_itext (old_input);
+   remember_itext (input_text, from);
+ #endif
+ }
+ 
  /* Read characters from the file until we are at MATCH or end of line.
!    Place the characters read into STRING.  If EXPAND is non-zero,
!    expand the text before looking for MATCH for those cases where
!    MATCH might be produced by some macro.  */
  void
  get_until_in_line (expand, match, string)
       int expand;
*************** get_until_in_line (expand, match, string
*** 1827,1835 ****
    if (limit < 0)
      limit = size_of_input_text;
  
!   /* Replace input_text[input_text_offset .. limit-1] with its macro
!      expansion (actually, we expand all commands).  This allows the node
!      names themselves to be constructed via a macro, as in:
          @macro foo{p, q}
          Together: \p\ & \q\.
          @end macro
--- 1900,1908 ----
    if (limit < 0)
      limit = size_of_input_text;
  
!   /* Replace input_text[input_text_offset .. limit-1] with its expansion.
!      This allows the node names and menu entries themselves to be
!      constructed via a macro, as in:
          @macro foo{p, q}
          Together: \p\ & \q\.
          @end macro
*************** get_until_in_line (expand, match, string
*** 1849,1884 ****
  
    if (expand && !executing_string && !me_executing_string)
      {
!       char *xp;
!       unsigned xp_len, new_len;
!       
!       /* Get original string from input.  */
!       unsigned raw_len = limit - input_text_offset;
!       char *str = xmalloc (raw_len + 1);
!       strncpy (str, input_text + input_text_offset, raw_len);
!       str[raw_len] = 0;
!       
!       /* Expand it.  */
!       xp = expansion (str, 0);
!       xp_len = strlen (xp);
!       free (str);
!       
!       /* Plunk the expansion into the middle of `input_text' --
!          which is terminated by a newline, not a null.  */
!       str = xmalloc (real_bottom - limit + 1);
!       strncpy (str, input_text + limit, real_bottom - limit + 1);
!       new_len = input_text_offset + xp_len + real_bottom - limit + 1;
!       input_text = xrealloc (input_text, new_len);
!       strcpy (input_text + input_text_offset, xp);
!       strncpy (input_text + input_text_offset + xp_len, str,
! 	       real_bottom - limit + 1);
!       free (str);
!       free (xp);
!       
!       limit += xp_len - raw_len;
!       real_bottom += xp_len - raw_len;
      }
  
    size_of_input_text = limit;
    get_until (match, string);
    size_of_input_text = real_bottom;
--- 1922,1931 ----
  
    if (expand && !executing_string && !me_executing_string)
      {
!       replace_with_expansion (input_text_offset, &limit);
      }
  
+   real_bottom = size_of_input_text;
    size_of_input_text = limit;
    get_until (match, string);
    size_of_input_text = real_bottom;
*************** get_until_in_braces (match, string)
*** 1937,1943 ****
  
    match_len = i - input_text_offset;
    temp = (char *)xmalloc (2 + match_len);
!   strncpy (temp, input_text + input_text_offset, match_len);
    temp[match_len] = 0;
    input_text_offset = i;
    *string = temp;
--- 1984,1990 ----
  
    match_len = i - input_text_offset;
    temp = (char *)xmalloc (2 + match_len);
!   memcpy (temp, input_text + input_text_offset, match_len);
    temp[match_len] = 0;
    input_text_offset = i;
    *string = temp;
*************** reader_loop ()
*** 2329,2335 ****
  
        character = curchar ();
  
!       if (!in_fixed_width_font &&
            (character == '\'' || character == '`') &&
            input_text[input_text_offset + 1] == character)
          {
--- 2376,2384 ----
  
        character = curchar ();
  
!       /* If only_macro_expansion is non-zero, only
! 	 handle macros and leave everything else intact.  */
!       if (!only_macro_expansion && !in_fixed_width_font &&
            (character == '\'' || character == '`') &&
            input_text[input_text_offset + 1] == character)
          {
*************** reader_loop ()
*** 2337,2343 ****
            character = '"';
          }
  
!       if (character == '-')
          {
            dash_count++;
            if (dash_count == 2 && !in_fixed_width_font)
--- 2386,2392 ----
            character = '"';
          }
  
!       if (!only_macro_expansion && character == '-')
          {
            dash_count++;
            if (dash_count == 2 && !in_fixed_width_font)
*************** reader_loop ()
*** 2353,2359 ****
  
        /* If this is a whitespace character, then check to see if the line
           is blank.  If so, advance to the carriage return. */
!       if (whitespace (character))
          {
            register int i = input_text_offset + 1;
  
--- 2402,2408 ----
  
        /* If this is a whitespace character, then check to see if the line
           is blank.  If so, advance to the carriage return. */
!       if (!only_macro_expansion && whitespace (character))
          {
            register int i = input_text_offset + 1;
  
*************** reader_loop ()
*** 2376,2382 ****
  
            /* Check for a menu entry here, since the "escape sequence"
               that begins menu entries is "\n* ". */
!           if (in_menu && input_text_offset + 1 < size_of_input_text)
              {
                char *glean_node_from_menu (), *tem;
  
--- 2425,2432 ----
  
            /* Check for a menu entry here, since the "escape sequence"
               that begins menu entries is "\n* ". */
!           if (!only_macro_expansion && in_menu &&
! 	      input_text_offset + 1 < size_of_input_text)
              {
                char *glean_node_from_menu (), *tem;
  
*************** reader_loop ()
*** 2391,2426 ****
        switch (character)
          {
          case COMMAND_PREFIX:
!           read_command ();
!           break;
  
          case '{':
            /* Special case.  I'm not supposed to see this character by itself.
               If I do, it means there is a syntax error in the input text.
               Report the error here, but remember this brace on the stack so
               you can ignore its partner. */
  
!           line_error (_("Misplaced %c"), '{');
!           remember_brace (misplaced_brace);
! 
!           /* Don't advance input_text_offset since this happens in
!              remember_brace ().
!              input_text_offset++;
!            */
!           break;
  
          case '}':
!           pop_and_call_brace ();
!           input_text_offset++;
!           break;
  
          default:
            add_char (character);
            input_text_offset++;
          }
      }
  #if defined (HAVE_MACROS)
!   if (macro_expansion_output_stream)
      maybe_write_itext (input_text, input_text_offset);
  #endif /* HAVE_MACROS */
  }
--- 2441,2485 ----
        switch (character)
          {
          case COMMAND_PREFIX:
!           if (read_command () || !only_macro_expansion)
! 	    break;
  
+ 	/* FALLTHROUGH */
          case '{':
            /* Special case.  I'm not supposed to see this character by itself.
               If I do, it means there is a syntax error in the input text.
               Report the error here, but remember this brace on the stack so
               you can ignore its partner. */
  
! 	  if (!only_macro_expansion)
! 	    {
! 	      line_error (_("Misplaced %c"), '{');
! 	      remember_brace (misplaced_brace);
! 
! 	      /* Don't advance input_text_offset since this happens in
! 		 remember_brace ().
! 		 input_text_offset++;
! 	      */
! 	      break;
! 	    }
  
+ 	/* FALLTHROUGH */
          case '}':
! 	  if (!only_macro_expansion)
! 	    {
! 	      pop_and_call_brace ();
! 	      input_text_offset++;
! 	      break;
! 	    }
  
+ 	/* FALLTHROUGH */
          default:
            add_char (character);
            input_text_offset++;
          }
      }
  #if defined (HAVE_MACROS)
!   if (macro_expansion_output_stream && !only_macro_expansion)
      maybe_write_itext (input_text, input_text_offset);
  #endif /* HAVE_MACROS */
  }
*************** get_command_entry (string)
*** 2450,2462 ****
  }
  
  /* input_text_offset is right at the command prefix character.
!    Read the next token to determine what to do. */
! void
  read_command ()
  {
    COMMAND *entry;
  
-   input_text_offset++;
    free_and_clear (&command);
    command = read_token ();
  
--- 2509,2522 ----
  }
  
  /* input_text_offset is right at the command prefix character.
!    Read the next token to determine what to do.  Return zero
!    if there's no known command or macro after the prefix character.  */
! int
  read_command ()
  {
    COMMAND *entry;
+   int old_text_offset = input_text_offset++;
  
    free_and_clear (&command);
    command = read_token ();
  
*************** read_command ()
*** 2479,2500 ****
          if (!(def->flags & ME_RECURSE))
            def->inhibited = 0;
  
!         return;
        }
      }
  #endif /* HAVE_MACROS */
  
    entry = get_command_entry (command);
    if (entry == (COMMAND *)-1)
      {
        line_error (_("Unknown command `%s'"), command);
!       return;
      }
  
    if (entry->argument_in_braces)
      remember_brace (entry->proc);
  
    (*(entry->proc)) (START, output_paragraph_offset, 0);
  }
  
  /* Return the string which invokes PROC; a pointer to a function. */
--- 2539,2569 ----
          if (!(def->flags & ME_RECURSE))
            def->inhibited = 0;
  
!         return 1;
        }
      }
  #endif /* HAVE_MACROS */
  
+   if (only_macro_expansion)
+     {
+       /* Back up to the place where we were called, so the
+ 	 caller will have a chance to process this non-macro.  */
+       input_text_offset = old_text_offset;
+       return 0;
+     }
+ 
    entry = get_command_entry (command);
    if (entry == (COMMAND *)-1)
      {
        line_error (_("Unknown command `%s'"), command);
!       return 0;
      }
  
    if (entry->argument_in_braces)
      remember_brace (entry->proc);
  
    (*(entry->proc)) (START, output_paragraph_offset, 0);
+   return 1;
  }
  
  /* Return the string which invokes PROC; a pointer to a function. */
*************** add_char (character)
*** 2838,2844 ****
                            if (t1 != temp)
                              {
                                adjust_braces_following (temp, (- (t1 - temp)));
!                               strncpy ((char *) &output_paragraph[temp],
                                         (char *) &output_paragraph[t1],
                                         (output_paragraph_offset - t1));
                                output_paragraph_offset -= (t1 - temp);
--- 2907,2913 ----
                            if (t1 != temp)
                              {
                                adjust_braces_following (temp, (- (t1 - temp)));
!                               memcpy ((char *) &output_paragraph[temp],
                                         (char *) &output_paragraph[t1],
                                         (output_paragraph_offset - t1));
                                output_paragraph_offset -= (t1 - temp);
*************** add_char (character)
*** 2861,2867 ****
                                     indentation != current_indent)
                                temp_buffer[indentation++] = ' ';
  
!                             strncpy ((char *) &temp_buffer[current_indent],
                                       (char *) &output_paragraph[temp],
                                       buffer_len - current_indent);
  
--- 2930,2936 ----
                                     indentation != current_indent)
                                temp_buffer[indentation++] = ' ';
  
!                             memcpy ((char *) &temp_buffer[current_indent],
                                       (char *) &output_paragraph[temp],
                                       buffer_len - current_indent);
  
*************** add_char (character)
*** 2873,2879 ****
                                     (paragraph_buffer_len += buffer_len));
                                  output_paragraph = tt;
                                }
!                             strncpy ((char *) &output_paragraph[temp],
                                       temp_buffer, buffer_len);
                              output_paragraph_offset += current_indent;
                              free (temp_buffer);
--- 2942,2948 ----
                                     (paragraph_buffer_len += buffer_len));
                                  output_paragraph = tt;
                                }
!                             memcpy ((char *) &output_paragraph[temp],
                                       temp_buffer, buffer_len);
                              output_paragraph_offset += current_indent;
                              free (temp_buffer);
*************** cm_node ()
*** 4747,4753 ****
--- 4816,4826 ----
      append_to_expansion_output (input_text_offset + 1);
  #endif /* HAVE_MACROS */
  
+   /* 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);
*************** cm_node ()
*** 4952,4969 ****
        char *temp;
        int op_orig = output_paragraph_offset;
  
!       temp = (char *)xmalloc (3 + strlen (next));
!       sprintf (temp, ", %s", next);
!       me_execute_string (temp);
!       free (temp);
! 
!       temp = (char *)xmalloc (3 + strlen (prev));
!       sprintf (temp, ", %s", prev);
!       me_execute_string (temp);
!       free (temp);
! 
!       temp = (char *)xmalloc (4 + strlen (up));
!       sprintf (temp, ", %s", up);
        me_execute_string (temp);
        free (temp);
  
--- 5025,5032 ----
        char *temp;
        int op_orig = output_paragraph_offset;
  
!       temp = (char *)xmalloc (7 + strlen (next) + strlen (prev) + strlen (up));
!       sprintf (temp, ", %s, %s, %s", next, prev, up);
        me_execute_string (temp);
        free (temp);
  
*************** glean_node_from_menu (remember_reference
*** 5592,5597 ****
--- 5655,5663 ----
  {
    int i, orig_offset = input_text_offset;
    char *nodename;
+   char *line, *expanded_line;
+   char *old_input = input_text;
+   size_t old_size = size_of_input_text;
  
    if (strncmp (&input_text[input_text_offset + 1],
                 menu_starter,
*************** glean_node_from_menu (remember_reference
*** 5600,5605 ****
--- 5666,5681 ----
    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;
+   size_of_input_text = strlen (expanded_line);
+ 
    get_until_in_line (0, ":", &nodename);
    if (curchar () == ':')
      input_text_offset++;
*************** glean_node_from_menu (remember_reference
*** 5609,5628 ****
      goto save_node;
  
    free (nodename);
!   get_rest_of_line (&nodename);
! 
!   /* Special hack: If the nodename follows the menu item name,
!      then we have to read the rest of the line in order to find
!      out what the nodename is.  But we still have to read the
!      line later, in order to process any formatting commands that
!      might be present.  So un-count the carriage return that has just
!      been counted. */
!   line_number--;
! 
    isolate_nodename (nodename);
  
  save_node:
    input_text_offset = orig_offset;
    normalize_node_name (nodename);
    i = strlen (nodename);
    if (i && nodename[i - 1] == ':')
--- 5685,5698 ----
      goto save_node;
  
    free (nodename);
!   get_until_in_line (0, "\n", &nodename);
    isolate_nodename (nodename);
  
  save_node:
+   input_text = old_input;
    input_text_offset = orig_offset;
+   size_of_input_text = old_size;
+   free (expanded_line);
    normalize_node_name (nodename);
    i = strlen (nodename);
    if (i && nodename[i - 1] == ':')
*************** cm_detailmenu ()
*** 5723,5734 ****
  /* **************************************************************** */
  
  /* Return next comma-delimited argument, but do not cross a close-brace
!    boundary.  Clean up whitespace, too.  */
  char *
! get_xref_token ()
  {
    char *string;
  
    get_until_in_braces (",", &string);
    if (curchar () == ',')
      input_text_offset++;
--- 5793,5827 ----
  /* **************************************************************** */
  
  /* Return next comma-delimited argument, but do not cross a close-brace
!    boundary.  Clean up whitespace, too.  If EXPAND is non-zero, replace
!    the entire brace-delimited argument list with its expansion before
!    looking for the next comma.  */
  char *
! get_xref_token (expand)
  {
    char *string;
  
+ #if defined (HAVE_MACROS)
+   if (expand && !executing_string && !me_executing_string)
+     {
+       int old_offset = input_text_offset;
+ 
+       get_until_in_braces ("}", &string);
+       if (curchar () == '}')	/* as opposed to end of text */
+ 	input_text_offset++;
+       if (input_text_offset > old_offset)
+ 	{
+ 	  int limit = input_text_offset;
+ 
+ 	  input_text_offset = old_offset;
+ 	  only_macro_expansion++;
+ 	  replace_with_expansion (input_text_offset, &limit);
+ 	  only_macro_expansion--;
+ 	}
+       free (string);
+     }
+ #endif
+ 
    get_until_in_braces (",", &string);
    if (curchar () == ',')
      input_text_offset++;
*************** cm_xref (arg)
*** 5746,5756 ****
      {
        char *arg1, *arg2, *arg3, *arg4, *arg5;
  
!       arg1 = get_xref_token ();
!       arg2 = get_xref_token ();
!       arg3 = get_xref_token ();
!       arg4 = get_xref_token ();
!       arg5 = get_xref_token ();
  
        add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
  
--- 5839,5849 ----
      {
        char *arg1, *arg2, *arg3, *arg4, *arg5;
  
!       arg1 = get_xref_token (1);
!       arg2 = get_xref_token (0);
!       arg3 = get_xref_token (0);
!       arg4 = get_xref_token (0);
!       arg5 = get_xref_token (0);
  
        add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
  
*************** cm_inforef (arg)
*** 5852,5860 ****
  {
    if (arg == START)
      {
!       char *node = get_xref_token ();
!       char *pname = get_xref_token ();
!       char *file = get_xref_token ();
  
        if (*pname)
          execute_string ("*note %s: (%s)%s", pname, file, node);
--- 5945,5953 ----
  {
    if (arg == START)
      {
!       char *node = get_xref_token (1);
!       char *pname = get_xref_token (0);
!       char *file = get_xref_token (0);
  
        if (*pname)
          execute_string ("*note %s: (%s)%s", pname, file, node);
*************** cm_image (arg)
*** 5950,5961 ****
  {
    if (arg == START)
      {
!       char *name_arg = get_xref_token ();
        /* We don't yet care about any other args, but read them so they
           don't end up in the text.  */
!       char *arg = get_xref_token ();
        if (arg) free (arg);
!       arg = get_xref_token ();
        if (arg) free (arg);
        
        if (*name_arg)
--- 6043,6054 ----
  {
    if (arg == START)
      {
!       char *name_arg = get_xref_token (1);
        /* We don't yet care about any other args, but read them so they
           don't end up in the text.  */
!       char *arg = get_xref_token (0);
        if (arg) free (arg);
!       arg = get_xref_token (0);
        if (arg) free (arg);
        
        if (*name_arg)
*************** expansion (str, implicit_code)
*** 6665,6670 ****
--- 6758,6775 ----
    /* Inhibit any real output.  */
    int start = output_paragraph_offset;
    int saved_paragraph_is_open = paragraph_is_open;
+   int saved_output_column = output_column;
+ 
+   /* Inhibit indentation and filling, so that extra newlines
+      are not added to the expansion.  (This is undesirable if
+      we write the expanded text to macro_expansion_output_stream.)  */
+   int saved_filling_enabled = filling_enabled;
+   int saved_indented_fill = indented_fill;
+   int saved_no_indent = no_indent;
+ 
+   filling_enabled = 0;
+   indented_fill = 0;
+   no_indent = 1;
  
    inhibit_output_flushing ();
    paragraph_is_open = 1;
*************** expansion (str, implicit_code)
*** 6680,6685 ****
--- 6785,6794 ----
    /* Pretend it never happened.  */
    output_paragraph_offset = start;
    paragraph_is_open = saved_paragraph_is_open;
+   output_column = saved_output_column;
+   filling_enabled = saved_filling_enabled;
+   indented_fill = saved_indented_fill;
+   no_indent = saved_no_indent;
  
    return result;
  }
*************** index_add_arg (name)
*** 7983,7995 ****
  #if defined (HAVE_MACROS)
    if (macro_expansion_output_stream && !executing_string)
      {
!       int op_orig;
  
!       remember_itext (input_text, input_text_offset);
!       op_orig = output_paragraph_offset;
!       me_execute_string (index_entry);
!       me_execute_string ("\n");
!       output_paragraph_offset = op_orig;
      }
  #endif /* HAVE_MACROS */
  
--- 8092,8101 ----
  #if defined (HAVE_MACROS)
    if (macro_expansion_output_stream && !executing_string)
      {
!       char *index_line = (char *)alloca (strlen (index_entry) + 2);
  
!       sprintf (index_line, "%s\n", index_entry);
!       me_execute_string_keep_state (index_line, NULL);
      }
  #endif /* HAVE_MACROS */
  
*************** cm_footnote ()
*** 8515,8521 ****
  
        len = (loc - input_text_offset) - 1;
        note = (char *)xmalloc (len + 1);
!       strncpy (note, &input_text[input_text_offset], len);
        note[len] = 0;
        input_text_offset = loc;
      }
--- 8621,8627 ----
  
        len = (loc - input_text_offset) - 1;
        note = (char *)xmalloc (len + 1);
!       memcpy (note, &input_text[input_text_offset], len);
        note[len] = 0;
        input_text_offset = loc;
      }
*************** cm_footnote ()
*** 8524,8539 ****
       output stream.  This is like the case in index_add_arg.  */
    if (macro_expansion_output_stream && !executing_string)
      {
-       int op_orig;
- 
-       remember_itext (input_text, input_text_offset);
-       op_orig = output_paragraph_offset;
-       me_execute_string (note);
        /* Calling me_execute_string on a lone } provokes an error, since
           as far as the reader knows there is no matching {.  We wrote
           the { above in the call to append_to_expansion_output. */
!       write_region_to_macro_output ("}", 0, 1);
!       output_paragraph_offset = op_orig;
      }
  
    if (!current_node || !*current_node)
--- 8630,8639 ----
       output stream.  This is like the case in index_add_arg.  */
    if (macro_expansion_output_stream && !executing_string)
      {
        /* Calling me_execute_string on a lone } provokes an error, since
           as far as the reader knows there is no matching {.  We wrote
           the { above in the call to append_to_expansion_output. */
!       me_execute_string_keep_state (note, "}");
      }
  
    if (!current_node || !*current_node)
*************** apply (named, actuals, body)
*** 8918,8935 ****
    return (new_body);
  }
  
! /* Execute the macro passed in DEF, a pointer to a MACRO_DEF.  */
! void
! execute_macro (def)
       MACRO_DEF *def;
  {
    char **arglist;
    int num_args;
    char *execution_string = (char *)NULL;
  
-   if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
-     me_append_before_this_command ();
- 
    /* Find out how many arguments this macro definition takes. */
    num_args = array_len (def->arglist);
  
--- 9018,9033 ----
    return (new_body);
  }
  
! /* Expand macro passed in DEF, a pointer to a MACRO_DEF, and
!    return its expansion as a string.  */
! char *
! expand_macro (def)
       MACRO_DEF *def;
  {
    char **arglist;
    int num_args;
    char *execution_string = (char *)NULL;
  
    /* Find out how many arguments this macro definition takes. */
    num_args = array_len (def->arglist);
  
*************** execute_macro (def)
*** 8947,8952 ****
--- 9045,9064 ----
      execution_string = apply (def->arglist, arglist, def->body);
  
    free_array (arglist);
+   return execution_string;
+ }
+ 
+ /* Execute the macro passed in DEF, a pointer to a MACRO_DEF.  */
+ void
+ execute_macro (def)
+      MACRO_DEF *def;
+ {
+   char *execution_string;
+ 
+   if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
+     me_append_before_this_command ();
+ 
+   execution_string = expand_macro (def);
  
    if (def->body)
      {
*************** cm_macro ()
*** 8997,9003 ****
  
      len = i - start;
      name = (char *)xmalloc (1 + len);
!     strncpy (name, input_text + start, len);
      name[len] = 0;
      input_text_offset = i;
    }
--- 9109,9115 ----
  
      len = i - start;
      name = (char *)xmalloc (1 + len);
!     memcpy (name, input_text + start, len);
      name[len] = 0;
      input_text_offset = i;
    }
*************** cm_macro ()
*** 9039,9045 ****
                    /* Found the end of the current arglist word.  Save it. */
                    len = i - input_text_offset;
                    word = (char *)xmalloc (1 + len);
!                   strncpy (word, input_text + input_text_offset, len);
                    word[len] = 0;
                    input_text_offset = i;
  
--- 9151,9157 ----
                    /* Found the end of the current arglist word.  Save it. */
                    len = i - input_text_offset;
                    word = (char *)xmalloc (1 + len);
!                   memcpy (word, input_text + input_text_offset, len);
                    word[len] = 0;
                    input_text_offset = i;
  
*************** cm_unmacro ()
*** 9193,9199 ****
  
    for (i = 0; line[i] && !whitespace (line[i]); i++);
    name = (char *)xmalloc (i + 1);
!   strncpy (name, line, i);
    name[i] = 0;
  
    def = delete_macro (name);
--- 9305,9311 ----
  
    for (i = 0; line[i] && !whitespace (line[i]); i++);
    name = (char *)xmalloc (i + 1);
!   memcpy (name, line, i);
    name[i] = 0;
  
    def = delete_macro (name);
*************** me_execute_string (execution_string)
*** 9325,9334 ****
--- 9437,9478 ----
  
    me_executing_string++;
    reader_loop ();
+   free (input_filename);
    popfile ();
    me_executing_string--;
  }
  
+ /* A wrapper around me_execute_string which saves and restores
+    variables important for output generation.  This is called
+    when we need to produce macro-expanded output for input which
+    leaves no traces in the Info output.  */
+ void
+ me_execute_string_keep_state (execution_string, append_string)
+      char *execution_string, *append_string;
+ {
+   int op_orig, opcol_orig, popen_orig;
+   int fill_orig, newline_orig, indent_orig;
+ 
+   remember_itext (input_text, input_text_offset);
+   op_orig = output_paragraph_offset;
+   opcol_orig = output_column;
+   popen_orig = paragraph_is_open;
+   fill_orig = filling_enabled;
+   newline_orig = last_char_was_newline;
+   filling_enabled = 0;
+   indent_orig = no_indent;
+   no_indent = 1;
+   me_execute_string (execution_string);
+   if (append_string)
+     write_region_to_macro_output (append_string, 0, strlen (append_string));
+   output_paragraph_offset = op_orig;
+   output_column = opcol_orig;
+   paragraph_is_open = popen_orig;
+   filling_enabled = fill_orig;
+   last_char_was_newline = newline_orig;
+   no_indent = indent_orig;
+ }
+ 
  /* Append the text which appears in input_text from the last offset to
     the current OFFSET. */
  void
*************** get_brace_args (quote_single)
*** 9461,9467 ****
            if (len || (character != '}'))
              {
                word = (char *)xmalloc (1 + len);
!               strncpy (word, input_text + start, len);
                word[len] = 0;
  
                /* Clean up escaped characters. */
--- 9605,9611 ----
            if (len || (character != '}'))
              {
                word = (char *)xmalloc (1 + len);
!               memcpy (word, input_text + start, len);
                word[len] = 0;
  
                /* Clean up escaped characters. */
*************** extract_colon_unit (string, index)
*** 9552,9558 ****
        char *value;
  
        value = (char *)xmalloc (1 + (i - start));
!       strncpy (value, &string[start], (i - start));
        value [i - start] = 0;
  
        return (value);
--- 9696,9702 ----
        char *value;
  
        value = (char *)xmalloc (1 + (i - start));
!       memcpy (value, &string[start], (i - start));
        value [i - start] = 0;
  
        return (value);
*** djgpp/README.~1	Fri May 22 18:53:16 1998
--- djgpp/README	Fri Jun 26 21:40:14 1998
***************
*** 16,21 ****
--- 16,23 ----
        - a DJGPP port of Bash;
        - a port of GNU Sed;
        - ginstall and rm from the Fileutils package;
+       - DJGPP ports of Fileutils, Diffutils, and Grep (only if you
+         need to reconfigure the source distribution);
        - etags (from the Emacs distribution) and mkid (from ID-utils)
          if you need the TAGS and ID targets of the Makefile's.
  
***************
*** 346,351 ****
--- 348,374 ----
     forget to edit the indirect file table in the main Info file and
     change the sub-file filenames there too!
  
+    An alternative for those packages which have more than 99 Info
+    sub-files is to generate them from the Texinfo sources and force
+    Makeinfo to produce files without the .iNN extensions, like this:
+ 
+ 	        makeinfo -o foo foo.txi
+ 
+    This causes Makeinfo to generate file names like foo-1, foo-2,
+    etc., which leave more place for the numeric index.  If necessary,
+    Makeinfo will automatically remove characters from the end of the
+    argument to `-o'.  For example, "-o texinfo" produces files
+    texinf-1, ..., texin-10, ..., texi-100, etc. on platforms which
+    only support 8+3 file names.
+ 
+    Saying "@setfilename foo" near the beginning of the Texinfo source
+    file is another way of forcing Makeinfo to produce files without
+    the .iNN extensions.
+ 
+    Using Makeinfo to produce files whose names are "compression-ready"
+    is more convenient, since you don't need to edit the the indirect
+    file table to reflect the changes in file names.
+ 
     On platforms which support long filenames, the usual Info behavior
     of appending `.gz' or `.Z' to the original filename also works;
     this is done *before* Info checks the above butchered names.
***************
*** 384,390 ****
     whose name follows the `>' character.
  
     If INFO_PRINT_COMMAND is not defined, the DJGPP port will use
!    ">PRN" as the default, which causes it print to the local priner
     device, PRN.
  
  6. Bug Reports
--- 407,413 ----
     whose name follows the `>' character.
  
     If INFO_PRINT_COMMAND is not defined, the DJGPP port will use
!    ">PRN" as the default, which causes it to print to the local printer
     device, PRN.
  
  6. Bug Reports
