Bug Summary

File:src/gnu/usr.bin/texinfo/info/echo-area.c
Warning:line 1350, column 3
Value stored to 'old_pagetop' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name echo-area.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/texinfo/obj/info -resource-dir /usr/local/lib/clang/13.0.0 -D HAVE_CONFIG_H -D LOCALEDIR="/usr/share/locale" -D INFODIR="/usr/share/info" -D INFODIR2="/usr/share/info" -I . -I /usr/src/gnu/usr.bin/texinfo/info -I .. -I . -I /usr/src/gnu/usr.bin/texinfo/lib -I ../intl -I .. -I /usr/src/gnu/usr.bin/texinfo/info -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/gnu/usr.bin/texinfo/obj/info -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/gnu/usr.bin/texinfo/info/echo-area.c
1/* echo-area.c -- how to read a line in the echo area.
2 $Id: echo-area.c,v 1.5 2006/07/17 16:12:36 espie Exp $
3
4 Copyright (C) 1993, 1997, 1998, 1999, 2001, 2004 Free Software
5 Foundation, Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21 Written by Brian Fox (bfox@ai.mit.edu). */
22
23#include "info.h"
24
25#if defined (FD_SET)
26# if defined (hpux)
27# define fd_set_cast(x)(fd_set *)(x) (int *)(x)
28# else
29# define fd_set_cast(x)(fd_set *)(x) (fd_set *)(x)
30# endif /* !hpux */
31#endif /* FD_SET */
32
33/* Non-zero means that C-g was used to quit reading input. */
34int info_aborted_echo_area = 0;
35
36/* Non-zero means that the echo area is being used to read input. */
37int echo_area_is_active = 0;
38
39/* The address of the last command executed in the echo area. */
40VFunction *ea_last_executed_command = (VFunction *)NULL((void *)0);
41
42/* Non-zero means that the last command executed while reading input
43 killed some text. */
44int echo_area_last_command_was_kill = 0;
45
46/* Variables which hold on to the current state of the input line. */
47static char input_line[1 + EA_MAX_INPUT256];
48static char *input_line_prompt;
49static int input_line_point;
50static int input_line_beg;
51static int input_line_end;
52static NODE input_line_node = {
53 (char *)NULL((void *)0), (char *)NULL((void *)0), (char *)NULL((void *)0), input_line,
54 EA_MAX_INPUT256, 0, N_IsInternal0x10
55};
56
57static void echo_area_initialize_node (void);
58static void push_echo_area (void), pop_echo_area (void);
59static int echo_area_stack_contains_completions_p (void);
60
61static void ea_kill_text (int from, int to);
62
63/* Non-zero means we force the user to complete. */
64static int echo_area_must_complete_p = 0;
65static int completions_window_p (WINDOW *window);
66
67/* If non-null, this is a window which was specifically created to display
68 possible completions output. We remember it so we can delete it when
69 appropriate. */
70static WINDOW *echo_area_completions_window = (WINDOW *)NULL((void *)0);
71
72/* Variables which keep track of the window which was active prior to
73 entering the echo area. */
74static WINDOW *calling_window = (WINDOW *)NULL((void *)0);
75static NODE *calling_window_node = (NODE *)NULL((void *)0);
76static long calling_window_point = 0;
77static long calling_window_pagetop = 0;
78
79/* Remember the node and pertinent variables of the calling window. */
80static void
81remember_calling_window (WINDOW *window)
82{
83 /* Only do this if the calling window is not the completions window, or,
84 if it is the completions window and there is no other window. */
85 if (!completions_window_p (window) ||
86 ((window == windows) && !(window->next)))
87 {
88 calling_window = window;
89 calling_window_node = window->node;
90 calling_window_point = window->point;
91 calling_window_pagetop = window->pagetop;
92 }
93}
94
95/* Restore the caller's window so that it shows the node that it was showing
96 on entry to info_read_xxx_echo_area (). */
97static void
98restore_calling_window (void)
99{
100 register WINDOW *win, *compwin = (WINDOW *)NULL((void *)0);
101
102 /* If the calling window is still visible, and it is the window that
103 we used for completions output, then restore the calling window. */
104 for (win = windows; win; win = win->next)
105 {
106 if (completions_window_p (win))
107 compwin = win;
108
109 if (win == calling_window && win == compwin)
110 {
111 window_set_node_of_window (calling_window, calling_window_node);
112 calling_window->point = calling_window_point;
113 calling_window->pagetop = calling_window_pagetop;
114 compwin = (WINDOW *)NULL((void *)0);
115 break;
116 }
117 }
118
119 /* Delete the completions window if it is still present, it isn't the
120 last window on the screen, and there aren't any prior echo area reads
121 pending which created a completions window. */
122 if (compwin)
123 {
124 if ((compwin != windows || windows->next) &&
125 !echo_area_stack_contains_completions_p ())
126 {
127 WINDOW *next;
128 int pagetop = 0;
129 int start = 0;
130 int end = 0;
131 int amount = 0;
132
133 next = compwin->next;
134 if (next)
135 {
136 start = next->first_row;
137 end = start + next->height;
138 amount = - (compwin->height + 1);
139 pagetop = next->pagetop;
140 }
141
142 info_delete_window_internal (compwin);
143
144 /* This is not necessary because info_delete_window_internal ()
145 calls echo_area_inform_of_deleted_window (), which does the
146 right thing. */
147#if defined (UNNECESSARY)
148 echo_area_completions_window = (WINDOW *)NULL((void *)0);
149#endif /* UNNECESSARY */
150
151 if (next)
152 {
153 display_scroll_display (start, end, amount);
154 next->pagetop = pagetop;
155 display_update_display (windows);
156 }
157 }
158 }
159}
160
161/* Set up a new input line with PROMPT. */
162static void
163initialize_input_line (char *prompt)
164{
165 input_line_prompt = prompt;
166 if (prompt)
167 strcpy (input_line, prompt);
168 else
169 input_line[0] = '\0';
170
171 input_line_beg = input_line_end = input_line_point = strlen (prompt);
172}
173
174static char *
175echo_area_after_read (void)
176{
177 char *return_value;
178
179 if (info_aborted_echo_area)
180 {
181 info_aborted_echo_area = 0;
182 return_value = (char *)NULL((void *)0);
183 }
184 else
185 {
186 if (input_line_beg == input_line_end)
187 return_value = xstrdup ("");
188 else
189 {
190 int line_len = input_line_end - input_line_beg;
191 return_value = (char *) xmalloc (1 + line_len);
192 strncpy (return_value, &input_line[input_line_beg], line_len);
193 return_value[line_len] = '\0';
194 }
195 }
196 return (return_value);
197}
198
199/* Read a line of text in the echo area. Return a malloc ()'ed string,
200 or NULL if the user aborted out of this read. WINDOW is the currently
201 active window, so that we can restore it when we need to. PROMPT, if
202 non-null, is a prompt to print before reading the line. */
203char *
204info_read_in_echo_area (WINDOW *window, char *prompt)
205{
206 char *line;
207
208 /* If the echo area is already active, remember the current state. */
209 if (echo_area_is_active)
210 push_echo_area ();
211
212 /* Initialize our local variables. */
213 initialize_input_line (prompt);
214
215 /* Initialize the echo area for the first (but maybe not the last) time. */
216 echo_area_initialize_node ();
217
218 /* Save away the original node of this window, and the window itself,
219 so echo area commands can temporarily use this window. */
220 remember_calling_window (window);
221
222 /* Let the rest of Info know that the echo area is active. */
223 echo_area_is_active++;
224 active_window = the_echo_area;
225
226 /* Read characters in the echo area. */
227 info_read_and_dispatch ();
228
229 echo_area_is_active--;
230
231 /* Restore the original active window and show point in it. */
232 active_window = calling_window;
233 restore_calling_window ();
234 display_cursor_at_point (active_window);
235 fflush (stdout(&__sF[1]));
236
237 /* Get the value of the line. */
238 line = echo_area_after_read ();
239
240 /* If there is a previous loop waiting for us, restore it now. */
241 if (echo_area_is_active)
242 pop_echo_area ();
243
244 /* Return the results to the caller. */
245 return (line);
246}
247
248/* (re) Initialize the echo area node. */
249static void
250echo_area_initialize_node (void)
251{
252 register int i;
253
254 for (i = input_line_end; (unsigned int) i < sizeof (input_line); i++)
255 input_line[i] = ' ';
256
257 input_line[i - 1] = '\n';
258 window_set_node_of_window (the_echo_area, &input_line_node);
259 input_line[input_line_end] = '\n';
260}
261
262/* Prepare to read characters in the echo area. This can initialize the
263 echo area node, but its primary purpose is to side effect the input
264 line buffer contents. */
265void
266echo_area_prep_read (void)
267{
268 if (the_echo_area->node != &input_line_node)
269 echo_area_initialize_node ();
270
271 the_echo_area->point = input_line_point;
272 input_line[input_line_end] = '\n';
273 display_update_one_window (the_echo_area);
274 display_cursor_at_point (active_window);
275}
276
277
278/* **************************************************************** */
279/* */
280/* Echo Area Movement Commands */
281/* */
282/* **************************************************************** */
283
284DECLARE_INFO_COMMAND (ea_forward, _("Move forward a character"))void ea_forward (WINDOW *window, int count, unsigned char key
)
285{
286 if (count < 0)
287 ea_backward (window, -count, key);
288 else
289 {
290 input_line_point += count;
291 if (input_line_point > input_line_end)
292 input_line_point = input_line_end;
293 }
294}
295
296DECLARE_INFO_COMMAND (ea_backward, _("Move backward a character"))void ea_backward (WINDOW *window, int count, unsigned char key
)
297{
298 if (count < 0)
299 ea_forward (window, -count, key);
300 else
301 {
302 input_line_point -= count;
303 if (input_line_point < input_line_beg)
304 input_line_point = input_line_beg;
305 }
306}
307
308DECLARE_INFO_COMMAND (ea_beg_of_line, _("Move to the start of this line"))void ea_beg_of_line (WINDOW *window, int count, unsigned char
key)
309{
310 input_line_point = input_line_beg;
311}
312
313DECLARE_INFO_COMMAND (ea_end_of_line, _("Move to the end of this line"))void ea_end_of_line (WINDOW *window, int count, unsigned char
key)
314{
315 input_line_point = input_line_end;
316}
317
318#define alphabetic(c)(islower (c) || isupper (c) || isdigit (c)) (islower (c) || isupper (c) || isdigit (c))
319
320/* Move forward a word in the input line. */
321DECLARE_INFO_COMMAND (ea_forward_word, _("Move forward a word"))void ea_forward_word (WINDOW *window, int count, unsigned char
key)
322{
323 int c;
324
325 if (count < 0)
326 ea_backward_word (window, -count, key);
327 else
328 {
329 while (count--)
330 {
331 if (input_line_point == input_line_end)
332 return;
333
334 /* If we are not in a word, move forward until we are in one.
335 Then, move forward until we hit a non-alphabetic character. */
336 c = input_line[input_line_point];
337
338 if (!alphabetic (c)(islower (c) || isupper (c) || isdigit (c)))
339 {
340 while (++input_line_point < input_line_end)
341 {
342 c = input_line[input_line_point];
343 if (alphabetic (c)(islower (c) || isupper (c) || isdigit (c)))
344 break;
345 }
346 }
347
348 if (input_line_point == input_line_end)
349 return;
350
351 while (++input_line_point < input_line_end)
352 {
353 c = input_line[input_line_point];
354 if (!alphabetic (c)(islower (c) || isupper (c) || isdigit (c)))
355 break;
356 }
357 }
358 }
359}
360
361DECLARE_INFO_COMMAND (ea_backward_word, _("Move backward a word"))void ea_backward_word (WINDOW *window, int count, unsigned char
key)
362{
363 int c;
364
365 if (count < 0)
366 ea_forward_word (window, -count, key);
367 else
368 {
369 while (count--)
370 {
371 if (input_line_point == input_line_beg)
372 return;
373
374 /* Like ea_forward_word (), except that we look at the
375 characters just before point. */
376
377 c = input_line[input_line_point - 1];
378
379 if (!alphabetic (c)(islower (c) || isupper (c) || isdigit (c)))
380 {
381 while ((--input_line_point) != input_line_beg)
382 {
383 c = input_line[input_line_point - 1];
384 if (alphabetic (c)(islower (c) || isupper (c) || isdigit (c)))
385 break;
386 }
387 }
388
389 while (input_line_point != input_line_beg)
390 {
391 c = input_line[input_line_point - 1];
392 if (!alphabetic (c)(islower (c) || isupper (c) || isdigit (c)))
393 break;
394 else
395 --input_line_point;
396 }
397 }
398 }
399}
400
401DECLARE_INFO_COMMAND (ea_delete, _("Delete the character under the cursor"))void ea_delete (WINDOW *window, int count, unsigned char key)
402{
403 register int i;
404
405 if (count < 0)
406 ea_rubout (window, -count, key);
407 else
408 {
409 if (input_line_point == input_line_end)
410 return;
411
412 if (info_explicit_arg || count > 1)
413 {
414 int orig_point;
415
416 orig_point = input_line_point;
417 ea_forward (window, count, key);
418 ea_kill_text (orig_point, input_line_point);
419 input_line_point = orig_point;
420 }
421 else
422 {
423 for (i = input_line_point; i < input_line_end; i++)
424 input_line[i] = input_line[i + 1];
425
426 input_line_end--;
427 }
428 }
429}
430
431DECLARE_INFO_COMMAND (ea_rubout, _("Delete the character behind the cursor"))void ea_rubout (WINDOW *window, int count, unsigned char key)
432{
433 if (count < 0)
434 ea_delete (window, -count, key);
435 else
436 {
437 int start;
438
439 if (input_line_point == input_line_beg)
440 return;
441
442 start = input_line_point;
443 ea_backward (window, count, key);
444
445 if (info_explicit_arg || count > 1)
446 ea_kill_text (start, input_line_point);
447 else
448 ea_delete (window, count, key);
449 }
450}
451
452DECLARE_INFO_COMMAND (ea_abort, _("Cancel or quit operation"))void ea_abort (WINDOW *window, int count, unsigned char key)
453{
454 /* If any text, just discard it, and restore the calling window's node.
455 If no text, quit. */
456 if (input_line_end != input_line_beg)
457 {
458 terminal_ring_bell ();
459 input_line_end = input_line_point = input_line_beg;
460 if (calling_window->node != calling_window_node)
461 restore_calling_window ();
462 }
463 else
464 info_aborted_echo_area = 1;
465}
466
467DECLARE_INFO_COMMAND (ea_newline, _("Accept (or force completion of) this line"))void ea_newline (WINDOW *window, int count, unsigned char key
)
468{
469 /* Stub does nothing. Simply here to see if it has been executed. */
470}
471
472DECLARE_INFO_COMMAND (ea_quoted_insert, _("Insert next character verbatim"))void ea_quoted_insert (WINDOW *window, int count, unsigned char
key)
473{
474 unsigned char character;
475
476 character = info_get_another_input_char ();
477 ea_insert (window, count, character);
478}
479
480DECLARE_INFO_COMMAND (ea_insert, _("Insert this character"))void ea_insert (WINDOW *window, int count, unsigned char key)
481{
482 register int i;
483
484 if ((input_line_end + 1) == EA_MAX_INPUT256)
485 {
486 terminal_ring_bell ();
487 return;
488 }
489
490 for (i = input_line_end + 1; i != input_line_point; i--)
491 input_line[i] = input_line[i - 1];
492
493 input_line[input_line_point] = key;
494 input_line_point++;
495 input_line_end++;
496}
497
498DECLARE_INFO_COMMAND (ea_tab_insert, _("Insert a TAB character"))void ea_tab_insert (WINDOW *window, int count, unsigned char key
)
499{
500 ea_insert (window, count, '\t');
501}
502
503/* Transpose the characters at point. If point is at the end of the line,
504 then transpose the characters before point. */
505DECLARE_INFO_COMMAND (ea_transpose_chars, _("Transpose characters at point"))void ea_transpose_chars (WINDOW *window, int count, unsigned char
key)
506{
507 /* Handle conditions that would make it impossible to transpose
508 characters. */
509 if (!count || !input_line_point || (input_line_end - input_line_beg) < 2)
510 return;
511
512 while (count)
513 {
514 int t;
515 if (input_line_point == input_line_end)
516 {
517 t = input_line[input_line_point - 1];
518
519 input_line[input_line_point - 1] = input_line[input_line_point - 2];
520 input_line[input_line_point - 2] = t;
521 }
522 else
523 {
524 t = input_line[input_line_point];
525
526 input_line[input_line_point] = input_line[input_line_point - 1];
527 input_line[input_line_point - 1] = t;
528
529 if (count < 0 && input_line_point != input_line_beg)
530 input_line_point--;
531 else
532 input_line_point++;
533 }
534
535 if (count < 0)
536 count++;
537 else
538 count--;
539 }
540}
541
542/* **************************************************************** */
543/* */
544/* Echo Area Killing and Yanking */
545/* */
546/* **************************************************************** */
547
548static char **kill_ring = (char **)NULL((void *)0);
549static int kill_ring_index = 0; /* Number of kills appearing in KILL_RING. */
550static int kill_ring_slots = 0; /* Number of slots allocated to KILL_RING. */
551static int kill_ring_loc = 0; /* Location of current yank pointer. */
552
553/* The largest number of kills that we remember at one time. */
554static int max_retained_kills = 15;
555
556DECLARE_INFO_COMMAND (ea_yank, _("Yank back the contents of the last kill"))void ea_yank (WINDOW *window, int count, unsigned char key)
557{
558 register int i;
559 register char *text;
560
561 if (!kill_ring_index)
562 {
563 inform_in_echo_area ((char *) _("Kill ring is empty")((const char *) ("Kill ring is empty")));
564 return;
565 }
566
567 text = kill_ring[kill_ring_loc];
568
569 for (i = 0; text[i]; i++)
570 ea_insert (window, 1, text[i]);
571}
572
573/* If the last command was yank, or yank_pop, and the text just before
574 point is identical to the current kill item, then delete that text
575 from the line, rotate the index down, and yank back some other text. */
576DECLARE_INFO_COMMAND (ea_yank_pop, _("Yank back a previous kill"))void ea_yank_pop (WINDOW *window, int count, unsigned char key
)
577{
578 register int len;
579
580 if (((ea_last_executed_command != (VFunction *) ea_yank) &&
581 (ea_last_executed_command != (VFunction *) ea_yank_pop)) ||
582 (kill_ring_index == 0))
583 return;
584
585 len = strlen (kill_ring[kill_ring_loc]);
586
587 /* Delete the last yanked item from the line. */
588 {
589 register int i, counter;
590
591 counter = input_line_end - input_line_point;
592
593 for (i = input_line_point - len; counter; i++, counter--)
594 input_line[i] = input_line[i + len];
595
596 input_line_end -= len;
597 input_line_point -= len;
598 }
599
600 /* Get a previous kill, and yank that. */
601 kill_ring_loc--;
602 if (kill_ring_loc < 0)
603 kill_ring_loc = kill_ring_index - 1;
604
605 ea_yank (window, count, key);
606}
607
608/* Delete the text from point to end of line. */
609DECLARE_INFO_COMMAND (ea_kill_line, _("Kill to the end of the line"))void ea_kill_line (WINDOW *window, int count, unsigned char key
)
610{
611 if (count < 0)
612 {
613 ea_kill_text (input_line_point, input_line_beg);
614 input_line_point = input_line_beg;
615 }
616 else
617 ea_kill_text (input_line_point, input_line_end);
618}
619
620/* Delete the text from point to beg of line. */
621DECLARE_INFO_COMMAND (ea_backward_kill_line,void ea_backward_kill_line (WINDOW *window, int count, unsigned
char key)
622 _("Kill to the beginning of the line"))void ea_backward_kill_line (WINDOW *window, int count, unsigned
char key)
623{
624 if (count < 0)
625 ea_kill_text (input_line_point, input_line_end);
626 else
627 {
628 ea_kill_text (input_line_point, input_line_beg);
629 input_line_point = input_line_beg;
630 }
631}
632
633/* Delete from point to the end of the current word. */
634DECLARE_INFO_COMMAND (ea_kill_word, _("Kill the word following the cursor"))void ea_kill_word (WINDOW *window, int count, unsigned char key
)
635{
636 int orig_point = input_line_point;
637
638 if (count < 0)
639 ea_backward_kill_word (window, -count, key);
640 else
641 {
642 ea_forward_word (window, count, key);
643
644 if (input_line_point != orig_point)
645 ea_kill_text (orig_point, input_line_point);
646
647 input_line_point = orig_point;
648 }
649}
650
651/* Delete from point to the start of the current word. */
652DECLARE_INFO_COMMAND (ea_backward_kill_word,void ea_backward_kill_word (WINDOW *window, int count, unsigned
char key)
653 _("Kill the word preceding the cursor"))void ea_backward_kill_word (WINDOW *window, int count, unsigned
char key)
654{
655 int orig_point = input_line_point;
656
657 if (count < 0)
658 ea_kill_word (window, -count, key);
659 else
660 {
661 ea_backward_word (window, count, key);
662
663 if (input_line_point != orig_point)
664 ea_kill_text (orig_point, input_line_point);
665 }
666}
667
668/* The way to kill something. This appends or prepends to the last
669 kill, if the last command was a kill command. If FROM is less
670 than TO, then the killed text is appended to the most recent kill,
671 otherwise it is prepended. If the last command was not a kill command,
672 then a new slot is made for this kill. */
673static void
674ea_kill_text (int from, int to)
675{
676 register int i, counter, distance;
677 int killing_backwards, slot;
678 char *killed_text;
679
680 killing_backwards = (from > to);
681
682 /* If killing backwards, reverse the values of FROM and TO. */
683 if (killing_backwards)
684 {
685 int temp = from;
686 from = to;
687 to = temp;
688 }
689
690 /* Remember the text that we are about to delete. */
691 distance = to - from;
692 killed_text = (char *)xmalloc (1 + distance);
693 strncpy (killed_text, &input_line[from], distance);
694 killed_text[distance] = '\0';
695
696 /* Actually delete the text from the line. */
697 counter = input_line_end - to;
698
699 for (i = from; counter; i++, counter--)
700 input_line[i] = input_line[i + distance];
701
702 input_line_end -= distance;
703
704 /* If the last command was a kill, append or prepend the killed text to
705 the last command's killed text. */
706 if (echo_area_last_command_was_kill)
707 {
708 char *old, *new;
709
710 slot = kill_ring_loc;
711 old = kill_ring[slot];
712 new = (char *)xmalloc (1 + strlen (old) + strlen (killed_text));
713
714 if (killing_backwards)
715 {
716 /* Prepend TEXT to current kill. */
717 strcpy (new, killed_text);
718 strcat (new, old);
719 }
720 else
721 {
722 /* Append TEXT to current kill. */
723 strcpy (new, old);
724 strcat (new, killed_text);
725 }
726
727 free (old);
728 free (killed_text);
729 kill_ring[slot] = new;
730 }
731 else
732 {
733 /* Try to store the kill in a new slot, unless that would cause there
734 to be too many remembered kills. */
735 slot = kill_ring_index;
736
737 if (slot == max_retained_kills)
738 slot = 0;
739
740 if (slot + 1 > kill_ring_slots)
741 kill_ring = (char **) xrealloc
742 (kill_ring,
743 (kill_ring_slots += max_retained_kills) * sizeof (char *));
744
745 if (slot != kill_ring_index)
746 free (kill_ring[slot]);
747 else
748 kill_ring_index++;
749
750 kill_ring[slot] = killed_text;
751
752 kill_ring_loc = slot;
753 }
754
755 /* Notice that the last command was a kill. */
756 echo_area_last_command_was_kill++;
757}
758
759/* **************************************************************** */
760/* */
761/* Echo Area Completion */
762/* */
763/* **************************************************************** */
764
765/* Pointer to an array of REFERENCE to complete over. */
766static REFERENCE **echo_area_completion_items = (REFERENCE **)NULL((void *)0);
767
768/* Sorted array of REFERENCE * which is the possible completions found in
769 the variable echo_area_completion_items. If there is only one element,
770 it is the only possible completion. */
771static REFERENCE **completions_found = (REFERENCE **)NULL((void *)0);
772static int completions_found_index = 0;
773static int completions_found_slots = 0;
774
775/* The lowest common denominator found while completing. */
776static REFERENCE *LCD_completion;
777
778/* Internal functions used by the user calls. */
779static void build_completions (void), completions_must_be_rebuilt (void);
780
781/* Variable which holds the output of completions. */
782static NODE *possible_completions_output_node = (NODE *)NULL((void *)0);
783
784static char *compwin_name = "*Completions*";
785
786/* Return non-zero if WINDOW is a window used for completions output. */
787static int
788completions_window_p (WINDOW *window)
789{
790 int result = 0;
791
792 if (internal_info_node_p (window->node) &&
793 (strcmp (window->node->nodename, compwin_name) == 0))
794 result = 1;
795
796 return (result);
797}
798
799/* Workhorse for completion readers. If FORCE is non-zero, the user cannot
800 exit unless the line read completes, or is empty. */
801char *
802info_read_completing_internal (WINDOW *window, char *prompt,
803 REFERENCE **completions, int force)
804{
805 char *line;
806
807 /* If the echo area is already active, remember the current state. */
808 if (echo_area_is_active)
809 push_echo_area ();
810
811 echo_area_must_complete_p = force;
812
813 /* Initialize our local variables. */
814 initialize_input_line (prompt);
815
816 /* Initialize the echo area for the first (but maybe not the last) time. */
817 echo_area_initialize_node ();
818
819 /* Save away the original node of this window, and the window itself,
820 so echo area commands can temporarily use this window. */
821 remember_calling_window (window);
822
823 /* Save away the list of items to complete over. */
824 echo_area_completion_items = completions;
825 completions_must_be_rebuilt ();
826
827 active_window = the_echo_area;
828 echo_area_is_active++;
829
830 /* Read characters in the echo area. */
831 while (1)
832 {
833 info_read_and_dispatch ();
834
835 line = echo_area_after_read ();
836
837 /* Force the completion to take place if the user hasn't accepted
838 a default or aborted, and if FORCE is active. */
839 if (force && line && *line && completions)
840 {
841 register int i;
842
843 build_completions ();
844
845 /* If there is only one completion, then make the line be that
846 completion. */
847 if (completions_found_index == 1)
848 {
849 free (line);
850 line = xstrdup (completions_found[0]->label);
851 break;
852 }
853
854 /* If one of the completions matches exactly, then that is okay, so
855 return the current line. */
856 for (i = 0; i < completions_found_index; i++)
857 if (strcasecmp (completions_found[i]->label, line) == 0)
858 {
859 free (line);
860 line = xstrdup (completions_found[i]->label);
861 break;
862 }
863
864 /* If no match, go back and try again. */
865 if (i == completions_found_index)
866 {
867 if (!completions_found_index)
868 inform_in_echo_area ((char *) _("No completions")((const char *) ("No completions")));
869 else
870 inform_in_echo_area ((char *) _("Not complete")((const char *) ("Not complete")));
871 continue;
872 }
873 }
874 break;
875 }
876 echo_area_is_active--;
877
878 /* Restore the original active window and show point in it. */
879 active_window = calling_window;
880 restore_calling_window ();
881 display_cursor_at_point (active_window);
882 fflush (stdout(&__sF[1]));
883
884 echo_area_completion_items = (REFERENCE **)NULL((void *)0);
885 completions_must_be_rebuilt ();
886
887 /* If there is a previous loop waiting for us, restore it now. */
888 if (echo_area_is_active)
889 pop_echo_area ();
890
891 return (line);
892}
893
894/* Read a line in the echo area with completion over COMPLETIONS. */
895char *
896info_read_completing_in_echo_area (WINDOW *window,
897 char *prompt, REFERENCE **completions)
898{
899 return (info_read_completing_internal (window, prompt, completions, 1));
900}
901
902/* Read a line in the echo area allowing completion over COMPLETIONS, but
903 not requiring it. */
904char *
905info_read_maybe_completing (WINDOW *window,
906 char *prompt, REFERENCE **completions)
907{
908 return (info_read_completing_internal (window, prompt, completions, 0));
909}
910
911DECLARE_INFO_COMMAND (ea_possible_completions, _("List possible completions"))void ea_possible_completions (WINDOW *window, int count, unsigned
char key)
912{
913 if (!echo_area_completion_items)
914 {
915 ea_insert (window, count, key);
916 return;
917 }
918
919 build_completions ();
920
921 if (!completions_found_index)
922 {
923 terminal_ring_bell ();
924 inform_in_echo_area ((char *) _("No completions")((const char *) ("No completions")));
925 }
926 else if ((completions_found_index == 1) && (key != '?'))
927 {
928 inform_in_echo_area ((char *) _("Sole completion")((const char *) ("Sole completion")));
929 }
930 else
931 {
932 register int i, l;
933 int limit, iterations, max_label = 0;
934
935 initialize_message_buffer ();
936 printf_to_message_buffer (completions_found_index == 1
937 ? (char *) _("One completion:\n")((const char *) ("One completion:\n"))
938 : (char *) _("%d completions:\n")((const char *) ("%d completions:\n")),
939 (void *) (long) completions_found_index,
940 NULL((void *)0), NULL((void *)0));
941
942 /* Find the maximum length of a label. */
943 for (i = 0; i < completions_found_index; i++)
944 {
945 int len = strlen (completions_found[i]->label);
946 if (len > max_label)
947 max_label = len;
948 }
949
950 max_label += 4;
951
952 /* Find out how many columns we should print in. */
953 limit = calling_window->width / max_label;
954 if (limit != 1 && (limit * max_label == calling_window->width))
955 limit--;
956
957 /* Avoid a possible floating exception. If max_label > width then
958 the limit will be 0 and a divide-by-zero fault will result. */
959 if (limit == 0)
960 limit = 1;
961
962 /* How many iterations of the printing loop? */
963 iterations = (completions_found_index + (limit - 1)) / limit;
964
965 /* Watch out for special case. If the number of completions is less
966 than LIMIT, then just do the inner printing loop. */
967 if (completions_found_index < limit)
968 iterations = 1;
969
970 /* Print the sorted items, up-and-down alphabetically. */
971 for (i = 0; i < iterations; i++)
972 {
973 register int j;
974
975 for (j = 0, l = i; j < limit; j++)
976 {
977 if (l >= completions_found_index)
978 break;
979 else
980 {
981 char *label;
982 int printed_length, k;
983
984 label = completions_found[l]->label;
985 printed_length = strlen (label);
986 printf_to_message_buffer ("%s", label, NULL((void *)0), NULL((void *)0));
987
988 if (j + 1 < limit)
989 {
990 for (k = 0; k < max_label - printed_length; k++)
991 printf_to_message_buffer (" ", NULL((void *)0), NULL((void *)0), NULL((void *)0));
992 }
993 }
994 l += iterations;
995 }
996 printf_to_message_buffer ("\n", NULL((void *)0), NULL((void *)0), NULL((void *)0));
997 }
998
999 /* Make a new node to hold onto possible completions. Don't destroy
1000 dangling pointers. */
1001 {
1002 NODE *temp;
1003
1004 temp = message_buffer_to_node ();
1005 add_gcable_pointer (temp->contents);
1006 name_internal_node (temp, compwin_name);
1007 possible_completions_output_node = temp;
1008 }
1009
1010 /* Find a suitable window for displaying the completions output.
1011 First choice is an existing window showing completions output.
1012 If there is only one window, and it is large, make another
1013 (smaller) window, and use that one. Otherwise, use the caller's
1014 window. */
1015 {
1016 WINDOW *compwin;
1017
1018 compwin = get_internal_info_window (compwin_name);
1019
1020 if (!compwin)
1021 {
1022 /* If we can split the window to display most of the completion
1023 items, then do so. */
1024 if (calling_window->height > (iterations * 2)
1025 && calling_window->height / 2 >= WINDOW_MIN_SIZE(2 + 1))
1026 {
1027 int start, pagetop;
1028#ifdef SPLIT_BEFORE_ACTIVE
1029 int end;
1030#endif
1031
1032 active_window = calling_window;
1033
1034 /* Perhaps we can scroll this window on redisplay. */
1035 start = calling_window->first_row;
1036 pagetop = calling_window->pagetop;
1037
1038 compwin =
1039 window_make_window (possible_completions_output_node);
1040 active_window = the_echo_area;
1041 window_change_window_height
1042 (compwin, -(compwin->height - (iterations + 2)));
1043
1044 window_adjust_pagetop (calling_window);
1045 remember_calling_window (calling_window);
1046
1047#if defined (SPLIT_BEFORE_ACTIVE)
1048 /* If the pagetop hasn't changed, scrolling the calling
1049 window is a reasonable thing to do. */
1050 if (pagetop == calling_window->pagetop)
1051 {
1052 end = start + calling_window->height;
1053 display_scroll_display
1054 (start, end, calling_window->prev->height + 1);
1055 }
1056#else /* !SPLIT_BEFORE_ACTIVE */
1057 /* If the pagetop has changed, set the new pagetop here. */
1058 if (pagetop != calling_window->pagetop)
1059 {
1060 int newtop = calling_window->pagetop;
1061 calling_window->pagetop = pagetop;
1062 set_window_pagetop (calling_window, newtop);
1063 }
1064#endif /* !SPLIT_BEFORE_ACTIVE */
1065
1066 echo_area_completions_window = compwin;
1067 remember_window_and_node (compwin, compwin->node);
1068 }
1069 else
1070 compwin = calling_window;
1071 }
1072
1073 if (compwin->node != possible_completions_output_node)
1074 {
1075 window_set_node_of_window
1076 (compwin, possible_completions_output_node);
1077 remember_window_and_node (compwin, compwin->node);
1078 }
1079
1080 display_update_display (windows);
1081 }
1082 }
1083}
1084
1085DECLARE_INFO_COMMAND (ea_complete, _("Insert completion"))void ea_complete (WINDOW *window, int count, unsigned char key
)
1086{
1087 if (!echo_area_completion_items)
1088 {
1089 ea_insert (window, count, key);
1090 return;
1091 }
1092
1093 /* If KEY is SPC, and we are not forcing completion to take place, simply
1094 insert the key. */
1095 if (!echo_area_must_complete_p && key == SPC' ')
1096 {
1097 ea_insert (window, count, key);
1098 return;
1099 }
1100
1101 if (ea_last_executed_command == (VFunction *) ea_complete)
1102 {
1103 /* If the keypress is a SPC character, and we have already tried
1104 completing once, and there are several completions, then check
1105 the batch of completions to see if any continue with a space.
1106 If there are some, insert the space character and continue. */
1107 if (key == SPC' ' && completions_found_index > 1)
1108 {
1109 register int i, offset;
1110
1111 offset = input_line_end - input_line_beg;
1112
1113 for (i = 0; i < completions_found_index; i++)
1114 if (completions_found[i]->label[offset] == ' ')
1115 break;
1116
1117 if (completions_found[i])
1118 ea_insert (window, 1, ' ');
1119 else
1120 {
1121 ea_possible_completions (window, count, key);
1122 return;
1123 }
1124 }
1125 else
1126 {
1127 ea_possible_completions (window, count, key);
1128 return;
1129 }
1130 }
1131
1132 input_line_point = input_line_end;
1133 build_completions ();
1134
1135 if (!completions_found_index)
1136 terminal_ring_bell ();
1137 else if (LCD_completion->label[0] == '\0')
1138 ea_possible_completions (window, count, key);
1139 else
1140 {
1141 register int i;
1142 input_line_point = input_line_end = input_line_beg;
1143 for (i = 0; LCD_completion->label[i]; i++)
1144 ea_insert (window, 1, LCD_completion->label[i]);
1145 }
1146}
1147
1148/* Utility REFERENCE used to store possible LCD. */
1149static REFERENCE LCD_reference = {
1150 (char *)NULL((void *)0), (char *)NULL((void *)0), (char *)NULL((void *)0), 0, 0, 0
1151};
1152
1153static void remove_completion_duplicates (void);
1154
1155/* Variables which remember the state of the most recent call
1156 to build_completions (). */
1157static char *last_completion_request = (char *)NULL((void *)0);
1158static REFERENCE **last_completion_items = (REFERENCE **)NULL((void *)0);
1159
1160/* How to tell the completion builder to reset internal state. */
1161static void
1162completions_must_be_rebuilt (void)
1163{
1164 maybe_free (last_completion_request)do { if (last_completion_request) free (last_completion_request
); } while (0)
;
1165 last_completion_request = (char *)NULL((void *)0);
1166 last_completion_items = (REFERENCE **)NULL((void *)0);
1167}
1168
1169/* Build a list of possible completions from echo_area_completion_items,
1170 and the contents of input_line. */
1171static void
1172build_completions (void)
1173{
1174 register int i, len;
1175 register REFERENCE *entry;
1176 char *request;
1177 int informed_of_lengthy_job = 0;
1178
1179 /* If there are no items to complete over, exit immediately. */
1180 if (!echo_area_completion_items)
1181 {
1182 completions_found_index = 0;
1183 LCD_completion = (REFERENCE *)NULL((void *)0);
1184 return;
1185 }
1186
1187 /* Check to see if this call to build completions is the same as the last
1188 call to build completions. */
1189 len = input_line_end - input_line_beg;
1190 request = (char *)xmalloc (1 + len);
1191 strncpy (request, &input_line[input_line_beg], len);
1192 request[len] = '\0';
1193
1194 if (last_completion_request && last_completion_items &&
1195 last_completion_items == echo_area_completion_items &&
1196 (strcmp (last_completion_request, request) == 0))
1197 {
1198 free (request);
1199 return;
1200 }
1201
1202 maybe_free (last_completion_request)do { if (last_completion_request) free (last_completion_request
); } while (0)
;
1203 last_completion_request = request;
1204 last_completion_items = echo_area_completion_items;
1205
1206 /* Always start at the beginning of the list. */
1207 completions_found_index = 0;
1208 LCD_completion = (REFERENCE *)NULL((void *)0);
1209
1210 for (i = 0; (entry = echo_area_completion_items[i]); i++)
1211 {
1212 if (strncasecmp (request, entry->label, len) == 0)
1213 add_pointer_to_array (entry, completions_found_index,do { if (completions_found_index + 2 >= completions_found_slots
) completions_found = (REFERENCE * *)(xrealloc (completions_found
, (completions_found_slots += 20) * sizeof (REFERENCE *))); completions_found
[completions_found_index++] = (REFERENCE *)entry; completions_found
[completions_found_index] = (REFERENCE *)((void *)0); } while
(0)
1214 completions_found, completions_found_slots,do { if (completions_found_index + 2 >= completions_found_slots
) completions_found = (REFERENCE * *)(xrealloc (completions_found
, (completions_found_slots += 20) * sizeof (REFERENCE *))); completions_found
[completions_found_index++] = (REFERENCE *)entry; completions_found
[completions_found_index] = (REFERENCE *)((void *)0); } while
(0)
1215 20, REFERENCE *)do { if (completions_found_index + 2 >= completions_found_slots
) completions_found = (REFERENCE * *)(xrealloc (completions_found
, (completions_found_slots += 20) * sizeof (REFERENCE *))); completions_found
[completions_found_index++] = (REFERENCE *)entry; completions_found
[completions_found_index] = (REFERENCE *)((void *)0); } while
(0)
;
1216
1217 if (!informed_of_lengthy_job && completions_found_index > 100)
1218 {
1219 informed_of_lengthy_job = 1;
1220 window_message_in_echo_area ((char *) _("Building completions...")((const char *) ("Building completions...")),
1221 NULL((void *)0), NULL((void *)0));
1222 }
1223 }
1224
1225 if (!completions_found_index)
1226 return;
1227
1228 /* Sort and prune duplicate entries from the completions array. */
1229 remove_completion_duplicates ();
1230
1231 /* If there is only one completion, just return that. */
1232 if (completions_found_index == 1)
1233 {
1234 LCD_completion = completions_found[0];
1235 return;
1236 }
1237
1238 /* Find the least common denominator. */
1239 {
1240 long shortest = 100000;
1241
1242 for (i = 1; i < completions_found_index; i++)
1243 {
1244 register int j;
1245 int c1, c2;
1246
1247 for (j = 0;
1248 (c1 = info_tolower (completions_found[i - 1]->label[j])(isupper (completions_found[i - 1]->label[j]) ? tolower (completions_found
[i - 1]->label[j]) : completions_found[i - 1]->label[j]
)
) &&
1249 (c2 = info_tolower (completions_found[i]->label[j])(isupper (completions_found[i]->label[j]) ? tolower (completions_found
[i]->label[j]) : completions_found[i]->label[j])
);
1250 j++)
1251 if (c1 != c2)
1252 break;
1253
1254 if (shortest > j)
1255 shortest = j;
1256 }
1257
1258 maybe_free (LCD_reference.label)do { if (LCD_reference.label) free (LCD_reference.label); } while
(0)
;
1259 LCD_reference.label = (char *)xmalloc (1 + shortest);
1260 /* Since both the sorting done inside remove_completion_duplicates
1261 and all the comparisons above are case-insensitive, it's
1262 possible that the completion we are going to return is
1263 identical to what the user typed but for the letter-case. This
1264 is confusing, since the user could type FOOBAR<TAB> and get her
1265 string change letter-case for no good reason. So try to find a
1266 possible completion whose letter-case is identical, and if so,
1267 use that. */
1268 if (completions_found_index > 1)
1269 {
1270 int req_len = strlen (request);
1271
1272 for (i = 0; i < completions_found_index; i++)
1273 if (strncmp (request, completions_found[i]->label, req_len) == 0)
1274 break;
1275 /* If none of the candidates match exactly, use the first one. */
1276 if (i >= completions_found_index)
1277 i = 0;
1278 }
1279 strncpy (LCD_reference.label, completions_found[i]->label, shortest);
1280 LCD_reference.label[shortest] = '\0';
1281 LCD_completion = &LCD_reference;
1282 }
1283
1284 if (informed_of_lengthy_job)
1285 echo_area_initialize_node ();
1286}
1287
1288/* Function called by qsort. */
1289static int
1290compare_references (const void *entry1, const void *entry2)
1291{
1292 REFERENCE **e1 = (REFERENCE **) entry1;
1293 REFERENCE **e2 = (REFERENCE **) entry2;
1294
1295 return (strcasecmp ((*e1)->label, (*e2)->label));
1296}
1297
1298/* Prune duplicate entries from COMPLETIONS_FOUND. */
1299static void
1300remove_completion_duplicates (void)
1301{
1302 register int i, j;
1303 REFERENCE **temp;
1304 int newlen;
1305
1306 if (!completions_found_index)
1307 return;
1308
1309 /* Sort the items. */
1310 qsort (completions_found, completions_found_index, sizeof (REFERENCE *),
1311 compare_references);
1312
1313 for (i = 0, newlen = 1; i < completions_found_index - 1; i++)
1314 {
1315 if (strcmp (completions_found[i]->label,
1316 completions_found[i + 1]->label) == 0)
1317 completions_found[i] = (REFERENCE *)NULL((void *)0);
1318 else
1319 newlen++;
1320 }
1321
1322 /* We have marked all the dead slots. It is faster to copy the live slots
1323 twice than to prune the dead slots one by one. */
1324 temp = (REFERENCE **)xmalloc ((1 + newlen) * sizeof (REFERENCE *));
1325 for (i = 0, j = 0; i < completions_found_index; i++)
1326 if (completions_found[i])
1327 temp[j++] = completions_found[i];
1328
1329 for (i = 0; i < newlen; i++)
1330 completions_found[i] = temp[i];
1331
1332 completions_found[i] = (REFERENCE *)NULL((void *)0);
1333 completions_found_index = newlen;
1334 free (temp);
1335}
1336
1337/* Scroll the "other" window. If there is a window showing completions, scroll
1338 that one, otherwise scroll the window which was active on entering the read
1339 function. */
1340DECLARE_INFO_COMMAND (ea_scroll_completions_window, _("Scroll the completions window"))void ea_scroll_completions_window (WINDOW *window, int count,
unsigned char key)
1341{
1342 WINDOW *compwin;
1343 int old_pagetop;
1344
1345 compwin = get_internal_info_window (compwin_name);
1346
1347 if (!compwin)
1348 compwin = calling_window;
1349
1350 old_pagetop = compwin->pagetop;
Value stored to 'old_pagetop' is never read
1351
1352 /* Let info_scroll_forward () do the work, and print any messages that
1353 need to be displayed. */
1354 info_scroll_forward (compwin, count, key);
1355}
1356
1357/* Function which gets called when an Info window is deleted while the
1358 echo area is active. WINDOW is the window which has just been deleted. */
1359void
1360echo_area_inform_of_deleted_window (WINDOW *window)
1361{
1362 /* If this is the calling_window, forget what we remembered about it. */
1363 if (window == calling_window)
1364 {
1365 if (active_window != the_echo_area)
1366 remember_calling_window (active_window);
1367 else
1368 remember_calling_window (windows);
1369 }
1370
1371 /* If this window was the echo_area_completions_window, then notice that
1372 the window has been deleted. */
1373 if (window == echo_area_completions_window)
1374 echo_area_completions_window = (WINDOW *)NULL((void *)0);
1375}
1376
1377/* **************************************************************** */
1378/* */
1379/* Pushing and Popping the Echo Area */
1380/* */
1381/* **************************************************************** */
1382
1383/* Push and Pop the echo area. */
1384typedef struct {
1385 char *line;
1386 char *prompt;
1387 REFERENCE **comp_items;
1388 int point, beg, end;
1389 int must_complete;
1390 NODE node;
1391 WINDOW *compwin;
1392} PUSHED_EA;
1393
1394static PUSHED_EA **pushed_echo_areas = (PUSHED_EA **)NULL((void *)0);
1395static int pushed_echo_areas_index = 0;
1396static int pushed_echo_areas_slots = 0;
1397
1398/* Pushing the echo_area has a side effect of zeroing the completion_items. */
1399static void
1400push_echo_area (void)
1401{
1402 PUSHED_EA *pushed;
1403
1404 pushed = (PUSHED_EA *)xmalloc (sizeof (PUSHED_EA));
1405 pushed->line = xstrdup (input_line);
1406 pushed->prompt = input_line_prompt;
1407 pushed->point = input_line_point;
1408 pushed->beg = input_line_beg;
1409 pushed->end = input_line_end;
1410 pushed->node = input_line_node;
1411 pushed->comp_items = echo_area_completion_items;
1412 pushed->must_complete = echo_area_must_complete_p;
1413 pushed->compwin = echo_area_completions_window;
1414
1415 add_pointer_to_array (pushed, pushed_echo_areas_index, pushed_echo_areas,do { if (pushed_echo_areas_index + 2 >= pushed_echo_areas_slots
) pushed_echo_areas = (PUSHED_EA * *)(xrealloc (pushed_echo_areas
, (pushed_echo_areas_slots += 4) * sizeof (PUSHED_EA *))); pushed_echo_areas
[pushed_echo_areas_index++] = (PUSHED_EA *)pushed; pushed_echo_areas
[pushed_echo_areas_index] = (PUSHED_EA *)((void *)0); } while
(0)
1416 pushed_echo_areas_slots, 4, PUSHED_EA *)do { if (pushed_echo_areas_index + 2 >= pushed_echo_areas_slots
) pushed_echo_areas = (PUSHED_EA * *)(xrealloc (pushed_echo_areas
, (pushed_echo_areas_slots += 4) * sizeof (PUSHED_EA *))); pushed_echo_areas
[pushed_echo_areas_index++] = (PUSHED_EA *)pushed; pushed_echo_areas
[pushed_echo_areas_index] = (PUSHED_EA *)((void *)0); } while
(0)
;
1417
1418 echo_area_completion_items = (REFERENCE **)NULL((void *)0);
1419}
1420
1421static void
1422pop_echo_area (void)
1423{
1424 PUSHED_EA *popped;
1425
1426 popped = pushed_echo_areas[--pushed_echo_areas_index];
1427
1428 strcpy (input_line, popped->line);
1429 free (popped->line);
1430 input_line_prompt = popped->prompt;
1431 input_line_point = popped->point;
1432 input_line_beg = popped->beg;
1433 input_line_end = popped->end;
1434 input_line_node = popped->node;
1435 echo_area_completion_items = popped->comp_items;
1436 echo_area_must_complete_p = popped->must_complete;
1437 echo_area_completions_window = popped->compwin;
1438 completions_must_be_rebuilt ();
1439
1440 /* If the completion window no longer exists, forget about it. */
1441 if (echo_area_completions_window)
1442 {
1443 register WINDOW *win;
1444
1445 for (win = windows; win; win = win->next)
1446 if (echo_area_completions_window == win)
1447 break;
1448
1449 /* If the window wasn't found, then it has already been deleted. */
1450 if (!win)
1451 echo_area_completions_window = (WINDOW *)NULL((void *)0);
1452 }
1453
1454 free (popped);
1455}
1456
1457/* Returns non-zero if any of the prior stacked calls to read in the echo
1458 area produced a completions window. */
1459static int
1460echo_area_stack_contains_completions_p (void)
1461{
1462 register int i;
1463
1464 for (i = 0; i < pushed_echo_areas_index; i++)
1465 if (pushed_echo_areas[i]->compwin)
1466 return (1);
1467
1468 return (0);
1469}
1470
1471/* **************************************************************** */
1472/* */
1473/* Error Messages While Reading in Echo Area */
1474/* */
1475/* **************************************************************** */
1476
1477#if defined (HAVE_SYS_TIME_H1)
1478# include <sys/time.h>
1479# define HAVE_STRUCT_TIMEVAL
1480#endif /* HAVE_SYS_TIME_H */
1481
1482static void
1483pause_or_input (void)
1484{
1485#ifdef FD_SET
1486 struct timeval timer;
1487 fd_set readfds;
1488 int ready;
1489
1490 FD_ZERO (&readfds)do { fd_set *_p = (&readfds); __size_t _n = (((1024) + ((
((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)(sizeof
(__fd_mask) * 8)))); while (_n > 0) _p->fds_bits[--_n] =
0; } while (0)
;
1491 FD_SET (fileno (stdin), &readfds)__fd_set(((!__isthreaded ? (((&__sF[0]))->_file) : (fileno
)((&__sF[0])))), (&readfds))
;
1492 timer.tv_sec = 2;
1493 timer.tv_usec = 0;
1494 ready = select (fileno (stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
+ 1, &readfds, (fd_set *) NULL((void *)0),
1495 (fd_set *) NULL((void *)0), &timer);
1496#endif /* FD_SET */
1497}
1498
1499/* Print MESSAGE right after the end of the current line, and wait
1500 for input or a couple of seconds, whichever comes first. Then flush the
1501 informational message that was printed. */
1502void
1503inform_in_echo_area (const char *message)
1504{
1505 int i;
1506 char *text;
1507 int avail = EA_MAX_INPUT256 + 1 - input_line_end;
1508
1509 text = xstrdup (message);
1510 for (i = 0; text[i] && text[i] != '\n' && i < avail; i++)
1511 ;
1512 text[i] = 0;
1513
1514 echo_area_initialize_node ();
1515 sprintf (&input_line[input_line_end], "%s[%s]\n",
1516 echo_area_is_active ? " ": "", text);
1517 free (text);
1518 the_echo_area->point = input_line_point;
1519 display_update_one_window (the_echo_area);
1520 display_cursor_at_point (active_window);
1521 fflush (stdout(&__sF[1]));
1522 pause_or_input ();
1523 echo_area_initialize_node ();
1524}