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