1 /*
2  * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
3  *
4  * All rights reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, and/or sell copies of the Software, and to permit persons
11  * to whom the Software is furnished to do so, provided that the above
12  * copyright notice(s) and this permission notice appear in all copies of
13  * the Software and that both the above copyright notice(s) and this
14  * permission notice appear in supporting documentation.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19  * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20  * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
21  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
22  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
23  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25  *
26  * Except as contained in this notice, the name of a copyright holder
27  * shall not be used in advertising or otherwise to promote the sale, use
28  * or other dealings in this Software without prior written authorization
29  * of the copyright holder.
30  */
31 
32 /*
33  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
34  * Use is subject to license terms.
35  * Copyright (c) 2016 by Delphix. All rights reserved.
36  */
37 
38 /*
39  * Standard headers.
40  */
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <signal.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <ctype.h>
47 #include <setjmp.h>
48 #include <stdarg.h>
49 
50 /*
51  * UNIX headers.
52  */
53 #include <sys/ioctl.h>
54 #ifdef HAVE_SELECT
55 #ifdef HAVE_SYS_SELECT_H
56 #include <sys/select.h>
57 #endif
58 #include <sys/time.h>
59 #include <sys/types.h>
60 #endif
61 
62 /*
63  * Handle the different sources of terminal control string and size
64  * information. Note that if no terminal information database is available,
65  * ANSI VT100 control sequences are used.
66  */
67 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
68 /*
69  * Include curses.h or ncurses/curses.h depending on which is available.
70  */
71 #ifdef HAVE_CURSES_H
72 #include <curses.h>
73 #elif defined(HAVE_NCURSES_CURSES_H)
74 #include <ncurses/curses.h>
75 #endif
76 /*
77  * Include term.h where available.
78  */
79 #if defined(HAVE_TERM_H)
80 #include <term.h>
81 #elif defined(HAVE_NCURSES_TERM_H)
82 #include <ncurses/term.h>
83 #endif
84 /*
85  * When using termcap, include termcap.h on systems that have it.
86  * Otherwise assume that all prototypes are provided by curses.h.
87  */
88 #if defined(USE_TERMCAP) && defined(HAVE_TERMCAP_H)
89 #include <termcap.h>
90 #endif
91 
92 /*
93  * Under Solaris default Curses the output function that tputs takes is
94  * declared to have a char argument. On all other systems and on Solaris
95  * X/Open Curses (Issue 4, Version 2) it expects an int argument (using
96  * c89 or options -I /usr/xpg4/include -L /usr/xpg4/lib -R /usr/xpg4/lib
97  * selects XPG4v2 Curses on Solaris 2.6 and later).
98  *
99  * Similarly, under Mac OS X, the return value of the tputs output
100  * function is declared as void, whereas it is declared as int on
101  * other systems.
102  */
103 #if defined __sun && defined __SVR4 && !defined _XOPEN_CURSES
104 typedef int TputsRetType;
105 typedef char TputsArgType;              /* int tputs(char c, FILE *fp) */
106 #define TPUTS_RETURNS_VALUE 1
107 #elif defined(__APPLE__) && defined(__MACH__)
108 typedef void TputsRetType;
109 typedef int TputsArgType;               /* void tputs(int c, FILE *fp) */
110 #define TPUTS_RETURNS_VALUE 0
111 #else
112 typedef int TputsRetType;
113 typedef int TputsArgType;               /* int tputs(int c, FILE *fp) */
114 #define TPUTS_RETURNS_VALUE 1
115 #endif
116 
117 /*
118  * Use the above specifications to prototype our tputs callback function.
119  */
120 static TputsRetType gl_tputs_putchar(TputsArgType c);
121 
122 #endif  /* defined(USE_TERMINFO) || defined(USE_TERMCAP) */
123 
124 /*
125  * If the library is being compiled without filesystem access facilities,
126  * ensure that none of the action functions that normally do access the
127  * filesystem are bound by default, and that it they do get bound, that
128  * they don't do anything.
129  */
130 #if WITHOUT_FILE_SYSTEM
131 #define HIDE_FILE_SYSTEM
132 #endif
133 
134 /*
135  * POSIX headers.
136  */
137 #include <unistd.h>
138 #include <fcntl.h>
139 #include <termios.h>
140 
141 /*
142  * Provide typedefs for standard POSIX structures.
143  */
144 typedef struct sigaction SigAction;
145 typedef struct termios Termios;
146 
147 /*
148  * Which flag is used to select non-blocking I/O with fcntl()?
149  */
150 #undef NON_BLOCKING_FLAG
151 #if defined(O_NONBLOCK)
152 #define NON_BLOCKING_FLAG (O_NONBLOCK)
153 #elif defined(O_NDELAY)
154 #define NON_BLOCKING_FLAG (O_NDELAY)
155 #endif
156 
157 /*
158  * What value should we give errno if I/O blocks when it shouldn't.
159  */
160 #undef BLOCKED_ERRNO
161 #if defined(EAGAIN)
162 #define BLOCKED_ERRNO (EAGAIN)
163 #elif defined(EWOULDBLOCK)
164 #define BLOCKED_ERRNO (EWOULDBLOCK)
165 #elif defined(EIO)
166 #define BLOCKED_ERRNO (EIO)
167 #else
168 #define BLOCKED_ERRNO 0
169 #endif
170 
171 /*
172  * Local headers.
173  */
174 #ifndef WITHOUT_FILE_SYSTEM
175 #include "pathutil.h"
176 #endif
177 #include "libtecla.h"
178 #include "keytab.h"
179 #include "getline.h"
180 #include "ioutil.h"
181 #include "history.h"
182 #include "freelist.h"
183 #include "stringrp.h"
184 #include "chrqueue.h"
185 #include "cplmatch.h"
186 #ifndef WITHOUT_FILE_SYSTEM
187 #include "expand.h"
188 #endif
189 #include "errmsg.h"
190 
191 /*
192  * Enumerate the available editing styles.
193  */
194 typedef enum {
195   GL_EMACS_MODE,   /* Emacs style editing */
196   GL_VI_MODE,      /* Vi style editing */
197   GL_NO_EDITOR     /* Fall back to the basic OS-provided editing */
198 } GlEditor;
199 
200 /*
201  * Set the largest key-sequence that can be handled.
202  */
203 #define GL_KEY_MAX 64
204 
205 /*
206  * In vi mode, the following datatype is used to implement the
207  * undo command. It records a copy of the input line from before
208  * the command-mode action which edited the input line.
209  */
210 typedef struct {
211   char *line;        /* A historical copy of the input line */
212   int buff_curpos;   /* The historical location of the cursor in */
213                      /*  line[] when the line was modified. */
214   int ntotal;        /* The number of characters in line[] */
215   int saved;         /* True once a line has been saved after the */
216                      /*  last call to gl_interpret_char(). */
217 } ViUndo;
218 
219 /*
220  * In vi mode, the following datatype is used to record information
221  * needed by the vi-repeat-change command.
222  */
223 typedef struct {
224   KtAction action;           /* The last action function that made a */
225                              /*  change to the line. */
226   int count;                 /* The repeat count that was passed to the */
227                              /*  above command. */
228   int input_curpos;          /* Whenever vi command mode is entered, the */
229                              /*  the position at which it was first left */
230                              /*  is recorded here. */
231   int command_curpos;        /* Whenever vi command mode is entered, the */
232                              /*  the location of the cursor is recorded */
233                              /*  here. */
234   char input_char;           /* Commands that call gl_read_terminal() */
235                              /*  record the character here, so that it can */
236                              /*  used on repeating the function. */
237   int saved;                 /* True if a function has been saved since the */
238                              /*  last call to gl_interpret_char(). */
239   int active;                /* True while a function is being repeated. */
240 } ViRepeat;
241 
242 /*
243  * The following datatype is used to encapsulate information specific
244  * to vi mode.
245  */
246 typedef struct {
247   ViUndo undo;               /* Information needed to implement the vi */
248                              /*  undo command. */
249   ViRepeat repeat;           /* Information needed to implement the vi */
250                              /*  repeat command. */
251   int command;               /* True in vi command-mode */
252   int find_forward;          /* True if the last character search was in the */
253                              /*  forward direction. */
254   int find_onto;             /* True if the last character search left the */
255                              /*  on top of the located character, as opposed */
256                              /*  to just before or after it. */
257   char find_char;            /* The last character sought, or '\0' if no */
258                              /*  searches have been performed yet. */
259 } ViMode;
260 
261 #ifdef HAVE_SELECT
262 /*
263  * Define a type for recording a file-descriptor callback and its associated
264  * data.
265  */
266 typedef struct {
267   GlFdEventFn *fn;   /* The callback function */
268   void *data;        /* Anonymous data to pass to the callback function */
269 } GlFdHandler;
270 
271 /*
272  * A list of nodes of the following type is used to record file-activity
273  * event handlers, but only on systems that have the select() system call.
274  */
275 typedef struct GlFdNode GlFdNode;
276 struct GlFdNode {
277   GlFdNode *next;    /* The next in the list of nodes */
278   int fd;            /* The file descriptor being watched */
279   GlFdHandler rd;    /* The callback to call when fd is readable */
280   GlFdHandler wr;    /* The callback to call when fd is writable */
281   GlFdHandler ur;    /* The callback to call when fd has urgent data */
282 };
283 
284 /*
285  * Set the number of the above structures to allocate every time that
286  * the freelist of GlFdNode's becomes exhausted.
287  */
288 #define GLFD_FREELIST_BLOCKING 10
289 
290 
291 static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
292 			      GlFdEvent event);
293 
294 static int gl_call_timeout_handler(GetLine *gl);
295 
296 #endif
297 
298 /*
299  * Each signal that gl_get_line() traps is described by a list node
300  * of the following type.
301  */
302 typedef struct GlSignalNode GlSignalNode;
303 struct GlSignalNode {
304   GlSignalNode *next;  /* The next signal in the list */
305   int signo;           /* The number of the signal */
306   sigset_t proc_mask;  /* A process mask which only includes signo */
307   SigAction original;  /* The signal disposition of the calling program */
308                        /*  for this signal. */
309   unsigned flags;      /* A bitwise union of GlSignalFlags enumerators */
310   GlAfterSignal after; /* What to do after the signal has been handled */
311   int errno_value;     /* What to set errno to */
312 };
313 
314 /*
315  * Set the number of the above structures to allocate every time that
316  * the freelist of GlSignalNode's becomes exhausted.
317  */
318 #define GLS_FREELIST_BLOCKING 30
319 
320 /*
321  * Completion handlers and their callback data are recorded in
322  * nodes of the following type.
323  */
324 typedef struct GlCplCallback GlCplCallback;
325 struct GlCplCallback {
326   CplMatchFn *fn;            /* The completion callback function */
327   void *data;                /* Arbitrary callback data */
328 };
329 
330 /*
331  * The following function is used as the default completion handler when
332  * the filesystem is to be hidden. It simply reports no completions.
333  */
334 #ifdef HIDE_FILE_SYSTEM
335 static CPL_MATCH_FN(gl_no_completions);
336 #endif
337 
338 /*
339  * Specify how many GlCplCallback nodes are added to the GlCplCallback freelist
340  * whenever it becomes exhausted.
341  */
342 #define GL_CPL_FREELIST_BLOCKING 10
343 
344 /*
345  * External action functions and their callback data are recorded in
346  * nodes of the following type.
347  */
348 typedef struct GlExternalAction GlExternalAction;
349 struct GlExternalAction {
350   GlActionFn *fn;          /* The function which implements the action */
351   void *data;              /* Arbitrary callback data */
352 };
353 
354 /*
355  * Specify how many GlExternalAction nodes are added to the
356  * GlExternalAction freelist whenever it becomes exhausted.
357  */
358 #define GL_EXT_ACT_FREELIST_BLOCKING 10
359 
360 /*
361  * Define the contents of the GetLine object.
362  * Note that the typedef for this object can be found in libtecla.h.
363  */
364 struct GetLine {
365   ErrMsg *err;               /* The error-reporting buffer */
366   GlHistory *glh;            /* The line-history buffer */
367   WordCompletion *cpl;       /* String completion resource object */
368   GlCplCallback cplfn;       /* The completion callback */
369 #ifndef WITHOUT_FILE_SYSTEM
370   ExpandFile *ef;            /* ~user/, $envvar and wildcard expansion */
371                              /*  resource object. */
372 #endif
373   StringGroup *capmem;       /* Memory for recording terminal capability */
374                              /*  strings. */
375   GlCharQueue *cq;           /* The terminal output character queue */
376   int input_fd;              /* The file descriptor to read on */
377   int output_fd;             /* The file descriptor to write to */
378   FILE *input_fp;            /* A stream wrapper around input_fd */
379   FILE *output_fp;           /* A stream wrapper around output_fd */
380   FILE *file_fp;             /* When input is being temporarily taken from */
381                              /*  a file, this is its file-pointer. Otherwise */
382                              /*  it is NULL. */
383   char *term;                /* The terminal type specified on the last call */
384                              /*  to gl_change_terminal(). */
385   int is_term;               /* True if stdin is a terminal */
386   GlWriteFn *flush_fn;       /* The function to call to write to the terminal */
387   GlIOMode io_mode;          /* The I/O mode established by gl_io_mode() */
388   int raw_mode;              /* True while the terminal is in raw mode */
389   GlPendingIO pending_io;    /* The type of I/O that is currently pending */
390   GlReturnStatus rtn_status; /* The reason why gl_get_line() returned */
391   int rtn_errno;             /* THe value of errno associated with rtn_status */
392   size_t linelen;            /* The max number of characters per line */
393   char *line;                /* A line-input buffer of allocated size */
394                              /*  linelen+2. The extra 2 characters are */
395                              /*  reserved for "\n\0". */
396   char *cutbuf;              /* A cut-buffer of the same size as line[] */
397   char *prompt;              /* The current prompt string */
398   int prompt_len;            /* The length of the prompt string */
399   int prompt_changed;        /* True after a callback changes the prompt */
400   int prompt_style;          /* How the prompt string is displayed */
401   FreeList *cpl_mem;         /* Memory for GlCplCallback objects */
402   FreeList *ext_act_mem;     /* Memory for GlExternalAction objects */
403   FreeList *sig_mem;         /* Memory for nodes of the signal list */
404   GlSignalNode *sigs;        /* The head of the list of signals */
405   int signals_masked;        /* True between calls to gl_mask_signals() and */
406                              /*  gl_unmask_signals() */
407   int signals_overriden;     /* True between calls to gl_override_signals() */
408                              /*  and gl_restore_signals() */
409   sigset_t all_signal_set;   /* The set of all signals that we are trapping */
410   sigset_t old_signal_set;   /* The set of blocked signals on entry to */
411                              /*  gl_get_line(). */
412   sigset_t use_signal_set;   /* The subset of all_signal_set to unblock */
413                              /*  while waiting for key-strokes */
414   Termios oldattr;           /* Saved terminal attributes. */
415   KeyTab *bindings;          /* A table of key-bindings */
416   int ntotal;                /* The number of characters in gl->line[] */
417   int buff_curpos;           /* The cursor position within gl->line[] */
418   int term_curpos;           /* The cursor position on the terminal */
419   int term_len;              /* The number of terminal characters used to */
420                              /*  display the current input line. */
421   int buff_mark;             /* A marker location in the buffer */
422   int insert_curpos;         /* The cursor position at start of insert */
423   int insert;                /* True in insert mode */
424   int number;                /* If >= 0, a numeric argument is being read */
425   int endline;               /* True to tell gl_get_input_line() to return */
426                              /*  the current contents of gl->line[] */
427   int displayed;             /* True if an input line is currently displayed */
428   int redisplay;             /* If true, the input line will be redrawn */
429                              /*  either after the current action function */
430                              /*  returns, or when gl_get_input_line() */
431                              /*  is next called. */
432   int postpone;              /* _gl_normal_io() sets this flag, to */
433                              /*  postpone any redisplays until */
434                              /*  is next called, to resume line editing. */
435   char keybuf[GL_KEY_MAX+1]; /* A buffer of currently unprocessed key presses */
436   int nbuf;                  /* The number of characters in keybuf[] */
437   int nread;                 /* The number of characters read from keybuf[] */
438   KtAction current_action;   /* The action function that is being invoked */
439   int current_count;         /* The repeat count passed to */
440                              /*  current_acction.fn() */
441   GlhLineID preload_id;      /* When not zero, this should be the ID of a */
442                              /*  line in the history buffer for potential */
443                              /*  recall. */
444   int preload_history;       /* If true, preload the above history line when */
445                              /*  gl_get_input_line() is next called. */
446   long keyseq_count;         /* The number of key sequences entered by the */
447                              /*  the user since new_GetLine() was called. */
448   long last_search;          /* The value of keyseq_count during the last */
449                              /*  history search operation. */
450   GlEditor editor;           /* The style of editing, (eg. vi or emacs) */
451   int silence_bell;          /* True if gl_ring_bell() should do nothing. */
452   int automatic_history;     /* True to automatically archive entered lines */
453                              /*  in the history list. */
454   ViMode vi;                 /* Parameters used when editing in vi mode */
455   const char *left;          /* The string that moves the cursor 1 character */
456                              /*  left. */
457   const char *right;         /* The string that moves the cursor 1 character */
458                              /*  right. */
459   const char *up;            /* The string that moves the cursor 1 character */
460                              /*  up. */
461   const char *down;          /* The string that moves the cursor 1 character */
462                              /*  down. */
463   const char *home;          /* The string that moves the cursor home */
464   const char *bol;           /* Move cursor to beginning of line */
465   const char *clear_eol;     /* The string that clears from the cursor to */
466                              /*  the end of the line. */
467   const char *clear_eod;     /* The string that clears from the cursor to */
468                              /*  the end of the display. */
469   const char *u_arrow;       /* The string returned by the up-arrow key */
470   const char *d_arrow;       /* The string returned by the down-arrow key */
471   const char *l_arrow;       /* The string returned by the left-arrow key */
472   const char *r_arrow;       /* The string returned by the right-arrow key */
473   const char *sound_bell;    /* The string needed to ring the terminal bell */
474   const char *bold;          /* Switch to the bold font */
475   const char *underline;     /* Underline subsequent characters */
476   const char *standout;      /* Turn on standout mode */
477   const char *dim;           /* Switch to a dim font */
478   const char *reverse;       /* Turn on reverse video */
479   const char *blink;         /* Switch to a blinking font */
480   const char *text_attr_off; /* Turn off all text attributes */
481   int nline;                 /* The height of the terminal in lines */
482   int ncolumn;               /* The width of the terminal in columns */
483 #ifdef USE_TERMCAP
484   char *tgetent_buf;         /* The buffer that is used by tgetent() to */
485                              /*  store a terminal description. */
486   char *tgetstr_buf;         /* The buffer that is used by tgetstr() to */
487                              /*  store terminal capabilities. */
488 #endif
489 #ifdef USE_TERMINFO
490   const char *left_n;        /* The parameter string that moves the cursor */
491                              /*  n characters left. */
492   const char *right_n;       /* The parameter string that moves the cursor */
493                              /*  n characters right. */
494 #endif
495   char *app_file;            /* The pathname of the application-specific */
496                              /*  .teclarc configuration file, or NULL. */
497   char *user_file;           /* The pathname of the user-specific */
498                              /*  .teclarc configuration file, or NULL. */
499   int configured;            /* True as soon as any teclarc configuration */
500                              /*  file has been read. */
501   int echo;                  /* True to display the line as it is being */
502                              /*  entered. If 0, only the prompt will be */
503                              /*  displayed, and the line will not be */
504                              /*  archived in the history list. */
505   int last_signal;           /* The last signal that was caught by */
506                              /*  the last call to gl_get_line(), or -1 */
507                              /*  if no signal has been caught yet. */
508 #ifdef HAVE_SELECT
509   FreeList *fd_node_mem;     /* A freelist of GlFdNode structures */
510   GlFdNode *fd_nodes;        /* The list of fd event descriptions */
511   fd_set rfds;               /* The set of fds to watch for readability */
512   fd_set wfds;               /* The set of fds to watch for writability */
513   fd_set ufds;               /* The set of fds to watch for urgent data */
514   int max_fd;                /* The maximum file-descriptor being watched */
515   struct {                   /* Inactivity timeout related data */
516     struct timeval dt;       /* The inactivity timeout when timer.fn() */
517                              /*  isn't 0 */
518     GlTimeoutFn *fn;         /* The application callback to call when */
519                              /*  the inactivity timer expires, or 0 if */
520                              /*  timeouts are not required. */
521     void *data;              /* Application provided data to be passed to */
522                              /*  timer.fn(). */
523   } timer;
524 #endif
525 };
526 
527 /*
528  * Define the max amount of space needed to store a termcap terminal
529  * description. Unfortunately this has to be done by guesswork, so
530  * there is the potential for buffer overflows if we guess too small.
531  * Fortunately termcap has been replaced by terminfo on most
532  * platforms, and with terminfo this isn't an issue. The value that I
533  * am using here is the conventional value, as recommended by certain
534  * web references.
535  */
536 #ifdef USE_TERMCAP
537 #define TERMCAP_BUF_SIZE 2048
538 #endif
539 
540 /*
541  * Set the size of the string segments used to store terminal capability
542  * strings.
543  */
544 #define CAPMEM_SEGMENT_SIZE 512
545 
546 /*
547  * If no terminal size information is available, substitute the
548  * following vt100 default sizes.
549  */
550 #define GL_DEF_NLINE 24
551 #define GL_DEF_NCOLUMN 80
552 
553 /*
554  * Enumerate the attributes needed to classify different types of
555  * signals. These attributes reflect the standard default
556  * characteristics of these signals (according to Richard Steven's
557  * Advanced Programming in the UNIX Environment). Note that these values
558  * are all powers of 2, so that they can be combined in a bitwise union.
559  */
560 typedef enum {
561   GLSA_TERM=1,   /* A signal that terminates processes */
562   GLSA_SUSP=2,   /* A signal that suspends processes */
563   GLSA_CONT=4,   /* A signal that is sent when suspended processes resume */
564   GLSA_IGN=8,    /* A signal that is ignored */
565   GLSA_CORE=16,  /* A signal that generates a core dump */
566   GLSA_HARD=32,  /* A signal generated by a hardware exception */
567   GLSA_SIZE=64   /* A signal indicating terminal size changes */
568 } GlSigAttr;
569 
570 /*
571  * List the signals that we need to catch. In general these are
572  * those that by default terminate or suspend the process, since
573  * in such cases we need to restore terminal settings.
574  */
575 static const struct GlDefSignal {
576   int signo;            /* The number of the signal */
577   unsigned flags;       /* A bitwise union of GlSignalFlags enumerators */
578   GlAfterSignal after;  /* What to do after the signal has been delivered */
579   int attr;             /* The default attributes of this signal, expressed */
580                         /* as a bitwise union of GlSigAttr enumerators */
581   int errno_value;      /* What to set errno to */
582 } gl_signal_list[] = {
583   {SIGABRT,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
584   {SIGALRM,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM,           0},
585   {SIGCONT,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_CONT|GLSA_IGN,  0},
586 #if defined(SIGHUP)
587 #ifdef ENOTTY
588   {SIGHUP,    GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           ENOTTY},
589 #else
590   {SIGHUP,    GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
591 #endif
592 #endif
593   {SIGINT,    GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
594 #if defined(SIGPIPE)
595 #ifdef EPIPE
596   {SIGPIPE,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EPIPE},
597 #else
598   {SIGPIPE,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
599 #endif
600 #endif
601 #ifdef SIGPOLL
602   {SIGPOLL,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
603 #endif
604 #ifdef SIGPWR
605   {SIGPWR,    GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_IGN,            0},
606 #endif
607 #ifdef SIGQUIT
608   {SIGQUIT,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
609 #endif
610   {SIGTERM,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
611 #ifdef SIGTSTP
612   {SIGTSTP,   GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP,           0},
613 #endif
614 #ifdef SIGTTIN
615   {SIGTTIN,   GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP,           0},
616 #endif
617 #ifdef SIGTTOU
618   {SIGTTOU,   GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP,           0},
619 #endif
620 #ifdef SIGUSR1
621   {SIGUSR1,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM,           0},
622 #endif
623 #ifdef SIGUSR2
624   {SIGUSR2,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM,           0},
625 #endif
626 #ifdef SIGVTALRM
627   {SIGVTALRM, GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM,           0},
628 #endif
629 #ifdef SIGWINCH
630   {SIGWINCH,  GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_SIZE|GLSA_IGN,  0},
631 #endif
632 #ifdef SIGXCPU
633   {SIGXCPU,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
634 #endif
635 #ifdef SIGXFSZ
636   {SIGXFSZ,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
637 #endif
638 };
639 
640 /*
641  * Define file-scope variables for use in signal handlers.
642  */
643 static volatile sig_atomic_t gl_pending_signal = -1;
644 static sigjmp_buf gl_setjmp_buffer;
645 
646 static void gl_signal_handler(int signo);
647 
648 static int gl_check_caught_signal(GetLine *gl);
649 
650 /*
651  * Respond to an externally caught process suspension or
652  * termination signal.
653  */
654 static void gl_suspend_process(int signo, GetLine *gl, int ngl);
655 
656 /* Return the default attributes of a given signal */
657 
658 static int gl_classify_signal(int signo);
659 
660 /*
661  * Unfortunately both terminfo and termcap require one to use the tputs()
662  * function to output terminal control characters, and this function
663  * doesn't allow one to specify a file stream. As a result, the following
664  * file-scope variable is used to pass the current output file stream.
665  * This is bad, but there doesn't seem to be any alternative.
666  */
667 static GetLine *tputs_gl = NULL;
668 
669 /*
670  * Define a tab to be a string of 8 spaces.
671  */
672 #define TAB_WIDTH 8
673 
674 /*
675  * Lookup the current size of the terminal.
676  */
677 static void gl_query_size(GetLine *gl, int *ncolumn, int *nline);
678 
679 /*
680  * Getline calls this to temporarily override certain signal handlers
681  * of the calling program.
682  */
683 static int gl_override_signal_handlers(GetLine *gl);
684 
685 /*
686  * Getline calls this to restore the signal handlers of the calling
687  * program.
688  */
689 static int gl_restore_signal_handlers(GetLine *gl);
690 
691 /*
692  * Temporarily block the delivery of all signals that gl_get_line()
693  * is currently configured to trap.
694  */
695 static int gl_mask_signals(GetLine *gl, sigset_t *oldset);
696 
697 /*
698  * Restore the process signal mask that was overriden by a previous
699  * call to gl_mask_signals().
700  */
701 static int gl_unmask_signals(GetLine *gl, sigset_t *oldset);
702 
703 /*
704  * Unblock the signals that gl_get_line() has been configured to catch.
705  */
706 static int gl_catch_signals(GetLine *gl);
707 
708 /*
709  * Return the set of all trappable signals.
710  */
711 static void gl_list_trappable_signals(sigset_t *signals);
712 
713 /*
714  * Put the terminal into raw input mode, after saving the original
715  * terminal attributes in gl->oldattr.
716  */
717 static int gl_raw_terminal_mode(GetLine *gl);
718 
719 /*
720  * Restore the terminal attributes from gl->oldattr.
721  */
722 static int gl_restore_terminal_attributes(GetLine *gl);
723 
724 /*
725  * Switch to non-blocking I/O if possible.
726  */
727 static int gl_nonblocking_io(GetLine *gl, int fd);
728 
729 /*
730  * Switch to blocking I/O if possible.
731  */
732 static int gl_blocking_io(GetLine *gl, int fd);
733 
734 /*
735  * Read a line from the user in raw mode.
736  */
737 static int gl_get_input_line(GetLine *gl, const char *prompt,
738 			     const char *start_line, int start_pos);
739 
740 /*
741  * Query the user for a single character.
742  */
743 static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar);
744 
745 /*
746  * Read input from a non-interactive input stream.
747  */
748 static int gl_read_stream_line(GetLine *gl);
749 
750 /*
751  * Read a single character from a non-interactive input stream.
752  */
753 static int gl_read_stream_char(GetLine *gl);
754 
755 /*
756  * Prepare to edit a new line.
757  */
758 static int gl_present_line(GetLine *gl, const char *prompt,
759 			   const char *start_line, int start_pos);
760 
761 /*
762  * Reset all line input parameters for a new input line.
763  */
764 static void gl_reset_input_line(GetLine *gl);
765 
766 /*
767  * Handle the receipt of the potential start of a new key-sequence from
768  * the user.
769  */
770 static int gl_interpret_char(GetLine *gl, char c);
771 
772 /*
773  * Bind a single control or meta character to an action.
774  */
775 static int gl_bind_control_char(GetLine *gl, KtBinder binder,
776 				char c, const char *action);
777 
778 /*
779  * Set up terminal-specific key bindings.
780  */
781 static int gl_bind_terminal_keys(GetLine *gl);
782 
783 /*
784  * Lookup terminal control string and size information.
785  */
786 static int gl_control_strings(GetLine *gl, const char *term);
787 
788 /*
789  * Wrappers around the terminfo and termcap functions that lookup
790  * strings in the terminal information databases.
791  */
792 #ifdef USE_TERMINFO
793 static const char *gl_tigetstr(GetLine *gl, const char *name);
794 #elif defined(USE_TERMCAP)
795 static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr);
796 #endif
797 
798 /*
799  * Output a binary string directly to the terminal.
800  */
801 static int gl_print_raw_string(GetLine *gl, int buffered,
802 			       const char *string, int n);
803 
804 /*
805  * Print an informational message, starting and finishing on new lines.
806  * After the list of strings to be printed, the last argument MUST be
807  * GL_END_INFO.
808  */
809 static int gl_print_info(GetLine *gl, ...);
810 #define GL_END_INFO ((const char *)0)
811 
812 /*
813  * Start a newline and place the cursor at its start.
814  */
815 static int gl_start_newline(GetLine *gl, int buffered);
816 
817 /*
818  * Output a terminal control sequence.
819  */
820 static int gl_print_control_sequence(GetLine *gl, int nline,
821 				     const char *string);
822 
823 /*
824  * Output a character or string to the terminal after converting tabs
825  * to spaces and control characters to a caret followed by the modified
826  * character.
827  */
828 static int gl_print_char(GetLine *gl, char c, char pad);
829 static int gl_print_string(GetLine *gl, const char *string, char pad);
830 
831 /*
832  * Delete nc characters starting from the one under the cursor.
833  * Optionally copy the deleted characters to the cut buffer.
834  */
835 static int gl_delete_chars(GetLine *gl, int nc, int cut);
836 
837 /*
838  * Add a character to the line buffer at the current cursor position,
839  * inserting or overwriting according the current mode.
840  */
841 static int gl_add_char_to_line(GetLine *gl, char c);
842 
843 /*
844  * Insert/append a string to the line buffer and terminal at the current
845  * cursor position.
846  */
847 static int gl_add_string_to_line(GetLine *gl, const char *s);
848 
849 /*
850  * Record a new character in the input-line buffer.
851  */
852 static int gl_buffer_char(GetLine *gl, char c, int bufpos);
853 
854 /*
855  * Record a string in the input-line buffer.
856  */
857 static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos);
858 
859 /*
860  * Make way to insert a string in the input-line buffer.
861  */
862 static int gl_make_gap_in_buffer(GetLine *gl, int start, int n);
863 
864 /*
865  * Remove characters from the input-line buffer, and move any characters
866  * that followed them to the start of the vacated space.
867  */
868 static void gl_remove_from_buffer(GetLine *gl, int start, int n);
869 
870 /*
871  * Terminate the input-line buffer after a specified number of characters.
872  */
873 static int gl_truncate_buffer(GetLine *gl, int n);
874 
875 /*
876  * Delete the displayed part of the input line that follows the current
877  * terminal cursor position.
878  */
879 static int gl_truncate_display(GetLine *gl);
880 
881 /*
882  * Accomodate changes to the contents of the input line buffer
883  * that weren't made by the above gl_*buffer functions.
884  */
885 static void gl_update_buffer(GetLine *gl);
886 
887 /*
888  * Read a single character from the terminal.
889  */
890 static int gl_read_terminal(GetLine *gl, int keep, char *c);
891 
892 /*
893  * Discard processed characters from the key-press lookahead buffer.
894  */
895 static void gl_discard_chars(GetLine *gl, int nused);
896 
897 /*
898  * Move the terminal cursor n positions to the left or right.
899  */
900 static int gl_terminal_move_cursor(GetLine *gl, int n);
901 
902 /*
903  * Move the terminal cursor to a given position.
904  */
905 static int gl_set_term_curpos(GetLine *gl, int term_curpos);
906 
907 /*
908  * Set the position of the cursor both in the line input buffer and on the
909  * terminal.
910  */
911 static int gl_place_cursor(GetLine *gl, int buff_curpos);
912 
913 /*
914  * How many characters are needed to write a number as an octal string?
915  */
916 static int gl_octal_width(unsigned num);
917 
918 /*
919  * Return the number of spaces needed to display a tab character at
920  * a given location of the terminal.
921  */
922 static int gl_displayed_tab_width(GetLine *gl, int term_curpos);
923 
924 /*
925  * Return the number of terminal characters needed to display a
926  * given raw character.
927  */
928 static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos);
929 
930 /*
931  * Return the number of terminal characters needed to display a
932  * given substring.
933  */
934 static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
935 				     int term_curpos);
936 
937 /*
938  * Return non-zero if 'c' is to be considered part of a word.
939  */
940 static int gl_is_word_char(int c);
941 
942 /*
943  * Read a tecla configuration file.
944  */
945 static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who);
946 
947 /*
948  * Read a tecla configuration string.
949  */
950 static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who);
951 
952 /*
953  * Define the callback function used by _gl_parse_config_line() to
954  * read the next character of a configuration stream.
955  */
956 #define GLC_GETC_FN(fn) int (fn)(void *stream)
957 typedef GLC_GETC_FN(GlcGetcFn);
958 
959 static GLC_GETC_FN(glc_file_getc);  /* Read from a file */
960 static GLC_GETC_FN(glc_buff_getc);  /* Read from a string */
961 
962 /*
963  * Parse a single configuration command line.
964  */
965 static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
966 				 const char *origin, KtBinder who, int *lineno);
967 static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
968 				  const char *errmsg);
969 
970 /*
971  * Bind the actual arrow key bindings to match those of the symbolic
972  * arrow-key bindings.
973  */
974 static int _gl_bind_arrow_keys(GetLine *gl);
975 
976 /*
977  * Copy the binding of the specified symbolic arrow-key binding to
978  * the terminal specific, and default arrow-key key-sequences.
979  */
980 static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
981 				const char *term_seq,
982 				const char *def_seq1,
983 				const char *def_seq2);
984 
985 /*
986  * After the gl_read_from_file() action has been used to tell gl_get_line()
987  * to temporarily read input from a file, gl_revert_input() arranges
988  * for input to be reverted to the input stream last registered with
989  * gl_change_terminal().
990  */
991 static void gl_revert_input(GetLine *gl);
992 
993 /*
994  * Flush unwritten characters to the terminal.
995  */
996 static int gl_flush_output(GetLine *gl);
997 
998 /*
999  * The callback through which all terminal output is routed.
1000  * This simply appends characters to a queue buffer, which is
1001  * subsequently flushed to the output channel by gl_flush_output().
1002  */
1003 static GL_WRITE_FN(gl_write_fn);
1004 
1005 /*
1006  * The callback function which the output character queue object
1007  * calls to transfer characters to the output channel.
1008  */
1009 static GL_WRITE_FN(gl_flush_terminal);
1010 
1011 /*
1012  * Enumerate the possible return statuses of gl_read_input().
1013  */
1014 typedef enum {
1015   GL_READ_OK,      /* A character was read successfully */
1016   GL_READ_ERROR,   /* A read-error occurred */
1017   GL_READ_BLOCKED, /* The read would have blocked the caller */
1018   GL_READ_EOF      /* The end of the current input file was reached */
1019 } GlReadStatus;
1020 
1021 static GlReadStatus gl_read_input(GetLine *gl, char *c);
1022 /*
1023  * Private functions of gl_read_input().
1024  */
1025 static int gl_event_handler(GetLine *gl, int fd);
1026 static int gl_read_unmasked(GetLine *gl, int fd, char *c);
1027 
1028 
1029 /*
1030  * A private function of gl_tty_signals().
1031  */
1032 static int gl_set_tty_signal(int signo, void (*handler)(int));
1033 
1034 /*
1035  * Change the editor style being emulated.
1036  */
1037 static int gl_change_editor(GetLine *gl, GlEditor editor);
1038 
1039 /*
1040  * Searching in a given direction, return the index of a given (or
1041  * read) character in the input line, or the character that precedes
1042  * it in the specified search direction. Return -1 if not found.
1043  */
1044 static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c);
1045 
1046 /*
1047  * Return the buffer index of the nth word ending after the cursor.
1048  */
1049 static int gl_nth_word_end_forward(GetLine *gl, int n);
1050 
1051 /*
1052  * Return the buffer index of the nth word start after the cursor.
1053  */
1054 static int gl_nth_word_start_forward(GetLine *gl, int n);
1055 
1056 /*
1057  * Return the buffer index of the nth word start before the cursor.
1058  */
1059 static int gl_nth_word_start_backward(GetLine *gl, int n);
1060 
1061 /*
1062  * When called when vi command mode is enabled, this function saves the
1063  * current line and cursor position for potential restoration later
1064  * by the vi undo command.
1065  */
1066 static void gl_save_for_undo(GetLine *gl);
1067 
1068 /*
1069  * If in vi mode, switch to vi command mode.
1070  */
1071 static void gl_vi_command_mode(GetLine *gl);
1072 
1073 /*
1074  * In vi mode this is used to delete up to or onto a given or read
1075  * character in the input line. Also switch to insert mode if requested
1076  * after the deletion.
1077  */
1078 static int gl_delete_find(GetLine *gl, int count, char c, int forward,
1079 			  int onto, int change);
1080 
1081 /*
1082  * Copy the characters between the cursor and the count'th instance of
1083  * a specified (or read) character in the input line, into the cut buffer.
1084  */
1085 static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto);
1086 
1087 /*
1088  * Return the line index of the parenthesis that either matches the one under
1089  * the cursor, or not over a parenthesis character, the index of the next
1090  * close parenthesis. Return -1 if not found.
1091  */
1092 static int gl_index_of_matching_paren(GetLine *gl);
1093 
1094 /*
1095  * Replace a malloc'd string (or NULL), with another malloc'd copy of
1096  * a string (or NULL).
1097  */
1098 static int gl_record_string(char **sptr, const char *string);
1099 
1100 /*
1101  * Enumerate text display attributes as powers of two, suitable for
1102  * use in a bit-mask.
1103  */
1104 typedef enum {
1105   GL_TXT_STANDOUT=1,   /* Display text highlighted */
1106   GL_TXT_UNDERLINE=2,  /* Display text underlined */
1107   GL_TXT_REVERSE=4,    /* Display text with reverse video */
1108   GL_TXT_BLINK=8,      /* Display blinking text */
1109   GL_TXT_DIM=16,       /* Display text in a dim font */
1110   GL_TXT_BOLD=32       /* Display text using a bold font */
1111 } GlTextAttr;
1112 
1113 /*
1114  * Display the prompt regardless of the current visibility mode.
1115  */
1116 static int gl_display_prompt(GetLine *gl);
1117 
1118 /*
1119  * Return the number of characters used by the prompt on the terminal.
1120  */
1121 static int gl_displayed_prompt_width(GetLine *gl);
1122 
1123 /*
1124  * Prepare to return the current input line to the caller of gl_get_line().
1125  */
1126 static int gl_line_ended(GetLine *gl, int newline_char);
1127 
1128 /*
1129  * Arrange for the input line to be redisplayed when the current contents
1130  * of the output queue have been flushed.
1131  */
1132 static void gl_queue_redisplay(GetLine *gl);
1133 
1134 /*
1135  * Erase the displayed representation of the input line, without
1136  * touching the buffered copy.
1137  */
1138 static int gl_erase_line(GetLine *gl);
1139 
1140 /*
1141  * This function is called whenever the input line has been erased.
1142  */
1143 static void gl_line_erased(GetLine *gl);
1144 
1145 /*
1146  * Arrange for the current input line to be discarded.
1147  */
1148 void _gl_abandon_line(GetLine *gl);
1149 
1150 /*
1151  * The following are private internally callable versions of pertinent
1152  * public functions. Unlike their public wrapper functions, they don't
1153  * block signals while running, and assume that their arguments are valid.
1154  * They are designed to be called from places where signals are already
1155  * blocked, and where simple sanity checks have already been applied to
1156  * their arguments.
1157  */
1158 static char *_gl_get_line(GetLine *gl, const char *prompt,
1159 			  const char *start_line, int start_pos);
1160 static int _gl_query_char(GetLine *gl, const char *prompt, char defchar);
1161 static int _gl_read_char(GetLine *gl);
1162 static int _gl_update_size(GetLine *gl);
1163 /*
1164  * Redraw the current input line to account for a change in the terminal
1165  * size. Also install the new size in gl.
1166  */
1167 static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline);
1168 
1169 static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
1170 			       const char *term);
1171 static int _gl_configure_getline(GetLine *gl, const char *app_string,
1172 				 const char *app_file, const char *user_file);
1173 static int _gl_save_history(GetLine *gl, const char *filename,
1174 			    const char *comment, int max_lines);
1175 static int _gl_load_history(GetLine *gl, const char *filename,
1176 			    const char *comment);
1177 static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
1178 			GlFdEventFn *callback, void *data);
1179 static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
1180 			      GlTerminalSize *size);
1181 static void _gl_replace_prompt(GetLine *gl, const char *prompt);
1182 static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
1183 			   GlAfterSignal after, int errno_value);
1184 static int _gl_raw_io(GetLine *gl, int redisplay);
1185 static int _gl_normal_io(GetLine *gl);
1186 static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
1187 				 int list_only, const char *name,
1188 				 const char *keyseq);
1189 static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
1190 			       const char *name, const char *keyseq);
1191 static int _gl_io_mode(GetLine *gl, GlIOMode mode);
1192 static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline);
1193 static int _gl_append_history(GetLine *gl, const char *line);
1194 
1195 /*
1196  * Reset the completion status and associated errno value in
1197  * gl->rtn_status and gl->rtn_errno.
1198  */
1199 static void gl_clear_status(GetLine *gl);
1200 
1201 /*
1202  * Record a completion status, unless a previous abnormal completion
1203  * status has already been recorded for the current call.
1204  */
1205 static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
1206 			     int rtn_errno);
1207 
1208 /*
1209  * Set the maximum length of a line in a user's tecla configuration
1210  * file (not counting comments).
1211  */
1212 #define GL_CONF_BUFLEN 100
1213 
1214 /*
1215  * Set the maximum number of arguments supported by individual commands
1216  * in tecla configuration files.
1217  */
1218 #define GL_CONF_MAXARG 10
1219 
1220 /*
1221  * Prototype the available action functions.
1222  */
1223 static KT_KEY_FN(gl_user_interrupt);
1224 static KT_KEY_FN(gl_abort);
1225 static KT_KEY_FN(gl_suspend);
1226 static KT_KEY_FN(gl_stop_output);
1227 static KT_KEY_FN(gl_start_output);
1228 static KT_KEY_FN(gl_literal_next);
1229 static KT_KEY_FN(gl_cursor_left);
1230 static KT_KEY_FN(gl_cursor_right);
1231 static KT_KEY_FN(gl_insert_mode);
1232 static KT_KEY_FN(gl_beginning_of_line);
1233 static KT_KEY_FN(gl_end_of_line);
1234 static KT_KEY_FN(gl_delete_line);
1235 static KT_KEY_FN(gl_kill_line);
1236 static KT_KEY_FN(gl_forward_word);
1237 static KT_KEY_FN(gl_backward_word);
1238 static KT_KEY_FN(gl_forward_delete_char);
1239 static KT_KEY_FN(gl_backward_delete_char);
1240 static KT_KEY_FN(gl_forward_delete_word);
1241 static KT_KEY_FN(gl_backward_delete_word);
1242 static KT_KEY_FN(gl_delete_refind);
1243 static KT_KEY_FN(gl_delete_invert_refind);
1244 static KT_KEY_FN(gl_delete_to_column);
1245 static KT_KEY_FN(gl_delete_to_parenthesis);
1246 static KT_KEY_FN(gl_forward_delete_find);
1247 static KT_KEY_FN(gl_backward_delete_find);
1248 static KT_KEY_FN(gl_forward_delete_to);
1249 static KT_KEY_FN(gl_backward_delete_to);
1250 static KT_KEY_FN(gl_upcase_word);
1251 static KT_KEY_FN(gl_downcase_word);
1252 static KT_KEY_FN(gl_capitalize_word);
1253 static KT_KEY_FN(gl_redisplay);
1254 static KT_KEY_FN(gl_clear_screen);
1255 static KT_KEY_FN(gl_transpose_chars);
1256 static KT_KEY_FN(gl_set_mark);
1257 static KT_KEY_FN(gl_exchange_point_and_mark);
1258 static KT_KEY_FN(gl_kill_region);
1259 static KT_KEY_FN(gl_copy_region_as_kill);
1260 static KT_KEY_FN(gl_yank);
1261 static KT_KEY_FN(gl_up_history);
1262 static KT_KEY_FN(gl_down_history);
1263 static KT_KEY_FN(gl_history_search_backward);
1264 static KT_KEY_FN(gl_history_re_search_backward);
1265 static KT_KEY_FN(gl_history_search_forward);
1266 static KT_KEY_FN(gl_history_re_search_forward);
1267 static KT_KEY_FN(gl_complete_word);
1268 #ifndef HIDE_FILE_SYSTEM
1269 static KT_KEY_FN(gl_expand_filename);
1270 static KT_KEY_FN(gl_read_from_file);
1271 static KT_KEY_FN(gl_read_init_files);
1272 static KT_KEY_FN(gl_list_glob);
1273 #endif
1274 static KT_KEY_FN(gl_del_char_or_list_or_eof);
1275 static KT_KEY_FN(gl_list_or_eof);
1276 static KT_KEY_FN(gl_beginning_of_history);
1277 static KT_KEY_FN(gl_end_of_history);
1278 static KT_KEY_FN(gl_digit_argument);
1279 static KT_KEY_FN(gl_newline);
1280 static KT_KEY_FN(gl_repeat_history);
1281 static KT_KEY_FN(gl_vi_insert);
1282 static KT_KEY_FN(gl_vi_overwrite);
1283 static KT_KEY_FN(gl_change_case);
1284 static KT_KEY_FN(gl_vi_insert_at_bol);
1285 static KT_KEY_FN(gl_vi_append_at_eol);
1286 static KT_KEY_FN(gl_vi_append);
1287 static KT_KEY_FN(gl_backward_kill_line);
1288 static KT_KEY_FN(gl_goto_column);
1289 static KT_KEY_FN(gl_forward_to_word);
1290 static KT_KEY_FN(gl_vi_replace_char);
1291 static KT_KEY_FN(gl_vi_change_rest_of_line);
1292 static KT_KEY_FN(gl_vi_change_line);
1293 static KT_KEY_FN(gl_vi_change_to_bol);
1294 static KT_KEY_FN(gl_vi_change_refind);
1295 static KT_KEY_FN(gl_vi_change_invert_refind);
1296 static KT_KEY_FN(gl_vi_change_to_column);
1297 static KT_KEY_FN(gl_vi_change_to_parenthesis);
1298 static KT_KEY_FN(gl_vi_forward_change_word);
1299 static KT_KEY_FN(gl_vi_backward_change_word);
1300 static KT_KEY_FN(gl_vi_forward_change_find);
1301 static KT_KEY_FN(gl_vi_backward_change_find);
1302 static KT_KEY_FN(gl_vi_forward_change_to);
1303 static KT_KEY_FN(gl_vi_backward_change_to);
1304 static KT_KEY_FN(gl_vi_forward_change_char);
1305 static KT_KEY_FN(gl_vi_backward_change_char);
1306 static KT_KEY_FN(gl_forward_copy_char);
1307 static KT_KEY_FN(gl_backward_copy_char);
1308 static KT_KEY_FN(gl_forward_find_char);
1309 static KT_KEY_FN(gl_backward_find_char);
1310 static KT_KEY_FN(gl_forward_to_char);
1311 static KT_KEY_FN(gl_backward_to_char);
1312 static KT_KEY_FN(gl_repeat_find_char);
1313 static KT_KEY_FN(gl_invert_refind_char);
1314 static KT_KEY_FN(gl_append_yank);
1315 static KT_KEY_FN(gl_backward_copy_word);
1316 static KT_KEY_FN(gl_forward_copy_word);
1317 static KT_KEY_FN(gl_copy_to_bol);
1318 static KT_KEY_FN(gl_copy_refind);
1319 static KT_KEY_FN(gl_copy_invert_refind);
1320 static KT_KEY_FN(gl_copy_to_column);
1321 static KT_KEY_FN(gl_copy_to_parenthesis);
1322 static KT_KEY_FN(gl_copy_rest_of_line);
1323 static KT_KEY_FN(gl_copy_line);
1324 static KT_KEY_FN(gl_backward_copy_find);
1325 static KT_KEY_FN(gl_forward_copy_find);
1326 static KT_KEY_FN(gl_backward_copy_to);
1327 static KT_KEY_FN(gl_forward_copy_to);
1328 static KT_KEY_FN(gl_vi_undo);
1329 static KT_KEY_FN(gl_emacs_editing_mode);
1330 static KT_KEY_FN(gl_vi_editing_mode);
1331 static KT_KEY_FN(gl_ring_bell);
1332 static KT_KEY_FN(gl_vi_repeat_change);
1333 static KT_KEY_FN(gl_find_parenthesis);
1334 static KT_KEY_FN(gl_list_history);
1335 static KT_KEY_FN(gl_list_completions);
1336 static KT_KEY_FN(gl_run_external_action);
1337 
1338 /*
1339  * Name the available action functions.
1340  */
1341 static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = {
1342   {"user-interrupt",             gl_user_interrupt},
1343   {"abort",                      gl_abort},
1344   {"suspend",                    gl_suspend},
1345   {"stop-output",                gl_stop_output},
1346   {"start-output",               gl_start_output},
1347   {"literal-next",               gl_literal_next},
1348   {"cursor-right",               gl_cursor_right},
1349   {"cursor-left",                gl_cursor_left},
1350   {"insert-mode",                gl_insert_mode},
1351   {"beginning-of-line",          gl_beginning_of_line},
1352   {"end-of-line",                gl_end_of_line},
1353   {"delete-line",                gl_delete_line},
1354   {"kill-line",                  gl_kill_line},
1355   {"forward-word",               gl_forward_word},
1356   {"backward-word",              gl_backward_word},
1357   {"forward-delete-char",        gl_forward_delete_char},
1358   {"backward-delete-char",       gl_backward_delete_char},
1359   {"forward-delete-word",        gl_forward_delete_word},
1360   {"backward-delete-word",       gl_backward_delete_word},
1361   {"delete-refind",              gl_delete_refind},
1362   {"delete-invert-refind",       gl_delete_invert_refind},
1363   {"delete-to-column",           gl_delete_to_column},
1364   {"delete-to-parenthesis",      gl_delete_to_parenthesis},
1365   {"forward-delete-find",        gl_forward_delete_find},
1366   {"backward-delete-find",       gl_backward_delete_find},
1367   {"forward-delete-to",          gl_forward_delete_to},
1368   {"backward-delete-to",         gl_backward_delete_to},
1369   {"upcase-word",                gl_upcase_word},
1370   {"downcase-word",              gl_downcase_word},
1371   {"capitalize-word",            gl_capitalize_word},
1372   {"redisplay",                  gl_redisplay},
1373   {"clear-screen",               gl_clear_screen},
1374   {"transpose-chars",            gl_transpose_chars},
1375   {"set-mark",                   gl_set_mark},
1376   {"exchange-point-and-mark",    gl_exchange_point_and_mark},
1377   {"kill-region",                gl_kill_region},
1378   {"copy-region-as-kill",        gl_copy_region_as_kill},
1379   {"yank",                       gl_yank},
1380   {"up-history",                 gl_up_history},
1381   {"down-history",               gl_down_history},
1382   {"history-search-backward",    gl_history_search_backward},
1383   {"history-re-search-backward", gl_history_re_search_backward},
1384   {"history-search-forward",     gl_history_search_forward},
1385   {"history-re-search-forward",  gl_history_re_search_forward},
1386   {"complete-word",              gl_complete_word},
1387 #ifndef HIDE_FILE_SYSTEM
1388   {"expand-filename",            gl_expand_filename},
1389   {"read-from-file",             gl_read_from_file},
1390   {"read-init-files",            gl_read_init_files},
1391   {"list-glob",                  gl_list_glob},
1392 #endif
1393   {"del-char-or-list-or-eof",    gl_del_char_or_list_or_eof},
1394   {"beginning-of-history",       gl_beginning_of_history},
1395   {"end-of-history",             gl_end_of_history},
1396   {"digit-argument",             gl_digit_argument},
1397   {"newline",                    gl_newline},
1398   {"repeat-history",             gl_repeat_history},
1399   {"vi-insert",                  gl_vi_insert},
1400   {"vi-overwrite",               gl_vi_overwrite},
1401   {"vi-insert-at-bol",           gl_vi_insert_at_bol},
1402   {"vi-append-at-eol",           gl_vi_append_at_eol},
1403   {"vi-append",                  gl_vi_append},
1404   {"change-case",                gl_change_case},
1405   {"backward-kill-line",         gl_backward_kill_line},
1406   {"goto-column",                gl_goto_column},
1407   {"forward-to-word",            gl_forward_to_word},
1408   {"vi-replace-char",            gl_vi_replace_char},
1409   {"vi-change-rest-of-line",     gl_vi_change_rest_of_line},
1410   {"vi-change-line",             gl_vi_change_line},
1411   {"vi-change-to-bol",           gl_vi_change_to_bol},
1412   {"vi-change-refind",           gl_vi_change_refind},
1413   {"vi-change-invert-refind",    gl_vi_change_invert_refind},
1414   {"vi-change-to-column",        gl_vi_change_to_column},
1415   {"vi-change-to-parenthesis",   gl_vi_change_to_parenthesis},
1416   {"forward-copy-char",          gl_forward_copy_char},
1417   {"backward-copy-char",         gl_backward_copy_char},
1418   {"forward-find-char",          gl_forward_find_char},
1419   {"backward-find-char",         gl_backward_find_char},
1420   {"forward-to-char",            gl_forward_to_char},
1421   {"backward-to-char",           gl_backward_to_char},
1422   {"repeat-find-char",           gl_repeat_find_char},
1423   {"invert-refind-char",         gl_invert_refind_char},
1424   {"append-yank",                gl_append_yank},
1425   {"backward-copy-word",         gl_backward_copy_word},
1426   {"forward-copy-word",          gl_forward_copy_word},
1427   {"copy-to-bol",                gl_copy_to_bol},
1428   {"copy-refind",                gl_copy_refind},
1429   {"copy-invert-refind",         gl_copy_invert_refind},
1430   {"copy-to-column",             gl_copy_to_column},
1431   {"copy-to-parenthesis",        gl_copy_to_parenthesis},
1432   {"copy-rest-of-line",          gl_copy_rest_of_line},
1433   {"copy-line",                  gl_copy_line},
1434   {"backward-copy-find",         gl_backward_copy_find},
1435   {"forward-copy-find",          gl_forward_copy_find},
1436   {"backward-copy-to",           gl_backward_copy_to},
1437   {"forward-copy-to",            gl_forward_copy_to},
1438   {"list-or-eof",                gl_list_or_eof},
1439   {"vi-undo",                    gl_vi_undo},
1440   {"vi-backward-change-word",    gl_vi_backward_change_word},
1441   {"vi-forward-change-word",     gl_vi_forward_change_word},
1442   {"vi-backward-change-find",    gl_vi_backward_change_find},
1443   {"vi-forward-change-find",     gl_vi_forward_change_find},
1444   {"vi-backward-change-to",      gl_vi_backward_change_to},
1445   {"vi-forward-change-to",       gl_vi_forward_change_to},
1446   {"vi-backward-change-char",    gl_vi_backward_change_char},
1447   {"vi-forward-change-char",     gl_vi_forward_change_char},
1448   {"emacs-mode",                 gl_emacs_editing_mode},
1449   {"vi-mode",                    gl_vi_editing_mode},
1450   {"ring-bell",                  gl_ring_bell},
1451   {"vi-repeat-change",           gl_vi_repeat_change},
1452   {"find-parenthesis",           gl_find_parenthesis},
1453   {"list-history",               gl_list_history},
1454 };
1455 
1456 /*
1457  * Define the default key-bindings in emacs mode.
1458  */
1459 static const KtKeyBinding gl_emacs_bindings[] = {
1460   {"right",        "cursor-right"},
1461   {"^F",           "cursor-right"},
1462   {"left",         "cursor-left"},
1463   {"^B",           "cursor-left"},
1464   {"M-i",          "insert-mode"},
1465   {"M-I",          "insert-mode"},
1466   {"^A",           "beginning-of-line"},
1467   {"^E",           "end-of-line"},
1468   {"^U",           "delete-line"},
1469   {"^K",           "kill-line"},
1470   {"M-f",          "forward-word"},
1471   {"M-F",          "forward-word"},
1472   {"M-b",          "backward-word"},
1473   {"M-B",          "backward-word"},
1474   {"^D",           "del-char-or-list-or-eof"},
1475   {"^H",           "backward-delete-char"},
1476   {"^?",           "backward-delete-char"},
1477   {"M-d",          "forward-delete-word"},
1478   {"M-D",          "forward-delete-word"},
1479   {"M-^H",         "backward-delete-word"},
1480   {"M-^?",         "backward-delete-word"},
1481   {"M-u",          "upcase-word"},
1482   {"M-U",          "upcase-word"},
1483   {"M-l",          "downcase-word"},
1484   {"M-L",          "downcase-word"},
1485   {"M-c",          "capitalize-word"},
1486   {"M-C",          "capitalize-word"},
1487   {"^R",           "redisplay"},
1488   {"^L",           "clear-screen"},
1489   {"^T",           "transpose-chars"},
1490   {"^@",           "set-mark"},
1491   {"^X^X",         "exchange-point-and-mark"},
1492   {"^W",           "kill-region"},
1493   {"M-w",          "copy-region-as-kill"},
1494   {"M-W",          "copy-region-as-kill"},
1495   {"^Y",           "yank"},
1496   {"^P",           "up-history"},
1497   {"up",           "up-history"},
1498   {"^N",           "down-history"},
1499   {"down",         "down-history"},
1500   {"M-p",          "history-search-backward"},
1501   {"M-P",          "history-search-backward"},
1502   {"M-n",          "history-search-forward"},
1503   {"M-N",          "history-search-forward"},
1504   {"\t",           "complete-word"},
1505 #ifndef HIDE_FILE_SYSTEM
1506   {"^X*",          "expand-filename"},
1507   {"^X^F",         "read-from-file"},
1508   {"^X^R",         "read-init-files"},
1509   {"^Xg",          "list-glob"},
1510   {"^XG",          "list-glob"},
1511 #endif
1512   {"^Xh",          "list-history"},
1513   {"^XH",          "list-history"},
1514   {"M-<",          "beginning-of-history"},
1515   {"M->",          "end-of-history"},
1516   {"M-0",          "digit-argument"},
1517   {"M-1",          "digit-argument"},
1518   {"M-2",          "digit-argument"},
1519   {"M-3",          "digit-argument"},
1520   {"M-4",          "digit-argument"},
1521   {"M-5",          "digit-argument"},
1522   {"M-6",          "digit-argument"},
1523   {"M-7",          "digit-argument"},
1524   {"M-8",          "digit-argument"},
1525   {"M-9",          "digit-argument"},
1526   {"\r",           "newline"},
1527   {"\n",           "newline"},
1528   {"M-o",          "repeat-history"},
1529   {"M-C-v",        "vi-mode"},
1530 };
1531 
1532 /*
1533  * Define the default key-bindings in vi mode. Note that in vi-mode
1534  * meta-key bindings are command-mode bindings. For example M-i first
1535  * switches to command mode if not already in that mode, then moves
1536  * the cursor one position right, as in vi.
1537  */
1538 static const KtKeyBinding gl_vi_bindings[] = {
1539   {"^D",           "list-or-eof"},
1540 #ifndef HIDE_FILE_SYSTEM
1541   {"^G",           "list-glob"},
1542 #endif
1543   {"^H",           "backward-delete-char"},
1544   {"\t",           "complete-word"},
1545   {"\r",           "newline"},
1546   {"\n",           "newline"},
1547   {"^L",           "clear-screen"},
1548   {"^N",           "down-history"},
1549   {"^P",           "up-history"},
1550   {"^R",           "redisplay"},
1551   {"^U",           "backward-kill-line"},
1552   {"^W",           "backward-delete-word"},
1553 #ifndef HIDE_FILE_SYSTEM
1554   {"^X^F",         "read-from-file"},
1555   {"^X^R",         "read-init-files"},
1556   {"^X*",          "expand-filename"},
1557 #endif
1558   {"^?",           "backward-delete-char"},
1559   {"M- ",          "cursor-right"},
1560   {"M-$",          "end-of-line"},
1561 #ifndef HIDE_FILE_SYSTEM
1562   {"M-*",          "expand-filename"},
1563 #endif
1564   {"M-+",          "down-history"},
1565   {"M--",          "up-history"},
1566   {"M-<",          "beginning-of-history"},
1567   {"M->",          "end-of-history"},
1568   {"M-^",          "beginning-of-line"},
1569   {"M-;",          "repeat-find-char"},
1570   {"M-,",          "invert-refind-char"},
1571   {"M-|",          "goto-column"},
1572   {"M-~",          "change-case"},
1573   {"M-.",          "vi-repeat-change"},
1574   {"M-%",          "find-parenthesis"},
1575   {"M-0",          "digit-argument"},
1576   {"M-1",          "digit-argument"},
1577   {"M-2",          "digit-argument"},
1578   {"M-3",          "digit-argument"},
1579   {"M-4",          "digit-argument"},
1580   {"M-5",          "digit-argument"},
1581   {"M-6",          "digit-argument"},
1582   {"M-7",          "digit-argument"},
1583   {"M-8",          "digit-argument"},
1584   {"M-9",          "digit-argument"},
1585   {"M-a",          "vi-append"},
1586   {"M-A",          "vi-append-at-eol"},
1587   {"M-b",          "backward-word"},
1588   {"M-B",          "backward-word"},
1589   {"M-C",          "vi-change-rest-of-line"},
1590   {"M-cb",         "vi-backward-change-word"},
1591   {"M-cB",         "vi-backward-change-word"},
1592   {"M-cc",         "vi-change-line"},
1593   {"M-ce",         "vi-forward-change-word"},
1594   {"M-cE",         "vi-forward-change-word"},
1595   {"M-cw",         "vi-forward-change-word"},
1596   {"M-cW",         "vi-forward-change-word"},
1597   {"M-cF",         "vi-backward-change-find"},
1598   {"M-cf",         "vi-forward-change-find"},
1599   {"M-cT",         "vi-backward-change-to"},
1600   {"M-ct",         "vi-forward-change-to"},
1601   {"M-c;",         "vi-change-refind"},
1602   {"M-c,",         "vi-change-invert-refind"},
1603   {"M-ch",         "vi-backward-change-char"},
1604   {"M-c^H",        "vi-backward-change-char"},
1605   {"M-c^?",        "vi-backward-change-char"},
1606   {"M-cl",         "vi-forward-change-char"},
1607   {"M-c ",         "vi-forward-change-char"},
1608   {"M-c^",         "vi-change-to-bol"},
1609   {"M-c0",         "vi-change-to-bol"},
1610   {"M-c$",         "vi-change-rest-of-line"},
1611   {"M-c|",         "vi-change-to-column"},
1612   {"M-c%",         "vi-change-to-parenthesis"},
1613   {"M-dh",         "backward-delete-char"},
1614   {"M-d^H",        "backward-delete-char"},
1615   {"M-d^?",        "backward-delete-char"},
1616   {"M-dl",         "forward-delete-char"},
1617   {"M-d ",         "forward-delete-char"},
1618   {"M-dd",         "delete-line"},
1619   {"M-db",         "backward-delete-word"},
1620   {"M-dB",         "backward-delete-word"},
1621   {"M-de",         "forward-delete-word"},
1622   {"M-dE",         "forward-delete-word"},
1623   {"M-dw",         "forward-delete-word"},
1624   {"M-dW",         "forward-delete-word"},
1625   {"M-dF",         "backward-delete-find"},
1626   {"M-df",         "forward-delete-find"},
1627   {"M-dT",         "backward-delete-to"},
1628   {"M-dt",         "forward-delete-to"},
1629   {"M-d;",         "delete-refind"},
1630   {"M-d,",         "delete-invert-refind"},
1631   {"M-d^",         "backward-kill-line"},
1632   {"M-d0",         "backward-kill-line"},
1633   {"M-d$",         "kill-line"},
1634   {"M-D",          "kill-line"},
1635   {"M-d|",         "delete-to-column"},
1636   {"M-d%",         "delete-to-parenthesis"},
1637   {"M-e",          "forward-word"},
1638   {"M-E",          "forward-word"},
1639   {"M-f",          "forward-find-char"},
1640   {"M-F",          "backward-find-char"},
1641   {"M--",          "up-history"},
1642   {"M-h",          "cursor-left"},
1643   {"M-H",          "beginning-of-history"},
1644   {"M-i",          "vi-insert"},
1645   {"M-I",          "vi-insert-at-bol"},
1646   {"M-j",          "down-history"},
1647   {"M-J",          "history-search-forward"},
1648   {"M-k",          "up-history"},
1649   {"M-K",          "history-search-backward"},
1650   {"M-l",          "cursor-right"},
1651   {"M-L",          "end-of-history"},
1652   {"M-n",          "history-re-search-forward"},
1653   {"M-N",          "history-re-search-backward"},
1654   {"M-p",          "append-yank"},
1655   {"M-P",          "yank"},
1656   {"M-r",          "vi-replace-char"},
1657   {"M-R",          "vi-overwrite"},
1658   {"M-s",          "vi-forward-change-char"},
1659   {"M-S",          "vi-change-line"},
1660   {"M-t",          "forward-to-char"},
1661   {"M-T",          "backward-to-char"},
1662   {"M-u",          "vi-undo"},
1663   {"M-w",          "forward-to-word"},
1664   {"M-W",          "forward-to-word"},
1665   {"M-x",          "forward-delete-char"},
1666   {"M-X",          "backward-delete-char"},
1667   {"M-yh",         "backward-copy-char"},
1668   {"M-y^H",        "backward-copy-char"},
1669   {"M-y^?",        "backward-copy-char"},
1670   {"M-yl",         "forward-copy-char"},
1671   {"M-y ",         "forward-copy-char"},
1672   {"M-ye",         "forward-copy-word"},
1673   {"M-yE",         "forward-copy-word"},
1674   {"M-yw",         "forward-copy-word"},
1675   {"M-yW",         "forward-copy-word"},
1676   {"M-yb",         "backward-copy-word"},
1677   {"M-yB",         "backward-copy-word"},
1678   {"M-yf",         "forward-copy-find"},
1679   {"M-yF",         "backward-copy-find"},
1680   {"M-yt",         "forward-copy-to"},
1681   {"M-yT",         "backward-copy-to"},
1682   {"M-y;",         "copy-refind"},
1683   {"M-y,",         "copy-invert-refind"},
1684   {"M-y^",         "copy-to-bol"},
1685   {"M-y0",         "copy-to-bol"},
1686   {"M-y$",         "copy-rest-of-line"},
1687   {"M-yy",         "copy-line"},
1688   {"M-Y",          "copy-line"},
1689   {"M-y|",         "copy-to-column"},
1690   {"M-y%",         "copy-to-parenthesis"},
1691   {"M-^E",         "emacs-mode"},
1692   {"M-^H",         "cursor-left"},
1693   {"M-^?",         "cursor-left"},
1694   {"M-^L",         "clear-screen"},
1695   {"M-^N",         "down-history"},
1696   {"M-^P",         "up-history"},
1697   {"M-^R",         "redisplay"},
1698   {"M-^D",         "list-or-eof"},
1699   {"M-\r",         "newline"},
1700   {"M-\t",         "complete-word"},
1701   {"M-\n",         "newline"},
1702 #ifndef HIDE_FILE_SYSTEM
1703   {"M-^X^R",       "read-init-files"},
1704 #endif
1705   {"M-^Xh",        "list-history"},
1706   {"M-^XH",        "list-history"},
1707   {"down",         "down-history"},
1708   {"up",           "up-history"},
1709   {"left",         "cursor-left"},
1710   {"right",        "cursor-right"},
1711 };
1712 
1713 /*.......................................................................
1714  * Create a new GetLine object.
1715  *
1716  * Input:
1717  *  linelen  size_t    The maximum line length to allow for.
1718  *  histlen  size_t    The number of bytes to allocate for recording
1719  *                     a circular buffer of history lines.
1720  * Output:
1721  *  return  GetLine *  The new object, or NULL on error.
1722  */
new_GetLine(size_t linelen,size_t histlen)1723 GetLine *new_GetLine(size_t linelen, size_t histlen)
1724 {
1725   GetLine *gl;  /* The object to be returned */
1726   int i;
1727 /*
1728  * Check the arguments.
1729  */
1730   if(linelen < 10) {
1731     errno = ENOMEM;
1732     return NULL;
1733   };
1734 /*
1735  * Allocate the container.
1736  */
1737   gl = (GetLine *) malloc(sizeof(GetLine));
1738   if(!gl) {
1739     errno = ENOMEM;
1740     return NULL;
1741   };
1742 /*
1743  * Before attempting any operation that might fail, initialize the
1744  * container at least up to the point at which it can safely be passed
1745  * to del_GetLine().
1746  */
1747   gl->err = NULL;
1748   gl->glh = NULL;
1749   gl->cpl = NULL;
1750 #ifndef HIDE_FILE_SYSTEM
1751   gl->cplfn.fn = cpl_file_completions;
1752 #else
1753   gl->cplfn.fn = gl_no_completions;
1754 #endif
1755   gl->cplfn.data = NULL;
1756 #ifndef WITHOUT_FILE_SYSTEM
1757   gl->ef = NULL;
1758 #endif
1759   gl->capmem = NULL;
1760   gl->cq = NULL;
1761   gl->input_fd = -1;
1762   gl->output_fd = -1;
1763   gl->input_fp = NULL;
1764   gl->output_fp = NULL;
1765   gl->file_fp = NULL;
1766   gl->term = NULL;
1767   gl->is_term = 0;
1768   gl->flush_fn = gl_flush_terminal;
1769   gl->io_mode = GL_NORMAL_MODE;
1770   gl->raw_mode = 0;
1771   gl->pending_io = GLP_WRITE;  /* We will start by writing the prompt */
1772   gl_clear_status(gl);
1773   gl->linelen = linelen;
1774   gl->line = NULL;
1775   gl->cutbuf = NULL;
1776   gl->prompt = NULL;
1777   gl->prompt_len = 0;
1778   gl->prompt_changed = 0;
1779   gl->prompt_style = GL_LITERAL_PROMPT;
1780   gl->cpl_mem = NULL;
1781   gl->ext_act_mem = NULL;
1782   gl->sig_mem = NULL;
1783   gl->sigs = NULL;
1784   gl->signals_masked = 0;
1785   gl->signals_overriden = 0;
1786   sigemptyset(&gl->all_signal_set);
1787   sigemptyset(&gl->old_signal_set);
1788   sigemptyset(&gl->use_signal_set);
1789   gl->bindings = NULL;
1790   gl->ntotal = 0;
1791   gl->buff_curpos = 0;
1792   gl->term_curpos = 0;
1793   gl->term_len = 0;
1794   gl->buff_mark = 0;
1795   gl->insert_curpos = 0;
1796   gl->insert = 1;
1797   gl->number = -1;
1798   gl->endline = 1;
1799   gl->displayed = 0;
1800   gl->redisplay = 0;
1801   gl->postpone = 0;
1802   gl->keybuf[0]='\0';
1803   gl->nbuf = 0;
1804   gl->nread = 0;
1805   gl->current_action.fn = 0;
1806   gl->current_action.data = NULL;
1807   gl->current_count = 0;
1808   gl->preload_id = 0;
1809   gl->preload_history = 0;
1810   gl->keyseq_count = 0;
1811   gl->last_search = -1;
1812   gl->editor = GL_EMACS_MODE;
1813   gl->silence_bell = 0;
1814   gl->automatic_history = 1;
1815   gl->vi.undo.line = NULL;
1816   gl->vi.undo.buff_curpos = 0;
1817   gl->vi.undo.ntotal = 0;
1818   gl->vi.undo.saved = 0;
1819   gl->vi.repeat.action.fn = 0;
1820   gl->vi.repeat.action.data = 0;
1821   gl->vi.repeat.count = 0;
1822   gl->vi.repeat.input_curpos = 0;
1823   gl->vi.repeat.command_curpos = 0;
1824   gl->vi.repeat.input_char = '\0';
1825   gl->vi.repeat.saved = 0;
1826   gl->vi.repeat.active = 0;
1827   gl->vi.command = 0;
1828   gl->vi.find_forward = 0;
1829   gl->vi.find_onto = 0;
1830   gl->vi.find_char = '\0';
1831   gl->left = NULL;
1832   gl->right = NULL;
1833   gl->up = NULL;
1834   gl->down = NULL;
1835   gl->home = NULL;
1836   gl->bol = 0;
1837   gl->clear_eol = NULL;
1838   gl->clear_eod = NULL;
1839   gl->u_arrow = NULL;
1840   gl->d_arrow = NULL;
1841   gl->l_arrow = NULL;
1842   gl->r_arrow = NULL;
1843   gl->sound_bell = NULL;
1844   gl->bold = NULL;
1845   gl->underline = NULL;
1846   gl->standout = NULL;
1847   gl->dim = NULL;
1848   gl->reverse = NULL;
1849   gl->blink = NULL;
1850   gl->text_attr_off = NULL;
1851   gl->nline = 0;
1852   gl->ncolumn = 0;
1853 #ifdef USE_TERMINFO
1854   gl->left_n = NULL;
1855   gl->right_n = NULL;
1856 #elif defined(USE_TERMCAP)
1857   gl->tgetent_buf = NULL;
1858   gl->tgetstr_buf = NULL;
1859 #endif
1860   gl->app_file = NULL;
1861   gl->user_file = NULL;
1862   gl->configured = 0;
1863   gl->echo = 1;
1864   gl->last_signal = -1;
1865 #ifdef HAVE_SELECT
1866   gl->fd_node_mem = NULL;
1867   gl->fd_nodes = NULL;
1868   FD_ZERO(&gl->rfds);
1869   FD_ZERO(&gl->wfds);
1870   FD_ZERO(&gl->ufds);
1871   gl->max_fd = 0;
1872   gl->timer.dt.tv_sec = 0;
1873   gl->timer.dt.tv_usec = 0;
1874   gl->timer.fn = 0;
1875   gl->timer.data = NULL;
1876 #endif
1877 /*
1878  * Allocate an error reporting buffer.
1879  */
1880   gl->err = _new_ErrMsg();
1881   if(!gl->err)
1882     return del_GetLine(gl);
1883 /*
1884  * Allocate the history buffer.
1885  */
1886   gl->glh = _new_GlHistory(histlen);
1887   if(!gl->glh)
1888     return del_GetLine(gl);
1889 /*
1890  * Allocate the resource object for file-completion.
1891  */
1892   gl->cpl = new_WordCompletion();
1893   if(!gl->cpl)
1894     return del_GetLine(gl);
1895 /*
1896  * Allocate the resource object for file-completion.
1897  */
1898 #ifndef WITHOUT_FILE_SYSTEM
1899   gl->ef = new_ExpandFile();
1900   if(!gl->ef)
1901     return del_GetLine(gl);
1902 #endif
1903 /*
1904  * Allocate a string-segment memory allocator for use in storing terminal
1905  * capablity strings.
1906  */
1907   gl->capmem = _new_StringGroup(CAPMEM_SEGMENT_SIZE);
1908   if(!gl->capmem)
1909     return del_GetLine(gl);
1910 /*
1911  * Allocate the character queue that is used to buffer terminal output.
1912  */
1913   gl->cq = _new_GlCharQueue();
1914   if(!gl->cq)
1915     return del_GetLine(gl);
1916 /*
1917  * Allocate a line buffer, leaving 2 extra characters for the terminating
1918  * '\n' and '\0' characters
1919  */
1920   gl->line = (char *) malloc(linelen + 2);
1921   if(!gl->line) {
1922     errno = ENOMEM;
1923     return del_GetLine(gl);
1924   };
1925 /*
1926  * Start with an empty input line.
1927  */
1928   gl_truncate_buffer(gl, 0);
1929 /*
1930  * Allocate a cut buffer.
1931  */
1932   gl->cutbuf = (char *) malloc(linelen + 2);
1933   if(!gl->cutbuf) {
1934     errno = ENOMEM;
1935     return del_GetLine(gl);
1936   };
1937   gl->cutbuf[0] = '\0';
1938 /*
1939  * Allocate an initial empty prompt.
1940  */
1941   _gl_replace_prompt(gl, NULL);
1942   if(!gl->prompt) {
1943     errno = ENOMEM;
1944     return del_GetLine(gl);
1945   };
1946 /*
1947  * Allocate a vi undo buffer.
1948  */
1949   gl->vi.undo.line = (char *) malloc(linelen + 2);
1950   if(!gl->vi.undo.line) {
1951     errno = ENOMEM;
1952     return del_GetLine(gl);
1953   };
1954   gl->vi.undo.line[0] = '\0';
1955 /*
1956  * Allocate a freelist from which to allocate nodes for the list
1957  * of completion functions.
1958  */
1959   gl->cpl_mem = _new_FreeList(sizeof(GlCplCallback), GL_CPL_FREELIST_BLOCKING);
1960   if(!gl->cpl_mem)
1961     return del_GetLine(gl);
1962 /*
1963  * Allocate a freelist from which to allocate nodes for the list
1964  * of external action functions.
1965  */
1966   gl->ext_act_mem = _new_FreeList(sizeof(GlExternalAction),
1967 				  GL_EXT_ACT_FREELIST_BLOCKING);
1968   if(!gl->ext_act_mem)
1969     return del_GetLine(gl);
1970 /*
1971  * Allocate a freelist from which to allocate nodes for the list
1972  * of signals.
1973  */
1974   gl->sig_mem = _new_FreeList(sizeof(GlSignalNode), GLS_FREELIST_BLOCKING);
1975   if(!gl->sig_mem)
1976     return del_GetLine(gl);
1977 /*
1978  * Install initial dispositions for the default list of signals that
1979  * gl_get_line() traps.
1980  */
1981   for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
1982     const struct GlDefSignal *sig = gl_signal_list + i;
1983     if(_gl_trap_signal(gl, sig->signo, sig->flags, sig->after,
1984 		       sig->errno_value))
1985       return del_GetLine(gl);
1986   };
1987 /*
1988  * Allocate an empty table of key bindings.
1989  */
1990   gl->bindings = _new_KeyTab();
1991   if(!gl->bindings)
1992     return del_GetLine(gl);
1993 /*
1994  * Define the available actions that can be bound to key sequences.
1995  */
1996   for(i=0; i<sizeof(gl_actions)/sizeof(gl_actions[0]); i++) {
1997     if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn, NULL))
1998       return del_GetLine(gl);
1999   };
2000 /*
2001  * Set up the default bindings.
2002  */
2003   if(gl_change_editor(gl, gl->editor))
2004     return del_GetLine(gl);
2005 /*
2006  * Allocate termcap buffers.
2007  */
2008 #ifdef USE_TERMCAP
2009   gl->tgetent_buf = (char *) malloc(TERMCAP_BUF_SIZE);
2010   gl->tgetstr_buf = (char *) malloc(TERMCAP_BUF_SIZE);
2011   if(!gl->tgetent_buf || !gl->tgetstr_buf) {
2012     errno = ENOMEM;
2013     return del_GetLine(gl);
2014   };
2015 #endif
2016 /*
2017  * Set up for I/O assuming stdin and stdout.
2018  */
2019   if(_gl_change_terminal(gl, stdin, stdout, getenv("TERM")))
2020     return del_GetLine(gl);
2021 /*
2022  * Create a freelist for use in allocating GlFdNode list nodes.
2023  */
2024 #ifdef HAVE_SELECT
2025   gl->fd_node_mem = _new_FreeList(sizeof(GlFdNode), GLFD_FREELIST_BLOCKING);
2026   if(!gl->fd_node_mem)
2027     return del_GetLine(gl);
2028 #endif
2029 /*
2030  * We are done for now.
2031  */
2032   return gl;
2033 }
2034 
2035 /*.......................................................................
2036  * Delete a GetLine object.
2037  *
2038  * Input:
2039  *  gl     GetLine *  The object to be deleted.
2040  * Output:
2041  *  return GetLine *  The deleted object (always NULL).
2042  */
del_GetLine(GetLine * gl)2043 GetLine *del_GetLine(GetLine *gl)
2044 {
2045   if(gl) {
2046 /*
2047  * If the terminal is in raw server mode, reset it.
2048  */
2049     _gl_normal_io(gl);
2050 /*
2051  * Deallocate all objects contained by gl.
2052  */
2053     gl->err = _del_ErrMsg(gl->err);
2054     gl->glh = _del_GlHistory(gl->glh);
2055     gl->cpl = del_WordCompletion(gl->cpl);
2056 #ifndef WITHOUT_FILE_SYSTEM
2057     gl->ef = del_ExpandFile(gl->ef);
2058 #endif
2059     gl->capmem = _del_StringGroup(gl->capmem);
2060     gl->cq = _del_GlCharQueue(gl->cq);
2061     if(gl->file_fp)
2062       fclose(gl->file_fp);
2063     if(gl->term)
2064       free(gl->term);
2065     if(gl->line)
2066       free(gl->line);
2067     if(gl->cutbuf)
2068       free(gl->cutbuf);
2069     if(gl->prompt)
2070       free(gl->prompt);
2071     gl->cpl_mem = _del_FreeList(gl->cpl_mem, 1);
2072     gl->ext_act_mem = _del_FreeList(gl->ext_act_mem, 1);
2073     gl->sig_mem = _del_FreeList(gl->sig_mem, 1);
2074     gl->sigs = NULL;       /* Already freed by freeing sig_mem */
2075     gl->bindings = _del_KeyTab(gl->bindings);
2076     if(gl->vi.undo.line)
2077       free(gl->vi.undo.line);
2078 #ifdef USE_TERMCAP
2079     if(gl->tgetent_buf)
2080       free(gl->tgetent_buf);
2081     if(gl->tgetstr_buf)
2082       free(gl->tgetstr_buf);
2083 #endif
2084     if(gl->app_file)
2085       free(gl->app_file);
2086     if(gl->user_file)
2087       free(gl->user_file);
2088 #ifdef HAVE_SELECT
2089     gl->fd_node_mem = _del_FreeList(gl->fd_node_mem, 1);
2090     gl->fd_nodes = NULL;  /* Already freed by freeing gl->fd_node_mem */
2091 #endif
2092 /*
2093  * Delete the now empty container.
2094  */
2095     free(gl);
2096   };
2097   return NULL;
2098 }
2099 
2100 /*.......................................................................
2101  * Bind a control or meta character to an action.
2102  *
2103  * Input:
2104  *  gl         GetLine *  The resource object of this program.
2105  *  binder    KtBinder    The source of the binding.
2106  *  c             char    The control or meta character.
2107  *                        If this is '\0', the call is ignored.
2108  *  action  const char *  The action name to bind the key to.
2109  * Output:
2110  *  return         int    0 - OK.
2111  *                        1 - Error.
2112  */
gl_bind_control_char(GetLine * gl,KtBinder binder,char c,const char * action)2113 static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c,
2114 				const char *action)
2115 {
2116   char keyseq[2];
2117 /*
2118  * Quietly reject binding to the NUL control character, since this
2119  * is an ambiguous prefix of all bindings.
2120  */
2121   if(c == '\0')
2122     return 0;
2123 /*
2124  * Making sure not to bind characters which aren't either control or
2125  * meta characters.
2126  */
2127   if(IS_CTRL_CHAR(c) || IS_META_CHAR(c)) {
2128     keyseq[0] = c;
2129     keyseq[1] = '\0';
2130   } else {
2131     return 0;
2132   };
2133 /*
2134  * Install the binding.
2135  */
2136   if(_kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
2137     _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
2138     return 1;
2139   };
2140   return 0;
2141 }
2142 
2143 /*.......................................................................
2144  * Read a line from the user.
2145  *
2146  * Input:
2147  *  gl       GetLine *  A resource object returned by new_GetLine().
2148  *  prompt      char *  The prompt to prefix the line with.
2149  *  start_line  char *  The initial contents of the input line, or NULL
2150  *                      if it should start out empty.
2151  *  start_pos    int    If start_line isn't NULL, this specifies the
2152  *                      index of the character over which the cursor
2153  *                      should initially be positioned within the line.
2154  *                      If you just want it to follow the last character
2155  *                      of the line, send -1.
2156  * Output:
2157  *  return      char *  An internal buffer containing the input line, or
2158  *                      NULL at the end of input. If the line fitted in
2159  *                      the buffer there will be a '\n' newline character
2160  *                      before the terminating '\0'. If it was truncated
2161  *                      there will be no newline character, and the remains
2162  *                      of the line should be retrieved via further calls
2163  *                      to this function.
2164  */
gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2165 char *gl_get_line(GetLine *gl, const char *prompt,
2166 		  const char *start_line, int start_pos)
2167 {
2168   char *retval;   /* The return value of _gl_get_line() */
2169 /*
2170  * Check the arguments.
2171  */
2172   if(!gl) {
2173     errno = EINVAL;
2174     return NULL;
2175   };
2176 /*
2177  * Temporarily block all of the signals that we have been asked to trap.
2178  */
2179   if(gl_mask_signals(gl, &gl->old_signal_set))
2180     return NULL;
2181 /*
2182  * Perform the command-line editing task.
2183  */
2184   retval = _gl_get_line(gl, prompt, start_line, start_pos);
2185 /*
2186  * Restore the process signal mask to how it was when this function was
2187  * first called.
2188  */
2189   gl_unmask_signals(gl, &gl->old_signal_set);
2190   return retval;
2191 }
2192 
2193 
2194 /*.......................................................................
2195  * This is the main body of the public function gl_get_line().
2196  */
_gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2197 static char *_gl_get_line(GetLine *gl, const char *prompt,
2198 			  const char *start_line, int start_pos)
2199 {
2200   int waserr = 0;    /* True if an error occurs */
2201 /*
2202  * Assume that this call will successfully complete the input
2203  * line until proven otherwise.
2204  */
2205   gl_clear_status(gl);
2206 /*
2207  * If this is the first call to this function since new_GetLine(),
2208  * complete any postponed configuration.
2209  */
2210   if(!gl->configured) {
2211     (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
2212     gl->configured = 1;
2213   };
2214 /*
2215  * Before installing our signal handler functions, record the fact
2216  * that there are no pending signals.
2217  */
2218   gl_pending_signal = -1;
2219 /*
2220  * Temporarily override the signal handlers of the calling program,
2221  * so that we can intercept signals that would leave the terminal
2222  * in a bad state.
2223  */
2224   waserr = gl_override_signal_handlers(gl);
2225 /*
2226  * After recording the current terminal settings, switch the terminal
2227  * into raw input mode.
2228  */
2229   waserr = waserr || _gl_raw_io(gl, 1);
2230 /*
2231  * Attempt to read the line. This will require more than one attempt if
2232  * either a current temporary input file is opened by gl_get_input_line()
2233  * or the end of a temporary input file is reached by gl_read_stream_line().
2234  */
2235   while(!waserr) {
2236 /*
2237  * Read a line from a non-interactive stream?
2238  */
2239     if(gl->file_fp || !gl->is_term) {
2240       if(gl_read_stream_line(gl)==0) {
2241 	break;
2242       } else if(gl->file_fp) {
2243 	gl_revert_input(gl);
2244 	gl_record_status(gl, GLR_NEWLINE, 0);
2245       } else {
2246 	waserr = 1;
2247 	break;
2248       };
2249     };
2250 /*
2251  * Read from the terminal? Note that the above if() block may have
2252  * changed gl->file_fp, so it is necessary to retest it here, rather
2253  * than using an else statement.
2254  */
2255     if(!gl->file_fp && gl->is_term) {
2256       if(gl_get_input_line(gl, prompt, start_line, start_pos))
2257 	waserr = 1;
2258       else
2259 	break;
2260     };
2261   };
2262 /*
2263  * If an error occurred, but gl->rtn_status is still set to
2264  * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
2265  * leave it at whatever specific value was assigned by the function
2266  * that aborted input. This means that only functions that trap
2267  * non-generic errors have to remember to update gl->rtn_status
2268  * themselves.
2269  */
2270   if(waserr && gl->rtn_status == GLR_NEWLINE)
2271     gl_record_status(gl, GLR_ERROR, errno);
2272 /*
2273  * Restore terminal settings.
2274  */
2275   if(gl->io_mode != GL_SERVER_MODE)
2276     _gl_normal_io(gl);
2277 /*
2278  * Restore the signal handlers.
2279  */
2280   gl_restore_signal_handlers(gl);
2281 /*
2282  * If gl_get_line() gets aborted early, the errno value associated
2283  * with the event that caused this to happen is recorded in
2284  * gl->rtn_errno. Since errno may have been overwritten by cleanup
2285  * functions after this, restore its value to the value that it had
2286  * when the error condition occured, so that the caller can examine it
2287  * to find out what happened.
2288  */
2289   errno = gl->rtn_errno;
2290 /*
2291  * Check the completion status to see how to return.
2292  */
2293   switch(gl->rtn_status) {
2294   case GLR_NEWLINE:    /* Success */
2295     return gl->line;
2296   case GLR_BLOCKED:    /* These events abort the current input line, */
2297   case GLR_SIGNAL:     /*  when in normal blocking I/O mode, but only */
2298   case GLR_TIMEOUT:    /*  temporarily pause line editing when in */
2299   case GLR_FDABORT:    /*  non-blocking server I/O mode. */
2300     if(gl->io_mode != GL_SERVER_MODE)
2301       _gl_abandon_line(gl);
2302     return NULL;
2303   case GLR_ERROR:      /* Unrecoverable errors abort the input line, */
2304   case GLR_EOF:        /*  regardless of the I/O mode. */
2305   default:
2306     _gl_abandon_line(gl);
2307     return NULL;
2308   };
2309 }
2310 
2311 /*.......................................................................
2312  * Read a single character from the user.
2313  *
2314  * Input:
2315  *  gl       GetLine *  A resource object returned by new_GetLine().
2316  *  prompt      char *  The prompt to prefix the line with, or NULL if
2317  *                      no prompt is required.
2318  *  defchar     char    The character to substitute if the
2319  *                      user simply hits return, or '\n' if you don't
2320  *                      need to substitute anything.
2321  * Output:
2322  *  return       int    The character that was read, or EOF if the read
2323  *                      had to be aborted (in which case you can call
2324  *                      gl_return_status() to find out why).
2325  */
gl_query_char(GetLine * gl,const char * prompt,char defchar)2326 int gl_query_char(GetLine *gl, const char *prompt, char defchar)
2327 {
2328   int retval;   /* The return value of _gl_query_char() */
2329 /*
2330  * Check the arguments.
2331  */
2332   if(!gl) {
2333     errno = EINVAL;
2334     return EOF;
2335   };
2336 /*
2337  * Temporarily block all of the signals that we have been asked to trap.
2338  */
2339   if(gl_mask_signals(gl, &gl->old_signal_set))
2340     return EOF;
2341 /*
2342  * Perform the character reading task.
2343  */
2344   retval = _gl_query_char(gl, prompt, defchar);
2345 /*
2346  * Restore the process signal mask to how it was when this function was
2347  * first called.
2348  */
2349   gl_unmask_signals(gl, &gl->old_signal_set);
2350   return retval;
2351 }
2352 
2353 /*.......................................................................
2354  * This is the main body of the public function gl_query_char().
2355  */
_gl_query_char(GetLine * gl,const char * prompt,char defchar)2356 static int _gl_query_char(GetLine *gl, const char *prompt, char defchar)
2357 {
2358   int c = EOF;       /* The character to be returned */
2359   int waserr = 0;    /* True if an error occurs */
2360 /*
2361  * Assume that this call will successfully complete the input operation
2362  * until proven otherwise.
2363  */
2364   gl_clear_status(gl);
2365 /*
2366  * If this is the first call to this function or gl_get_line(),
2367  * since new_GetLine(), complete any postponed configuration.
2368  */
2369   if(!gl->configured) {
2370     (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
2371     gl->configured = 1;
2372   };
2373 /*
2374  * Before installing our signal handler functions, record the fact
2375  * that there are no pending signals.
2376  */
2377   gl_pending_signal = -1;
2378 /*
2379  * Temporarily override the signal handlers of the calling program,
2380  * so that we can intercept signals that would leave the terminal
2381  * in a bad state.
2382  */
2383   waserr = gl_override_signal_handlers(gl);
2384 /*
2385  * After recording the current terminal settings, switch the terminal
2386  * into raw input mode without redisplaying any partially entered
2387  * input line.
2388  */
2389   waserr = waserr || _gl_raw_io(gl, 0);
2390 /*
2391  * Attempt to read the line. This will require more than one attempt if
2392  * either a current temporary input file is opened by gl_get_input_line()
2393  * or the end of a temporary input file is reached by gl_read_stream_line().
2394  */
2395   while(!waserr) {
2396 /*
2397  * Read a line from a non-interactive stream?
2398  */
2399     if(gl->file_fp || !gl->is_term) {
2400       c = gl_read_stream_char(gl);
2401       if(c != EOF) {            /* Success? */
2402 	if(c=='\n') c = defchar;
2403 	break;
2404       } else if(gl->file_fp) {  /* End of temporary input file? */
2405 	gl_revert_input(gl);
2406 	gl_record_status(gl, GLR_NEWLINE, 0);
2407       } else {                  /* An error? */
2408 	waserr = 1;
2409 	break;
2410       };
2411     };
2412 /*
2413  * Read from the terminal? Note that the above if() block may have
2414  * changed gl->file_fp, so it is necessary to retest it here, rather
2415  * than using an else statement.
2416  */
2417     if(!gl->file_fp && gl->is_term) {
2418       c = gl_get_query_char(gl, prompt, defchar);
2419       if(c==EOF)
2420 	waserr = 1;
2421       else
2422 	break;
2423     };
2424   };
2425 /*
2426  * If an error occurred, but gl->rtn_status is still set to
2427  * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
2428  * leave it at whatever specific value was assigned by the function
2429  * that aborted input. This means that only functions that trap
2430  * non-generic errors have to remember to update gl->rtn_status
2431  * themselves.
2432  */
2433   if(waserr && gl->rtn_status == GLR_NEWLINE)
2434     gl_record_status(gl, GLR_ERROR, errno);
2435 /*
2436  * Restore terminal settings.
2437  */
2438   if(gl->io_mode != GL_SERVER_MODE)
2439     _gl_normal_io(gl);
2440 /*
2441  * Restore the signal handlers.
2442  */
2443   gl_restore_signal_handlers(gl);
2444 /*
2445  * If this function gets aborted early, the errno value associated
2446  * with the event that caused this to happen is recorded in
2447  * gl->rtn_errno. Since errno may have been overwritten by cleanup
2448  * functions after this, restore its value to the value that it had
2449  * when the error condition occured, so that the caller can examine it
2450  * to find out what happened.
2451  */
2452   errno = gl->rtn_errno;
2453 /*
2454  * Error conditions are signalled to the caller, by setting the returned
2455  * character to EOF.
2456  */
2457   if(gl->rtn_status != GLR_NEWLINE)
2458     c = EOF;
2459 /*
2460  * In this mode, every character that is read is a completed
2461  * transaction, just like reading a completed input line, so prepare
2462  * for the next input line or character.
2463  */
2464   _gl_abandon_line(gl);
2465 /*
2466  * Return the acquired character.
2467  */
2468   return c;
2469 }
2470 
2471 /*.......................................................................
2472  * Record of the signal handlers of the calling program, so that they
2473  * can be restored later.
2474  *
2475  * Input:
2476  *  gl    GetLine *   The resource object of this library.
2477  * Output:
2478  *  return    int     0 - OK.
2479  *                    1 - Error.
2480  */
gl_override_signal_handlers(GetLine * gl)2481 static int gl_override_signal_handlers(GetLine *gl)
2482 {
2483   GlSignalNode *sig;   /* A node in the list of signals to be caught */
2484 /*
2485  * Set up our signal handler.
2486  */
2487   SigAction act;
2488   act.sa_handler = gl_signal_handler;
2489   memcpy(&act.sa_mask, &gl->all_signal_set, sizeof(sigset_t));
2490   act.sa_flags = 0;
2491 /*
2492  * Get the subset of the signals that we are supposed to trap that
2493  * should actually be trapped.
2494  */
2495   sigemptyset(&gl->use_signal_set);
2496   for(sig=gl->sigs; sig; sig=sig->next) {
2497 /*
2498  * Trap this signal? If it is blocked by the calling program and we
2499  * haven't been told to unblock it, don't arrange to trap this signal.
2500  */
2501     if(sig->flags & GLS_UNBLOCK_SIG ||
2502        !sigismember(&gl->old_signal_set, sig->signo)) {
2503       if(sigaddset(&gl->use_signal_set, sig->signo) == -1) {
2504 	_err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
2505 	return 1;
2506       };
2507     };
2508   };
2509 /*
2510  * Override the actions of the signals that we are trapping.
2511  */
2512   for(sig=gl->sigs; sig; sig=sig->next) {
2513     if(sigismember(&gl->use_signal_set, sig->signo)) {
2514       sigdelset(&act.sa_mask, sig->signo);
2515       if(sigaction(sig->signo, &act, &sig->original)) {
2516 	_err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
2517 	return 1;
2518       };
2519       sigaddset(&act.sa_mask, sig->signo);
2520     };
2521   };
2522 /*
2523  * Record the fact that the application's signal handlers have now
2524  * been overriden.
2525  */
2526   gl->signals_overriden = 1;
2527 /*
2528  * Just in case a SIGWINCH signal was sent to the process while our
2529  * SIGWINCH signal handler wasn't in place, check to see if the terminal
2530  * size needs updating.
2531  */
2532   if(_gl_update_size(gl))
2533     return 1;
2534   return 0;
2535 }
2536 
2537 /*.......................................................................
2538  * Restore the signal handlers of the calling program.
2539  *
2540  * Input:
2541  *  gl     GetLine *  The resource object of this library.
2542  * Output:
2543  *  return     int    0 - OK.
2544  *                    1 - Error.
2545  */
gl_restore_signal_handlers(GetLine * gl)2546 static int gl_restore_signal_handlers(GetLine *gl)
2547 {
2548   GlSignalNode *sig;   /* A node in the list of signals to be caught */
2549 /*
2550  * Restore application signal handlers that were overriden
2551  * by gl_override_signal_handlers().
2552  */
2553   for(sig=gl->sigs; sig; sig=sig->next) {
2554     if(sigismember(&gl->use_signal_set, sig->signo) &&
2555        sigaction(sig->signo, &sig->original, NULL)) {
2556       _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
2557       return 1;
2558     };
2559   };
2560 /*
2561  * Record the fact that the application's signal handlers have now
2562  * been restored.
2563  */
2564   gl->signals_overriden = 0;
2565   return 0;
2566 }
2567 
2568 /*.......................................................................
2569  * This signal handler simply records the fact that a given signal was
2570  * caught in the file-scope gl_pending_signal variable.
2571  */
gl_signal_handler(int signo)2572 static void gl_signal_handler(int signo)
2573 {
2574   gl_pending_signal = signo;
2575   siglongjmp(gl_setjmp_buffer, 1);
2576 }
2577 
2578 /*.......................................................................
2579  * Switch the terminal into raw mode after storing the previous terminal
2580  * settings in gl->attributes.
2581  *
2582  * Input:
2583  *  gl     GetLine *   The resource object of this program.
2584  * Output:
2585  *  return     int     0 - OK.
2586  *                     1 - Error.
2587  */
gl_raw_terminal_mode(GetLine * gl)2588 static int gl_raw_terminal_mode(GetLine *gl)
2589 {
2590   Termios newattr;   /* The new terminal attributes */
2591 /*
2592  * If the terminal is already in raw mode, do nothing.
2593  */
2594   if(gl->raw_mode)
2595     return 0;
2596 /*
2597  * Record the current terminal attributes.
2598  */
2599   if(tcgetattr(gl->input_fd, &gl->oldattr)) {
2600     _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
2601     return 1;
2602   };
2603 /*
2604  * This function shouldn't do anything but record the current terminal
2605  * attritubes if editing has been disabled.
2606  */
2607   if(gl->editor == GL_NO_EDITOR)
2608     return 0;
2609 /*
2610  * Modify the existing attributes.
2611  */
2612   newattr = gl->oldattr;
2613 /*
2614  * Turn off local echo, canonical input mode and extended input processing.
2615  */
2616   newattr.c_lflag &= ~(ECHO | ICANON | IEXTEN);
2617 /*
2618  * Don't translate carriage return to newline, turn off input parity
2619  * checking, don't strip off 8th bit, turn off output flow control.
2620  */
2621   newattr.c_iflag &= ~(ICRNL | INPCK | ISTRIP);
2622 /*
2623  * Clear size bits, turn off parity checking, and allow 8-bit characters.
2624  */
2625   newattr.c_cflag &= ~(CSIZE | PARENB);
2626   newattr.c_cflag |= CS8;
2627 /*
2628  * Turn off output processing.
2629  */
2630   newattr.c_oflag &= ~(OPOST);
2631 /*
2632  * Request one byte at a time, without waiting.
2633  */
2634   newattr.c_cc[VMIN] = gl->io_mode==GL_SERVER_MODE ? 0:1;
2635   newattr.c_cc[VTIME] = 0;
2636 /*
2637  * Install the new terminal modes.
2638  */
2639   while(tcsetattr(gl->input_fd, TCSADRAIN, &newattr)) {
2640     if(errno != EINTR) {
2641       _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
2642       return 1;
2643     };
2644   };
2645 /*
2646  * Record the new terminal mode.
2647  */
2648   gl->raw_mode = 1;
2649   return 0;
2650 }
2651 
2652 /*.......................................................................
2653  * Restore the terminal attributes recorded in gl->oldattr.
2654  *
2655  * Input:
2656  *  gl     GetLine *   The resource object of this library.
2657  * Output:
2658  *  return     int     0 - OK.
2659  *                     1 - Error.
2660  */
gl_restore_terminal_attributes(GetLine * gl)2661 static int gl_restore_terminal_attributes(GetLine *gl)
2662 {
2663   int waserr = 0;
2664 /*
2665  * If not in raw mode, do nothing.
2666  */
2667   if(!gl->raw_mode)
2668     return 0;
2669 /*
2670  * Before changing the terminal attributes, make sure that all output
2671  * has been passed to the terminal.
2672  */
2673   if(gl_flush_output(gl))
2674     waserr = 1;
2675 /*
2676  * Reset the terminal attributes to the values that they had on
2677  * entry to gl_get_line().
2678  */
2679   while(tcsetattr(gl->input_fd, TCSADRAIN, &gl->oldattr)) {
2680     if(errno != EINTR) {
2681       _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
2682       waserr = 1;
2683       break;
2684     };
2685   };
2686 /*
2687  * Record the new terminal mode.
2688  */
2689   gl->raw_mode = 0;
2690   return waserr;
2691 }
2692 
2693 /*.......................................................................
2694  * Switch the terminal file descriptor to use non-blocking I/O.
2695  *
2696  * Input:
2697  *  gl         GetLine *  The resource object of gl_get_line().
2698  *  fd             int    The file descriptor to make non-blocking.
2699  */
gl_nonblocking_io(GetLine * gl,int fd)2700 static int gl_nonblocking_io(GetLine *gl, int fd)
2701 {
2702   int fcntl_flags;   /* The new file-descriptor control flags */
2703 /*
2704  * Is non-blocking I/O supported on this system?  Note that even
2705  * without non-blocking I/O, the terminal will probably still act as
2706  * though it was non-blocking, because we also set the terminal
2707  * attributes to return immediately if no input is available and we
2708  * use select() to wait to be able to write. If select() also isn't
2709  * available, then input will probably remain fine, but output could
2710  * block, depending on the behaviour of the terminal driver.
2711  */
2712 #if defined(NON_BLOCKING_FLAG)
2713 /*
2714  * Query the current file-control flags, and add the
2715  * non-blocking I/O flag.
2716  */
2717   fcntl_flags = fcntl(fd, F_GETFL) | NON_BLOCKING_FLAG;
2718 /*
2719  * Install the new control flags.
2720  */
2721   if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
2722     _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
2723     return 1;
2724   };
2725 #endif
2726   return 0;
2727 }
2728 
2729 /*.......................................................................
2730  * Switch to blocking terminal I/O.
2731  *
2732  * Input:
2733  *  gl         GetLine *  The resource object of gl_get_line().
2734  *  fd             int    The file descriptor to make blocking.
2735  */
gl_blocking_io(GetLine * gl,int fd)2736 static int gl_blocking_io(GetLine *gl, int fd)
2737 {
2738   int fcntl_flags;   /* The new file-descriptor control flags */
2739 /*
2740  * Is non-blocking I/O implemented on this system?
2741  */
2742 #if defined(NON_BLOCKING_FLAG)
2743 /*
2744  * Query the current file control flags and remove the non-blocking
2745  * I/O flag.
2746  */
2747   fcntl_flags = fcntl(fd, F_GETFL) & ~NON_BLOCKING_FLAG;
2748 /*
2749  * Install the modified control flags.
2750  */
2751   if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
2752     _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
2753     return 1;
2754   };
2755 #endif
2756   return 0;
2757 }
2758 
2759 /*.......................................................................
2760  * Read a new input line from the user.
2761  *
2762  * Input:
2763  *  gl         GetLine *  The resource object of this library.
2764  *  prompt        char *  The prompt to prefix the line with, or NULL to
2765  *                        use the same prompt that was used by the previous
2766  *                        line.
2767  *  start_line    char *  The initial contents of the input line, or NULL
2768  *                        if it should start out empty.
2769  *  start_pos      int    If start_line isn't NULL, this specifies the
2770  *                        index of the character over which the cursor
2771  *                        should initially be positioned within the line.
2772  *                        If you just want it to follow the last character
2773  *                        of the line, send -1.
2774  * Output:
2775  *  return    int    0 - OK.
2776  *                   1 - Error.
2777  */
gl_get_input_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2778 static int gl_get_input_line(GetLine *gl, const char *prompt,
2779 			     const char *start_line, int start_pos)
2780 {
2781   char c;               /* The character being read */
2782 /*
2783  * Flush any pending output to the terminal.
2784  */
2785   if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
2786     return 1;
2787 /*
2788  * Are we starting a new line?
2789  */
2790   if(gl->endline) {
2791 /*
2792  * Delete any incompletely enterred line.
2793  */
2794     if(gl_erase_line(gl))
2795       return 1;
2796 /*
2797  * Display the new line to be edited.
2798  */
2799     if(gl_present_line(gl, prompt, start_line, start_pos))
2800       return 1;
2801   };
2802 /*
2803  * Read one character at a time.
2804  */
2805   while(gl_read_terminal(gl, 1, &c) == 0) {
2806 /*
2807  * Increment the count of the number of key sequences entered.
2808  */
2809     gl->keyseq_count++;
2810 /*
2811  * Interpret the character either as the start of a new key-sequence,
2812  * as a continuation of a repeat count, or as a printable character
2813  * to be added to the line.
2814  */
2815     if(gl_interpret_char(gl, c))
2816       break;
2817 /*
2818  * If we just ran an action function which temporarily asked for
2819  * input to be taken from a file, abort this call.
2820  */
2821     if(gl->file_fp)
2822       return 0;
2823 /*
2824  * Has the line been completed?
2825  */
2826     if(gl->endline)
2827       return gl_line_ended(gl, c);
2828   };
2829 /*
2830  * To get here, gl_read_terminal() must have returned non-zero. See
2831  * whether a signal was caught that requested that the current line
2832  * be returned.
2833  */
2834   if(gl->endline)
2835     return gl_line_ended(gl, '\n');
2836 /*
2837  * If I/O blocked while attempting to get the latest character
2838  * of the key sequence, rewind the key buffer to allow interpretation of
2839  * the current key sequence to be restarted on the next call to this
2840  * function.
2841  */
2842   if(gl->rtn_status == GLR_BLOCKED && gl->pending_io == GLP_READ)
2843     gl->nread = 0;
2844   return 1;
2845 }
2846 
2847 /*.......................................................................
2848  * This is the private function of gl_query_char() that handles
2849  * prompting the user, reading a character from the terminal, and
2850  * displaying what the user entered.
2851  *
2852  * Input:
2853  *  gl         GetLine *  The resource object of this library.
2854  *  prompt        char *  The prompt to prefix the line with.
2855  *  defchar       char    The character to substitute if the
2856  *                        user simply hits return, or '\n' if you don't
2857  *                        need to substitute anything.
2858  * Output:
2859  *  return         int    The character that was read, or EOF if something
2860  *                        prevented a character from being read.
2861  */
gl_get_query_char(GetLine * gl,const char * prompt,int defchar)2862 static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar)
2863 {
2864   char c;               /* The character being read */
2865   int retval;           /* The return value of this function */
2866 /*
2867  * Flush any pending output to the terminal.
2868  */
2869   if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
2870     return EOF;
2871 /*
2872  * Delete any incompletely entered line.
2873  */
2874   if(gl_erase_line(gl))
2875     return EOF;
2876 /*
2877  * Reset the line input parameters and display the prompt, if any.
2878  */
2879   if(gl_present_line(gl, prompt, NULL, 0))
2880     return EOF;
2881 /*
2882  * Read one character.
2883  */
2884   if(gl_read_terminal(gl, 1, &c) == 0) {
2885 /*
2886  * In this mode, count each character as being a new key-sequence.
2887  */
2888     gl->keyseq_count++;
2889 /*
2890  * Delete the character that was read, from the key-press buffer.
2891  */
2892     gl_discard_chars(gl, gl->nread);
2893 /*
2894  * Convert carriage returns to newlines.
2895  */
2896     if(c == '\r')
2897       c = '\n';
2898 /*
2899  * If the user just hit return, subsitute the default character.
2900  */
2901     if(c == '\n')
2902       c = defchar;
2903 /*
2904  * Display the entered character to the right of the prompt.
2905  */
2906     if(c!='\n') {
2907       if(gl_end_of_line(gl, 1, NULL)==0)
2908 	gl_print_char(gl, c, ' ');
2909     };
2910 /*
2911  * Record the return character, and mark the call as successful.
2912  */
2913     retval = c;
2914     gl_record_status(gl, GLR_NEWLINE, 0);
2915 /*
2916  * Was a signal caught whose disposition is to cause the current input
2917  * line to be returned? If so return a newline character.
2918  */
2919   } else if(gl->endline) {
2920     retval = '\n';
2921     gl_record_status(gl, GLR_NEWLINE, 0);
2922   } else {
2923     retval = EOF;
2924   };
2925 /*
2926  * Start a new line.
2927  */
2928   if(gl_start_newline(gl, 1))
2929     return EOF;
2930 /*
2931  * Attempt to flush any pending output.
2932  */
2933   (void) gl_flush_output(gl);
2934 /*
2935  * Return either the character that was read, or EOF if an error occurred.
2936  */
2937   return retval;
2938 }
2939 
2940 /*.......................................................................
2941  * Add a character to the line buffer at the current cursor position,
2942  * inserting or overwriting according the current mode.
2943  *
2944  * Input:
2945  *  gl   GetLine *   The resource object of this library.
2946  *  c       char     The character to be added.
2947  * Output:
2948  *  return   int     0 - OK.
2949  *                   1 - Insufficient room.
2950  */
gl_add_char_to_line(GetLine * gl,char c)2951 static int gl_add_char_to_line(GetLine *gl, char c)
2952 {
2953 /*
2954  * Keep a record of the current cursor position.
2955  */
2956   int buff_curpos = gl->buff_curpos;
2957   int term_curpos = gl->term_curpos;
2958 /*
2959  * Work out the displayed width of the new character.
2960  */
2961   int width = gl_displayed_char_width(gl, c, term_curpos);
2962 /*
2963  * If we are in insert mode, or at the end of the line,
2964  * check that we can accomodate a new character in the buffer.
2965  * If not, simply return, leaving it up to the calling program
2966  * to check for the absence of a newline character.
2967  */
2968   if((gl->insert || buff_curpos >= gl->ntotal) && gl->ntotal >= gl->linelen)
2969     return 0;
2970 /*
2971  * Are we adding characters to the line (ie. inserting or appending)?
2972  */
2973   if(gl->insert || buff_curpos >= gl->ntotal) {
2974 /*
2975  * If inserting, make room for the new character.
2976  */
2977     if(buff_curpos < gl->ntotal)
2978       gl_make_gap_in_buffer(gl, buff_curpos, 1);
2979 /*
2980  * Copy the character into the buffer.
2981  */
2982     gl_buffer_char(gl, c, buff_curpos);
2983     gl->buff_curpos++;
2984 /*
2985  * Redraw the line from the cursor position to the end of the line,
2986  * and move the cursor to just after the added character.
2987  */
2988     if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
2989        gl_set_term_curpos(gl, term_curpos + width))
2990       return 1;
2991 /*
2992  * Are we overwriting an existing character?
2993  */
2994   } else {
2995 /*
2996  * Get the width of the character being overwritten.
2997  */
2998     int old_width = gl_displayed_char_width(gl, gl->line[buff_curpos],
2999 					    term_curpos);
3000 /*
3001  * Overwrite the character in the buffer.
3002  */
3003     gl_buffer_char(gl, c, buff_curpos);
3004 /*
3005  * If we are replacing with a narrower character, we need to
3006  * redraw the terminal string to the end of the line, then
3007  * overwrite the trailing old_width - width characters
3008  * with spaces.
3009  */
3010     if(old_width > width) {
3011       if(gl_print_string(gl, gl->line + buff_curpos, '\0'))
3012 	return 1;
3013 /*
3014  * Clear to the end of the terminal.
3015  */
3016       if(gl_truncate_display(gl))
3017 	return 1;
3018 /*
3019  * Move the cursor to the end of the new character.
3020  */
3021       if(gl_set_term_curpos(gl, term_curpos + width))
3022 	return 1;
3023       gl->buff_curpos++;
3024 /*
3025  * If we are replacing with a wider character, then we will be
3026  * inserting new characters, and thus extending the line.
3027  */
3028     } else if(width > old_width) {
3029 /*
3030  * Redraw the line from the cursor position to the end of the line,
3031  * and move the cursor to just after the added character.
3032  */
3033       if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
3034 	 gl_set_term_curpos(gl, term_curpos + width))
3035 	return 1;
3036       gl->buff_curpos++;
3037 /*
3038  * The original and replacement characters have the same width,
3039  * so simply overwrite.
3040  */
3041     } else {
3042 /*
3043  * Copy the character into the buffer.
3044  */
3045       gl_buffer_char(gl, c, buff_curpos);
3046       gl->buff_curpos++;
3047 /*
3048  * Overwrite the original character.
3049  */
3050       if(gl_print_char(gl, c, gl->line[gl->buff_curpos]))
3051 	return 1;
3052     };
3053   };
3054   return 0;
3055 }
3056 
3057 /*.......................................................................
3058  * Insert/append a string to the line buffer and terminal at the current
3059  * cursor position.
3060  *
3061  * Input:
3062  *  gl   GetLine *   The resource object of this library.
3063  *  s       char *   The string to be added.
3064  * Output:
3065  *  return   int     0 - OK.
3066  *                   1 - Insufficient room.
3067  */
gl_add_string_to_line(GetLine * gl,const char * s)3068 static int gl_add_string_to_line(GetLine *gl, const char *s)
3069 {
3070   int buff_slen;   /* The length of the string being added to line[] */
3071   int term_slen;   /* The length of the string being written to the terminal */
3072   int buff_curpos; /* The original value of gl->buff_curpos */
3073   int term_curpos; /* The original value of gl->term_curpos */
3074 /*
3075  * Keep a record of the current cursor position.
3076  */
3077   buff_curpos = gl->buff_curpos;
3078   term_curpos = gl->term_curpos;
3079 /*
3080  * How long is the string to be added?
3081  */
3082   buff_slen = strlen(s);
3083   term_slen = gl_displayed_string_width(gl, s, buff_slen, term_curpos);
3084 /*
3085  * Check that we can accomodate the string in the buffer.
3086  * If not, simply return, leaving it up to the calling program
3087  * to check for the absence of a newline character.
3088  */
3089   if(gl->ntotal + buff_slen > gl->linelen)
3090     return 0;
3091 /*
3092  * Move the characters that follow the cursor in the buffer by
3093  * buff_slen characters to the right.
3094  */
3095   if(gl->ntotal > gl->buff_curpos)
3096     gl_make_gap_in_buffer(gl, gl->buff_curpos, buff_slen);
3097 /*
3098  * Copy the string into the buffer.
3099  */
3100   gl_buffer_string(gl, s, buff_slen, gl->buff_curpos);
3101   gl->buff_curpos += buff_slen;
3102 /*
3103  * Write the modified part of the line to the terminal, then move
3104  * the terminal cursor to the end of the displayed input string.
3105  */
3106   if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
3107      gl_set_term_curpos(gl, term_curpos + term_slen))
3108     return 1;
3109   return 0;
3110 }
3111 
3112 /*.......................................................................
3113  * Read a single character from the terminal.
3114  *
3115  * Input:
3116  *  gl    GetLine *   The resource object of this library.
3117  *  keep      int     If true, the returned character will be kept in
3118  *                    the input buffer, for potential replays. It should
3119  *                    subsequently be removed from the buffer when the
3120  *                    key sequence that it belongs to has been fully
3121  *                    processed, by calling gl_discard_chars().
3122  * Input/Output:
3123  *  c        char *   The character that is read, is assigned to *c.
3124  * Output:
3125  *  return    int     0 - OK.
3126  *                    1 - Either an I/O error occurred, or a signal was
3127  *                        caught who's disposition is to abort gl_get_line()
3128  *                        or to have gl_get_line() return the current line
3129  *                        as though the user had pressed return. In the
3130  *                        latter case gl->endline will be non-zero.
3131  */
gl_read_terminal(GetLine * gl,int keep,char * c)3132 static int gl_read_terminal(GetLine *gl, int keep, char *c)
3133 {
3134 /*
3135  * Before waiting for a new character to be input, flush unwritten
3136  * characters to the terminal.
3137  */
3138   if(gl_flush_output(gl))
3139     return 1;
3140 /*
3141  * Record the fact that we are about to read from the terminal.
3142  */
3143   gl->pending_io = GLP_READ;
3144 /*
3145  * If there is already an unread character in the buffer,
3146  * return it.
3147  */
3148   if(gl->nread < gl->nbuf) {
3149     *c = gl->keybuf[gl->nread];
3150 /*
3151  * Retain the character in the key buffer, but mark it as having been read?
3152  */
3153     if(keep) {
3154       gl->nread++;
3155 /*
3156  * Completely remove the character from the key buffer?
3157  */
3158     } else {
3159       memmove(gl->keybuf + gl->nread, gl->keybuf + gl->nread + 1,
3160 	      gl->nbuf - gl->nread - 1);
3161     };
3162     return 0;
3163   };
3164 /*
3165  * Make sure that there is space in the key buffer for one more character.
3166  * This should always be true if gl_interpret_char() is called for each
3167  * new character added, since it will clear the buffer once it has recognized
3168  * or rejected a key sequence.
3169  */
3170   if(gl->nbuf + 1 > GL_KEY_MAX) {
3171     gl_print_info(gl, "gl_read_terminal: Buffer overflow avoided.",
3172 		  GL_END_INFO);
3173     errno = EIO;
3174     return 1;
3175   };
3176 /*
3177  * Read one character from the terminal.
3178  */
3179   switch(gl_read_input(gl, c)) {
3180   case GL_READ_OK:
3181     break;
3182   case GL_READ_BLOCKED:
3183     gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
3184     return 1;
3185     break;
3186   default:
3187     return 1;
3188     break;
3189   };
3190 /*
3191  * Append the character to the key buffer?
3192  */
3193   if(keep) {
3194     gl->keybuf[gl->nbuf] = *c;
3195     gl->nread = ++gl->nbuf;
3196   };
3197   return 0;
3198 }
3199 
3200 /*.......................................................................
3201  * Read one or more keypresses from the terminal of an input stream.
3202  *
3203  * Input:
3204  *  gl           GetLine *  The resource object of this module.
3205  *  c               char *  The character that was read is assigned to *c.
3206  * Output:
3207  *  return  GlReadStatus    The completion status of the read operation.
3208  */
gl_read_input(GetLine * gl,char * c)3209 static GlReadStatus gl_read_input(GetLine *gl, char *c)
3210 {
3211 /*
3212  * We may have to repeat the read if window change signals are received.
3213  */
3214   for(;;) {
3215 /*
3216  * Which file descriptor should we read from? Mark this volatile, so
3217  * that siglongjmp() can't clobber it.
3218  */
3219     volatile int fd = gl->file_fp ? fileno(gl->file_fp) : gl->input_fd;
3220 /*
3221  * If the endline flag becomes set, don't wait for another character.
3222  */
3223     if(gl->endline)
3224       return GL_READ_ERROR;
3225 /*
3226  * Since the code in this function can block, trap signals.
3227  */
3228     if(sigsetjmp(gl_setjmp_buffer, 1)==0) {
3229 /*
3230  * Handle the different I/O modes.
3231  */
3232       switch(gl->io_mode) {
3233 /*
3234  * In normal I/O mode, we call the event handler before attempting
3235  * to read, since read() blocks.
3236  */
3237       case GL_NORMAL_MODE:
3238 	if(gl_event_handler(gl, fd))
3239 	  return GL_READ_ERROR;
3240 	return gl_read_unmasked(gl, fd, c);  /* Read one character */
3241 	break;
3242 /*
3243  * In non-blocking server I/O mode, we attempt to read a character,
3244  * and only if this fails, call the event handler to wait for a any
3245  * user-configured timeout and any other user-configured events.  In
3246  * addition, we turn off the fcntl() non-blocking flag when reading
3247  * from the terminal, to work around a bug in Solaris. We can do this
3248  * without causing the read() to block, because when in non-blocking
3249  * server-I/O mode, gl_raw_io() sets the VMIN terminal attribute to 0,
3250  * which tells the terminal driver to return immediately if no
3251  * characters are available to be read.
3252  */
3253       case GL_SERVER_MODE:
3254 	{
3255 	  GlReadStatus status;        /* The return status */
3256 	  if(isatty(fd))              /* If we reading from a terminal, */
3257 	     gl_blocking_io(gl, fd);  /* switch to blocking I/O */
3258 	  status = gl_read_unmasked(gl, fd, c); /* Try reading */
3259 	  if(status == GL_READ_BLOCKED) {       /* Nothing readable yet */
3260 	    if(gl_event_handler(gl, fd))        /* Wait for input */
3261 	      status = GL_READ_ERROR;
3262 	    else
3263 	      status = gl_read_unmasked(gl, fd, c); /* Try reading again */
3264 	  };
3265 	  gl_nonblocking_io(gl, fd); /* Restore non-blocking I/O */
3266 	  return status;
3267 	};
3268 	break;
3269       };
3270     };
3271 /*
3272  * To get here, one of the signals that we are trapping must have
3273  * been received. Note that by using sigsetjmp() instead of setjmp()
3274  * the signal mask that was blocking these signals will have been
3275  * reinstated, so we can be sure that no more of these signals will
3276  * be received until we explicitly unblock them again.
3277  *
3278  * First, if non-blocking I/O was temporarily disabled, reinstate it.
3279  */
3280     if(gl->io_mode == GL_SERVER_MODE)
3281       gl_nonblocking_io(gl, fd);
3282 /*
3283  * Now respond to the signal that was caught.
3284  */
3285     if(gl_check_caught_signal(gl))
3286       return GL_READ_ERROR;
3287   };
3288 }
3289 
3290 /*.......................................................................
3291  * This is a private function of gl_read_input(), which unblocks signals
3292  * temporarily while it reads a single character from the specified file
3293  * descriptor.
3294  *
3295  * Input:
3296  *  gl          GetLine *  The resource object of this module.
3297  *  fd              int    The file descriptor to read from.
3298  *  c              char *  The character that was read is assigned to *c.
3299  * Output:
3300  *  return GlReadStatus    The completion status of the read.
3301  */
gl_read_unmasked(GetLine * gl,int fd,char * c)3302 static int gl_read_unmasked(GetLine *gl, int fd, char *c)
3303 {
3304   int nread;  /* The return value of read() */
3305 /*
3306  * Unblock the signals that we are trapping, while waiting for I/O.
3307  */
3308   gl_catch_signals(gl);
3309 /*
3310  * Attempt to read one character from the terminal, restarting the read
3311  * if any signals that we aren't trapping, are received.
3312  */
3313   do {
3314     errno = 0;
3315     nread = read(fd, c, 1);
3316   } while(nread < 0 && errno==EINTR);
3317 /*
3318  * Block all of the signals that we are trapping.
3319  */
3320   gl_mask_signals(gl, NULL);
3321 /*
3322  * Check the completion status of the read.
3323  */
3324   switch(nread) {
3325   case 1:
3326     return GL_READ_OK;
3327   case 0:
3328     return (isatty(fd) || errno != 0) ? GL_READ_BLOCKED : GL_READ_EOF;
3329   default:
3330     return GL_READ_ERROR;
3331   };
3332 }
3333 
3334 /*.......................................................................
3335  * Remove a specified number of characters from the start of the
3336  * key-press lookahead buffer, gl->keybuf[], and arrange for the next
3337  * read to start from the character at the start of the shifted buffer.
3338  *
3339  * Input:
3340  *  gl      GetLine *  The resource object of this module.
3341  *  nused       int    The number of characters to discard from the start
3342  *                     of the buffer.
3343  */
gl_discard_chars(GetLine * gl,int nused)3344 static void gl_discard_chars(GetLine *gl, int nused)
3345 {
3346   int nkeep = gl->nbuf - nused;
3347   if(nkeep > 0) {
3348     memmove(gl->keybuf, gl->keybuf + nused, nkeep);
3349     gl->nbuf = nkeep;
3350     gl->nread = 0;
3351   } else {
3352     gl->nbuf = gl->nread = 0;
3353   };
3354 }
3355 
3356 /*.......................................................................
3357  * This function is called to handle signals caught between calls to
3358  * sigsetjmp() and siglongjmp().
3359  *
3360  * Input:
3361  *  gl      GetLine *   The resource object of this library.
3362  * Output:
3363  *  return      int     0 - Signal handled internally.
3364  *                      1 - Signal requires gl_get_line() to abort.
3365  */
gl_check_caught_signal(GetLine * gl)3366 static int gl_check_caught_signal(GetLine *gl)
3367 {
3368   GlSignalNode *sig;      /* The signal disposition */
3369   SigAction keep_action;  /* The signal disposition of tecla signal handlers */
3370   unsigned flags;         /* The signal processing flags to use */
3371   int signo;              /* The signal to be handled */
3372 /*
3373  * Was no signal caught?
3374  */
3375   if(gl_pending_signal == -1)
3376     return 0;
3377 /*
3378  * Get the signal to be handled.
3379  */
3380   signo = gl_pending_signal;
3381 /*
3382  * Mark the signal as handled. Note that at this point, all of
3383  * the signals that we are trapping are blocked from delivery.
3384  */
3385   gl_pending_signal = -1;
3386 /*
3387  * Record the signal that was caught, so that the user can query it later.
3388  */
3389   gl->last_signal = signo;
3390 /*
3391  * In non-blocking server mode, the application is responsible for
3392  * responding to terminal signals, and we don't want gl_get_line()s
3393  * normal signal handling to clash with this, so whenever a signal
3394  * is caught, we arrange for gl_get_line() to abort and requeue the
3395  * signal while signals are still blocked. If the application
3396  * had the signal unblocked when gl_get_line() was called, the signal
3397  * will be delivered again as soon as gl_get_line() restores the
3398  * process signal mask, just before returning to the application.
3399  * Note that the caller of this function should set gl->pending_io
3400  * to the appropriate choice of GLP_READ and GLP_WRITE, before returning.
3401  */
3402   if(gl->io_mode==GL_SERVER_MODE) {
3403     gl_record_status(gl, GLR_SIGNAL, EINTR);
3404     raise(signo);
3405     return 1;
3406   };
3407 /*
3408  * Lookup the requested disposition of this signal.
3409  */
3410   for(sig=gl->sigs; sig && sig->signo != signo; sig=sig->next)
3411     ;
3412   if(!sig)
3413     return 0;
3414 /*
3415  * Get the signal response flags for this signal.
3416  */
3417   flags = sig->flags;
3418 /*
3419  * Did we receive a terminal size signal?
3420  */
3421 #ifdef SIGWINCH
3422   if(signo == SIGWINCH && _gl_update_size(gl))
3423     return 1;
3424 #endif
3425 /*
3426  * Start a fresh line?
3427  */
3428   if(flags & GLS_RESTORE_LINE) {
3429     if(gl_start_newline(gl, 0))
3430       return 1;
3431   };
3432 /*
3433  * Restore terminal settings to how they were before gl_get_line() was
3434  * called?
3435  */
3436   if(flags & GLS_RESTORE_TTY)
3437     gl_restore_terminal_attributes(gl);
3438 /*
3439  * Restore signal handlers to how they were before gl_get_line() was
3440  * called? If this hasn't been requested, only reinstate the signal
3441  * handler of the signal that we are handling.
3442  */
3443   if(flags & GLS_RESTORE_SIG) {
3444     gl_restore_signal_handlers(gl);
3445     gl_unmask_signals(gl, &gl->old_signal_set);
3446   } else {
3447     (void) sigaction(sig->signo, &sig->original, &keep_action);
3448     (void) sigprocmask(SIG_UNBLOCK, &sig->proc_mask, NULL);
3449   };
3450 /*
3451  * Forward the signal to the application's signal handler.
3452  */
3453   if(!(flags & GLS_DONT_FORWARD))
3454     raise(signo);
3455 /*
3456  * Reinstate our signal handlers.
3457  */
3458   if(flags & GLS_RESTORE_SIG) {
3459     gl_mask_signals(gl, NULL);
3460     gl_override_signal_handlers(gl);
3461   } else {
3462     (void) sigaction(sig->signo, &keep_action, NULL);
3463     (void) sigprocmask(SIG_BLOCK, &sig->proc_mask, NULL);
3464   };
3465 /*
3466  * Do we need to reinstate our terminal settings?
3467  */
3468   if(flags & GLS_RESTORE_TTY)
3469     gl_raw_terminal_mode(gl);
3470 /*
3471  * Redraw the line?
3472  */
3473   if(flags & GLS_REDRAW_LINE)
3474     gl_queue_redisplay(gl);
3475 /*
3476  * What next?
3477  */
3478   switch(sig->after) {
3479   case GLS_RETURN:
3480     gl_newline(gl, 1, NULL);
3481     return gl_flush_output(gl);
3482     break;
3483   case GLS_ABORT:
3484     gl_record_status(gl, GLR_SIGNAL, sig->errno_value);
3485     return 1;
3486     break;
3487   case GLS_CONTINUE:
3488     return gl_flush_output(gl);
3489     break;
3490   };
3491   return 0;
3492 }
3493 
3494 /*.......................................................................
3495  * Get pertinent terminal control strings and the initial terminal size.
3496  *
3497  * Input:
3498  *  gl     GetLine *  The resource object of this library.
3499  *  term      char *  The type of the terminal.
3500  * Output:
3501  *  return     int    0 - OK.
3502  *                    1 - Error.
3503  */
gl_control_strings(GetLine * gl,const char * term)3504 static int gl_control_strings(GetLine *gl, const char *term)
3505 {
3506   int bad_term = 0;   /* True if term is unusable */
3507 /*
3508  * Discard any existing control strings from a previous terminal.
3509  */
3510   gl->left = NULL;
3511   gl->right = NULL;
3512   gl->up = NULL;
3513   gl->down = NULL;
3514   gl->home = NULL;
3515   gl->bol = 0;
3516   gl->clear_eol = NULL;
3517   gl->clear_eod = NULL;
3518   gl->u_arrow = NULL;
3519   gl->d_arrow = NULL;
3520   gl->l_arrow = NULL;
3521   gl->r_arrow = NULL;
3522   gl->sound_bell = NULL;
3523   gl->bold = NULL;
3524   gl->underline = NULL;
3525   gl->standout = NULL;
3526   gl->dim = NULL;
3527   gl->reverse = NULL;
3528   gl->blink = NULL;
3529   gl->text_attr_off = NULL;
3530   gl->nline = 0;
3531   gl->ncolumn = 0;
3532 #ifdef USE_TERMINFO
3533   gl->left_n = NULL;
3534   gl->right_n = NULL;
3535 #endif
3536 /*
3537  * If possible lookup the information in a terminal information
3538  * database.
3539  */
3540 #ifdef USE_TERMINFO
3541   {
3542     int errret;
3543     if(!term || setupterm((char *)term, gl->input_fd, &errret) == ERR) {
3544       bad_term = 1;
3545     } else {
3546       _clr_StringGroup(gl->capmem);
3547       gl->left = gl_tigetstr(gl, "cub1");
3548       gl->right = gl_tigetstr(gl, "cuf1");
3549       gl->up = gl_tigetstr(gl, "cuu1");
3550       gl->down = gl_tigetstr(gl, "cud1");
3551       gl->home = gl_tigetstr(gl, "home");
3552       gl->clear_eol = gl_tigetstr(gl, "el");
3553       gl->clear_eod = gl_tigetstr(gl, "ed");
3554       gl->u_arrow = gl_tigetstr(gl, "kcuu1");
3555       gl->d_arrow = gl_tigetstr(gl, "kcud1");
3556       gl->l_arrow = gl_tigetstr(gl, "kcub1");
3557       gl->r_arrow = gl_tigetstr(gl, "kcuf1");
3558       gl->left_n = gl_tigetstr(gl, "cub");
3559       gl->right_n = gl_tigetstr(gl, "cuf");
3560       gl->sound_bell = gl_tigetstr(gl, "bel");
3561       gl->bold = gl_tigetstr(gl, "bold");
3562       gl->underline = gl_tigetstr(gl, "smul");
3563       gl->standout = gl_tigetstr(gl, "smso");
3564       gl->dim = gl_tigetstr(gl, "dim");
3565       gl->reverse = gl_tigetstr(gl, "rev");
3566       gl->blink = gl_tigetstr(gl, "blink");
3567       gl->text_attr_off = gl_tigetstr(gl, "sgr0");
3568     };
3569   };
3570 #elif defined(USE_TERMCAP)
3571   if(!term || tgetent(gl->tgetent_buf, (char *)term) < 0) {
3572     bad_term = 1;
3573   } else {
3574     char *tgetstr_buf_ptr = gl->tgetstr_buf;
3575     _clr_StringGroup(gl->capmem);
3576     gl->left = gl_tgetstr(gl, "le", &tgetstr_buf_ptr);
3577     gl->right = gl_tgetstr(gl, "nd", &tgetstr_buf_ptr);
3578     gl->up = gl_tgetstr(gl, "up", &tgetstr_buf_ptr);
3579     gl->down = gl_tgetstr(gl, "do", &tgetstr_buf_ptr);
3580     gl->home = gl_tgetstr(gl, "ho", &tgetstr_buf_ptr);
3581     gl->clear_eol = gl_tgetstr(gl, "ce", &tgetstr_buf_ptr);
3582     gl->clear_eod = gl_tgetstr(gl, "cd", &tgetstr_buf_ptr);
3583     gl->u_arrow = gl_tgetstr(gl, "ku", &tgetstr_buf_ptr);
3584     gl->d_arrow = gl_tgetstr(gl, "kd", &tgetstr_buf_ptr);
3585     gl->l_arrow = gl_tgetstr(gl, "kl", &tgetstr_buf_ptr);
3586     gl->r_arrow = gl_tgetstr(gl, "kr", &tgetstr_buf_ptr);
3587     gl->sound_bell = gl_tgetstr(gl, "bl", &tgetstr_buf_ptr);
3588     gl->bold = gl_tgetstr(gl, "md", &tgetstr_buf_ptr);
3589     gl->underline = gl_tgetstr(gl, "us", &tgetstr_buf_ptr);
3590     gl->standout = gl_tgetstr(gl, "so", &tgetstr_buf_ptr);
3591     gl->dim = gl_tgetstr(gl, "mh", &tgetstr_buf_ptr);
3592     gl->reverse = gl_tgetstr(gl, "mr", &tgetstr_buf_ptr);
3593     gl->blink = gl_tgetstr(gl, "mb", &tgetstr_buf_ptr);
3594     gl->text_attr_off = gl_tgetstr(gl, "me", &tgetstr_buf_ptr);
3595   };
3596 #endif
3597 /*
3598  * Report term being unusable.
3599  */
3600   if(bad_term) {
3601     gl_print_info(gl, "Bad terminal type: \"", term ? term : "(null)",
3602 		  "\". Will assume vt100.", GL_END_INFO);
3603   };
3604 /*
3605  * Fill in missing information with ANSI VT100 strings.
3606  */
3607   if(!gl->left)
3608     gl->left = "\b";    /* ^H */
3609   if(!gl->right)
3610     gl->right = GL_ESC_STR "[C";
3611   if(!gl->up)
3612     gl->up = GL_ESC_STR "[A";
3613   if(!gl->down)
3614     gl->down = "\n";
3615   if(!gl->home)
3616     gl->home = GL_ESC_STR "[H";
3617   if(!gl->bol)
3618     gl->bol = "\r";
3619   if(!gl->clear_eol)
3620     gl->clear_eol = GL_ESC_STR "[K";
3621   if(!gl->clear_eod)
3622     gl->clear_eod = GL_ESC_STR "[J";
3623   if(!gl->u_arrow)
3624     gl->u_arrow = GL_ESC_STR "[A";
3625   if(!gl->d_arrow)
3626     gl->d_arrow = GL_ESC_STR "[B";
3627   if(!gl->l_arrow)
3628     gl->l_arrow = GL_ESC_STR "[D";
3629   if(!gl->r_arrow)
3630     gl->r_arrow = GL_ESC_STR "[C";
3631   if(!gl->sound_bell)
3632     gl->sound_bell = "\a";
3633   if(!gl->bold)
3634     gl->bold = GL_ESC_STR "[1m";
3635   if(!gl->underline)
3636     gl->underline = GL_ESC_STR "[4m";
3637   if(!gl->standout)
3638     gl->standout = GL_ESC_STR "[1;7m";
3639   if(!gl->dim)
3640     gl->dim = "";  /* Not available */
3641   if(!gl->reverse)
3642     gl->reverse = GL_ESC_STR "[7m";
3643   if(!gl->blink)
3644     gl->blink = GL_ESC_STR "[5m";
3645   if(!gl->text_attr_off)
3646     gl->text_attr_off = GL_ESC_STR "[m";
3647 /*
3648  * Find out the current terminal size.
3649  */
3650   (void) _gl_terminal_size(gl, GL_DEF_NCOLUMN, GL_DEF_NLINE, NULL);
3651   return 0;
3652 }
3653 
3654 #ifdef USE_TERMINFO
3655 /*.......................................................................
3656  * This is a private function of gl_control_strings() used to look up
3657  * a termninal capability string from the terminfo database and make
3658  * a private copy of it.
3659  *
3660  * Input:
3661  *  gl         GetLine *  The resource object of gl_get_line().
3662  *  name    const char *  The name of the terminfo string to look up.
3663  * Output:
3664  *  return  const char *  The local copy of the capability, or NULL
3665  *                        if not available.
3666  */
gl_tigetstr(GetLine * gl,const char * name)3667 static const char *gl_tigetstr(GetLine *gl, const char *name)
3668 {
3669   const char *value = tigetstr((char *)name);
3670   if(!value || value == (char *) -1)
3671     return NULL;
3672   return _sg_store_string(gl->capmem, value, 0);
3673 }
3674 #elif defined(USE_TERMCAP)
3675 /*.......................................................................
3676  * This is a private function of gl_control_strings() used to look up
3677  * a termninal capability string from the termcap database and make
3678  * a private copy of it. Note that some emulations of tgetstr(), such
3679  * as that used by Solaris, ignores the buffer pointer that is past to
3680  * it, so we can't assume that a private copy has been made that won't
3681  * be trashed by another call to gl_control_strings() by another
3682  * GetLine object. So we make what may be a redundant private copy
3683  * of the string in gl->capmem.
3684  *
3685  * Input:
3686  *  gl         GetLine *  The resource object of gl_get_line().
3687  *  name    const char *  The name of the terminfo string to look up.
3688  * Input/Output:
3689  *  bufptr        char ** On input *bufptr points to the location in
3690  *                        gl->tgetstr_buf at which to record the
3691  *                        capability string. On output *bufptr is
3692  *                        incremented over the stored string.
3693  * Output:
3694  *  return  const char *  The local copy of the capability, or NULL
3695  *                        on error.
3696  */
gl_tgetstr(GetLine * gl,const char * name,char ** bufptr)3697 static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr)
3698 {
3699   const char *value = tgetstr((char *)name, bufptr);
3700   if(!value || value == (char *) -1)
3701     return NULL;
3702   return _sg_store_string(gl->capmem, value, 0);
3703 }
3704 #endif
3705 
3706 /*.......................................................................
3707  * This is an action function that implements a user interrupt (eg. ^C).
3708  */
KT_KEY_FN(gl_user_interrupt)3709 static KT_KEY_FN(gl_user_interrupt)
3710 {
3711   raise(SIGINT);
3712   return 1;
3713 }
3714 
3715 /*.......................................................................
3716  * This is an action function that implements the abort signal.
3717  */
KT_KEY_FN(gl_abort)3718 static KT_KEY_FN(gl_abort)
3719 {
3720   raise(SIGABRT);
3721   return 1;
3722 }
3723 
3724 /*.......................................................................
3725  * This is an action function that sends a suspend signal (eg. ^Z) to the
3726  * the parent process.
3727  */
KT_KEY_FN(gl_suspend)3728 static KT_KEY_FN(gl_suspend)
3729 {
3730   raise(SIGTSTP);
3731   return 0;
3732 }
3733 
3734 /*.......................................................................
3735  * This is an action function that halts output to the terminal.
3736  */
KT_KEY_FN(gl_stop_output)3737 static KT_KEY_FN(gl_stop_output)
3738 {
3739   tcflow(gl->output_fd, TCOOFF);
3740   return 0;
3741 }
3742 
3743 /*.......................................................................
3744  * This is an action function that resumes halted terminal output.
3745  */
KT_KEY_FN(gl_start_output)3746 static KT_KEY_FN(gl_start_output)
3747 {
3748   tcflow(gl->output_fd, TCOON);
3749   return 0;
3750 }
3751 
3752 /*.......................................................................
3753  * This is an action function that allows the next character to be accepted
3754  * without any interpretation as a special character.
3755  */
KT_KEY_FN(gl_literal_next)3756 static KT_KEY_FN(gl_literal_next)
3757 {
3758   char c;   /* The character to be added to the line */
3759   int i;
3760 /*
3761  * Get the character to be inserted literally.
3762  */
3763   if(gl_read_terminal(gl, 1, &c))
3764     return 1;
3765 /*
3766  * Add the character to the line 'count' times.
3767  */
3768   for(i=0; i<count; i++)
3769     gl_add_char_to_line(gl, c);
3770   return 0;
3771 }
3772 
3773 /*.......................................................................
3774  * Return the width of a tab character at a given position when
3775  * displayed at a given position on the terminal. This is needed
3776  * because the width of tab characters depends on where they are,
3777  * relative to the preceding tab stops.
3778  *
3779  * Input:
3780  *  gl       GetLine *  The resource object of this library.
3781  *  term_curpos  int    The destination terminal location of the character.
3782  * Output:
3783  *  return       int    The number of terminal charaters needed.
3784  */
gl_displayed_tab_width(GetLine * gl,int term_curpos)3785 static int gl_displayed_tab_width(GetLine *gl, int term_curpos)
3786 {
3787   return TAB_WIDTH - ((term_curpos % gl->ncolumn) % TAB_WIDTH);
3788 }
3789 
3790 /*.......................................................................
3791  * Return the number of characters needed to display a given character
3792  * on the screen. Tab characters require eight spaces, and control
3793  * characters are represented by a caret followed by the modified
3794  * character.
3795  *
3796  * Input:
3797  *  gl       GetLine *  The resource object of this library.
3798  *  c           char    The character to be displayed.
3799  *  term_curpos  int    The destination terminal location of the character.
3800  *                      This is needed because the width of tab characters
3801  *                      depends on where they are, relative to the
3802  *                      preceding tab stops.
3803  * Output:
3804  *  return       int    The number of terminal charaters needed.
3805  */
gl_displayed_char_width(GetLine * gl,char c,int term_curpos)3806 static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos)
3807 {
3808   if(c=='\t')
3809     return gl_displayed_tab_width(gl, term_curpos);
3810   if(IS_CTRL_CHAR(c))
3811     return 2;
3812   if(!isprint((int)(unsigned char) c))
3813     return gl_octal_width((int)(unsigned char)c) + 1;
3814   return 1;
3815 }
3816 
3817 
3818 /*.......................................................................
3819  * Work out the length of given string of characters on the terminal.
3820  *
3821  * Input:
3822  *  gl       GetLine *  The resource object of this library.
3823  *  string      char *  The string to be measured.
3824  *  nc           int    The number of characters to be measured, or -1
3825  *                      to measure the whole string.
3826  *  term_curpos  int    The destination terminal location of the character.
3827  *                      This is needed because the width of tab characters
3828  *                      depends on where they are, relative to the
3829  *                      preceding tab stops.
3830  * Output:
3831  *  return       int    The number of displayed characters.
3832  */
gl_displayed_string_width(GetLine * gl,const char * string,int nc,int term_curpos)3833 static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
3834 				     int term_curpos)
3835 {
3836   int slen = 0;   /* The displayed number of characters */
3837   int i;
3838 /*
3839  * How many characters are to be measured?
3840  */
3841   if(nc < 0)
3842     nc = strlen(string);
3843 /*
3844  * Add up the length of the displayed string.
3845  */
3846   for(i=0; i<nc; i++)
3847     slen += gl_displayed_char_width(gl, string[i], term_curpos + slen);
3848   return slen;
3849 }
3850 
3851 /*.......................................................................
3852  * Write a string verbatim to the current terminal or output stream.
3853  *
3854  * Note that when async-signal safety is required, the 'buffered'
3855  * argument must be 0, and n must not be -1.
3856  *
3857  * Input:
3858  *  gl         GetLine *  The resource object of the gl_get_line().
3859  *  buffered       int    If true, used buffered I/O when writing to
3860  *                        the terminal. Otherwise use async-signal-safe
3861  *                        unbuffered I/O.
3862  *  string  const char *  The string to be written (this need not be
3863  *                        '\0' terminated unless n<0).
3864  *  n              int    The number of characters to write from the
3865  *                        prefix of string[], or -1 to request that
3866  *                        gl_print_raw_string() use strlen() to figure
3867  *                        out the length.
3868  * Output:
3869  *  return         int    0 - OK.
3870  *                        1 - Error.
3871  */
gl_print_raw_string(GetLine * gl,int buffered,const char * string,int n)3872 static int gl_print_raw_string(GetLine *gl, int buffered,
3873 			       const char *string, int n)
3874 {
3875   GlWriteFn *write_fn = buffered ? gl_write_fn : gl->flush_fn;
3876 /*
3877  * Only display output when echoing is turned on.
3878  */
3879   if(gl->echo) {
3880     int ndone = 0;   /* The number of characters written so far */
3881 /*
3882  * When using un-buffered I/O, flush pending output first.
3883  */
3884     if(!buffered) {
3885       if(gl_flush_output(gl))
3886 	return 1;
3887     };
3888 /*
3889  * If no length has been provided, measure the length of the string.
3890  */
3891     if(n < 0)
3892       n = strlen(string);
3893 /*
3894  * Write the string.
3895  */
3896     if(write_fn(gl, string + ndone, n-ndone) != n)
3897       return 1;
3898   };
3899   return 0;
3900 }
3901 
3902 /*.......................................................................
3903  * Output a terminal control sequence. When using terminfo,
3904  * this must be a sequence returned by tgetstr() or tigetstr()
3905  * respectively.
3906  *
3907  * Input:
3908  *  gl     GetLine *   The resource object of this library.
3909  *  nline      int     The number of lines affected by the operation,
3910  *                     or 1 if not relevant.
3911  *  string    char *   The control sequence to be sent.
3912  * Output:
3913  *  return     int     0 - OK.
3914  *                     1 - Error.
3915  */
gl_print_control_sequence(GetLine * gl,int nline,const char * string)3916 static int gl_print_control_sequence(GetLine *gl, int nline, const char *string)
3917 {
3918   int waserr = 0;   /* True if an error occurs */
3919 /*
3920  * Only write characters to the terminal when echoing is enabled.
3921  */
3922   if(gl->echo) {
3923 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
3924     tputs_gl = gl;
3925     errno = 0;
3926     tputs((char *)string, nline, gl_tputs_putchar);
3927     waserr = errno != 0;
3928 #else
3929     waserr = gl_print_raw_string(gl, 1, string, -1);
3930 #endif
3931   };
3932   return waserr;
3933 }
3934 
3935 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
3936 /*.......................................................................
3937  * The following callback function is called by tputs() to output a raw
3938  * control character to the terminal.
3939  */
gl_tputs_putchar(TputsArgType c)3940 static TputsRetType gl_tputs_putchar(TputsArgType c)
3941 {
3942   char ch = c;
3943 #if TPUTS_RETURNS_VALUE
3944   return gl_print_raw_string(tputs_gl, 1, &ch, 1);
3945 #else
3946   (void) gl_print_raw_string(tputs_gl, 1, &ch, 1);
3947 #endif
3948 }
3949 #endif
3950 
3951 /*.......................................................................
3952  * Move the terminal cursor n characters to the left or right.
3953  *
3954  * Input:
3955  *  gl     GetLine *   The resource object of this program.
3956  *  n          int     number of positions to the right (> 0) or left (< 0).
3957  * Output:
3958  *  return     int     0 - OK.
3959  *                     1 - Error.
3960  */
gl_terminal_move_cursor(GetLine * gl,int n)3961 static int gl_terminal_move_cursor(GetLine *gl, int n)
3962 {
3963   int cur_row, cur_col; /* The current terminal row and column index of */
3964                         /*  the cursor wrt the start of the input line. */
3965   int new_row, new_col; /* The target terminal row and column index of */
3966                         /*  the cursor wrt the start of the input line. */
3967 /*
3968  * Do nothing if the input line isn't currently displayed. In this
3969  * case, the cursor will be moved to the right place when the line
3970  * is next redisplayed.
3971  */
3972   if(!gl->displayed)
3973     return 0;
3974 /*
3975  * How far can we move left?
3976  */
3977   if(gl->term_curpos + n < 0)
3978     n = gl->term_curpos;
3979 /*
3980  * Break down the current and target cursor locations into rows and columns.
3981  */
3982   cur_row = gl->term_curpos / gl->ncolumn;
3983   cur_col = gl->term_curpos % gl->ncolumn;
3984   new_row = (gl->term_curpos + n) / gl->ncolumn;
3985   new_col = (gl->term_curpos + n) % gl->ncolumn;
3986 /*
3987  * Move down to the next line.
3988  */
3989   for(; cur_row < new_row; cur_row++) {
3990     if(gl_print_control_sequence(gl, 1, gl->down))
3991       return 1;
3992   };
3993 /*
3994  * Move up to the previous line.
3995  */
3996   for(; cur_row > new_row; cur_row--) {
3997     if(gl_print_control_sequence(gl, 1, gl->up))
3998       return 1;
3999   };
4000 /*
4001  * Move to the right within the target line?
4002  */
4003   if(cur_col < new_col) {
4004 #ifdef USE_TERMINFO
4005 /*
4006  * Use a parameterized control sequence if it generates less control
4007  * characters (guess based on ANSI terminal termcap entry).
4008  */
4009     if(gl->right_n != NULL && new_col - cur_col > 1) {
4010       if(gl_print_control_sequence(gl, 1, tparm((char *)gl->right_n,
4011            (long)(new_col - cur_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
4012 	return 1;
4013     } else
4014 #endif
4015     {
4016       for(; cur_col < new_col; cur_col++) {
4017         if(gl_print_control_sequence(gl, 1, gl->right))
4018           return 1;
4019       };
4020     };
4021 /*
4022  * Move to the left within the target line?
4023  */
4024   } else if(cur_col > new_col) {
4025 #ifdef USE_TERMINFO
4026 /*
4027  * Use a parameterized control sequence if it generates less control
4028  * characters (guess based on ANSI terminal termcap entry).
4029  */
4030     if(gl->left_n != NULL && cur_col - new_col > 3) {
4031       if(gl_print_control_sequence(gl, 1, tparm((char *)gl->left_n,
4032            (long)(cur_col - new_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
4033 	return 1;
4034     } else
4035 #endif
4036     {
4037       for(; cur_col > new_col; cur_col--) {
4038         if(gl_print_control_sequence(gl, 1, gl->left))
4039           return 1;
4040       };
4041     };
4042   }
4043 /*
4044  * Update the recorded position of the terminal cursor.
4045  */
4046   gl->term_curpos += n;
4047   return 0;
4048 }
4049 
4050 /*.......................................................................
4051  * Write a character to the terminal after expanding tabs and control
4052  * characters to their multi-character representations.
4053  *
4054  * Input:
4055  *  gl    GetLine *   The resource object of this program.
4056  *  c        char     The character to be output.
4057  *  pad      char     Many terminals have the irritating feature that
4058  *                    when one writes a character in the last column of
4059  *                    of the terminal, the cursor isn't wrapped to the
4060  *                    start of the next line until one more character
4061  *                    is written. Some terminals don't do this, so
4062  *                    after such a write, we don't know where the
4063  *                    terminal is unless we output an extra character.
4064  *                    This argument specifies the character to write.
4065  *                    If at the end of the input line send '\0' or a
4066  *                    space, and a space will be written. Otherwise,
4067  *                    pass the next character in the input line
4068  *                    following the one being written.
4069  * Output:
4070  *  return    int     0 - OK.
4071  */
gl_print_char(GetLine * gl,char c,char pad)4072 static int gl_print_char(GetLine *gl, char c, char pad)
4073 {
4074   char string[TAB_WIDTH + 4]; /* A work area for composing compound strings */
4075   int nchar;                  /* The number of terminal characters */
4076   int i;
4077 /*
4078  * Check for special characters.
4079  */
4080   if(c == '\t') {
4081 /*
4082  * How many spaces do we need to represent a tab at the current terminal
4083  * column?
4084  */
4085     nchar = gl_displayed_tab_width(gl, gl->term_curpos);
4086 /*
4087  * Compose the tab string.
4088  */
4089     for(i=0; i<nchar; i++)
4090       string[i] = ' ';
4091   } else if(IS_CTRL_CHAR(c)) {
4092     string[0] = '^';
4093     string[1] = CTRL_TO_CHAR(c);
4094     nchar = 2;
4095   } else if(!isprint((int)(unsigned char) c)) {
4096     snprintf(string, sizeof(string), "\\%o", (int)(unsigned char)c);
4097     nchar = strlen(string);
4098   } else {
4099     string[0] = c;
4100     nchar = 1;
4101   };
4102 /*
4103  * Terminate the string.
4104  */
4105   string[nchar] = '\0';
4106 /*
4107  * Write the string to the terminal.
4108  */
4109   if(gl_print_raw_string(gl, 1, string, -1))
4110     return 1;
4111 /*
4112  * Except for one exception to be described in a moment, the cursor should
4113  * now have been positioned after the character that was just output.
4114  */
4115   gl->term_curpos += nchar;
4116 /*
4117  * Keep a record of the number of characters in the terminal version
4118  * of the input line.
4119  */
4120   if(gl->term_curpos > gl->term_len)
4121     gl->term_len = gl->term_curpos;
4122 /*
4123  * If the new character ended exactly at the end of a line,
4124  * most terminals won't move the cursor onto the next line until we
4125  * have written a character on the next line, so append an extra
4126  * space then move the cursor back.
4127  */
4128   if(gl->term_curpos % gl->ncolumn == 0) {
4129