xref: /netbsd-src/external/gpl2/texinfo/dist/info/echo-area.c (revision d3737e9cfd8cdb680cae0994d1d5f26b365d6d47)
1*d3737e9cSchristos /*	$NetBSD: echo-area.c,v 1.2 2016/01/14 00:34:52 christos Exp $	*/
229619d2aSchristos 
329619d2aSchristos /* echo-area.c -- how to read a line in the echo area.
429619d2aSchristos    Id: echo-area.c,v 1.7 2004/12/14 00:15:36 karl Exp
529619d2aSchristos 
629619d2aSchristos    Copyright (C) 1993, 1997, 1998, 1999, 2001, 2004 Free Software
729619d2aSchristos    Foundation, Inc.
829619d2aSchristos 
929619d2aSchristos    This program is free software; you can redistribute it and/or modify
1029619d2aSchristos    it under the terms of the GNU General Public License as published by
1129619d2aSchristos    the Free Software Foundation; either version 2, or (at your option)
1229619d2aSchristos    any later version.
1329619d2aSchristos 
1429619d2aSchristos    This program is distributed in the hope that it will be useful,
1529619d2aSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1629619d2aSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1729619d2aSchristos    GNU General Public License for more details.
1829619d2aSchristos 
1929619d2aSchristos    You should have received a copy of the GNU General Public License
2029619d2aSchristos    along with this program; if not, write to the Free Software
2129619d2aSchristos    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2229619d2aSchristos 
2329619d2aSchristos    Written by Brian Fox (bfox@ai.mit.edu). */
2429619d2aSchristos 
2529619d2aSchristos #include "info.h"
2629619d2aSchristos 
2729619d2aSchristos #if defined (FD_SET)
2829619d2aSchristos #  if defined (hpux)
2929619d2aSchristos #    define fd_set_cast(x) (int *)(x)
3029619d2aSchristos #  else
3129619d2aSchristos #    define fd_set_cast(x) (fd_set *)(x)
3229619d2aSchristos #  endif /* !hpux */
3329619d2aSchristos #endif /* FD_SET */
3429619d2aSchristos 
3529619d2aSchristos /* Non-zero means that C-g was used to quit reading input. */
3629619d2aSchristos int info_aborted_echo_area = 0;
3729619d2aSchristos 
3829619d2aSchristos /* Non-zero means that the echo area is being used to read input. */
3929619d2aSchristos int echo_area_is_active = 0;
4029619d2aSchristos 
4129619d2aSchristos /* The address of the last command executed in the echo area. */
4229619d2aSchristos VFunction *ea_last_executed_command = (VFunction *)NULL;
4329619d2aSchristos 
4429619d2aSchristos /* Non-zero means that the last command executed while reading input
4529619d2aSchristos    killed some text. */
4629619d2aSchristos int echo_area_last_command_was_kill = 0;
4729619d2aSchristos 
4829619d2aSchristos /* Variables which hold on to the current state of the input line. */
4929619d2aSchristos static char input_line[1 + EA_MAX_INPUT];
5029619d2aSchristos static char *input_line_prompt;
5129619d2aSchristos static int input_line_point;
5229619d2aSchristos static int input_line_beg;
5329619d2aSchristos static int input_line_end;
5429619d2aSchristos static NODE input_line_node = {
5529619d2aSchristos   (char *)NULL, (char *)NULL, (char *)NULL, input_line,
5629619d2aSchristos   EA_MAX_INPUT, 0, N_IsInternal
5729619d2aSchristos };
5829619d2aSchristos 
5929619d2aSchristos static void echo_area_initialize_node (void);
6029619d2aSchristos static void push_echo_area (void), pop_echo_area (void);
6129619d2aSchristos static int echo_area_stack_contains_completions_p (void);
6229619d2aSchristos 
6329619d2aSchristos static void ea_kill_text (int from, int to);
6429619d2aSchristos 
6529619d2aSchristos /* Non-zero means we force the user to complete. */
6629619d2aSchristos static int echo_area_must_complete_p = 0;
6729619d2aSchristos static int completions_window_p (WINDOW *window);
6829619d2aSchristos 
6929619d2aSchristos /* If non-null, this is a window which was specifically created to display
7029619d2aSchristos    possible completions output.  We remember it so we can delete it when
7129619d2aSchristos    appropriate. */
7229619d2aSchristos static WINDOW *echo_area_completions_window = (WINDOW *)NULL;
7329619d2aSchristos 
7429619d2aSchristos /* Variables which keep track of the window which was active prior to
7529619d2aSchristos    entering the echo area. */
7629619d2aSchristos static WINDOW *calling_window = (WINDOW *)NULL;
7729619d2aSchristos static NODE *calling_window_node = (NODE *)NULL;
7829619d2aSchristos static long calling_window_point = 0;
7929619d2aSchristos static long calling_window_pagetop = 0;
8029619d2aSchristos 
8129619d2aSchristos /* Remember the node and pertinent variables of the calling window. */
8229619d2aSchristos static void
remember_calling_window(WINDOW * window)8329619d2aSchristos remember_calling_window (WINDOW *window)
8429619d2aSchristos {
8529619d2aSchristos   /* Only do this if the calling window is not the completions window, or,
8629619d2aSchristos      if it is the completions window and there is no other window. */
8729619d2aSchristos   if (!completions_window_p (window) ||
8829619d2aSchristos       ((window == windows) && !(window->next)))
8929619d2aSchristos     {
9029619d2aSchristos       calling_window = window;
9129619d2aSchristos       calling_window_node = window->node;
9229619d2aSchristos       calling_window_point = window->point;
9329619d2aSchristos       calling_window_pagetop = window->pagetop;
9429619d2aSchristos     }
9529619d2aSchristos }
9629619d2aSchristos 
9729619d2aSchristos /* Restore the caller's window so that it shows the node that it was showing
9829619d2aSchristos    on entry to info_read_xxx_echo_area (). */
9929619d2aSchristos static void
restore_calling_window(void)10029619d2aSchristos restore_calling_window (void)
10129619d2aSchristos {
10229619d2aSchristos   register WINDOW *win, *compwin = (WINDOW *)NULL;
10329619d2aSchristos 
10429619d2aSchristos   /* If the calling window is still visible, and it is the window that
10529619d2aSchristos      we used for completions output, then restore the calling window. */
10629619d2aSchristos   for (win = windows; win; win = win->next)
10729619d2aSchristos     {
10829619d2aSchristos       if (completions_window_p (win))
10929619d2aSchristos         compwin = win;
11029619d2aSchristos 
11129619d2aSchristos       if (win == calling_window && win == compwin)
11229619d2aSchristos         {
11329619d2aSchristos           window_set_node_of_window (calling_window, calling_window_node);
11429619d2aSchristos           calling_window->point = calling_window_point;
11529619d2aSchristos           calling_window->pagetop = calling_window_pagetop;
11629619d2aSchristos           compwin = (WINDOW *)NULL;
11729619d2aSchristos           break;
11829619d2aSchristos         }
11929619d2aSchristos     }
12029619d2aSchristos 
12129619d2aSchristos   /* Delete the completions window if it is still present, it isn't the
12229619d2aSchristos      last window on the screen, and there aren't any prior echo area reads
12329619d2aSchristos      pending which created a completions window. */
12429619d2aSchristos   if (compwin)
12529619d2aSchristos     {
12629619d2aSchristos       if ((compwin != windows || windows->next) &&
12729619d2aSchristos           !echo_area_stack_contains_completions_p ())
12829619d2aSchristos         {
12929619d2aSchristos           WINDOW *next;
13029619d2aSchristos           int pagetop = 0;
13129619d2aSchristos           int start = 0;
13229619d2aSchristos           int end = 0;
13329619d2aSchristos           int amount = 0;
13429619d2aSchristos 
13529619d2aSchristos           next = compwin->next;
13629619d2aSchristos           if (next)
13729619d2aSchristos             {
13829619d2aSchristos               start = next->first_row;
13929619d2aSchristos               end = start + next->height;
14029619d2aSchristos               amount = - (compwin->height + 1);
14129619d2aSchristos               pagetop = next->pagetop;
14229619d2aSchristos             }
14329619d2aSchristos 
14429619d2aSchristos           info_delete_window_internal (compwin);
14529619d2aSchristos 
14629619d2aSchristos           /* This is not necessary because info_delete_window_internal ()
14729619d2aSchristos              calls echo_area_inform_of_deleted_window (), which does the
14829619d2aSchristos              right thing. */
14929619d2aSchristos #if defined (UNNECESSARY)
15029619d2aSchristos           echo_area_completions_window = (WINDOW *)NULL;
15129619d2aSchristos #endif /* UNNECESSARY */
15229619d2aSchristos 
15329619d2aSchristos           if (next)
15429619d2aSchristos             {
15529619d2aSchristos               display_scroll_display (start, end, amount);
15629619d2aSchristos               next->pagetop = pagetop;
15729619d2aSchristos               display_update_display (windows);
15829619d2aSchristos             }
15929619d2aSchristos         }
16029619d2aSchristos     }
16129619d2aSchristos }
16229619d2aSchristos 
16329619d2aSchristos /* Set up a new input line with PROMPT. */
16429619d2aSchristos static void
initialize_input_line(char * prompt)16529619d2aSchristos initialize_input_line (char *prompt)
16629619d2aSchristos {
16729619d2aSchristos   input_line_prompt = prompt;
16829619d2aSchristos   if (prompt)
16929619d2aSchristos     strcpy (input_line, prompt);
17029619d2aSchristos   else
17129619d2aSchristos     input_line[0] = '\0';
17229619d2aSchristos 
17329619d2aSchristos   input_line_beg = input_line_end = input_line_point = strlen (prompt);
17429619d2aSchristos }
17529619d2aSchristos 
17629619d2aSchristos static char *
echo_area_after_read(void)17729619d2aSchristos echo_area_after_read (void)
17829619d2aSchristos {
17929619d2aSchristos   char *return_value;
18029619d2aSchristos 
18129619d2aSchristos   if (info_aborted_echo_area)
18229619d2aSchristos     {
18329619d2aSchristos       info_aborted_echo_area = 0;
18429619d2aSchristos       return_value = (char *)NULL;
18529619d2aSchristos     }
18629619d2aSchristos   else
18729619d2aSchristos     {
18829619d2aSchristos       if (input_line_beg == input_line_end)
18929619d2aSchristos         return_value = xstrdup ("");
19029619d2aSchristos       else
19129619d2aSchristos         {
19229619d2aSchristos           int line_len = input_line_end - input_line_beg;
19329619d2aSchristos           return_value = (char *) xmalloc (1 + line_len);
19429619d2aSchristos           strncpy (return_value, &input_line[input_line_beg], line_len);
19529619d2aSchristos           return_value[line_len] = '\0';
19629619d2aSchristos         }
19729619d2aSchristos     }
19829619d2aSchristos   return (return_value);
19929619d2aSchristos }
20029619d2aSchristos 
20129619d2aSchristos /* Read a line of text in the echo area.  Return a malloc ()'ed string,
20229619d2aSchristos    or NULL if the user aborted out of this read.  WINDOW is the currently
20329619d2aSchristos    active window, so that we can restore it when we need to.  PROMPT, if
20429619d2aSchristos    non-null, is a prompt to print before reading the line. */
20529619d2aSchristos char *
info_read_in_echo_area(WINDOW * window,char * prompt)20629619d2aSchristos info_read_in_echo_area (WINDOW *window, char *prompt)
20729619d2aSchristos {
20829619d2aSchristos   char *line;
20929619d2aSchristos 
21029619d2aSchristos   /* If the echo area is already active, remember the current state. */
21129619d2aSchristos   if (echo_area_is_active)
21229619d2aSchristos     push_echo_area ();
21329619d2aSchristos 
21429619d2aSchristos   /* Initialize our local variables. */
21529619d2aSchristos   initialize_input_line (prompt);
21629619d2aSchristos 
21729619d2aSchristos   /* Initialize the echo area for the first (but maybe not the last) time. */
21829619d2aSchristos   echo_area_initialize_node ();
21929619d2aSchristos 
22029619d2aSchristos   /* Save away the original node of this window, and the window itself,
22129619d2aSchristos      so echo area commands can temporarily use this window. */
22229619d2aSchristos   remember_calling_window (window);
22329619d2aSchristos 
22429619d2aSchristos   /* Let the rest of Info know that the echo area is active. */
22529619d2aSchristos   echo_area_is_active++;
22629619d2aSchristos   active_window = the_echo_area;
22729619d2aSchristos 
22829619d2aSchristos   /* Read characters in the echo area. */
22929619d2aSchristos   info_read_and_dispatch ();
23029619d2aSchristos 
23129619d2aSchristos   echo_area_is_active--;
23229619d2aSchristos 
23329619d2aSchristos   /* Restore the original active window and show point in it. */
23429619d2aSchristos   active_window = calling_window;
23529619d2aSchristos   restore_calling_window ();
23629619d2aSchristos   display_cursor_at_point (active_window);
23729619d2aSchristos   fflush (stdout);
23829619d2aSchristos 
23929619d2aSchristos   /* Get the value of the line. */
24029619d2aSchristos   line = echo_area_after_read ();
24129619d2aSchristos 
24229619d2aSchristos   /* If there is a previous loop waiting for us, restore it now. */
24329619d2aSchristos   if (echo_area_is_active)
24429619d2aSchristos     pop_echo_area ();
24529619d2aSchristos 
24629619d2aSchristos   /* Return the results to the caller. */
24729619d2aSchristos   return (line);
24829619d2aSchristos }
24929619d2aSchristos 
25029619d2aSchristos /* (re) Initialize the echo area node. */
25129619d2aSchristos static void
echo_area_initialize_node(void)25229619d2aSchristos echo_area_initialize_node (void)
25329619d2aSchristos {
25429619d2aSchristos   register int i;
25529619d2aSchristos 
25629619d2aSchristos   for (i = input_line_end; (unsigned int) i < sizeof (input_line); i++)
25729619d2aSchristos     input_line[i] = ' ';
25829619d2aSchristos 
25929619d2aSchristos   input_line[i - 1] = '\n';
26029619d2aSchristos   window_set_node_of_window (the_echo_area, &input_line_node);
26129619d2aSchristos   input_line[input_line_end] = '\n';
26229619d2aSchristos }
26329619d2aSchristos 
26429619d2aSchristos /* Prepare to read characters in the echo area.  This can initialize the
26529619d2aSchristos    echo area node, but its primary purpose is to side effect the input
26629619d2aSchristos    line buffer contents. */
26729619d2aSchristos void
echo_area_prep_read(void)26829619d2aSchristos echo_area_prep_read (void)
26929619d2aSchristos {
27029619d2aSchristos   if (the_echo_area->node != &input_line_node)
27129619d2aSchristos     echo_area_initialize_node ();
27229619d2aSchristos 
27329619d2aSchristos   the_echo_area->point = input_line_point;
27429619d2aSchristos   input_line[input_line_end] = '\n';
27529619d2aSchristos   display_update_one_window (the_echo_area);
27629619d2aSchristos   display_cursor_at_point (active_window);
27729619d2aSchristos }
27829619d2aSchristos 
27929619d2aSchristos 
28029619d2aSchristos /* **************************************************************** */
28129619d2aSchristos /*                                                                  */
28229619d2aSchristos /*                   Echo Area Movement Commands                    */
28329619d2aSchristos /*                                                                  */
28429619d2aSchristos /* **************************************************************** */
28529619d2aSchristos 
28629619d2aSchristos DECLARE_INFO_COMMAND (ea_forward, _("Move forward a character"))
28729619d2aSchristos {
28829619d2aSchristos   if (count < 0)
28929619d2aSchristos     ea_backward (window, -count, key);
29029619d2aSchristos   else
29129619d2aSchristos     {
29229619d2aSchristos       input_line_point += count;
29329619d2aSchristos       if (input_line_point > input_line_end)
29429619d2aSchristos         input_line_point = input_line_end;
29529619d2aSchristos     }
29629619d2aSchristos }
29729619d2aSchristos 
29829619d2aSchristos DECLARE_INFO_COMMAND (ea_backward, _("Move backward a character"))
29929619d2aSchristos {
30029619d2aSchristos   if (count < 0)
30129619d2aSchristos     ea_forward (window, -count, key);
30229619d2aSchristos   else
30329619d2aSchristos     {
30429619d2aSchristos       input_line_point -= count;
30529619d2aSchristos       if (input_line_point < input_line_beg)
30629619d2aSchristos         input_line_point = input_line_beg;
30729619d2aSchristos     }
30829619d2aSchristos }
30929619d2aSchristos 
31029619d2aSchristos DECLARE_INFO_COMMAND (ea_beg_of_line, _("Move to the start of this line"))
31129619d2aSchristos {
31229619d2aSchristos   input_line_point = input_line_beg;
31329619d2aSchristos }
31429619d2aSchristos 
31529619d2aSchristos DECLARE_INFO_COMMAND (ea_end_of_line, _("Move to the end of this line"))
31629619d2aSchristos {
31729619d2aSchristos   input_line_point = input_line_end;
31829619d2aSchristos }
31929619d2aSchristos 
32029619d2aSchristos #define alphabetic(c) (islower (c) || isupper (c) || isdigit (c))
32129619d2aSchristos 
32229619d2aSchristos /* Move forward a word in the input line. */
32329619d2aSchristos DECLARE_INFO_COMMAND (ea_forward_word, _("Move forward a word"))
32429619d2aSchristos {
32529619d2aSchristos   int c;
32629619d2aSchristos 
32729619d2aSchristos   if (count < 0)
32829619d2aSchristos     ea_backward_word (window, -count, key);
32929619d2aSchristos   else
33029619d2aSchristos     {
33129619d2aSchristos       while (count--)
33229619d2aSchristos         {
33329619d2aSchristos           if (input_line_point == input_line_end)
33429619d2aSchristos             return;
33529619d2aSchristos 
33629619d2aSchristos           /* If we are not in a word, move forward until we are in one.
33729619d2aSchristos              Then, move forward until we hit a non-alphabetic character. */
33829619d2aSchristos           c = input_line[input_line_point];
33929619d2aSchristos 
34029619d2aSchristos           if (!alphabetic (c))
34129619d2aSchristos             {
34229619d2aSchristos               while (++input_line_point < input_line_end)
34329619d2aSchristos                 {
34429619d2aSchristos                   c = input_line[input_line_point];
34529619d2aSchristos                   if (alphabetic (c))
34629619d2aSchristos                     break;
34729619d2aSchristos                 }
34829619d2aSchristos             }
34929619d2aSchristos 
35029619d2aSchristos           if (input_line_point == input_line_end)
35129619d2aSchristos             return;
35229619d2aSchristos 
35329619d2aSchristos           while (++input_line_point < input_line_end)
35429619d2aSchristos             {
35529619d2aSchristos               c = input_line[input_line_point];
35629619d2aSchristos               if (!alphabetic (c))
35729619d2aSchristos                 break;
35829619d2aSchristos             }
35929619d2aSchristos         }
36029619d2aSchristos     }
36129619d2aSchristos }
36229619d2aSchristos 
36329619d2aSchristos DECLARE_INFO_COMMAND (ea_backward_word, _("Move backward a word"))
36429619d2aSchristos {
36529619d2aSchristos   int c;
36629619d2aSchristos 
36729619d2aSchristos   if (count < 0)
36829619d2aSchristos     ea_forward_word (window, -count, key);
36929619d2aSchristos   else
37029619d2aSchristos     {
37129619d2aSchristos       while (count--)
37229619d2aSchristos         {
37329619d2aSchristos           if (input_line_point == input_line_beg)
37429619d2aSchristos             return;
37529619d2aSchristos 
37629619d2aSchristos           /* Like ea_forward_word (), except that we look at the
37729619d2aSchristos              characters just before point. */
37829619d2aSchristos 
37929619d2aSchristos           c = input_line[input_line_point - 1];
38029619d2aSchristos 
38129619d2aSchristos           if (!alphabetic (c))
38229619d2aSchristos             {
38329619d2aSchristos               while ((--input_line_point) != input_line_beg)
38429619d2aSchristos                 {
38529619d2aSchristos                   c = input_line[input_line_point - 1];
38629619d2aSchristos                   if (alphabetic (c))
38729619d2aSchristos                     break;
38829619d2aSchristos                 }
38929619d2aSchristos             }
39029619d2aSchristos 
39129619d2aSchristos           while (input_line_point != input_line_beg)
39229619d2aSchristos             {
39329619d2aSchristos               c = input_line[input_line_point - 1];
39429619d2aSchristos               if (!alphabetic (c))
39529619d2aSchristos                 break;
39629619d2aSchristos               else
39729619d2aSchristos                 --input_line_point;
39829619d2aSchristos             }
39929619d2aSchristos         }
40029619d2aSchristos     }
40129619d2aSchristos }
40229619d2aSchristos 
40329619d2aSchristos DECLARE_INFO_COMMAND (ea_delete, _("Delete the character under the cursor"))
40429619d2aSchristos {
40529619d2aSchristos   register int i;
40629619d2aSchristos 
40729619d2aSchristos   if (count < 0)
40829619d2aSchristos     ea_rubout (window, -count, key);
40929619d2aSchristos   else
41029619d2aSchristos     {
41129619d2aSchristos       if (input_line_point == input_line_end)
41229619d2aSchristos         return;
41329619d2aSchristos 
41429619d2aSchristos       if (info_explicit_arg || count > 1)
41529619d2aSchristos         {
41629619d2aSchristos           int orig_point;
41729619d2aSchristos 
41829619d2aSchristos           orig_point = input_line_point;
41929619d2aSchristos           ea_forward (window, count, key);
42029619d2aSchristos           ea_kill_text (orig_point, input_line_point);
42129619d2aSchristos           input_line_point = orig_point;
42229619d2aSchristos         }
42329619d2aSchristos       else
42429619d2aSchristos         {
42529619d2aSchristos           for (i = input_line_point; i < input_line_end; i++)
42629619d2aSchristos             input_line[i] = input_line[i + 1];
42729619d2aSchristos 
42829619d2aSchristos           input_line_end--;
42929619d2aSchristos         }
43029619d2aSchristos     }
43129619d2aSchristos }
43229619d2aSchristos 
43329619d2aSchristos DECLARE_INFO_COMMAND (ea_rubout, _("Delete the character behind the cursor"))
43429619d2aSchristos {
43529619d2aSchristos   if (count < 0)
43629619d2aSchristos     ea_delete (window, -count, key);
43729619d2aSchristos   else
43829619d2aSchristos     {
43929619d2aSchristos       int start;
44029619d2aSchristos 
44129619d2aSchristos       if (input_line_point == input_line_beg)
44229619d2aSchristos         return;
44329619d2aSchristos 
44429619d2aSchristos       start = input_line_point;
44529619d2aSchristos       ea_backward (window, count, key);
44629619d2aSchristos 
44729619d2aSchristos       if (info_explicit_arg || count > 1)
44829619d2aSchristos         ea_kill_text (start, input_line_point);
44929619d2aSchristos       else
45029619d2aSchristos         ea_delete (window, count, key);
45129619d2aSchristos     }
45229619d2aSchristos }
45329619d2aSchristos 
45429619d2aSchristos DECLARE_INFO_COMMAND (ea_abort, _("Cancel or quit operation"))
45529619d2aSchristos {
45629619d2aSchristos   /* If any text, just discard it, and restore the calling window's node.
45729619d2aSchristos      If no text, quit. */
45829619d2aSchristos   if (input_line_end != input_line_beg)
45929619d2aSchristos     {
46029619d2aSchristos       terminal_ring_bell ();
46129619d2aSchristos       input_line_end = input_line_point = input_line_beg;
46229619d2aSchristos       if (calling_window->node != calling_window_node)
46329619d2aSchristos         restore_calling_window ();
46429619d2aSchristos     }
46529619d2aSchristos   else
46629619d2aSchristos     info_aborted_echo_area = 1;
46729619d2aSchristos }
46829619d2aSchristos 
46929619d2aSchristos DECLARE_INFO_COMMAND (ea_newline, _("Accept (or force completion of) this line"))
47029619d2aSchristos {
47129619d2aSchristos   /* Stub does nothing.  Simply here to see if it has been executed. */
47229619d2aSchristos }
47329619d2aSchristos 
47429619d2aSchristos DECLARE_INFO_COMMAND (ea_quoted_insert, _("Insert next character verbatim"))
47529619d2aSchristos {
47629619d2aSchristos   unsigned char character;
47729619d2aSchristos 
47829619d2aSchristos   character = info_get_another_input_char ();
47929619d2aSchristos   ea_insert (window, count, character);
48029619d2aSchristos }
48129619d2aSchristos 
48229619d2aSchristos DECLARE_INFO_COMMAND (ea_insert, _("Insert this character"))
48329619d2aSchristos {
48429619d2aSchristos   register int i;
48529619d2aSchristos 
48629619d2aSchristos   if ((input_line_end + 1) == EA_MAX_INPUT)
48729619d2aSchristos     {
48829619d2aSchristos       terminal_ring_bell ();
48929619d2aSchristos       return;
49029619d2aSchristos     }
49129619d2aSchristos 
49229619d2aSchristos   for (i = input_line_end + 1; i != input_line_point; i--)
49329619d2aSchristos     input_line[i] = input_line[i - 1];
49429619d2aSchristos 
49529619d2aSchristos   input_line[input_line_point] = key;
49629619d2aSchristos   input_line_point++;
49729619d2aSchristos   input_line_end++;
49829619d2aSchristos }
49929619d2aSchristos 
50029619d2aSchristos DECLARE_INFO_COMMAND (ea_tab_insert, _("Insert a TAB character"))
50129619d2aSchristos {
50229619d2aSchristos   ea_insert (window, count, '\t');
50329619d2aSchristos }
50429619d2aSchristos 
50529619d2aSchristos /* Transpose the characters at point.  If point is at the end of the line,
50629619d2aSchristos    then transpose the characters before point. */
50729619d2aSchristos DECLARE_INFO_COMMAND (ea_transpose_chars, _("Transpose characters at point"))
50829619d2aSchristos {
50929619d2aSchristos   /* Handle conditions that would make it impossible to transpose
51029619d2aSchristos      characters. */
51129619d2aSchristos   if (!count || !input_line_point || (input_line_end - input_line_beg) < 2)
51229619d2aSchristos     return;
51329619d2aSchristos 
51429619d2aSchristos   while (count)
51529619d2aSchristos     {
51629619d2aSchristos       int t;
51729619d2aSchristos       if (input_line_point == input_line_end)
51829619d2aSchristos         {
51929619d2aSchristos           t = input_line[input_line_point - 1];
52029619d2aSchristos 
52129619d2aSchristos           input_line[input_line_point - 1] = input_line[input_line_point - 2];
52229619d2aSchristos           input_line[input_line_point - 2] = t;
52329619d2aSchristos         }
52429619d2aSchristos       else
52529619d2aSchristos         {
52629619d2aSchristos           t = input_line[input_line_point];
52729619d2aSchristos 
52829619d2aSchristos           input_line[input_line_point] = input_line[input_line_point - 1];
52929619d2aSchristos           input_line[input_line_point - 1] = t;
53029619d2aSchristos 
53129619d2aSchristos           if (count < 0 && input_line_point != input_line_beg)
53229619d2aSchristos             input_line_point--;
53329619d2aSchristos           else
53429619d2aSchristos             input_line_point++;
53529619d2aSchristos         }
53629619d2aSchristos 
53729619d2aSchristos       if (count < 0)
53829619d2aSchristos         count++;
53929619d2aSchristos       else
54029619d2aSchristos         count--;
54129619d2aSchristos     }
54229619d2aSchristos }
54329619d2aSchristos 
54429619d2aSchristos /* **************************************************************** */
54529619d2aSchristos /*                                                                  */
54629619d2aSchristos /*                   Echo Area Killing and Yanking                  */
54729619d2aSchristos /*                                                                  */
54829619d2aSchristos /* **************************************************************** */
54929619d2aSchristos 
55029619d2aSchristos static char **kill_ring = (char **)NULL;
55129619d2aSchristos static int kill_ring_index = 0; /* Number of kills appearing in KILL_RING. */
55229619d2aSchristos static int kill_ring_slots = 0; /* Number of slots allocated to KILL_RING. */
55329619d2aSchristos static int kill_ring_loc = 0;   /* Location of current yank pointer. */
55429619d2aSchristos 
55529619d2aSchristos /* The largest number of kills that we remember at one time. */
55629619d2aSchristos static int max_retained_kills = 15;
55729619d2aSchristos 
55829619d2aSchristos DECLARE_INFO_COMMAND (ea_yank, _("Yank back the contents of the last kill"))
55929619d2aSchristos {
56029619d2aSchristos   register int i;
56129619d2aSchristos   register char *text;
56229619d2aSchristos 
56329619d2aSchristos   if (!kill_ring_index)
56429619d2aSchristos     {
56529619d2aSchristos       inform_in_echo_area ((char *) _("Kill ring is empty"));
56629619d2aSchristos       return;
56729619d2aSchristos     }
56829619d2aSchristos 
56929619d2aSchristos   text = kill_ring[kill_ring_loc];
57029619d2aSchristos 
57129619d2aSchristos   for (i = 0; text[i]; i++)
57229619d2aSchristos     ea_insert (window, 1, text[i]);
57329619d2aSchristos }
57429619d2aSchristos 
57529619d2aSchristos /* If the last command was yank, or yank_pop, and the text just before
57629619d2aSchristos    point is identical to the current kill item, then delete that text
57729619d2aSchristos    from the line, rotate the index down, and yank back some other text. */
57829619d2aSchristos DECLARE_INFO_COMMAND (ea_yank_pop, _("Yank back a previous kill"))
57929619d2aSchristos {
58029619d2aSchristos   register int len;
58129619d2aSchristos 
58229619d2aSchristos   if (((ea_last_executed_command != (VFunction *) ea_yank) &&
58329619d2aSchristos        (ea_last_executed_command != (VFunction *) ea_yank_pop)) ||
58429619d2aSchristos       (kill_ring_index == 0))
58529619d2aSchristos     return;
58629619d2aSchristos 
58729619d2aSchristos   len = strlen (kill_ring[kill_ring_loc]);
58829619d2aSchristos 
58929619d2aSchristos   /* Delete the last yanked item from the line. */
59029619d2aSchristos   {
59129619d2aSchristos     register int i, counter;
59229619d2aSchristos 
59329619d2aSchristos     counter = input_line_end - input_line_point;
59429619d2aSchristos 
59529619d2aSchristos     for (i = input_line_point - len; counter; i++, counter--)
59629619d2aSchristos       input_line[i] = input_line[i + len];
59729619d2aSchristos 
59829619d2aSchristos     input_line_end -= len;
59929619d2aSchristos     input_line_point -= len;
60029619d2aSchristos   }
60129619d2aSchristos 
60229619d2aSchristos   /* Get a previous kill, and yank that. */
60329619d2aSchristos   kill_ring_loc--;
60429619d2aSchristos   if (kill_ring_loc < 0)
60529619d2aSchristos     kill_ring_loc = kill_ring_index - 1;
60629619d2aSchristos 
60729619d2aSchristos   ea_yank (window, count, key);
60829619d2aSchristos }
60929619d2aSchristos 
61029619d2aSchristos /* Delete the text from point to end of line. */
61129619d2aSchristos DECLARE_INFO_COMMAND (ea_kill_line, _("Kill to the end of the line"))
61229619d2aSchristos {
61329619d2aSchristos   if (count < 0)
61429619d2aSchristos     {
61529619d2aSchristos       ea_kill_text (input_line_point, input_line_beg);
61629619d2aSchristos       input_line_point = input_line_beg;
61729619d2aSchristos     }
61829619d2aSchristos   else
61929619d2aSchristos     ea_kill_text (input_line_point, input_line_end);
62029619d2aSchristos }
62129619d2aSchristos 
62229619d2aSchristos /* Delete the text from point to beg of line. */
62329619d2aSchristos DECLARE_INFO_COMMAND (ea_backward_kill_line,
62429619d2aSchristos                       _("Kill to the beginning of the line"))
62529619d2aSchristos {
62629619d2aSchristos   if (count < 0)
62729619d2aSchristos     ea_kill_text (input_line_point, input_line_end);
62829619d2aSchristos   else
62929619d2aSchristos     {
63029619d2aSchristos       ea_kill_text (input_line_point, input_line_beg);
63129619d2aSchristos       input_line_point = input_line_beg;
63229619d2aSchristos     }
63329619d2aSchristos }
63429619d2aSchristos 
63529619d2aSchristos /* Delete from point to the end of the current word. */
63629619d2aSchristos DECLARE_INFO_COMMAND (ea_kill_word, _("Kill the word following the cursor"))
63729619d2aSchristos {
63829619d2aSchristos   int orig_point = input_line_point;
63929619d2aSchristos 
64029619d2aSchristos   if (count < 0)
64129619d2aSchristos     ea_backward_kill_word (window, -count, key);
64229619d2aSchristos   else
64329619d2aSchristos     {
64429619d2aSchristos       ea_forward_word (window, count, key);
64529619d2aSchristos 
64629619d2aSchristos       if (input_line_point != orig_point)
64729619d2aSchristos         ea_kill_text (orig_point, input_line_point);
64829619d2aSchristos 
64929619d2aSchristos       input_line_point = orig_point;
65029619d2aSchristos     }
65129619d2aSchristos }
65229619d2aSchristos 
65329619d2aSchristos /* Delete from point to the start of the current word. */
65429619d2aSchristos DECLARE_INFO_COMMAND (ea_backward_kill_word,
65529619d2aSchristos                       _("Kill the word preceding the cursor"))
65629619d2aSchristos {
65729619d2aSchristos   int orig_point = input_line_point;
65829619d2aSchristos 
65929619d2aSchristos   if (count < 0)
66029619d2aSchristos     ea_kill_word (window, -count, key);
66129619d2aSchristos   else
66229619d2aSchristos     {
66329619d2aSchristos       ea_backward_word (window, count, key);
66429619d2aSchristos 
66529619d2aSchristos       if (input_line_point != orig_point)
66629619d2aSchristos         ea_kill_text (orig_point, input_line_point);
66729619d2aSchristos     }
66829619d2aSchristos }
66929619d2aSchristos 
67029619d2aSchristos /* The way to kill something.  This appends or prepends to the last
67129619d2aSchristos    kill, if the last command was a kill command.  If FROM is less
67229619d2aSchristos    than TO, then the killed text is appended to the most recent kill,
67329619d2aSchristos    otherwise it is prepended.  If the last command was not a kill command,
67429619d2aSchristos    then a new slot is made for this kill. */
67529619d2aSchristos static void
ea_kill_text(int from,int to)67629619d2aSchristos ea_kill_text (int from, int to)
67729619d2aSchristos {
67829619d2aSchristos   register int i, counter, distance;
67929619d2aSchristos   int killing_backwards, slot;
68029619d2aSchristos   char *killed_text;
68129619d2aSchristos 
68229619d2aSchristos   killing_backwards = (from > to);
68329619d2aSchristos 
68429619d2aSchristos   /* If killing backwards, reverse the values of FROM and TO. */
68529619d2aSchristos   if (killing_backwards)
68629619d2aSchristos     {
68729619d2aSchristos       int temp = from;
68829619d2aSchristos       from = to;
68929619d2aSchristos       to = temp;
69029619d2aSchristos     }
69129619d2aSchristos 
69229619d2aSchristos   /* Remember the text that we are about to delete. */
69329619d2aSchristos   distance = to - from;
69429619d2aSchristos   killed_text = (char *)xmalloc (1 + distance);
69529619d2aSchristos   strncpy (killed_text, &input_line[from], distance);
69629619d2aSchristos   killed_text[distance] = '\0';
69729619d2aSchristos 
69829619d2aSchristos   /* Actually delete the text from the line. */
69929619d2aSchristos   counter = input_line_end - to;
70029619d2aSchristos 
70129619d2aSchristos   for (i = from; counter; i++, counter--)
70229619d2aSchristos     input_line[i] = input_line[i + distance];
70329619d2aSchristos 
70429619d2aSchristos   input_line_end -= distance;
70529619d2aSchristos 
70629619d2aSchristos   /* If the last command was a kill, append or prepend the killed text to
70729619d2aSchristos      the last command's killed text. */
70829619d2aSchristos   if (echo_area_last_command_was_kill)
70929619d2aSchristos     {
71029619d2aSchristos       char *old, *new;
71129619d2aSchristos 
71229619d2aSchristos       slot = kill_ring_loc;
71329619d2aSchristos       old = kill_ring[slot];
71429619d2aSchristos       new = (char *)xmalloc (1 + strlen (old) + strlen (killed_text));
71529619d2aSchristos 
71629619d2aSchristos       if (killing_backwards)
71729619d2aSchristos         {
71829619d2aSchristos           /* Prepend TEXT to current kill. */
71929619d2aSchristos           strcpy (new, killed_text);
72029619d2aSchristos           strcat (new, old);
72129619d2aSchristos         }
72229619d2aSchristos       else
72329619d2aSchristos         {
72429619d2aSchristos           /* Append TEXT to current kill. */
72529619d2aSchristos           strcpy (new, old);
72629619d2aSchristos           strcat (new, killed_text);
72729619d2aSchristos         }
72829619d2aSchristos 
72929619d2aSchristos       free (old);
73029619d2aSchristos       free (killed_text);
73129619d2aSchristos       kill_ring[slot] = new;
73229619d2aSchristos     }
73329619d2aSchristos   else
73429619d2aSchristos     {
73529619d2aSchristos       /* Try to store the kill in a new slot, unless that would cause there
73629619d2aSchristos          to be too many remembered kills. */
73729619d2aSchristos       slot = kill_ring_index;
73829619d2aSchristos 
73929619d2aSchristos       if (slot == max_retained_kills)
74029619d2aSchristos         slot = 0;
74129619d2aSchristos 
74229619d2aSchristos       if (slot + 1 > kill_ring_slots)
74329619d2aSchristos         kill_ring = (char **) xrealloc
74429619d2aSchristos           (kill_ring,
74529619d2aSchristos            (kill_ring_slots += max_retained_kills) * sizeof (char *));
74629619d2aSchristos 
74729619d2aSchristos       if (slot != kill_ring_index)
74829619d2aSchristos         free (kill_ring[slot]);
74929619d2aSchristos       else
75029619d2aSchristos         kill_ring_index++;
75129619d2aSchristos 
75229619d2aSchristos       kill_ring[slot] = killed_text;
75329619d2aSchristos 
75429619d2aSchristos       kill_ring_loc = slot;
75529619d2aSchristos     }
75629619d2aSchristos 
75729619d2aSchristos   /* Notice that the last command was a kill. */
75829619d2aSchristos   echo_area_last_command_was_kill++;
75929619d2aSchristos }
76029619d2aSchristos 
76129619d2aSchristos /* **************************************************************** */
76229619d2aSchristos /*                                                                  */
76329619d2aSchristos /*                      Echo Area Completion                        */
76429619d2aSchristos /*                                                                  */
76529619d2aSchristos /* **************************************************************** */
76629619d2aSchristos 
76729619d2aSchristos /* Pointer to an array of REFERENCE to complete over. */
76829619d2aSchristos static REFERENCE **echo_area_completion_items = (REFERENCE **)NULL;
76929619d2aSchristos 
77029619d2aSchristos /* Sorted array of REFERENCE * which is the possible completions found in
77129619d2aSchristos    the variable echo_area_completion_items.  If there is only one element,
77229619d2aSchristos    it is the only possible completion. */
77329619d2aSchristos static REFERENCE **completions_found = (REFERENCE **)NULL;
77429619d2aSchristos static int completions_found_index = 0;
77529619d2aSchristos static int completions_found_slots = 0;
77629619d2aSchristos 
77729619d2aSchristos /* The lowest common denominator found while completing. */
77829619d2aSchristos static REFERENCE *LCD_completion;
77929619d2aSchristos 
78029619d2aSchristos /* Internal functions used by the user calls. */
78129619d2aSchristos static void build_completions (void), completions_must_be_rebuilt (void);
78229619d2aSchristos 
78329619d2aSchristos /* Variable which holds the output of completions. */
78429619d2aSchristos static NODE *possible_completions_output_node = (NODE *)NULL;
78529619d2aSchristos 
78629619d2aSchristos static char *compwin_name = "*Completions*";
78729619d2aSchristos 
78829619d2aSchristos /* Return non-zero if WINDOW is a window used for completions output. */
78929619d2aSchristos static int
completions_window_p(WINDOW * window)79029619d2aSchristos completions_window_p (WINDOW *window)
79129619d2aSchristos {
79229619d2aSchristos   int result = 0;
79329619d2aSchristos 
79429619d2aSchristos   if (internal_info_node_p (window->node) &&
79529619d2aSchristos       (strcmp (window->node->nodename, compwin_name) == 0))
79629619d2aSchristos     result = 1;
79729619d2aSchristos 
79829619d2aSchristos   return (result);
79929619d2aSchristos }
80029619d2aSchristos 
80129619d2aSchristos /* Workhorse for completion readers.  If FORCE is non-zero, the user cannot
80229619d2aSchristos    exit unless the line read completes, or is empty. */
80329619d2aSchristos char *
info_read_completing_internal(WINDOW * window,char * prompt,REFERENCE ** completions,int force)80429619d2aSchristos info_read_completing_internal (WINDOW *window, char *prompt,
80529619d2aSchristos     REFERENCE **completions, int force)
80629619d2aSchristos {
80729619d2aSchristos   char *line;
80829619d2aSchristos 
80929619d2aSchristos   /* If the echo area is already active, remember the current state. */
81029619d2aSchristos   if (echo_area_is_active)
81129619d2aSchristos     push_echo_area ();
81229619d2aSchristos 
81329619d2aSchristos   echo_area_must_complete_p = force;
81429619d2aSchristos 
81529619d2aSchristos   /* Initialize our local variables. */
81629619d2aSchristos   initialize_input_line (prompt);
81729619d2aSchristos 
81829619d2aSchristos   /* Initialize the echo area for the first (but maybe not the last) time. */
81929619d2aSchristos   echo_area_initialize_node ();
82029619d2aSchristos 
82129619d2aSchristos   /* Save away the original node of this window, and the window itself,
82229619d2aSchristos      so echo area commands can temporarily use this window. */
82329619d2aSchristos   remember_calling_window (window);
82429619d2aSchristos 
82529619d2aSchristos   /* Save away the list of items to complete over. */
82629619d2aSchristos   echo_area_completion_items = completions;
82729619d2aSchristos   completions_must_be_rebuilt ();
82829619d2aSchristos 
82929619d2aSchristos   active_window = the_echo_area;
83029619d2aSchristos   echo_area_is_active++;
83129619d2aSchristos 
83229619d2aSchristos   /* Read characters in the echo area. */
83329619d2aSchristos   while (1)
83429619d2aSchristos     {
83529619d2aSchristos       info_read_and_dispatch ();
83629619d2aSchristos 
83729619d2aSchristos       line = echo_area_after_read ();
83829619d2aSchristos 
83929619d2aSchristos       /* Force the completion to take place if the user hasn't accepted
84029619d2aSchristos          a default or aborted, and if FORCE is active. */
84129619d2aSchristos       if (force && line && *line && completions)
84229619d2aSchristos         {
84329619d2aSchristos           register int i;
84429619d2aSchristos 
84529619d2aSchristos           build_completions ();
84629619d2aSchristos 
84729619d2aSchristos           /* If there is only one completion, then make the line be that
84829619d2aSchristos              completion. */
84929619d2aSchristos           if (completions_found_index == 1)
85029619d2aSchristos             {
85129619d2aSchristos               free (line);
85229619d2aSchristos               line = xstrdup (completions_found[0]->label);
85329619d2aSchristos               break;
85429619d2aSchristos             }
85529619d2aSchristos 
85629619d2aSchristos           /* If one of the completions matches exactly, then that is okay, so
85729619d2aSchristos              return the current line. */
85829619d2aSchristos           for (i = 0; i < completions_found_index; i++)
85929619d2aSchristos             if (strcasecmp (completions_found[i]->label, line) == 0)
86029619d2aSchristos               {
86129619d2aSchristos                 free (line);
86229619d2aSchristos                 line = xstrdup (completions_found[i]->label);
86329619d2aSchristos                 break;
86429619d2aSchristos               }
86529619d2aSchristos 
86629619d2aSchristos           /* If no match, go back and try again. */
86729619d2aSchristos           if (i == completions_found_index)
86829619d2aSchristos             {
86929619d2aSchristos               if (!completions_found_index)
87029619d2aSchristos                 inform_in_echo_area ((char *) _("No completions"));
87129619d2aSchristos               else
87229619d2aSchristos                 inform_in_echo_area ((char *) _("Not complete"));
87329619d2aSchristos               continue;
87429619d2aSchristos             }
87529619d2aSchristos         }
87629619d2aSchristos       break;
87729619d2aSchristos     }
87829619d2aSchristos   echo_area_is_active--;
87929619d2aSchristos 
88029619d2aSchristos   /* Restore the original active window and show point in it. */
88129619d2aSchristos   active_window = calling_window;
88229619d2aSchristos   restore_calling_window ();
88329619d2aSchristos   display_cursor_at_point (active_window);
88429619d2aSchristos   fflush (stdout);
88529619d2aSchristos 
88629619d2aSchristos   echo_area_completion_items = (REFERENCE **)NULL;
88729619d2aSchristos   completions_must_be_rebuilt ();
88829619d2aSchristos 
88929619d2aSchristos   /* If there is a previous loop waiting for us, restore it now. */
89029619d2aSchristos   if (echo_area_is_active)
89129619d2aSchristos     pop_echo_area ();
89229619d2aSchristos 
89329619d2aSchristos   return (line);
89429619d2aSchristos }
89529619d2aSchristos 
89629619d2aSchristos /* Read a line in the echo area with completion over COMPLETIONS. */
89729619d2aSchristos char *
info_read_completing_in_echo_area(WINDOW * window,char * prompt,REFERENCE ** completions)89829619d2aSchristos info_read_completing_in_echo_area (WINDOW *window,
89929619d2aSchristos     char *prompt, REFERENCE **completions)
90029619d2aSchristos {
90129619d2aSchristos   return (info_read_completing_internal (window, prompt, completions, 1));
90229619d2aSchristos }
90329619d2aSchristos 
90429619d2aSchristos /* Read a line in the echo area allowing completion over COMPLETIONS, but
90529619d2aSchristos    not requiring it. */
90629619d2aSchristos char *
info_read_maybe_completing(WINDOW * window,char * prompt,REFERENCE ** completions)90729619d2aSchristos info_read_maybe_completing (WINDOW *window,
90829619d2aSchristos     char *prompt, REFERENCE **completions)
90929619d2aSchristos {
91029619d2aSchristos   return (info_read_completing_internal (window, prompt, completions, 0));
91129619d2aSchristos }
91229619d2aSchristos 
91329619d2aSchristos DECLARE_INFO_COMMAND (ea_possible_completions, _("List possible completions"))
91429619d2aSchristos {
91529619d2aSchristos   if (!echo_area_completion_items)
91629619d2aSchristos     {
91729619d2aSchristos       ea_insert (window, count, key);
91829619d2aSchristos       return;
91929619d2aSchristos     }
92029619d2aSchristos 
92129619d2aSchristos   build_completions ();
92229619d2aSchristos 
92329619d2aSchristos   if (!completions_found_index)
92429619d2aSchristos     {
92529619d2aSchristos       terminal_ring_bell ();
92629619d2aSchristos       inform_in_echo_area ((char *) _("No completions"));
92729619d2aSchristos     }
92829619d2aSchristos   else if ((completions_found_index == 1) && (key != '?'))
92929619d2aSchristos     {
93029619d2aSchristos       inform_in_echo_area ((char *) _("Sole completion"));
93129619d2aSchristos     }
93229619d2aSchristos   else
93329619d2aSchristos     {
93429619d2aSchristos       register int i, l;
93529619d2aSchristos       int limit, iterations, max_label = 0;
93629619d2aSchristos 
93729619d2aSchristos       initialize_message_buffer ();
93829619d2aSchristos       printf_to_message_buffer (completions_found_index == 1
93929619d2aSchristos                                 ? (char *) _("One completion:\n")
94029619d2aSchristos                                 : (char *) _("%d completions:\n"),
941*d3737e9cSchristos 				(void*)((intptr_t)completions_found_index),
94229619d2aSchristos 				NULL, NULL);
94329619d2aSchristos 
94429619d2aSchristos       /* Find the maximum length of a label. */
94529619d2aSchristos       for (i = 0; i < completions_found_index; i++)
94629619d2aSchristos         {
94729619d2aSchristos           int len = strlen (completions_found[i]->label);
94829619d2aSchristos           if (len > max_label)
94929619d2aSchristos             max_label = len;
95029619d2aSchristos         }
95129619d2aSchristos 
95229619d2aSchristos       max_label += 4;
95329619d2aSchristos 
95429619d2aSchristos       /* Find out how many columns we should print in. */
95529619d2aSchristos       limit = calling_window->width / max_label;
95629619d2aSchristos       if (limit != 1 && (limit * max_label == calling_window->width))
95729619d2aSchristos         limit--;
95829619d2aSchristos 
95929619d2aSchristos       /* Avoid a possible floating exception.  If max_label > width then
96029619d2aSchristos          the limit will be 0 and a divide-by-zero fault will result. */
96129619d2aSchristos       if (limit == 0)
96229619d2aSchristos         limit = 1;
96329619d2aSchristos 
96429619d2aSchristos       /* How many iterations of the printing loop? */
96529619d2aSchristos       iterations = (completions_found_index + (limit - 1)) / limit;
96629619d2aSchristos 
96729619d2aSchristos       /* Watch out for special case.  If the number of completions is less
96829619d2aSchristos          than LIMIT, then just do the inner printing loop. */
96929619d2aSchristos       if (completions_found_index < limit)
97029619d2aSchristos         iterations = 1;
97129619d2aSchristos 
97229619d2aSchristos       /* Print the sorted items, up-and-down alphabetically. */
97329619d2aSchristos       for (i = 0; i < iterations; i++)
97429619d2aSchristos         {
97529619d2aSchristos           register int j;
97629619d2aSchristos 
97729619d2aSchristos           for (j = 0, l = i; j < limit; j++)
97829619d2aSchristos             {
97929619d2aSchristos               if (l >= completions_found_index)
98029619d2aSchristos                 break;
98129619d2aSchristos               else
98229619d2aSchristos                 {
98329619d2aSchristos                   char *label;
98429619d2aSchristos                   int printed_length, k;
98529619d2aSchristos 
98629619d2aSchristos                   label = completions_found[l]->label;
98729619d2aSchristos                   printed_length = strlen (label);
98829619d2aSchristos                   printf_to_message_buffer ("%s", label, NULL, NULL);
98929619d2aSchristos 
99029619d2aSchristos                   if (j + 1 < limit)
99129619d2aSchristos                     {
99229619d2aSchristos                       for (k = 0; k < max_label - printed_length; k++)
99329619d2aSchristos                         printf_to_message_buffer (" ", NULL, NULL, NULL);
99429619d2aSchristos                     }
99529619d2aSchristos                 }
99629619d2aSchristos               l += iterations;
99729619d2aSchristos             }
99829619d2aSchristos           printf_to_message_buffer ("\n", NULL, NULL, NULL);
99929619d2aSchristos         }
100029619d2aSchristos 
100129619d2aSchristos       /* Make a new node to hold onto possible completions.  Don't destroy
100229619d2aSchristos          dangling pointers. */
100329619d2aSchristos       {
100429619d2aSchristos         NODE *temp;
100529619d2aSchristos 
100629619d2aSchristos         temp = message_buffer_to_node ();
100729619d2aSchristos         add_gcable_pointer (temp->contents);
100829619d2aSchristos         name_internal_node (temp, compwin_name);
100929619d2aSchristos         possible_completions_output_node = temp;
101029619d2aSchristos       }
101129619d2aSchristos 
101229619d2aSchristos       /* Find a suitable window for displaying the completions output.
101329619d2aSchristos          First choice is an existing window showing completions output.
101429619d2aSchristos          If there is only one window, and it is large, make another
101529619d2aSchristos          (smaller) window, and use that one.  Otherwise, use the caller's
101629619d2aSchristos          window. */
101729619d2aSchristos       {
101829619d2aSchristos         WINDOW *compwin;
101929619d2aSchristos 
102029619d2aSchristos         compwin = get_internal_info_window (compwin_name);
102129619d2aSchristos 
102229619d2aSchristos         if (!compwin)
102329619d2aSchristos           {
102429619d2aSchristos             /* If we can split the window to display most of the completion
102529619d2aSchristos                items, then do so. */
102629619d2aSchristos             if (calling_window->height > (iterations * 2)
102729619d2aSchristos 		&& calling_window->height / 2 >= WINDOW_MIN_SIZE)
102829619d2aSchristos               {
102929619d2aSchristos                 int start, pagetop;
103029619d2aSchristos #ifdef SPLIT_BEFORE_ACTIVE
103129619d2aSchristos                 int end;
103229619d2aSchristos #endif
103329619d2aSchristos 
103429619d2aSchristos                 active_window = calling_window;
103529619d2aSchristos 
103629619d2aSchristos                 /* Perhaps we can scroll this window on redisplay. */
103729619d2aSchristos                 start = calling_window->first_row;
103829619d2aSchristos                 pagetop = calling_window->pagetop;
103929619d2aSchristos 
104029619d2aSchristos                 compwin =
104129619d2aSchristos                   window_make_window (possible_completions_output_node);
104229619d2aSchristos                 active_window = the_echo_area;
104329619d2aSchristos                 window_change_window_height
104429619d2aSchristos                   (compwin, -(compwin->height - (iterations + 2)));
104529619d2aSchristos 
104629619d2aSchristos                 window_adjust_pagetop (calling_window);
104729619d2aSchristos                 remember_calling_window (calling_window);
104829619d2aSchristos 
104929619d2aSchristos #if defined (SPLIT_BEFORE_ACTIVE)
105029619d2aSchristos                 /* If the pagetop hasn't changed, scrolling the calling
105129619d2aSchristos                    window is a reasonable thing to do. */
105229619d2aSchristos                 if (pagetop == calling_window->pagetop)
105329619d2aSchristos                   {
105429619d2aSchristos                     end = start + calling_window->height;
105529619d2aSchristos                     display_scroll_display
105629619d2aSchristos                       (start, end, calling_window->prev->height + 1);
105729619d2aSchristos                   }
105829619d2aSchristos #else /* !SPLIT_BEFORE_ACTIVE */
105929619d2aSchristos                 /* If the pagetop has changed, set the new pagetop here. */
106029619d2aSchristos                 if (pagetop != calling_window->pagetop)
106129619d2aSchristos                   {
106229619d2aSchristos                     int newtop = calling_window->pagetop;
106329619d2aSchristos                     calling_window->pagetop = pagetop;
106429619d2aSchristos                     set_window_pagetop (calling_window, newtop);
106529619d2aSchristos                   }
106629619d2aSchristos #endif /* !SPLIT_BEFORE_ACTIVE */
106729619d2aSchristos 
106829619d2aSchristos                 echo_area_completions_window = compwin;
106929619d2aSchristos                 remember_window_and_node (compwin, compwin->node);
107029619d2aSchristos               }
107129619d2aSchristos             else
107229619d2aSchristos               compwin = calling_window;
107329619d2aSchristos           }
107429619d2aSchristos 
107529619d2aSchristos         if (compwin->node != possible_completions_output_node)
107629619d2aSchristos           {
107729619d2aSchristos             window_set_node_of_window
107829619d2aSchristos               (compwin, possible_completions_output_node);
107929619d2aSchristos             remember_window_and_node (compwin, compwin->node);
108029619d2aSchristos           }
108129619d2aSchristos 
108229619d2aSchristos         display_update_display (windows);
108329619d2aSchristos       }
108429619d2aSchristos     }
108529619d2aSchristos }
108629619d2aSchristos 
108729619d2aSchristos DECLARE_INFO_COMMAND (ea_complete, _("Insert completion"))
108829619d2aSchristos {
108929619d2aSchristos   if (!echo_area_completion_items)
109029619d2aSchristos     {
109129619d2aSchristos       ea_insert (window, count, key);
109229619d2aSchristos       return;
109329619d2aSchristos     }
109429619d2aSchristos 
109529619d2aSchristos   /* If KEY is SPC, and we are not forcing completion to take place, simply
109629619d2aSchristos      insert the key. */
109729619d2aSchristos   if (!echo_area_must_complete_p && key == SPC)
109829619d2aSchristos     {
109929619d2aSchristos       ea_insert (window, count, key);
110029619d2aSchristos       return;
110129619d2aSchristos     }
110229619d2aSchristos 
110329619d2aSchristos   if (ea_last_executed_command == (VFunction *) ea_complete)
110429619d2aSchristos     {
110529619d2aSchristos       /* If the keypress is a SPC character, and we have already tried
110629619d2aSchristos          completing once, and there are several completions, then check
110729619d2aSchristos          the batch of completions to see if any continue with a space.
110829619d2aSchristos          If there are some, insert the space character and continue. */
110929619d2aSchristos       if (key == SPC && completions_found_index > 1)
111029619d2aSchristos         {
111129619d2aSchristos           register int i, offset;
111229619d2aSchristos 
111329619d2aSchristos           offset = input_line_end - input_line_beg;
111429619d2aSchristos 
111529619d2aSchristos           for (i = 0; i < completions_found_index; i++)
111629619d2aSchristos             if (completions_found[i]->label[offset] == ' ')
111729619d2aSchristos               break;
111829619d2aSchristos 
111929619d2aSchristos           if (completions_found[i])
112029619d2aSchristos             ea_insert (window, 1, ' ');
112129619d2aSchristos           else
112229619d2aSchristos             {
112329619d2aSchristos               ea_possible_completions (window, count, key);
112429619d2aSchristos               return;
112529619d2aSchristos             }
112629619d2aSchristos         }
112729619d2aSchristos       else
112829619d2aSchristos         {
112929619d2aSchristos           ea_possible_completions (window, count, key);
113029619d2aSchristos           return;
113129619d2aSchristos         }
113229619d2aSchristos     }
113329619d2aSchristos 
113429619d2aSchristos   input_line_point = input_line_end;
113529619d2aSchristos   build_completions ();
113629619d2aSchristos 
113729619d2aSchristos   if (!completions_found_index)
113829619d2aSchristos     terminal_ring_bell ();
113929619d2aSchristos   else if (LCD_completion->label[0] == '\0')
114029619d2aSchristos     ea_possible_completions (window, count, key);
114129619d2aSchristos   else
114229619d2aSchristos     {
114329619d2aSchristos       register int i;
114429619d2aSchristos       input_line_point = input_line_end = input_line_beg;
114529619d2aSchristos       for (i = 0; LCD_completion->label[i]; i++)
114629619d2aSchristos         ea_insert (window, 1, LCD_completion->label[i]);
114729619d2aSchristos     }
114829619d2aSchristos }
114929619d2aSchristos 
115029619d2aSchristos /* Utility REFERENCE used to store possible LCD. */
115129619d2aSchristos static REFERENCE LCD_reference = {
115229619d2aSchristos     (char *)NULL, (char *)NULL, (char *)NULL, 0, 0, 0
115329619d2aSchristos };
115429619d2aSchristos 
115529619d2aSchristos static void remove_completion_duplicates (void);
115629619d2aSchristos 
115729619d2aSchristos /* Variables which remember the state of the most recent call
115829619d2aSchristos    to build_completions (). */
115929619d2aSchristos static char *last_completion_request = (char *)NULL;
116029619d2aSchristos static REFERENCE **last_completion_items = (REFERENCE **)NULL;
116129619d2aSchristos 
116229619d2aSchristos /* How to tell the completion builder to reset internal state. */
116329619d2aSchristos static void
completions_must_be_rebuilt(void)116429619d2aSchristos completions_must_be_rebuilt (void)
116529619d2aSchristos {
116629619d2aSchristos   maybe_free (last_completion_request);
116729619d2aSchristos   last_completion_request = (char *)NULL;
116829619d2aSchristos   last_completion_items = (REFERENCE **)NULL;
116929619d2aSchristos }
117029619d2aSchristos 
117129619d2aSchristos /* Build a list of possible completions from echo_area_completion_items,
117229619d2aSchristos    and the contents of input_line. */
117329619d2aSchristos static void
build_completions(void)117429619d2aSchristos build_completions (void)
117529619d2aSchristos {
117629619d2aSchristos   register int i, len;
117729619d2aSchristos   register REFERENCE *entry;
117829619d2aSchristos   char *request;
117929619d2aSchristos   int informed_of_lengthy_job = 0;
118029619d2aSchristos 
118129619d2aSchristos   /* If there are no items to complete over, exit immediately. */
118229619d2aSchristos   if (!echo_area_completion_items)
118329619d2aSchristos     {
118429619d2aSchristos       completions_found_index = 0;
118529619d2aSchristos       LCD_completion = (REFERENCE *)NULL;
118629619d2aSchristos       return;
118729619d2aSchristos     }
118829619d2aSchristos 
118929619d2aSchristos   /* Check to see if this call to build completions is the same as the last
119029619d2aSchristos      call to build completions. */
119129619d2aSchristos   len = input_line_end - input_line_beg;
119229619d2aSchristos   request = (char *)xmalloc (1 + len);
119329619d2aSchristos   strncpy (request, &input_line[input_line_beg], len);
119429619d2aSchristos   request[len] = '\0';
119529619d2aSchristos 
119629619d2aSchristos   if (last_completion_request && last_completion_items &&
119729619d2aSchristos       last_completion_items == echo_area_completion_items &&
119829619d2aSchristos       (strcmp (last_completion_request, request) == 0))
119929619d2aSchristos     {
120029619d2aSchristos       free (request);
120129619d2aSchristos       return;
120229619d2aSchristos     }
120329619d2aSchristos 
120429619d2aSchristos   maybe_free (last_completion_request);
120529619d2aSchristos   last_completion_request = request;
120629619d2aSchristos   last_completion_items = echo_area_completion_items;
120729619d2aSchristos 
120829619d2aSchristos   /* Always start at the beginning of the list. */
120929619d2aSchristos   completions_found_index = 0;
121029619d2aSchristos   LCD_completion = (REFERENCE *)NULL;
121129619d2aSchristos 
121229619d2aSchristos   for (i = 0; (entry = echo_area_completion_items[i]); i++)
121329619d2aSchristos     {
121429619d2aSchristos       if (strncasecmp (request, entry->label, len) == 0)
121529619d2aSchristos         add_pointer_to_array (entry, completions_found_index,
121629619d2aSchristos                               completions_found, completions_found_slots,
121729619d2aSchristos                               20, REFERENCE *);
121829619d2aSchristos 
121929619d2aSchristos       if (!informed_of_lengthy_job && completions_found_index > 100)
122029619d2aSchristos         {
122129619d2aSchristos           informed_of_lengthy_job = 1;
122229619d2aSchristos           window_message_in_echo_area ((char *) _("Building completions..."),
122329619d2aSchristos               NULL, NULL);
122429619d2aSchristos         }
122529619d2aSchristos     }
122629619d2aSchristos 
122729619d2aSchristos   if (!completions_found_index)
122829619d2aSchristos     return;
122929619d2aSchristos 
123029619d2aSchristos   /* Sort and prune duplicate entries from the completions array. */
123129619d2aSchristos   remove_completion_duplicates ();
123229619d2aSchristos 
123329619d2aSchristos   /* If there is only one completion, just return that. */
123429619d2aSchristos   if (completions_found_index == 1)
123529619d2aSchristos     {
123629619d2aSchristos       LCD_completion = completions_found[0];
123729619d2aSchristos       return;
123829619d2aSchristos     }
123929619d2aSchristos 
124029619d2aSchristos   /* Find the least common denominator. */
124129619d2aSchristos   {
124229619d2aSchristos     long shortest = 100000;
124329619d2aSchristos 
124429619d2aSchristos     for (i = 1; i < completions_found_index; i++)
124529619d2aSchristos       {
124629619d2aSchristos         register int j;
124729619d2aSchristos         int c1, c2;
124829619d2aSchristos 
124929619d2aSchristos         for (j = 0;
125029619d2aSchristos              (c1 = info_tolower (completions_found[i - 1]->label[j])) &&
125129619d2aSchristos              (c2 = info_tolower (completions_found[i]->label[j]));
125229619d2aSchristos              j++)
125329619d2aSchristos           if (c1 != c2)
125429619d2aSchristos             break;
125529619d2aSchristos 
125629619d2aSchristos         if (shortest > j)
125729619d2aSchristos           shortest = j;
125829619d2aSchristos       }
125929619d2aSchristos 
126029619d2aSchristos     maybe_free (LCD_reference.label);
126129619d2aSchristos     LCD_reference.label = (char *)xmalloc (1 + shortest);
126229619d2aSchristos     /* Since both the sorting done inside remove_completion_duplicates
126329619d2aSchristos        and all the comparisons above are case-insensitive, it's
126429619d2aSchristos        possible that the completion we are going to return is
126529619d2aSchristos        identical to what the user typed but for the letter-case.  This
126629619d2aSchristos        is confusing, since the user could type FOOBAR<TAB> and get her
126729619d2aSchristos        string change letter-case for no good reason.  So try to find a
126829619d2aSchristos        possible completion whose letter-case is identical, and if so,
126929619d2aSchristos        use that.  */
127029619d2aSchristos     if (completions_found_index > 1)
127129619d2aSchristos       {
127229619d2aSchristos 	int req_len = strlen (request);
127329619d2aSchristos 
127429619d2aSchristos         for (i = 0; i < completions_found_index; i++)
127529619d2aSchristos           if (strncmp (request, completions_found[i]->label, req_len) == 0)
127629619d2aSchristos             break;
127729619d2aSchristos         /* If none of the candidates match exactly, use the first one.  */
127829619d2aSchristos         if (i >= completions_found_index)
127929619d2aSchristos           i = 0;
128029619d2aSchristos       }
128129619d2aSchristos     strncpy (LCD_reference.label, completions_found[i]->label, shortest);
128229619d2aSchristos     LCD_reference.label[shortest] = '\0';
128329619d2aSchristos     LCD_completion = &LCD_reference;
128429619d2aSchristos   }
128529619d2aSchristos 
128629619d2aSchristos   if (informed_of_lengthy_job)
128729619d2aSchristos     echo_area_initialize_node ();
128829619d2aSchristos }
128929619d2aSchristos 
129029619d2aSchristos /* Function called by qsort. */
129129619d2aSchristos static int
compare_references(const void * entry1,const void * entry2)129229619d2aSchristos compare_references (const void *entry1, const void *entry2)
129329619d2aSchristos {
129429619d2aSchristos   REFERENCE **e1 = (REFERENCE **) entry1;
129529619d2aSchristos   REFERENCE **e2 = (REFERENCE **) entry2;
129629619d2aSchristos 
129729619d2aSchristos   return (strcasecmp ((*e1)->label, (*e2)->label));
129829619d2aSchristos }
129929619d2aSchristos 
130029619d2aSchristos /* Prune duplicate entries from COMPLETIONS_FOUND. */
130129619d2aSchristos static void
remove_completion_duplicates(void)130229619d2aSchristos remove_completion_duplicates (void)
130329619d2aSchristos {
130429619d2aSchristos   register int i, j;
130529619d2aSchristos   REFERENCE **temp;
130629619d2aSchristos   int newlen;
130729619d2aSchristos 
130829619d2aSchristos   if (!completions_found_index)
130929619d2aSchristos     return;
131029619d2aSchristos 
131129619d2aSchristos   /* Sort the items. */
131229619d2aSchristos   qsort (completions_found, completions_found_index, sizeof (REFERENCE *),
131329619d2aSchristos          compare_references);
131429619d2aSchristos 
131529619d2aSchristos   for (i = 0, newlen = 1; i < completions_found_index - 1; i++)
131629619d2aSchristos     {
131729619d2aSchristos       if (strcmp (completions_found[i]->label,
131829619d2aSchristos                   completions_found[i + 1]->label) == 0)
131929619d2aSchristos         completions_found[i] = (REFERENCE *)NULL;
132029619d2aSchristos       else
132129619d2aSchristos         newlen++;
132229619d2aSchristos     }
132329619d2aSchristos 
132429619d2aSchristos   /* We have marked all the dead slots.  It is faster to copy the live slots
132529619d2aSchristos      twice than to prune the dead slots one by one. */
132629619d2aSchristos   temp = (REFERENCE **)xmalloc ((1 + newlen) * sizeof (REFERENCE *));
132729619d2aSchristos   for (i = 0, j = 0; i < completions_found_index; i++)
132829619d2aSchristos     if (completions_found[i])
132929619d2aSchristos       temp[j++] = completions_found[i];
133029619d2aSchristos 
133129619d2aSchristos   for (i = 0; i < newlen; i++)
133229619d2aSchristos     completions_found[i] = temp[i];
133329619d2aSchristos 
133429619d2aSchristos   completions_found[i] = (REFERENCE *)NULL;
133529619d2aSchristos   completions_found_index = newlen;
133629619d2aSchristos   free (temp);
133729619d2aSchristos }
133829619d2aSchristos 
133929619d2aSchristos /* Scroll the "other" window.  If there is a window showing completions, scroll
134029619d2aSchristos    that one, otherwise scroll the window which was active on entering the read
134129619d2aSchristos    function. */
134229619d2aSchristos DECLARE_INFO_COMMAND (ea_scroll_completions_window, _("Scroll the completions window"))
134329619d2aSchristos {
134429619d2aSchristos   WINDOW *compwin;
134529619d2aSchristos   int old_pagetop;
134629619d2aSchristos 
134729619d2aSchristos   compwin = get_internal_info_window (compwin_name);
134829619d2aSchristos 
134929619d2aSchristos   if (!compwin)
135029619d2aSchristos     compwin = calling_window;
135129619d2aSchristos 
135229619d2aSchristos   old_pagetop = compwin->pagetop;
135329619d2aSchristos 
135429619d2aSchristos   /* Let info_scroll_forward () do the work, and print any messages that
135529619d2aSchristos      need to be displayed. */
135629619d2aSchristos   info_scroll_forward (compwin, count, key);
135729619d2aSchristos }
135829619d2aSchristos 
135929619d2aSchristos /* Function which gets called when an Info window is deleted while the
136029619d2aSchristos    echo area is active.  WINDOW is the window which has just been deleted. */
136129619d2aSchristos void
echo_area_inform_of_deleted_window(WINDOW * window)136229619d2aSchristos echo_area_inform_of_deleted_window (WINDOW *window)
136329619d2aSchristos {
136429619d2aSchristos   /* If this is the calling_window, forget what we remembered about it. */
136529619d2aSchristos   if (window == calling_window)
136629619d2aSchristos     {
136729619d2aSchristos       if (active_window != the_echo_area)
136829619d2aSchristos         remember_calling_window (active_window);
136929619d2aSchristos       else
137029619d2aSchristos         remember_calling_window (windows);
137129619d2aSchristos     }
137229619d2aSchristos 
137329619d2aSchristos   /* If this window was the echo_area_completions_window, then notice that
137429619d2aSchristos      the window has been deleted. */
137529619d2aSchristos   if (window == echo_area_completions_window)
137629619d2aSchristos     echo_area_completions_window = (WINDOW *)NULL;
137729619d2aSchristos }
137829619d2aSchristos 
137929619d2aSchristos /* **************************************************************** */
138029619d2aSchristos /*                                                                  */
138129619d2aSchristos /*                 Pushing and Popping the Echo Area                */
138229619d2aSchristos /*                                                                  */
138329619d2aSchristos /* **************************************************************** */
138429619d2aSchristos 
138529619d2aSchristos /* Push and Pop the echo area. */
138629619d2aSchristos typedef struct {
138729619d2aSchristos   char *line;
138829619d2aSchristos   char *prompt;
138929619d2aSchristos   REFERENCE **comp_items;
139029619d2aSchristos   int point, beg, end;
139129619d2aSchristos   int must_complete;
139229619d2aSchristos   NODE node;
139329619d2aSchristos   WINDOW *compwin;
139429619d2aSchristos } PUSHED_EA;
139529619d2aSchristos 
139629619d2aSchristos static PUSHED_EA **pushed_echo_areas = (PUSHED_EA **)NULL;
139729619d2aSchristos static int pushed_echo_areas_index = 0;
139829619d2aSchristos static int pushed_echo_areas_slots = 0;
139929619d2aSchristos 
140029619d2aSchristos /* Pushing the echo_area has a side effect of zeroing the completion_items. */
140129619d2aSchristos static void
push_echo_area(void)140229619d2aSchristos push_echo_area (void)
140329619d2aSchristos {
140429619d2aSchristos   PUSHED_EA *pushed;
140529619d2aSchristos 
140629619d2aSchristos   pushed = (PUSHED_EA *)xmalloc (sizeof (PUSHED_EA));
140729619d2aSchristos   pushed->line = xstrdup (input_line);
140829619d2aSchristos   pushed->prompt = input_line_prompt;
140929619d2aSchristos   pushed->point = input_line_point;
141029619d2aSchristos   pushed->beg = input_line_beg;
141129619d2aSchristos   pushed->end = input_line_end;
141229619d2aSchristos   pushed->node = input_line_node;
141329619d2aSchristos   pushed->comp_items = echo_area_completion_items;
141429619d2aSchristos   pushed->must_complete = echo_area_must_complete_p;
141529619d2aSchristos   pushed->compwin = echo_area_completions_window;
141629619d2aSchristos 
141729619d2aSchristos   add_pointer_to_array (pushed, pushed_echo_areas_index, pushed_echo_areas,
141829619d2aSchristos                         pushed_echo_areas_slots, 4, PUSHED_EA *);
141929619d2aSchristos 
142029619d2aSchristos   echo_area_completion_items = (REFERENCE **)NULL;
142129619d2aSchristos }
142229619d2aSchristos 
142329619d2aSchristos static void
pop_echo_area(void)142429619d2aSchristos pop_echo_area (void)
142529619d2aSchristos {
142629619d2aSchristos   PUSHED_EA *popped;
142729619d2aSchristos 
142829619d2aSchristos   popped = pushed_echo_areas[--pushed_echo_areas_index];
142929619d2aSchristos 
143029619d2aSchristos   strcpy (input_line, popped->line);
143129619d2aSchristos   free (popped->line);
143229619d2aSchristos   input_line_prompt = popped->prompt;
143329619d2aSchristos   input_line_point = popped->point;
143429619d2aSchristos   input_line_beg = popped->beg;
143529619d2aSchristos   input_line_end = popped->end;
143629619d2aSchristos   input_line_node = popped->node;
143729619d2aSchristos   echo_area_completion_items = popped->comp_items;
143829619d2aSchristos   echo_area_must_complete_p = popped->must_complete;
143929619d2aSchristos   echo_area_completions_window = popped->compwin;
144029619d2aSchristos   completions_must_be_rebuilt ();
144129619d2aSchristos 
144229619d2aSchristos   /* If the completion window no longer exists, forget about it. */
144329619d2aSchristos   if (echo_area_completions_window)
144429619d2aSchristos     {
144529619d2aSchristos       register WINDOW *win;
144629619d2aSchristos 
144729619d2aSchristos       for (win = windows; win; win = win->next)
144829619d2aSchristos         if (echo_area_completions_window == win)
144929619d2aSchristos           break;
145029619d2aSchristos 
145129619d2aSchristos       /* If the window wasn't found, then it has already been deleted. */
145229619d2aSchristos       if (!win)
145329619d2aSchristos         echo_area_completions_window = (WINDOW *)NULL;
145429619d2aSchristos     }
145529619d2aSchristos 
145629619d2aSchristos   free (popped);
145729619d2aSchristos }
145829619d2aSchristos 
145929619d2aSchristos /* Returns non-zero if any of the prior stacked calls to read in the echo
146029619d2aSchristos    area produced a completions window. */
146129619d2aSchristos static int
echo_area_stack_contains_completions_p(void)146229619d2aSchristos echo_area_stack_contains_completions_p (void)
146329619d2aSchristos {
146429619d2aSchristos   register int i;
146529619d2aSchristos 
146629619d2aSchristos   for (i = 0; i < pushed_echo_areas_index; i++)
146729619d2aSchristos     if (pushed_echo_areas[i]->compwin)
146829619d2aSchristos       return (1);
146929619d2aSchristos 
147029619d2aSchristos   return (0);
147129619d2aSchristos }
147229619d2aSchristos 
147329619d2aSchristos /* **************************************************************** */
147429619d2aSchristos /*                                                                  */
147529619d2aSchristos /*             Error Messages While Reading in Echo Area            */
147629619d2aSchristos /*                                                                  */
147729619d2aSchristos /* **************************************************************** */
147829619d2aSchristos 
147929619d2aSchristos #if defined (HAVE_SYS_TIME_H)
148029619d2aSchristos #  include <sys/time.h>
148129619d2aSchristos #  define HAVE_STRUCT_TIMEVAL
148229619d2aSchristos #endif /* HAVE_SYS_TIME_H */
148329619d2aSchristos 
148429619d2aSchristos static void
pause_or_input(void)148529619d2aSchristos pause_or_input (void)
148629619d2aSchristos {
148729619d2aSchristos #ifdef FD_SET
148829619d2aSchristos   struct timeval timer;
148929619d2aSchristos   fd_set readfds;
149029619d2aSchristos   int ready;
149129619d2aSchristos 
149229619d2aSchristos   FD_ZERO (&readfds);
149329619d2aSchristos   FD_SET (fileno (stdin), &readfds);
149429619d2aSchristos   timer.tv_sec = 2;
149529619d2aSchristos   timer.tv_usec = 0;
149629619d2aSchristos   ready = select (fileno (stdin) + 1, &readfds, (fd_set *) NULL,
149729619d2aSchristos                   (fd_set *) NULL, &timer);
149829619d2aSchristos #endif /* FD_SET */
149929619d2aSchristos }
150029619d2aSchristos 
150129619d2aSchristos /* Print MESSAGE right after the end of the current line, and wait
150229619d2aSchristos    for input or a couple of seconds, whichever comes first.  Then flush the
150329619d2aSchristos    informational message that was printed. */
150429619d2aSchristos void
inform_in_echo_area(const char * message)150529619d2aSchristos inform_in_echo_area (const char *message)
150629619d2aSchristos {
150729619d2aSchristos   int i;
150829619d2aSchristos   char *text;
150929619d2aSchristos   int avail = EA_MAX_INPUT + 1 - input_line_end;
151029619d2aSchristos 
151129619d2aSchristos   text = xstrdup (message);
151229619d2aSchristos   for (i = 0; text[i] && text[i] != '\n' && i < avail; i++)
151329619d2aSchristos     ;
151429619d2aSchristos   text[i] = 0;
151529619d2aSchristos 
151629619d2aSchristos   echo_area_initialize_node ();
151729619d2aSchristos   sprintf (&input_line[input_line_end], "%s[%s]\n",
151829619d2aSchristos            echo_area_is_active ? " ": "", text);
151929619d2aSchristos   free (text);
152029619d2aSchristos   the_echo_area->point = input_line_point;
152129619d2aSchristos   display_update_one_window (the_echo_area);
152229619d2aSchristos   display_cursor_at_point (active_window);
152329619d2aSchristos   fflush (stdout);
152429619d2aSchristos   pause_or_input ();
152529619d2aSchristos   echo_area_initialize_node ();
152629619d2aSchristos }
1527