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