xref: /openbsd/gnu/usr.bin/texinfo/info/echo-area.c (revision 1076333c)
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) (int *)(x)
28 #  else
29 #    define fd_set_cast(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. */
34 int info_aborted_echo_area = 0;
35 
36 /* Non-zero means that the echo area is being used to read input. */
37 int echo_area_is_active = 0;
38 
39 /* The address of the last command executed in the echo area. */
40 VFunction *ea_last_executed_command = (VFunction *)NULL;
41 
42 /* Non-zero means that the last command executed while reading input
43    killed some text. */
44 int echo_area_last_command_was_kill = 0;
45 
46 /* Variables which hold on to the current state of the input line. */
47 static char input_line[1 + EA_MAX_INPUT];
48 static char *input_line_prompt;
49 static int input_line_point;
50 static int input_line_beg;
51 static int input_line_end;
52 static NODE input_line_node = {
53   (char *)NULL, (char *)NULL, (char *)NULL, input_line,
54   EA_MAX_INPUT, 0, N_IsInternal
55 };
56 
57 static void echo_area_initialize_node (void);
58 static void push_echo_area (void), pop_echo_area (void);
59 static int echo_area_stack_contains_completions_p (void);
60 
61 static void ea_kill_text (int from, int to);
62 
63 /* Non-zero means we force the user to complete. */
64 static int echo_area_must_complete_p = 0;
65 static 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. */
70 static WINDOW *echo_area_completions_window = (WINDOW *)NULL;
71 
72 /* Variables which keep track of the window which was active prior to
73    entering the echo area. */
74 static WINDOW *calling_window = (WINDOW *)NULL;
75 static NODE *calling_window_node = (NODE *)NULL;
76 static long calling_window_point = 0;
77 static long calling_window_pagetop = 0;
78 
79 /* Remember the node and pertinent variables of the calling window. */
80 static void
remember_calling_window(WINDOW * window)81 remember_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 (). */
97 static void
restore_calling_window(void)98 restore_calling_window (void)
99 {
100   register WINDOW *win, *compwin = (WINDOW *)NULL;
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;
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;
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. */
162 static void
initialize_input_line(char * prompt)163 initialize_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 
174 static char *
echo_area_after_read(void)175 echo_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;
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. */
203 char *
info_read_in_echo_area(WINDOW * window,char * prompt)204 info_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);
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. */
249 static void
echo_area_initialize_node(void)250 echo_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. */
265 void
echo_area_prep_read(void)266 echo_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 
284 DECLARE_INFO_COMMAND (ea_forward, _("Move forward a character"))
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 
296 DECLARE_INFO_COMMAND (ea_backward, _("Move backward a character"))
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 
308 DECLARE_INFO_COMMAND (ea_beg_of_line, _("Move to the start of this line"))
309 {
310   input_line_point = input_line_beg;
311 }
312 
313 DECLARE_INFO_COMMAND (ea_end_of_line, _("Move to the end of this line"))
314 {
315   input_line_point = input_line_end;
316 }
317 
318 #define alphabetic(c) (islower (c) || isupper (c) || isdigit (c))
319 
320 /* Move forward a word in the input line. */
321 DECLARE_INFO_COMMAND (ea_forward_word, _("Move forward a word"))
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))
339             {
340               while (++input_line_point < input_line_end)
341                 {
342                   c = input_line[input_line_point];
343                   if (alphabetic (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))
355                 break;
356             }
357         }
358     }
359 }
360 
361 DECLARE_INFO_COMMAND (ea_backward_word, _("Move backward a word"))
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))
380             {
381               while ((--input_line_point) != input_line_beg)
382                 {
383                   c = input_line[input_line_point - 1];
384                   if (alphabetic (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))
393                 break;
394               else
395                 --input_line_point;
396             }
397         }
398     }
399 }
400 
401 DECLARE_INFO_COMMAND (ea_delete, _("Delete the character under the cursor"))
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 
431 DECLARE_INFO_COMMAND (ea_rubout, _("Delete the character behind the cursor"))
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 
452 DECLARE_INFO_COMMAND (ea_abort, _("Cancel or quit operation"))
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 
467 DECLARE_INFO_COMMAND (ea_newline, _("Accept (or force completion of) this line"))
468 {
469   /* Stub does nothing.  Simply here to see if it has been executed. */
470 }
471 
472 DECLARE_INFO_COMMAND (ea_quoted_insert, _("Insert next character verbatim"))
473 {
474   unsigned char character;
475 
476   character = info_get_another_input_char ();
477   ea_insert (window, count, character);
478 }
479 
480 DECLARE_INFO_COMMAND (ea_insert, _("Insert this character"))
481 {
482   register int i;
483 
484   if ((input_line_end + 1) == EA_MAX_INPUT)
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 
498 DECLARE_INFO_COMMAND (ea_tab_insert, _("Insert a TAB character"))
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. */
505 DECLARE_INFO_COMMAND (ea_transpose_chars, _("Transpose characters at point"))
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 
548 static char **kill_ring = (char **)NULL;
549 static int kill_ring_index = 0; /* Number of kills appearing in KILL_RING. */
550 static int kill_ring_slots = 0; /* Number of slots allocated to KILL_RING. */
551 static int kill_ring_loc = 0;   /* Location of current yank pointer. */
552 
553 /* The largest number of kills that we remember at one time. */
554 static int max_retained_kills = 15;
555 
556 DECLARE_INFO_COMMAND (ea_yank, _("Yank back the contents of the last kill"))
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"));
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. */
576 DECLARE_INFO_COMMAND (ea_yank_pop, _("Yank back a previous kill"))
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. */
609 DECLARE_INFO_COMMAND (ea_kill_line, _("Kill to the end of the line"))
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. */
621 DECLARE_INFO_COMMAND (ea_backward_kill_line,
622                       _("Kill to the beginning of the line"))
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. */
634 DECLARE_INFO_COMMAND (ea_kill_word, _("Kill the word following the cursor"))
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. */
652 DECLARE_INFO_COMMAND (ea_backward_kill_word,
653                       _("Kill the word preceding the cursor"))
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. */
673 static void
ea_kill_text(int from,int to)674 ea_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. */
766 static REFERENCE **echo_area_completion_items = (REFERENCE **)NULL;
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. */
771 static REFERENCE **completions_found = (REFERENCE **)NULL;
772 static int completions_found_index = 0;
773 static int completions_found_slots = 0;
774 
775 /* The lowest common denominator found while completing. */
776 static REFERENCE *LCD_completion;
777 
778 /* Internal functions used by the user calls. */
779 static void build_completions (void), completions_must_be_rebuilt (void);
780 
781 /* Variable which holds the output of completions. */
782 static NODE *possible_completions_output_node = (NODE *)NULL;
783 
784 static char *compwin_name = "*Completions*";
785 
786 /* Return non-zero if WINDOW is a window used for completions output. */
787 static int
completions_window_p(WINDOW * window)788 completions_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. */
801 char *
info_read_completing_internal(WINDOW * window,char * prompt,REFERENCE ** completions,int force)802 info_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"));
869               else
870                 inform_in_echo_area ((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);
883 
884   echo_area_completion_items = (REFERENCE **)NULL;
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. */
895 char *
info_read_completing_in_echo_area(WINDOW * window,char * prompt,REFERENCE ** completions)896 info_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. */
904 char *
info_read_maybe_completing(WINDOW * window,char * prompt,REFERENCE ** completions)905 info_read_maybe_completing (WINDOW *window,
906     char *prompt, REFERENCE **completions)
907 {
908   return (info_read_completing_internal (window, prompt, completions, 0));
909 }
910 
911 DECLARE_INFO_COMMAND (ea_possible_completions, _("List possible completions"))
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"));
925     }
926   else if ((completions_found_index == 1) && (key != '?'))
927     {
928       inform_in_echo_area ((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")
938                                 : (char *) _("%d completions:\n"),
939 				(void *) (long) completions_found_index,
940 				NULL, NULL);
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, NULL);
987 
988                   if (j + 1 < limit)
989                     {
990                       for (k = 0; k < max_label - printed_length; k++)
991                         printf_to_message_buffer (" ", NULL, NULL, NULL);
992                     }
993                 }
994               l += iterations;
995             }
996           printf_to_message_buffer ("\n", NULL, NULL, NULL);
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)
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 
1085 DECLARE_INFO_COMMAND (ea_complete, _("Insert completion"))
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. */
1149 static REFERENCE LCD_reference = {
1150     (char *)NULL, (char *)NULL, (char *)NULL, 0, 0, 0
1151 };
1152 
1153 static void remove_completion_duplicates (void);
1154 
1155 /* Variables which remember the state of the most recent call
1156    to build_completions (). */
1157 static char *last_completion_request = (char *)NULL;
1158 static REFERENCE **last_completion_items = (REFERENCE **)NULL;
1159 
1160 /* How to tell the completion builder to reset internal state. */
1161 static void
completions_must_be_rebuilt(void)1162 completions_must_be_rebuilt (void)
1163 {
1164   maybe_free (last_completion_request);
1165   last_completion_request = (char *)NULL;
1166   last_completion_items = (REFERENCE **)NULL;
1167 }
1168 
1169 /* Build a list of possible completions from echo_area_completion_items,
1170    and the contents of input_line. */
1171 static void
build_completions(void)1172 build_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;
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);
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;
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,
1214                               completions_found, completions_found_slots,
1215                               20, REFERENCE *);
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..."),
1221               NULL, NULL);
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])) &&
1249              (c2 = info_tolower (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);
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. */
1289 static int
compare_references(const void * entry1,const void * entry2)1290 compare_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. */
1299 static void
remove_completion_duplicates(void)1300 remove_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;
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;
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. */
1340 DECLARE_INFO_COMMAND (ea_scroll_completions_window, _("Scroll the completions window"))
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;
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. */
1359 void
echo_area_inform_of_deleted_window(WINDOW * window)1360 echo_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;
1375 }
1376 
1377 /* **************************************************************** */
1378 /*                                                                  */
1379 /*                 Pushing and Popping the Echo Area                */
1380 /*                                                                  */
1381 /* **************************************************************** */
1382 
1383 /* Push and Pop the echo area. */
1384 typedef 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 
1394 static PUSHED_EA **pushed_echo_areas = (PUSHED_EA **)NULL;
1395 static int pushed_echo_areas_index = 0;
1396 static int pushed_echo_areas_slots = 0;
1397 
1398 /* Pushing the echo_area has a side effect of zeroing the completion_items. */
1399 static void
push_echo_area(void)1400 push_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,
1416                         pushed_echo_areas_slots, 4, PUSHED_EA *);
1417 
1418   echo_area_completion_items = (REFERENCE **)NULL;
1419 }
1420 
1421 static void
pop_echo_area(void)1422 pop_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;
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. */
1459 static int
echo_area_stack_contains_completions_p(void)1460 echo_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_H)
1478 #  include <sys/time.h>
1479 #  define HAVE_STRUCT_TIMEVAL
1480 #endif /* HAVE_SYS_TIME_H */
1481 
1482 static void
pause_or_input(void)1483 pause_or_input (void)
1484 {
1485 #ifdef FD_SET
1486   struct timeval timer;
1487   fd_set readfds;
1488   int ready;
1489 
1490   FD_ZERO (&readfds);
1491   FD_SET (fileno (stdin), &readfds);
1492   timer.tv_sec = 2;
1493   timer.tv_usec = 0;
1494   ready = select (fileno (stdin) + 1, &readfds, (fd_set *) NULL,
1495                   (fd_set *) NULL, &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. */
1502 void
inform_in_echo_area(const char * message)1503 inform_in_echo_area (const char *message)
1504 {
1505   int i;
1506   char *text;
1507   int avail = EA_MAX_INPUT + 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);
1522   pause_or_input ();
1523   echo_area_initialize_node ();
1524 }
1525