1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2012 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 * Standard headers.
34 */
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <signal.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <setjmp.h>
42 #include <stdarg.h>
43
44 /*
45 * UNIX headers.
46 */
47 #include <sys/ioctl.h>
48 #ifdef HAVE_SELECT
49 #ifdef HAVE_SYS_SELECT_H
50 #include <sys/select.h>
51 #endif
52 #include <sys/time.h>
53 #include <sys/types.h>
54 #endif
55
56 /*
57 * Handle the different sources of terminal control string and size
58 * information. Note that if no terminal information database is available,
59 * ANSI VT100 control sequences are used.
60 */
61 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
62 /*
63 * Include curses.h or ncurses/curses.h depending on which is available.
64 */
65 #ifdef HAVE_CURSES_H
66 #include <curses.h>
67 #elif defined(HAVE_NCURSES_CURSES_H)
68 #include <ncurses/curses.h>
69 #endif
70 /*
71 * Include term.h where available.
72 */
73 #if defined(HAVE_TERM_H)
74 #include <term.h>
75 #elif defined(HAVE_NCURSES_TERM_H)
76 #include <ncurses/term.h>
77 #endif
78 /*
79 * When using termcap, include termcap.h on systems that have it.
80 * Otherwise assume that all prototypes are provided by curses.h.
81 */
82 #if defined(USE_TERMCAP) && defined(HAVE_TERMCAP_H)
83 #include <termcap.h>
84 #endif
85
86 /*
87 * Under Solaris default Curses the output function that tputs takes is
88 * declared to have a char argument. On all other systems and on Solaris
89 * X/Open Curses (Issue 4, Version 2) it expects an int argument (using
90 * c89 or options -I /usr/xpg4/include -L /usr/xpg4/lib -R /usr/xpg4/lib
91 * selects XPG4v2 Curses on Solaris 2.6 and later).
92 *
93 * Similarly, under Mac OS X, the return value of the tputs output
94 * function is declared as void, whereas it is declared as int on
95 * other systems.
96 */
97 #if defined __sun && defined __SVR4 && !defined _XOPEN_CURSES
98 typedef int TputsRetType;
99 typedef char TputsArgType; /* int tputs(char c, FILE *fp) */
100 #define TPUTS_RETURNS_VALUE 1
101 #elif defined(__APPLE__) && defined(__MACH__)
102 typedef void TputsRetType;
103 typedef int TputsArgType; /* void tputs(int c, FILE *fp) */
104 #define TPUTS_RETURNS_VALUE 0
105 #else
106 typedef int TputsRetType;
107 typedef int TputsArgType; /* int tputs(int c, FILE *fp) */
108 #define TPUTS_RETURNS_VALUE 1
109 #endif
110
111 /*
112 * Use the above specifications to prototype our tputs callback function.
113 */
114 static TputsRetType gl_tputs_putchar(TputsArgType c);
115
116 #endif /* defined(USE_TERMINFO) || defined(USE_TERMCAP) */
117
118 /*
119 * If the library is being compiled without filesystem access facilities,
120 * ensure that none of the action functions that normally do access the
121 * filesystem are bound by default, and that it they do get bound, that
122 * they don't do anything.
123 */
124 #if WITHOUT_FILE_SYSTEM
125 #define HIDE_FILE_SYSTEM
126 #endif
127
128 /*
129 * POSIX headers.
130 */
131 #include <unistd.h>
132 #include <fcntl.h>
133 #include <termios.h>
134
135 /*
136 * Provide typedefs for standard POSIX structures.
137 */
138 typedef struct sigaction SigAction;
139 typedef struct termios Termios;
140
141 /*
142 * Which flag is used to select non-blocking I/O with fcntl()?
143 */
144 #undef NON_BLOCKING_FLAG
145 #if defined(O_NONBLOCK)
146 #define NON_BLOCKING_FLAG (O_NONBLOCK)
147 #elif defined(O_NDELAY)
148 #define NON_BLOCKING_FLAG (O_NDELAY)
149 #endif
150
151 /*
152 * What value should we give errno if I/O blocks when it shouldn't.
153 */
154 #undef BLOCKED_ERRNO
155 #if defined(EAGAIN)
156 #define BLOCKED_ERRNO (EAGAIN)
157 #elif defined(EWOULDBLOCK)
158 #define BLOCKED_ERRNO (EWOULDBLOCK)
159 #elif defined(EIO)
160 #define BLOCKED_ERRNO (EIO)
161 #else
162 #define BLOCKED_ERRNO 0
163 #endif
164
165 /*
166 * Local headers.
167 */
168 #ifndef WITHOUT_FILE_SYSTEM
169 #include "pathutil.h"
170 #endif
171 #include "libtecla.h"
172 #include "keytab.h"
173 #include "getline.h"
174 #include "ioutil.h"
175 #include "history.h"
176 #include "freelist.h"
177 #include "stringrp.h"
178 #include "chrqueue.h"
179 #include "cplmatch.h"
180 #ifndef WITHOUT_FILE_SYSTEM
181 #include "expand.h"
182 #endif
183 #include "errmsg.h"
184
185 /*
186 * Enumerate the available editing styles.
187 */
188 typedef enum {
189 GL_EMACS_MODE, /* Emacs style editing */
190 GL_VI_MODE, /* Vi style editing */
191 GL_NO_EDITOR /* Fall back to the basic OS-provided editing */
192 } GlEditor;
193
194 /*
195 * Set the largest key-sequence that can be handled.
196 */
197 #define GL_KEY_MAX 64
198
199 /*
200 * In vi mode, the following datatype is used to implement the
201 * undo command. It records a copy of the input line from before
202 * the command-mode action which edited the input line.
203 */
204 typedef struct {
205 char *line; /* A historical copy of the input line */
206 int buff_curpos; /* The historical location of the cursor in */
207 /* line[] when the line was modified. */
208 int ntotal; /* The number of characters in line[] */
209 int saved; /* True once a line has been saved after the */
210 /* last call to gl_interpret_char(). */
211 } ViUndo;
212
213 /*
214 * In vi mode, the following datatype is used to record information
215 * needed by the vi-repeat-change command.
216 */
217 typedef struct {
218 KtAction action; /* The last action function that made a */
219 /* change to the line. */
220 int count; /* The repeat count that was passed to the */
221 /* above command. */
222 int input_curpos; /* Whenever vi command mode is entered, the */
223 /* the position at which it was first left */
224 /* is recorded here. */
225 int command_curpos; /* Whenever vi command mode is entered, the */
226 /* the location of the cursor is recorded */
227 /* here. */
228 char input_char; /* Commands that call gl_read_terminal() */
229 /* record the character here, so that it can */
230 /* used on repeating the function. */
231 int saved; /* True if a function has been saved since the */
232 /* last call to gl_interpret_char(). */
233 int active; /* True while a function is being repeated. */
234 } ViRepeat;
235
236 /*
237 * The following datatype is used to encapsulate information specific
238 * to vi mode.
239 */
240 typedef struct {
241 ViUndo undo; /* Information needed to implement the vi */
242 /* undo command. */
243 ViRepeat repeat; /* Information needed to implement the vi */
244 /* repeat command. */
245 int command; /* True in vi command-mode */
246 int find_forward; /* True if the last character search was in the */
247 /* forward direction. */
248 int find_onto; /* True if the last character search left the */
249 /* on top of the located character, as opposed */
250 /* to just before or after it. */
251 char find_char; /* The last character sought, or '\0' if no */
252 /* searches have been performed yet. */
253 } ViMode;
254
255 #ifdef HAVE_SELECT
256 /*
257 * Define a type for recording a file-descriptor callback and its associated
258 * data.
259 */
260 typedef struct {
261 GlFdEventFn *fn; /* The callback function */
262 void *data; /* Anonymous data to pass to the callback function */
263 } GlFdHandler;
264
265 /*
266 * A list of nodes of the following type is used to record file-activity
267 * event handlers, but only on systems that have the select() system call.
268 */
269 typedef struct GlFdNode GlFdNode;
270 struct GlFdNode {
271 GlFdNode *next; /* The next in the list of nodes */
272 int fd; /* The file descriptor being watched */
273 GlFdHandler rd; /* The callback to call when fd is readable */
274 GlFdHandler wr; /* The callback to call when fd is writable */
275 GlFdHandler ur; /* The callback to call when fd has urgent data */
276 };
277
278 /*
279 * Set the number of the above structures to allocate every time that
280 * the freelist of GlFdNode's becomes exhausted.
281 */
282 #define GLFD_FREELIST_BLOCKING 10
283
284
285 static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
286 GlFdEvent event);
287
288 static int gl_call_timeout_handler(GetLine *gl);
289
290 #endif
291
292 /*
293 * Each signal that gl_get_line() traps is described by a list node
294 * of the following type.
295 */
296 typedef struct GlSignalNode GlSignalNode;
297 struct GlSignalNode {
298 GlSignalNode *next; /* The next signal in the list */
299 int signo; /* The number of the signal */
300 sigset_t proc_mask; /* A process mask which only includes signo */
301 SigAction original; /* The signal disposition of the calling program */
302 /* for this signal. */
303 unsigned flags; /* A bitwise union of GlSignalFlags enumerators */
304 GlAfterSignal after; /* What to do after the signal has been handled */
305 int errno_value; /* What to set errno to */
306 };
307
308 /*
309 * Set the number of the above structures to allocate every time that
310 * the freelist of GlSignalNode's becomes exhausted.
311 */
312 #define GLS_FREELIST_BLOCKING 30
313
314 /*
315 * Completion handlers and their callback data are recorded in
316 * nodes of the following type.
317 */
318 typedef struct GlCplCallback GlCplCallback;
319 struct GlCplCallback {
320 CplMatchFn *fn; /* The completion callback function */
321 void *data; /* Arbitrary callback data */
322 };
323
324 /*
325 * The following function is used as the default completion handler when
326 * the filesystem is to be hidden. It simply reports no completions.
327 */
328 #ifdef HIDE_FILE_SYSTEM
329 static CPL_MATCH_FN(gl_no_completions);
330 #endif
331
332 /*
333 * Specify how many GlCplCallback nodes are added to the GlCplCallback freelist
334 * whenever it becomes exhausted.
335 */
336 #define GL_CPL_FREELIST_BLOCKING 10
337
338 /*
339 * External action functions and their callback data are recorded in
340 * nodes of the following type.
341 */
342 typedef struct GlExternalAction GlExternalAction;
343 struct GlExternalAction {
344 GlActionFn *fn; /* The function which implements the action */
345 void *data; /* Arbitrary callback data */
346 };
347
348 /*
349 * Specify how many GlExternalAction nodes are added to the
350 * GlExternalAction freelist whenever it becomes exhausted.
351 */
352 #define GL_EXT_ACT_FREELIST_BLOCKING 10
353
354 /*
355 * Define the contents of the GetLine object.
356 * Note that the typedef for this object can be found in libtecla.h.
357 */
358 struct GetLine {
359 ErrMsg *err; /* The error-reporting buffer */
360 GlHistory *glh; /* The line-history buffer */
361 WordCompletion *cpl; /* String completion resource object */
362 GlCplCallback cplfn; /* The completion callback */
363 #ifndef WITHOUT_FILE_SYSTEM
364 ExpandFile *ef; /* ~user/, $envvar and wildcard expansion */
365 /* resource object. */
366 #endif
367 StringGroup *capmem; /* Memory for recording terminal capability */
368 /* strings. */
369 GlCharQueue *cq; /* The terminal output character queue */
370 int input_fd; /* The file descriptor to read on */
371 int output_fd; /* The file descriptor to write to */
372 FILE *input_fp; /* A stream wrapper around input_fd */
373 FILE *output_fp; /* A stream wrapper around output_fd */
374 FILE *file_fp; /* When input is being temporarily taken from */
375 /* a file, this is its file-pointer. Otherwise */
376 /* it is NULL. */
377 char *term; /* The terminal type specified on the last call */
378 /* to gl_change_terminal(). */
379 int is_term; /* True if stdin is a terminal */
380 GlWriteFn *flush_fn; /* The function to call to write to the terminal */
381 GlIOMode io_mode; /* The I/O mode established by gl_io_mode() */
382 int raw_mode; /* True while the terminal is in raw mode */
383 GlPendingIO pending_io; /* The type of I/O that is currently pending */
384 GlReturnStatus rtn_status; /* The reason why gl_get_line() returned */
385 int rtn_errno; /* THe value of errno associated with rtn_status */
386 size_t linelen; /* The max number of characters per line */
387 char *line; /* A line-input buffer of allocated size */
388 /* linelen+2. The extra 2 characters are */
389 /* reserved for "\n\0". */
390 char *cutbuf; /* A cut-buffer of the same size as line[] */
391 char *prompt; /* The current prompt string */
392 int prompt_len; /* The length of the prompt string */
393 int prompt_changed; /* True after a callback changes the prompt */
394 int prompt_style; /* How the prompt string is displayed */
395 FreeList *cpl_mem; /* Memory for GlCplCallback objects */
396 FreeList *ext_act_mem; /* Memory for GlExternalAction objects */
397 FreeList *sig_mem; /* Memory for nodes of the signal list */
398 GlSignalNode *sigs; /* The head of the list of signals */
399 int signals_masked; /* True between calls to gl_mask_signals() and */
400 /* gl_unmask_signals() */
401 int signals_overriden; /* True between calls to gl_override_signals() */
402 /* and gl_restore_signals() */
403 sigset_t all_signal_set; /* The set of all signals that we are trapping */
404 sigset_t old_signal_set; /* The set of blocked signals on entry to */
405 /* gl_get_line(). */
406 sigset_t use_signal_set; /* The subset of all_signal_set to unblock */
407 /* while waiting for key-strokes */
408 Termios oldattr; /* Saved terminal attributes. */
409 KeyTab *bindings; /* A table of key-bindings */
410 int ntotal; /* The number of characters in gl->line[] */
411 int buff_curpos; /* The cursor position within gl->line[] */
412 int term_curpos; /* The cursor position on the terminal */
413 int term_len; /* The number of terminal characters used to */
414 /* display the current input line. */
415 int buff_mark; /* A marker location in the buffer */
416 int insert_curpos; /* The cursor position at start of insert */
417 int insert; /* True in insert mode */
418 int number; /* If >= 0, a numeric argument is being read */
419 int endline; /* True to tell gl_get_input_line() to return */
420 /* the current contents of gl->line[] */
421 int displayed; /* True if an input line is currently displayed */
422 int redisplay; /* If true, the input line will be redrawn */
423 /* either after the current action function */
424 /* returns, or when gl_get_input_line() */
425 /* is next called. */
426 int postpone; /* _gl_normal_io() sets this flag, to */
427 /* postpone any redisplays until */
428 /* is next called, to resume line editing. */
429 char keybuf[GL_KEY_MAX+1]; /* A buffer of currently unprocessed key presses */
430 int nbuf; /* The number of characters in keybuf[] */
431 int nread; /* The number of characters read from keybuf[] */
432 KtAction current_action; /* The action function that is being invoked */
433 int current_count; /* The repeat count passed to */
434 /* current_acction.fn() */
435 GlhLineID preload_id; /* When not zero, this should be the ID of a */
436 /* line in the history buffer for potential */
437 /* recall. */
438 int preload_history; /* If true, preload the above history line when */
439 /* gl_get_input_line() is next called. */
440 long keyseq_count; /* The number of key sequences entered by the */
441 /* the user since new_GetLine() was called. */
442 long last_search; /* The value of keyseq_count during the last */
443 /* history search operation. */
444 GlEditor editor; /* The style of editing, (eg. vi or emacs) */
445 int silence_bell; /* True if gl_ring_bell() should do nothing. */
446 int automatic_history; /* True to automatically archive entered lines */
447 /* in the history list. */
448 ViMode vi; /* Parameters used when editing in vi mode */
449 const char *left; /* The string that moves the cursor 1 character */
450 /* left. */
451 const char *right; /* The string that moves the cursor 1 character */
452 /* right. */
453 const char *up; /* The string that moves the cursor 1 character */
454 /* up. */
455 const char *down; /* The string that moves the cursor 1 character */
456 /* down. */
457 const char *home; /* The string that moves the cursor home */
458 const char *bol; /* Move cursor to beginning of line */
459 const char *clear_eol; /* The string that clears from the cursor to */
460 /* the end of the line. */
461 const char *clear_eod; /* The string that clears from the cursor to */
462 /* the end of the display. */
463 const char *u_arrow; /* The string returned by the up-arrow key */
464 const char *d_arrow; /* The string returned by the down-arrow key */
465 const char *l_arrow; /* The string returned by the left-arrow key */
466 const char *r_arrow; /* The string returned by the right-arrow key */
467 const char *sound_bell; /* The string needed to ring the terminal bell */
468 const char *bold; /* Switch to the bold font */
469 const char *underline; /* Underline subsequent characters */
470 const char *standout; /* Turn on standout mode */
471 const char *dim; /* Switch to a dim font */
472 const char *reverse; /* Turn on reverse video */
473 const char *blink; /* Switch to a blinking font */
474 const char *text_attr_off; /* Turn off all text attributes */
475 int nline; /* The height of the terminal in lines */
476 int ncolumn; /* The width of the terminal in columns */
477 #ifdef USE_TERMCAP
478 char *tgetent_buf; /* The buffer that is used by tgetent() to */
479 /* store a terminal description. */
480 char *tgetstr_buf; /* The buffer that is used by tgetstr() to */
481 /* store terminal capabilities. */
482 #endif
483 #ifdef USE_TERMINFO
484 const char *left_n; /* The parameter string that moves the cursor */
485 /* n characters left. */
486 const char *right_n; /* The parameter string that moves the cursor */
487 /* n characters right. */
488 #endif
489 char *app_file; /* The pathname of the application-specific */
490 /* .teclarc configuration file, or NULL. */
491 char *user_file; /* The pathname of the user-specific */
492 /* .teclarc configuration file, or NULL. */
493 int configured; /* True as soon as any teclarc configuration */
494 /* file has been read. */
495 int echo; /* True to display the line as it is being */
496 /* entered. If 0, only the prompt will be */
497 /* displayed, and the line will not be */
498 /* archived in the history list. */
499 int last_signal; /* The last signal that was caught by */
500 /* the last call to gl_get_line(), or -1 */
501 /* if no signal has been caught yet. */
502 #ifdef HAVE_SELECT
503 FreeList *fd_node_mem; /* A freelist of GlFdNode structures */
504 GlFdNode *fd_nodes; /* The list of fd event descriptions */
505 fd_set rfds; /* The set of fds to watch for readability */
506 fd_set wfds; /* The set of fds to watch for writability */
507 fd_set ufds; /* The set of fds to watch for urgent data */
508 int max_fd; /* The maximum file-descriptor being watched */
509 struct { /* Inactivity timeout related data */
510 struct timeval dt; /* The inactivity timeout when timer.fn() */
511 /* isn't 0 */
512 GlTimeoutFn *fn; /* The application callback to call when */
513 /* the inactivity timer expires, or 0 if */
514 /* timeouts are not required. */
515 void *data; /* Application provided data to be passed to */
516 /* timer.fn(). */
517 } timer;
518 #endif
519 };
520
521 /*
522 * Define the max amount of space needed to store a termcap terminal
523 * description. Unfortunately this has to be done by guesswork, so
524 * there is the potential for buffer overflows if we guess too small.
525 * Fortunately termcap has been replaced by terminfo on most
526 * platforms, and with terminfo this isn't an issue. The value that I
527 * am using here is the conventional value, as recommended by certain
528 * web references.
529 */
530 #ifdef USE_TERMCAP
531 #define TERMCAP_BUF_SIZE 2048
532 #endif
533
534 /*
535 * Set the size of the string segments used to store terminal capability
536 * strings.
537 */
538 #define CAPMEM_SEGMENT_SIZE 512
539
540 /*
541 * If no terminal size information is available, substitute the
542 * following vt100 default sizes.
543 */
544 #define GL_DEF_NLINE 24
545 #define GL_DEF_NCOLUMN 80
546
547 /*
548 * Enumerate the attributes needed to classify different types of
549 * signals. These attributes reflect the standard default
550 * characteristics of these signals (according to Richard Steven's
551 * Advanced Programming in the UNIX Environment). Note that these values
552 * are all powers of 2, so that they can be combined in a bitwise union.
553 */
554 typedef enum {
555 GLSA_TERM=1, /* A signal that terminates processes */
556 GLSA_SUSP=2, /* A signal that suspends processes */
557 GLSA_CONT=4, /* A signal that is sent when suspended processes resume */
558 GLSA_IGN=8, /* A signal that is ignored */
559 GLSA_CORE=16, /* A signal that generates a core dump */
560 GLSA_HARD=32, /* A signal generated by a hardware exception */
561 GLSA_SIZE=64 /* A signal indicating terminal size changes */
562 } GlSigAttr;
563
564 /*
565 * List the signals that we need to catch. In general these are
566 * those that by default terminate or suspend the process, since
567 * in such cases we need to restore terminal settings.
568 */
569 static const struct GlDefSignal {
570 int signo; /* The number of the signal */
571 unsigned flags; /* A bitwise union of GlSignalFlags enumerators */
572 GlAfterSignal after; /* What to do after the signal has been delivered */
573 int attr; /* The default attributes of this signal, expressed */
574 /* as a bitwise union of GlSigAttr enumerators */
575 int errno_value; /* What to set errno to */
576 } gl_signal_list[] = {
577 {SIGABRT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
578 {SIGALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
579 {SIGCONT, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_CONT|GLSA_IGN, 0},
580 #if defined(SIGHUP)
581 #ifdef ENOTTY
582 {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, ENOTTY},
583 #else
584 {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
585 #endif
586 #endif
587 {SIGINT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
588 #if defined(SIGPIPE)
589 #ifdef EPIPE
590 {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EPIPE},
591 #else
592 {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
593 #endif
594 #endif
595 #ifdef SIGPOLL
596 {SIGPOLL, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
597 #endif
598 #ifdef SIGPWR
599 {SIGPWR, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_IGN, 0},
600 #endif
601 #ifdef SIGQUIT
602 {SIGQUIT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
603 #endif
604 {SIGTERM, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
605 #ifdef SIGTSTP
606 {SIGTSTP, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
607 #endif
608 #ifdef SIGTTIN
609 {SIGTTIN, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
610 #endif
611 #ifdef SIGTTOU
612 {SIGTTOU, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
613 #endif
614 #ifdef SIGUSR1
615 {SIGUSR1, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
616 #endif
617 #ifdef SIGUSR2
618 {SIGUSR2, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
619 #endif
620 #ifdef SIGVTALRM
621 {SIGVTALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
622 #endif
623 #ifdef SIGWINCH
624 {SIGWINCH, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_SIZE|GLSA_IGN, 0},
625 #endif
626 #ifdef SIGXCPU
627 {SIGXCPU, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
628 #endif
629 #ifdef SIGXFSZ
630 {SIGXFSZ, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
631 #endif
632 };
633
634 /*
635 * Define file-scope variables for use in signal handlers.
636 */
637 static volatile sig_atomic_t gl_pending_signal = -1;
638 static sigjmp_buf gl_setjmp_buffer;
639
640 static void gl_signal_handler(int signo);
641
642 static int gl_check_caught_signal(GetLine *gl);
643
644 /*
645 * Respond to an externally caught process suspension or
646 * termination signal.
647 */
648 static void gl_suspend_process(int signo, GetLine *gl, int ngl);
649
650 /* Return the default attributes of a given signal */
651
652 static int gl_classify_signal(int signo);
653
654 /*
655 * Unfortunately both terminfo and termcap require one to use the tputs()
656 * function to output terminal control characters, and this function
657 * doesn't allow one to specify a file stream. As a result, the following
658 * file-scope variable is used to pass the current output file stream.
659 * This is bad, but there doesn't seem to be any alternative.
660 */
661 static GetLine *tputs_gl = NULL;
662
663 /*
664 * Define a tab to be a string of 8 spaces.
665 */
666 #define TAB_WIDTH 8
667
668 /*
669 * Lookup the current size of the terminal.
670 */
671 static void gl_query_size(GetLine *gl, int *ncolumn, int *nline);
672
673 /*
674 * Getline calls this to temporarily override certain signal handlers
675 * of the calling program.
676 */
677 static int gl_override_signal_handlers(GetLine *gl);
678
679 /*
680 * Getline calls this to restore the signal handlers of the calling
681 * program.
682 */
683 static int gl_restore_signal_handlers(GetLine *gl);
684
685 /*
686 * Temporarily block the delivery of all signals that gl_get_line()
687 * is currently configured to trap.
688 */
689 static int gl_mask_signals(GetLine *gl, sigset_t *oldset);
690
691 /*
692 * Restore the process signal mask that was overriden by a previous
693 * call to gl_mask_signals().
694 */
695 static int gl_unmask_signals(GetLine *gl, sigset_t *oldset);
696
697 /*
698 * Unblock the signals that gl_get_line() has been configured to catch.
699 */
700 static int gl_catch_signals(GetLine *gl);
701
702 /*
703 * Return the set of all trappable signals.
704 */
705 static void gl_list_trappable_signals(sigset_t *signals);
706
707 /*
708 * Put the terminal into raw input mode, after saving the original
709 * terminal attributes in gl->oldattr.
710 */
711 static int gl_raw_terminal_mode(GetLine *gl);
712
713 /*
714 * Restore the terminal attributes from gl->oldattr.
715 */
716 static int gl_restore_terminal_attributes(GetLine *gl);
717
718 /*
719 * Switch to non-blocking I/O if possible.
720 */
721 static int gl_nonblocking_io(GetLine *gl, int fd);
722
723 /*
724 * Switch to blocking I/O if possible.
725 */
726 static int gl_blocking_io(GetLine *gl, int fd);
727
728 /*
729 * Read a line from the user in raw mode.
730 */
731 static int gl_get_input_line(GetLine *gl, const char *prompt,
732 const char *start_line, int start_pos);
733
734 /*
735 * Query the user for a single character.
736 */
737 static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar);
738
739 /*
740 * Read input from a non-interactive input stream.
741 */
742 static int gl_read_stream_line(GetLine *gl);
743
744 /*
745 * Read a single character from a non-interactive input stream.
746 */
747 static int gl_read_stream_char(GetLine *gl);
748
749 /*
750 * Prepare to edit a new line.
751 */
752 static int gl_present_line(GetLine *gl, const char *prompt,
753 const char *start_line, int start_pos);
754
755 /*
756 * Reset all line-editing parameters for a new input line.
757 */
758 static void gl_reset_editor(GetLine *gl);
759
760 /*
761 * Handle the receipt of the potential start of a new key-sequence from
762 * the user.
763 */
764 static int gl_interpret_char(GetLine *gl, char c);
765
766 /*
767 * Bind a single control or meta character to an action.
768 */
769 static int gl_bind_control_char(GetLine *gl, KtBinder binder,
770 char c, const char *action);
771
772 /*
773 * Set up terminal-specific key bindings.
774 */
775 static int gl_bind_terminal_keys(GetLine *gl);
776
777 /*
778 * Lookup terminal control string and size information.
779 */
780 static int gl_control_strings(GetLine *gl, const char *term);
781
782 /*
783 * Wrappers around the terminfo and termcap functions that lookup
784 * strings in the terminal information databases.
785 */
786 #ifdef USE_TERMINFO
787 static const char *gl_tigetstr(GetLine *gl, const char *name);
788 #elif defined(USE_TERMCAP)
789 static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr);
790 #endif
791
792 /*
793 * Output a binary string directly to the terminal.
794 */
795 static int gl_print_raw_string(GetLine *gl, int buffered,
796 const char *string, int n);
797
798 /*
799 * Print an informational message, starting and finishing on new lines.
800 * After the list of strings to be printed, the last argument MUST be
801 * GL_END_INFO.
802 */
803 static int gl_print_info(GetLine *gl, ...);
804 #define GL_END_INFO ((const char *)0)
805
806 /*
807 * Start a newline and place the cursor at its start.
808 */
809 static int gl_start_newline(GetLine *gl, int buffered);
810
811 /*
812 * Output a terminal control sequence.
813 */
814 static int gl_print_control_sequence(GetLine *gl, int nline,
815 const char *string);
816
817 /*
818 * Output a character or string to the terminal after converting tabs
819 * to spaces and control characters to a caret followed by the modified
820 * character.
821 */
822 static int gl_print_char(GetLine *gl, char c, char pad);
823 static int gl_print_string(GetLine *gl, const char *string, char pad);
824
825 /*
826 * Delete nc characters starting from the one under the cursor.
827 * Optionally copy the deleted characters to the cut buffer.
828 */
829 static int gl_delete_chars(GetLine *gl, int nc, int cut);
830
831 /*
832 * Add a character to the line buffer at the current cursor position,
833 * inserting or overwriting according the current mode.
834 */
835 static int gl_add_char_to_line(GetLine *gl, char c);
836
837 /*
838 * Insert/append a string to the line buffer and terminal at the current
839 * cursor position.
840 */
841 static int gl_add_string_to_line(GetLine *gl, const char *s);
842
843 /*
844 * Record a new character in the input-line buffer.
845 */
846 static int gl_buffer_char(GetLine *gl, char c, int bufpos);
847
848 /*
849 * Record a string in the input-line buffer.
850 */
851 static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos);
852
853 /*
854 * Make way to insert a string in the input-line buffer.
855 */
856 static int gl_make_gap_in_buffer(GetLine *gl, int start, int n);
857
858 /*
859 * Remove characters from the input-line buffer, and move any characters
860 * that followed them to the start of the vacated space.
861 */
862 static void gl_remove_from_buffer(GetLine *gl, int start, int n);
863
864 /*
865 * Terminate the input-line buffer after a specified number of characters.
866 */
867 static int gl_truncate_buffer(GetLine *gl, int n);
868
869 /*
870 * Delete the displayed part of the input line that follows the current
871 * terminal cursor position.
872 */
873 static int gl_truncate_display(GetLine *gl);
874
875 /*
876 * Accomodate changes to the contents of the input line buffer
877 * that weren't made by the above gl_*buffer functions.
878 */
879 static void gl_update_buffer(GetLine *gl);
880
881 /*
882 * Read a single character from the terminal.
883 */
884 static int gl_read_terminal(GetLine *gl, int keep, char *c);
885
886 /*
887 * Discard processed characters from the key-press lookahead buffer.
888 */
889 static void gl_discard_chars(GetLine *gl, int nused);
890
891 /*
892 * Move the terminal cursor n positions to the left or right.
893 */
894 static int gl_terminal_move_cursor(GetLine *gl, int n);
895
896 /*
897 * Move the terminal cursor to a given position.
898 */
899 static int gl_set_term_curpos(GetLine *gl, int term_curpos);
900
901 /*
902 * Set the position of the cursor both in the line input buffer and on the
903 * terminal.
904 */
905 static int gl_place_cursor(GetLine *gl, int buff_curpos);
906
907 /*
908 * How many characters are needed to write a number as an octal string?
909 */
910 static int gl_octal_width(unsigned num);
911
912 /*
913 * Return the number of spaces needed to display a tab character at
914 * a given location of the terminal.
915 */
916 static int gl_displayed_tab_width(GetLine *gl, int term_curpos);
917
918 /*
919 * Return the number of terminal characters needed to display a
920 * given raw character.
921 */
922 static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos);
923
924 /*
925 * Return the number of terminal characters needed to display a
926 * given substring.
927 */
928 static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
929 int term_curpos);
930
931 /*
932 * Return non-zero if 'c' is to be considered part of a word.
933 */
934 static int gl_is_word_char(int c);
935
936 /*
937 * Read a tecla configuration file.
938 */
939 static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who);
940
941 /*
942 * Read a tecla configuration string.
943 */
944 static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who);
945
946 /*
947 * Define the callback function used by _gl_parse_config_line() to
948 * read the next character of a configuration stream.
949 */
950 #define GLC_GETC_FN(fn) int (fn)(void *stream)
951 typedef GLC_GETC_FN(GlcGetcFn);
952
953 static GLC_GETC_FN(glc_file_getc); /* Read from a file */
954 static GLC_GETC_FN(glc_buff_getc); /* Read from a string */
955
956 /*
957 * Parse a single configuration command line.
958 */
959 static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
960 const char *origin, KtBinder who, int *lineno);
961 static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
962 const char *errmsg);
963
964 /*
965 * Bind the actual arrow key bindings to match those of the symbolic
966 * arrow-key bindings.
967 */
968 static int _gl_bind_arrow_keys(GetLine *gl);
969
970 /*
971 * Copy the binding of the specified symbolic arrow-key binding to
972 * the terminal specific, and default arrow-key key-sequences.
973 */
974 static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
975 const char *term_seq,
976 const char *def_seq1,
977 const char *def_seq2);
978
979 /*
980 * After the gl_read_from_file() action has been used to tell gl_get_line()
981 * to temporarily read input from a file, gl_revert_input() arranges
982 * for input to be reverted to the input stream last registered with
983 * gl_change_terminal().
984 */
985 static void gl_revert_input(GetLine *gl);
986
987 /*
988 * Flush unwritten characters to the terminal.
989 */
990 static int gl_flush_output(GetLine *gl);
991
992 /*
993 * The callback through which all terminal output is routed.
994 * This simply appends characters to a queue buffer, which is
995 * subsequently flushed to the output channel by gl_flush_output().
996 */
997 static GL_WRITE_FN(gl_write_fn);
998
999 /*
1000 * The callback function which the output character queue object
1001 * calls to transfer characters to the output channel.
1002 */
1003 static GL_WRITE_FN(gl_flush_terminal);
1004
1005 /*
1006 * Enumerate the possible return statuses of gl_read_input().
1007 */
1008 typedef enum {
1009 GL_READ_OK, /* A character was read successfully */
1010 GL_READ_ERROR, /* A read-error occurred */
1011 GL_READ_BLOCKED, /* The read would have blocked the caller */
1012 GL_READ_EOF /* The end of the current input file was reached */
1013 } GlReadStatus;
1014
1015 static GlReadStatus gl_read_input(GetLine *gl, char *c);
1016 /*
1017 * Private functions of gl_read_input().
1018 */
1019 static int gl_event_handler(GetLine *gl, int fd);
1020 static GlReadStatus gl_read_unmasked(GetLine *gl, int fd, char *c);
1021
1022
1023 /*
1024 * A private function of gl_tty_signals().
1025 */
1026 static int gl_set_tty_signal(int signo, void (*handler)(int));
1027
1028 /*
1029 * Change the editor style being emulated.
1030 */
1031 static int gl_change_editor(GetLine *gl, GlEditor editor);
1032
1033 /*
1034 * Searching in a given direction, return the index of a given (or
1035 * read) character in the input line, or the character that precedes
1036 * it in the specified search direction. Return -1 if not found.
1037 */
1038 static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c);
1039
1040 /*
1041 * Return the buffer index of the nth word ending after the cursor.
1042 */
1043 static int gl_nth_word_end_forward(GetLine *gl, int n);
1044
1045 /*
1046 * Return the buffer index of the nth word start after the cursor.
1047 */
1048 static int gl_nth_word_start_forward(GetLine *gl, int n);
1049
1050 /*
1051 * Return the buffer index of the nth word start before the cursor.
1052 */
1053 static int gl_nth_word_start_backward(GetLine *gl, int n);
1054
1055 /*
1056 * When called when vi command mode is enabled, this function saves the
1057 * current line and cursor position for potential restoration later
1058 * by the vi undo command.
1059 */
1060 static void gl_save_for_undo(GetLine *gl);
1061
1062 /*
1063 * If in vi mode, switch to vi command mode.
1064 */
1065 static void gl_vi_command_mode(GetLine *gl);
1066
1067 /*
1068 * In vi mode this is used to delete up to or onto a given or read
1069 * character in the input line. Also switch to insert mode if requested
1070 * after the deletion.
1071 */
1072 static int gl_delete_find(GetLine *gl, int count, char c, int forward,
1073 int onto, int change);
1074
1075 /*
1076 * Copy the characters between the cursor and the count'th instance of
1077 * a specified (or read) character in the input line, into the cut buffer.
1078 */
1079 static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto);
1080
1081 /*
1082 * Return the line index of the parenthesis that either matches the one under
1083 * the cursor, or not over a parenthesis character, the index of the next
1084 * close parenthesis. Return -1 if not found.
1085 */
1086 static int gl_index_of_matching_paren(GetLine *gl);
1087
1088 /*
1089 * Replace a malloc'd string (or NULL), with another malloc'd copy of
1090 * a string (or NULL).
1091 */
1092 static int gl_record_string(char **sptr, const char *string);
1093
1094 /*
1095 * Enumerate text display attributes as powers of two, suitable for
1096 * use in a bit-mask.
1097 */
1098 typedef enum {
1099 GL_TXT_STANDOUT=1, /* Display text highlighted */
1100 GL_TXT_UNDERLINE=2, /* Display text underlined */
1101 GL_TXT_REVERSE=4, /* Display text with reverse video */
1102 GL_TXT_BLINK=8, /* Display blinking text */
1103 GL_TXT_DIM=16, /* Display text in a dim font */
1104 GL_TXT_BOLD=32 /* Display text using a bold font */
1105 } GlTextAttr;
1106
1107 /*
1108 * Display the prompt regardless of the current visibility mode.
1109 */
1110 static int gl_display_prompt(GetLine *gl);
1111
1112 /*
1113 * Return the number of characters used by the prompt on the terminal.
1114 */
1115 static int gl_displayed_prompt_width(GetLine *gl);
1116
1117 /*
1118 * Prepare to return the current input line to the caller of gl_get_line().
1119 */
1120 static int gl_line_ended(GetLine *gl, int newline_char);
1121
1122 /*
1123 * Arrange for the input line to be redisplayed when the current contents
1124 * of the output queue have been flushed.
1125 */
1126 static void gl_queue_redisplay(GetLine *gl);
1127
1128 /*
1129 * Erase the displayed representation of the input line, without
1130 * touching the buffered copy.
1131 */
1132 static int gl_erase_line(GetLine *gl);
1133
1134 /*
1135 * This function is called whenever the input line has been erased.
1136 */
1137 static void gl_line_erased(GetLine *gl);
1138
1139 /*
1140 * Arrange for the current input line to be discarded.
1141 */
1142 void _gl_abandon_line(GetLine *gl);
1143
1144 /*
1145 * The following are private internally callable versions of pertinent
1146 * public functions. Unlike their public wrapper functions, they don't
1147 * block signals while running, and assume that their arguments are valid.
1148 * They are designed to be called from places where signals are already
1149 * blocked, and where simple sanity checks have already been applied to
1150 * their arguments.
1151 */
1152 static char *_gl_get_line(GetLine *gl, const char *prompt,
1153 const char *start_line, int start_pos);
1154 static int _gl_query_char(GetLine *gl, const char *prompt, char defchar);
1155 static int _gl_read_char(GetLine *gl);
1156 static int _gl_update_size(GetLine *gl);
1157 /*
1158 * Redraw the current input line to account for a change in the terminal
1159 * size. Also install the new size in gl.
1160 */
1161 static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline);
1162
1163 static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
1164 const char *term);
1165 static int _gl_configure_getline(GetLine *gl, const char *app_string,
1166 const char *app_file, const char *user_file);
1167 static int _gl_save_history(GetLine *gl, const char *filename,
1168 const char *comment, int max_lines);
1169 static int _gl_load_history(GetLine *gl, const char *filename,
1170 const char *comment);
1171 static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
1172 GlFdEventFn *callback, void *data);
1173 static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
1174 GlTerminalSize *size);
1175 static void _gl_replace_prompt(GetLine *gl, const char *prompt);
1176 static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
1177 GlAfterSignal after, int errno_value);
1178 static int _gl_raw_io(GetLine *gl, int redisplay);
1179 static int _gl_normal_io(GetLine *gl);
1180 static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
1181 int list_only, const char *name,
1182 const char *keyseq);
1183 static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
1184 const char *name, const char *keyseq);
1185 static int _gl_io_mode(GetLine *gl, GlIOMode mode);
1186 static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline);
1187 static int _gl_append_history(GetLine *gl, const char *line);
1188
1189 /*
1190 * Reset the completion status and associated errno value in
1191 * gl->rtn_status and gl->rtn_errno.
1192 */
1193 static void gl_clear_status(GetLine *gl);
1194
1195 /*
1196 * Record a completion status, unless a previous abnormal completion
1197 * status has already been recorded for the current call.
1198 */
1199 static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
1200 int rtn_errno);
1201
1202 /*
1203 * Set the maximum length of a line in a user's tecla configuration
1204 * file (not counting comments).
1205 */
1206 #define GL_CONF_BUFLEN 100
1207
1208 /*
1209 * Set the maximum number of arguments supported by individual commands
1210 * in tecla configuration files.
1211 */
1212 #define GL_CONF_MAXARG 10
1213
1214 /*
1215 * Prototype the available action functions.
1216 */
1217 static KT_KEY_FN(gl_user_interrupt);
1218 static KT_KEY_FN(gl_abort);
1219 static KT_KEY_FN(gl_suspend);
1220 static KT_KEY_FN(gl_stop_output);
1221 static KT_KEY_FN(gl_start_output);
1222 static KT_KEY_FN(gl_literal_next);
1223 static KT_KEY_FN(gl_cursor_left);
1224 static KT_KEY_FN(gl_cursor_right);
1225 static KT_KEY_FN(gl_insert_mode);
1226 static KT_KEY_FN(gl_beginning_of_line);
1227 static KT_KEY_FN(gl_end_of_line);
1228 static KT_KEY_FN(gl_delete_line);
1229 static KT_KEY_FN(gl_kill_line);
1230 static KT_KEY_FN(gl_forward_word);
1231 static KT_KEY_FN(gl_backward_word);
1232 static KT_KEY_FN(gl_forward_delete_char);
1233 static KT_KEY_FN(gl_backward_delete_char);
1234 static KT_KEY_FN(gl_forward_delete_word);
1235 static KT_KEY_FN(gl_backward_delete_word);
1236 static KT_KEY_FN(gl_delete_refind);
1237 static KT_KEY_FN(gl_delete_invert_refind);
1238 static KT_KEY_FN(gl_delete_to_column);
1239 static KT_KEY_FN(gl_delete_to_parenthesis);
1240 static KT_KEY_FN(gl_forward_delete_find);
1241 static KT_KEY_FN(gl_backward_delete_find);
1242 static KT_KEY_FN(gl_forward_delete_to);
1243 static KT_KEY_FN(gl_backward_delete_to);
1244 static KT_KEY_FN(gl_upcase_word);
1245 static KT_KEY_FN(gl_downcase_word);
1246 static KT_KEY_FN(gl_capitalize_word);
1247 static KT_KEY_FN(gl_redisplay);
1248 static KT_KEY_FN(gl_clear_screen);
1249 static KT_KEY_FN(gl_transpose_chars);
1250 static KT_KEY_FN(gl_set_mark);
1251 static KT_KEY_FN(gl_exchange_point_and_mark);
1252 static KT_KEY_FN(gl_kill_region);
1253 static KT_KEY_FN(gl_copy_region_as_kill);
1254 static KT_KEY_FN(gl_yank);
1255 static KT_KEY_FN(gl_up_history);
1256 static KT_KEY_FN(gl_down_history);
1257 static KT_KEY_FN(gl_history_search_backward);
1258 static KT_KEY_FN(gl_history_re_search_backward);
1259 static KT_KEY_FN(gl_history_search_forward);
1260 static KT_KEY_FN(gl_history_re_search_forward);
1261 static KT_KEY_FN(gl_complete_word);
1262 #ifndef HIDE_FILE_SYSTEM
1263 static KT_KEY_FN(gl_expand_filename);
1264 static KT_KEY_FN(gl_read_from_file);
1265 static KT_KEY_FN(gl_read_init_files);
1266 static KT_KEY_FN(gl_list_glob);
1267 #endif
1268 static KT_KEY_FN(gl_del_char_or_list_or_eof);
1269 static KT_KEY_FN(gl_list_or_eof);
1270 static KT_KEY_FN(gl_beginning_of_history);
1271 static KT_KEY_FN(gl_end_of_history);
1272 static KT_KEY_FN(gl_digit_argument);
1273 static KT_KEY_FN(gl_newline);
1274 static KT_KEY_FN(gl_repeat_history);
1275 static KT_KEY_FN(gl_vi_insert);
1276 static KT_KEY_FN(gl_vi_overwrite);
1277 static KT_KEY_FN(gl_change_case);
1278 static KT_KEY_FN(gl_vi_insert_at_bol);
1279 static KT_KEY_FN(gl_vi_append_at_eol);
1280 static KT_KEY_FN(gl_vi_append);
1281 static KT_KEY_FN(gl_backward_kill_line);
1282 static KT_KEY_FN(gl_goto_column);
1283 static KT_KEY_FN(gl_forward_to_word);
1284 static KT_KEY_FN(gl_vi_replace_char);
1285 static KT_KEY_FN(gl_vi_change_rest_of_line);
1286 static KT_KEY_FN(gl_vi_change_line);
1287 static KT_KEY_FN(gl_vi_change_to_bol);
1288 static KT_KEY_FN(gl_vi_change_refind);
1289 static KT_KEY_FN(gl_vi_change_invert_refind);
1290 static KT_KEY_FN(gl_vi_change_to_column);
1291 static KT_KEY_FN(gl_vi_change_to_parenthesis);
1292 static KT_KEY_FN(gl_vi_forward_change_word);
1293 static KT_KEY_FN(gl_vi_backward_change_word);
1294 static KT_KEY_FN(gl_vi_forward_change_find);
1295 static KT_KEY_FN(gl_vi_backward_change_find);
1296 static KT_KEY_FN(gl_vi_forward_change_to);
1297 static KT_KEY_FN(gl_vi_backward_change_to);
1298 static KT_KEY_FN(gl_vi_forward_change_char);
1299 static KT_KEY_FN(gl_vi_backward_change_char);
1300 static KT_KEY_FN(gl_forward_copy_char);
1301 static KT_KEY_FN(gl_backward_copy_char);
1302 static KT_KEY_FN(gl_forward_find_char);
1303 static KT_KEY_FN(gl_backward_find_char);
1304 static KT_KEY_FN(gl_forward_to_char);
1305 static KT_KEY_FN(gl_backward_to_char);
1306 static KT_KEY_FN(gl_repeat_find_char);
1307 static KT_KEY_FN(gl_invert_refind_char);
1308 static KT_KEY_FN(gl_append_yank);
1309 static KT_KEY_FN(gl_backward_copy_word);
1310 static KT_KEY_FN(gl_forward_copy_word);
1311 static KT_KEY_FN(gl_copy_to_bol);
1312 static KT_KEY_FN(gl_copy_refind);
1313 static KT_KEY_FN(gl_copy_invert_refind);
1314 static KT_KEY_FN(gl_copy_to_column);
1315 static KT_KEY_FN(gl_copy_to_parenthesis);
1316 static KT_KEY_FN(gl_copy_rest_of_line);
1317 static KT_KEY_FN(gl_copy_line);
1318 static KT_KEY_FN(gl_backward_copy_find);
1319 static KT_KEY_FN(gl_forward_copy_find);
1320 static KT_KEY_FN(gl_backward_copy_to);
1321 static KT_KEY_FN(gl_forward_copy_to);
1322 static KT_KEY_FN(gl_vi_undo);
1323 static KT_KEY_FN(gl_emacs_editing_mode);
1324 static KT_KEY_FN(gl_vi_editing_mode);
1325 static KT_KEY_FN(gl_ring_bell);
1326 static KT_KEY_FN(gl_vi_repeat_change);
1327 static KT_KEY_FN(gl_find_parenthesis);
1328 static KT_KEY_FN(gl_list_history);
1329 static KT_KEY_FN(gl_list_completions);
1330 static KT_KEY_FN(gl_run_external_action);
1331
1332 /*
1333 * Name the available action functions.
1334 */
1335 static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = {
1336 {"user-interrupt", gl_user_interrupt},
1337 {"abort", gl_abort},
1338 {"suspend", gl_suspend},
1339 {"stop-output", gl_stop_output},
1340 {"start-output", gl_start_output},
1341 {"literal-next", gl_literal_next},
1342 {"cursor-right", gl_cursor_right},
1343 {"cursor-left", gl_cursor_left},
1344 {"insert-mode", gl_insert_mode},
1345 {"beginning-of-line", gl_beginning_of_line},
1346 {"end-of-line", gl_end_of_line},
1347 {"delete-line", gl_delete_line},
1348 {"kill-line", gl_kill_line},
1349 {"forward-word", gl_forward_word},
1350 {"backward-word", gl_backward_word},
1351 {"forward-delete-char", gl_forward_delete_char},
1352 {"backward-delete-char", gl_backward_delete_char},
1353 {"forward-delete-word", gl_forward_delete_word},
1354 {"backward-delete-word", gl_backward_delete_word},
1355 {"delete-refind", gl_delete_refind},
1356 {"delete-invert-refind", gl_delete_invert_refind},
1357 {"delete-to-column", gl_delete_to_column},
1358 {"delete-to-parenthesis", gl_delete_to_parenthesis},
1359 {"forward-delete-find", gl_forward_delete_find},
1360 {"backward-delete-find", gl_backward_delete_find},
1361 {"forward-delete-to", gl_forward_delete_to},
1362 {"backward-delete-to", gl_backward_delete_to},
1363 {"upcase-word", gl_upcase_word},
1364 {"downcase-word", gl_downcase_word},
1365 {"capitalize-word", gl_capitalize_word},
1366 {"redisplay", gl_redisplay},
1367 {"clear-screen", gl_clear_screen},
1368 {"transpose-chars", gl_transpose_chars},
1369 {"set-mark", gl_set_mark},
1370 {"exchange-point-and-mark", gl_exchange_point_and_mark},
1371 {"kill-region", gl_kill_region},
1372 {"copy-region-as-kill", gl_copy_region_as_kill},
1373 {"yank", gl_yank},
1374 {"up-history", gl_up_history},
1375 {"down-history", gl_down_history},
1376 {"history-search-backward", gl_history_search_backward},
1377 {"history-re-search-backward", gl_history_re_search_backward},
1378 {"history-search-forward", gl_history_search_forward},
1379 {"history-re-search-forward", gl_history_re_search_forward},
1380 {"complete-word", gl_complete_word},
1381 #ifndef HIDE_FILE_SYSTEM
1382 {"expand-filename", gl_expand_filename},
1383 {"read-from-file", gl_read_from_file},
1384 {"read-init-files", gl_read_init_files},
1385 {"list-glob", gl_list_glob},
1386 #endif
1387 {"del-char-or-list-or-eof", gl_del_char_or_list_or_eof},
1388 {"beginning-of-history", gl_beginning_of_history},
1389 {"end-of-history", gl_end_of_history},
1390 {"digit-argument", gl_digit_argument},
1391 {"newline", gl_newline},
1392 {"repeat-history", gl_repeat_history},
1393 {"vi-insert", gl_vi_insert},
1394 {"vi-overwrite", gl_vi_overwrite},
1395 {"vi-insert-at-bol", gl_vi_insert_at_bol},
1396 {"vi-append-at-eol", gl_vi_append_at_eol},
1397 {"vi-append", gl_vi_append},
1398 {"change-case", gl_change_case},
1399 {"backward-kill-line", gl_backward_kill_line},
1400 {"goto-column", gl_goto_column},
1401 {"forward-to-word", gl_forward_to_word},
1402 {"vi-replace-char", gl_vi_replace_char},
1403 {"vi-change-rest-of-line", gl_vi_change_rest_of_line},
1404 {"vi-change-line", gl_vi_change_line},
1405 {"vi-change-to-bol", gl_vi_change_to_bol},
1406 {"vi-change-refind", gl_vi_change_refind},
1407 {"vi-change-invert-refind", gl_vi_change_invert_refind},
1408 {"vi-change-to-column", gl_vi_change_to_column},
1409 {"vi-change-to-parenthesis", gl_vi_change_to_parenthesis},
1410 {"forward-copy-char", gl_forward_copy_char},
1411 {"backward-copy-char", gl_backward_copy_char},
1412 {"forward-find-char", gl_forward_find_char},
1413 {"backward-find-char", gl_backward_find_char},
1414 {"forward-to-char", gl_forward_to_char},
1415 {"backward-to-char", gl_backward_to_char},
1416 {"repeat-find-char", gl_repeat_find_char},
1417 {"invert-refind-char", gl_invert_refind_char},
1418 {"append-yank", gl_append_yank},
1419 {"backward-copy-word", gl_backward_copy_word},
1420 {"forward-copy-word", gl_forward_copy_word},
1421 {"copy-to-bol", gl_copy_to_bol},
1422 {"copy-refind", gl_copy_refind},
1423 {"copy-invert-refind", gl_copy_invert_refind},
1424 {"copy-to-column", gl_copy_to_column},
1425 {"copy-to-parenthesis", gl_copy_to_parenthesis},
1426 {"copy-rest-of-line", gl_copy_rest_of_line},
1427 {"copy-line", gl_copy_line},
1428 {"backward-copy-find", gl_backward_copy_find},
1429 {"forward-copy-find", gl_forward_copy_find},
1430 {"backward-copy-to", gl_backward_copy_to},
1431 {"forward-copy-to", gl_forward_copy_to},
1432 {"list-or-eof", gl_list_or_eof},
1433 {"vi-undo", gl_vi_undo},
1434 {"vi-backward-change-word", gl_vi_backward_change_word},
1435 {"vi-forward-change-word", gl_vi_forward_change_word},
1436 {"vi-backward-change-find", gl_vi_backward_change_find},
1437 {"vi-forward-change-find", gl_vi_forward_change_find},
1438 {"vi-backward-change-to", gl_vi_backward_change_to},
1439 {"vi-forward-change-to", gl_vi_forward_change_to},
1440 {"vi-backward-change-char", gl_vi_backward_change_char},
1441 {"vi-forward-change-char", gl_vi_forward_change_char},
1442 {"emacs-mode", gl_emacs_editing_mode},
1443 {"vi-mode", gl_vi_editing_mode},
1444 {"ring-bell", gl_ring_bell},
1445 {"vi-repeat-change", gl_vi_repeat_change},
1446 {"find-parenthesis", gl_find_parenthesis},
1447 {"list-history", gl_list_history},
1448 };
1449
1450 /*
1451 * Define the default key-bindings in emacs mode.
1452 */
1453 static const KtKeyBinding gl_emacs_bindings[] = {
1454 {"right", "cursor-right"},
1455 {"^F", "cursor-right"},
1456 {"left", "cursor-left"},
1457 {"^B", "cursor-left"},
1458 {"M-i", "insert-mode"},
1459 {"M-I", "insert-mode"},
1460 {"^A", "beginning-of-line"},
1461 {"^E", "end-of-line"},
1462 {"^U", "delete-line"},
1463 {"^K", "kill-line"},
1464 {"M-f", "forward-word"},
1465 {"M-F", "forward-word"},
1466 {"M-b", "backward-word"},
1467 {"M-B", "backward-word"},
1468 {"^D", "del-char-or-list-or-eof"},
1469 {"^H", "backward-delete-char"},
1470 {"^?", "backward-delete-char"},
1471 {"M-d", "forward-delete-word"},
1472 {"M-D", "forward-delete-word"},
1473 {"M-^H", "backward-delete-word"},
1474 {"M-^?", "backward-delete-word"},
1475 {"M-u", "upcase-word"},
1476 {"M-U", "upcase-word"},
1477 {"M-l", "downcase-word"},
1478 {"M-L", "downcase-word"},
1479 {"M-c", "capitalize-word"},
1480 {"M-C", "capitalize-word"},
1481 {"^R", "redisplay"},
1482 {"^L", "clear-screen"},
1483 {"^T", "transpose-chars"},
1484 {"^@", "set-mark"},
1485 {"^X^X", "exchange-point-and-mark"},
1486 {"^W", "kill-region"},
1487 {"M-w", "copy-region-as-kill"},
1488 {"M-W", "copy-region-as-kill"},
1489 {"^Y", "yank"},
1490 {"^P", "up-history"},
1491 {"up", "up-history"},
1492 {"^N", "down-history"},
1493 {"down", "down-history"},
1494 {"M-p", "history-search-backward"},
1495 {"M-P", "history-search-backward"},
1496 {"M-n", "history-search-forward"},
1497 {"M-N", "history-search-forward"},
1498 {"\t", "complete-word"},
1499 #ifndef HIDE_FILE_SYSTEM
1500 {"^X*", "expand-filename"},
1501 {"^X^F", "read-from-file"},
1502 {"^X^R", "read-init-files"},
1503 {"^Xg", "list-glob"},
1504 {"^XG", "list-glob"},
1505 #endif
1506 {"^Xh", "list-history"},
1507 {"^XH", "list-history"},
1508 {"M-<", "beginning-of-history"},
1509 {"M->", "end-of-history"},
1510 {"M-0", "digit-argument"},
1511 {"M-1", "digit-argument"},
1512 {"M-2", "digit-argument"},
1513 {"M-3", "digit-argument"},
1514 {"M-4", "digit-argument"},
1515 {"M-5", "digit-argument"},
1516 {"M-6", "digit-argument"},
1517 {"M-7", "digit-argument"},
1518 {"M-8", "digit-argument"},
1519 {"M-9", "digit-argument"},
1520 {"\r", "newline"},
1521 {"\n", "newline"},
1522 {"M-o", "repeat-history"},
1523 {"M-C-v", "vi-mode"},
1524 };
1525
1526 /*
1527 * Define the default key-bindings in vi mode. Note that in vi-mode
1528 * meta-key bindings are command-mode bindings. For example M-i first
1529 * switches to command mode if not already in that mode, then moves
1530 * the cursor one position right, as in vi.
1531 */
1532 static const KtKeyBinding gl_vi_bindings[] = {
1533 {"^D", "list-or-eof"},
1534 #ifndef HIDE_FILE_SYSTEM
1535 {"^G", "list-glob"},
1536 #endif
1537 {"^H", "backward-delete-char"},
1538 {"\t", "complete-word"},
1539 {"\r", "newline"},
1540 {"\n", "newline"},
1541 {"^L", "clear-screen"},
1542 {"^N", "down-history"},
1543 {"^P", "up-history"},
1544 {"^R", "redisplay"},
1545 {"^U", "backward-kill-line"},
1546 {"^W", "backward-delete-word"},
1547 #ifndef HIDE_FILE_SYSTEM
1548 {"^X^F", "read-from-file"},
1549 {"^X^R", "read-init-files"},
1550 {"^X*", "expand-filename"},
1551 #endif
1552 {"^?", "backward-delete-char"},
1553 {"M- ", "cursor-right"},
1554 {"M-$", "end-of-line"},
1555 #ifndef HIDE_FILE_SYSTEM
1556 {"M-*", "expand-filename"},
1557 #endif
1558 {"M-+", "down-history"},
1559 {"M--", "up-history"},
1560 {"M-<", "beginning-of-history"},
1561 {"M->", "end-of-history"},
1562 {"M-^", "beginning-of-line"},
1563 {"M-;", "repeat-find-char"},
1564 {"M-,", "invert-refind-char"},
1565 {"M-|", "goto-column"},
1566 {"M-~", "change-case"},
1567 {"M-.", "vi-repeat-change"},
1568 {"M-%", "find-parenthesis"},
1569 {"M-0", "digit-argument"},
1570 {"M-1", "digit-argument"},
1571 {"M-2", "digit-argument"},
1572 {"M-3", "digit-argument"},
1573 {"M-4", "digit-argument"},
1574 {"M-5", "digit-argument"},
1575 {"M-6", "digit-argument"},
1576 {"M-7", "digit-argument"},
1577 {"M-8", "digit-argument"},
1578 {"M-9", "digit-argument"},
1579 {"M-a", "vi-append"},
1580 {"M-A", "vi-append-at-eol"},
1581 {"M-b", "backward-word"},
1582 {"M-B", "backward-word"},
1583 {"M-C", "vi-change-rest-of-line"},
1584 {"M-cb", "vi-backward-change-word"},
1585 {"M-cB", "vi-backward-change-word"},
1586 {"M-cc", "vi-change-line"},
1587 {"M-ce", "vi-forward-change-word"},
1588 {"M-cE", "vi-forward-change-word"},
1589 {"M-cw", "vi-forward-change-word"},
1590 {"M-cW", "vi-forward-change-word"},
1591 {"M-cF", "vi-backward-change-find"},
1592 {"M-cf", "vi-forward-change-find"},
1593 {"M-cT", "vi-backward-change-to"},
1594 {"M-ct", "vi-forward-change-to"},
1595 {"M-c;", "vi-change-refind"},
1596 {"M-c,", "vi-change-invert-refind"},
1597 {"M-ch", "vi-backward-change-char"},
1598 {"M-c^H", "vi-backward-change-char"},
1599 {"M-c^?", "vi-backward-change-char"},
1600 {"M-cl", "vi-forward-change-char"},
1601 {"M-c ", "vi-forward-change-char"},
1602 {"M-c^", "vi-change-to-bol"},
1603 {"M-c0", "vi-change-to-bol"},
1604 {"M-c$", "vi-change-rest-of-line"},
1605 {"M-c|", "vi-change-to-column"},
1606 {"M-c%", "vi-change-to-parenthesis"},
1607 {"M-dh", "backward-delete-char"},
1608 {"M-d^H", "backward-delete-char"},
1609 {"M-d^?", "backward-delete-char"},
1610 {"M-dl", "forward-delete-char"},
1611 {"M-d ", "forward-delete-char"},
1612 {"M-dd", "delete-line"},
1613 {"M-db", "backward-delete-word"},
1614 {"M-dB", "backward-delete-word"},
1615 {"M-de", "forward-delete-word"},
1616 {"M-dE", "forward-delete-word"},
1617 {"M-dw", "forward-delete-word"},
1618 {"M-dW", "forward-delete-word"},
1619 {"M-dF", "backward-delete-find"},
1620 {"M-df", "forward-delete-find"},
1621 {"M-dT", "backward-delete-to"},
1622 {"M-dt", "forward-delete-to"},
1623 {"M-d;", "delete-refind"},
1624 {"M-d,", "delete-invert-refind"},
1625 {"M-d^", "backward-kill-line"},
1626 {"M-d0", "backward-kill-line"},
1627 {"M-d$", "kill-line"},
1628 {"M-D", "kill-line"},
1629 {"M-d|", "delete-to-column"},
1630 {"M-d%", "delete-to-parenthesis"},
1631 {"M-e", "forward-word"},
1632 {"M-E", "forward-word"},
1633 {"M-f", "forward-find-char"},
1634 {"M-F", "backward-find-char"},
1635 {"M--", "up-history"},
1636 {"M-h", "cursor-left"},
1637 {"M-H", "beginning-of-history"},
1638 {"M-i", "vi-insert"},
1639 {"M-I", "vi-insert-at-bol"},
1640 {"M-j", "down-history"},
1641 {"M-J", "history-search-forward"},
1642 {"M-k", "up-history"},
1643 {"M-K", "history-search-backward"},
1644 {"M-l", "cursor-right"},
1645 {"M-L", "end-of-history"},
1646 {"M-n", "history-re-search-forward"},
1647 {"M-N", "history-re-search-backward"},
1648 {"M-p", "append-yank"},
1649 {"M-P", "yank"},
1650 {"M-r", "vi-replace-char"},
1651 {"M-R", "vi-overwrite"},
1652 {"M-s", "vi-forward-change-char"},
1653 {"M-S", "vi-change-line"},
1654 {"M-t", "forward-to-char"},
1655 {"M-T", "backward-to-char"},
1656 {"M-u", "vi-undo"},
1657 {"M-w", "forward-to-word"},
1658 {"M-W", "forward-to-word"},
1659 {"M-x", "forward-delete-char"},
1660 {"M-X", "backward-delete-char"},
1661 {"M-yh", "backward-copy-char"},
1662 {"M-y^H", "backward-copy-char"},
1663 {"M-y^?", "backward-copy-char"},
1664 {"M-yl", "forward-copy-char"},
1665 {"M-y ", "forward-copy-char"},
1666 {"M-ye", "forward-copy-word"},
1667 {"M-yE", "forward-copy-word"},
1668 {"M-yw", "forward-copy-word"},
1669 {"M-yW", "forward-copy-word"},
1670 {"M-yb", "backward-copy-word"},
1671 {"M-yB", "backward-copy-word"},
1672 {"M-yf", "forward-copy-find"},
1673 {"M-yF", "backward-copy-find"},
1674 {"M-yt", "forward-copy-to"},
1675 {"M-yT", "backward-copy-to"},
1676 {"M-y;", "copy-refind"},
1677 {"M-y,", "copy-invert-refind"},
1678 {"M-y^", "copy-to-bol"},
1679 {"M-y0", "copy-to-bol"},
1680 {"M-y$", "copy-rest-of-line"},
1681 {"M-yy", "copy-line"},
1682 {"M-Y", "copy-line"},
1683 {"M-y|", "copy-to-column"},
1684 {"M-y%", "copy-to-parenthesis"},
1685 {"M-^E", "emacs-mode"},
1686 {"M-^H", "cursor-left"},
1687 {"M-^?", "cursor-left"},
1688 {"M-^L", "clear-screen"},
1689 {"M-^N", "down-history"},
1690 {"M-^P", "up-history"},
1691 {"M-^R", "redisplay"},
1692 {"M-^D", "list-or-eof"},
1693 {"M-\r", "newline"},
1694 {"M-\t", "complete-word"},
1695 {"M-\n", "newline"},
1696 #ifndef HIDE_FILE_SYSTEM
1697 {"M-^X^R", "read-init-files"},
1698 #endif
1699 {"M-^Xh", "list-history"},
1700 {"M-^XH", "list-history"},
1701 {"down", "down-history"},
1702 {"up", "up-history"},
1703 {"left", "cursor-left"},
1704 {"right", "cursor-right"},
1705 };
1706
1707 /*.......................................................................
1708 * Create a new GetLine object.
1709 *
1710 * Input:
1711 * linelen size_t The maximum line length to allow for.
1712 * histlen size_t The number of bytes to allocate for recording
1713 * a circular buffer of history lines.
1714 * Output:
1715 * return GetLine * The new object, or NULL on error.
1716 */
new_GetLine(size_t linelen,size_t histlen)1717 GetLine *new_GetLine(size_t linelen, size_t histlen)
1718 {
1719 GetLine *gl; /* The object to be returned */
1720 int i;
1721 /*
1722 * Check the arguments.
1723 */
1724 if(linelen < 10) {
1725 errno = ENOMEM;
1726 return NULL;
1727 };
1728 /*
1729 * Allocate the container.
1730 */
1731 gl = (GetLine *) malloc(sizeof(GetLine));
1732 if(!gl) {
1733 errno = ENOMEM;
1734 return NULL;
1735 };
1736 /*
1737 * Before attempting any operation that might fail, initialize the
1738 * container at least up to the point at which it can safely be passed
1739 * to del_GetLine().
1740 */
1741 gl->err = NULL;
1742 gl->glh = NULL;
1743 gl->cpl = NULL;
1744 #ifndef HIDE_FILE_SYSTEM
1745 gl->cplfn.fn = cpl_file_completions;
1746 #else
1747 gl->cplfn.fn = gl_no_completions;
1748 #endif
1749 gl->cplfn.data = NULL;
1750 #ifndef WITHOUT_FILE_SYSTEM
1751 gl->ef = NULL;
1752 #endif
1753 gl->capmem = NULL;
1754 gl->cq = NULL;
1755 gl->input_fd = -1;
1756 gl->output_fd = -1;
1757 gl->input_fp = NULL;
1758 gl->output_fp = NULL;
1759 gl->file_fp = NULL;
1760 gl->term = NULL;
1761 gl->is_term = 0;
1762 gl->flush_fn = gl_flush_terminal;
1763 gl->io_mode = GL_NORMAL_MODE;
1764 gl->raw_mode = 0;
1765 gl->pending_io = GLP_WRITE; /* We will start by writing the prompt */
1766 gl_clear_status(gl);
1767 gl->linelen = linelen;
1768 gl->line = NULL;
1769 gl->cutbuf = NULL;
1770 gl->prompt = NULL;
1771 gl->prompt_len = 0;
1772 gl->prompt_changed = 0;
1773 gl->prompt_style = GL_LITERAL_PROMPT;
1774 gl->cpl_mem = NULL;
1775 gl->ext_act_mem = NULL;
1776 gl->sig_mem = NULL;
1777 gl->sigs = NULL;
1778 gl->signals_masked = 0;
1779 gl->signals_overriden = 0;
1780 sigemptyset(&gl->all_signal_set);
1781 sigemptyset(&gl->old_signal_set);
1782 sigemptyset(&gl->use_signal_set);
1783 gl->bindings = NULL;
1784 gl->ntotal = 0;
1785 gl->buff_curpos = 0;
1786 gl->term_curpos = 0;
1787 gl->term_len = 0;
1788 gl->buff_mark = 0;
1789 gl->insert_curpos = 0;
1790 gl->insert = 1;
1791 gl->number = -1;
1792 gl->endline = 1;
1793 gl->displayed = 0;
1794 gl->redisplay = 0;
1795 gl->postpone = 0;
1796 gl->keybuf[0]='\0';
1797 gl->nbuf = 0;
1798 gl->nread = 0;
1799 gl->current_action.fn = 0;
1800 gl->current_action.data = NULL;
1801 gl->current_count = 0;
1802 gl->preload_id = 0;
1803 gl->preload_history = 0;
1804 gl->keyseq_count = 0;
1805 gl->last_search = -1;
1806 gl->editor = GL_EMACS_MODE;
1807 gl->silence_bell = 0;
1808 gl->automatic_history = 1;
1809 gl->vi.undo.line = NULL;
1810 gl->vi.undo.buff_curpos = 0;
1811 gl->vi.undo.ntotal = 0;
1812 gl->vi.undo.saved = 0;
1813 gl->vi.repeat.action.fn = 0;
1814 gl->vi.repeat.action.data = 0;
1815 gl->vi.repeat.count = 0;
1816 gl->vi.repeat.input_curpos = 0;
1817 gl->vi.repeat.command_curpos = 0;
1818 gl->vi.repeat.input_char = '\0';
1819 gl->vi.repeat.saved = 0;
1820 gl->vi.repeat.active = 0;
1821 gl->vi.command = 0;
1822 gl->vi.find_forward = 0;
1823 gl->vi.find_onto = 0;
1824 gl->vi.find_char = '\0';
1825 gl->left = NULL;
1826 gl->right = NULL;
1827 gl->up = NULL;
1828 gl->down = NULL;
1829 gl->home = NULL;
1830 gl->bol = 0;
1831 gl->clear_eol = NULL;
1832 gl->clear_eod = NULL;
1833 gl->u_arrow = NULL;
1834 gl->d_arrow = NULL;
1835 gl->l_arrow = NULL;
1836 gl->r_arrow = NULL;
1837 gl->sound_bell = NULL;
1838 gl->bold = NULL;
1839 gl->underline = NULL;
1840 gl->standout = NULL;
1841 gl->dim = NULL;
1842 gl->reverse = NULL;
1843 gl->blink = NULL;
1844 gl->text_attr_off = NULL;
1845 gl->nline = 0;
1846 gl->ncolumn = 0;
1847 #ifdef USE_TERMINFO
1848 gl->left_n = NULL;
1849 gl->right_n = NULL;
1850 #elif defined(USE_TERMCAP)
1851 gl->tgetent_buf = NULL;
1852 gl->tgetstr_buf = NULL;
1853 #endif
1854 gl->app_file = NULL;
1855 gl->user_file = NULL;
1856 gl->configured = 0;
1857 gl->echo = 1;
1858 gl->last_signal = -1;
1859 #ifdef HAVE_SELECT
1860 gl->fd_node_mem = NULL;
1861 gl->fd_nodes = NULL;
1862 FD_ZERO(&gl->rfds);
1863 FD_ZERO(&gl->wfds);
1864 FD_ZERO(&gl->ufds);
1865 gl->max_fd = 0;
1866 gl->timer.dt.tv_sec = 0;
1867 gl->timer.dt.tv_usec = 0;
1868 gl->timer.fn = 0;
1869 gl->timer.data = NULL;
1870 #endif
1871 /*
1872 * Allocate an error reporting buffer.
1873 */
1874 gl->err = _new_ErrMsg();
1875 if(!gl->err)
1876 return del_GetLine(gl);
1877 /*
1878 * Allocate the history buffer.
1879 */
1880 gl->glh = _new_GlHistory(histlen);
1881 if(!gl->glh)
1882 return del_GetLine(gl);
1883 /*
1884 * Allocate the resource object for file-completion.
1885 */
1886 gl->cpl = new_WordCompletion();
1887 if(!gl->cpl)
1888 return del_GetLine(gl);
1889 /*
1890 * Allocate the resource object for file-completion.
1891 */
1892 #ifndef WITHOUT_FILE_SYSTEM
1893 gl->ef = new_ExpandFile();
1894 if(!gl->ef)
1895 return del_GetLine(gl);
1896 #endif
1897 /*
1898 * Allocate a string-segment memory allocator for use in storing terminal
1899 * capablity strings.
1900 */
1901 gl->capmem = _new_StringGroup(CAPMEM_SEGMENT_SIZE);
1902 if(!gl->capmem)
1903 return del_GetLine(gl);
1904 /*
1905 * Allocate the character queue that is used to buffer terminal output.
1906 */
1907 gl->cq = _new_GlCharQueue();
1908 if(!gl->cq)
1909 return del_GetLine(gl);
1910 /*
1911 * Allocate a line buffer, leaving 2 extra characters for the terminating
1912 * '\n' and '\0' characters
1913 */
1914 gl->line = (char *) malloc(linelen + 2);
1915 if(!gl->line) {
1916 errno = ENOMEM;
1917 return del_GetLine(gl);
1918 };
1919 /*
1920 * Start with an empty input line.
1921 */
1922 gl_truncate_buffer(gl, 0);
1923 /*
1924 * Allocate a cut buffer.
1925 */
1926 gl->cutbuf = (char *) malloc(linelen + 2);
1927 if(!gl->cutbuf) {
1928 errno = ENOMEM;
1929 return del_GetLine(gl);
1930 };
1931 gl->cutbuf[0] = '\0';
1932 /*
1933 * Allocate an initial empty prompt.
1934 */
1935 _gl_replace_prompt(gl, NULL);
1936 if(!gl->prompt) {
1937 errno = ENOMEM;
1938 return del_GetLine(gl);
1939 };
1940 /*
1941 * Allocate a vi undo buffer.
1942 */
1943 gl->vi.undo.line = (char *) malloc(linelen + 2);
1944 if(!gl->vi.undo.line) {
1945 errno = ENOMEM;
1946 return del_GetLine(gl);
1947 };
1948 gl->vi.undo.line[0] = '\0';
1949 /*
1950 * Allocate a freelist from which to allocate nodes for the list
1951 * of completion functions.
1952 */
1953 gl->cpl_mem = _new_FreeList(sizeof(GlCplCallback), GL_CPL_FREELIST_BLOCKING);
1954 if(!gl->cpl_mem)
1955 return del_GetLine(gl);
1956 /*
1957 * Allocate a freelist from which to allocate nodes for the list
1958 * of external action functions.
1959 */
1960 gl->ext_act_mem = _new_FreeList(sizeof(GlExternalAction),
1961 GL_EXT_ACT_FREELIST_BLOCKING);
1962 if(!gl->ext_act_mem)
1963 return del_GetLine(gl);
1964 /*
1965 * Allocate a freelist from which to allocate nodes for the list
1966 * of signals.
1967 */
1968 gl->sig_mem = _new_FreeList(sizeof(GlSignalNode), GLS_FREELIST_BLOCKING);
1969 if(!gl->sig_mem)
1970 return del_GetLine(gl);
1971 /*
1972 * Install initial dispositions for the default list of signals that
1973 * gl_get_line() traps.
1974 */
1975 for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
1976 const struct GlDefSignal *sig = gl_signal_list + i;
1977 if(_gl_trap_signal(gl, sig->signo, sig->flags, sig->after,
1978 sig->errno_value))
1979 return del_GetLine(gl);
1980 };
1981 /*
1982 * Allocate an empty table of key bindings.
1983 */
1984 gl->bindings = _new_KeyTab();
1985 if(!gl->bindings)
1986 return del_GetLine(gl);
1987 /*
1988 * Define the available actions that can be bound to key sequences.
1989 */
1990 for(i=0; i<sizeof(gl_actions)/sizeof(gl_actions[0]); i++) {
1991 if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn, NULL))
1992 return del_GetLine(gl);
1993 };
1994 /*
1995 * Set up the default bindings.
1996 */
1997 if(gl_change_editor(gl, gl->editor))
1998 return del_GetLine(gl);
1999 /*
2000 * Allocate termcap buffers.
2001 */
2002 #ifdef USE_TERMCAP
2003 gl->tgetent_buf = (char *) malloc(TERMCAP_BUF_SIZE);
2004 gl->tgetstr_buf = (char *) malloc(TERMCAP_BUF_SIZE);
2005 if(!gl->tgetent_buf || !gl->tgetstr_buf) {
2006 errno = ENOMEM;
2007 return del_GetLine(gl);
2008 };
2009 #endif
2010 /*
2011 * Set up for I/O assuming stdin and stdout.
2012 */
2013 if(_gl_change_terminal(gl, stdin, stdout, getenv("TERM")))
2014 return del_GetLine(gl);
2015 /*
2016 * Create a freelist for use in allocating GlFdNode list nodes.
2017 */
2018 #ifdef HAVE_SELECT
2019 gl->fd_node_mem = _new_FreeList(sizeof(GlFdNode), GLFD_FREELIST_BLOCKING);
2020 if(!gl->fd_node_mem)
2021 return del_GetLine(gl);
2022 #endif
2023 /*
2024 * We are done for now.
2025 */
2026 return gl;
2027 }
2028
2029 /*.......................................................................
2030 * Delete a GetLine object.
2031 *
2032 * Input:
2033 * gl GetLine * The object to be deleted.
2034 * Output:
2035 * return GetLine * The deleted object (always NULL).
2036 */
del_GetLine(GetLine * gl)2037 GetLine *del_GetLine(GetLine *gl)
2038 {
2039 if(gl) {
2040 /*
2041 * If the terminal is in raw server mode, reset it.
2042 */
2043 _gl_normal_io(gl);
2044 /*
2045 * Deallocate all objects contained by gl.
2046 */
2047 gl->err = _del_ErrMsg(gl->err);
2048 gl->glh = _del_GlHistory(gl->glh);
2049 gl->cpl = del_WordCompletion(gl->cpl);
2050 #ifndef WITHOUT_FILE_SYSTEM
2051 gl->ef = del_ExpandFile(gl->ef);
2052 #endif
2053 gl->capmem = _del_StringGroup(gl->capmem);
2054 gl->cq = _del_GlCharQueue(gl->cq);
2055 if(gl->file_fp)
2056 fclose(gl->file_fp);
2057 if(gl->term)
2058 free(gl->term);
2059 if(gl->line)
2060 free(gl->line);
2061 if(gl->cutbuf)
2062 free(gl->cutbuf);
2063 if(gl->prompt)
2064 free(gl->prompt);
2065 gl->cpl_mem = _del_FreeList(gl->cpl_mem, 1);
2066 gl->ext_act_mem = _del_FreeList(gl->ext_act_mem, 1);
2067 gl->sig_mem = _del_FreeList(gl->sig_mem, 1);
2068 gl->sigs = NULL; /* Already freed by freeing sig_mem */
2069 gl->bindings = _del_KeyTab(gl->bindings);
2070 if(gl->vi.undo.line)
2071 free(gl->vi.undo.line);
2072 #ifdef USE_TERMCAP
2073 if(gl->tgetent_buf)
2074 free(gl->tgetent_buf);
2075 if(gl->tgetstr_buf)
2076 free(gl->tgetstr_buf);
2077 #endif
2078 if(gl->app_file)
2079 free(gl->app_file);
2080 if(gl->user_file)
2081 free(gl->user_file);
2082 #ifdef HAVE_SELECT
2083 gl->fd_node_mem = _del_FreeList(gl->fd_node_mem, 1);
2084 gl->fd_nodes = NULL; /* Already freed by freeing gl->fd_node_mem */
2085 #endif
2086 /*
2087 * Delete the now empty container.
2088 */
2089 free(gl);
2090 };
2091 return NULL;
2092 }
2093
2094 /*.......................................................................
2095 * Bind a control or meta character to an action.
2096 *
2097 * Input:
2098 * gl GetLine * The resource object of this program.
2099 * binder KtBinder The source of the binding.
2100 * c char The control or meta character.
2101 * If this is '\0', the call is ignored.
2102 * action const char * The action name to bind the key to.
2103 * Output:
2104 * return int 0 - OK.
2105 * 1 - Error.
2106 */
gl_bind_control_char(GetLine * gl,KtBinder binder,char c,const char * action)2107 static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c,
2108 const char *action)
2109 {
2110 char keyseq[2];
2111 /*
2112 * Quietly reject binding to the NUL control character, since this
2113 * is an ambiguous prefix of all bindings.
2114 */
2115 if(c == '\0')
2116 return 0;
2117 /*
2118 * Making sure not to bind characters which aren't either control or
2119 * meta characters.
2120 */
2121 if(IS_CTRL_CHAR(c) || IS_META_CHAR(c)) {
2122 keyseq[0] = c;
2123 keyseq[1] = '\0';
2124 } else {
2125 return 0;
2126 };
2127 /*
2128 * Install the binding.
2129 */
2130 if(_kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
2131 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
2132 return 1;
2133 };
2134 return 0;
2135 }
2136
2137 /*.......................................................................
2138 * Read a line from the user.
2139 *
2140 * Input:
2141 * gl GetLine * A resource object returned by new_GetLine().
2142 * prompt char * The prompt to prefix the line with.
2143 * start_line char * The initial contents of the input line, or NULL
2144 * if it should start out empty.
2145 * start_pos int If start_line isn't NULL, this specifies the
2146 * index of the character over which the cursor
2147 * should initially be positioned within the line.
2148 * If you just want it to follow the last character
2149 * of the line, send -1.
2150 * Output:
2151 * return char * An internal buffer containing the input line, or
2152 * NULL at the end of input. If the line fitted in
2153 * the buffer there will be a '\n' newline character
2154 * before the terminating '\0'. If it was truncated
2155 * there will be no newline character, and the remains
2156 * of the line should be retrieved via further calls
2157 * to this function.
2158 */
gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2159 char *gl_get_line(GetLine *gl, const char *prompt,
2160 const char *start_line, int start_pos)
2161 {
2162 char *retval; /* The return value of _gl_get_line() */
2163 /*
2164 * Check the arguments.
2165 */
2166 if(!gl) {
2167 errno = EINVAL;
2168 return NULL;
2169 };
2170 /*
2171 * Temporarily block all of the signals that we have been asked to trap.
2172 */
2173 if(gl_mask_signals(gl, &gl->old_signal_set))
2174 return NULL;
2175 /*
2176 * Perform the command-line editing task.
2177 */
2178 retval = _gl_get_line(gl, prompt, start_line, start_pos);
2179 /*
2180 * Restore the process signal mask to how it was when this function was
2181 * first called.
2182 */
2183 gl_unmask_signals(gl, &gl->old_signal_set);
2184 return retval;
2185 }
2186
2187
2188 /*.......................................................................
2189 * This is the main body of the public function gl_get_line().
2190 */
_gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2191 static char *_gl_get_line(GetLine *gl, const char *prompt,
2192 const char *start_line, int start_pos)
2193 {
2194 int waserr = 0; /* True if an error occurs */
2195 /*
2196 * Assume that this call will successfully complete the input
2197 * line until proven otherwise.
2198 */
2199 gl_clear_status(gl);
2200 /*
2201 * If this is the first call to this function since new_GetLine(),
2202 * complete any postponed configuration.
2203 */
2204 if(!gl->configured) {
2205 (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
2206 gl->configured = 1;
2207 };
2208 /*
2209 * Before installing our signal handler functions, record the fact
2210 * that there are no pending signals.
2211 */
2212 gl_pending_signal = -1;
2213 /*
2214 * Temporarily override the signal handlers of the calling program,
2215 * so that we can intercept signals that would leave the terminal
2216 * in a bad state.
2217 */
2218 waserr = gl_override_signal_handlers(gl);
2219 /*
2220 * After recording the current terminal settings, switch the terminal
2221 * into raw input mode.
2222 */
2223 waserr = waserr || _gl_raw_io(gl, 1);
2224 /*
2225 * Attempt to read the line. This will require more than one attempt if
2226 * either a current temporary input file is opened by gl_get_input_line()
2227 * or the end of a temporary input file is reached by gl_read_stream_line().
2228 */
2229 while(!waserr) {
2230 /*
2231 * Read a line from a non-interactive stream?
2232 */
2233 if(gl->file_fp || !gl->is_term) {
2234 if(gl_read_stream_line(gl)==0) {
2235 break;
2236 } else if(gl->file_fp) {
2237 gl_revert_input(gl);
2238 gl_record_status(gl, GLR_NEWLINE, 0);
2239 } else {
2240 waserr = 1;
2241 break;
2242 };
2243 };
2244 /*
2245 * Read from the terminal? Note that the above if() block may have
2246 * changed gl->file_fp, so it is necessary to retest it here, rather
2247 * than using an else statement.
2248 */
2249 if(!gl->file_fp && gl->is_term) {
2250 if(gl_get_input_line(gl, prompt, start_line, start_pos))
2251 waserr = 1;
2252 else
2253 break;
2254 };
2255 };
2256 /*
2257 * If an error occurred, but gl->rtn_status is still set to
2258 * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
2259 * leave it at whatever specific value was assigned by the function
2260 * that aborted input. This means that only functions that trap
2261 * non-generic errors have to remember to update gl->rtn_status
2262 * themselves.
2263 */
2264 if(waserr && gl->rtn_status == GLR_NEWLINE)
2265 gl_record_status(gl, GLR_ERROR, errno);
2266 /*
2267 * Restore terminal settings.
2268 */
2269 if(gl->io_mode != GL_SERVER_MODE)
2270 _gl_normal_io(gl);
2271 /*
2272 * Restore the signal handlers.
2273 */
2274 gl_restore_signal_handlers(gl);
2275 /*
2276 * If gl_get_line() gets aborted early, the errno value associated
2277 * with the event that caused this to happen is recorded in
2278 * gl->rtn_errno. Since errno may have been overwritten by cleanup
2279 * functions after this, restore its value to the value that it had
2280 * when the error condition occured, so that the caller can examine it
2281 * to find out what happened.
2282 */
2283 errno = gl->rtn_errno;
2284 /*
2285 * Check the completion status to see how to return.
2286 */
2287 switch(gl->rtn_status) {
2288 case GLR_NEWLINE: /* Success */
2289 return gl->line;
2290 case GLR_BLOCKED: /* These events abort the current input line, */
2291 case GLR_SIGNAL: /* when in normal blocking I/O mode, but only */
2292 case GLR_TIMEOUT: /* temporarily pause line editing when in */
2293 case GLR_FDABORT: /* non-blocking server I/O mode. */
2294 if(gl->io_mode != GL_SERVER_MODE)
2295 _gl_abandon_line(gl);
2296 return NULL;
2297 case GLR_ERROR: /* Unrecoverable errors abort the input line, */
2298 case GLR_EOF: /* regardless of the I/O mode. */
2299 default:
2300 _gl_abandon_line(gl);
2301 return NULL;
2302 };
2303 }
2304
2305 /*.......................................................................
2306 * Read a single character from the user.
2307 *
2308 * Input:
2309 * gl GetLine * A resource object returned by new_GetLine().
2310 * prompt char * The prompt to prefix the line with, or NULL if
2311 * no prompt is required.
2312 * defchar char The character to substitute if the
2313 * user simply hits return, or '\n' if you don't
2314 * need to substitute anything.
2315 * Output:
2316 * return int The character that was read, or EOF if the read
2317 * had to be aborted (in which case you can call
2318 * gl_return_status() to find out why).
2319 */
gl_query_char(GetLine * gl,const char * prompt,char defchar)2320 int gl_query_char(GetLine *gl, const char *prompt, char defchar)
2321 {
2322 int retval; /* The return value of _gl_query_char() */
2323 /*
2324 * Check the arguments.
2325 */
2326 if(!gl) {
2327 errno = EINVAL;
2328 return EOF;
2329 };
2330 /*
2331 * Temporarily block all of the signals that we have been asked to trap.
2332 */
2333 if(gl_mask_signals(gl, &gl->old_signal_set))
2334 return EOF;
2335 /*
2336 * Perform the character reading task.
2337 */
2338 retval = _gl_query_char(gl, prompt, defchar);
2339 /*
2340 * Restore the process signal mask to how it was when this function was
2341 * first called.
2342 */
2343 gl_unmask_signals(gl, &gl->old_signal_set);
2344 return retval;
2345 }
2346
2347 /*.......................................................................
2348 * This is the main body of the public function gl_query_char().
2349 */
_gl_query_char(GetLine * gl,const char * prompt,char defchar)2350 static int _gl_query_char(GetLine *gl, const char *prompt, char defchar)
2351 {
2352 int c = EOF; /* The character to be returned */
2353 int waserr = 0; /* True if an error occurs */
2354 /*
2355 * Assume that this call will successfully complete the input operation
2356 * until proven otherwise.
2357 */
2358 gl_clear_status(gl);
2359 /*
2360 * If this is the first call to this function or gl_get_line(),
2361 * since new_GetLine(), complete any postponed configuration.
2362 */
2363 if(!gl->configured) {
2364 (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
2365 gl->configured = 1;
2366 };
2367 /*
2368 * Before installing our signal handler functions, record the fact
2369 * that there are no pending signals.
2370 */
2371 gl_pending_signal = -1;
2372 /*
2373 * Temporarily override the signal handlers of the calling program,
2374 * so that we can intercept signals that would leave the terminal
2375 * in a bad state.
2376 */
2377 waserr = gl_override_signal_handlers(gl);
2378 /*
2379 * After recording the current terminal settings, switch the terminal
2380 * into raw input mode without redisplaying any partially entered
2381 * input line.
2382 */
2383 waserr = waserr || _gl_raw_io(gl, 0);
2384 /*
2385 * Attempt to read the line. This will require more than one attempt if
2386 * either a current temporary input file is opened by gl_get_input_line()
2387 * or the end of a temporary input file is reached by gl_read_stream_line().
2388 */
2389 while(!waserr) {
2390 /*
2391 * Read a line from a non-interactive stream?
2392 */
2393 if(gl->file_fp || !gl->is_term) {
2394 c = gl_read_stream_char(gl);
2395 if(c != EOF) { /* Success? */
2396 if(c=='\n') c = defchar;
2397 break;
2398 } else if(gl->file_fp) { /* End of temporary input file? */
2399 gl_revert_input(gl);
2400 gl_record_status(gl, GLR_NEWLINE, 0);
2401 } else { /* An error? */
2402 waserr = 1;
2403 break;
2404 };
2405 };
2406 /*
2407 * Read from the terminal? Note that the above if() block may have
2408 * changed gl->file_fp, so it is necessary to retest it here, rather
2409 * than using an else statement.
2410 */
2411 if(!gl->file_fp && gl->is_term) {
2412 c = gl_get_query_char(gl, prompt, defchar);
2413 if(c==EOF)
2414 waserr = 1;
2415 else
2416 break;
2417 };
2418 };
2419 /*
2420 * If an error occurred, but gl->rtn_status is still set to
2421 * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
2422 * leave it at whatever specific value was assigned by the function
2423 * that aborted input. This means that only functions that trap
2424 * non-generic errors have to remember to update gl->rtn_status
2425 * themselves.
2426 */
2427 if(waserr && gl->rtn_status == GLR_NEWLINE)
2428 gl_record_status(gl, GLR_ERROR, errno);
2429 /*
2430 * Restore terminal settings.
2431 */
2432 if(gl->io_mode != GL_SERVER_MODE)
2433 _gl_normal_io(gl);
2434 /*
2435 * Restore the signal handlers.
2436 */
2437 gl_restore_signal_handlers(gl);
2438 /*
2439 * If this function gets aborted early, the errno value associated
2440 * with the event that caused this to happen is recorded in
2441 * gl->rtn_errno. Since errno may have been overwritten by cleanup
2442 * functions after this, restore its value to the value that it had
2443 * when the error condition occured, so that the caller can examine it
2444 * to find out what happened.
2445 */
2446 errno = gl->rtn_errno;
2447 /*
2448 * Error conditions are signalled to the caller, by setting the returned
2449 * character to EOF.
2450 */
2451 if(gl->rtn_status != GLR_NEWLINE)
2452 c = EOF;
2453 /*
2454 * In this mode, every character that is read is a completed
2455 * transaction, just like reading a completed input line, so prepare
2456 * for the next input line or character.
2457 */
2458 _gl_abandon_line(gl);
2459 /*
2460 * Return the acquired character.
2461 */
2462 return c;
2463 }
2464
2465 /*.......................................................................
2466 * Record of the signal handlers of the calling program, so that they
2467 * can be restored later.
2468 *
2469 * Input:
2470 * gl GetLine * The resource object of this library.
2471 * Output:
2472 * return int 0 - OK.
2473 * 1 - Error.
2474 */
gl_override_signal_handlers(GetLine * gl)2475 static int gl_override_signal_handlers(GetLine *gl)
2476 {
2477 GlSignalNode *sig; /* A node in the list of signals to be caught */
2478 /*
2479 * Set up our signal handler.
2480 */
2481 SigAction act;
2482 act.sa_handler = gl_signal_handler;
2483 memcpy(&act.sa_mask, &gl->all_signal_set, sizeof(sigset_t));
2484 act.sa_flags = 0;
2485 /*
2486 * Get the subset of the signals that we are supposed to trap that
2487 * should actually be trapped.
2488 */
2489 sigemptyset(&gl->use_signal_set);
2490 for(sig=gl->sigs; sig; sig=sig->next) {
2491 /*
2492 * Trap this signal? If it is blocked by the calling program and we
2493 * haven't been told to unblock it, don't arrange to trap this signal.
2494 */
2495 if(sig->flags & GLS_UNBLOCK_SIG ||
2496 !sigismember(&gl->old_signal_set, sig->signo)) {
2497 if(sigaddset(&gl->use_signal_set, sig->signo) == -1) {
2498 _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
2499 return 1;
2500 };
2501 };
2502 };
2503 /*
2504 * Override the actions of the signals that we are trapping.
2505 */
2506 for(sig=gl->sigs; sig; sig=sig->next) {
2507 if(sigismember(&gl->use_signal_set, sig->signo)) {
2508 sigdelset(&act.sa_mask, sig->signo);
2509 if(sigaction(sig->signo, &act, &sig->original)) {
2510 _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
2511 return 1;
2512 };
2513 sigaddset(&act.sa_mask, sig->signo);
2514 };
2515 };
2516 /*
2517 * Record the fact that the application's signal handlers have now
2518 * been overriden.
2519 */
2520 gl->signals_overriden = 1;
2521 /*
2522 * Just in case a SIGWINCH signal was sent to the process while our
2523 * SIGWINCH signal handler wasn't in place, check to see if the terminal
2524 * size needs updating.
2525 */
2526 if(_gl_update_size(gl))
2527 return 1;
2528 return 0;
2529 }
2530
2531 /*.......................................................................
2532 * Restore the signal handlers of the calling program.
2533 *
2534 * Input:
2535 * gl GetLine * The resource object of this library.
2536 * Output:
2537 * return int 0 - OK.
2538 * 1 - Error.
2539 */
gl_restore_signal_handlers(GetLine * gl)2540 static int gl_restore_signal_handlers(GetLine *gl)
2541 {
2542 GlSignalNode *sig; /* A node in the list of signals to be caught */
2543 /*
2544 * Restore application signal handlers that were overriden
2545 * by gl_override_signal_handlers().
2546 */
2547 for(sig=gl->sigs; sig; sig=sig->next) {
2548 if(sigismember(&gl->use_signal_set, sig->signo) &&
2549 sigaction(sig->signo, &sig->original, NULL)) {
2550 _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
2551 return 1;
2552 };
2553 };
2554 /*
2555 * Record the fact that the application's signal handlers have now
2556 * been restored.
2557 */
2558 gl->signals_overriden = 0;
2559 return 0;
2560 }
2561
2562 /*.......................................................................
2563 * This signal handler simply records the fact that a given signal was
2564 * caught in the file-scope gl_pending_signal variable.
2565 */
gl_signal_handler(int signo)2566 static void gl_signal_handler(int signo)
2567 {
2568 gl_pending_signal = signo;
2569 siglongjmp(gl_setjmp_buffer, 1);
2570 }
2571
2572 /*.......................................................................
2573 * Switch the terminal into raw mode after storing the previous terminal
2574 * settings in gl->attributes.
2575 *
2576 * Input:
2577 * gl GetLine * The resource object of this program.
2578 * Output:
2579 * return int 0 - OK.
2580 * 1 - Error.
2581 */
gl_raw_terminal_mode(GetLine * gl)2582 static int gl_raw_terminal_mode(GetLine *gl)
2583 {
2584 Termios newattr; /* The new terminal attributes */
2585 /*
2586 * If the terminal is already in raw mode, do nothing.
2587 */
2588 if(gl->raw_mode)
2589 return 0;
2590 /*
2591 * Record the current terminal attributes.
2592 */
2593 if(tcgetattr(gl->input_fd, &gl->oldattr)) {
2594 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
2595 return 1;
2596 };
2597 /*
2598 * This function shouldn't do anything but record the current terminal
2599 * attritubes if editing has been disabled.
2600 */
2601 if(gl->editor == GL_NO_EDITOR)
2602 return 0;
2603 /*
2604 * Modify the existing attributes.
2605 */
2606 newattr = gl->oldattr;
2607 /*
2608 * Turn off local echo, canonical input mode and extended input processing.
2609 */
2610 newattr.c_lflag &= ~(ECHO | ICANON | IEXTEN);
2611 /*
2612 * Don't translate carriage return to newline, turn off input parity
2613 * checking, don't strip off 8th bit, turn off output flow control.
2614 */
2615 newattr.c_iflag &= ~(ICRNL | INPCK | ISTRIP);
2616 /*
2617 * Clear size bits, turn off parity checking, and allow 8-bit characters.
2618 */
2619 newattr.c_cflag &= ~(CSIZE | PARENB);
2620 newattr.c_cflag |= CS8;
2621 /*
2622 * Turn off output processing.
2623 */
2624 newattr.c_oflag &= ~(OPOST);
2625 /*
2626 * Request one byte at a time, without waiting.
2627 */
2628 newattr.c_cc[VMIN] = gl->io_mode==GL_SERVER_MODE ? 0:1;
2629 newattr.c_cc[VTIME] = 0;
2630 /*
2631 * Install the new terminal modes.
2632 */
2633 while(tcsetattr(gl->input_fd, TCSADRAIN, &newattr)) {
2634 if(errno != EINTR) {
2635 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
2636 return 1;
2637 };
2638 };
2639 /*
2640 * Record the new terminal mode.
2641 */
2642 gl->raw_mode = 1;
2643 return 0;
2644 }
2645
2646 /*.......................................................................
2647 * Restore the terminal attributes recorded in gl->oldattr.
2648 *
2649 * Input:
2650 * gl GetLine * The resource object of this library.
2651 * Output:
2652 * return int 0 - OK.
2653 * 1 - Error.
2654 */
gl_restore_terminal_attributes(GetLine * gl)2655 static int gl_restore_terminal_attributes(GetLine *gl)
2656 {
2657 int waserr = 0;
2658 /*
2659 * If not in raw mode, do nothing.
2660 */
2661 if(!gl->raw_mode)
2662 return 0;
2663 /*
2664 * Before changing the terminal attributes, make sure that all output
2665 * has been passed to the terminal.
2666 */
2667 if(gl_flush_output(gl))
2668 waserr = 1;
2669 /*
2670 * Reset the terminal attributes to the values that they had on
2671 * entry to gl_get_line().
2672 */
2673 while(tcsetattr(gl->input_fd, TCSADRAIN, &gl->oldattr)) {
2674 if(errno != EINTR) {
2675 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
2676 waserr = 1;
2677 break;
2678 };
2679 };
2680 /*
2681 * Record the new terminal mode.
2682 */
2683 gl->raw_mode = 0;
2684 return waserr;
2685 }
2686
2687 /*.......................................................................
2688 * Switch the terminal file descriptor to use non-blocking I/O.
2689 *
2690 * Input:
2691 * gl GetLine * The resource object of gl_get_line().
2692 * fd int The file descriptor to make non-blocking.
2693 */
gl_nonblocking_io(GetLine * gl,int fd)2694 static int gl_nonblocking_io(GetLine *gl, int fd)
2695 {
2696 int fcntl_flags; /* The new file-descriptor control flags */
2697 /*
2698 * Is non-blocking I/O supported on this system? Note that even
2699 * without non-blocking I/O, the terminal will probably still act as
2700 * though it was non-blocking, because we also set the terminal
2701 * attributes to return immediately if no input is available and we
2702 * use select() to wait to be able to write. If select() also isn't
2703 * available, then input will probably remain fine, but output could
2704 * block, depending on the behaviour of the terminal driver.
2705 */
2706 #if defined(NON_BLOCKING_FLAG)
2707 /*
2708 * Query the current file-control flags, and add the
2709 * non-blocking I/O flag.
2710 */
2711 fcntl_flags = fcntl(fd, F_GETFL) | NON_BLOCKING_FLAG;
2712 /*
2713 * Install the new control flags.
2714 */
2715 if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
2716 _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
2717 return 1;
2718 };
2719 #endif
2720 return 0;
2721 }
2722
2723 /*.......................................................................
2724 * Switch to blocking terminal I/O.
2725 *
2726 * Input:
2727 * gl GetLine * The resource object of gl_get_line().
2728 * fd int The file descriptor to make blocking.
2729 */
gl_blocking_io(GetLine * gl,int fd)2730 static int gl_blocking_io(GetLine *gl, int fd)
2731 {
2732 int fcntl_flags; /* The new file-descriptor control flags */
2733 /*
2734 * Is non-blocking I/O implemented on this system?
2735 */
2736 #if defined(NON_BLOCKING_FLAG)
2737 /*
2738 * Query the current file control flags and remove the non-blocking
2739 * I/O flag.
2740 */
2741 fcntl_flags = fcntl(fd, F_GETFL) & ~NON_BLOCKING_FLAG;
2742 /*
2743 * Install the modified control flags.
2744 */
2745 if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
2746 _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
2747 return 1;
2748 };
2749 #endif
2750 return 0;
2751 }
2752
2753 /*.......................................................................
2754 * Read a new input line from the user.
2755 *
2756 * Input:
2757 * gl GetLine * The resource object of this library.
2758 * prompt char * The prompt to prefix the line with, or NULL to
2759 * use the same prompt that was used by the previous
2760 * line.
2761 * start_line char * The initial contents of the input line, or NULL
2762 * if it should start out empty.
2763 * start_pos int If start_line isn't NULL, this specifies the
2764 * index of the character over which the cursor
2765 * should initially be positioned within the line.
2766 * If you just want it to follow the last character
2767 * of the line, send -1.
2768 * Output:
2769 * return int 0 - OK.
2770 * 1 - Error.
2771 */
gl_get_input_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2772 static int gl_get_input_line(GetLine *gl, const char *prompt,
2773 const char *start_line, int start_pos)
2774 {
2775 char c; /* The character being read */
2776 /*
2777 * Flush any pending output to the terminal.
2778 */
2779 if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
2780 return 1;
2781 /*
2782 * Are we starting a new line?
2783 */
2784 if(gl->endline) {
2785 /*
2786 * Delete any incompletely enterred line.
2787 */
2788 if(gl_erase_line(gl))
2789 return 1;
2790 /*
2791 * Display the new line to be edited.
2792 */
2793 if(gl_present_line(gl, prompt, start_line, start_pos))
2794 return 1;
2795 };
2796 /*
2797 * Read one character at a time.
2798 */
2799 while(gl_read_terminal(gl, 1, &c) == 0) {
2800 /*
2801 * Increment the count of the number of key sequences entered.
2802 */
2803 gl->keyseq_count++;
2804 /*
2805 * Interpret the character either as the start of a new key-sequence,
2806 * as a continuation of a repeat count, or as a printable character
2807 * to be added to the line.
2808 */
2809 if(gl_interpret_char(gl, c))
2810 break;
2811 /*
2812 * If we just ran an action function which temporarily asked for
2813 * input to be taken from a file, abort this call.
2814 */
2815 if(gl->file_fp)
2816 return 0;
2817 /*
2818 * Has the line been completed?
2819 */
2820 if(gl->endline)
2821 return gl_line_ended(gl, c);
2822 };
2823 /*
2824 * To get here, gl_read_terminal() must have returned non-zero. See
2825 * whether a signal was caught that requested that the current line
2826 * be returned.
2827 */
2828 if(gl->endline)
2829 return gl_line_ended(gl, '\n');
2830 /*
2831 * If I/O blocked while attempting to get the latest character
2832 * of the key sequence, rewind the key buffer to allow interpretation of
2833 * the current key sequence to be restarted on the next call to this
2834 * function.
2835 */
2836 if(gl->rtn_status == GLR_BLOCKED && gl->pending_io == GLP_READ)
2837 gl->nread = 0;
2838 return 1;
2839 }
2840
2841 /*.......................................................................
2842 * This is the private function of gl_query_char() that handles
2843 * prompting the user, reading a character from the terminal, and
2844 * displaying what the user entered.
2845 *
2846 * Input:
2847 * gl GetLine * The resource object of this library.
2848 * prompt char * The prompt to prefix the line with.
2849 * defchar char The character to substitute if the
2850 * user simply hits return, or '\n' if you don't
2851 * need to substitute anything.
2852 * Output:
2853 * return int The character that was read, or EOF if something
2854 * prevented a character from being read.
2855 */
gl_get_query_char(GetLine * gl,const char * prompt,int defchar)2856 static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar)
2857 {
2858 char c; /* The character being read */
2859 int retval; /* The return value of this function */
2860 /*
2861 * Flush any pending output to the terminal.
2862 */
2863 if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
2864 return EOF;
2865 /*
2866 * Delete any incompletely entered line.
2867 */
2868 if(gl_erase_line(gl))
2869 return EOF;
2870 /*
2871 * Reset the line input parameters and display the prompt, if any.
2872 */
2873 if(gl_present_line(gl, prompt, NULL, 0))
2874 return EOF;
2875 /*
2876 * Read one character.
2877 */
2878 if(gl_read_terminal(gl, 1, &c) == 0) {
2879 /*
2880 * In this mode, count each character as being a new key-sequence.
2881 */
2882 gl->keyseq_count++;
2883 /*
2884 * Delete the character that was read, from the key-press buffer.
2885 */
2886 gl_discard_chars(gl, gl->nread);
2887 /*
2888 * Convert carriage returns to newlines.
2889 */
2890 if(c == '\r')
2891 c = '\n';
2892 /*
2893 * If the user just hit return, subsitute the default character.
2894 */
2895 if(c == '\n')
2896 c = defchar;
2897 /*
2898 * Display the entered character to the right of the prompt.
2899 */
2900 if(c!='\n') {
2901 if(gl_end_of_line(gl, 1, NULL)==0)
2902 gl_print_char(gl, c, ' ');
2903 };
2904 /*
2905 * Record the return character, and mark the call as successful.
2906 */
2907 retval = c;
2908 gl_record_status(gl, GLR_NEWLINE, 0);
2909 /*
2910 * Was a signal caught whose disposition is to cause the current input
2911 * line to be returned? If so return a newline character.
2912 */
2913 } else if(gl->endline) {
2914 retval = '\n';
2915 gl_record_status(gl, GLR_NEWLINE, 0);
2916 } else {
2917 retval = EOF;
2918 };
2919 /*
2920 * Start a new line.
2921 */
2922 if(gl_start_newline(gl, 1))
2923 return EOF;
2924 /*
2925 * Attempt to flush any pending output.
2926 */
2927 (void) gl_flush_output(gl);
2928 /*
2929 * Return either the character that was read, or EOF if an error occurred.
2930 */
2931 return retval;
2932 }
2933
2934 /*.......................................................................
2935 * Add a character to the line buffer at the current cursor position,
2936 * inserting or overwriting according the current mode.
2937 *
2938 * Input:
2939 * gl GetLine * The resource object of this library.
2940 * c char The character to be added.
2941 * Output:
2942 * return int 0 - OK.
2943 * 1 - Insufficient room.
2944 */
gl_add_char_to_line(GetLine * gl,char c)2945 static int gl_add_char_to_line(GetLine *gl, char c)
2946 {
2947 /*
2948 * Keep a record of the current cursor position.
2949 */
2950 int buff_curpos = gl->buff_curpos;
2951 int term_curpos = gl->term_curpos;
2952 /*
2953 * Work out the displayed width of the new character.
2954 */
2955 int width = gl_displayed_char_width(gl, c, term_curpos);
2956 /*
2957 * If we are in insert mode, or at the end of the line,
2958 * check that we can accomodate a new character in the buffer.
2959 * If not, simply return, leaving it up to the calling program
2960 * to check for the absence of a newline character.
2961 */
2962 if((gl->insert || buff_curpos >= gl->ntotal) && gl->ntotal >= gl->linelen)
2963 return 0;
2964 /*
2965 * Are we adding characters to the line (ie. inserting or appending)?
2966 */
2967 if(gl->insert || buff_curpos >= gl->ntotal) {
2968 /*
2969 * If inserting, make room for the new character.
2970 */
2971 if(buff_curpos < gl->ntotal)
2972 gl_make_gap_in_buffer(gl, buff_curpos, 1);
2973 /*
2974 * Copy the character into the buffer.
2975 */
2976 gl_buffer_char(gl, c, buff_curpos);
2977 gl->buff_curpos++;
2978 /*
2979 * Redraw the line from the cursor position to the end of the line,
2980 * and move the cursor to just after the added character.
2981 */
2982 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
2983 gl_set_term_curpos(gl, term_curpos + width))
2984 return 1;
2985 /*
2986 * Are we overwriting an existing character?
2987 */
2988 } else {
2989 /*
2990 * Get the width of the character being overwritten.
2991 */
2992 int old_width = gl_displayed_char_width(gl, gl->line[buff_curpos],
2993 term_curpos);
2994 /*
2995 * Overwrite the character in the buffer.
2996 */
2997 gl_buffer_char(gl, c, buff_curpos);
2998 /*
2999 * If we are replacing with a narrower character, we need to
3000 * redraw the terminal string to the end of the line, then
3001 * overwrite the trailing old_width - width characters
3002 * with spaces.
3003 */
3004 if(old_width > width) {
3005 if(gl_print_string(gl, gl->line + buff_curpos, '\0'))
3006 return 1;
3007 /*
3008 * Clear to the end of the terminal.
3009 */
3010 if(gl_truncate_display(gl))
3011 return 1;
3012 /*
3013 * Move the cursor to the end of the new character.
3014 */
3015 if(gl_set_term_curpos(gl, term_curpos + width))
3016 return 1;
3017 gl->buff_curpos++;
3018 /*
3019 * If we are replacing with a wider character, then we will be
3020 * inserting new characters, and thus extending the line.
3021 */
3022 } else if(width > old_width) {
3023 /*
3024 * Redraw the line from the cursor position to the end of the line,
3025 * and move the cursor to just after the added character.
3026 */
3027 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
3028 gl_set_term_curpos(gl, term_curpos + width))
3029 return 1;
3030 gl->buff_curpos++;
3031 /*
3032 * The original and replacement characters have the same width,
3033 * so simply overwrite.
3034 */
3035 } else {
3036 /*
3037 * Copy the character into the buffer.
3038 */
3039 gl_buffer_char(gl, c, buff_curpos);
3040 gl->buff_curpos++;
3041 /*
3042 * Overwrite the original character.
3043 */
3044 if(gl_print_char(gl, c, gl->line[gl->buff_curpos]))
3045 return 1;
3046 };
3047 };
3048 return 0;
3049 }
3050
3051 /*.......................................................................
3052 * Insert/append a string to the line buffer and terminal at the current
3053 * cursor position.
3054 *
3055 * Input:
3056 * gl GetLine * The resource object of this library.
3057 * s char * The string to be added.
3058 * Output:
3059 * return int 0 - OK.
3060 * 1 - Insufficient room.
3061 */
gl_add_string_to_line(GetLine * gl,const char * s)3062 static int gl_add_string_to_line(GetLine *gl, const char *s)
3063 {
3064 int buff_slen; /* The length of the string being added to line[] */
3065 int term_slen; /* The length of the string being written to the terminal */
3066 int buff_curpos; /* The original value of gl->buff_curpos */
3067 int term_curpos; /* The original value of gl->term_curpos */
3068 /*
3069 * Keep a record of the current cursor position.
3070 */
3071 buff_curpos = gl->buff_curpos;
3072 term_curpos = gl->term_curpos;
3073 /*
3074 * How long is the string to be added?
3075 */
3076 buff_slen = strlen(s);
3077 term_slen = gl_displayed_string_width(gl, s, buff_slen, term_curpos);
3078 /*
3079 * Check that we can accomodate the string in the buffer.
3080 * If not, simply return, leaving it up to the calling program
3081 * to check for the absence of a newline character.
3082 */
3083 if(gl->ntotal + buff_slen > gl->linelen)
3084 return 0;
3085 /*
3086 * Move the characters that follow the cursor in the buffer by
3087 * buff_slen characters to the right.
3088 */
3089 if(gl->ntotal > gl->buff_curpos)
3090 gl_make_gap_in_buffer(gl, gl->buff_curpos, buff_slen);
3091 /*
3092 * Copy the string into the buffer.
3093 */
3094 gl_buffer_string(gl, s, buff_slen, gl->buff_curpos);
3095 gl->buff_curpos += buff_slen;
3096 /*
3097 * Write the modified part of the line to the terminal, then move
3098 * the terminal cursor to the end of the displayed input string.
3099 */
3100 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
3101 gl_set_term_curpos(gl, term_curpos + term_slen))
3102 return 1;
3103 return 0;
3104 }
3105
3106 /*.......................................................................
3107 * Read a single character from the terminal.
3108 *
3109 * Input:
3110 * gl GetLine * The resource object of this library.
3111 * keep int If true, the returned character will be kept in
3112 * the input buffer, for potential replays. It should
3113 * subsequently be removed from the buffer when the
3114 * key sequence that it belongs to has been fully
3115 * processed, by calling gl_discard_chars().
3116 * Input/Output:
3117 * c char * The character that is read, is assigned to *c.
3118 * Output:
3119 * return int 0 - OK.
3120 * 1 - Either an I/O error occurred, or a signal was
3121 * caught who's disposition is to abort gl_get_line()
3122 * or to have gl_get_line() return the current line
3123 * as though the user had pressed return. In the
3124 * latter case gl->endline will be non-zero.
3125 */
gl_read_terminal(GetLine * gl,int keep,char * c)3126 static int gl_read_terminal(GetLine *gl, int keep, char *c)
3127 {
3128 /*
3129 * Before waiting for a new character to be input, flush unwritten
3130 * characters to the terminal.
3131 */
3132 if(gl_flush_output(gl))
3133 return 1;
3134 /*
3135 * Record the fact that we are about to read from the terminal.
3136 */
3137 gl->pending_io = GLP_READ;
3138 /*
3139 * If there is already an unread character in the buffer,
3140 * return it.
3141 */
3142 if(gl->nread < gl->nbuf) {
3143 *c = gl->keybuf[gl->nread];
3144 /*
3145 * Retain the character in the key buffer, but mark it as having been read?
3146 */
3147 if(keep) {
3148 gl->nread++;
3149 /*
3150 * Completely remove the character from the key buffer?
3151 */
3152 } else {
3153 memmove(gl->keybuf + gl->nread, gl->keybuf + gl->nread + 1,
3154 gl->nbuf - gl->nread - 1);
3155 };
3156 return 0;
3157 };
3158 /*
3159 * Make sure that there is space in the key buffer for one more character.
3160 * This should always be true if gl_interpret_char() is called for each
3161 * new character added, since it will clear the buffer once it has recognized
3162 * or rejected a key sequence.
3163 */
3164 if(gl->nbuf + 1 > GL_KEY_MAX) {
3165 gl_print_info(gl, "gl_read_terminal: Buffer overflow avoided.",
3166 GL_END_INFO);
3167 errno = EIO;
3168 return 1;
3169 };
3170 /*
3171 * Read one character from the terminal.
3172 */
3173 switch(gl_read_input(gl, c)) {
3174 case GL_READ_OK:
3175 break;
3176 case GL_READ_BLOCKED:
3177 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
3178 return 1;
3179 break;
3180 default:
3181 return 1;
3182 break;
3183 };
3184 /*
3185 * Append the character to the key buffer?
3186 */
3187 if(keep) {
3188 gl->keybuf[gl->nbuf] = *c;
3189 gl->nread = ++gl->nbuf;
3190 };
3191 return 0;
3192 }
3193
3194 /*.......................................................................
3195 * Read one or more keypresses from the terminal of an input stream.
3196 *
3197 * Input:
3198 * gl GetLine * The resource object of this module.
3199 * c char * The character that was read is assigned to *c.
3200 * Output:
3201 * return GlReadStatus The completion status of the read operation.
3202 */
gl_read_input(GetLine * gl,char * c)3203 static GlReadStatus gl_read_input(GetLine *gl, char *c)
3204 {
3205 /*
3206 * We may have to repeat the read if window change signals are received.
3207 */
3208 for(;;) {
3209 /*
3210 * Which file descriptor should we read from? Mark this volatile, so
3211 * that siglongjmp() can't clobber it.
3212 */
3213 volatile int fd = gl->file_fp ? fileno(gl->file_fp) : gl->input_fd;
3214 /*
3215 * If the endline flag becomes set, don't wait for another character.
3216 */
3217 if(gl->endline)
3218 return GL_READ_ERROR;
3219 /*
3220 * Since the code in this function can block, trap signals.
3221 */
3222 if(sigsetjmp(gl_setjmp_buffer, 1)==0) {
3223 /*
3224 * Handle the different I/O modes.
3225 */
3226 switch(gl->io_mode) {
3227 /*
3228 * In normal I/O mode, we call the event handler before attempting
3229 * to read, since read() blocks.
3230 */
3231 case GL_NORMAL_MODE:
3232 if(gl_event_handler(gl, fd))
3233 return GL_READ_ERROR;
3234 return gl_read_unmasked(gl, fd, c); /* Read one character */
3235 break;
3236 /*
3237 * In non-blocking server I/O mode, we attempt to read a character,
3238 * and only if this fails, call the event handler to wait for a any
3239 * user-configured timeout and any other user-configured events. In
3240 * addition, we turn off the fcntl() non-blocking flag when reading
3241 * from the terminal, to work around a bug in Solaris. We can do this
3242 * without causing the read() to block, because when in non-blocking
3243 * server-I/O mode, gl_raw_io() sets the VMIN terminal attribute to 0,
3244 * which tells the terminal driver to return immediately if no
3245 * characters are available to be read.
3246 */
3247 case GL_SERVER_MODE:
3248 {
3249 GlReadStatus status; /* The return status */
3250 if(isatty(fd)) /* If we reading from a terminal, */
3251 gl_blocking_io(gl, fd); /* switch to blocking I/O */
3252 status = gl_read_unmasked(gl, fd, c); /* Try reading */
3253 if(status == GL_READ_BLOCKED) { /* Nothing readable yet */
3254 if(gl_event_handler(gl, fd)) /* Wait for input */
3255 status = GL_READ_ERROR;
3256 else
3257 status = gl_read_unmasked(gl, fd, c); /* Try reading again */
3258 };
3259 gl_nonblocking_io(gl, fd); /* Restore non-blocking I/O */
3260 return status;
3261 };
3262 break;
3263 };
3264 };
3265 /*
3266 * To get here, one of the signals that we are trapping must have
3267 * been received. Note that by using sigsetjmp() instead of setjmp()
3268 * the signal mask that was blocking these signals will have been
3269 * reinstated, so we can be sure that no more of these signals will
3270 * be received until we explicitly unblock them again.
3271 *
3272 * First, if non-blocking I/O was temporarily disabled, reinstate it.
3273 */
3274 if(gl->io_mode == GL_SERVER_MODE)
3275 gl_nonblocking_io(gl, fd);
3276 /*
3277 * Now respond to the signal that was caught.
3278 */
3279 if(gl_check_caught_signal(gl))
3280 return GL_READ_ERROR;
3281 };
3282 }
3283
3284 /*.......................................................................
3285 * This is a private function of gl_read_input(), which unblocks signals
3286 * temporarily while it reads a single character from the specified file
3287 * descriptor.
3288 *
3289 * Input:
3290 * gl GetLine * The resource object of this module.
3291 * fd int The file descriptor to read from.
3292 * c char * The character that was read is assigned to *c.
3293 * Output:
3294 * return GlReadStatus The completion status of the read.
3295 */
gl_read_unmasked(GetLine * gl,int fd,char * c)3296 static GlReadStatus gl_read_unmasked(GetLine *gl, int fd, char *c)
3297 {
3298 int nread; /* The return value of read() */
3299 /*
3300 * Unblock the signals that we are trapping, while waiting for I/O.
3301 */
3302 gl_catch_signals(gl);
3303 /*
3304 * Attempt to read one character from the terminal, restarting the read
3305 * if any signals that we aren't trapping, are received.
3306 */
3307 do {
3308 errno = 0;
3309 nread = read(fd, c, 1);
3310 } while(nread < 0 && errno==EINTR);
3311 /*
3312 * Block all of the signals that we are trapping.
3313 */
3314 gl_mask_signals(gl, NULL);
3315 /*
3316 * Check the completion status of the read.
3317 */
3318 switch(nread) {
3319 case 1:
3320 return GL_READ_OK;
3321 case 0:
3322 return (isatty(fd) || errno != 0) ? GL_READ_BLOCKED : GL_READ_EOF;
3323 default:
3324 return GL_READ_ERROR;
3325 };
3326 }
3327
3328 /*.......................................................................
3329 * Remove a specified number of characters from the start of the
3330 * key-press lookahead buffer, gl->keybuf[], and arrange for the next
3331 * read to start from the character at the start of the shifted buffer.
3332 *
3333 * Input:
3334 * gl GetLine * The resource object of this module.
3335 * nused int The number of characters to discard from the start
3336 * of the buffer.
3337 */
gl_discard_chars(GetLine * gl,int nused)3338 static void gl_discard_chars(GetLine *gl, int nused)
3339 {
3340 int nkeep = gl->nbuf - nused;
3341 if(nkeep > 0) {
3342 memmove(gl->keybuf, gl->keybuf + nused, nkeep);
3343 gl->nbuf = nkeep;
3344 gl->nread = 0;
3345 } else {
3346 gl->nbuf = gl->nread = 0;
3347 };
3348 }
3349
3350 /*.......................................................................
3351 * This function is called to handle signals caught between calls to
3352 * sigsetjmp() and siglongjmp().
3353 *
3354 * Input:
3355 * gl GetLine * The resource object of this library.
3356 * Output:
3357 * return int 0 - Signal handled internally.
3358 * 1 - Signal requires gl_get_line() to abort.
3359 */
gl_check_caught_signal(GetLine * gl)3360 static int gl_check_caught_signal(GetLine *gl)
3361 {
3362 GlSignalNode *sig; /* The signal disposition */
3363 SigAction keep_action; /* The signal disposition of tecla signal handlers */
3364 unsigned flags; /* The signal processing flags to use */
3365 int signo; /* The signal to be handled */
3366 /*
3367 * Was no signal caught?
3368 */
3369 if(gl_pending_signal == -1)
3370 return 0;
3371 /*
3372 * Get the signal to be handled.
3373 */
3374 signo = gl_pending_signal;
3375 /*
3376 * Mark the signal as handled. Note that at this point, all of
3377 * the signals that we are trapping are blocked from delivery.
3378 */
3379 gl_pending_signal = -1;
3380 /*
3381 * Record the signal that was caught, so that the user can query it later.
3382 */
3383 gl->last_signal = signo;
3384 /*
3385 * In non-blocking server mode, the application is responsible for
3386 * responding to terminal signals, and we don't want gl_get_line()s
3387 * normal signal handling to clash with this, so whenever a signal
3388 * is caught, we arrange for gl_get_line() to abort and requeue the
3389 * signal while signals are still blocked. If the application
3390 * had the signal unblocked when gl_get_line() was called, the signal
3391 * will be delivered again as soon as gl_get_line() restores the
3392 * process signal mask, just before returning to the application.
3393 * Note that the caller of this function should set gl->pending_io
3394 * to the appropriate choice of GLP_READ and GLP_WRITE, before returning.
3395 */
3396 if(gl->io_mode==GL_SERVER_MODE) {
3397 gl_record_status(gl, GLR_SIGNAL, EINTR);
3398 raise(signo);
3399 return 1;
3400 };
3401 /*
3402 * Lookup the requested disposition of this signal.
3403 */
3404 for(sig=gl->sigs; sig && sig->signo != signo; sig=sig->next)
3405 ;
3406 if(!sig)
3407 return 0;
3408 /*
3409 * Get the signal response flags for this signal.
3410 */
3411 flags = sig->flags;
3412 /*
3413 * Only perform terminal-specific actions if the session is interactive.
3414 */
3415 if(gl->is_term) {
3416 /*
3417 * Did we receive a terminal size signal?
3418 */
3419 #ifdef SIGWINCH
3420 if(signo == SIGWINCH && _gl_update_size(gl))
3421 return 1;
3422 #endif
3423 /*
3424 * Start a fresh line?
3425 */
3426 if(flags & GLS_RESTORE_LINE) {
3427 if(gl_start_newline(gl, 0))
3428 return 1;
3429 };
3430 /*
3431 * Restore terminal settings to how they were before gl_get_line() was
3432 * called?
3433 */
3434 if(flags & GLS_RESTORE_TTY)
3435 gl_restore_terminal_attributes(gl);
3436 };
3437 /*
3438 * Restore signal handlers to how they were before gl_get_line() was
3439 * called? If this hasn't been requested, only reinstate the signal
3440 * handler of the signal that we are handling.
3441 */
3442 if(flags & GLS_RESTORE_SIG) {
3443 gl_restore_signal_handlers(gl);
3444 gl_unmask_signals(gl, &gl->old_signal_set);
3445 } else {
3446 (void) sigaction(sig->signo, &sig->original, &keep_action);
3447 (void) sigprocmask(SIG_UNBLOCK, &sig->proc_mask, NULL);
3448 };
3449 /*
3450 * Forward the signal to the application's signal handler.
3451 */
3452 if(!(flags & GLS_DONT_FORWARD))
3453 raise(signo);
3454 /*
3455 * Reinstate our signal handlers.
3456 */
3457 if(flags & GLS_RESTORE_SIG) {
3458 gl_mask_signals(gl, NULL);
3459 gl_override_signal_handlers(gl);
3460 } else {
3461 (void) sigaction(sig->signo, &keep_action, NULL);
3462 (void) sigprocmask(SIG_BLOCK, &sig->proc_mask, NULL);
3463 };
3464 /*
3465 * Prepare the terminal for continued editing, if this is an interactive
3466 * session.
3467 */
3468 if(gl->is_term) {
3469 /*
3470 * Do we need to reinstate our terminal settings?
3471 */
3472 if(flags & GLS_RESTORE_TTY)
3473 gl_raw_terminal_mode(gl);
3474 /*
3475 * Redraw the line?
3476 */
3477 if(flags & GLS_REDRAW_LINE)
3478 gl_queue_redisplay(gl);
3479 };
3480 /*
3481 * What next?
3482 */
3483 switch(sig->after) {
3484 case GLS_RETURN:
3485 gl_newline(gl, 1, NULL);
3486 return gl->is_term && gl_flush_output(gl);
3487 break;
3488 case GLS_ABORT:
3489 gl_record_status(gl, GLR_SIGNAL, sig->errno_value);
3490 return 1;
3491 break;
3492 case GLS_CONTINUE:
3493 return gl->is_term && gl_flush_output(gl);
3494 break;
3495 };
3496 return 0;
3497 }
3498
3499 /*.......................................................................
3500 * Get pertinent terminal control strings and the initial terminal size.
3501 *
3502 * Input:
3503 * gl GetLine * The resource object of this library.
3504 * term char * The type of the terminal.
3505 * Output:
3506 * return int 0 - OK.
3507 * 1 - Error.
3508 */
gl_control_strings(GetLine * gl,const char * term)3509 static int gl_control_strings(GetLine *gl, const char *term)
3510 {
3511 int bad_term = 0; /* True if term is unusable */
3512 /*
3513 * Discard any existing control strings from a previous terminal.
3514 */
3515 gl->left = NULL;
3516 gl->right = NULL;
3517 gl->up = NULL;
3518 gl->down = NULL;
3519 gl->home = NULL;
3520 gl->bol = 0;
3521 gl->clear_eol = NULL;
3522 gl->clear_eod = NULL;
3523 gl->u_arrow = NULL;
3524 gl->d_arrow = NULL;
3525 gl->l_arrow = NULL;
3526 gl->r_arrow = NULL;
3527 gl->sound_bell = NULL;
3528 gl->bold = NULL;
3529 gl->underline = NULL;
3530 gl->standout = NULL;
3531 gl->dim = NULL;
3532 gl->reverse = NULL;
3533 gl->blink = NULL;
3534 gl->text_attr_off = NULL;
3535 gl->nline = 0;
3536 gl->ncolumn = 0;
3537 #ifdef USE_TERMINFO
3538 gl->left_n = NULL;
3539 gl->right_n = NULL;
3540 #endif
3541 /*
3542 * If possible lookup the information in a terminal information
3543 * database.
3544 */
3545 #ifdef USE_TERMINFO
3546 {
3547 int errret;
3548 if(!term || setupterm((char *)term, gl->input_fd, &errret) == ERR) {
3549 bad_term = 1;
3550 } else {
3551 _clr_StringGroup(gl->capmem);
3552 gl->left = gl_tigetstr(gl, "cub1");
3553 gl->right = gl_tigetstr(gl, "cuf1");
3554 gl->up = gl_tigetstr(gl, "cuu1");
3555 gl->down = gl_tigetstr(gl, "cud1");
3556 gl->home = gl_tigetstr(gl, "home");
3557 gl->clear_eol = gl_tigetstr(gl, "el");
3558 gl->clear_eod = gl_tigetstr(gl, "ed");
3559 gl->u_arrow = gl_tigetstr(gl, "kcuu1");
3560 gl->d_arrow = gl_tigetstr(gl, "kcud1");
3561 gl->l_arrow = gl_tigetstr(gl, "kcub1");
3562 gl->r_arrow = gl_tigetstr(gl, "kcuf1");
3563 gl->left_n = gl_tigetstr(gl, "cub");
3564 gl->right_n = gl_tigetstr(gl, "cuf");
3565 gl->sound_bell = gl_tigetstr(gl, "bel");
3566 gl->bold = gl_tigetstr(gl, "bold");
3567 gl->underline = gl_tigetstr(gl, "smul");
3568 gl->standout = gl_tigetstr(gl, "smso");
3569 gl->dim = gl_tigetstr(gl, "dim");
3570 gl->reverse = gl_tigetstr(gl, "rev");
3571 gl->blink = gl_tigetstr(gl, "blink");
3572 gl->text_attr_off = gl_tigetstr(gl, "sgr0");
3573 };
3574 };
3575 #elif defined(USE_TERMCAP)
3576 if(!term || tgetent(gl->tgetent_buf, (char *)term) < 0) {
3577 bad_term = 1;
3578 } else {
3579 char *tgetstr_buf_ptr = gl->tgetstr_buf;
3580 _clr_StringGroup(gl->capmem);
3581 gl->left = gl_tgetstr(gl, "le", &tgetstr_buf_ptr);
3582 gl->right = gl_tgetstr(gl, "nd", &tgetstr_buf_ptr);
3583 gl->up = gl_tgetstr(gl, "up", &tgetstr_buf_ptr);
3584 gl->down = gl_tgetstr(gl, "do", &tgetstr_buf_ptr);
3585 gl->home = gl_tgetstr(gl, "ho", &tgetstr_buf_ptr);
3586 gl->clear_eol = gl_tgetstr(gl, "ce", &tgetstr_buf_ptr);
3587 gl->clear_eod = gl_tgetstr(gl, "cd", &tgetstr_buf_ptr);
3588 gl->u_arrow = gl_tgetstr(gl, "ku", &tgetstr_buf_ptr);
3589 gl->d_arrow = gl_tgetstr(gl, "kd", &tgetstr_buf_ptr);
3590 gl->l_arrow = gl_tgetstr(gl, "kl", &tgetstr_buf_ptr);
3591 gl->r_arrow = gl_tgetstr(gl, "kr", &tgetstr_buf_ptr);
3592 gl->sound_bell = gl_tgetstr(gl, "bl", &tgetstr_buf_ptr);
3593 gl->bold = gl_tgetstr(gl, "md", &tgetstr_buf_ptr);
3594 gl->underline = gl_tgetstr(gl, "us", &tgetstr_buf_ptr);
3595 gl->standout = gl_tgetstr(gl, "so", &tgetstr_buf_ptr);
3596 gl->dim = gl_tgetstr(gl, "mh", &tgetstr_buf_ptr);
3597 gl->reverse = gl_tgetstr(gl, "mr", &tgetstr_buf_ptr);
3598 gl->blink = gl_tgetstr(gl, "mb", &tgetstr_buf_ptr);
3599 gl->text_attr_off = gl_tgetstr(gl, "me", &tgetstr_buf_ptr);
3600 };
3601 #endif
3602 /*
3603 * Report term being unusable.
3604 */
3605 if(bad_term) {
3606 gl_print_info(gl, "Bad terminal type: \"", term ? term : "(null)",
3607 "\". Will assume vt100.", GL_END_INFO);
3608 };
3609 /*
3610 * Fill in missing information with ANSI VT100 strings.
3611 */
3612 if(!gl->left)
3613 gl->left = "\b"; /* ^H */
3614 if(!gl->right)
3615 gl->right = GL_ESC_STR "[C";
3616 if(!gl->up)
3617 gl->up = GL_ESC_STR "[A";
3618 if(!gl->down)
3619 gl->down = "\n";
3620 if(!gl->home)
3621 gl->home = GL_ESC_STR "[H";
3622 if(!gl->bol)
3623 gl->bol = "\r";
3624 if(!gl->clear_eol)
3625 gl->clear_eol = GL_ESC_STR "[K";
3626 if(!gl->clear_eod)
3627 gl->clear_eod = GL_ESC_STR "[J";
3628 if(!gl->u_arrow)
3629 gl->u_arrow = GL_ESC_STR "[A";
3630 if(!gl->d_arrow)
3631 gl->d_arrow = GL_ESC_STR "[B";
3632 if(!gl->l_arrow)
3633 gl->l_arrow = GL_ESC_STR "[D";
3634 if(!gl->r_arrow)
3635 gl->r_arrow = GL_ESC_STR "[C";
3636 if(!gl->sound_bell)
3637 gl->sound_bell = "\a";
3638 if(!gl->bold)
3639 gl->bold = GL_ESC_STR "[1m";
3640 if(!gl->underline)
3641 gl->underline = GL_ESC_STR "[4m";
3642 if(!gl->standout)
3643 gl->standout = GL_ESC_STR "[1;7m";
3644 if(!gl->dim)
3645 gl->dim = ""; /* Not available */
3646 if(!gl->reverse)
3647 gl->reverse = GL_ESC_STR "[7m";
3648 if(!gl->blink)
3649 gl->blink = GL_ESC_STR "[5m";
3650 if(!gl->text_attr_off)
3651 gl->text_attr_off = GL_ESC_STR "[m";
3652 /*
3653 * Find out the current terminal size.
3654 */
3655 (void) _gl_terminal_size(gl, GL_DEF_NCOLUMN, GL_DEF_NLINE, NULL);
3656 return 0;
3657 }
3658
3659 #ifdef USE_TERMINFO
3660 /*.......................................................................
3661 * This is a private function of gl_control_strings() used to look up
3662 * a termninal capability string from the terminfo database and make
3663 * a private copy of it.
3664 *
3665 * Input:
3666 * gl GetLine * The resource object of gl_get_line().
3667 * name const char * The name of the terminfo string to look up.
3668 * Output:
3669 * return const char * The local copy of the capability, or NULL
3670 * if not available.
3671 */
gl_tigetstr(GetLine * gl,const char * name)3672 static const char *gl_tigetstr(GetLine *gl, const char *name)
3673 {
3674 const char *value = tigetstr((char *)name);
3675 if(!value || value == (char *) -1)
3676 return NULL;
3677 return _sg_store_string(gl->capmem, value, 0);
3678 }
3679 #elif defined(USE_TERMCAP)
3680 /*.......................................................................
3681 * This is a private function of gl_control_strings() used to look up
3682 * a termninal capability string from the termcap database and make
3683 * a private copy of it. Note that some emulations of tgetstr(), such
3684 * as that used by Solaris, ignores the buffer pointer that is past to
3685 * it, so we can't assume that a private copy has been made that won't
3686 * be trashed by another call to gl_control_strings() by another
3687 * GetLine object. So we make what may be a redundant private copy
3688 * of the string in gl->capmem.
3689 *
3690 * Input:
3691 * gl GetLine * The resource object of gl_get_line().
3692 * name const char * The name of the terminfo string to look up.
3693 * Input/Output:
3694 * bufptr char ** On input *bufptr points to the location in
3695 * gl->tgetstr_buf at which to record the
3696 * capability string. On output *bufptr is
3697 * incremented over the stored string.
3698 * Output:
3699 * return const char * The local copy of the capability, or NULL
3700 * on error.
3701 */
gl_tgetstr(GetLine * gl,const char * name,char ** bufptr)3702 static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr)
3703 {
3704 const char *value = tgetstr((char *)name, bufptr);
3705 if(!value || value == (char *) -1)
3706 return NULL;
3707 return _sg_store_string(gl->capmem, value, 0);
3708 }
3709 #endif
3710
3711 /*.......................................................................
3712 * This is an action function that implements a user interrupt (eg. ^C).
3713 */
KT_KEY_FN(gl_user_interrupt)3714 static KT_KEY_FN(gl_user_interrupt)
3715 {
3716 raise(SIGINT);
3717 return 1;
3718 }
3719
3720 /*.......................................................................
3721 * This is an action function that implements the abort signal.
3722 */
KT_KEY_FN(gl_abort)3723 static KT_KEY_FN(gl_abort)
3724 {
3725 raise(SIGABRT);
3726 return 1;
3727 }
3728
3729 /*.......................................................................
3730 * This is an action function that sends a suspend signal (eg. ^Z) to the
3731 * the parent process.
3732 */
KT_KEY_FN(gl_suspend)3733 static KT_KEY_FN(gl_suspend)
3734 {
3735 raise(SIGTSTP);
3736 return 0;
3737 }
3738
3739 /*.......................................................................
3740 * This is an action function that halts output to the terminal.
3741 */
KT_KEY_FN(gl_stop_output)3742 static KT_KEY_FN(gl_stop_output)
3743 {
3744 tcflow(gl->output_fd, TCOOFF);
3745 return 0;
3746 }
3747
3748 /*.......................................................................
3749 * This is an action function that resumes halted terminal output.
3750 */
KT_KEY_FN(gl_start_output)3751 static KT_KEY_FN(gl_start_output)
3752 {
3753 tcflow(gl->output_fd, TCOON);
3754 return 0;
3755 }
3756
3757 /*.......................................................................
3758 * This is an action function that allows the next character to be accepted
3759 * without any interpretation as a special character.
3760 */
KT_KEY_FN(gl_literal_next)3761 static KT_KEY_FN(gl_literal_next)
3762 {
3763 char c; /* The character to be added to the line */
3764 int i;
3765 /*
3766 * Get the character to be inserted literally.
3767 */
3768 if(gl_read_terminal(gl, 1, &c))
3769 return 1;
3770 /*
3771 * Add the character to the line 'count' times.
3772 */
3773 for(i=0; i<count; i++)
3774 gl_add_char_to_line(gl, c);
3775 return 0;
3776 }
3777
3778 /*.......................................................................
3779 * Return the width of a tab character at a given position when
3780 * displayed at a given position on the terminal. This is needed
3781 * because the width of tab characters depends on where they are,
3782 * relative to the preceding tab stops.
3783 *
3784 * Input:
3785 * gl GetLine * The resource object of this library.
3786 * term_curpos int The destination terminal location of the character.
3787 * Output:
3788 * return int The number of terminal charaters needed.
3789 */
gl_displayed_tab_width(GetLine * gl,int term_curpos)3790 static int gl_displayed_tab_width(GetLine *gl, int term_curpos)
3791 {
3792 return TAB_WIDTH - ((term_curpos % gl->ncolumn) % TAB_WIDTH);
3793 }
3794
3795 /*.......................................................................
3796 * Return the number of characters needed to display a given character
3797 * on the screen. Tab characters require eight spaces, and control
3798 * characters are represented by a caret followed by the modified
3799 * character.
3800 *
3801 * Input:
3802 * gl GetLine * The resource object of this library.
3803 * c char The character to be displayed.
3804 * term_curpos int The destination terminal location of the character.
3805 * This is needed because the width of tab characters
3806 * depends on where they are, relative to the
3807 * preceding tab stops.
3808 * Output:
3809 * return int The number of terminal charaters needed.
3810 */
gl_displayed_char_width(GetLine * gl,char c,int term_curpos)3811 static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos)
3812 {
3813 if(c=='\t')
3814 return gl_displayed_tab_width(gl, term_curpos);
3815 if(IS_CTRL_CHAR(c))
3816 return 2;
3817 if(!isprint((int)(unsigned char) c))
3818 return gl_octal_width((int)(unsigned char)c) + 1;
3819 return 1;
3820 }
3821
3822
3823 /*.......................................................................
3824 * Work out the length of given string of characters on the terminal.
3825 *
3826 * Input:
3827 * gl GetLine * The resource object of this library.
3828 * string char * The string to be measured.
3829 * nc int The number of characters to be measured, or -1
3830 * to measure the whole string.
3831 * term_curpos int The destination terminal location of the character.
3832 * This is needed because the width of tab characters
3833 * depends on where they are, relative to the
3834 * preceding tab stops.
3835 * Output:
3836 * return int The number of displayed characters.
3837 */
gl_displayed_string_width(GetLine * gl,const char * string,int nc,int term_curpos)3838 static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
3839 int term_curpos)
3840 {
3841 int slen = 0; /* The displayed number of characters */
3842 int i;
3843 /*
3844 * How many characters are to be measured?
3845 */
3846 if(nc < 0)
3847 nc = strlen(string);
3848 /*
3849 * Add up the length of the displayed string.
3850 */
3851 for(i=0; i<nc; i++)
3852 slen += gl_displayed_char_width(gl, string[i], term_curpos + slen);
3853 return slen;
3854 }
3855
3856 /*.......................................................................
3857 * Write a string verbatim to the current terminal or output stream.
3858 *
3859 * Note that when async-signal safety is required, the 'buffered'
3860 * argument must be 0, and n must not be -1.
3861 *
3862 * Input:
3863 * gl GetLine * The resource object of the gl_get_line().
3864 * buffered int If true, used buffered I/O when writing to
3865 * the terminal. Otherwise use async-signal-safe
3866 * unbuffered I/O.
3867 * string const char * The string to be written (this need not be
3868 * '\0' terminated unless n<0).
3869 * n int The number of characters to write from the
3870 * prefix of string[], or -1 to request that
3871 * gl_print_raw_string() use strlen() to figure
3872 * out the length.
3873 * Output:
3874 * return int 0 - OK.
3875 * 1 - Error.
3876 */
gl_print_raw_string(GetLine * gl,int buffered,const char * string,int n)3877 static int gl_print_raw_string(GetLine *gl, int buffered,
3878 const char *string, int n)
3879 {
3880 GlWriteFn *write_fn = buffered ? gl_write_fn : gl->flush_fn;
3881 /*
3882 * Only display output when echoing is turned on.
3883 */
3884 if(gl->echo) {
3885 int ndone = 0; /* The number of characters written so far */
3886 /*
3887 * When using un-buffered I/O, flush pending output first.
3888 */
3889 if(!buffered) {
3890 if(gl_flush_output(gl))
3891 return 1;
3892 };
3893 /*
3894 * If no length has been provided, measure the length of the string.
3895 */
3896 if(n < 0)
3897 n = strlen(string);
3898 /*
3899 * Write the string.
3900 */
3901 if(write_fn(gl, string + ndone, n-ndone) != n)
3902 return 1;
3903 };
3904 return 0;
3905 }
3906
3907 /*.......................................................................
3908 * Output a terminal control sequence. When using terminfo,
3909 * this must be a sequence returned by tgetstr() or tigetstr()
3910 * respectively.
3911 *
3912 * Input:
3913 * gl GetLine * The resource object of this library.
3914 * nline int The number of lines affected by the operation,
3915 * or 1 if not relevant.
3916 * string char * The control sequence to be sent.
3917 * Output:
3918 * return int 0 - OK.
3919 * 1 - Error.
3920 */
gl_print_control_sequence(GetLine * gl,int nline,const char * string)3921 static int gl_print_control_sequence(GetLine *gl, int nline, const char *string)
3922 {
3923 int waserr = 0; /* True if an error occurs */
3924 /*
3925 * Only write characters to the terminal when echoing is enabled.
3926 */
3927 if(gl->echo) {
3928 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
3929 tputs_gl = gl;
3930 errno = 0;
3931 tputs((char *)string, nline, gl_tputs_putchar);
3932 waserr = errno != 0;
3933 #else
3934 waserr = gl_print_raw_string(gl, 1, string, -1);
3935 #endif
3936 };
3937 return waserr;
3938 }
3939
3940 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
3941 /*.......................................................................
3942 * The following callback function is called by tputs() to output a raw
3943 * control character to the terminal.
3944 */
gl_tputs_putchar(TputsArgType c)3945 static TputsRetType gl_tputs_putchar(TputsArgType c)
3946 {
3947 char ch = c;
3948 #if TPUTS_RETURNS_VALUE
3949 return gl_print_raw_string(tputs_gl, 1, &ch, 1);
3950 #else
3951 (void) gl_print_raw_string(tputs_gl, 1, &ch, 1);
3952 #endif
3953 }
3954 #endif
3955
3956 /*.......................................................................
3957 * Move the terminal cursor n characters to the left or right.
3958 *
3959 * Input:
3960 * gl GetLine * The resource object of this program.
3961 * n int number of positions to the right (> 0) or left (< 0).
3962 * Output:
3963 * return int 0 - OK.
3964 * 1 - Error.
3965 */
gl_terminal_move_cursor(GetLine * gl,int n)3966 static int gl_terminal_move_cursor(GetLine *gl, int n)
3967 {
3968 int cur_row, cur_col; /* The current terminal row and column index of */
3969 /* the cursor wrt the start of the input line. */
3970 int new_row, new_col; /* The target terminal row and column index of */
3971 /* the cursor wrt the start of the input line. */
3972 /*
3973 * Do nothing if the input line isn't currently displayed. In this
3974 * case, the cursor will be moved to the right place when the line
3975 * is next redisplayed.
3976 */
3977 if(!gl->displayed)
3978 return 0;
3979 /*
3980 * How far can we move left?
3981 */
3982 if(gl->term_curpos + n < 0)
3983 n = gl->term_curpos;
3984 /*
3985 * Break down the current and target cursor locations into rows and columns.
3986 */
3987 cur_row = gl->term_curpos / gl->ncolumn;
3988 cur_col = gl->term_curpos % gl->ncolumn;
3989 new_row = (gl->term_curpos + n) / gl->ncolumn;
3990 new_col = (gl->term_curpos + n) % gl->ncolumn;
3991 /*
3992 * Move down to the next line.
3993 */
3994 for(; cur_row < new_row; cur_row++) {
3995 if(gl_print_control_sequence(gl, 1, gl->down))
3996 return 1;
3997 };
3998 /*
3999 * Move up to the previous line.
4000 */
4001 for(; cur_row > new_row; cur_row--) {
4002 if(gl_print_control_sequence(gl, 1, gl->up))
4003 return 1;
4004 };
4005 /*
4006 * Move to the right within the target line?
4007 */
4008 if(cur_col < new_col) {
4009 #ifdef USE_TERMINFO
4010 /*
4011 * Use a parameterized control sequence if it generates less control
4012 * characters (guess based on ANSI terminal termcap entry).
4013 */
4014 if(gl->right_n != NULL && new_col - cur_col > 1) {
4015 if(gl_print_control_sequence(gl, 1, tparm((char *)gl->right_n,
4016 (long)(new_col - cur_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
4017 return 1;
4018 } else
4019 #endif
4020 {
4021 for(; cur_col < new_col; cur_col++) {
4022 if(gl_print_control_sequence(gl, 1, gl->right))
4023 return 1;
4024 };
4025 };
4026 /*
4027 * Move to the left within the target line?
4028 */
4029 } else if(cur_col > new_col) {
4030 #ifdef USE_TERMINFO
4031 /*
4032 * Use a parameterized control sequence if it generates less control
4033 * characters (guess based on ANSI terminal termcap entry).
4034 */
4035 if(gl->left_n != NULL && cur_col - new_col > 3) {
4036 if(gl_print_control_sequence(gl, 1, tparm((char *)gl->left_n,
4037 (long)(cur_col - new_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
4038 return 1;
4039 } else
4040 #endif
4041 {
4042 for(; cur_col > new_col; cur_col--) {
4043 if(gl_print_control_sequence(gl, 1, gl->left))
4044 return 1;
4045 };
4046 };
4047 }
4048 /*
4049 * Update the recorded position of the terminal cursor.
4050 */
4051 gl->term_curpos += n;
4052 return 0;
4053 }
4054
4055 /*.......................................................................
4056 * Write a character to the terminal after expanding tabs and control
4057 * characters to their multi-character representations.
4058 *
4059 * Input:
4060 * gl GetLine * The resource object of this program.
4061 * c char The character to be output.
4062 * pad char Many terminals have the irritating feature that
4063 * when one writes a character in the last column of
4064 * of the terminal, the cursor isn't wrapped to the
4065 * start of the next line until one more character
4066 * is written. Some terminals don't do this, so
4067 * after such a write, we don't know where the
4068 * terminal is unless we output an extra character.
4069 * This argument specifies the character to write.
4070 * If at the end of the input line send '\0' or a
4071 * space, and a space will be written. Otherwise,
4072 * pass the next character in the input line
4073 * following the one being written.
4074 * Output:
4075 * return int 0 - OK.
4076 */
gl_print_char(GetLine * gl,char c,char pad)4077 static int gl_print_char(GetLine *gl, char c, char pad)
4078 {
4079 char string[TAB_WIDTH + 4]; /* A work area for composing compound strings */
4080 int nchar; /* The number of terminal characters */
4081 int i;
4082 /*
4083 * Check for special characters.
4084 */
4085 if(c == '\t') {
4086 /*
4087 * How many spaces do we need to represent a tab at the current terminal
4088 * column?
4089 */
4090 nchar = gl_displayed_tab_width(gl, gl->term_curpos);
4091 /*
4092 * Compose the tab string.
4093 */
4094 for(i=0; i<nchar; i++)
4095 string[i] = ' ';
4096 } else if(IS_CTRL_CHAR(c)) {
4097 string[0] = '^';
4098 string[1] = CTRL_TO_CHAR(c);
4099 nchar = 2;
4100 } else if(!isprint((int)(unsigned char) c)) {
4101 sprintf(string, "\\%o", (int)(unsigned char)c);
4102 nchar = strlen(string);
4103 } else {
4104 string[0] = c;
4105 nchar = 1;
4106 };
4107 /*
4108 * Terminate the string.
4109 */
4110 string[nchar] = '\0';
4111 /*
4112 * Write the string to the terminal.
4113 */
4114 if(gl_print_raw_string(gl, 1, string, -1))
4115 return 1;
4116 /*
4117 * Except for one exception to be described in a moment, the cursor should
4118 * now have been positioned after the character that was just output.
4119 */
4120 gl->term_curpos += nchar;
4121 /*
4122 * Keep a record of the number of characters in the terminal version
4123 * of the input line.
4124 */
4125 if(gl->term_curpos > gl->term_len)
4126 gl->term_len = gl->term_curpos;
4127 /*
4128 * If the new character ended exactly at the end of a line,
4129 * most terminals won't move the cursor onto the next line until we
4130 * have written a character on the next line, so append an extra
4131 * space then move the cursor back.
4132 */
4133 if(gl->term_curpos % gl->ncolumn == 0) {
4134 int term_curpos = gl->term_curpos;
4135 if(gl_print_char(gl, pad ? pad : ' ', ' ') ||
4136 gl_set_term_curpos(gl, term_curpos))
4137 return 1;
4138 };
4139 return 0;
4140 }
4141
4142 /*.......................................................................
4143 * Write a string to the terminal after expanding tabs and control
4144 * characters to their multi-character representations.
4145 *
4146 * Input:
4147 * gl GetLine * The resource object of this program.
4148 * string char * The string to be output.
4149 * pad char Many terminals have the irritating feature that
4150 * when one writes a character in the last column of
4151 * of the terminal, the cursor isn't wrapped to the
4152 * start of the next line until one more character
4153 * is written. Some terminals don't do this, so
4154 * after such a write, we don't know where the
4155 * terminal is unless we output an extra character.
4156 * This argument specifies the character to write.
4157 * If at the end of the input line send '\0' or a
4158 * space, and a space will be written. Otherwise,
4159 * pass the next character in the input line
4160 * following the one being written.
4161 * Output:
4162 * return int 0 - OK.
4163 */
gl_print_string(GetLine * gl,const char * string,char pad)4164 static int gl_print_string(GetLine *gl, const char *string, char pad)
4165 {
4166 const char *cptr; /* A pointer into string[] */
4167 for(cptr=string; *cptr; cptr++) {
4168 char nextc = cptr[1];
4169 if(gl_print_char(gl, *cptr, nextc ? nextc : pad))
4170 return 1;
4171 };
4172 return 0;
4173 }
4174
4175 /*.......................................................................
4176 * Move the terminal cursor position.
4177 *
4178 * Input:
4179 * gl GetLine * The resource object of this library.
4180 * term_curpos int The destination terminal cursor position.
4181 * Output:
4182 * return int 0 - OK.
4183 * 1 - Error.
4184 */
gl_set_term_curpos(GetLine * gl,int term_curpos)4185 static int gl_set_term_curpos(GetLine *gl, int term_curpos)
4186 {
4187 return gl_terminal_move_cursor(gl, term_curpos - gl->term_curpos);
4188 }
4189
4190 /*.......................................................................
4191 * This is an action function that moves the buffer cursor one character
4192 * left, and updates the terminal cursor to match.
4193 */
KT_KEY_FN(gl_cursor_left)4194 static KT_KEY_FN(gl_cursor_left)
4195 {
4196 return gl_place_cursor(gl, gl->buff_curpos - count);
4197 }
4198
4199 /*.......................................................................
4200 * This is an action function that moves the buffer cursor one character
4201 * right, and updates the terminal cursor to match.
4202 */
KT_KEY_FN(gl_cursor_right)4203 static KT_KEY_FN(gl_cursor_right)
4204 {
4205 return gl_place_cursor(gl, gl->buff_curpos + count);
4206 }
4207
4208 /*.......................................................................
4209 * This is an action function that toggles between overwrite and insert
4210 * mode.
4211 */
KT_KEY_FN(gl_insert_mode)4212 static KT_KEY_FN(gl_insert_mode)
4213 {
4214 gl->insert = !gl->insert;
4215 return 0;
4216 }
4217
4218 /*.......................................................................
4219 * This is an action function which moves the cursor to the beginning of
4220 * the line.
4221 */
KT_KEY_FN(gl_beginning_of_line)4222 static KT_KEY_FN(gl_beginning_of_line)
4223 {
4224 return gl_place_cursor(gl, 0);
4225 }
4226
4227 /*.......................................................................
4228 * This is an action function which moves the cursor to the end of
4229 * the line.
4230 */
KT_KEY_FN(gl_end_of_line)4231 static KT_KEY_FN(gl_end_of_line)
4232 {
4233 return gl_place_cursor(gl, gl->ntotal);
4234 }
4235
4236 /*.......................................................................
4237 * This is an action function which deletes the entire contents of the
4238 * current line.
4239 */
KT_KEY_FN(gl_delete_line)4240 static KT_KEY_FN(gl_delete_line)
4241 {
4242 /*
4243 * If in vi command mode, preserve the current line for potential
4244 * use by vi-undo.
4245 */
4246 gl_save_for_undo(gl);
4247 /*
4248 * Copy the contents of the line to the cut buffer.
4249 */
4250 strcpy(gl->cutbuf, gl->line);
4251 /*
4252 * Clear the buffer.
4253 */
4254 gl_truncate_buffer(gl, 0);
4255 /*
4256 * Move the terminal cursor to just after the prompt.
4257 */
4258 if(gl_place_cursor(gl, 0))
4259 return 1;
4260 /*
4261 * Clear from the end of the prompt to the end of the terminal.
4262 */
4263 if(gl_truncate_display(gl))
4264 return 1;
4265 return 0;
4266 }
4267
4268 /*.......................................................................
4269 * This is an action function which deletes all characters between the
4270 * current cursor position and the end of the line.
4271 */
KT_KEY_FN(gl_kill_line)4272 static KT_KEY_FN(gl_kill_line)
4273 {
4274 /*
4275 * If in vi command mode, preserve the current line for potential
4276 * use by vi-undo.
4277 */
4278 gl_save_for_undo(gl);
4279 /*
4280 * Copy the part of the line that is about to be deleted to the cut buffer.
4281 */
4282 strcpy(gl->cutbuf, gl->line + gl->buff_curpos);
4283 /*
4284 * Terminate the buffered line at the current cursor position.
4285 */
4286 gl_truncate_buffer(gl, gl->buff_curpos);
4287 /*
4288 * Clear the part of the line that follows the cursor.
4289 */
4290 if(gl_truncate_display(gl))
4291 return 1;
4292 /*
4293 * Explicitly reset the cursor position to allow vi command mode
4294 * constraints on its position to be set.
4295 */
4296 return gl_place_cursor(gl, gl->buff_curpos);
4297 }
4298
4299 /*.......................................................................
4300 * This is an action function which deletes all characters between the
4301 * start of the line and the current cursor position.
4302 */
KT_KEY_FN(gl_backward_kill_line)4303 static KT_KEY_FN(gl_backward_kill_line)
4304 {
4305 /*
4306 * How many characters are to be deleted from before the cursor?
4307 */
4308 int nc = gl->buff_curpos - gl->insert_curpos;
4309 if (!nc)
4310 return 0;
4311 /*
4312 * Move the cursor to the start of the line, or in vi input mode,
4313 * the start of the sub-line at which insertion started, and delete
4314 * up to the old cursor position.
4315 */
4316 return gl_place_cursor(gl, gl->insert_curpos) ||
4317 gl_delete_chars(gl, nc, gl->editor == GL_EMACS_MODE || gl->vi.command);
4318 }
4319
4320 /*.......................................................................
4321 * This is an action function which moves the cursor forward by a word.
4322 */
KT_KEY_FN(gl_forward_word)4323 static KT_KEY_FN(gl_forward_word)
4324 {
4325 return gl_place_cursor(gl, gl_nth_word_end_forward(gl, count) +
4326 (gl->editor==GL_EMACS_MODE));
4327 }
4328
4329 /*.......................................................................
4330 * This is an action function which moves the cursor forward to the start
4331 * of the next word.
4332 */
KT_KEY_FN(gl_forward_to_word)4333 static KT_KEY_FN(gl_forward_to_word)
4334 {
4335 return gl_place_cursor(gl, gl_nth_word_start_forward(gl, count));
4336 }
4337
4338 /*.......................................................................
4339 * This is an action function which moves the cursor backward by a word.
4340 */
KT_KEY_FN(gl_backward_word)4341 static KT_KEY_FN(gl_backward_word)
4342 {
4343 return gl_place_cursor(gl, gl_nth_word_start_backward(gl, count));
4344 }
4345
4346 /*.......................................................................
4347 * Delete one or more characters, starting with the one under the cursor.
4348 *
4349 * Input:
4350 * gl GetLine * The resource object of this library.
4351 * nc int The number of characters to delete.
4352 * cut int If true, copy the characters to the cut buffer.
4353 * Output:
4354 * return int 0 - OK.
4355 * 1 - Error.
4356 */
gl_delete_chars(GetLine * gl,int nc,int cut)4357 static int gl_delete_chars(GetLine *gl, int nc, int cut)
4358 {
4359 /*
4360 * If in vi command mode, preserve the current line for potential
4361 * use by vi-undo.
4362 */
4363 gl_save_for_undo(gl);
4364 /*
4365 * If there are fewer than nc characters following the cursor, limit
4366 * nc to the number available.
4367 */
4368 if(gl->buff_curpos + nc > gl->ntotal)
4369 nc = gl->ntotal - gl->buff_curpos;
4370 /*
4371 * Copy the about to be deleted region to the cut buffer.
4372 */
4373 if(cut) {
4374 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, nc);
4375 gl->cutbuf[nc] = '\0';
4376 }
4377 /*
4378 * Nothing to delete?
4379 */
4380 if(nc <= 0)
4381 return 0;
4382 /*
4383 * In vi overwrite mode, restore any previously overwritten characters
4384 * from the undo buffer.
4385 */
4386 if(gl->editor == GL_VI_MODE && !gl->vi.command && !gl->insert) {
4387 /*
4388 * How many of the characters being deleted can be restored from the
4389 * undo buffer?
4390 */
4391 int nrestore = gl->buff_curpos + nc <= gl->vi.undo.ntotal ?
4392 nc : gl->vi.undo.ntotal - gl->buff_curpos;
4393 /*
4394 * Restore any available characters.
4395 */
4396 if(nrestore > 0) {
4397 gl_buffer_string(gl, gl->vi.undo.line + gl->buff_curpos, nrestore,
4398 gl->buff_curpos);
4399 };
4400 /*
4401 * If their were insufficient characters in the undo buffer, then this
4402 * implies that we are deleting from the end of the line, so we need
4403 * to terminate the line either where the undo buffer ran out, or if
4404 * we are deleting from beyond the end of the undo buffer, at the current
4405 * cursor position.
4406 */
4407 if(nc != nrestore) {
4408 gl_truncate_buffer(gl, (gl->vi.undo.ntotal > gl->buff_curpos) ?
4409 gl->vi.undo.ntotal : gl->buff_curpos);
4410 };
4411 } else {
4412 /*
4413 * Copy the remaining part of the line back over the deleted characters.
4414 */
4415 gl_remove_from_buffer(gl, gl->buff_curpos, nc);
4416 };
4417 /*
4418 * Redraw the remaining characters following the cursor.
4419 */
4420 if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0'))
4421 return 1;
4422 /*
4423 * Clear to the end of the terminal.
4424 */
4425 if(gl_truncate_display(gl))
4426 return 1;
4427 /*
4428 * Place the cursor at the start of where the deletion was performed.
4429 */
4430 return gl_place_cursor(gl, gl->buff_curpos);
4431 }
4432
4433 /*.......................................................................
4434 * This is an action function which deletes character(s) under the
4435 * cursor without moving the cursor.
4436 */
KT_KEY_FN(gl_forward_delete_char)4437 static KT_KEY_FN(gl_forward_delete_char)
4438 {
4439 /*
4440 * Delete 'count' characters.
4441 */
4442 return gl_delete_chars(gl, count, gl->vi.command);
4443 }
4444
4445 /*.......................................................................
4446 * This is an action function which deletes character(s) under the
4447 * cursor and moves the cursor back one character.
4448 */
KT_KEY_FN(gl_backward_delete_char)4449 static KT_KEY_FN(gl_backward_delete_char)
4450 {
4451 /*
4452 * Restrict the deletion count to the number of characters that
4453 * precede the insertion point.
4454 */
4455 if(count > gl->buff_curpos - gl->insert_curpos)
4456 count = gl->buff_curpos - gl->insert_curpos;
4457 /*
4458 * If in vi command mode, preserve the current line for potential
4459 * use by vi-undo.
4460 */
4461 gl_save_for_undo(gl);
4462 return gl_cursor_left(gl, count, NULL) ||
4463 gl_delete_chars(gl, count, gl->vi.command);
4464 }
4465
4466 /*.......................................................................
4467 * Starting from the cursor position delete to the specified column.
4468 */
KT_KEY_FN(gl_delete_to_column)4469 static KT_KEY_FN(gl_delete_to_column)
4470 {
4471 if (--count >= gl->buff_curpos)
4472 return gl_forward_delete_char(gl, count - gl->buff_curpos, NULL);
4473 else
4474 return gl_backward_delete_char(gl, gl->buff_curpos - count, NULL);
4475 }
4476
4477 /*.......................................................................
4478 * Starting from the cursor position delete characters to a matching
4479 * parenthesis.
4480 */
KT_KEY_FN(gl_delete_to_parenthesis)4481 static KT_KEY_FN(gl_delete_to_parenthesis)
4482 {
4483 int curpos = gl_index_of_matching_paren(gl);
4484 if(curpos >= 0) {
4485 gl_save_for_undo(gl);
4486 if(curpos >= gl->buff_curpos)
4487 return gl_forward_delete_char(gl, curpos - gl->buff_curpos + 1, NULL);
4488 else
4489 return gl_backward_delete_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
4490 };
4491 return 0;
4492 }
4493
4494 /*.......................................................................
4495 * This is an action function which deletes from the cursor to the end
4496 * of the word that the cursor is either in or precedes.
4497 */
KT_KEY_FN(gl_forward_delete_word)4498 static KT_KEY_FN(gl_forward_delete_word)
4499 {
4500 /*
4501 * If in vi command mode, preserve the current line for potential
4502 * use by vi-undo.
4503 */
4504 gl_save_for_undo(gl);
4505 /*
4506 * In emacs mode delete to the end of the word. In vi mode delete to the
4507 * start of the net word.
4508 */
4509 if(gl->editor == GL_EMACS_MODE) {
4510 return gl_delete_chars(gl,
4511 gl_nth_word_end_forward(gl,count) - gl->buff_curpos + 1, 1);
4512 } else {
4513 return gl_delete_chars(gl,
4514 gl_nth_word_start_forward(gl,count) - gl->buff_curpos,
4515 gl->vi.command);
4516 };
4517 }
4518
4519 /*.......................................................................
4520 * This is an action function which deletes the word that precedes the
4521 * cursor.
4522 */
KT_KEY_FN(gl_backward_delete_word)4523 static KT_KEY_FN(gl_backward_delete_word)
4524 {
4525 /*
4526 * Keep a record of the current cursor position.
4527 */
4528 int buff_curpos = gl->buff_curpos;
4529 /*
4530 * If in vi command mode, preserve the current line for potential
4531 * use by vi-undo.
4532 */
4533 gl_save_for_undo(gl);
4534 /*
4535 * Move back 'count' words.
4536 */
4537 if(gl_backward_word(gl, count, NULL))
4538 return 1;
4539 /*
4540 * Delete from the new cursor position to the original one.
4541 */
4542 return gl_delete_chars(gl, buff_curpos - gl->buff_curpos,
4543 gl->editor == GL_EMACS_MODE || gl->vi.command);
4544 }
4545
4546 /*.......................................................................
4547 * Searching in a given direction, delete to the count'th
4548 * instance of a specified or queried character, in the input line.
4549 *
4550 * Input:
4551 * gl GetLine * The getline resource object.
4552 * count int The number of times to search.
4553 * c char The character to be searched for, or '\0' if
4554 * the character should be read from the user.
4555 * forward int True if searching forward.
4556 * onto int True if the search should end on top of the
4557 * character, false if the search should stop
4558 * one character before the character in the
4559 * specified search direction.
4560 * change int If true, this function is being called upon
4561 * to do a vi change command, in which case the
4562 * user will be left in insert mode after the
4563 * deletion.
4564 * Output:
4565 * return int 0 - OK.
4566 * 1 - Error.
4567 */
gl_delete_find(GetLine * gl,int count,char c,int forward,int onto,int change)4568 static int gl_delete_find(GetLine *gl, int count, char c, int forward,
4569 int onto, int change)
4570 {
4571 /*
4572 * Search for the character, and abort the deletion if not found.
4573 */
4574 int pos = gl_find_char(gl, count, forward, onto, c);
4575 if(pos < 0)
4576 return 0;
4577 /*
4578 * If in vi command mode, preserve the current line for potential
4579 * use by vi-undo.
4580 */
4581 gl_save_for_undo(gl);
4582 /*
4583 * Allow the cursor to be at the end of the line if this is a change
4584 * command.
4585 */
4586 if(change)
4587 gl->vi.command = 0;
4588 /*
4589 * Delete the appropriate span of characters.
4590 */
4591 if(forward) {
4592 if(gl_delete_chars(gl, pos - gl->buff_curpos + 1, 1))
4593 return 1;
4594 } else {
4595 int buff_curpos = gl->buff_curpos;
4596 if(gl_place_cursor(gl, pos) ||
4597 gl_delete_chars(gl, buff_curpos - gl->buff_curpos, 1))
4598 return 1;
4599 };
4600 /*
4601 * If this is a change operation, switch the insert mode.
4602 */
4603 if(change && gl_vi_insert(gl, 0, NULL))
4604 return 1;
4605 return 0;
4606 }
4607
4608 /*.......................................................................
4609 * This is an action function which deletes forward from the cursor up to and
4610 * including a specified character.
4611 */
KT_KEY_FN(gl_forward_delete_find)4612 static KT_KEY_FN(gl_forward_delete_find)
4613 {
4614 return gl_delete_find(gl, count, '\0', 1, 1, 0);
4615 }
4616
4617 /*.......................................................................
4618 * This is an action function which deletes backward from the cursor back to
4619 * and including a specified character.
4620 */
KT_KEY_FN(gl_backward_delete_find)4621 static KT_KEY_FN(gl_backward_delete_find)
4622 {
4623 return gl_delete_find(gl, count, '\0', 0, 1, 0);
4624 }
4625
4626 /*.......................................................................
4627 * This is an action function which deletes forward from the cursor up to but
4628 * not including a specified character.
4629 */
KT_KEY_FN(gl_forward_delete_to)4630 static KT_KEY_FN(gl_forward_delete_to)
4631 {
4632 return gl_delete_find(gl, count, '\0', 1, 0, 0);
4633 }
4634
4635 /*.......................................................................
4636 * This is an action function which deletes backward from the cursor back to
4637 * but not including a specified character.
4638 */
KT_KEY_FN(gl_backward_delete_to)4639 static KT_KEY_FN(gl_backward_delete_to)
4640 {
4641 return gl_delete_find(gl, count, '\0', 0, 0, 0);
4642 }
4643
4644 /*.......................................................................
4645 * This is an action function which deletes to a character specified by a
4646 * previous search.
4647 */
KT_KEY_FN(gl_delete_refind)4648 static KT_KEY_FN(gl_delete_refind)
4649 {
4650 return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
4651 gl->vi.find_onto, 0);
4652 }
4653
4654 /*.......................................................................
4655 * This is an action function which deletes to a character specified by a
4656 * previous search, but in the opposite direction.
4657 */
KT_KEY_FN(gl_delete_invert_refind)4658 static KT_KEY_FN(gl_delete_invert_refind)
4659 {
4660 return gl_delete_find(gl, count, gl->vi.find_char,
4661 !gl->vi.find_forward, gl->vi.find_onto, 0);
4662 }
4663
4664 /*.......................................................................
4665 * This is an action function which converts the characters in the word
4666 * following the cursor to upper case.
4667 */
KT_KEY_FN(gl_upcase_word)4668 static KT_KEY_FN(gl_upcase_word)
4669 {
4670 /*
4671 * Locate the count'th word ending after the cursor.
4672 */
4673 int last = gl_nth_word_end_forward(gl, count);
4674 /*
4675 * If in vi command mode, preserve the current line for potential
4676 * use by vi-undo.
4677 */
4678 gl_save_for_undo(gl);
4679 /*
4680 * Upcase characters from the current cursor position to 'last'.
4681 */
4682 while(gl->buff_curpos <= last) {
4683 char *cptr = gl->line + gl->buff_curpos;
4684 /*
4685 * Convert the character to upper case?
4686 */
4687 if(islower((int)(unsigned char) *cptr))
4688 gl_buffer_char(gl, toupper((int) *cptr), gl->buff_curpos);
4689 gl->buff_curpos++;
4690 /*
4691 * Write the possibly modified character back. Note that for non-modified
4692 * characters we want to do this as well, so as to advance the cursor.
4693 */
4694 if(gl_print_char(gl, *cptr, cptr[1]))
4695 return 1;
4696 };
4697 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4698 }
4699
4700 /*.......................................................................
4701 * This is an action function which converts the characters in the word
4702 * following the cursor to lower case.
4703 */
KT_KEY_FN(gl_downcase_word)4704 static KT_KEY_FN(gl_downcase_word)
4705 {
4706 /*
4707 * Locate the count'th word ending after the cursor.
4708 */
4709 int last = gl_nth_word_end_forward(gl, count);
4710 /*
4711 * If in vi command mode, preserve the current line for potential
4712 * use by vi-undo.
4713 */
4714 gl_save_for_undo(gl);
4715 /*
4716 * Upcase characters from the current cursor position to 'last'.
4717 */
4718 while(gl->buff_curpos <= last) {
4719 char *cptr = gl->line + gl->buff_curpos;
4720 /*
4721 * Convert the character to upper case?
4722 */
4723 if(isupper((int)(unsigned char) *cptr))
4724 gl_buffer_char(gl, tolower((int) *cptr), gl->buff_curpos);
4725 gl->buff_curpos++;
4726 /*
4727 * Write the possibly modified character back. Note that for non-modified
4728 * characters we want to do this as well, so as to advance the cursor.
4729 */
4730 if(gl_print_char(gl, *cptr, cptr[1]))
4731 return 1;
4732 };
4733 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4734 }
4735
4736 /*.......................................................................
4737 * This is an action function which converts the first character of the
4738 * following word to upper case, in order to capitalize the word, and
4739 * leaves the cursor at the end of the word.
4740 */
KT_KEY_FN(gl_capitalize_word)4741 static KT_KEY_FN(gl_capitalize_word)
4742 {
4743 char *cptr; /* &gl->line[gl->buff_curpos] */
4744 int first; /* True for the first letter of the word */
4745 int i;
4746 /*
4747 * Keep a record of the current insert mode and the cursor position.
4748 */
4749 int insert = gl->insert;
4750 /*
4751 * If in vi command mode, preserve the current line for potential
4752 * use by vi-undo.
4753 */
4754 gl_save_for_undo(gl);
4755 /*
4756 * We want to overwrite the modified word.
4757 */
4758 gl->insert = 0;
4759 /*
4760 * Capitalize 'count' words.
4761 */
4762 for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) {
4763 int pos = gl->buff_curpos;
4764 /*
4765 * If we are not already within a word, skip to the start of the word.
4766 */
4767 for(cptr = gl->line + pos ; pos<gl->ntotal && !gl_is_word_char((int) *cptr);
4768 pos++, cptr++)
4769 ;
4770 /*
4771 * Move the cursor to the new position.
4772 */
4773 if(gl_place_cursor(gl, pos))
4774 return 1;
4775 /*
4776 * While searching for the end of the word, change lower case letters
4777 * to upper case.
4778 */
4779 for(first=1; gl->buff_curpos<gl->ntotal && gl_is_word_char((int) *cptr);
4780 gl->buff_curpos++, cptr++) {
4781 /*
4782 * Convert the character to upper case?
4783 */
4784 if(first) {
4785 if(islower((int)(unsigned char) *cptr))
4786 gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
4787 } else {
4788 if(isupper((int)(unsigned char) *cptr))
4789 gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
4790 };
4791 first = 0;
4792 /*
4793 * Write the possibly modified character back. Note that for non-modified
4794 * characters we want to do this as well, so as to advance the cursor.
4795 */
4796 if(gl_print_char(gl, *cptr, cptr[1]))
4797 return 1;
4798 };
4799 };
4800 /*
4801 * Restore the insertion mode.
4802 */
4803 gl->insert = insert;
4804 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4805 }
4806
4807 /*.......................................................................
4808 * This is an action function which redraws the current line.
4809 */
KT_KEY_FN(gl_redisplay)4810 static KT_KEY_FN(gl_redisplay)
4811 {
4812 /*
4813 * Keep a record of the current cursor position.
4814 */
4815 int buff_curpos = gl->buff_curpos;
4816 /*
4817 * Do nothing if there is no line to be redisplayed.
4818 */
4819 if(gl->endline)
4820 return 0;
4821 /*
4822 * Erase the current input line.
4823 */
4824 if(gl_erase_line(gl))
4825 return 1;
4826 /*
4827 * Display the current prompt.
4828 */
4829 if(gl_display_prompt(gl))
4830 return 1;
4831 /*
4832 * Render the part of the line that the user has typed in so far.
4833 */
4834 if(gl_print_string(gl, gl->line, '\0'))
4835 return 1;
4836 /*
4837 * Restore the cursor position.
4838 */
4839 if(gl_place_cursor(gl, buff_curpos))
4840 return 1;
4841 /*
4842 * Mark the redisplay operation as having been completed.
4843 */
4844 gl->redisplay = 0;
4845 /*
4846 * Flush the redisplayed line to the terminal.
4847 */
4848 return gl_flush_output(gl);
4849 }
4850
4851 /*.......................................................................
4852 * This is an action function which clears the display and redraws the
4853 * input line from the home position.
4854 */
KT_KEY_FN(gl_clear_screen)4855 static KT_KEY_FN(gl_clear_screen)
4856 {
4857 /*
4858 * Home the cursor and clear from there to the end of the display.
4859 */
4860 if(gl_print_control_sequence(gl, gl->nline, gl->home) ||
4861 gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
4862 return 1;
4863 /*
4864 * The input line is no longer displayed.
4865 */
4866 gl_line_erased(gl);
4867 /*
4868 * Arrange for the input line to be redisplayed.
4869 */
4870 gl_queue_redisplay(gl);
4871 return 0;
4872 }
4873
4874 /*.......................................................................
4875 * This is an action function which swaps the character under the cursor
4876 * with the character to the left of the cursor.
4877 */
KT_KEY_FN(gl_transpose_chars)4878 static KT_KEY_FN(gl_transpose_chars)
4879 {
4880 char from[3]; /* The original string of 2 characters */
4881 char swap[3]; /* The swapped string of two characters */
4882 /*
4883 * If we are at the beginning or end of the line, there aren't two
4884 * characters to swap.
4885 */
4886 if(gl->buff_curpos < 1 || gl->buff_curpos >= gl->ntotal)
4887 return 0;
4888 /*
4889 * If in vi command mode, preserve the current line for potential
4890 * use by vi-undo.
4891 */
4892 gl_save_for_undo(gl);
4893 /*
4894 * Get the original and swapped strings of the two characters.
4895 */
4896 from[0] = gl->line[gl->buff_curpos - 1];
4897 from[1] = gl->line[gl->buff_curpos];
4898 from[2] = '\0';
4899 swap[0] = gl->line[gl->buff_curpos];
4900 swap[1] = gl->line[gl->buff_curpos - 1];
4901 swap[2] = '\0';
4902 /*
4903 * Move the cursor to the start of the two characters.
4904 */
4905 if(gl_place_cursor(gl, gl->buff_curpos-1))
4906 return 1;
4907 /*
4908 * Swap the two characters in the buffer.
4909 */
4910 gl_buffer_char(gl, swap[0], gl->buff_curpos);
4911 gl_buffer_char(gl, swap[1], gl->buff_curpos+1);
4912 /*
4913 * If the sum of the displayed width of the two characters
4914 * in their current and final positions is the same, swapping can
4915 * be done by just overwriting with the two swapped characters.
4916 */
4917 if(gl_displayed_string_width(gl, from, -1, gl->term_curpos) ==
4918 gl_displayed_string_width(gl, swap, -1, gl->term_curpos)) {
4919 int insert = gl->insert;
4920 gl->insert = 0;
4921 if(gl_print_char(gl, swap[0], swap[1]) ||
4922 gl_print_char(gl, swap[1], gl->line[gl->buff_curpos+2]))
4923 return 1;
4924 gl->insert = insert;
4925 /*
4926 * If the swapped substring has a different displayed size, we need to
4927 * redraw everything after the first of the characters.
4928 */
4929 } else {
4930 if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0') ||
4931 gl_truncate_display(gl))
4932 return 1;
4933 };
4934 /*
4935 * Advance the cursor to the character after the swapped pair.
4936 */
4937 return gl_place_cursor(gl, gl->buff_curpos + 2);
4938 }
4939
4940 /*.......................................................................
4941 * This is an action function which sets a mark at the current cursor
4942 * location.
4943 */
KT_KEY_FN(gl_set_mark)4944 static KT_KEY_FN(gl_set_mark)
4945 {
4946 gl->buff_mark = gl->buff_curpos;
4947 return 0;
4948 }
4949
4950 /*.......................................................................
4951 * This is an action function which swaps the mark location for the
4952 * cursor location.
4953 */
KT_KEY_FN(gl_exchange_point_and_mark)4954 static KT_KEY_FN(gl_exchange_point_and_mark)
4955 {
4956 /*
4957 * Get the old mark position, and limit to the extent of the input
4958 * line.
4959 */
4960 int old_mark = gl->buff_mark <= gl->ntotal ? gl->buff_mark : gl->ntotal;
4961 /*
4962 * Make the current cursor position the new mark.
4963 */
4964 gl->buff_mark = gl->buff_curpos;
4965 /*
4966 * Move the cursor to the old mark position.
4967 */
4968 return gl_place_cursor(gl, old_mark);
4969 }
4970
4971 /*.......................................................................
4972 * This is an action function which deletes the characters between the
4973 * mark and the cursor, recording them in gl->cutbuf for later pasting.
4974 */
KT_KEY_FN(gl_kill_region)4975 static KT_KEY_FN(gl_kill_region)
4976 {
4977 /*
4978 * If in vi command mode, preserve the current line for potential
4979 * use by vi-undo.
4980 */
4981 gl_save_for_undo(gl);
4982 /*
4983 * Limit the mark to be within the line.
4984 */
4985 if(gl->buff_mark > gl->ntotal)
4986 gl->buff_mark = gl->ntotal;
4987 /*
4988 * If there are no characters between the cursor and the mark, simply clear
4989 * the cut buffer.
4990 */
4991 if(gl->buff_mark == gl->buff_curpos) {
4992 gl->cutbuf[0] = '\0';
4993 return 0;
4994 };
4995 /*
4996 * If the mark is before the cursor, swap the cursor and the mark.
4997 */
4998 if(gl->buff_mark < gl->buff_curpos && gl_exchange_point_and_mark(gl,1,NULL))
4999 return 1;
5000 /*
5001 * Delete the characters.
5002 */
5003 if(gl_delete_chars(gl, gl->buff_mark - gl->buff_curpos, 1))
5004 return 1;
5005 /*
5006 * Make the mark the same as the cursor position.
5007 */
5008 gl->buff_mark = gl->buff_curpos;
5009 return 0;
5010 }
5011
5012 /*.......................................................................
5013 * This is an action function which records the characters between the
5014 * mark and the cursor, in gl->cutbuf for later pasting.
5015 */
KT_KEY_FN(gl_copy_region_as_kill)5016 static KT_KEY_FN(gl_copy_region_as_kill)
5017 {
5018 int ca, cb; /* The indexes of the first and last characters in the region */
5019 int mark; /* The position of the mark */
5020 /*
5021 * Get the position of the mark, limiting it to lie within the line.
5022 */
5023 mark = gl->buff_mark > gl->ntotal ? gl->ntotal : gl->buff_mark;
5024 /*
5025 * If there are no characters between the cursor and the mark, clear
5026 * the cut buffer.
5027 */
5028 if(mark == gl->buff_curpos) {
5029 gl->cutbuf[0] = '\0';
5030 return 0;
5031 };
5032 /*
5033 * Get the line indexes of the first and last characters in the region.
5034 */
5035 if(mark < gl->buff_curpos) {
5036 ca = mark;
5037 cb = gl->buff_curpos - 1;
5038 } else {
5039 ca = gl->buff_curpos;
5040 cb = mark - 1;
5041 };
5042 /*
5043 * Copy the region to the cut buffer.
5044 */
5045 memcpy(gl->cutbuf, gl->line + ca, cb + 1 - ca);
5046 gl->cutbuf[cb + 1 - ca] = '\0';
5047 return 0;
5048 }
5049
5050 /*.......................................................................
5051 * This is an action function which inserts the contents of the cut
5052 * buffer at the current cursor location.
5053 */
KT_KEY_FN(gl_yank)5054 static KT_KEY_FN(gl_yank)
5055 {
5056 int i;
5057 /*
5058 * Set the mark at the current location.
5059 */
5060 gl->buff_mark = gl->buff_curpos;
5061 /*
5062 * Do nothing else if the cut buffer is empty.
5063 */
5064 if(gl->cutbuf[0] == '\0')
5065 return gl_ring_bell(gl, 1, NULL);
5066 /*
5067 * If in vi command mode, preserve the current line for potential
5068 * use by vi-undo.
5069 */
5070 gl_save_for_undo(gl);
5071 /*
5072 * Insert the string count times.
5073 */
5074 for(i=0; i<count; i++) {
5075 if(gl_add_string_to_line(gl, gl->cutbuf))
5076 return 1;
5077 };
5078 /*
5079 * gl_add_string_to_line() leaves the cursor after the last character that
5080 * was pasted, whereas vi leaves the cursor over the last character pasted.
5081 */
5082 if(gl->editor == GL_VI_MODE && gl_cursor_left(gl, 1, NULL))
5083 return 1;
5084 return 0;
5085 }
5086
5087 /*.......................................................................
5088 * This is an action function which inserts the contents of the cut
5089 * buffer one character beyond the current cursor location.
5090 */
KT_KEY_FN(gl_append_yank)5091 static KT_KEY_FN(gl_append_yank)
5092 {
5093 int was_command = gl->vi.command;
5094 int i;
5095 /*
5096 * If the cut buffer is empty, ring the terminal bell.
5097 */
5098 if(gl->cutbuf[0] == '\0')
5099 return gl_ring_bell(gl, 1, NULL);
5100 /*
5101 * Set the mark at the current location + 1.
5102 */
5103 gl->buff_mark = gl->buff_curpos + 1;
5104 /*
5105 * If in vi command mode, preserve the current line for potential
5106 * use by vi-undo.
5107 */
5108 gl_save_for_undo(gl);
5109 /*
5110 * Arrange to paste the text in insert mode after the current character.
5111 */
5112 if(gl_vi_append(gl, 0, NULL))
5113 return 1;
5114 /*
5115 * Insert the string count times.
5116 */
5117 for(i=0; i<count; i++) {
5118 if(gl_add_string_to_line(gl, gl->cutbuf))
5119 return 1;
5120 };
5121 /*
5122 * Switch back to command mode if necessary.
5123 */
5124 if(was_command)
5125 gl_vi_command_mode(gl);
5126 return 0;
5127 }
5128
5129 /*.......................................................................
5130 * Attempt to ask the terminal for its current size. On systems that
5131 * don't support the TIOCWINSZ ioctl() for querying the terminal size,
5132 * the current values of gl->ncolumn and gl->nrow are returned.
5133 *
5134 * Input:
5135 * gl GetLine * The resource object of gl_get_line().
5136 * Input/Output:
5137 * ncolumn int * The number of columns will be assigned to *ncolumn.
5138 * nline int * The number of lines will be assigned to *nline.
5139 */
gl_query_size(GetLine * gl,int * ncolumn,int * nline)5140 static void gl_query_size(GetLine *gl, int *ncolumn, int *nline)
5141 {
5142 #ifdef TIOCGWINSZ
5143 /*
5144 * Query the new terminal window size. Ignore invalid responses.
5145 */
5146 struct winsize size;
5147 if(ioctl(gl->output_fd, TIOCGWINSZ, &size) == 0 &&
5148 size.ws_row > 0 && size.ws_col > 0) {
5149 *ncolumn = size.ws_col;
5150 *nline = size.ws_row;
5151 return;
5152 };
5153 #endif
5154 /*
5155 * Return the existing values.
5156 */
5157 *ncolumn = gl->ncolumn;
5158 *nline = gl->nline;
5159 return;
5160 }
5161
5162 /*.......................................................................
5163 * Query the size of the terminal, and if it has changed, redraw the
5164 * current input line accordingly.
5165 *
5166 * Input:
5167 * gl GetLine * The resource object of gl_get_line().
5168 * Output:
5169 * return int 0 - OK.
5170 * 1 - Error.
5171 */
_gl_update_size(GetLine * gl)5172 static int _gl_update_size(GetLine *gl)
5173 {
5174 int ncolumn, nline; /* The new size of the terminal */
5175 /*
5176 * Query the new terminal window size.
5177 */
5178 gl_query_size(gl, &ncolumn, &nline);
5179 /*
5180 * Update gl and the displayed line to fit the new dimensions.
5181 */
5182 return gl_handle_tty_resize(gl, ncolumn, nline);
5183 }
5184
5185 /*.......................................................................
5186 * Redraw the current input line to account for a change in the terminal
5187 * size. Also install the new size in gl.
5188 *
5189 * Input:
5190 * gl GetLine * The resource object of gl_get_line().
5191 * ncolumn int The new number of columns.
5192 * nline int The new number of lines.
5193 * Output:
5194 * return int 0 - OK.
5195 * 1 - Error.
5196 */
gl_handle_tty_resize(GetLine * gl,int ncolumn,int nline)5197 static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline)
5198 {
5199 /*
5200 * If the input device isn't a terminal, just record the new size.
5201 */
5202 if(!gl->is_term) {
5203 gl->nline = nline;
5204 gl->ncolumn = ncolumn;
5205 /*
5206 * Has the size actually changed?
5207 */
5208 } else if(ncolumn != gl->ncolumn || nline != gl->nline) {
5209 /*
5210 * If we are currently editing a line, erase it.
5211 */
5212 if(gl_erase_line(gl))
5213 return 1;
5214 /*
5215 * Update the recorded window size.
5216 */
5217 gl->nline = nline;
5218 gl->ncolumn = ncolumn;
5219 /*
5220 * Arrange for the input line to be redrawn before the next character
5221 * is read from the terminal.
5222 */
5223 gl_queue_redisplay(gl);
5224 };
5225 return 0;
5226 }
5227
5228 /*.......................................................................
5229 * This is the action function that recalls the previous line in the
5230 * history buffer.
5231 */
KT_KEY_FN(gl_up_history)5232 static KT_KEY_FN(gl_up_history)
5233 {
5234 /*
5235 * In vi mode, switch to command mode, since the user is very
5236 * likely to want to move around newly recalled lines.
5237 */
5238 gl_vi_command_mode(gl);
5239 /*
5240 * Forget any previous recall session.
5241 */
5242 gl->preload_id = 0;
5243 /*
5244 * Record the key sequence number of this search action.
5245 */
5246 gl->last_search = gl->keyseq_count;
5247 /*
5248 * We don't want a search prefix for this function.
5249 */
5250 if(_glh_search_prefix(gl->glh, gl->line, 0)) {
5251 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5252 return 1;
5253 };
5254 /*
5255 * Recall the count'th next older line in the history list. If the first one
5256 * fails we can return since nothing has changed, otherwise we must continue
5257 * and update the line state.
5258 */
5259 if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5260 return 0;
5261 while(--count && _glh_find_backwards(gl->glh, gl->line, gl->linelen+1))
5262 ;
5263 /*
5264 * Accomodate the new contents of gl->line[].
5265 */
5266 gl_update_buffer(gl);
5267 /*
5268 * Arrange to have the cursor placed at the end of the new line.
5269 */
5270 gl->buff_curpos = gl->ntotal;
5271 /*
5272 * Erase and display the new line.
5273 */
5274 gl_queue_redisplay(gl);
5275 return 0;
5276 }
5277
5278 /*.......................................................................
5279 * This is the action function that recalls the next line in the
5280 * history buffer.
5281 */
KT_KEY_FN(gl_down_history)5282 static KT_KEY_FN(gl_down_history)
5283 {
5284 /*
5285 * In vi mode, switch to command mode, since the user is very
5286 * likely to want to move around newly recalled lines.
5287 */
5288 gl_vi_command_mode(gl);
5289 /*
5290 * Record the key sequence number of this search action.
5291 */
5292 gl->last_search = gl->keyseq_count;
5293 /*
5294 * If no search is currently in progress continue a previous recall
5295 * session from a previous entered line if possible.
5296 */
5297 if(_glh_line_id(gl->glh, 0) == 0 && gl->preload_id) {
5298 _glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1);
5299 gl->preload_id = 0;
5300 } else {
5301 /*
5302 * We don't want a search prefix for this function.
5303 */
5304 if(_glh_search_prefix(gl->glh, gl->line, 0)) {
5305 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5306 return 1;
5307 };
5308 /*
5309 * Recall the count'th next newer line in the history list. If the first one
5310 * fails we can return since nothing has changed otherwise we must continue
5311 * and update the line state.
5312 */
5313 if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5314 return 0;
5315 while(--count && _glh_find_forwards(gl->glh, gl->line, gl->linelen+1))
5316 ;
5317 };
5318 /*
5319 * Accomodate the new contents of gl->line[].
5320 */
5321 gl_update_buffer(gl);
5322 /*
5323 * Arrange to have the cursor placed at the end of the new line.
5324 */
5325 gl->buff_curpos = gl->ntotal;
5326 /*
5327 * Erase and display the new line.
5328 */
5329 gl_queue_redisplay(gl);
5330 return 0;
5331 }
5332
5333 /*.......................................................................
5334 * This is the action function that recalls the previous line in the
5335 * history buffer whos prefix matches the characters that currently
5336 * precede the cursor. By setting count=-1, this can be used internally
5337 * to force searching for the prefix used in the last search.
5338 */
KT_KEY_FN(gl_history_search_backward)5339 static KT_KEY_FN(gl_history_search_backward)
5340 {
5341 /*
5342 * In vi mode, switch to command mode, since the user is very
5343 * likely to want to move around newly recalled lines.
5344 */
5345 gl_vi_command_mode(gl);
5346 /*
5347 * Forget any previous recall session.
5348 */
5349 gl->preload_id = 0;
5350 /*
5351 * Record the key sequence number of this search action.
5352 */
5353 gl->last_search = gl->keyseq_count;
5354 /*
5355 * If a prefix search isn't already in progress, replace the search
5356 * prefix to the string that precedes the cursor. In vi command mode
5357 * include the character that is under the cursor in the string. If
5358 * count<0 keep the previous search prefix regardless, so as to force
5359 * a repeat search even if the last command wasn't a history command.
5360 */
5361 if(count >= 0 && !_glh_search_active(gl->glh) &&
5362 _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
5363 (gl->editor==GL_VI_MODE && gl->ntotal>0))) {
5364 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5365 return 1;
5366 };
5367 /*
5368 * Search backwards for a match to the part of the line which precedes the
5369 * cursor.
5370 */
5371 if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5372 return 0;
5373 /*
5374 * Accomodate the new contents of gl->line[].
5375 */
5376 gl_update_buffer(gl);
5377 /*
5378 * Arrange to have the cursor placed at the end of the new line.
5379 */
5380 gl->buff_curpos = gl->ntotal;
5381 /*
5382 * Erase and display the new line.
5383 */
5384 gl_queue_redisplay(gl);
5385 return 0;
5386 }
5387
5388 /*.......................................................................
5389 * This is the action function that recalls the previous line in the
5390 * history buffer who's prefix matches that specified in an earlier call
5391 * to gl_history_search_backward() or gl_history_search_forward().
5392 */
KT_KEY_FN(gl_history_re_search_backward)5393 static KT_KEY_FN(gl_history_re_search_backward)
5394 {
5395 return gl_history_search_backward(gl, -1, NULL);
5396 }
5397
5398 /*.......................................................................
5399 * This is the action function that recalls the next line in the
5400 * history buffer who's prefix matches that specified in the earlier call
5401 * to gl_history_search_backward) which started the history search.
5402 * By setting count=-1, this can be used internally to force searching
5403 * for the prefix used in the last search.
5404 */
KT_KEY_FN(gl_history_search_forward)5405 static KT_KEY_FN(gl_history_search_forward)
5406 {
5407 /*
5408 * In vi mode, switch to command mode, since the user is very
5409 * likely to want to move around newly recalled lines.
5410 */
5411 gl_vi_command_mode(gl);
5412 /*
5413 * Record the key sequence number of this search action.
5414 */
5415 gl->last_search = gl->keyseq_count;
5416 /*
5417 * If a prefix search isn't already in progress, replace the search
5418 * prefix to the string that precedes the cursor. In vi command mode
5419 * include the character that is under the cursor in the string. If
5420 * count<0 keep the previous search prefix regardless, so as to force
5421 * a repeat search even if the last command wasn't a history command.
5422 */
5423 if(count >= 0 && !_glh_search_active(gl->glh) &&
5424 _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
5425 (gl->editor==GL_VI_MODE && gl->ntotal>0))) {
5426 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5427 return 1;
5428 };
5429 /*
5430 * Search forwards for the next matching line.
5431 */
5432 if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5433 return 0;
5434 /*
5435 * Accomodate the new contents of gl->line[].
5436 */
5437 gl_update_buffer(gl);
5438 /*
5439 * Arrange for the cursor to be placed at the end of the new line.
5440 */
5441 gl->buff_curpos = gl->ntotal;
5442 /*
5443 * Erase and display the new line.
5444 */
5445 gl_queue_redisplay(gl);
5446 return 0;
5447 }
5448
5449 /*.......................................................................
5450 * This is the action function that recalls the next line in the
5451 * history buffer who's prefix matches that specified in an earlier call
5452 * to gl_history_search_backward() or gl_history_search_forward().
5453 */
KT_KEY_FN(gl_history_re_search_forward)5454 static KT_KEY_FN(gl_history_re_search_forward)
5455 {
5456 return gl_history_search_forward(gl, -1, NULL);
5457 }
5458
5459 #ifdef HIDE_FILE_SYSTEM
5460 /*.......................................................................
5461 * The following function is used as the default completion handler when
5462 * the filesystem is to be hidden. It simply reports no completions.
5463 */
CPL_MATCH_FN(gl_no_completions)5464 static CPL_MATCH_FN(gl_no_completions)
5465 {
5466 return 0;
5467 }
5468 #endif
5469
5470 /*.......................................................................
5471 * This is the tab completion function that completes the filename that
5472 * precedes the cursor position. Its callback data argument must be a
5473 * pointer to a GlCplCallback containing the completion callback function
5474 * and its callback data, or NULL to use the builtin filename completer.
5475 */
KT_KEY_FN(gl_complete_word)5476 static KT_KEY_FN(gl_complete_word)
5477 {
5478 CplMatches *matches; /* The possible completions */
5479 int suffix_len; /* The length of the completion extension */
5480 int cont_len; /* The length of any continuation suffix */
5481 int nextra; /* The number of characters being added to the */
5482 /* total length of the line. */
5483 int buff_pos; /* The buffer index at which the completion is */
5484 /* to be inserted. */
5485 int waserr = 0; /* True after errors */
5486 /*
5487 * Get the container of the completion callback and its callback data.
5488 */
5489 GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
5490 /*
5491 * In vi command mode, switch to append mode so that the character under
5492 * the cursor is included in the completion (otherwise people can't
5493 * complete at the end of the line).
5494 */
5495 if(gl->vi.command && gl_vi_append(gl, 0, NULL))
5496 return 1;
5497 /*
5498 * Get the cursor position at which the completion is to be inserted.
5499 */
5500 buff_pos = gl->buff_curpos;
5501 /*
5502 * Perform the completion.
5503 */
5504 matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos, cb->data,
5505 cb->fn);
5506 /*
5507 * No matching completions?
5508 */
5509 if(!matches) {
5510 waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
5511 /*
5512 * Are there any completions?
5513 */
5514 } else if(matches->nmatch >= 1) {
5515 /*
5516 * If there any ambiguous matches, report them, starting on a new line.
5517 */
5518 if(matches->nmatch > 1 && gl->echo) {
5519 if(_gl_normal_io(gl) ||
5520 _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
5521 waserr = 1;
5522 };
5523 /*
5524 * Get the length of the suffix and any continuation suffix to add to it.
5525 */
5526 suffix_len = strlen(matches->suffix);
5527 cont_len = strlen(matches->cont_suffix);
5528 /*
5529 * If there is an unambiguous match, and the continuation suffix ends in
5530 * a newline, strip that newline and arrange to have getline return
5531 * after this action function returns.
5532 */
5533 if(matches->nmatch==1 && cont_len > 0 &&
5534 matches->cont_suffix[cont_len - 1] == '\n') {
5535 cont_len--;
5536 if(gl_newline(gl, 1, NULL))
5537 waserr = 1;
5538 };
5539 /*
5540 * Work out the number of characters that are to be added.
5541 */
5542 nextra = suffix_len + cont_len;
5543 /*
5544 * Is there anything to be added?
5545 */
5546 if(!waserr && nextra) {
5547 /*
5548 * Will there be space for the expansion in the line buffer?
5549 */
5550 if(gl->ntotal + nextra < gl->linelen) {
5551 /*
5552 * Make room to insert the filename extension.
5553 */
5554 gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
5555 /*
5556 * Insert the filename extension.
5557 */
5558 gl_buffer_string(gl, matches->suffix, suffix_len, gl->buff_curpos);
5559 /*
5560 * Add the terminating characters.
5561 */
5562 gl_buffer_string(gl, matches->cont_suffix, cont_len,
5563 gl->buff_curpos + suffix_len);
5564 /*
5565 * Place the cursor position at the end of the completion.
5566 */
5567 gl->buff_curpos += nextra;
5568 /*
5569 * If we don't have to redisplay the whole line, redisplay the part
5570 * of the line which follows the original cursor position, and place
5571 * the cursor at the end of the completion.
5572 */
5573 if(gl->displayed) {
5574 if(gl_truncate_display(gl) ||
5575 gl_print_string(gl, gl->line + buff_pos, '\0') ||
5576 gl_place_cursor(gl, gl->buff_curpos))
5577 waserr = 1;
5578 };
5579 } else {
5580 (void) gl_print_info(gl,
5581 "Insufficient room in line for file completion.",
5582 GL_END_INFO);
5583 waserr = 1;
5584 };
5585 };
5586 };
5587 /*
5588 * If any output had to be written to the terminal, then editing will
5589 * have been suspended, make sure that we are back in raw line editing
5590 * mode before returning.
5591 */
5592 if(_gl_raw_io(gl, 1))
5593 waserr = 1;
5594 return 0;
5595 }
5596
5597 #ifndef HIDE_FILE_SYSTEM
5598 /*.......................................................................
5599 * This is the function that expands the filename that precedes the
5600 * cursor position. It expands ~user/ expressions, $envvar expressions,
5601 * and wildcards.
5602 */
KT_KEY_FN(gl_expand_filename)5603 static KT_KEY_FN(gl_expand_filename)
5604 {
5605 char *start_path; /* The pointer to the start of the pathname in */
5606 /* gl->line[]. */
5607 FileExpansion *result; /* The results of the filename expansion */
5608 int pathlen; /* The length of the pathname being expanded */
5609 int length; /* The number of characters needed to display the */
5610 /* expanded files. */
5611 int nextra; /* The number of characters to be added */
5612 int i,j;
5613 /*
5614 * In vi command mode, switch to append mode so that the character under
5615 * the cursor is included in the completion (otherwise people can't
5616 * complete at the end of the line).
5617 */
5618 if(gl->vi.command && gl_vi_append(gl, 0, NULL))
5619 return 1;
5620 /*
5621 * Locate the start of the filename that precedes the cursor position.
5622 */
5623 start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
5624 if(!start_path)
5625 return 1;
5626 /*
5627 * Get the length of the string that is to be expanded.
5628 */
5629 pathlen = gl->buff_curpos - (start_path - gl->line);
5630 /*
5631 * Attempt to expand it.
5632 */
5633 result = ef_expand_file(gl->ef, start_path, pathlen);
5634 /*
5635 * If there was an error, report the error on a new line.
5636 */
5637 if(!result)
5638 return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
5639 /*
5640 * If no files matched, report this as well.
5641 */
5642 if(result->nfile == 0 || !result->exists)
5643 return gl_print_info(gl, "No files match.", GL_END_INFO);
5644 /*
5645 * If in vi command mode, preserve the current line for potential use by
5646 * vi-undo.
5647 */
5648 gl_save_for_undo(gl);
5649 /*
5650 * Work out how much space we will need to display all of the matching
5651 * filenames, taking account of the space that we need to place between
5652 * them, and the number of additional '\' characters needed to escape
5653 * spaces, tabs and backslash characters in the individual filenames.
5654 */
5655 length = 0;
5656 for(i=0; i<result->nfile; i++) {
5657 char *file = result->files[i];
5658 while(*file) {
5659 int c = *file++;
5660 switch(c) {
5661 case ' ': case '\t': case '\\': case '*': case '?': case '[':
5662 length++; /* Count extra backslash characters */
5663 };
5664 length++; /* Count the character itself */
5665 };
5666 length++; /* Count the space that follows each filename */
5667 };
5668 /*
5669 * Work out the number of characters that are to be added.
5670 */
5671 nextra = length - pathlen;
5672 /*
5673 * Will there be space for the expansion in the line buffer?
5674 */
5675 if(gl->ntotal + nextra >= gl->linelen) {
5676 return gl_print_info(gl, "Insufficient room in line for file expansion.",
5677 GL_END_INFO);
5678 } else {
5679 /*
5680 * Do we need to move the part of the line that followed the unexpanded
5681 * filename?
5682 */
5683 if(nextra > 0) {
5684 gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
5685 } else if(nextra < 0) {
5686 gl->buff_curpos += nextra;
5687 gl_remove_from_buffer(gl, gl->buff_curpos, -nextra);
5688 };
5689 /*
5690 * Insert the filenames, separated by spaces, and with internal spaces,
5691 * tabs and backslashes escaped with backslashes.
5692 */
5693 for(i=0,j=start_path - gl->line; i<result->nfile; i++) {
5694 char *file = result->files[i];
5695 while(*file) {
5696 int c = *file++;
5697 switch(c) {
5698 case ' ': case '\t': case '\\': case '*': case '?': case '[':
5699 gl_buffer_char(gl, '\\', j++);
5700 };
5701 gl_buffer_char(gl, c, j++);
5702 };
5703 gl_buffer_char(gl, ' ', j++);
5704 };
5705 };
5706 /*
5707 * Redisplay the part of the line which follows the start of
5708 * the original filename.
5709 */
5710 if(gl_place_cursor(gl, start_path - gl->line) ||
5711 gl_truncate_display(gl) ||
5712 gl_print_string(gl, start_path, start_path[length]))
5713 return 1;
5714 /*
5715 * Move the cursor to the end of the expansion.
5716 */
5717 return gl_place_cursor(gl, (start_path - gl->line) + length);
5718 }
5719 #endif
5720
5721 #ifndef HIDE_FILE_SYSTEM
5722 /*.......................................................................
5723 * This is the action function that lists glob expansions of the
5724 * filename that precedes the cursor position. It expands ~user/
5725 * expressions, $envvar expressions, and wildcards.
5726 */
KT_KEY_FN(gl_list_glob)5727 static KT_KEY_FN(gl_list_glob)
5728 {
5729 char *start_path; /* The pointer to the start of the pathname in */
5730 /* gl->line[]. */
5731 FileExpansion *result; /* The results of the filename expansion */
5732 int pathlen; /* The length of the pathname being expanded */
5733 /*
5734 * Locate the start of the filename that precedes the cursor position.
5735 */
5736 start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
5737 if(!start_path)
5738 return 1;
5739 /*
5740 * Get the length of the string that is to be expanded.
5741 */
5742 pathlen = gl->buff_curpos - (start_path - gl->line);
5743 /*
5744 * Attempt to expand it.
5745 */
5746 result = ef_expand_file(gl->ef, start_path, pathlen);
5747 /*
5748 * If there was an error, report it.
5749 */
5750 if(!result) {
5751 return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
5752 /*
5753 * If no files matched, report this as well.
5754 */
5755 } else if(result->nfile == 0 || !result->exists) {
5756 return gl_print_info(gl, "No files match.", GL_END_INFO);
5757 /*
5758 * List the matching expansions.
5759 */
5760 } else if(gl->echo) {
5761 if(gl_start_newline(gl, 1) ||
5762 _ef_output_expansions(result, gl_write_fn, gl, gl->ncolumn))
5763 return 1;
5764 gl_queue_redisplay(gl);
5765 };
5766 return 0;
5767 }
5768 #endif
5769
5770 /*.......................................................................
5771 * Return non-zero if a character should be considered a part of a word.
5772 *
5773 * Input:
5774 * c int The character to be tested.
5775 * Output:
5776 * return int True if the character should be considered part of a word.
5777 */
gl_is_word_char(int c)5778 static int gl_is_word_char(int c)
5779 {
5780 return isalnum((int)(unsigned char)c) || strchr(GL_WORD_CHARS, c) != NULL;
5781 }
5782
5783 /*.......................................................................
5784 * Override the builtin file-completion callback that is bound to the
5785 * "complete_word" action function.
5786 *
5787 * Input:
5788 * gl GetLine * The resource object of the command-line input
5789 * module.
5790 * data void * This is passed to match_fn() whenever it is
5791 * called. It could, for example, point to a
5792 * symbol table where match_fn() could look
5793 * for possible completions.
5794 * match_fn CplMatchFn * The function that will identify the prefix
5795 * to be completed from the input line, and
5796 * report matching symbols.
5797 * Output:
5798 * return int 0 - OK.
5799 * 1 - Error.
5800 */
gl_customize_completion(GetLine * gl,void * data,CplMatchFn * match_fn)5801 int gl_customize_completion(GetLine *gl, void *data, CplMatchFn *match_fn)
5802 {
5803 sigset_t oldset; /* The signals that were blocked on entry to this function */
5804 /*
5805 * Check the arguments.
5806 */
5807 if(!gl || !match_fn) {
5808 if(gl)
5809 _err_record_msg(gl->err, "NULL argument", END_ERR_MSG);
5810 errno = EINVAL;
5811 return 1;
5812 };
5813 /*
5814 * Temporarily block all signals.
5815 */
5816 gl_mask_signals(gl, &oldset);
5817 /*
5818 * Record the new completion function and its callback data.
5819 */
5820 gl->cplfn.fn = match_fn;
5821 gl->cplfn.data = data;
5822 /*
5823 * Restore the process signal mask before returning.
5824 */
5825 gl_unmask_signals(gl, &oldset);
5826 return 0;
5827 }
5828
5829 /*.......................................................................
5830 * Change the terminal (or stream) that getline interacts with.
5831 *
5832 * Input:
5833 * gl GetLine * The resource object of the command-line input
5834 * module.
5835 * input_fp FILE * The stdio stream to read from.
5836 * output_fp FILE * The stdio stream to write to.
5837 * term char * The terminal type. This can be NULL if
5838 * either or both of input_fp and output_fp don't
5839 * refer to a terminal. Otherwise it should refer
5840 * to an entry in the terminal information database.
5841 * Output:
5842 * return int 0 - OK.
5843 * 1 - Error.
5844 */
gl_change_terminal(GetLine * gl,FILE * input_fp,FILE * output_fp,const char * term)5845 int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
5846 const char *term)
5847 {
5848 sigset_t oldset; /* The signals that were blocked on entry to this function */
5849 int status; /* The return status of _gl_change_terminal() */
5850 /*
5851 * Check the arguments.
5852 */
5853 if(!gl) {
5854 errno = EINVAL;
5855 return 1;
5856 };
5857 /*
5858 * Block all signals.
5859 */
5860 if(gl_mask_signals(gl, &oldset))
5861 return 1;
5862 /*
5863 * Execute the private body of the function while signals are blocked.
5864 */
5865 status = _gl_change_terminal(gl, input_fp, output_fp, term);
5866 /*
5867 * Restore the process signal mask.
5868 */
5869 gl_unmask_signals(gl, &oldset);
5870 return status;
5871 }
5872
5873 /*.......................................................................
5874 * This is the private body of the gl_change_terminal() function. It
5875 * assumes that the caller has checked its arguments and blocked the
5876 * delivery of signals.
5877 */
_gl_change_terminal(GetLine * gl,FILE * input_fp,FILE * output_fp,const char * term)5878 static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
5879 const char *term)
5880 {
5881 int is_term = 0; /* True if both input_fd and output_fd are associated */
5882 /* with a terminal. */
5883 /*
5884 * Require that input_fp and output_fp both be valid.
5885 */
5886 if(!input_fp || !output_fp) {
5887 gl_print_info(gl, "Can't change terminal. Bad input/output stream(s).",
5888 GL_END_INFO);
5889 return 1;
5890 };
5891 /*
5892 * Are we displacing an existing terminal (as opposed to setting the
5893 * initial terminal)?
5894 */
5895 if(gl->input_fd >= 0) {
5896 /*
5897 * Make sure to leave the previous terminal in a usable state.
5898 */
5899 if(_gl_normal_io(gl))
5900 return 1;
5901 /*
5902 * Remove the displaced terminal from the list of fds to watch.
5903 */
5904 #ifdef HAVE_SELECT
5905 FD_CLR(gl->input_fd, &gl->rfds);
5906 #endif
5907 };
5908 /*
5909 * Record the file descriptors and streams.
5910 */
5911 gl->input_fp = input_fp;
5912 gl->input_fd = fileno(input_fp);
5913 gl->output_fp = output_fp;
5914 gl->output_fd = fileno(output_fp);
5915 /*
5916 * If needed, expand the record of the maximum file-descriptor that might
5917 * need to be monitored with select().
5918 */
5919 #ifdef HAVE_SELECT
5920 if(gl->input_fd > gl->max_fd)
5921 gl->max_fd = gl->input_fd;
5922 #endif
5923 /*
5924 * Disable terminal interaction until we have enough info to interact
5925 * with the terminal.
5926 */
5927 gl->is_term = 0;
5928 /*
5929 * For terminal editing, we need both output_fd and input_fd to refer to
5930 * a terminal. While we can't verify that they both point to the same
5931 * terminal, we can verify that they point to terminals. If the user
5932 * sets the TERM environment variable to "dumb", treat a terminal as
5933 * a non-interactive I/O stream.
5934 */
5935 is_term = (isatty(gl->input_fd) && isatty(gl->output_fd)) &&
5936 !(term && strcmp(term, "dumb")==0);
5937 /*
5938 * If we are interacting with a terminal and no terminal type has been
5939 * specified, treat it as a generic ANSI terminal.
5940 */
5941 if(is_term && !term)
5942 term = "ansi";
5943 /*
5944 * Make a copy of the terminal type string.
5945 */
5946 if(term != gl->term) {
5947 /*
5948 * Delete any old terminal type string.
5949 */
5950 if(gl->term) {
5951 free(gl->term);
5952 gl->term = NULL;
5953 };
5954 /*
5955 * Make a copy of the new terminal-type string, if any.
5956 */
5957 if(term) {
5958 gl->term = (char *) malloc(strlen(term)+1);
5959 if(gl->term)
5960 strcpy(gl->term, term);
5961 };
5962 };
5963 /*
5964 * Clear any terminal-specific key bindings that were taken from the
5965 * settings of the last terminal.
5966 */
5967 _kt_clear_bindings(gl->bindings, KTB_TERM);
5968 /*
5969 * If we have a terminal install new bindings for it.
5970 */
5971 if(is_term) {
5972 /*
5973 * Get the current settings of the terminal.
5974 */
5975 if(tcgetattr(gl->input_fd, &gl->oldattr)) {
5976 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
5977 return 1;
5978 };
5979 /*
5980 * If we don't set this now, gl_control_strings() won't know
5981 * that it is talking to a terminal.
5982 */
5983 gl->is_term = 1;
5984 /*
5985 * Lookup the terminal control string and size information.
5986 */
5987 if(gl_control_strings(gl, term)) {
5988 gl->is_term = 0;
5989 return 1;
5990 };
5991 /*
5992 * Bind terminal-specific keys.
5993 */
5994 if(gl_bind_terminal_keys(gl))
5995 return 1;
5996 };
5997 /*
5998 * Assume that the caller has given us a terminal in a sane state.
5999 */
6000 gl->io_mode = GL_NORMAL_MODE;
6001 /*
6002 * Switch into the currently configured I/O mode.
6003 */
6004 if(_gl_io_mode(gl, gl->io_mode))
6005 return 1;
6006 return 0;
6007 }
6008
6009 /*.......................................................................
6010 * Set up terminal-specific key bindings.
6011 *
6012 * Input:
6013 * gl GetLine * The resource object of the command-line input
6014 * module.
6015 * Output:
6016 * return int 0 - OK.
6017 * 1 - Error.
6018 */
gl_bind_terminal_keys(GetLine * gl)6019 static int gl_bind_terminal_keys(GetLine *gl)
6020 {
6021 /*
6022 * Install key-bindings for the special terminal characters.
6023 */
6024 if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VINTR],
6025 "user-interrupt") ||
6026 gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VQUIT], "abort") ||
6027 gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VSUSP], "suspend"))
6028 return 1;
6029 /*
6030 * In vi-mode, arrange for the above characters to be seen in command
6031 * mode.
6032 */
6033 if(gl->editor == GL_VI_MODE) {
6034 if(gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VINTR]),
6035 "user-interrupt") ||
6036 gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VQUIT]),
6037 "abort") ||
6038 gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VSUSP]),
6039 "suspend"))
6040 return 1;
6041 };
6042 /*
6043 * Non-universal special keys.
6044 */
6045 #ifdef VLNEXT
6046 if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VLNEXT],
6047 "literal-next"))
6048 return 1;
6049 #else
6050 if(_kt_set_keybinding(gl->bindings, KTB_TERM, "^V", "literal-next")) {
6051 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
6052 return 1;
6053 };
6054 #endif
6055 /*
6056 * Bind action functions to the terminal-specific arrow keys
6057 * looked up by gl_control_strings().
6058 */
6059 if(_gl_bind_arrow_keys(gl))
6060 return 1;
6061 return 0;
6062 }
6063
6064 /*.......................................................................
6065 * This function is normally bound to control-D. When it is invoked within
6066 * a line it deletes the character which follows the cursor. When invoked
6067 * at the end of the line it lists possible file completions, and when
6068 * invoked on an empty line it causes gl_get_line() to return EOF. This
6069 * function emulates the one that is normally bound to control-D by tcsh.
6070 */
KT_KEY_FN(gl_del_char_or_list_or_eof)6071 static KT_KEY_FN(gl_del_char_or_list_or_eof)
6072 {
6073 /*
6074 * If we have an empty line arrange to return EOF.
6075 */
6076 if(gl->ntotal < 1) {
6077 gl_record_status(gl, GLR_EOF, 0);
6078 return 1;
6079 /*
6080 * If we are at the end of the line list possible completions.
6081 */
6082 } else if(gl->buff_curpos >= gl->ntotal) {
6083 return gl_list_completions(gl, 1, NULL);
6084 /*
6085 * Within the line delete the character that follows the cursor.
6086 */
6087 } else {
6088 /*
6089 * If in vi command mode, first preserve the current line for potential use
6090 * by vi-undo.
6091 */
6092 gl_save_for_undo(gl);
6093 /*
6094 * Delete 'count' characters.
6095 */
6096 return gl_forward_delete_char(gl, count, NULL);
6097 };
6098 }
6099
6100 /*.......................................................................
6101 * This function is normally bound to control-D in vi mode. When it is
6102 * invoked within a line it lists possible file completions, and when
6103 * invoked on an empty line it causes gl_get_line() to return EOF. This
6104 * function emulates the one that is normally bound to control-D by tcsh.
6105 */
KT_KEY_FN(gl_list_or_eof)6106 static KT_KEY_FN(gl_list_or_eof)
6107 {
6108 /*
6109 * If we have an empty line arrange to return EOF.
6110 */
6111 if(gl->ntotal < 1) {
6112 gl_record_status(gl, GLR_EOF, 0);
6113 return 1;
6114 /*
6115 * Otherwise list possible completions.
6116 */
6117 } else {
6118 return gl_list_completions(gl, 1, NULL);
6119 };
6120 }
6121
6122 /*.......................................................................
6123 * List possible completions of the word that precedes the cursor. The
6124 * callback data argument must either be NULL to select the default
6125 * file completion callback, or be a GlCplCallback object containing the
6126 * completion callback function to call.
6127 */
KT_KEY_FN(gl_list_completions)6128 static KT_KEY_FN(gl_list_completions)
6129 {
6130 int waserr = 0; /* True after errors */
6131 /*
6132 * Get the container of the completion callback and its callback data.
6133 */
6134 GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
6135 /*
6136 * Get the list of possible completions.
6137 */
6138 CplMatches *matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos,
6139 cb->data, cb->fn);
6140 /*
6141 * No matching completions?
6142 */
6143 if(!matches) {
6144 waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
6145 /*
6146 * List the matches.
6147 */
6148 } else if(matches->nmatch > 0 && gl->echo) {
6149 if(_gl_normal_io(gl) ||
6150 _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
6151 waserr = 1;
6152 };
6153 /*
6154 * If any output had to be written to the terminal, then editing will
6155 * have been suspended, make sure that we are back in raw line editing
6156 * mode before returning.
6157 */
6158 if(_gl_raw_io(gl, 1))
6159 waserr = 1;
6160 return waserr;
6161 }
6162
6163 /*.......................................................................
6164 * Where the user has used the symbolic arrow-key names to specify
6165 * arrow key bindings, bind the specified action functions to the default
6166 * and terminal specific arrow key sequences.
6167 *
6168 * Input:
6169 * gl GetLine * The getline resource object.
6170 * Output:
6171 * return int 0 - OK.
6172 * 1 - Error.
6173 */
_gl_bind_arrow_keys(GetLine * gl)6174 static int _gl_bind_arrow_keys(GetLine *gl)
6175 {
6176 /*
6177 * Process each of the arrow keys.
6178 */
6179 if(_gl_rebind_arrow_key(gl, "up", gl->u_arrow, "^[[A", "^[OA") ||
6180 _gl_rebind_arrow_key(gl, "down", gl->d_arrow, "^[[B", "^[OB") ||
6181 _gl_rebind_arrow_key(gl, "left", gl->l_arrow, "^[[D", "^[OD") ||
6182 _gl_rebind_arrow_key(gl, "right", gl->r_arrow, "^[[C", "^[OC"))
6183 return 1;
6184 return 0;
6185 }
6186
6187 /*.......................................................................
6188 * Lookup the action function of a symbolic arrow-key binding, and bind
6189 * it to the terminal-specific and default arrow-key sequences. Note that
6190 * we don't trust the terminal-specified key sequences to be correct.
6191 * The main reason for this is that on some machines the xterm terminfo
6192 * entry is for hardware X-terminals, rather than xterm terminal emulators
6193 * and the two terminal types emit different character sequences when the
6194 * their cursor keys are pressed. As a result we also supply a couple
6195 * of default key sequences.
6196 *
6197 * Input:
6198 * gl GetLine * The resource object of gl_get_line().
6199 * name char * The symbolic name of the arrow key.
6200 * term_seq char * The terminal-specific arrow-key sequence.
6201 * def_seq1 char * The first default arrow-key sequence.
6202 * def_seq2 char * The second arrow-key sequence.
6203 * Output:
6204 * return int 0 - OK.
6205 * 1 - Error.
6206 */
_gl_rebind_arrow_key(GetLine * gl,const char * name,const char * term_seq,const char * def_seq1,const char * def_seq2)6207 static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
6208 const char *term_seq, const char *def_seq1,
6209 const char *def_seq2)
6210 {
6211 KeySym *keysym; /* The binding-table entry matching the arrow-key name */
6212 int nsym; /* The number of ambiguous matches */
6213 /*
6214 * Lookup the key binding for the symbolic name of the arrow key. This
6215 * will either be the default action, or a user provided one.
6216 */
6217 if(_kt_lookup_keybinding(gl->bindings, name, strlen(name), &keysym, &nsym)
6218 == KT_EXACT_MATCH) {
6219 /*
6220 * Get the action function.
6221 */
6222 KtAction *action = keysym->actions + keysym->binder;
6223 KtKeyFn *fn = action->fn;
6224 void *data = action->data;
6225 /*
6226 * Bind this to each of the specified key sequences.
6227 */
6228 if((term_seq &&
6229 _kt_set_keyfn(gl->bindings, KTB_TERM, term_seq, fn, data)) ||
6230 (def_seq1 &&
6231 _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq1, fn, data)) ||
6232 (def_seq2 &&
6233 _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq2, fn, data))) {
6234 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
6235 return 1;
6236 };
6237 };
6238 return 0;
6239 }
6240
6241 /*.......................................................................
6242 * Read getline configuration information from a given file.
6243 *
6244 * Input:
6245 * gl GetLine * The getline resource object.
6246 * filename const char * The name of the file to read configuration
6247 * information from. The contents of this file
6248 * are as described in the gl_get_line(3) man
6249 * page for the default ~/.teclarc configuration
6250 * file.
6251 * who KtBinder Who bindings are to be installed for.
6252 * Output:
6253 * return int 0 - OK.
6254 * 1 - Irrecoverable error.
6255 */
_gl_read_config_file(GetLine * gl,const char * filename,KtBinder who)6256 static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who)
6257 {
6258 /*
6259 * If filesystem access is to be excluded, configuration files can't
6260 * be read.
6261 */
6262 #ifdef WITHOUT_FILE_SYSTEM
6263 _err_record_msg(gl->err,
6264 "Can't read configuration files without filesystem access",
6265 END_ERR_MSG);
6266 errno = EINVAL;
6267 return 1;
6268 #else
6269 FileExpansion *expansion; /* The expansion of the filename */
6270 FILE *fp; /* The opened file */
6271 int waserr = 0; /* True if an error occurred while reading */
6272 int lineno = 1; /* The line number being processed */
6273 /*
6274 * Check the arguments.
6275 */
6276 if(!gl || !filename) {
6277 if(gl)
6278 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
6279 errno = EINVAL;
6280 return 1;
6281 };
6282 /*
6283 * Expand the filename.
6284 */
6285 expansion = ef_expand_file(gl->ef, filename, -1);
6286 if(!expansion) {
6287 gl_print_info(gl, "Unable to expand ", filename, " (",
6288 ef_last_error(gl->ef), ").", GL_END_INFO);
6289 return 1;
6290 };
6291 /*
6292 * Attempt to open the file.
6293 */
6294 fp = fopen(expansion->files[0], "r");
6295 /*
6296 * It isn't an error for there to be no configuration file.
6297 */
6298 if(!fp)
6299 return 0;
6300 /*
6301 * Parse the contents of the file.
6302 */
6303 while(!waserr && !feof(fp))
6304 waserr = _gl_parse_config_line(gl, fp, glc_file_getc, filename, who,
6305 &lineno);
6306 /*
6307 * Bind action functions to the terminal-specific arrow keys.
6308 */
6309 if(_gl_bind_arrow_keys(gl))
6310 return 1;
6311 /*
6312 * Clean up.
6313 */
6314 (void) fclose(fp);
6315 return waserr;
6316 #endif
6317 }
6318
6319 /*.......................................................................
6320 * Read GetLine configuration information from a string. The contents of
6321 * the string are the same as those described in the gl_get_line(3)
6322 * man page for the contents of the ~/.teclarc configuration file.
6323 */
_gl_read_config_string(GetLine * gl,const char * buffer,KtBinder who)6324 static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who)
6325 {
6326 const char *bptr; /* A pointer into buffer[] */
6327 int waserr = 0; /* True if an error occurred while reading */
6328 int lineno = 1; /* The line number being processed */
6329 /*
6330 * Check the arguments.
6331 */
6332 if(!gl || !buffer) {
6333 if(gl)
6334 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
6335 errno = EINVAL;
6336 return 1;
6337 };
6338 /*
6339 * Get a pointer to the start of the buffer.
6340 */
6341 bptr = buffer;
6342 /*
6343 * Parse the contents of the buffer.
6344 */
6345 while(!waserr && *bptr)
6346 waserr = _gl_parse_config_line(gl, &bptr, glc_buff_getc, "", who, &lineno);
6347 /*
6348 * Bind action functions to the terminal-specific arrow keys.
6349 */
6350 if(_gl_bind_arrow_keys(gl))
6351 return 1;
6352 return waserr;
6353 }
6354
6355 /*.......................................................................
6356 * Parse the next line of a getline configuration file.
6357 *
6358 * Input:
6359 * gl GetLine * The getline resource object.
6360 * stream void * The pointer representing the stream to be read
6361 * by getc_fn().
6362 * getc_fn GlcGetcFn * A callback function which when called with
6363 * 'stream' as its argument, returns the next
6364 * unread character from the stream.
6365 * origin const char * The name of the entity being read (eg. a
6366 * file name).
6367 * who KtBinder Who bindings are to be installed for.
6368 * Input/Output:
6369 * lineno int * The line number being processed is to be
6370 * maintained in *lineno.
6371 * Output:
6372 * return int 0 - OK.
6373 * 1 - Irrecoverable error.
6374 */
_gl_parse_config_line(GetLine * gl,void * stream,GlcGetcFn * getc_fn,const char * origin,KtBinder who,int * lineno)6375 static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
6376 const char *origin, KtBinder who, int *lineno)
6377 {
6378 char buffer[GL_CONF_BUFLEN+1]; /* The input line buffer */
6379 char *argv[GL_CONF_MAXARG]; /* The argument list */
6380 int argc = 0; /* The number of arguments in argv[] */
6381 int c; /* A character from the file */
6382 int escaped = 0; /* True if the next character is escaped */
6383 int i;
6384 /*
6385 * Skip spaces and tabs.
6386 */
6387 do c = getc_fn(stream); while(c==' ' || c=='\t');
6388 /*
6389 * Comments extend to the end of the line.
6390 */
6391 if(c=='#')
6392 do c = getc_fn(stream); while(c != '\n' && c != EOF);
6393 /*
6394 * Ignore empty lines.
6395 */
6396 if(c=='\n' || c==EOF) {
6397 (*lineno)++;
6398 return 0;
6399 };
6400 /*
6401 * Record the buffer location of the start of the first argument.
6402 */
6403 argv[argc] = buffer;
6404 /*
6405 * Read the rest of the line, stopping early if a comment is seen, or
6406 * the buffer overflows, and replacing sequences of spaces with a
6407 * '\0', and recording the thus terminated string as an argument.
6408 */
6409 i = 0;
6410 while(i<GL_CONF_BUFLEN) {
6411 /*
6412 * Did we hit the end of the latest argument?
6413 */
6414 if(c==EOF || (!escaped && (c==' ' || c=='\n' || c=='\t' || c=='#'))) {
6415 /*
6416 * Terminate the argument.
6417 */
6418 buffer[i++] = '\0';
6419 argc++;
6420 /*
6421 * Skip spaces and tabs.
6422 */
6423 while(c==' ' || c=='\t')
6424 c = getc_fn(stream);
6425 /*
6426 * If we hit the end of the line, or the start of a comment, exit the loop.
6427 */
6428 if(c==EOF || c=='\n' || c=='#')
6429 break;
6430 /*
6431 * Start recording the next argument.
6432 */
6433 if(argc >= GL_CONF_MAXARG) {
6434 gl_report_config_error(gl, origin, *lineno, "Too many arguments.");
6435 do c = getc_fn(stream); while(c!='\n' && c!=EOF); /* Skip past eol */
6436 return 0;
6437 };
6438 argv[argc] = buffer + i;
6439 /*
6440 * The next character was preceded by spaces, so it isn't escaped.
6441 */
6442 escaped = 0;
6443 } else {
6444 /*
6445 * If we hit an unescaped backslash, this means that we should arrange
6446 * to treat the next character like a simple alphabetical character.
6447 */
6448 if(c=='\\' && !escaped) {
6449 escaped = 1;
6450 /*
6451 * Splice lines where the newline is escaped.
6452 */
6453 } else if(c=='\n' && escaped) {
6454 (*lineno)++;
6455 /*
6456 * Record a normal character, preserving any preceding backslash.
6457 */
6458 } else {
6459 if(escaped)
6460 buffer[i++] = '\\';
6461 if(i>=GL_CONF_BUFLEN)
6462 break;
6463 escaped = 0;
6464 buffer[i++] = c;
6465 };
6466 /*
6467 * Get the next character.
6468 */
6469 c = getc_fn(stream);
6470 };
6471 };
6472 /*
6473 * Did the buffer overflow?
6474 */
6475 if(i>=GL_CONF_BUFLEN) {
6476 gl_report_config_error(gl, origin, *lineno, "Line too long.");
6477 return 0;
6478 };
6479 /*
6480 * The first argument should be a command name.
6481 */
6482 if(strcmp(argv[0], "bind") == 0) {
6483 const char *action = NULL; /* A NULL action removes a keybinding */
6484 const char *keyseq = NULL;
6485 switch(argc) {
6486 case 3:
6487 action = argv[2];
6488 case 2: /* Note the intentional fallthrough */
6489 keyseq = argv[1];
6490 /*
6491 * Attempt to record the new keybinding.
6492 */
6493 if(_kt_set_keybinding(gl->bindings, who, keyseq, action)) {
6494 gl_report_config_error(gl, origin, *lineno,
6495 _kt_last_error(gl->bindings));
6496 };
6497 break;
6498 default:
6499 gl_report_config_error(gl, origin, *lineno, "Wrong number of arguments.");
6500 };
6501 } else if(strcmp(argv[0], "edit-mode") == 0) {
6502 if(argc == 2 && strcmp(argv[1], "emacs") == 0) {
6503 gl_change_editor(gl, GL_EMACS_MODE);
6504 } else if(argc == 2 && strcmp(argv[1], "vi") == 0) {
6505 gl_change_editor(gl, GL_VI_MODE);
6506 } else if(argc == 2 && strcmp(argv[1], "none") == 0) {
6507 gl_change_editor(gl, GL_NO_EDITOR);
6508 } else {
6509 gl_report_config_error(gl, origin, *lineno,
6510 "The argument of editor should be vi or emacs.");
6511 };
6512 } else if(strcmp(argv[0], "nobeep") == 0) {
6513 gl->silence_bell = 1;
6514 } else {
6515 gl_report_config_error(gl, origin, *lineno, "Unknown command name.");
6516 };
6517 /*
6518 * Skip any trailing comment.
6519 */
6520 while(c != '\n' && c != EOF)
6521 c = getc_fn(stream);
6522 (*lineno)++;
6523 return 0;
6524 }
6525
6526 /*.......................................................................
6527 * This is a private function of _gl_parse_config_line() which prints
6528 * out an error message about the contents of the line, prefixed by the
6529 * name of the origin of the line and its line number.
6530 *
6531 * Input:
6532 * gl GetLine * The resource object of gl_get_line().
6533 * origin const char * The name of the entity being read (eg. a
6534 * file name).
6535 * lineno int The line number at which the error occurred.
6536 * errmsg const char * The error message.
6537 * Output:
6538 * return int 0 - OK.
6539 * 1 - Error.
6540 */
gl_report_config_error(GetLine * gl,const char * origin,int lineno,const char * errmsg)6541 static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
6542 const char *errmsg)
6543 {
6544 char lnum[20]; /* A buffer in which to render a single integer */
6545 /*
6546 * Convert the line number into a string.
6547 */
6548 sprintf(lnum, "%d", lineno);
6549 /*
6550 * Have the string printed on the terminal.
6551 */
6552 return gl_print_info(gl, origin, ":", lnum, ": ", errmsg, GL_END_INFO);
6553 }
6554
6555 /*.......................................................................
6556 * This is the _gl_parse_config_line() callback function which reads the
6557 * next character from a configuration file.
6558 */
GLC_GETC_FN(glc_file_getc)6559 static GLC_GETC_FN(glc_file_getc)
6560 {
6561 return fgetc((FILE *) stream);
6562 }
6563
6564 /*.......................................................................
6565 * This is the _gl_parse_config_line() callback function which reads the
6566 * next character from a buffer. Its stream argument is a pointer to a
6567 * variable which is, in turn, a pointer into the buffer being read from.
6568 */
GLC_GETC_FN(glc_buff_getc)6569 static GLC_GETC_FN(glc_buff_getc)
6570 {
6571 const char **lptr = (char const **) stream;
6572 return **lptr ? *(*lptr)++ : EOF;
6573 }
6574
6575 #ifndef HIDE_FILE_SYSTEM
6576 /*.......................................................................
6577 * When this action is triggered, it arranges to temporarily read command
6578 * lines from the regular file whos name precedes the cursor.
6579 * The current line is first discarded.
6580 */
KT_KEY_FN(gl_read_from_file)6581 static KT_KEY_FN(gl_read_from_file)
6582 {
6583 char *start_path; /* The pointer to the start of the pathname in */
6584 /* gl->line[]. */
6585 FileExpansion *result; /* The results of the filename expansion */
6586 int pathlen; /* The length of the pathname being expanded */
6587 /*
6588 * Locate the start of the filename that precedes the cursor position.
6589 */
6590 start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
6591 if(!start_path)
6592 return 1;
6593 /*
6594 * Get the length of the pathname string.
6595 */
6596 pathlen = gl->buff_curpos - (start_path - gl->line);
6597 /*
6598 * Attempt to expand the pathname.
6599 */
6600 result = ef_expand_file(gl->ef, start_path, pathlen);
6601 /*
6602 * If there was an error, report the error on a new line.
6603 */
6604 if(!result) {
6605 return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
6606 /*
6607 * If no files matched, report this as well.
6608 */
6609 } else if(result->nfile == 0 || !result->exists) {
6610 return gl_print_info(gl, "No files match.", GL_END_INFO);
6611 /*
6612 * Complain if more than one file matches.
6613 */
6614 } else if(result->nfile > 1) {
6615 return gl_print_info(gl, "More than one file matches.", GL_END_INFO);
6616 /*
6617 * Disallow input from anything but normal files. In principle we could
6618 * also support input from named pipes. Terminal files would be a problem
6619 * since we wouldn't know the terminal type, and other types of files
6620 * might cause the library to lock up.
6621 */
6622 } else if(!_pu_path_is_file(result->files[0])) {
6623 return gl_print_info(gl, "Not a normal file.", GL_END_INFO);
6624 } else {
6625 /*
6626 * Attempt to open and install the specified file for reading.
6627 */
6628 gl->file_fp = fopen(result->files[0], "r");
6629 if(!gl->file_fp) {
6630 return gl_print_info(gl, "Unable to open: ", result->files[0],
6631 GL_END_INFO);
6632 };
6633 /*
6634 * If needed, expand the record of the maximum file-descriptor that might
6635 * need to be monitored with select().
6636 */
6637 #ifdef HAVE_SELECT
6638 if(fileno(gl->file_fp) > gl->max_fd)
6639 gl->max_fd = fileno(gl->file_fp);
6640 #endif
6641 /*
6642 * Is non-blocking I/O needed?
6643 */
6644 if(gl->raw_mode && gl->io_mode==GL_SERVER_MODE &&
6645 gl_nonblocking_io(gl, fileno(gl->file_fp))) {
6646 gl_revert_input(gl);
6647 return gl_print_info(gl, "Can't read file %s with non-blocking I/O",
6648 result->files[0]);
6649 };
6650 /*
6651 * Inform the user what is happening.
6652 */
6653 if(gl_print_info(gl, "<Taking input from ", result->files[0], ">",
6654 GL_END_INFO))
6655 return 1;
6656 };
6657 return 0;
6658 }
6659 #endif
6660
6661 /*.......................................................................
6662 * Close any temporary file that is being used for input.
6663 *
6664 * Input:
6665 * gl GetLine * The getline resource object.
6666 */
gl_revert_input(GetLine * gl)6667 static void gl_revert_input(GetLine *gl)
6668 {
6669 if(gl->file_fp)
6670 fclose(gl->file_fp);
6671 gl->file_fp = NULL;
6672 gl->endline = 1;
6673 }
6674
6675 /*.......................................................................
6676 * This is the action function that recalls the oldest line in the
6677 * history buffer.
6678 */
KT_KEY_FN(gl_beginning_of_history)6679 static KT_KEY_FN(gl_beginning_of_history)
6680 {
6681 /*
6682 * In vi mode, switch to command mode, since the user is very
6683 * likely to want to move around newly recalled lines.
6684 */
6685 gl_vi_command_mode(gl);
6686 /*
6687 * Forget any previous recall session.
6688 */
6689 gl->preload_id = 0;
6690 /*
6691 * Record the key sequence number of this search action.
6692 */
6693 gl->last_search = gl->keyseq_count;
6694 /*
6695 * Recall the next oldest line in the history list.
6696 */
6697 if(_glh_oldest_line(gl->glh, gl->line, gl->linelen+1) == NULL)
6698 return 0;
6699 /*
6700 * Accomodate the new contents of gl->line[].
6701 */
6702 gl_update_buffer(gl);
6703 /*
6704 * Arrange to have the cursor placed at the end of the new line.
6705 */
6706 gl->buff_curpos = gl->ntotal;
6707 /*
6708 * Erase and display the new line.
6709 */
6710 gl_queue_redisplay(gl);
6711 return 0;
6712 }
6713
6714 /*.......................................................................
6715 * If a history session is currently in progress, this action function
6716 * recalls the line that was being edited when the session started. If
6717 * no history session is in progress, it does nothing.
6718 */
KT_KEY_FN(gl_end_of_history)6719 static KT_KEY_FN(gl_end_of_history)
6720 {
6721 /*
6722 * In vi mode, switch to command mode, since the user is very
6723 * likely to want to move around newly recalled lines.
6724 */
6725 gl_vi_command_mode(gl);
6726 /*
6727 * Forget any previous recall session.
6728 */
6729 gl->preload_id = 0;
6730 /*
6731 * Record the key sequence number of this search action.
6732 */
6733 gl->last_search = gl->keyseq_count;
6734 /*
6735 * Recall the next oldest line in the history list.
6736 */
6737 if(_glh_current_line(gl->glh, gl->line, gl->linelen+1) == NULL)
6738 return 0;
6739 /*
6740 * Accomodate the new contents of gl->line[].
6741 */
6742 gl_update_buffer(gl);
6743 /*
6744 * Arrange to have the cursor placed at the end of the new line.
6745 */
6746 gl->buff_curpos = gl->ntotal;
6747 /*
6748 * Erase and display the new line.
6749 */
6750 gl_queue_redisplay(gl);
6751 return 0;
6752 }
6753
6754 /*.......................................................................
6755 * This action function is treated specially, in that its count argument
6756 * is set to the end keystroke of the keysequence that activated it.
6757 * It accumulates a numeric argument, adding one digit on each call in
6758 * which the last keystroke was a numeric digit.
6759 */
KT_KEY_FN(gl_digit_argument)6760 static KT_KEY_FN(gl_digit_argument)
6761 {
6762 /*
6763 * Was the last keystroke a digit?
6764 */
6765 int is_digit = isdigit((int)(unsigned char) count);
6766 /*
6767 * In vi command mode, a lone '0' means goto-start-of-line.
6768 */
6769 if(gl->vi.command && gl->number < 0 && count == '0')
6770 return gl_beginning_of_line(gl, count, NULL);
6771 /*
6772 * Are we starting to accumulate a new number?
6773 */
6774 if(gl->number < 0 || !is_digit)
6775 gl->number = 0;
6776 /*
6777 * Was the last keystroke a digit?
6778 */
6779 if(is_digit) {
6780 /*
6781 * Read the numeric value of the digit, without assuming ASCII.
6782 */
6783 int n;
6784 char s[2]; s[0] = count; s[1] = '\0';
6785 n = atoi(s);
6786 /*
6787 * Append the new digit.
6788 */
6789 gl->number = gl->number * 10 + n;
6790 };
6791 return 0;
6792 }
6793
6794 /*.......................................................................
6795 * The newline action function sets gl->endline to tell
6796 * gl_get_input_line() that the line is now complete.
6797 */
KT_KEY_FN(gl_newline)6798 static KT_KEY_FN(gl_newline)
6799 {
6800 GlhLineID id; /* The last history line recalled while entering this line */
6801 /*
6802 * Flag the line as ended.
6803 */
6804 gl->endline = 1;
6805 /*
6806 * Record the next position in the history buffer, for potential
6807 * recall by an action function on the next call to gl_get_line().
6808 */
6809 id = _glh_line_id(gl->glh, 1);
6810 if(id)
6811 gl->preload_id = id;
6812 return 0;
6813 }
6814
6815 /*.......................................................................
6816 * The 'repeat' action function sets gl->endline to tell
6817 * gl_get_input_line() that the line is now complete, and records the
6818 * ID of the next history line in gl->preload_id so that the next call
6819 * to gl_get_input_line() will preload the line with that history line.
6820 */
KT_KEY_FN(gl_repeat_history)6821 static KT_KEY_FN(gl_repeat_history)
6822 {
6823 gl->endline = 1;
6824 gl->preload_id = _glh_line_id(gl->glh, 1);
6825 gl->preload_history = 1;
6826 return 0;
6827 }
6828
6829 /*.......................................................................
6830 * Flush unwritten characters to the terminal.
6831 *
6832 * Input:
6833 * gl GetLine * The getline resource object.
6834 * Output:
6835 * return int 0 - OK.
6836 * 1 - Either an error occured, or the output
6837 * blocked and non-blocking I/O is being used.
6838 * See gl->rtn_status for details.
6839 */
gl_flush_output(GetLine * gl)6840 static int gl_flush_output(GetLine *gl)
6841 {
6842 /*
6843 * Record the fact that we are about to write to the terminal.
6844 */
6845 gl->pending_io = GLP_WRITE;
6846 /*
6847 * Attempt to flush the output to the terminal.
6848 */
6849 errno = 0;
6850 switch(_glq_flush_queue(gl->cq, gl->flush_fn, gl)) {
6851 case GLQ_FLUSH_DONE:
6852 return gl->redisplay && !gl->postpone && gl_redisplay(gl, 1, NULL);
6853 break;
6854 case GLQ_FLUSH_AGAIN: /* Output blocked */
6855 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
6856 return 1;
6857 break;
6858 default: /* Abort the line if an error occurs */
6859 gl_record_status(gl, errno==EINTR ? GLR_SIGNAL : GLR_ERROR, errno);
6860 return 1;
6861 break;
6862 };
6863 }
6864
6865 /*.......................................................................
6866 * This is the callback which _glq_flush_queue() uses to write buffered
6867 * characters to the terminal.
6868 */
GL_WRITE_FN(gl_flush_terminal)6869 static GL_WRITE_FN(gl_flush_terminal)
6870 {
6871 int ndone = 0; /* The number of characters written so far */
6872 /*
6873 * Get the line-editor resource object.
6874 */
6875 GetLine *gl = (GetLine *) data;
6876 /*
6877 * Transfer the latest array of characters to stdio.
6878 */
6879 while(ndone < n) {
6880 int nnew = write(gl->output_fd, s, n-ndone);
6881 /*
6882 * If the write was successful, add to the recorded number of bytes
6883 * that have now been written.
6884 */
6885 if(nnew > 0) {
6886 ndone += nnew;
6887 /*
6888 * If a signal interrupted the call, restart the write(), since all of
6889 * the signals that gl_get_line() has been told to watch for are
6890 * currently blocked.
6891 */
6892 } else if(errno == EINTR) {
6893 continue;
6894 /*
6895 * If we managed to write something before an I/O error occurred, or
6896 * output blocked before anything was written, report the number of
6897 * bytes that were successfully written before this happened.
6898 */
6899 } else if(ndone > 0
6900 #if defined(EAGAIN)
6901 || errno==EAGAIN
6902 #endif
6903 #if defined(EWOULDBLOCK)
6904 || errno==EWOULDBLOCK
6905 #endif
6906 ) {
6907 return ndone;
6908
6909 /*
6910 * To get here, an error must have occurred before anything new could
6911 * be written.
6912 */
6913 } else {
6914 return -1;
6915 };
6916 };
6917 /*
6918 * To get here, we must have successfully written the number of
6919 * bytes that was specified.
6920 */
6921 return n;
6922 }
6923
6924 /*.......................................................................
6925 * Change the style of editing to emulate a given editor.
6926 *
6927 * Input:
6928 * gl GetLine * The getline resource object.
6929 * editor GlEditor The type of editor to emulate.
6930 * Output:
6931 * return int 0 - OK.
6932 * 1 - Error.
6933 */
gl_change_editor(GetLine * gl,GlEditor editor)6934 static int gl_change_editor(GetLine *gl, GlEditor editor)
6935 {
6936 /*
6937 * Install the default key-bindings of the requested editor.
6938 */
6939 switch(editor) {
6940 case GL_EMACS_MODE:
6941 _kt_clear_bindings(gl->bindings, KTB_NORM);
6942 _kt_clear_bindings(gl->bindings, KTB_TERM);
6943 (void) _kt_add_bindings(gl->bindings, KTB_NORM, gl_emacs_bindings,
6944 sizeof(gl_emacs_bindings)/sizeof(gl_emacs_bindings[0]));
6945 break;
6946 case GL_VI_MODE:
6947 _kt_clear_bindings(gl->bindings, KTB_NORM);
6948 _kt_clear_bindings(gl->bindings, KTB_TERM);
6949 (void) _kt_add_bindings(gl->bindings, KTB_NORM, gl_vi_bindings,
6950 sizeof(gl_vi_bindings)/sizeof(gl_vi_bindings[0]));
6951 break;
6952 case GL_NO_EDITOR:
6953 break;
6954 default:
6955 _err_record_msg(gl->err, "Unknown editor", END_ERR_MSG);
6956 errno = EINVAL;
6957 return 1;
6958 };
6959 /*
6960 * Record the new editing mode.
6961 */
6962 gl->editor = editor;
6963 gl->vi.command = 0; /* Start in input mode */
6964 gl->insert_curpos = 0;
6965 /*
6966 * Reinstate terminal-specific bindings.
6967 */
6968 if(gl->editor != GL_NO_EDITOR && gl->input_fp)
6969 (void) gl_bind_terminal_keys(gl);
6970 return 0;
6971 }
6972
6973 /*.......................................................................
6974 * This is an action function that switches to editing using emacs bindings
6975 */
KT_KEY_FN(gl_emacs_editing_mode)6976 static KT_KEY_FN(gl_emacs_editing_mode)
6977 {
6978 return gl_change_editor(gl, GL_EMACS_MODE);
6979 }
6980
6981 /*.......................................................................
6982 * This is an action function that switches to editing using vi bindings
6983 */
KT_KEY_FN(gl_vi_editing_mode)6984 static KT_KEY_FN(gl_vi_editing_mode)
6985 {
6986 return gl_change_editor(gl, GL_VI_MODE);
6987 }
6988
6989 /*.......................................................................
6990 * This is the action function that switches to insert mode.
6991 */
KT_KEY_FN(gl_vi_insert)6992 static KT_KEY_FN(gl_vi_insert)
6993 {
6994 /*
6995 * If in vi command mode, preserve the current line for potential
6996 * use by vi-undo.
6997 */
6998 gl_save_for_undo(gl);
6999 /*
7000 * Switch to vi insert mode.
7001 */
7002 gl->insert = 1;
7003 gl->vi.command = 0;
7004 gl->insert_curpos = gl->buff_curpos;
7005 return 0;
7006 }
7007
7008 /*.......................................................................
7009 * This is an action function that switches to overwrite mode.
7010 */
KT_KEY_FN(gl_vi_overwrite)7011 static KT_KEY_FN(gl_vi_overwrite)
7012 {
7013 /*
7014 * If in vi command mode, preserve the current line for potential
7015 * use by vi-undo.
7016 */
7017 gl_save_for_undo(gl);
7018 /*
7019 * Switch to vi overwrite mode.
7020 */
7021 gl->insert = 0;
7022 gl->vi.command = 0;
7023 gl->insert_curpos = gl->buff_curpos;
7024 return 0;
7025 }
7026
7027 /*.......................................................................
7028 * This action function toggles the case of the character under the
7029 * cursor.
7030 */
KT_KEY_FN(gl_change_case)7031 static KT_KEY_FN(gl_change_case)
7032 {
7033 int i;
7034 /*
7035 * Keep a record of the current insert mode and the cursor position.
7036 */
7037 int insert = gl->insert;
7038 /*
7039 * If in vi command mode, preserve the current line for potential
7040 * use by vi-undo.
7041 */
7042 gl_save_for_undo(gl);
7043 /*
7044 * We want to overwrite the modified word.
7045 */
7046 gl->insert = 0;
7047 /*
7048 * Toggle the case of 'count' characters.
7049 */
7050 for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) {
7051 char *cptr = gl->line + gl->buff_curpos++;
7052 /*
7053 * Convert the character to upper case?
7054 */
7055 if(islower((int)(unsigned char) *cptr))
7056 gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
7057 else if(isupper((int)(unsigned char) *cptr))
7058 gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
7059 /*
7060 * Write the possibly modified character back. Note that for non-modified
7061 * characters we want to do this as well, so as to advance the cursor.
7062 */
7063 if(gl_print_char(gl, *cptr, cptr[1]))
7064 return 1;
7065 };
7066 /*
7067 * Restore the insertion mode.
7068 */
7069 gl->insert = insert;
7070 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
7071 }
7072
7073 /*.......................................................................
7074 * This is the action function which implements the vi-style action which
7075 * moves the cursor to the start of the line, then switches to insert mode.
7076 */
KT_KEY_FN(gl_vi_insert_at_bol)7077 static KT_KEY_FN(gl_vi_insert_at_bol)
7078 {
7079 gl_save_for_undo(gl);
7080 return gl_beginning_of_line(gl, 0, NULL) ||
7081 gl_vi_insert(gl, 0, NULL);
7082
7083 }
7084
7085 /*.......................................................................
7086 * This is the action function which implements the vi-style action which
7087 * moves the cursor to the end of the line, then switches to insert mode
7088 * to allow text to be appended to the line.
7089 */
KT_KEY_FN(gl_vi_append_at_eol)7090 static KT_KEY_FN(gl_vi_append_at_eol)
7091 {
7092 gl_save_for_undo(gl);
7093 gl->vi.command = 0; /* Allow cursor at EOL */
7094 return gl_end_of_line(gl, 0, NULL) ||
7095 gl_vi_insert(gl, 0, NULL);
7096 }
7097
7098 /*.......................................................................
7099 * This is the action function which implements the vi-style action which
7100 * moves the cursor to right one then switches to insert mode, thus
7101 * allowing text to be appended after the next character.
7102 */
KT_KEY_FN(gl_vi_append)7103 static KT_KEY_FN(gl_vi_append)
7104 {
7105 gl_save_for_undo(gl);
7106 gl->vi.command = 0; /* Allow cursor at EOL */
7107 return gl_cursor_right(gl, 1, NULL) ||
7108 gl_vi_insert(gl, 0, NULL);
7109 }
7110
7111 /*.......................................................................
7112 * This action function moves the cursor to the column specified by the
7113 * numeric argument. Column indexes start at 1.
7114 */
KT_KEY_FN(gl_goto_column)7115 static KT_KEY_FN(gl_goto_column)
7116 {
7117 return gl_place_cursor(gl, count - 1);
7118 }
7119
7120 /*.......................................................................
7121 * Starting with the character under the cursor, replace 'count'
7122 * characters with the next character that the user types.
7123 */
KT_KEY_FN(gl_vi_replace_char)7124 static KT_KEY_FN(gl_vi_replace_char)
7125 {
7126 char c; /* The replacement character */
7127 int i;
7128 /*
7129 * Keep a record of the current insert mode.
7130 */
7131 int insert = gl->insert;
7132 /*
7133 * Get the replacement character.
7134 */
7135 if(gl->vi.repeat.active) {
7136 c = gl->vi.repeat.input_char;
7137 } else {
7138 if(gl_read_terminal(gl, 1, &c))
7139 return 1;
7140 gl->vi.repeat.input_char = c;
7141 };
7142 /*
7143 * Are there 'count' characters to be replaced?
7144 */
7145 if(gl->ntotal - gl->buff_curpos >= count) {
7146 /*
7147 * If in vi command mode, preserve the current line for potential
7148 * use by vi-undo.
7149 */
7150 gl_save_for_undo(gl);
7151 /*
7152 * Temporarily switch to overwrite mode.
7153 */
7154 gl->insert = 0;
7155 /*
7156 * Overwrite the current character plus count-1 subsequent characters
7157 * with the replacement character.
7158 */
7159 for(i=0; i<count; i++)
7160 gl_add_char_to_line(gl, c);
7161 /*
7162 * Restore the original insert/overwrite mode.
7163 */
7164 gl->insert = insert;
7165 };
7166 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
7167 }
7168
7169 /*.......................................................................
7170 * This is an action function which changes all characters between the
7171 * current cursor position and the end of the line.
7172 */
KT_KEY_FN(gl_vi_change_rest_of_line)7173 static KT_KEY_FN(gl_vi_change_rest_of_line)
7174 {
7175 gl_save_for_undo(gl);
7176 gl->vi.command = 0; /* Allow cursor at EOL */
7177 return gl_kill_line(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
7178 }
7179
7180 /*.......................................................................
7181 * This is an action function which changes all characters between the
7182 * start of the line and the current cursor position.
7183 */
KT_KEY_FN(gl_vi_change_to_bol)7184 static KT_KEY_FN(gl_vi_change_to_bol)
7185 {
7186 return gl_backward_kill_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL);
7187 }
7188
7189 /*.......................................................................
7190 * This is an action function which deletes the entire contents of the
7191 * current line and switches to insert mode.
7192 */
KT_KEY_FN(gl_vi_change_line)7193 static KT_KEY_FN(gl_vi_change_line)
7194 {
7195 return gl_delete_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL);
7196 }
7197
7198 /*.......................................................................
7199 * Starting from the cursor position and looking towards the end of the
7200 * line, copy 'count' characters to the cut buffer.
7201 */
KT_KEY_FN(gl_forward_copy_char)7202 static KT_KEY_FN(gl_forward_copy_char)
7203 {
7204 /*
7205 * Limit the count to the number of characters available.
7206 */
7207 if(gl->buff_curpos + count >= gl->ntotal)
7208 count = gl->ntotal - gl->buff_curpos;
7209 if(count < 0)
7210 count = 0;
7211 /*
7212 * Copy the characters to the cut buffer.
7213 */
7214 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, count);
7215 gl->cutbuf[count] = '\0';
7216 return 0;
7217 }
7218
7219 /*.......................................................................
7220 * Starting from the character before the cursor position and looking
7221 * backwards towards the start of the line, copy 'count' characters to
7222 * the cut buffer.
7223 */
KT_KEY_FN(gl_backward_copy_char)7224 static KT_KEY_FN(gl_backward_copy_char)
7225 {
7226 /*
7227 * Limit the count to the number of characters available.
7228 */
7229 if(count > gl->buff_curpos)
7230 count = gl->buff_curpos;
7231 if(count < 0)
7232 count = 0;
7233 gl_place_cursor(gl, gl->buff_curpos - count);
7234 /*
7235 * Copy the characters to the cut buffer.
7236 */
7237 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, count);
7238 gl->cutbuf[count] = '\0';
7239 return 0;
7240 }
7241
7242 /*.......................................................................
7243 * Starting from the cursor position copy to the specified column into the
7244 * cut buffer.
7245 */
KT_KEY_FN(gl_copy_to_column)7246 static KT_KEY_FN(gl_copy_to_column)
7247 {
7248 if (--count >= gl->buff_curpos)
7249 return gl_forward_copy_char(gl, count - gl->buff_curpos, NULL);
7250 else
7251 return gl_backward_copy_char(gl, gl->buff_curpos - count, NULL);
7252 }
7253
7254 /*.......................................................................
7255 * Starting from the cursor position copy characters up to a matching
7256 * parenthesis into the cut buffer.
7257 */
KT_KEY_FN(gl_copy_to_parenthesis)7258 static KT_KEY_FN(gl_copy_to_parenthesis)
7259 {
7260 int curpos = gl_index_of_matching_paren(gl);
7261 if(curpos >= 0) {
7262 gl_save_for_undo(gl);
7263 if(curpos >= gl->buff_curpos)
7264 return gl_forward_copy_char(gl, curpos - gl->buff_curpos + 1, NULL);
7265 else
7266 return gl_backward_copy_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
7267 };
7268 return 0;
7269 }
7270
7271 /*.......................................................................
7272 * Starting from the cursor position copy the rest of the line into the
7273 * cut buffer.
7274 */
KT_KEY_FN(gl_copy_rest_of_line)7275 static KT_KEY_FN(gl_copy_rest_of_line)
7276 {
7277 /*
7278 * Copy the characters to the cut buffer.
7279 */
7280 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, gl->ntotal - gl->buff_curpos);
7281 gl->cutbuf[gl->ntotal - gl->buff_curpos] = '\0';
7282 return 0;
7283 }
7284
7285 /*.......................................................................
7286 * Copy from the beginning of the line to the cursor position into the
7287 * cut buffer.
7288 */
KT_KEY_FN(gl_copy_to_bol)7289 static KT_KEY_FN(gl_copy_to_bol)
7290 {
7291 /*
7292 * Copy the characters to the cut buffer.
7293 */
7294 memcpy(gl->cutbuf, gl->line, gl->buff_curpos);
7295 gl->cutbuf[gl->buff_curpos] = '\0';
7296 gl_place_cursor(gl, 0);
7297 return 0;
7298 }
7299
7300 /*.......................................................................
7301 * Copy the entire line into the cut buffer.
7302 */
KT_KEY_FN(gl_copy_line)7303 static KT_KEY_FN(gl_copy_line)
7304 {
7305 /*
7306 * Copy the characters to the cut buffer.
7307 */
7308 memcpy(gl->cutbuf, gl->line, gl->ntotal);
7309 gl->cutbuf[gl->ntotal] = '\0';
7310 return 0;
7311 }
7312
7313 /*.......................................................................
7314 * Search forwards for the next character that the user enters.
7315 */
KT_KEY_FN(gl_forward_find_char)7316 static KT_KEY_FN(gl_forward_find_char)
7317 {
7318 int pos = gl_find_char(gl, count, 1, 1, '\0');
7319 return pos >= 0 && gl_place_cursor(gl, pos);
7320 }
7321
7322 /*.......................................................................
7323 * Search backwards for the next character that the user enters.
7324 */
KT_KEY_FN(gl_backward_find_char)7325 static KT_KEY_FN(gl_backward_find_char)
7326 {
7327 int pos = gl_find_char(gl, count, 0, 1, '\0');
7328 return pos >= 0 && gl_place_cursor(gl, pos);
7329 }
7330
7331 /*.......................................................................
7332 * Search forwards for the next character that the user enters. Move up to,
7333 * but not onto, the found character.
7334 */
KT_KEY_FN(gl_forward_to_char)7335 static KT_KEY_FN(gl_forward_to_char)
7336 {
7337 int pos = gl_find_char(gl, count, 1, 0, '\0');
7338 return pos >= 0 && gl_place_cursor(gl, pos);
7339 }
7340
7341 /*.......................................................................
7342 * Search backwards for the next character that the user enters. Move back to,
7343 * but not onto, the found character.
7344 */
KT_KEY_FN(gl_backward_to_char)7345 static KT_KEY_FN(gl_backward_to_char)
7346 {
7347 int pos = gl_find_char(gl, count, 0, 0, '\0');
7348 return pos >= 0 && gl_place_cursor(gl, pos);
7349 }
7350
7351 /*.......................................................................
7352 * Searching in a given direction, return the index of a given (or
7353 * read) character in the input line, or the character that precedes
7354 * it in the specified search direction. Return -1 if not found.
7355 *
7356 * Input:
7357 * gl GetLine * The getline resource object.
7358 * count int The number of times to search.
7359 * forward int True if searching forward.
7360 * onto int True if the search should end on top of the
7361 * character, false if the search should stop
7362 * one character before the character in the
7363 * specified search direction.
7364 * c char The character to be sought, or '\0' if the
7365 * character should be read from the user.
7366 * Output:
7367 * return int The index of the character in gl->line[], or
7368 * -1 if not found.
7369 */
gl_find_char(GetLine * gl,int count,int forward,int onto,char c)7370 static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c)
7371 {
7372 int pos; /* The index reached in searching the input line */
7373 int i;
7374 /*
7375 * Get a character from the user?
7376 */
7377 if(!c) {
7378 /*
7379 * If we are in the process of repeating a previous change command, substitute
7380 * the last find character.
7381 */
7382 if(gl->vi.repeat.active) {
7383 c = gl->vi.find_char;
7384 } else {
7385 if(gl_read_terminal(gl, 1, &c))
7386 return -1;
7387 /*
7388 * Record the details of the new search, for use by repeat finds.
7389 */
7390 gl->vi.find_forward = forward;
7391 gl->vi.find_onto = onto;
7392 gl->vi.find_char = c;
7393 };
7394 };
7395 /*
7396 * Which direction should we search?
7397 */
7398 if(forward) {
7399 /*
7400 * Search forwards 'count' times for the character, starting with the
7401 * character that follows the cursor.
7402 */
7403 for(i=0, pos=gl->buff_curpos; i<count && pos < gl->ntotal; i++) {
7404 /*
7405 * Advance past the last match (or past the current cursor position
7406 * on the first search).
7407 */
7408 pos++;
7409 /*
7410 * Search for the next instance of c.
7411 */
7412 for( ; pos<gl->ntotal && c!=gl->line[pos]; pos++)
7413 ;
7414 };
7415 /*
7416 * If the character was found and we have been requested to return the
7417 * position of the character that precedes the desired character, then
7418 * we have gone one character too far.
7419 */
7420 if(!onto && pos<gl->ntotal)
7421 pos--;
7422 } else {
7423 /*
7424 * Search backwards 'count' times for the character, starting with the
7425 * character that precedes the cursor.
7426 */
7427 for(i=0, pos=gl->buff_curpos; i<count && pos >= gl->insert_curpos; i++) {
7428 /*
7429 * Step back one from the last match (or from the current cursor
7430 * position on the first search).
7431 */
7432 pos--;
7433 /*
7434 * Search for the next instance of c.
7435 */
7436 for( ; pos>=gl->insert_curpos && c!=gl->line[pos]; pos--)
7437 ;
7438 };
7439 /*
7440 * If the character was found and we have been requested to return the
7441 * position of the character that precedes the desired character, then
7442 * we have gone one character too far.
7443 */
7444 if(!onto && pos>=gl->insert_curpos)
7445 pos++;
7446 };
7447 /*
7448 * If found, return the cursor position of the count'th match.
7449 * Otherwise ring the terminal bell.
7450 */
7451 if(pos >= gl->insert_curpos && pos < gl->ntotal) {
7452 return pos;
7453 } else {
7454 (void) gl_ring_bell(gl, 1, NULL);
7455 return -1;
7456 }
7457 }
7458
7459 /*.......................................................................
7460 * Repeat the last character search in the same direction as the last
7461 * search.
7462 */
KT_KEY_FN(gl_repeat_find_char)7463 static KT_KEY_FN(gl_repeat_find_char)
7464 {
7465 int pos = gl->vi.find_char ?
7466 gl_find_char(gl, count, gl->vi.find_forward, gl->vi.find_onto,
7467 gl->vi.find_char) : -1;
7468 return pos >= 0 && gl_place_cursor(gl, pos);
7469 }
7470
7471 /*.......................................................................
7472 * Repeat the last character search in the opposite direction as the last
7473 * search.
7474 */
KT_KEY_FN(gl_invert_refind_char)7475 static KT_KEY_FN(gl_invert_refind_char)
7476 {
7477 int pos = gl->vi.find_char ?
7478 gl_find_char(gl, count, !gl->vi.find_forward, gl->vi.find_onto,
7479 gl->vi.find_char) : -1;
7480 return pos >= 0 && gl_place_cursor(gl, pos);
7481 }
7482
7483 /*.......................................................................
7484 * Search forward from the current position of the cursor for 'count'
7485 * word endings, returning the index of the last one found, or the end of
7486 * the line if there were less than 'count' words.
7487 *
7488 * Input:
7489 * gl GetLine * The getline resource object.
7490 * n int The number of word boundaries to search for.
7491 * Output:
7492 * return int The buffer index of the located position.
7493 */
gl_nth_word_end_forward(GetLine * gl,int n)7494 static int gl_nth_word_end_forward(GetLine *gl, int n)
7495 {
7496 int bufpos; /* The buffer index being checked. */
7497 int i;
7498 /*
7499 * In order to guarantee forward motion to the next word ending,
7500 * we need to start from one position to the right of the cursor
7501 * position, since this may already be at the end of a word.
7502 */
7503 bufpos = gl->buff_curpos + 1;
7504 /*
7505 * If we are at the end of the line, return the index of the last
7506 * real character on the line. Note that this will be -1 if the line
7507 * is empty.
7508 */
7509 if(bufpos >= gl->ntotal)
7510 return gl->ntotal - 1;
7511 /*
7512 * Search 'n' times, unless the end of the input line is reached first.
7513 */
7514 for(i=0; i<n && bufpos<gl->ntotal; i++) {
7515 /*
7516 * If we are not already within a word, skip to the start of the next word.
7517 */
7518 for( ; bufpos<gl->ntotal && !gl_is_word_char((int)gl->line[bufpos]);
7519 bufpos++)
7520 ;
7521 /*
7522 * Find the end of the next word.
7523 */
7524 for( ; bufpos<gl->ntotal && gl_is_word_char((int)gl->line[bufpos]);
7525 bufpos++)
7526 ;
7527 };
7528 /*
7529 * We will have overshot.
7530 */
7531 return bufpos > 0 ? bufpos-1 : bufpos;
7532 }
7533
7534 /*.......................................................................
7535 * Search forward from the current position of the cursor for 'count'
7536 * word starts, returning the index of the last one found, or the end of
7537 * the line if there were less than 'count' words.
7538 *
7539 * Input:
7540 * gl GetLine * The getline resource object.
7541 * n int The number of word boundaries to search for.
7542 * Output:
7543 * return int The buffer index of the located position.
7544 */
gl_nth_word_start_forward(GetLine * gl,int n)7545 static int gl_nth_word_start_forward(GetLine *gl, int n)
7546 {
7547 int bufpos; /* The buffer index being checked. */
7548 int i;
7549 /*
7550 * Get the current cursor position.
7551 */
7552 bufpos = gl->buff_curpos;
7553 /*
7554 * Search 'n' times, unless the end of the input line is reached first.
7555 */
7556 for(i=0; i<n && bufpos<gl->ntotal; i++) {
7557 /*
7558 * Find the end of the current word.
7559 */
7560 for( ; bufpos<gl->ntotal && gl_is_word_char((int)gl->line[bufpos]);
7561 bufpos++)
7562 ;
7563 /*
7564 * Skip to the start of the next word.
7565 */
7566 for( ; bufpos<gl->ntotal && !gl_is_word_char((int)gl->line[bufpos]);
7567 bufpos++)
7568 ;
7569 };
7570 return bufpos;
7571 }
7572
7573 /*.......................................................................
7574 * Search backward from the current position of the cursor for 'count'
7575 * word starts, returning the index of the last one found, or the start
7576 * of the line if there were less than 'count' words.
7577 *
7578 * Input:
7579 * gl GetLine * The getline resource object.
7580 * n int The number of word boundaries to search for.
7581 * Output:
7582 * return int The buffer index of the located position.
7583 */
gl_nth_word_start_backward(GetLine * gl,int n)7584 static int gl_nth_word_start_backward(GetLine *gl, int n)
7585 {
7586 int bufpos; /* The buffer index being checked. */
7587 int i;
7588 /*
7589 * Get the current cursor position.
7590 */
7591 bufpos = gl->buff_curpos;
7592 /*
7593 * Search 'n' times, unless the beginning of the input line (or vi insertion
7594 * point) is reached first.
7595 */
7596 for(i=0; i<n && bufpos > gl->insert_curpos; i++) {
7597 /*
7598 * Starting one character back from the last search, so as not to keep
7599 * settling on the same word-start, search backwards until finding a
7600 * word character.
7601 */
7602 while(--bufpos >= gl->insert_curpos &&
7603 !gl_is_word_char((int)gl->line[bufpos]))
7604 ;
7605 /*
7606 * Find the start of the word.
7607 */
7608 while(--bufpos >= gl->insert_curpos &&
7609 gl_is_word_char((int)gl->line[bufpos]))
7610 ;
7611 /*
7612 * We will have gone one character too far.
7613 */
7614 bufpos++;
7615 };
7616 return bufpos >= gl->insert_curpos ? bufpos : gl->insert_curpos;
7617 }
7618
7619 /*.......................................................................
7620 * Copy one or more words into the cut buffer without moving the cursor
7621 * or deleting text.
7622 */
KT_KEY_FN(gl_forward_copy_word)7623 static KT_KEY_FN(gl_forward_copy_word)
7624 {
7625 /*
7626 * Find the location of the count'th start or end of a word
7627 * after the cursor, depending on whether in emacs or vi mode.
7628 */
7629 int next = gl->editor == GL_EMACS_MODE ?
7630 gl_nth_word_end_forward(gl, count) :
7631 gl_nth_word_start_forward(gl, count);
7632 /*
7633 * How many characters are to be copied into the cut buffer?
7634 */
7635 int n = next - gl->buff_curpos;
7636 /*
7637 * Copy the specified segment and terminate the string.
7638 */
7639 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, n);
7640 gl->cutbuf[n] = '\0';
7641 return 0;
7642 }
7643
7644 /*.......................................................................
7645 * Copy one or more words preceding the cursor into the cut buffer,
7646 * without moving the cursor or deleting text.
7647 */
KT_KEY_FN(gl_backward_copy_word)7648 static KT_KEY_FN(gl_backward_copy_word)
7649 {
7650 /*
7651 * Find the location of the count'th start of word before the cursor.
7652 */
7653 int next = gl_nth_word_start_backward(gl, count);
7654 /*
7655 * How many characters are to be copied into the cut buffer?
7656 */
7657 int n = gl->buff_curpos - next;
7658 gl_place_cursor(gl, next);
7659 /*
7660 * Copy the specified segment and terminate the string.
7661 */
7662 memcpy(gl->cutbuf, gl->line + next, n);
7663 gl->cutbuf[n] = '\0';
7664 return 0;
7665 }
7666
7667 /*.......................................................................
7668 * Copy the characters between the cursor and the count'th instance of
7669 * a specified character in the input line, into the cut buffer.
7670 *
7671 * Input:
7672 * gl GetLine * The getline resource object.
7673 * count int The number of times to search.
7674 * c char The character to be searched for, or '\0' if
7675 * the character should be read from the user.
7676 * forward int True if searching forward.
7677 * onto int True if the search should end on top of the
7678 * character, false if the search should stop
7679 * one character before the character in the
7680 * specified search direction.
7681 * Output:
7682 * return int 0 - OK.
7683 * 1 - Error.
7684 *
7685 */
gl_copy_find(GetLine * gl,int count,char c,int forward,int onto)7686 static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto)
7687 {
7688 int n; /* The number of characters in the cut buffer */
7689 /*
7690 * Search for the character, and abort the operation if not found.
7691 */
7692 int pos = gl_find_char(gl, count, forward, onto, c);
7693 if(pos < 0)
7694 return 0;
7695 /*
7696 * Copy the specified segment.
7697 */
7698 if(forward) {
7699 n = pos + 1 - gl->buff_curpos;
7700 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, n);
7701 } else {
7702 n = gl->buff_curpos - pos;
7703 memcpy(gl->cutbuf, gl->line + pos, n);
7704 if(gl->editor == GL_VI_MODE)
7705 gl_place_cursor(gl, pos);
7706 }
7707 /*
7708 * Terminate the copy.
7709 */
7710 gl->cutbuf[n] = '\0';
7711 return 0;
7712 }
7713
7714 /*.......................................................................
7715 * Copy a section up to and including a specified character into the cut
7716 * buffer without moving the cursor or deleting text.
7717 */
KT_KEY_FN(gl_forward_copy_find)7718 static KT_KEY_FN(gl_forward_copy_find)
7719 {
7720 return gl_copy_find(gl, count, '\0', 1, 1);
7721 }
7722
7723 /*.......................................................................
7724 * Copy a section back to and including a specified character into the cut
7725 * buffer without moving the cursor or deleting text.
7726 */
KT_KEY_FN(gl_backward_copy_find)7727 static KT_KEY_FN(gl_backward_copy_find)
7728 {
7729 return gl_copy_find(gl, count, '\0', 0, 1);
7730 }
7731
7732 /*.......................................................................
7733 * Copy a section up to and not including a specified character into the cut
7734 * buffer without moving the cursor or deleting text.
7735 */
KT_KEY_FN(gl_forward_copy_to)7736 static KT_KEY_FN(gl_forward_copy_to)
7737 {
7738 return gl_copy_find(gl, count, '\0', 1, 0);
7739 }
7740
7741 /*.......................................................................
7742 * Copy a section back to and not including a specified character into the cut
7743 * buffer without moving the cursor or deleting text.
7744 */
KT_KEY_FN(gl_backward_copy_to)7745 static KT_KEY_FN(gl_backward_copy_to)
7746 {
7747 return gl_copy_find(gl, count, '\0', 0, 0);
7748 }
7749
7750 /*.......................................................................
7751 * Copy to a character specified in a previous search into the cut
7752 * buffer without moving the cursor or deleting text.
7753 */
KT_KEY_FN(gl_copy_refind)7754 static KT_KEY_FN(gl_copy_refind)
7755 {
7756 return gl_copy_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
7757 gl->vi.find_onto);
7758 }
7759
7760 /*.......................................................................
7761 * Copy to a character specified in a previous search, but in the opposite
7762 * direction, into the cut buffer without moving the cursor or deleting text.
7763 */
KT_KEY_FN(gl_copy_invert_refind)7764 static KT_KEY_FN(gl_copy_invert_refind)
7765 {
7766 return gl_copy_find(gl, count, gl->vi.find_char, !gl->vi.find_forward,
7767 gl->vi.find_onto);
7768 }
7769
7770 /*.......................................................................
7771 * Set the position of the cursor in the line input buffer and the
7772 * terminal.
7773 *
7774 * Input:
7775 * gl GetLine * The getline resource object.
7776 * buff_curpos int The new buffer cursor position.
7777 * Output:
7778 * return int 0 - OK.
7779 * 1 - Error.
7780 */
gl_place_cursor(GetLine * gl,int buff_curpos)7781 static int gl_place_cursor(GetLine *gl, int buff_curpos)
7782 {
7783 /*
7784 * Don't allow the cursor position to go out of the bounds of the input
7785 * line.
7786 */
7787 if(buff_curpos >= gl->ntotal)
7788 buff_curpos = gl->vi.command ? gl->ntotal-1 : gl->ntotal;
7789 if(buff_curpos < 0)
7790 buff_curpos = 0;
7791 /*
7792 * Record the new buffer position.
7793 */
7794 gl->buff_curpos = buff_curpos;
7795 /*
7796 * Move the terminal cursor to the corresponding character.
7797 */
7798 return gl_set_term_curpos(gl, gl->prompt_len +
7799 gl_displayed_string_width(gl, gl->line, buff_curpos, gl->prompt_len));
7800 }
7801
7802 /*.......................................................................
7803 * In vi command mode, this function saves the current line to the
7804 * historical buffer needed by the undo command. In emacs mode it does
7805 * nothing. In order to allow action functions to call other action
7806 * functions, gl_interpret_char() sets gl->vi.undo.saved to 0 before
7807 * invoking an action, and thereafter once any call to this function
7808 * has set it to 1, further calls are ignored.
7809 *
7810 * Input:
7811 * gl GetLine * The getline resource object.
7812 */
gl_save_for_undo(GetLine * gl)7813 static void gl_save_for_undo(GetLine *gl)
7814 {
7815 if(gl->vi.command && !gl->vi.undo.saved) {
7816 strcpy(gl->vi.undo.line, gl->line);
7817 gl->vi.undo.buff_curpos = gl->buff_curpos;
7818 gl->vi.undo.ntotal = gl->ntotal;
7819 gl->vi.undo.saved = 1;
7820 };
7821 if(gl->vi.command && !gl->vi.repeat.saved &&
7822 gl->current_action.fn != gl_vi_repeat_change) {
7823 gl->vi.repeat.action = gl->current_action;
7824 gl->vi.repeat.count = gl->current_count;
7825 gl->vi.repeat.saved = 1;
7826 };
7827 return;
7828 }
7829
7830 /*.......................................................................
7831 * In vi mode, restore the line to the way it was before the last command
7832 * mode operation, storing the current line in the buffer so that the
7833 * undo operation itself can subsequently be undone.
7834 */
KT_KEY_FN(gl_vi_undo)7835 static KT_KEY_FN(gl_vi_undo)
7836 {
7837 /*
7838 * Get pointers into the two lines.
7839 */
7840 char *undo_ptr = gl->vi.undo.line;
7841 char *line_ptr = gl->line;
7842 /*
7843 * Swap the characters of the two buffers up to the length of the shortest
7844 * line.
7845 */
7846 while(*undo_ptr && *line_ptr) {
7847 char c = *undo_ptr;
7848 *undo_ptr++ = *line_ptr;
7849 *line_ptr++ = c;
7850 };
7851 /*
7852 * Copy the rest directly.
7853 */
7854 if(gl->ntotal > gl->vi.undo.ntotal) {
7855 strcpy(undo_ptr, line_ptr);
7856 *line_ptr = '\0';
7857 } else {
7858 strcpy(line_ptr, undo_ptr);
7859 *undo_ptr = '\0';
7860 };
7861 /*
7862 * Record the length of the stored string.
7863 */
7864 gl->vi.undo.ntotal = gl->ntotal;
7865 /*
7866 * Accomodate the new contents of gl->line[].
7867 */
7868 gl_update_buffer(gl);
7869 /*
7870 * Set both cursor positions to the leftmost of the saved and current
7871 * cursor positions to emulate what vi does.
7872 */
7873 if(gl->buff_curpos < gl->vi.undo.buff_curpos)
7874 gl->vi.undo.buff_curpos = gl->buff_curpos;
7875 else
7876 gl->buff_curpos = gl->vi.undo.buff_curpos;
7877 /*
7878 * Since we have bipassed calling gl_save_for_undo(), record repeat
7879 * information inline.
7880 */
7881 gl->vi.repeat.action.fn = gl_vi_undo;
7882 gl->vi.repeat.action.data = NULL;
7883 gl->vi.repeat.count = 1;
7884 /*
7885 * Display the restored line.
7886 */
7887 gl_queue_redisplay(gl);
7888 return 0;
7889 }
7890
7891 /*.......................................................................
7892 * Delete the following word and leave the user in vi insert mode.
7893 */
KT_KEY_FN(gl_vi_forward_change_word)7894 static KT_KEY_FN(gl_vi_forward_change_word)
7895 {
7896 gl_save_for_undo(gl);
7897 gl->vi.command = 0; /* Allow cursor at EOL */
7898 return gl_forward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
7899 }
7900
7901 /*.......................................................................
7902 * Delete the preceding word and leave the user in vi insert mode.
7903 */
KT_KEY_FN(gl_vi_backward_change_word)7904 static KT_KEY_FN(gl_vi_backward_change_word)
7905 {
7906 return gl_backward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
7907 }
7908
7909 /*.......................................................................
7910 * Delete the following section and leave the user in vi insert mode.
7911 */
KT_KEY_FN(gl_vi_forward_change_find)7912 static KT_KEY_FN(gl_vi_forward_change_find)
7913 {
7914 return gl_delete_find(gl, count, '\0', 1, 1, 1);
7915 }
7916
7917 /*.......................................................................
7918 * Delete the preceding section and leave the user in vi insert mode.
7919 */
KT_KEY_FN(gl_vi_backward_change_find)7920 static KT_KEY_FN(gl_vi_backward_change_find)
7921 {
7922 return gl_delete_find(gl, count, '\0', 0, 1, 1);
7923 }
7924
7925 /*.......................................................................
7926 * Delete the following section and leave the user in vi insert mode.
7927 */
KT_KEY_FN(gl_vi_forward_change_to)7928 static KT_KEY_FN(gl_vi_forward_change_to)
7929 {
7930 return gl_delete_find(gl, count, '\0', 1, 0, 1);
7931 }
7932
7933 /*.......................................................................
7934 * Delete the preceding section and leave the user in vi insert mode.
7935 */
KT_KEY_FN(gl_vi_backward_change_to)7936 static KT_KEY_FN(gl_vi_backward_change_to)
7937 {
7938 return gl_delete_find(gl, count, '\0', 0, 0, 1);
7939 }
7940
7941 /*.......................................................................
7942 * Delete to a character specified by a previous search and leave the user
7943 * in vi insert mode.
7944 */
KT_KEY_FN(gl_vi_change_refind)7945 static KT_KEY_FN(gl_vi_change_refind)
7946 {
7947 return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
7948 gl->vi.find_onto, 1);
7949 }
7950
7951 /*.......................................................................
7952 * Delete to a character specified by a previous search, but in the opposite
7953 * direction, and leave the user in vi insert mode.
7954 */
KT_KEY_FN(gl_vi_change_invert_refind)7955 static KT_KEY_FN(gl_vi_change_invert_refind)
7956 {
7957 return gl_delete_find(gl, count, gl->vi.find_char, !gl->vi.find_forward,
7958 gl->vi.find_onto, 1);
7959 }
7960
7961 /*.......................................................................
7962 * Delete the following character and leave the user in vi insert mode.
7963 */
KT_KEY_FN(gl_vi_forward_change_char)7964 static KT_KEY_FN(gl_vi_forward_change_char)
7965 {
7966 gl_save_for_undo(gl);
7967 gl->vi.command = 0; /* Allow cursor at EOL */
7968 return gl_delete_chars(gl, count, 1) || gl_vi_insert(gl, 0, NULL);
7969 }
7970
7971 /*.......................................................................
7972 * Delete the preceding character and leave the user in vi insert mode.
7973 */
KT_KEY_FN(gl_vi_backward_change_char)7974 static KT_KEY_FN(gl_vi_backward_change_char)
7975 {
7976 return gl_backward_delete_char(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
7977 }
7978
7979 /*.......................................................................
7980 * Starting from the cursor position change characters to the specified column.
7981 */
KT_KEY_FN(gl_vi_change_to_column)7982 static KT_KEY_FN(gl_vi_change_to_column)
7983 {
7984 if (--count >= gl->buff_curpos)
7985 return gl_vi_forward_change_char(gl, count - gl->buff_curpos, NULL);
7986 else
7987 return gl_vi_backward_change_char(gl, gl->buff_curpos - count, NULL);
7988 }
7989
7990 /*.......................................................................
7991 * Starting from the cursor position change characters to a matching
7992 * parenthesis.
7993 */
KT_KEY_FN(gl_vi_change_to_parenthesis)7994 static KT_KEY_FN(gl_vi_change_to_parenthesis)
7995 {
7996 int curpos = gl_index_of_matching_paren(gl);
7997 if(curpos >= 0) {
7998 gl_save_for_undo(gl);
7999 if(curpos >= gl->buff_curpos)
8000 return gl_vi_forward_change_char(gl, curpos - gl->buff_curpos + 1, NULL);
8001 else
8002 return gl_vi_backward_change_char(gl, ++gl->buff_curpos - curpos + 1,
8003 NULL);
8004 };
8005 return 0;
8006 }
8007
8008 /*.......................................................................
8009 * If in vi mode, switch to vi command mode.
8010 *
8011 * Input:
8012 * gl GetLine * The getline resource object.
8013 */
gl_vi_command_mode(GetLine * gl)8014 static void gl_vi_command_mode(GetLine *gl)
8015 {
8016 if(gl->editor == GL_VI_MODE && !gl->vi.command) {
8017 gl->insert = 1;
8018 gl->vi.command = 1;
8019 gl->vi.repeat.input_curpos = gl->insert_curpos;
8020 gl->vi.repeat.command_curpos = gl->buff_curpos;
8021 gl->insert_curpos = 0; /* unrestrict left motion boundary */
8022 gl_cursor_left(gl, 1, NULL); /* Vi moves 1 left on entering command mode */
8023 };
8024 }
8025
8026 /*.......................................................................
8027 * This is an action function which rings the terminal bell.
8028 */
KT_KEY_FN(gl_ring_bell)8029 static KT_KEY_FN(gl_ring_bell)
8030 {
8031 return gl->silence_bell ? 0 :
8032 gl_print_control_sequence(gl, 1, gl->sound_bell);
8033 }
8034
8035 /*.......................................................................
8036 * This is the action function which implements the vi-repeat-change
8037 * action.
8038 */
KT_KEY_FN(gl_vi_repeat_change)8039 static KT_KEY_FN(gl_vi_repeat_change)
8040 {
8041 int status; /* The return status of the repeated action function */
8042 int i;
8043 /*
8044 * Nothing to repeat?
8045 */
8046 if(!gl->vi.repeat.action.fn)
8047 return gl_ring_bell(gl, 1, NULL);
8048 /*
8049 * Provide a way for action functions to know whether they are being
8050 * called by us.
8051 */
8052 gl->vi.repeat.active = 1;
8053 /*
8054 * Re-run the recorded function.
8055 */
8056 status = gl->vi.repeat.action.fn(gl, gl->vi.repeat.count,
8057 gl->vi.repeat.action.data);
8058 /*
8059 * Mark the repeat as completed.
8060 */
8061 gl->vi.repeat.active = 0;
8062 /*
8063 * Is we are repeating a function that has just switched to input
8064 * mode to allow the user to type, re-enter the text that the user
8065 * previously entered.
8066 */
8067 if(status==0 && !gl->vi.command) {
8068 /*
8069 * Make sure that the current line has been saved.
8070 */
8071 gl_save_for_undo(gl);
8072 /*
8073 * Repeat a previous insertion or overwrite?
8074 */
8075 if(gl->vi.repeat.input_curpos >= 0 &&
8076 gl->vi.repeat.input_curpos <= gl->vi.repeat.command_curpos &&
8077 gl->vi.repeat.command_curpos <= gl->vi.undo.ntotal) {
8078 /*
8079 * Using the current line which is saved in the undo buffer, plus
8080 * the range of characters therein, as recorded by gl_vi_command_mode(),
8081 * add the characters that the user previously entered, to the input
8082 * line.
8083 */
8084 for(i=gl->vi.repeat.input_curpos; i<gl->vi.repeat.command_curpos; i++) {
8085 if(gl_add_char_to_line(gl, gl->vi.undo.line[i]))
8086 return 1;
8087 };
8088 };
8089 /*
8090 * Switch back to command mode, now that the insertion has been repeated.
8091 */
8092 gl_vi_command_mode(gl);
8093 };
8094 return status;
8095 }
8096
8097 /*.......................................................................
8098 * If the cursor is currently over a parenthesis character, return the
8099 * index of its matching parenthesis. If not currently over a parenthesis
8100 * character, return the next close parenthesis character to the right of
8101 * the cursor. If the respective parenthesis character isn't found,
8102 * ring the terminal bell and return -1.
8103 *
8104 * Input:
8105 * gl GetLine * The getline resource object.
8106 * Output:
8107 * return int Either the index of the matching parenthesis,
8108 * or -1 if not found.
8109 */
gl_index_of_matching_paren(GetLine * gl)8110 static int gl_index_of_matching_paren(GetLine *gl)
8111 {
8112 int i;
8113 /*
8114 * List the recognized parentheses, and their matches.
8115 */
8116 const char *o_paren = "([{";
8117 const char *c_paren = ")]}";
8118 const char *cptr;
8119 /*
8120 * Get the character that is currently under the cursor.
8121 */
8122 char c = gl->line[gl->buff_curpos];
8123 /*
8124 * If the character under the cursor is an open parenthesis, look forward
8125 * for the matching close parenthesis.
8126 */
8127 if((cptr=strchr(o_paren, c))) {
8128 char match = c_paren[cptr - o_paren];
8129 int matches_needed = 1;
8130 for(i=gl->buff_curpos+1; i<gl->ntotal; i++) {
8131 if(gl->line[i] == c)
8132 matches_needed++;
8133 else if(gl->line[i] == match && --matches_needed==0)
8134 return i;
8135 };
8136 /*
8137 * If the character under the cursor is an close parenthesis, look forward
8138 * for the matching open parenthesis.
8139 */
8140 } else if((cptr=strchr(c_paren, c))) {
8141 char match = o_paren[cptr - c_paren];
8142 int matches_needed = 1;
8143 for(i=gl->buff_curpos-1; i>=0; i--) {
8144 if(gl->line[i] == c)
8145 matches_needed++;
8146 else if(gl->line[i] == match && --matches_needed==0)
8147 return i;
8148 };
8149 /*
8150 * If not currently over a parenthesis character, search forwards for
8151 * the first close parenthesis (this is what the vi % binding does).
8152 */
8153 } else {
8154 for(i=gl->buff_curpos+1; i<gl->ntotal; i++)
8155 if(strchr(c_paren, gl->line[i]) != NULL)
8156 return i;
8157 };
8158 /*
8159 * Not found.
8160 */
8161 (void) gl_ring_bell(gl, 1, NULL);
8162 return -1;
8163 }
8164
8165 /*.......................................................................
8166 * If the cursor is currently over a parenthesis character, this action
8167 * function moves the cursor to its matching parenthesis.
8168 */
KT_KEY_FN(gl_find_parenthesis)8169 static KT_KEY_FN(gl_find_parenthesis)
8170 {
8171 int curpos = gl_index_of_matching_paren(gl);
8172 if(curpos >= 0)
8173 return gl_place_cursor(gl, curpos);
8174 return 0;
8175 }
8176
8177 /*.......................................................................
8178 * Handle the receipt of the potential start of a new key-sequence from
8179 * the user.
8180 *
8181 * Input:
8182 * gl GetLine * The resource object of this library.
8183 * first_char char The first character of the sequence.
8184 * Output:
8185 * return int 0 - OK.
8186 * 1 - Error.
8187 */
gl_interpret_char(GetLine * gl,char first_char)8188 static int gl_interpret_char(GetLine *gl, char first_char)
8189 {
8190 char keyseq[GL_KEY_MAX+1]; /* A special key sequence being read */
8191 int nkey=0; /* The number of characters in the key sequence */
8192 int count; /* The repeat count of an action function */
8193 int ret; /* The return value of an action function */
8194 int i;
8195 /*
8196 * Get the first character.
8197 */
8198 char c = first_char;
8199 /*
8200 * If editing is disabled, just add newly entered characters to the
8201 * input line buffer, and watch for the end of the line.
8202 */
8203 if(gl->editor == GL_NO_EDITOR) {
8204 gl_discard_chars(gl, 1);
8205 if(gl->ntotal >= gl->linelen)
8206 return 0;
8207 if(c == '\n' || c == '\r')
8208 return gl_newline(gl, 1, NULL);
8209 gl_buffer_char(gl, c, gl->ntotal);
8210 return 0;
8211 };
8212 /*
8213 * If the user is in the process of specifying a repeat count and the
8214 * new character is a digit, increment the repeat count accordingly.
8215 */
8216 if(gl->number >= 0 && isdigit((int)(unsigned char) c)) {
8217 gl_discard_chars(gl, 1);
8218 return gl_digit_argument(gl, c, NULL);
8219 /*
8220 * In vi command mode, all key-sequences entered need to be
8221 * either implicitly or explicitly prefixed with an escape character.
8222 */
8223 } else if(gl->vi.command && c != GL_ESC_CHAR) {
8224 keyseq[nkey++] = GL_ESC_CHAR;
8225 /*
8226 * If the first character of the sequence is a printable character,
8227 * then to avoid confusion with the special "up", "down", "left"
8228 * or "right" cursor key bindings, we need to prefix the
8229 * printable character with a backslash escape before looking it up.
8230 */
8231 } else if(!IS_META_CHAR(c) && !IS_CTRL_CHAR(c)) {
8232 keyseq[nkey++] = '\\';
8233 };
8234 /*
8235 * Compose a potentially multiple key-sequence in gl->keyseq.
8236 */
8237 while(nkey < GL_KEY_MAX) {
8238 KtAction *action; /* An action function */
8239 KeySym *keysym; /* The symbol-table entry of a key-sequence */
8240 int nsym; /* The number of ambiguously matching key-sequences */
8241 /*
8242 * If the character is an unprintable meta character, split it
8243 * into two characters, an escape character and the character
8244 * that was modified by the meta key.
8245 */
8246 if(IS_META_CHAR(c)) {
8247 keyseq[nkey++] = GL_ESC_CHAR;
8248 c = META_TO_CHAR(c);
8249 continue;
8250 };
8251 /*
8252 * Append the latest character to the key sequence.
8253 */
8254 keyseq[nkey++] = c;
8255 /*
8256 * When doing vi-style editing, an escape at the beginning of any binding
8257 * switches to command mode.
8258 */
8259 if(keyseq[0] == GL_ESC_CHAR && !gl->vi.command)
8260 gl_vi_command_mode(gl);
8261 /*
8262 * Lookup the key sequence.
8263 */
8264 switch(_kt_lookup_keybinding(gl->bindings, keyseq, nkey, &keysym, &nsym)) {
8265 case KT_EXACT_MATCH:
8266 /*
8267 * Get the matching action function.
8268 */
8269 action = keysym->actions + keysym->binder;
8270 /*
8271 * Get the repeat count, passing the last keystroke if executing the
8272 * digit-argument action.
8273 */
8274 if(action->fn == gl_digit_argument) {
8275 count = c;
8276 } else {
8277 count = gl->number >= 0 ? gl->number : 1;
8278 };
8279 /*
8280 * Record the function that is being invoked.
8281 */
8282 gl->current_action = *action;
8283 gl->current_count = count;
8284 /*
8285 * Mark the current line as not yet preserved for use by the vi undo command.
8286 */
8287 gl->vi.undo.saved = 0;
8288 gl->vi.repeat.saved = 0;
8289 /*
8290 * Execute the action function. Note the action function can tell
8291 * whether the provided repeat count was defaulted or specified
8292 * explicitly by looking at whether gl->number is -1 or not. If
8293 * it is negative, then no repeat count was specified by the user.
8294 */
8295 ret = action->fn(gl, count, action->data);
8296 /*
8297 * In server mode, the action will return immediately if it tries to
8298 * read input from the terminal, and no input is currently available.
8299 * If this happens, abort. Note that gl_get_input_line() will rewind
8300 * the read-ahead buffer to allow the next call to redo the function
8301 * from scratch.
8302 */
8303 if(gl->rtn_status == GLR_BLOCKED && gl->pending_io==GLP_READ)
8304 return 1;
8305 /*
8306 * Discard the now processed characters from the key sequence buffer.
8307 */
8308 gl_discard_chars(gl, gl->nread);
8309 /*
8310 * If the latest action function wasn't a history action, cancel any
8311 * current history search.
8312 */
8313 if(gl->last_search != gl->keyseq_count)
8314 _glh_cancel_search(gl->glh);
8315 /*
8316 * Reset the repeat count after running action functions.
8317 */
8318 if(action->fn != gl_digit_argument)
8319 gl->number = -1;
8320 return ret ? 1 : 0;
8321 break;
8322 case KT_AMBIG_MATCH: /* Ambiguous match - so read the next character */
8323 if(gl_read_terminal(gl, 1, &c))
8324 return 1;
8325 break;
8326 case KT_NO_MATCH:
8327 /*
8328 * If the first character looked like it might be a prefix of a key-sequence
8329 * but it turned out not to be, ring the bell to tell the user that it
8330 * wasn't recognised.
8331 */
8332 if(keyseq[0] != '\\' && keyseq[0] != '\t') {
8333 gl_ring_bell(gl, 1, NULL);
8334 } else {
8335 /*
8336 * The user typed a single printable character that doesn't match
8337 * the start of any keysequence, so add it to the line in accordance
8338 * with the current repeat count.
8339 */
8340 count = gl->number >= 0 ? gl->number : 1;
8341 for(i=0; i<count; i++)
8342 gl_add_char_to_line(gl, first_char);
8343 gl->number = -1;
8344 };
8345 gl_discard_chars(gl, 1);
8346 _glh_cancel_search(gl->glh);
8347 return 0;
8348 break;
8349 case KT_BAD_MATCH:
8350 gl_ring_bell(gl, 1, NULL);
8351 gl_discard_chars(gl, gl->nread);
8352 _glh_cancel_search(gl->glh);
8353 return 1;
8354 break;
8355 };
8356 };
8357 /*
8358 * If the key sequence was too long to match, ring the bell, then
8359 * discard the first character, so that the next attempt to match a
8360 * key-sequence continues with the next key press. In practice this
8361 * shouldn't happen, since one isn't allowed to bind action functions
8362 * to keysequences that are longer than GL_KEY_MAX.
8363 */
8364 gl_ring_bell(gl, 1, NULL);
8365 gl_discard_chars(gl, 1);
8366 return 0;
8367 }
8368
8369 /*.......................................................................
8370 * Configure the application and/or user-specific behavior of
8371 * gl_get_line().
8372 *
8373 * Note that calling this function between calling new_GetLine() and
8374 * the first call to gl_get_line(), disables the otherwise automatic
8375 * reading of ~/.teclarc on the first call to gl_get_line().
8376 *
8377 * Input:
8378 * gl GetLine * The resource object of this library.
8379 * app_string const char * Either NULL, or a string containing one
8380 * or more .teclarc command lines, separated
8381 * by newline characters. This can be used to
8382 * establish an application-specific
8383 * configuration, without the need for an external
8384 * file. This is particularly useful in embedded
8385 * environments where there is no filesystem.
8386 * app_file const char * Either NULL, or the pathname of an
8387 * application-specific .teclarc file. The
8388 * contents of this file, if provided, are
8389 * read after the contents of app_string[].
8390 * user_file const char * Either NULL, or the pathname of a
8391 * user-specific .teclarc file. Except in
8392 * embedded applications, this should
8393 * usually be "~/.teclarc".
8394 * Output:
8395 * return int 0 - OK.
8396 * 1 - Bad argument(s).
8397 */
gl_configure_getline(GetLine * gl,const char * app_string,const char * app_file,const char * user_file)8398 int gl_configure_getline(GetLine *gl, const char *app_string,
8399 const char *app_file, const char *user_file)
8400 {
8401 sigset_t oldset; /* The signals that were blocked on entry to this function */
8402 int status; /* The return status of _gl_configure_getline() */
8403 /*
8404 * Check the arguments.
8405 */
8406 if(!gl) {
8407 errno = EINVAL;
8408 return 1;
8409 };
8410 /*
8411 * Block all signals.
8412 */
8413 if(gl_mask_signals(gl, &oldset))
8414 return 1;
8415 /*
8416 * Execute the private body of the function while signals are blocked.
8417 */
8418 status = _gl_configure_getline(gl, app_string, app_file, user_file);
8419 /*
8420 * Restore the process signal mask.
8421 */
8422 gl_unmask_signals(gl, &oldset);
8423 return status;
8424 }
8425
8426 /*.......................................................................
8427 * This is the private body of the gl_configure_getline() function. It
8428 * assumes that the caller has checked its arguments and blocked the
8429 * delivery of signals.
8430 */
_gl_configure_getline(GetLine * gl,const char * app_string,const char * app_file,const char * user_file)8431 static int _gl_configure_getline(GetLine *gl, const char *app_string,
8432 const char *app_file, const char *user_file)
8433 {
8434 /*
8435 * Mark getline as having been explicitly configured.
8436 */
8437 gl->configured = 1;
8438 /*
8439 * Start by parsing the configuration string, if provided.
8440 */
8441 if(app_string)
8442 (void) _gl_read_config_string(gl, app_string, KTB_NORM);
8443 /*
8444 * Now parse the application-specific configuration file, if provided.
8445 */
8446 if(app_file)
8447 (void) _gl_read_config_file(gl, app_file, KTB_NORM);
8448 /*
8449 * Finally, parse the user-specific configuration file, if provided.
8450 */
8451 if(user_file)
8452 (void) _gl_read_config_file(gl, user_file, KTB_USER);
8453 /*
8454 * Record the names of the configuration files to allow them to
8455 * be re-read if requested at a later time.
8456 */
8457 if(gl_record_string(&gl->app_file, app_file) ||
8458 gl_record_string(&gl->user_file, user_file)) {
8459 errno = ENOMEM;
8460 _err_record_msg(gl->err,
8461 "Insufficient memory to record tecla configuration file names",
8462 END_ERR_MSG);
8463 return 1;
8464 };
8465 return 0;
8466 }
8467
8468 /*.......................................................................
8469 * Replace a malloc'd string (or NULL), with another malloc'd copy of
8470 * a string (or NULL).
8471 *
8472 * Input:
8473 * sptr char ** On input if *sptr!=NULL, *sptr will be
8474 * free'd and *sptr will be set to NULL. Then,
8475 * on output, if string!=NULL a malloc'd copy
8476 * of this string will be assigned to *sptr.
8477 * string const char * The string to be copied, or NULL to simply
8478 * discard any existing string.
8479 * Output:
8480 * return int 0 - OK.
8481 * 1 - Malloc failure (no error message is generated).
8482 */
gl_record_string(char ** sptr,const char * string)8483 static int gl_record_string(char **sptr, const char *string)
8484 {
8485 /*
8486 * If the original string is the same string, don't do anything.
8487 */
8488 if(*sptr == string || (*sptr && string && strcmp(*sptr, string)==0))
8489 return 0;
8490 /*
8491 * Discard any existing cached string.
8492 */
8493 if(*sptr) {
8494 free(*sptr);
8495 *sptr = NULL;
8496 };
8497 /*
8498 * Allocate memory for a copy of the specified string.
8499 */
8500 if(string) {
8501 *sptr = (char *) malloc(strlen(string) + 1);
8502 if(!*sptr)
8503 return 1;
8504 /*
8505 * Copy the string.
8506 */
8507 strcpy(*sptr, string);
8508 };
8509 return 0;
8510 }
8511
8512 #ifndef HIDE_FILE_SYSTEM
8513 /*.......................................................................
8514 * Re-read any application-specific and user-specific files previously
8515 * specified via the gl_configure_getline() function.
8516 */
KT_KEY_FN(gl_read_init_files)8517 static KT_KEY_FN(gl_read_init_files)
8518 {
8519 return _gl_configure_getline(gl, NULL, gl->app_file, gl->user_file);
8520 }
8521 #endif
8522
8523 /*.......................................................................
8524 * Save the contents of the history buffer to a given new file.
8525 *
8526 * Input:
8527 * gl GetLine * The resource object of this library.
8528 * filename const char * The name of the new file to write to.
8529 * comment const char * Extra information such as timestamps will
8530 * be recorded on a line started with this
8531 * string, the idea being that the file can
8532 * double as a command file. Specify "" if
8533 * you don't care.
8534 * max_lines int The maximum number of lines to save, or -1
8535 * to save all of the lines in the history
8536 * list.
8537 * Output:
8538 * return int 0 - OK.
8539 * 1 - Error.
8540 */
gl_save_history(GetLine * gl,const char * filename,const char * comment,int max_lines)8541 int gl_save_history(GetLine *gl, const char *filename, const char *comment,
8542 int max_lines)
8543 {
8544 sigset_t oldset; /* The signals that were blocked on entry to this function */
8545 int status; /* The return status of _gl_save_history() */
8546 /*
8547 * Check the arguments.
8548 */
8549 if(!gl || !filename || !comment) {
8550 if(gl)
8551 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
8552 errno = EINVAL;
8553 return 1;
8554 };
8555 /*
8556 * Block all signals.
8557 */
8558 if(gl_mask_signals(gl, &oldset))
8559 return 1;
8560 /*
8561 * Execute the private body of the function while signals are blocked.
8562 */
8563 status = _gl_save_history(gl, filename, comment, max_lines);
8564 /*
8565 * Restore the process signal mask.
8566 */
8567 gl_unmask_signals(gl, &oldset);
8568 return status;
8569 }
8570
8571 /*.......................................................................
8572 * This is the private body of the gl_save_history() function. It
8573 * assumes that the caller has checked its arguments and blocked the
8574 * delivery of signals.
8575 */
_gl_save_history(GetLine * gl,const char * filename,const char * comment,int max_lines)8576 static int _gl_save_history(GetLine *gl, const char *filename,
8577 const char *comment, int max_lines)
8578 {
8579 /*
8580 * If filesystem access is to be excluded, then history files can't
8581 * be written.
8582 */
8583 #ifdef WITHOUT_FILE_SYSTEM
8584 _err_record_msg(gl->err, "Can't save history without filesystem access",
8585 END_ERR_MSG);
8586 errno = EINVAL;
8587 return 1;
8588 #else
8589 FileExpansion *expansion; /* The expansion of the filename */
8590 /*
8591 * Expand the filename.
8592 */
8593 expansion = ef_expand_file(gl->ef, filename, -1);
8594 if(!expansion) {
8595 gl_print_info(gl, "Unable to expand ", filename, " (",
8596 ef_last_error(gl->ef), ").", GL_END_INFO);
8597 return 1;
8598 };
8599 /*
8600 * Attempt to save to the specified file.
8601 */
8602 if(_glh_save_history(gl->glh, expansion->files[0], comment, max_lines)) {
8603 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
8604 return 1;
8605 };
8606 return 0;
8607 #endif
8608 }
8609
8610 /*.......................................................................
8611 * Restore the contents of the history buffer from a given new file.
8612 *
8613 * Input:
8614 * gl GetLine * The resource object of this library.
8615 * filename const char * The name of the new file to write to.
8616 * comment const char * This must be the same string that was
8617 * passed to gl_save_history() when the file
8618 * was written.
8619 * Output:
8620 * return int 0 - OK.
8621 * 1 - Error.
8622 */
gl_load_history(GetLine * gl,const char * filename,const char * comment)8623 int gl_load_history(GetLine *gl, const char *filename, const char *comment)
8624 {
8625 sigset_t oldset; /* The signals that were blocked on entry to this function */
8626 int status; /* The return status of _gl_load_history() */
8627 /*
8628 * Check the arguments.
8629 */
8630 if(!gl || !filename || !comment) {
8631 if(gl)
8632 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
8633 errno = EINVAL;
8634 return 1;
8635 };
8636 /*
8637 * Block all signals.
8638 */
8639 if(gl_mask_signals(gl, &oldset))
8640 return 1;
8641 /*
8642 * Execute the private body of the function while signals are blocked.
8643 */
8644 status = _gl_load_history(gl, filename, comment);
8645 /*
8646 * Restore the process signal mask.
8647 */
8648 gl_unmask_signals(gl, &oldset);
8649 return status;
8650 }
8651
8652 /*.......................................................................
8653 * This is the private body of the gl_load_history() function. It
8654 * assumes that the caller has checked its arguments and blocked the
8655 * delivery of signals.
8656 */
_gl_load_history(GetLine * gl,const char * filename,const char * comment)8657 static int _gl_load_history(GetLine *gl, const char *filename,
8658 const char *comment)
8659 {
8660 /*
8661 * If filesystem access is to be excluded, then history files can't
8662 * be read.
8663 */
8664 #ifdef WITHOUT_FILE_SYSTEM
8665 _err_record_msg(gl->err, "Can't load history without filesystem access",
8666 END_ERR_MSG);
8667 errno = EINVAL;
8668 return 1;
8669 #else
8670 FileExpansion *expansion; /* The expansion of the filename */
8671 /*
8672 * Expand the filename.
8673 */
8674 expansion = ef_expand_file(gl->ef, filename, -1);
8675 if(!expansion) {
8676 gl_print_info(gl, "Unable to expand ", filename, " (",
8677 ef_last_error(gl->ef), ").", GL_END_INFO);
8678 return 1;
8679 };
8680 /*
8681 * Attempt to load from the specified file.
8682 */
8683 if(_glh_load_history(gl->glh, expansion->files[0], comment,
8684 gl->cutbuf, gl->linelen+1)) {
8685 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
8686 gl->cutbuf[0] = '\0';
8687 return 1;
8688 };
8689 gl->cutbuf[0] = '\0';
8690 return 0;
8691 #endif
8692 }
8693
8694 /*.......................................................................
8695 * Where possible, register a function and associated data to be called
8696 * whenever a specified event is seen on a file descriptor.
8697 *
8698 * Input:
8699 * gl GetLine * The resource object of the command-line input
8700 * module.
8701 * fd int The file descriptor to watch.
8702 * event GlFdEvent The type of activity to watch for.
8703 * callback GlFdEventFn * The function to call when the specified
8704 * event occurs. Setting this to 0 removes
8705 * any existing callback.
8706 * data void * A pointer to arbitrary data to pass to the
8707 * callback function.
8708 * Output:
8709 * return int 0 - OK.
8710 * 1 - Either gl==NULL, or this facility isn't
8711 * available on the the host system
8712 * (ie. select() isn't available). No
8713 * error message is generated in the latter
8714 * case.
8715 */
gl_watch_fd(GetLine * gl,int fd,GlFdEvent event,GlFdEventFn * callback,void * data)8716 int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
8717 GlFdEventFn *callback, void *data)
8718 {
8719 sigset_t oldset; /* The signals that were blocked on entry to this function */
8720 int status; /* The return status of _gl_watch_fd() */
8721 /*
8722 * Check the arguments.
8723 */
8724 if(!gl) {
8725 errno = EINVAL;
8726 return 1;
8727 };
8728 if(fd < 0) {
8729 _err_record_msg(gl->err, "Error: fd < 0", END_ERR_MSG);
8730 errno = EINVAL;
8731 return 1;
8732 };
8733 /*
8734 * Block all signals.
8735 */
8736 if(gl_mask_signals(gl, &oldset))
8737 return 1;
8738 /*
8739 * Execute the private body of the function while signals are blocked.
8740 */
8741 status = _gl_watch_fd(gl, fd, event, callback, data);
8742 /*
8743 * Restore the process signal mask.
8744 */
8745 gl_unmask_signals(gl, &oldset);
8746 return status;
8747 }
8748
8749 /*.......................................................................
8750 * This is the private body of the gl_watch_fd() function. It
8751 * assumes that the caller has checked its arguments and blocked the
8752 * delivery of signals.
8753 */
_gl_watch_fd(GetLine * gl,int fd,GlFdEvent event,GlFdEventFn * callback,void * data)8754 static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
8755 GlFdEventFn *callback, void *data)
8756 #if !defined(HAVE_SELECT)
8757 {return 1;} /* The facility isn't supported on this system */
8758 #else
8759 {
8760 GlFdNode *prev; /* The node that precedes 'node' in gl->fd_nodes */
8761 GlFdNode *node; /* The file-descriptor node being checked */
8762 /*
8763 * Search the list of already registered fd activity nodes for the specified
8764 * file descriptor.
8765 */
8766 for(prev=NULL,node=gl->fd_nodes; node && node->fd != fd;
8767 prev=node, node=node->next)
8768 ;
8769 /*
8770 * Hasn't a node been allocated for this fd yet?
8771 */
8772 if(!node) {
8773 /*
8774 * If there is no callback to record, just ignore the call.
8775 */
8776 if(!callback)
8777 return 0;
8778 /*
8779 * Allocate the new node.
8780 */
8781 node = (GlFdNode *) _new_FreeListNode(gl->fd_node_mem);
8782 if(!node) {
8783 errno = ENOMEM;
8784 _err_record_msg(gl->err, "Insufficient memory", END_ERR_MSG);
8785 return 1;
8786 };
8787 /*
8788 * Prepend the node to the list.
8789 */
8790 node->next = gl->fd_nodes;
8791 gl->fd_nodes = node;
8792 /*
8793 * Initialize the node.
8794 */
8795 node->fd = fd;
8796 node->rd.fn = 0;
8797 node->rd.data = NULL;
8798 node->ur = node->wr = node->rd;
8799 };
8800 /*
8801 * Record the new callback.
8802 */
8803 switch(event) {
8804 case GLFD_READ:
8805 node->rd.fn = callback;
8806 node->rd.data = data;
8807 if(callback)
8808 FD_SET(fd, &gl->rfds);
8809 else
8810 FD_CLR(fd, &gl->rfds);
8811 break;
8812 case GLFD_WRITE:
8813 node->wr.fn = callback;
8814 node->wr.data = data;
8815 if(callback)
8816 FD_SET(fd, &gl->wfds);
8817 else
8818 FD_CLR(fd, &gl->wfds);
8819 break;
8820 case GLFD_URGENT:
8821 node->ur.fn = callback;
8822 node->ur.data = data;
8823 if(callback)
8824 FD_SET(fd, &gl->ufds);
8825 else
8826 FD_CLR(fd, &gl->ufds);
8827 break;
8828 };
8829 /*
8830 * Keep a record of the largest file descriptor being watched.
8831 */
8832 if(fd > gl->max_fd)
8833 gl->max_fd = fd;
8834 /*
8835 * If we are deleting an existing callback, also delete the parent
8836 * activity node if no callbacks are registered to the fd anymore.
8837 */
8838 if(!callback) {
8839 if(!node->rd.fn && !node->wr.fn && !node->ur.fn) {
8840 if(prev)
8841 prev->next = node->next;
8842 else
8843 gl->fd_nodes = node->next;
8844 node = (GlFdNode *) _del_FreeListNode(gl->fd_node_mem, node);
8845 };
8846 };
8847 return 0;
8848 }
8849 #endif
8850
8851 /*.......................................................................
8852 * On systems with the select() system call, the gl_inactivity_timeout()
8853 * function provides the option of setting (or cancelling) an
8854 * inactivity timeout. Inactivity, in this case, refers both to
8855 * terminal input received from the user, and to I/O on any file
8856 * descriptors registered by calls to gl_watch_fd(). If at any time,
8857 * no activity is seen for the requested time period, the specified
8858 * timeout callback function is called. On returning, this callback
8859 * returns a code which tells gl_get_line() what to do next. Note that
8860 * each call to gl_inactivity_timeout() replaces any previously installed
8861 * timeout callback, and that specifying a callback of 0, turns off
8862 * inactivity timing.
8863 *
8864 * Beware that although the timeout argument includes a nano-second
8865 * component, few computer clocks presently have resolutions finer
8866 * than a few milliseconds, so asking for less than a few milliseconds
8867 * is equivalent to zero on a lot of systems.
8868 *
8869 * Input:
8870 * gl GetLine * The resource object of the command-line input
8871 * module.
8872 * callback GlTimeoutFn * The function to call when the inactivity
8873 * timeout is exceeded. To turn off
8874 * inactivity timeouts altogether, send 0.
8875 * data void * A pointer to arbitrary data to pass to the
8876 * callback function.
8877 * sec unsigned long The number of whole seconds in the timeout.
8878 * nsec unsigned long The fractional number of seconds in the
8879 * timeout, expressed in nano-seconds (see
8880 * the caveat above).
8881 * Output:
8882 * return int 0 - OK.
8883 * 1 - Either gl==NULL, or this facility isn't
8884 * available on the the host system
8885 * (ie. select() isn't available). No
8886 * error message is generated in the latter
8887 * case.
8888 */
gl_inactivity_timeout(GetLine * gl,GlTimeoutFn * timeout_fn,void * data,unsigned long sec,unsigned long nsec)8889 int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *timeout_fn, void *data,
8890 unsigned long sec, unsigned long nsec)
8891 #if !defined(HAVE_SELECT)
8892 {return 1;} /* The facility isn't supported on this system */
8893 #else
8894 {
8895 sigset_t oldset; /* The signals that were blocked on entry to this function */
8896 /*
8897 * Check the arguments.
8898 */
8899 if(!gl) {
8900 errno = EINVAL;
8901 return 1;
8902 };
8903 /*
8904 * Block all signals.
8905 */
8906 if(gl_mask_signals(gl, &oldset))
8907 return 1;
8908 /*
8909 * Install a new timeout?
8910 */
8911 if(timeout_fn) {
8912 gl->timer.dt.tv_sec = sec;
8913 gl->timer.dt.tv_usec = nsec / 1000;
8914 gl->timer.fn = timeout_fn;
8915 gl->timer.data = data;
8916 } else {
8917 gl->timer.fn = 0;
8918 gl->timer.data = NULL;
8919 };
8920 /*
8921 * Restore the process signal mask.
8922 */
8923 gl_unmask_signals(gl, &oldset);
8924 return 0;
8925 }
8926 #endif
8927
8928 /*.......................................................................
8929 * When select() is available, this is a private function of
8930 * gl_read_input() which responds to file-descriptor events registered by
8931 * the caller. Note that it assumes that it is being called from within
8932 * gl_read_input()'s sigsetjump() clause.
8933 *
8934 * Input:
8935 * gl GetLine * The resource object of this module.
8936 * fd int The file descriptor to be watched for user input.
8937 * Output:
8938 * return int 0 - OK.
8939 * 1 - An error occurred.
8940 */
gl_event_handler(GetLine * gl,int fd)8941 static int gl_event_handler(GetLine *gl, int fd)
8942 #if !defined(HAVE_SELECT)
8943 {return 0;}
8944 #else
8945 {
8946 /*
8947 * Set up a zero-second timeout.
8948 */
8949 struct timeval zero;
8950 zero.tv_sec = zero.tv_usec = 0;
8951 /*
8952 * If at any time no external callbacks remain, quit the loop return,
8953 * so that we can simply wait in read(). This is designed as an
8954 * optimization for when no callbacks have been registered on entry to
8955 * this function, but since callbacks can delete themselves, it can
8956 * also help later.
8957 */
8958 while(gl->fd_nodes || gl->timer.fn) {
8959 int nready; /* The number of file descriptors that are ready for I/O */
8960 /*
8961 * Get the set of descriptors to be watched.
8962 */
8963 fd_set rfds = gl->rfds;
8964 fd_set wfds = gl->wfds;
8965 fd_set ufds = gl->ufds;
8966 /*
8967 * Get the appropriate timeout.
8968 */
8969 struct timeval dt = gl->timer.fn ? gl->timer.dt : zero;
8970 /*
8971 * Add the specified user-input file descriptor tot he set that is to
8972 * be watched.
8973 */
8974 FD_SET(fd, &rfds);
8975 /*
8976 * Unblock the signals that we are watching, while select is blocked
8977 * waiting for I/O.
8978 */
8979 gl_catch_signals(gl);
8980 /*
8981 * Wait for activity on any of the file descriptors.
8982 */
8983 nready = select(gl->max_fd+1, &rfds, &wfds, &ufds,
8984 (gl->timer.fn || gl->io_mode==GL_SERVER_MODE) ? &dt : NULL);
8985 /*
8986 * We don't want to do a longjmp in the middle of a callback that
8987 * might be modifying global or heap data, so block all the signals
8988 * that we are trapping before executing callback functions. Note that
8989 * the caller will unblock them again when it needs to, so there is
8990 * no need to undo this before returning.
8991 */
8992 gl_mask_signals(gl, NULL);
8993 /*
8994 * If select() returns but none of the file descriptors are reported
8995 * to have activity, then select() timed out.
8996 */
8997 if(nready == 0) {
8998 /*
8999 * Note that in non-blocking server mode, the inactivity timer is used
9000 * to allow I/O to block for a specified amount of time, so in this
9001 * mode we return the postponed blocked status when an abort is
9002 * requested.
9003 */
9004 if(gl_call_timeout_handler(gl)) {
9005 return 1;
9006 } else if(gl->io_mode == GL_SERVER_MODE) {
9007 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
9008 return 1;
9009 };
9010 /*
9011 * If nready < 0, this means an error occurred.
9012 */
9013 } else if(nready < 0) {
9014 if(errno != EINTR) {
9015 gl_record_status(gl, GLR_ERROR, errno);
9016 return 1;
9017 };
9018 /*
9019 * If the user-input file descriptor has data available, return.
9020 */
9021 } else if(FD_ISSET(fd, &rfds)) {
9022 return 0;
9023 /*
9024 * Check for activity on any of the file descriptors registered by the
9025 * calling application, and call the associated callback functions.
9026 */
9027 } else {
9028 GlFdNode *node; /* The fd event node being checked */
9029 /*
9030 * Search the list for the file descriptor that caused select() to return.
9031 */
9032 for(node=gl->fd_nodes; node; node=node->next) {
9033 /*
9034 * Is there urgent out of band data waiting to be read on fd?
9035 */
9036 if(node->ur.fn && FD_ISSET(node->fd, &ufds)) {
9037 if(gl_call_fd_handler(gl, &node->ur, node->fd, GLFD_URGENT))
9038 return 1;
9039 break; /* The callback may have changed the list of nodes */
9040 /*
9041 * Is the fd readable?
9042 */
9043 } else if(node->rd.fn && FD_ISSET(node->fd, &rfds)) {
9044 if(gl_call_fd_handler(gl, &node->rd, node->fd, GLFD_READ))
9045 return 1;
9046 break; /* The callback may have changed the list of nodes */
9047 /*
9048 * Is the fd writable?
9049 */
9050 } else if(node->wr.fn && FD_ISSET(node->fd, &wfds)) {
9051 if(gl_call_fd_handler(gl, &node->wr, node->fd, GLFD_WRITE))
9052 return 1;
9053 break; /* The callback may have changed the list of nodes */
9054 };
9055 };
9056 };
9057 /*
9058 * Just in case the above event handlers asked for the input line to
9059 * be redrawn, flush any pending output.
9060 */
9061 if(gl_flush_output(gl))
9062 return 1;
9063 };
9064 return 0;
9065 #endif
9066 }
9067
9068 #if defined(HAVE_SELECT)
9069 /*.......................................................................
9070 * This is a private function of gl_event_handler(), used to call a
9071 * file-descriptor callback.
9072 *
9073 * Input:
9074 * gl GetLine * The resource object of gl_get_line().
9075 * gfh GlFdHandler * The I/O handler.
9076 * fd int The file-descriptor being reported.
9077 * event GlFdEvent The I/O event being reported.
9078 * Output:
9079 * return int 0 - OK.
9080 * 1 - Error.
9081 */
9082 static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
9083 GlFdEvent event)
9084 {
9085 Termios attr; /* The terminal attributes */
9086 int waserr = 0; /* True after any error */
9087 /*
9088 * Re-enable conversion of newline characters to carriage-return/linefeed,
9089 * so that the callback can write to the terminal without having to do
9090 * anything special.
9091 */
9092 if(tcgetattr(gl->input_fd, &attr)) {
9093 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
9094 return 1;
9095 };
9096 attr.c_oflag |= OPOST;
9097 while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
9098 if(errno != EINTR) {
9099 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
9100 return 1;
9101 };
9102 };
9103 /*
9104 * Invoke the application's callback function.
9105 */
9106 switch(gfh->fn(gl, gfh->data, fd, event)) {
9107 default:
9108 case GLFD_ABORT:
9109 gl_record_status(gl, GLR_FDABORT, 0);
9110 waserr = 1;
9111 break;
9112 case GLFD_REFRESH:
9113 gl_queue_redisplay(gl);
9114 break;
9115 case GLFD_CONTINUE:
9116 break;
9117 };
9118 /*
9119 * If the callback function called gl_normal_io(), restore raw mode,
9120 * and queue a redisplay of the input line.
9121 */
9122 if(!gl->raw_mode)
9123 waserr = waserr || _gl_raw_io(gl, 1);
9124 /*
9125 * Disable conversion of newline characters to carriage-return/linefeed.
9126 */
9127 attr.c_oflag &= ~(OPOST);
9128 while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
9129 if(errno != EINTR) {
9130 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
9131 return 1;
9132 };
9133 };
9134 return waserr;
9135 }
9136
9137 /*.......................................................................
9138 * This is a private function of gl_event_handler(), used to call a
9139 * inactivity timer callbacks.
9140 *
9141 * Input:
9142 * gl GetLine * The resource object of gl_get_line().
9143 * Output:
9144 * return int 0 - OK.
9145 * 1 - Error.
9146 */
9147 static int gl_call_timeout_handler(GetLine *gl)
9148 {
9149 Termios attr; /* The terminal attributes */
9150 int waserr = 0; /* True after any error */
9151 /*
9152 * Make sure that there is an inactivity timeout callback.
9153 */
9154 if(!gl->timer.fn)
9155 return 0;
9156 /*
9157 * Re-enable conversion of newline characters to carriage-return/linefeed,
9158 * so that the callback can write to the terminal without having to do
9159 * anything special.
9160 */
9161 if(tcgetattr(gl->input_fd, &attr)) {
9162 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
9163 return 1;
9164 };
9165 attr.c_oflag |= OPOST;
9166 while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
9167 if(errno != EINTR) {
9168 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
9169 return 1;
9170 };
9171 };
9172 /*
9173 * Invoke the application's callback function.
9174 */
9175 switch(gl->timer.fn(gl, gl->timer.data)) {
9176 default:
9177 case GLTO_ABORT:
9178 gl_record_status(gl, GLR_TIMEOUT, 0);
9179 waserr = 1;
9180 break;
9181 case GLTO_REFRESH:
9182 gl_queue_redisplay(gl);
9183 break;
9184 case GLTO_CONTINUE:
9185 break;
9186 };
9187 /*
9188 * If the callback function called gl_normal_io(), restore raw mode,
9189 * and queue a redisplay of the input line.
9190 */
9191 if(!gl->raw_mode)
9192 waserr = waserr || _gl_raw_io(gl, 1);
9193 /*
9194 * Disable conversion of newline characters to carriage-return/linefeed.
9195 */
9196 attr.c_oflag &= ~(OPOST);
9197 while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
9198 if(errno != EINTR) {
9199 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
9200 return 1;
9201 };
9202 };
9203 return waserr;
9204 }
9205 #endif /* HAVE_SELECT */
9206
9207 /*.......................................................................
9208 * Switch history groups. History groups represent separate history
9209 * lists recorded within a single history buffer. Different groups
9210 * are distinguished by integer identifiers chosen by the calling
9211 * appplicaton. Initially new_GetLine() sets the group identifier to
9212 * 0. Whenever a new line is appended to the history list, the current
9213 * group identifier is recorded with it, and history lookups only
9214 * consider lines marked with the current group identifier.
9215 *
9216 * Input:
9217 * gl GetLine * The resource object of gl_get_line().
9218 * id unsigned The new history group identifier.
9219 * Output:
9220 * return int 0 - OK.
9221 * 1 - Error.
9222 */
9223 int gl_group_history(GetLine *gl, unsigned id)
9224 {
9225 sigset_t oldset; /* The signals that were blocked on entry to this function */
9226 int status; /* The return status of this function */
9227 /*
9228 * Check the arguments.
9229 */
9230 if(!gl) {
9231 errno = EINVAL;
9232 return 1;
9233 };
9234 /*
9235 * Block all signals while we install the new configuration.
9236 */
9237 if(gl_mask_signals(gl, &oldset))
9238 return 1;
9239 /*
9240 * If the group isn't being changed, do nothing.
9241 */
9242 if(_glh_get_group(gl->glh) == id) {
9243 status = 0;
9244 /*
9245 * Establish the new group.
9246 */
9247 } else if(_glh_set_group(gl->glh, id)) {
9248 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
9249 status = 1;
9250 /*
9251 * Prevent history information from the previous group being
9252 * inappropriately used by the next call to gl_get_line().
9253 */
9254 } else {
9255 gl->preload_history = 0;
9256 gl->last_search = -1;
9257 status = 0;
9258 };
9259 /*
9260 * Restore the process signal mask.
9261 */
9262 gl_unmask_signals(gl, &oldset);
9263 return status;
9264 }
9265
9266 /*.......................................................................
9267 * Display the contents of the history list.
9268 *
9269 * Input:
9270 * gl GetLine * The resource object of gl_get_line().
9271 * fp FILE * The stdio output stream to write to.
9272 * fmt const char * A format string. This containing characters to be
9273 * written verbatim, plus any of the following
9274 * format directives:
9275 * %D - The date, formatted like 2001-11-20
9276 * %T - The time of day, formatted like 23:59:59
9277 * %N - The sequential entry number of the
9278 * line in the history buffer.
9279 * %G - The number of the history group that
9280 * the line belongs to.
9281 * %% - A literal % character.
9282 * %H - The history line itself.
9283 * Note that a '\n' newline character is not
9284 * appended by default.
9285 * all_groups int If true, display history lines from all
9286 * history groups. Otherwise only display
9287 * those of the current history group.
9288 * max_lines int If max_lines is < 0, all available lines
9289 * are displayed. Otherwise only the most
9290 * recent max_lines lines will be displayed.
9291 * Output:
9292 * return int 0 - OK.
9293 * 1 - Error.
9294 */
9295 int gl_show_history(GetLine *gl, FILE *fp, const char *fmt, int all_groups,
9296 int max_lines)
9297 {
9298 sigset_t oldset; /* The signals that were blocked on entry to this function */
9299 int status; /* The return status of this function */
9300 /*
9301 * Check the arguments.
9302 */
9303 if(!gl || !fp || !fmt) {
9304 if(gl)
9305 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
9306 errno = EINVAL;
9307 return 1;
9308 };
9309 /*
9310 * Block all signals.
9311 */
9312 if(gl_mask_signals(gl, &oldset))
9313 return 1;
9314 /*
9315 * Display the specified history group(s) while signals are blocked.
9316 */
9317 status = _glh_show_history(gl->glh, _io_write_stdio, fp, fmt, all_groups,
9318 max_lines) || fflush(fp)==EOF;
9319 if(!status)
9320 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
9321 /*
9322 * Restore the process signal mask.
9323 */
9324 gl_unmask_signals(gl, &oldset);
9325 return status;
9326 }
9327
9328 /*.......................................................................
9329 * Update if necessary, and return the current size of the terminal.
9330 *
9331 * Input:
9332 * gl GetLine * The resource object of gl_get_line().
9333 * def_ncolumn int If the number of columns in the terminal
9334 * can't be determined, substitute this number.
9335 * def_nline int If the number of lines in the terminal can't
9336 * be determined, substitute this number.
9337 * Output:
9338 * return GlTerminalSize The current terminal size.
9339 */
9340 GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline)
9341 {
9342 GlTerminalSize size; /* The object to be returned */
9343 sigset_t oldset; /* The signals that were blocked on entry */
9344 /* to this function */
9345 /*
9346 * Block all signals while accessing gl.
9347 */
9348 gl_mask_signals(gl, &oldset);
9349 /*
9350 * Lookup/configure the terminal size.
9351 */
9352 _gl_terminal_size(gl, def_ncolumn, def_nline, &size);
9353 /*
9354 * Restore the process signal mask before returning.
9355 */
9356 gl_unmask_signals(gl, &oldset);
9357 return size;
9358 }
9359
9360 /*.......................................................................
9361 * This is the private body of the gl_terminal_size() function. It
9362 * assumes that the caller has checked its arguments and blocked the
9363 * delivery of signals.
9364 */
9365 static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
9366 GlTerminalSize *size)
9367 {
9368 const char *env; /* The value of an environment variable */
9369 int n; /* A number read from env[] */
9370 /*
9371 * Set the number of lines and columns to non-sensical values so that
9372 * we know later if they have been set.
9373 */
9374 gl->nline = 0;
9375 gl->ncolumn = 0;
9376 /*
9377 * Are we reading from a terminal?
9378 */
9379 if(gl->is_term) {
9380 /*
9381 * Ask the terminal directly if possible.
9382 */
9383 gl_query_size(gl, &gl->ncolumn, &gl->nline);
9384 /*
9385 * If gl_query_size() couldn't ask the terminal, it will have
9386 * left gl->nrow and gl->ncolumn unchanged. If these values haven't
9387 * been changed from their initial values of zero, we need to find
9388 * a different method to get the terminal size.
9389 *
9390 * If the number of lines isn't known yet, first see if the
9391 * LINES environment ariable exists and specifies a believable number.
9392 * If this doesn't work, look up the default size in the terminal
9393 * information database.
9394 */
9395 if(gl->nline < 1) {
9396 if((env = getenv("LINES")) && (n=atoi(env)) > 0)
9397 gl->nline = n;
9398 #ifdef USE_TERMINFO
9399 else
9400 gl->nline = tigetnum((char *)"lines");
9401 #elif defined(USE_TERMCAP)
9402 else
9403 gl->nline = tgetnum("li");
9404 #endif
9405 };
9406 /*
9407 * If the number of lines isn't known yet, first see if the COLUMNS
9408 * environment ariable exists and specifies a believable number. If
9409 * this doesn't work, look up the default size in the terminal
9410 * information database.
9411 */
9412 if(gl->ncolumn < 1) {
9413 if((env = getenv("COLUMNS")) && (n=atoi(env)) > 0)
9414 gl->ncolumn = n;
9415 #ifdef USE_TERMINFO
9416 else
9417 gl->ncolumn = tigetnum((char *)"cols");
9418 #elif defined(USE_TERMCAP)
9419 else
9420 gl->ncolumn = tgetnum("co");
9421 #endif
9422 };
9423 };
9424 /*
9425 * If we still haven't been able to acquire reasonable values, substitute
9426 * the default values specified by the caller.
9427 */
9428 if(gl->nline <= 0)
9429 gl->nline = def_nline;
9430 if(gl->ncolumn <= 0)
9431 gl->ncolumn = def_ncolumn;
9432 /*
9433 * Copy the new size into the return value.
9434 */
9435 if(size) {
9436 size->nline = gl->nline;
9437 size->ncolumn = gl->ncolumn;
9438 };
9439 return;
9440 }
9441
9442 /*.......................................................................
9443 * Resize or delete the history buffer.
9444 *
9445 * Input:
9446 * gl GetLine * The resource object of gl_get_line().
9447 * bufsize size_t The number of bytes in the history buffer, or 0
9448 * to delete the buffer completely.
9449 * Output:
9450 * return int 0 - OK.
9451 * 1 - Insufficient memory (the previous buffer
9452 * will have been retained). No error message
9453 * will be displayed.
9454 */
9455 int gl_resize_history(GetLine *gl, size_t bufsize)
9456 {
9457 sigset_t oldset; /* The signals that were blocked on entry to this function */
9458 int status; /* The return status of this function */
9459 /*
9460 * Check the arguments.
9461 */
9462 if(!gl)
9463 return 1;
9464 /*
9465 * Block all signals while modifying the contents of gl.
9466 */
9467 if(gl_mask_signals(gl, &oldset))
9468 return 1;
9469 /*
9470 * Perform the resize while signals are blocked.
9471 */
9472 status = _glh_resize_history(gl->glh, bufsize);
9473 if(status)
9474 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
9475 /*
9476 * Restore the process signal mask before returning.
9477 */
9478 gl_unmask_signals(gl, &oldset);
9479 return status;
9480 }
9481
9482 /*.......................................................................
9483 * Set an upper limit to the number of lines that can be recorded in the
9484 * history list, or remove a previously specified limit.
9485 *
9486 * Input:
9487 * gl GetLine * The resource object of gl_get_line().
9488 * max_lines int The maximum number of lines to allow, or -1 to
9489 * cancel a previous limit and allow as many lines
9490 * as will fit in the current history buffer size.
9491 */
9492 void gl_limit_history(GetLine *gl, int max_lines)
9493 {
9494 if(gl) {
9495 sigset_t oldset; /* The signals that were blocked on entry to this block */
9496 /*
9497 * Temporarily block all signals.
9498 */
9499 gl_mask_signals(gl, &oldset);
9500 /*
9501 * Apply the limit while signals are blocked.
9502 */
9503 _glh_limit_history(gl->glh, max_lines);
9504 /*
9505 * Restore the process signal mask before returning.
9506 */
9507 gl_unmask_signals(gl, &oldset);
9508 };
9509 }
9510
9511 /*.......................................................................
9512 * Discard either all historical lines, or just those associated with the
9513 * current history group.
9514 *
9515 * Input:
9516 * gl GetLine * The resource object of gl_get_line().
9517 * all_groups int If true, clear all of the history. If false,
9518 * clear only the stored lines associated with the
9519 * currently selected history group.
9520 */
9521 void gl_clear_history(GetLine *gl, int all_groups)
9522 {
9523 if(gl) {
9524 sigset_t oldset; /* The signals that were blocked on entry to this block */
9525 /*
9526 * Temporarily block all signals.
9527 */
9528 gl_mask_signals(gl, &oldset);
9529 /*
9530 * Clear the history buffer while signals are blocked.
9531 */
9532 _glh_clear_history(gl->glh, all_groups);
9533 /*
9534 * Restore the process signal mask before returning.
9535 */
9536 gl_unmask_signals(gl, &oldset);
9537 };
9538 }
9539
9540 /*.......................................................................
9541 * Temporarily enable or disable the gl_get_line() history mechanism.
9542 *
9543 * Input:
9544 * gl GetLine * The resource object of gl_get_line().
9545 * enable int If true, turn on the history mechanism. If
9546 * false, disable it.
9547 */
9548 void gl_toggle_history(GetLine *gl, int enable)
9549 {
9550 if(gl) {
9551 sigset_t oldset; /* The signals that were blocked on entry to this block */
9552 /*
9553 * Temporarily block all signals.
9554 */
9555 gl_mask_signals(gl, &oldset);
9556 /*
9557 * Change the history recording mode while signals are blocked.
9558 */
9559 _glh_toggle_history(gl->glh, enable);
9560 /*
9561 * Restore the process signal mask before returning.
9562 */
9563 gl_unmask_signals(gl, &oldset);
9564 };
9565 }
9566
9567 /*.......................................................................
9568 * Lookup a history line by its sequential number of entry in the
9569 * history buffer.
9570 *
9571 * Input:
9572 * gl GetLine * The resource object of gl_get_line().
9573 * id unsigned long The identification number of the line to
9574 * be returned, where 0 denotes the first line
9575 * that was entered in the history list, and
9576 * each subsequently added line has a number
9577 * one greater than the previous one. For
9578 * the range of lines currently in the list,
9579 * see the gl_range_of_history() function.
9580 * Input/Output:
9581 * line GlHistoryLine * A pointer to the variable in which to
9582 * return the details of the line.
9583 * Output:
9584 * return int 0 - The line is no longer in the history
9585 * list, and *line has not been changed.
9586 * 1 - The requested line can be found in
9587 * *line. Note that line->line is part
9588 * of the history buffer, so a
9589 * private copy should be made if you
9590 * wish to use it after subsequent calls
9591 * to any functions that take *gl as an
9592 * argument.
9593 */
9594 int gl_lookup_history(GetLine *gl, unsigned long id, GlHistoryLine *line)
9595 {
9596 sigset_t oldset; /* The signals that were blocked on entry to this function */
9597 int status; /* The return status of this function */
9598 /*
9599 * Check the arguments.
9600 */
9601 if(!gl)
9602 return 0;
9603 /*
9604 * Block all signals while modifying the contents of gl.
9605 */
9606 if(gl_mask_signals(gl, &oldset))
9607 return 1;
9608 /*
9609 * Perform the lookup while signals are blocked.
9610 */
9611 status = _glh_lookup_history(gl->glh, (GlhLineID) id, &line->line,
9612 &line->group, &line->timestamp);
9613 if(status)
9614 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
9615 /*
9616 * Restore the process signal mask before returning.
9617 */
9618 gl_unmask_signals(gl, &oldset);
9619 return status;
9620 }
9621
9622 /*.......................................................................
9623 * Query the state of the history list. Note that any of the input/output
9624 * pointers can be specified as NULL.
9625 *
9626 * Input:
9627 * gl GetLine * The resource object of gl_get_line().
9628 * Input/Output:
9629 * state GlHistoryState * A pointer to the variable in which to record
9630 * the return values.
9631 */
9632 void gl_state_of_history(GetLine *gl, GlHistoryState *state)
9633 {
9634 if(gl && state) {
9635 sigset_t oldset; /* The signals that were blocked on entry to this block */
9636 /*
9637 * Temporarily block all signals.
9638 */
9639 gl_mask_signals(gl, &oldset);
9640 /*
9641 * Lookup the status while signals are blocked.
9642 */
9643 _glh_state_of_history(gl->glh, &state->enabled, &state->group,
9644 &state->max_lines);
9645 /*
9646 * Restore the process signal mask before returning.
9647 */
9648 gl_unmask_signals(gl, &oldset);
9649 };
9650 }
9651
9652 /*.......................................................................
9653 * Query the number and range of lines in the history buffer.
9654 *
9655 * Input:
9656 * gl GetLine * The resource object of gl_get_line().
9657 * range GlHistoryRange * A pointer to the variable in which to record
9658 * the return values. If range->nline=0, the
9659 * range of lines will be given as 0-0.
9660 */
9661 void gl_range_of_history(GetLine *gl, GlHistoryRange *range)
9662 {
9663 if(gl && range) {
9664 sigset_t oldset; /* The signals that were blocked on entry to this block */
9665 /*
9666 * Temporarily block all signals.
9667 */
9668 gl_mask_signals(gl, &oldset);
9669 /*
9670 * Lookup the information while signals are blocked.
9671 */
9672 _glh_range_of_history(gl->glh, &range->oldest, &range->newest,
9673 &range->nlines);
9674 /*
9675 * Restore the process signal mask before returning.
9676 */
9677 gl_unmask_signals(gl, &oldset);
9678 };
9679 }
9680
9681 /*.......................................................................
9682 * Return the size of the history buffer and the amount of the
9683 * buffer that is currently in use.
9684 *
9685 * Input:
9686 * gl GetLine * The gl_get_line() resource object.
9687 * Input/Output:
9688 * GlHistorySize size * A pointer to the variable in which to return
9689 * the results.
9690 */
9691 void gl_size_of_history(GetLine *gl, GlHistorySize *size)
9692 {
9693 if(gl && size) {
9694 sigset_t oldset; /* The signals that were blocked on entry to this block */
9695 /*
9696 * Temporarily block all signals.
9697 */
9698 gl_mask_signals(gl, &oldset);
9699 /*
9700 * Lookup the information while signals are blocked.
9701 */
9702 _glh_size_of_history(gl->glh, &size->size, &size->used);
9703 /*
9704 * Restore the process signal mask before returning.
9705 */
9706 gl_unmask_signals(gl, &oldset);
9707 };
9708 }
9709
9710 /*.......................................................................
9711 * This is the action function that lists the contents of the history
9712 * list.
9713 */
9714 static KT_KEY_FN(gl_list_history)
9715 {
9716 /*
9717 * Start a new line.
9718 */
9719 if(gl_start_newline(gl, 1))
9720 return 1;
9721 /*
9722 * List history lines that belong to the current group.
9723 */
9724 _glh_show_history(gl->glh, gl_write_fn, gl, "%N %T %H\r\n", 0,
9725 count<=1 ? -1 : count);
9726 /*
9727 * Arrange for the input line to be redisplayed.
9728 */
9729 gl_queue_redisplay(gl);
9730 return 0;
9731 }
9732
9733 /*.......................................................................
9734 * Specify whether text that users type should be displayed or hidden.
9735 * In the latter case, only the prompt is displayed, and the final
9736 * input line is not archived in the history list.
9737 *
9738 * Input:
9739 * gl GetLine * The gl_get_line() resource object.
9740 * enable int 0 - Disable echoing.
9741 * 1 - Enable echoing.
9742 * -1 - Just query the mode without changing it.
9743 * Output:
9744 * return int The echoing disposition that was in effect
9745 * before this function was called:
9746 * 0 - Echoing was disabled.
9747 * 1 - Echoing was enabled.
9748 */
9749 int gl_echo_mode(GetLine *gl, int enable)
9750 {
9751 if(gl) {
9752 sigset_t oldset; /* The signals that were blocked on entry to this block */
9753 int was_echoing; /* The echoing disposition on entry to this function */
9754 /*
9755 * Temporarily block all signals.
9756 */
9757 gl_mask_signals(gl, &oldset);
9758 /*
9759 * Install the new disposition while signals are blocked.
9760 */
9761 was_echoing = gl->echo;
9762 if(enable >= 0)
9763 gl->echo = enable;
9764 /*
9765 * Restore the process signal mask before returning.
9766 */
9767 gl_unmask_signals(gl, &oldset);
9768 /*
9769 * Return the original echoing disposition.
9770 */
9771 return was_echoing;
9772 };
9773 return 1;
9774 }
9775
9776 /*.......................................................................
9777 * Display the prompt.
9778 *
9779 * Input:
9780 * gl GetLine * The resource object of gl_get_line().
9781 * Output:
9782 * return int 0 - OK.
9783 * 1 - Error.
9784 */
9785 static int gl_display_prompt(GetLine *gl)
9786 {
9787 const char *pptr; /* A pointer into gl->prompt[] */
9788 unsigned old_attr=0; /* The current text display attributes */
9789 unsigned new_attr=0; /* The requested text display attributes */
9790 /*
9791 * Temporarily switch to echoing output characters.
9792 */
9793 int kept_echo = gl->echo;
9794 gl->echo = 1;
9795 /*
9796 * In case the screen got messed up, send a carriage return to
9797 * put the cursor at the beginning of the current terminal line.
9798 */
9799 if(gl_print_control_sequence(gl, 1, gl->bol))
9800 return 1;
9801 /*
9802 * Mark the line as partially displayed.
9803 */
9804 gl->displayed = 1;
9805 /*
9806 * Write the prompt, using the currently selected prompt style.
9807 */
9808 switch(gl->prompt_style) {
9809 case GL_LITERAL_PROMPT:
9810 if(gl_print_string(gl, gl->prompt, '\0'))
9811 return 1;
9812 break;
9813 case GL_FORMAT_PROMPT:
9814 for(pptr=gl->prompt; *pptr; pptr++) {
9815 /*
9816 * Does the latest character appear to be the start of a directive?
9817 */
9818 if(*pptr == '%') {
9819 /*
9820 * Check for and act on attribute changing directives.
9821 */
9822 switch(pptr[1]) {
9823 /*
9824 * Add or remove a text attribute from the new set of attributes.
9825 * If you add or remove a directive from this list, be sure to update
9826 * the equivalent list of directives in gl_displayed_prompt_width().
9827 */
9828 case 'B': case 'U': case 'S': case 'P': case 'F': case 'V':
9829 case 'b': case 'u': case 's': case 'p': case 'f': case 'v':
9830 switch(*++pptr) {
9831 case 'B': /* Switch to a bold font */
9832 new_attr |= GL_TXT_BOLD;
9833 break;
9834 case 'b': /* Switch to a non-bold font */
9835 new_attr &= ~GL_TXT_BOLD;
9836 break;
9837 case 'U': /* Start underlining */
9838 new_attr |= GL_TXT_UNDERLINE;
9839 break;
9840 case 'u': /* Stop underlining */
9841 new_attr &= ~GL_TXT_UNDERLINE;
9842 break;
9843 case 'S': /* Start highlighting */
9844 new_attr |= GL_TXT_STANDOUT;
9845 break;
9846 case 's': /* Stop highlighting */
9847 new_attr &= ~GL_TXT_STANDOUT;
9848 break;
9849 case 'P': /* Switch to a pale font */
9850 new_attr |= GL_TXT_DIM;
9851 break;
9852 case 'p': /* Switch to a non-pale font */
9853 new_attr &= ~GL_TXT_DIM;
9854 break;
9855 case 'F': /* Switch to a flashing font */
9856 new_attr |= GL_TXT_BLINK;
9857 break;
9858 case 'f': /* Switch to a steady font */
9859 new_attr &= ~GL_TXT_BLINK;
9860 break;
9861 case 'V': /* Switch to reverse video */
9862 new_attr |= GL_TXT_REVERSE;
9863 break;
9864 case 'v': /* Switch out of reverse video */
9865 new_attr &= ~GL_TXT_REVERSE;
9866 break;
9867 };
9868 continue;
9869 /*
9870 * A literal % is represented by %%. Skip the leading %.
9871 */
9872 case '%':
9873 pptr++;
9874 break;
9875 };
9876 };
9877 /*
9878 * Many terminals, when asked to turn off a single text attribute, turn
9879 * them all off, so the portable way to turn one off individually is to
9880 * explicitly turn them all off, then specify those that we want from
9881 * scratch.
9882 */
9883 if(old_attr & ~new_attr) {
9884 if(gl_print_control_sequence(gl, 1, gl->text_attr_off))
9885 return 1;
9886 old_attr = 0;
9887 };
9888 /*
9889 * Install new text attributes?
9890 */
9891 if(new_attr != old_attr) {
9892 if(new_attr & GL_TXT_BOLD && !(old_attr & GL_TXT_BOLD) &&
9893 gl_print_control_sequence(gl, 1, gl->bold))
9894 return 1;
9895 if(new_attr & GL_TXT_UNDERLINE && !(old_attr & GL_TXT_UNDERLINE) &&
9896 gl_print_control_sequence(gl, 1, gl->underline))
9897 return 1;
9898 if(new_attr & GL_TXT_STANDOUT && !(old_attr & GL_TXT_STANDOUT) &&
9899 gl_print_control_sequence(gl, 1, gl->standout))
9900 return 1;
9901 if(new_attr & GL_TXT_DIM && !(old_attr & GL_TXT_DIM) &&
9902 gl_print_control_sequence(gl, 1, gl->dim))
9903 return 1;
9904 if(new_attr & GL_TXT_REVERSE && !(old_attr & GL_TXT_REVERSE) &&
9905 gl_print_control_sequence(gl, 1, gl->reverse))
9906 return 1;
9907 if(new_attr & GL_TXT_BLINK && !(old_attr & GL_TXT_BLINK) &&
9908 gl_print_control_sequence(gl, 1, gl->blink))
9909 return 1;
9910 old_attr = new_attr;
9911 };
9912 /*
9913 * Display the latest character.
9914 */
9915 if(gl_print_char(gl, *pptr, pptr[1]))
9916 return 1;
9917 };
9918 /*
9919 * Turn off all text attributes now that we have finished drawing
9920 * the prompt.
9921 */
9922 if(gl_print_control_sequence(gl, 1, gl->text_attr_off))
9923 return 1;
9924 break;
9925 };
9926 /*
9927 * Restore the original echo mode.
9928 */
9929 gl->echo = kept_echo;
9930 /*
9931 * The prompt has now been displayed at least once.
9932 */
9933 gl->prompt_changed = 0;
9934 return 0;
9935 }
9936
9937 /*.......................................................................
9938 * This function can be called from gl_get_line() callbacks to have
9939 * the prompt changed when they return. It has no effect if gl_get_line()
9940 * is not currently being invoked.
9941 *
9942 * Input:
9943 * gl GetLine * The resource object of gl_get_line().
9944 * prompt const char * The new prompt.
9945 */
9946 void gl_replace_prompt(GetLine *gl, const char *prompt)
9947 {
9948 if(gl) {
9949 sigset_t oldset; /* The signals that were blocked on entry to this block */
9950 /*
9951 * Temporarily block all signals.
9952 */
9953 gl_mask_signals(gl, &oldset);
9954 /*
9955 * Replace the prompt.
9956 */
9957 _gl_replace_prompt(gl, prompt);
9958 /*
9959 * Restore the process signal mask before returning.
9960 */
9961 gl_unmask_signals(gl, &oldset);
9962 };
9963 }
9964
9965 /*.......................................................................
9966 * This is the private body of the gl_replace_prompt() function. It
9967 * assumes that the caller has checked its arguments and blocked the
9968 * delivery of signals.
9969 */
9970 static void _gl_replace_prompt(GetLine *gl, const char *prompt)
9971 {
9972 /*
9973 * Substitute an empty prompt?
9974 */
9975 if(!prompt)
9976 prompt = "";
9977 /*
9978 * Gaurd against aliasing between prompt and gl->prompt.
9979 */
9980 if(gl->prompt != prompt) {
9981 /*
9982 * Get the length of the new prompt string.
9983 */
9984 size_t slen = strlen(prompt);
9985 /*
9986 * If needed, allocate a new buffer for the prompt string.
9987 */
9988 if(!gl->prompt || slen > strlen(gl->prompt)) {
9989 size_t size = sizeof(char) * (slen + 1);
9990 char *new_prompt = gl->prompt ? realloc(gl->prompt, size) : malloc(size);
9991 if(!new_prompt)
9992 return;
9993 gl->prompt = new_prompt;
9994 };
9995 /*
9996 * Make a copy of the new prompt.
9997 */
9998 strcpy(gl->prompt, prompt);
9999 };
10000 /*
10001 * Record the statistics of the new prompt.
10002 */
10003 gl->prompt_len = gl_displayed_prompt_width(gl);
10004 gl->prompt_changed = 1;
10005 gl_queue_redisplay(gl);
10006 return;
10007 }
10008
10009 /*.......................................................................
10010 * Work out the length of the current prompt on the terminal, according
10011 * to the current prompt formatting style.
10012 *
10013 * Input:
10014 * gl GetLine * The resource object of this library.
10015 * Output:
10016 * return int The number of displayed characters.
10017 */
10018 static int gl_displayed_prompt_width(GetLine *gl)
10019 {
10020 int slen=0; /* The displayed number of characters */
10021 const char *pptr; /* A pointer into prompt[] */
10022 /*
10023 * The length differs according to the prompt display style.
10024 */
10025 switch(gl->prompt_style) {
10026 case GL_LITERAL_PROMPT:
10027 return gl_displayed_string_width(gl, gl->prompt, -1, 0);
10028 break;
10029 case GL_FORMAT_PROMPT:
10030 /*
10031 * Add up the length of the displayed string, while filtering out
10032 * attribute directives.
10033 */
10034 for(pptr=gl->prompt; *pptr; pptr++) {
10035 /*
10036 * Does the latest character appear to be the start of a directive?
10037 */
10038 if(*pptr == '%') {
10039 /*
10040 * Check for and skip attribute changing directives.
10041 */
10042 switch(pptr[1]) {
10043 case 'B': case 'U': case 'S': case 'P': case 'F': case 'V':
10044 case 'b': case 'u': case 's': case 'p': case 'f': case 'v':
10045 pptr++;
10046 continue;
10047 /*
10048 * A literal % is represented by %%. Skip the leading %.
10049 */
10050 case '%':
10051 pptr++;
10052 break;
10053 };
10054 };
10055 slen += gl_displayed_char_width(gl, *pptr, slen);
10056 };
10057 break;
10058 };
10059 return slen;
10060 }
10061
10062 /*.......................................................................
10063 * Specify whether to heed text attribute directives within prompt
10064 * strings.
10065 *
10066 * Input:
10067 * gl GetLine * The resource object of gl_get_line().
10068 * style GlPromptStyle The style of prompt (see the definition of
10069 * GlPromptStyle in libtecla.h for details).
10070 */
10071 void gl_prompt_style(GetLine *gl, GlPromptStyle style)
10072 {
10073 if(gl) {
10074 sigset_t oldset; /* The signals that were blocked on entry to this block */
10075 /*
10076 * Temporarily block all signals.
10077 */
10078 gl_mask_signals(gl, &oldset);
10079 /*
10080 * Install the new style in gl while signals are blocked.
10081 */
10082 if(style != gl->prompt_style) {
10083 gl->prompt_style = style;
10084 gl->prompt_len = gl_displayed_prompt_width(gl);
10085 gl->prompt_changed = 1;
10086 gl_queue_redisplay(gl);
10087 };
10088 /*
10089 * Restore the process signal mask before returning.
10090 */
10091 gl_unmask_signals(gl, &oldset);
10092 };
10093 }
10094
10095 /*.......................................................................
10096 * Tell gl_get_line() how to respond to a given signal. This can be used
10097 * both to override the default responses to signals that gl_get_line()
10098 * normally catches and to add new signals to the list that are to be
10099 * caught.
10100 *
10101 * Input:
10102 * gl GetLine * The resource object of gl_get_line().
10103 * signo int The number of the signal to be caught.
10104 * flags unsigned A bitwise union of GlSignalFlags enumerators.
10105 * after GlAfterSignal What to do after the application's signal
10106 * handler has been called.
10107 * errno_value int The value to set errno to.
10108 * Output:
10109 * return int 0 - OK.
10110 * 1 - Error.
10111 */
10112 int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
10113 GlAfterSignal after, int errno_value)
10114 {
10115 sigset_t oldset; /* The signals that were blocked on entry to this function */
10116 int status; /* The return status of this function */
10117 /*
10118 * Check the arguments.
10119 */
10120 if(!gl) {
10121 errno = EINVAL;
10122 return 1;
10123 };
10124 /*
10125 * Block all signals while modifying the contents of gl.
10126 */
10127 if(gl_mask_signals(gl, &oldset))
10128 return 1;
10129 /*
10130 * Perform the modification while signals are blocked.
10131 */
10132 status = _gl_trap_signal(gl, signo, flags, after, errno_value);
10133 /*
10134 * Restore the process signal mask before returning.
10135 */
10136 gl_unmask_signals(gl, &oldset);
10137 return status;
10138 }
10139
10140 /*.......................................................................
10141 * This is the private body of the gl_trap_signal() function. It
10142 * assumes that the caller has checked its arguments and blocked the
10143 * delivery of signals.
10144 */
10145 static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
10146 GlAfterSignal after, int errno_value)
10147 {
10148 GlSignalNode *sig;
10149 /*
10150 * Complain if an attempt is made to trap untrappable signals.
10151 * These would otherwise cause errors later in gl_mask_signals().
10152 */
10153 if(0
10154 #ifdef SIGKILL
10155 || signo==SIGKILL
10156 #endif
10157 #ifdef SIGBLOCK
10158 || signo==SIGBLOCK
10159 #endif
10160 ) {
10161 return 1;
10162 };
10163 /*
10164 * See if the signal has already been registered.
10165 */
10166 for(sig=gl->sigs; sig && sig->signo != signo; sig = sig->next)
10167 ;
10168 /*
10169 * If the signal hasn't already been registered, allocate a node for
10170 * it.
10171 */
10172 if(!sig) {
10173 sig = (GlSignalNode *) _new_FreeListNode(gl->sig_mem);
10174 if(!sig)
10175 return 1;
10176 /*
10177 * Add the new node to the head of the list.
10178 */
10179 sig->next = gl->sigs;
10180 gl->sigs = sig;
10181 /*
10182 * Record the signal number.
10183 */
10184 sig->signo = signo;
10185 /*
10186 * Create a signal set that includes just this signal.
10187 */
10188 sigemptyset(&sig->proc_mask);
10189 if(sigaddset(&sig->proc_mask, signo) == -1) {
10190 _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
10191 sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig);
10192 return 1;
10193 };
10194 /*
10195 * Add the signal to the bit-mask of signals being trapped.
10196 */
10197 sigaddset(&gl->all_signal_set, signo);
10198 };
10199 /*
10200 * Record the new signal attributes.
10201 */
10202 sig->flags = flags;
10203 sig->after = after;
10204 sig->errno_value = errno_value;
10205 return 0;
10206 }
10207
10208 /*.......................................................................
10209 * Remove a signal from the list of signals that gl_get_line() traps.
10210 *
10211 * Input:
10212 * gl GetLine * The resource object of gl_get_line().
10213 * signo int The number of the signal to be ignored.
10214 * Output:
10215 * return int 0 - OK.
10216 * 1 - Error.
10217 */
10218 int gl_ignore_signal(GetLine *gl, int signo)
10219 {
10220 GlSignalNode *sig; /* The gl->sigs list node of the specified signal */
10221 GlSignalNode *prev; /* The node that precedes sig in the list */
10222 sigset_t oldset; /* The signals that were blocked on entry to this */
10223 /* function. */
10224 /*
10225 * Check the arguments.
10226 */
10227 if(!gl) {
10228 errno = EINVAL;
10229 return 1;
10230 };
10231 /*
10232 * Block all signals while modifying the contents of gl.
10233 */
10234 if(gl_mask_signals(gl, &oldset))
10235 return 1;
10236 /*
10237 * Find the node of the gl->sigs list which records the disposition
10238 * of the specified signal.
10239 */
10240 for(prev=NULL,sig=gl->sigs; sig && sig->signo != signo;
10241 prev=sig,sig=sig->next)
10242 ;
10243 if(sig) {
10244 /*
10245 * Remove the node from the list.
10246 */
10247 if(prev)
10248 prev->next = sig->next;
10249 else
10250 gl->sigs = sig->next;
10251 /*
10252 * Return the node to the freelist.
10253 */
10254 sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig);
10255 /*
10256 * Remove the signal from the bit-mask union of signals being trapped.
10257 */
10258 sigdelset(&gl->all_signal_set, signo);
10259 };
10260 /*
10261 * Restore the process signal mask before returning.
10262 */
10263 gl_unmask_signals(gl, &oldset);
10264 return 0;
10265 }
10266
10267 /*.......................................................................
10268 * This function is called when an input line has been completed. It
10269 * appends the specified newline character, terminates the line,
10270 * records the line in the history buffer if appropriate, and positions
10271 * the terminal cursor at the start of the next line.
10272 *
10273 * Input:
10274 * gl GetLine * The resource object of gl_get_line().
10275 * newline_char int The newline character to add to the end
10276 * of the line.
10277 * Output:
10278 * return int 0 - OK.
10279 * 1 - Error.
10280 */
10281 static int gl_line_ended(GetLine *gl, int newline_char)
10282 {
10283 /*
10284 * If the newline character is printable, display it at the end of
10285 * the line, and add it to the input line buffer.
10286 */
10287 if(isprint((int)(unsigned char) newline_char)) {
10288 if(gl_end_of_line(gl, 1, NULL) || gl_add_char_to_line(gl, newline_char))
10289 return 1;
10290 } else {
10291 /*
10292 * Otherwise just append a newline character to the input line buffer.
10293 */
10294 newline_char = '\n';
10295 gl_buffer_char(gl, newline_char, gl->ntotal);
10296 };
10297 /*
10298 * Add the line to the history buffer if it was entered with a
10299 * newline character.
10300 */
10301 if(gl->echo && gl->automatic_history && newline_char=='\n')
10302 (void) _gl_append_history(gl, gl->line);
10303 /*
10304 * Except when depending on the system-provided line editing, start a new
10305 * line after the end of the line that has just been entered.
10306 */
10307 if(gl->editor != GL_NO_EDITOR && gl_start_newline(gl, 1))
10308 return 1;
10309 /*
10310 * Record the successful return status.
10311 */
10312 gl_record_status(gl, GLR_NEWLINE, 0);
10313 /*
10314 * Attempt to flush any pending output.
10315 */
10316 (void) gl_flush_output(gl);
10317 /*
10318 * The next call to gl_get_line() will write the prompt for a new line
10319 * (or continue the above flush if incomplete), so if we manage to
10320 * flush the terminal now, report that we are waiting to write to the
10321 * terminal.
10322 */
10323 gl->pending_io = GLP_WRITE;
10324 return 0;
10325 }
10326
10327 /*.......................................................................
10328 * Return the last signal that was caught by the most recent call to
10329 * gl_get_line(), or -1 if no signals were caught. This is useful if
10330 * gl_get_line() returns errno=EINTR and you need to find out what signal
10331 * caused it to abort.
10332 *
10333 * Input:
10334 * gl GetLine * The resource object of gl_get_line().
10335 * Output:
10336 * return int The last signal caught by the most recent
10337 * call to gl_get_line(), or -1 if no signals
10338 * were caught.
10339 */
10340 int gl_last_signal(GetLine *gl)
10341 {
10342 int signo = -1; /* The requested signal number */
10343 if(gl) {
10344 sigset_t oldset; /* The signals that were blocked on entry to this block */
10345 /*
10346 * Temporarily block all signals.
10347 */
10348 gl_mask_signals(gl, &oldset);
10349 /*
10350 * Access gl now that signals are blocked.
10351 */
10352 signo = gl->last_signal;
10353 /*
10354 * Restore the process signal mask before returning.
10355 */
10356 gl_unmask_signals(gl, &oldset);
10357 };
10358 return signo;
10359 }
10360
10361 /*.......................................................................
10362 * Prepare to edit a new line.
10363 *
10364 * Input:
10365 * gl GetLine * The resource object of this library.
10366 * prompt char * The prompt to prefix the line with, or NULL to
10367 * use the same prompt that was used by the previous
10368 * line.
10369 * start_line char * The initial contents of the input line, or NULL
10370 * if it should start out empty.
10371 * start_pos int If start_line isn't NULL, this specifies the
10372 * index of the character over which the cursor
10373 * should initially be positioned within the line.
10374 * If you just want it to follow the last character
10375 * of the line, send -1.
10376 * Output:
10377 * return int 0 - OK.
10378 * 1 - Error.
10379 */
10380 static int gl_present_line(GetLine *gl, const char *prompt,
10381 const char *start_line, int start_pos)
10382 {
10383 /*
10384 * Prepare the line-editing properties for a new editing session.
10385 */
10386 gl_reset_editor(gl);
10387 /*
10388 * Record the new prompt and its displayed width.
10389 */
10390 if(prompt)
10391 _gl_replace_prompt(gl, prompt);
10392 /*
10393 * Reset the history search pointers.
10394 */
10395 if(_glh_cancel_search(gl->glh)) {
10396 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
10397 return 1;
10398 };
10399 /*
10400 * If the previous line was entered via the repeat-history action,
10401 * preload the specified history line.
10402 */
10403 if(gl->preload_history) {
10404 gl->preload_history = 0;
10405 if(_glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1)) {
10406 gl_update_buffer(gl); /* Compute gl->ntotal etc.. */
10407 gl->buff_curpos = gl->ntotal;
10408 } else {
10409 gl_truncate_buffer(gl, 0);
10410 };
10411 gl->preload_id = 0;
10412 /*
10413 * Present a specified initial line?
10414 */
10415 } else if(start_line) {
10416 char *cptr; /* A pointer into gl->line[] */
10417 /*
10418 * Measure the length of the starting line.
10419 */
10420 int start_len = strlen(start_line);
10421 /*
10422 * If the length of the line is greater than the available space,
10423 * truncate it.
10424 */
10425 if(start_len > gl->linelen)
10426 start_len = gl->linelen;
10427 /*
10428 * Load the line into the buffer.
10429 */
10430 if(start_line != gl->line) {
10431 gl_truncate_buffer(gl, 0);
10432 gl_buffer_string(gl, start_line, start_len, 0);
10433 };
10434 /*
10435 * Strip off any trailing newline and carriage return characters.
10436 */
10437 for(cptr=gl->line + gl->ntotal - 1; cptr >= gl->line &&
10438 (*cptr=='\n' || *cptr=='\r'); cptr--,gl->ntotal--)
10439 ;
10440 gl_truncate_buffer(gl, gl->ntotal < 0 ? 0 : gl->ntotal);
10441 /*
10442 * Where should the cursor be placed within the line?
10443 */
10444 if(start_pos < 0 || start_pos > gl->ntotal) {
10445 if(gl_place_cursor(gl, gl->ntotal))
10446 return 1;
10447 } else {
10448 if(gl_place_cursor(gl, start_pos))
10449 return 1;
10450 };
10451 /*
10452 * Clear the input line?
10453 */
10454 } else {
10455 gl_truncate_buffer(gl, 0);
10456 };
10457 /*
10458 * Arrange for the line to be displayed by gl_flush_output().
10459 */
10460 gl_queue_redisplay(gl);
10461 /*
10462 * Update the display.
10463 */
10464 return gl_flush_output(gl);
10465 }
10466
10467 /*.......................................................................
10468 * Reset all line-editing parameters for a new editing session. Note
10469 * that this does not empty the input line, since that would prevent a
10470 * gl_get_line() caller from specifying the returned line buffer as
10471 * the start_line argument of the next call to gl_get_line().
10472 *
10473 * Input:
10474 * gl GetLine * The line editor resource object.
10475 */
10476 static void gl_reset_editor(GetLine *gl)
10477 {
10478 /*
10479 * Warning: Don't clear gl->line[] and gl->ntotal here (see above).
10480 */
10481 gl->buff_curpos = 0;
10482 gl->term_curpos = 0;
10483 gl->term_len = 0;
10484 gl->insert_curpos = 0;
10485 gl->number = -1;
10486 gl->displayed = 0;
10487 gl->endline = 0;
10488 gl->redisplay = 0;
10489 gl->postpone = 0;
10490 gl->nbuf = 0;
10491 gl->nread = 0;
10492 gl->vi.command = 0;
10493 gl->vi.undo.line[0] = '\0';
10494 gl->vi.undo.ntotal = 0;
10495 gl->vi.undo.buff_curpos = 0;
10496 gl->vi.repeat.action.fn = 0;
10497 gl->vi.repeat.action.data = 0;
10498 gl->last_signal = -1;
10499 }
10500
10501 /*.......................................................................
10502 * Print an informational message to the terminal, after starting a new
10503 * line.
10504 *
10505 * Input:
10506 * gl GetLine * The line editor resource object.
10507 * ... const char * Zero or more strings to be printed.
10508 * ... void * The last argument must always be GL_END_INFO.
10509 * Output:
10510 * return int 0 - OK.
10511 * 1 - Error.
10512 */
10513 static int gl_print_info(GetLine *gl, ...)
10514 {
10515 va_list ap; /* The variable argument list */
10516 const char *s; /* The string being printed */
10517 int waserr = 0; /* True after an error */
10518 /*
10519 * Only display output when echoing is on.
10520 */
10521 if(gl->echo) {
10522 /*
10523 * Skip to the start of the next empty line before displaying the message.
10524 */
10525 if(gl_start_newline(gl, 1))
10526 return 1;
10527 /*
10528 * Display the list of provided messages.
10529 */
10530 va_start(ap, gl);
10531 while(!waserr && (s = va_arg(ap, const char *)) != GL_END_INFO)
10532 waserr = gl_print_raw_string(gl, 1, s, -1);
10533 va_end(ap);
10534 /*
10535 * Start a newline.
10536 */
10537 waserr = waserr || gl_print_raw_string(gl, 1, "\n\r", -1);
10538 /*
10539 * Arrange for the input line to be redrawn.
10540 */
10541 gl_queue_redisplay(gl);
10542 };
10543 return waserr;
10544 }
10545
10546 /*.......................................................................
10547 * Go to the start of the next empty line, ready to output miscellaneous
10548 * text to the screen.
10549 *
10550 * Note that when async-signal safety is required, the 'buffered'
10551 * argument must be 0.
10552 *
10553 * Input:
10554 * gl GetLine * The line editor resource object.
10555 * buffered int If true, used buffered I/O when writing to
10556 * the terminal. Otherwise use async-signal-safe
10557 * unbuffered I/O.
10558 * Output:
10559 * return int 0 - OK.
10560 * 1 - Error.
10561 */
10562 static int gl_start_newline(GetLine *gl, int buffered)
10563 {
10564 int waserr = 0; /* True after any I/O error */
10565 /*
10566 * Move the cursor to the start of the terminal line that follows the
10567 * last line of the partially enterred line. In order that this
10568 * function remain async-signal safe when write_fn is signal safe, we
10569 * can't call our normal output functions, since they call tputs(),
10570 * who's signal saftey isn't defined. Fortunately, we can simply use
10571 * \r and \n to move the cursor to the right place.
10572 */
10573 if(gl->displayed) { /* Is an input line currently displayed? */
10574 /*
10575 * On which terminal lines are the cursor and the last character of the
10576 * input line?
10577 */
10578 int curs_line = gl->term_curpos / gl->ncolumn;
10579 int last_line = gl->term_len / gl->ncolumn;
10580 /*
10581 * Move the cursor to the start of the line that follows the last
10582 * terminal line that is occupied by the input line.
10583 */
10584 for( ; curs_line < last_line + 1; curs_line++)
10585 waserr = waserr || gl_print_raw_string(gl, buffered, "\n", 1);
10586 waserr = waserr || gl_print_raw_string(gl, buffered, "\r", 1);
10587 /*
10588 * Mark the line as no longer displayed.
10589 */
10590 gl_line_erased(gl);
10591 };
10592 return waserr;
10593 }
10594
10595 /*.......................................................................
10596 * The callback through which all terminal output is routed.
10597 * This simply appends characters to a queue buffer, which is
10598 * subsequently flushed to the output channel by gl_flush_output().
10599 *
10600 * Input:
10601 * data void * The pointer to a GetLine line editor resource object
10602 * cast to (void *).
10603 * s const char * The string to be written.
10604 * n int The number of characters to write from s[].
10605 * Output:
10606 * return int The number of characters written. This will always
10607 * be equal to 'n' unless an error occurs.
10608 */
10609 static GL_WRITE_FN(gl_write_fn)
10610 {
10611 GetLine *gl = (GetLine *) data;
10612 int ndone = _glq_append_chars(gl->cq, s, n, gl->flush_fn, gl);
10613 if(ndone != n)
10614 _err_record_msg(gl->err, _glq_last_error(gl->cq), END_ERR_MSG);
10615 return ndone;
10616 }
10617
10618 /*.......................................................................
10619 * Ask gl_get_line() what caused it to return.
10620 *
10621 * Input:
10622 * gl GetLine * The line editor resource object.
10623 * Output:
10624 * return GlReturnStatus The return status of the last call to
10625 * gl_get_line().
10626 */
10627 GlReturnStatus gl_return_status(GetLine *gl)
10628 {
10629 GlReturnStatus rtn_status = GLR_ERROR; /* The requested status */
10630 if(gl) {
10631 sigset_t oldset; /* The signals that were blocked on entry to this block */
10632 /*
10633 * Temporarily block all signals.
10634 */
10635 gl_mask_signals(gl, &oldset);
10636 /*
10637 * Access gl while signals are blocked.
10638 */
10639 rtn_status = gl->rtn_status;
10640 /*
10641 * Restore the process signal mask before returning.
10642 */
10643 gl_unmask_signals(gl, &oldset);
10644 };
10645 return rtn_status;
10646 }
10647
10648 /*.......................................................................
10649 * In non-blocking server-I/O mode, this function should be called
10650 * from the application's external event loop to see what type of
10651 * terminal I/O is being waited for by gl_get_line(), and thus what
10652 * direction of I/O to wait for with select() or poll().
10653 *
10654 * Input:
10655 * gl GetLine * The resource object of gl_get_line().
10656 * Output:
10657 * return GlPendingIO The type of pending I/O being waited for.
10658 */
10659 GlPendingIO gl_pending_io(GetLine *gl)
10660 {
10661 GlPendingIO pending_io = GLP_WRITE; /* The requested information */
10662 if(gl) {
10663 sigset_t oldset; /* The signals that were blocked on entry to this block */
10664 /*
10665 * Temporarily block all signals.
10666 */
10667 gl_mask_signals(gl, &oldset);
10668 /*
10669 * Access gl while signals are blocked.
10670 */
10671 pending_io = gl->pending_io;
10672 /*
10673 * Restore the process signal mask before returning.
10674 */
10675 gl_unmask_signals(gl, &oldset);
10676 };
10677 return pending_io;
10678 }
10679
10680 /*.......................................................................
10681 * In server mode, this function configures the terminal for non-blocking
10682 * raw terminal I/O. In normal I/O mode it does nothing.
10683 *
10684 * Callers of this function must be careful to trap all signals that
10685 * terminate or suspend the program, and call gl_normal_io()
10686 * from the corresponding signal handlers in order to restore the
10687 * terminal to its original settings before the program is terminated
10688 * or suspended. They should also trap the SIGCONT signal to detect
10689 * when the program resumes, and ensure that its signal handler
10690 * call gl_raw_io() to redisplay the line and resume editing.
10691 *
10692 * This function is async signal safe.
10693 *
10694 * Input:
10695 * gl GetLine * The line editor resource object.
10696 * Output:
10697 * return int 0 - OK.
10698 * 1 - Error.
10699 */
10700 int gl_raw_io(GetLine *gl)
10701 {
10702 sigset_t oldset; /* The signals that were blocked on entry to this function */
10703 int status; /* The return status of _gl_raw_io() */
10704 /*
10705 * Check the arguments.
10706 */
10707 if(!gl) {
10708 errno = EINVAL;
10709 return 1;
10710 };
10711 /*
10712 * Block all signals.
10713 */
10714 if(gl_mask_signals(gl, &oldset))
10715 return 1;
10716 /*
10717 * Don't allow applications to switch into raw mode unless in server mode.
10718 */
10719 if(gl->io_mode != GL_SERVER_MODE) {
10720 _err_record_msg(gl->err, "Can't switch to raw I/O unless in server mode",
10721 END_ERR_MSG);
10722 errno = EPERM;
10723 status = 1;
10724 } else {
10725 /*
10726 * Execute the private body of the function while signals are blocked.
10727 */
10728 status = _gl_raw_io(gl, 1);
10729 };
10730 /*
10731 * Restore the process signal mask.
10732 */
10733 gl_unmask_signals(gl, &oldset);
10734 return status;
10735 }
10736
10737 /*.......................................................................
10738 * This is the private body of the public function, gl_raw_io().
10739 * It assumes that the caller has checked its arguments and blocked the
10740 * delivery of signals.
10741 *
10742 * This function is async signal safe.
10743 */
10744 static int _gl_raw_io(GetLine *gl, int redisplay)
10745 {
10746 /*
10747 * If we are already in the correct mode, do nothing.
10748 */
10749 if(gl->raw_mode)
10750 return 0;
10751 /*
10752 * Switch the terminal to raw mode.
10753 */
10754 if(gl->is_term && gl_raw_terminal_mode(gl))
10755 return 1;
10756 /*
10757 * Switch to non-blocking I/O mode?
10758 */
10759 if(gl->io_mode==GL_SERVER_MODE &&
10760 (gl_nonblocking_io(gl, gl->input_fd) ||
10761 gl_nonblocking_io(gl, gl->output_fd) ||
10762 (gl->file_fp && gl_nonblocking_io(gl, fileno(gl->file_fp))))) {
10763 if(gl->is_term)
10764 gl_restore_terminal_attributes(gl);
10765 return 1;
10766 };
10767 /*
10768 * If an input line is being entered, arrange for it to be
10769 * displayed.
10770 */
10771 if(redisplay) {
10772 gl->postpone = 0;
10773 gl_queue_redisplay(gl);
10774 };
10775 return 0;
10776 }
10777
10778 /*.......................................................................
10779 * Restore the terminal to the state that it had when
10780 * gl_raw_io() was last called. After calling
10781 * gl_raw_io(), this function must be called before
10782 * terminating or suspending the program, and before attempting other
10783 * uses of the terminal from within the program. See gl_raw_io()
10784 * for more details.
10785 *
10786 * Input:
10787 * gl GetLine * The line editor resource object.
10788 * Output:
10789 * return int 0 - OK.
10790 * 1 - Error.
10791 */
10792 int gl_normal_io(GetLine *gl)
10793 {
10794 sigset_t oldset; /* The signals that were blocked on entry to this function */
10795 int status; /* The return status of _gl_normal_io() */
10796 /*
10797 * Check the arguments.
10798 */
10799 if(!gl) {
10800 errno = EINVAL;
10801 return 1;
10802 };
10803 /*
10804 * Block all signals.
10805 */
10806 if(gl_mask_signals(gl, &oldset))
10807 return 1;
10808 /*
10809 * Execute the private body of the function while signals are blocked.
10810 */
10811 status = _gl_normal_io(gl);
10812 /*
10813 * Restore the process signal mask.
10814 */
10815 gl_unmask_signals(gl, &oldset);
10816 return status;
10817 }
10818
10819 /*.......................................................................
10820 * This is the private body of the public function, gl_normal_io().
10821 * It assumes that the caller has checked its arguments and blocked the
10822 * delivery of signals.
10823 */
10824 static int _gl_normal_io(GetLine *gl)
10825 {
10826 /*
10827 * If we are already in normal mode, do nothing.
10828 */
10829 if(!gl->raw_mode)
10830 return 0;
10831 /*
10832 * Postpone subsequent redisplays until after _gl_raw_io(gl, 1)
10833 * is next called.
10834 */
10835 gl->postpone = 1;
10836 /*
10837 * Switch back to blocking I/O. Note that this is essential to do
10838 * here, because when using non-blocking I/O, the terminal output
10839 * buffering code can't always make room for new output without calling
10840 * malloc(), and a call to malloc() would mean that this function
10841 * couldn't safely be called from signal handlers.
10842 */
10843 if(gl->io_mode==GL_SERVER_MODE &&
10844 (gl_blocking_io(gl, gl->input_fd) ||
10845 gl_blocking_io(gl, gl->output_fd) ||
10846 (gl->file_fp && gl_blocking_io(gl, fileno(gl->file_fp)))))
10847 return 1;
10848 /*
10849 * Move the cursor to the next empty terminal line. Note that
10850 * unbuffered I/O is requested, to ensure that gl_start_newline() be
10851 * async-signal-safe.
10852 */
10853 if(gl->is_term && gl_start_newline(gl, 0))
10854 return 1;
10855 /*
10856 * Switch the terminal to normal mode.
10857 */
10858 if(gl->is_term && gl_restore_terminal_attributes(gl)) {
10859 /*
10860 * On error, revert to non-blocking I/O if needed, so that on failure
10861 * we remain in raw mode.
10862 */
10863 if(gl->io_mode==GL_SERVER_MODE) {
10864 gl_nonblocking_io(gl, gl->input_fd);
10865 gl_nonblocking_io(gl, gl->output_fd);
10866 if(gl->file_fp)
10867 gl_nonblocking_io(gl, fileno(gl->file_fp));
10868 };
10869 return 1;
10870 };
10871 return 0;
10872 }
10873
10874 /*.......................................................................
10875 * This function allows you to install an additional completion
10876 * action, or to change the completion function of an existing
10877 * one. This should be called before the first call to gl_get_line()
10878 * so that the name of the action be defined before the user's
10879 * configuration file is read.
10880 *
10881 * Input:
10882 * gl GetLine * The resource object of the command-line input
10883 * module.
10884 * data void * This is passed to match_fn() whenever it is
10885 * called. It could, for example, point to a
10886 * symbol table that match_fn() would look up
10887 * matches in.
10888 * match_fn CplMatchFn * The function that will identify the prefix
10889 * to be completed from the input line, and
10890 * report matching symbols.
10891 * list_only int If non-zero, install an action that only lists
10892 * possible completions, rather than attempting
10893 * to perform the completion.
10894 * name const char * The name with which users can refer to the
10895 * binding in tecla configuration files.
10896 * keyseq const char * Either NULL, or a key sequence with which
10897 * to invoke the binding. This should be
10898 * specified in the same manner as key-sequences
10899 * in tecla configuration files (eg. "M-^I").
10900 * Output:
10901 * return int 0 - OK.
10902 * 1 - Error.
10903 */
10904 int gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
10905 int list_only, const char *name, const char *keyseq)
10906 {
10907 sigset_t oldset; /* The signals that were blocked on entry to this function */
10908 int status; /* The return status of _gl_completion_action() */
10909 /*
10910 * Check the arguments.
10911 */
10912 if(!gl || !name || !match_fn) {
10913 errno = EINVAL;
10914 return 1;
10915 };
10916 /*
10917 * Block all signals.
10918 */
10919 if(gl_mask_signals(gl, &oldset))
10920 return 1;
10921 /*
10922 * Install the new action while signals are blocked.
10923 */
10924 status = _gl_completion_action(gl, data, match_fn, list_only, name, keyseq);
10925 /*
10926 * Restore the process signal mask.
10927 */
10928 gl_unmask_signals(gl, &oldset);
10929 return status;
10930 }
10931
10932 /*.......................................................................
10933 * This is the private body of the public function, gl_completion_action().
10934 * It assumes that the caller has checked its arguments and blocked the
10935 * delivery of signals.
10936 */
10937 static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
10938 int list_only, const char *name,
10939 const char *keyseq)
10940 {
10941 KtKeyFn *current_fn; /* An existing action function */
10942 void *current_data; /* The action-function callback data */
10943 /*
10944 * Which action function is desired?
10945 */
10946 KtKeyFn *action_fn = list_only ? gl_list_completions : gl_complete_word;
10947 /*
10948 * Is there already an action of the specified name?
10949 */
10950 if(_kt_lookup_action(gl->bindings, name, ¤t_fn, ¤t_data) == 0) {
10951 /*
10952 * If the action has the same type as the one being requested,
10953 * simply change the contents of its GlCplCallback callback data.
10954 */
10955 if(current_fn == action_fn) {
10956 GlCplCallback *cb = (GlCplCallback *) current_data;
10957 cb->fn = match_fn;
10958 cb->data = data;
10959 } else {
10960 errno = EINVAL;
10961 _err_record_msg(gl->err,
10962 "Illegal attempt to change the type of an existing completion action",
10963 END_ERR_MSG);
10964 return 1;
10965 };
10966 /*
10967 * No existing action has the specified name.
10968 */
10969 } else {
10970 /*
10971 * Allocate a new GlCplCallback callback object.
10972 */
10973 GlCplCallback *cb = (GlCplCallback *) _new_FreeListNode(gl->cpl_mem);
10974 if(!cb) {
10975 errno = ENOMEM;
10976 _err_record_msg(gl->err, "Insufficient memory to add completion action",
10977 END_ERR_MSG);
10978 return 1;
10979 };
10980 /*
10981 * Record the completion callback data.
10982 */
10983 cb->fn = match_fn;
10984 cb->data = data;
10985 /*
10986 * Attempt to register the new action.
10987 */
10988 if(_kt_set_action(gl->bindings, name, action_fn, cb)) {
10989 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
10990 _del_FreeListNode(gl->cpl_mem, (void *) cb);
10991 return 1;
10992 };
10993 };
10994 /*
10995 * Bind the action to a given key-sequence?
10996 */
10997 if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) {
10998 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
10999 return 1;
11000 };
11001 return 0;
11002 }
11003
11004 /*.......................................................................
11005 * Register an application-provided function as an action function.
11006 * This should preferably be called before the first call to gl_get_line()
11007 * so that the name of the action becomes defined before the user's
11008 * configuration file is read.
11009 *
11010 * Input:
11011 * gl GetLine * The resource object of the command-line input
11012 * module.
11013 * data void * Arbitrary application-specific callback
11014 * data to be passed to the callback
11015 * function, fn().
11016 * fn GlActionFn * The application-specific function that
11017 * implements the action. This will be invoked
11018 * whenever the user presses any
11019 * key-sequence which is bound to this action.
11020 * name const char * The name with which users can refer to the
11021 * binding in tecla configuration files.
11022 * keyseq const char * The key sequence with which to invoke
11023 * the binding. This should be specified in the
11024 * same manner as key-sequences in tecla
11025 * configuration files (eg. "M-^I").
11026 * Output:
11027 * return int 0 - OK.
11028 * 1 - Error.
11029 */
11030 int gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
11031 const char *name, const char *keyseq)
11032 {
11033 sigset_t oldset; /* The signals that were blocked on entry to this function */
11034 int status; /* The return status of _gl_register_action() */
11035 /*
11036 * Check the arguments.
11037 */
11038 if(!gl || !name || !fn) {
11039 errno = EINVAL;
11040 return 1;
11041 };
11042 /*
11043 * Block all signals.
11044 */
11045 if(gl_mask_signals(gl, &oldset))
11046 return 1;
11047 /*
11048 * Install the new action while signals are blocked.
11049 */
11050 status = _gl_register_action(gl, data, fn, name, keyseq);
11051 /*
11052 * Restore the process signal mask.
11053 */
11054 gl_unmask_signals(gl, &oldset);
11055 return status;
11056 }
11057
11058 /*.......................................................................
11059 * This is the private body of the public function, gl_register_action().
11060 * It assumes that the caller has checked its arguments and blocked the
11061 * delivery of signals.
11062 */
11063 static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
11064 const char *name, const char *keyseq)
11065 {
11066 KtKeyFn *current_fn; /* An existing action function */
11067 void *current_data; /* The action-function callback data */
11068 /*
11069 * Get the action function which actually runs the application-provided
11070 * function.
11071 */
11072 KtKeyFn *action_fn = gl_run_external_action;
11073 /*
11074 * Is there already an action of the specified name?
11075 */
11076 if(_kt_lookup_action(gl->bindings, name, ¤t_fn, ¤t_data) == 0) {
11077 /*
11078 * If the action has the same type as the one being requested,
11079 * simply change the contents of its GlCplCallback callback data.
11080 */
11081 if(current_fn == action_fn) {
11082 GlExternalAction *a = (GlExternalAction *) current_data;
11083 a->fn = fn;
11084 a->data = data;
11085 } else {
11086 errno = EINVAL;
11087 _err_record_msg(gl->err,
11088 "Illegal attempt to change the type of an existing action",
11089 END_ERR_MSG);
11090 return 1;
11091 };
11092 /*
11093 * No existing action has the specified name.
11094 */
11095 } else {
11096 /*
11097 * Allocate a new GlCplCallback callback object.
11098 */
11099 GlExternalAction *a =
11100 (GlExternalAction *) _new_FreeListNode(gl->ext_act_mem);
11101 if(!a) {
11102 errno = ENOMEM;
11103 _err_record_msg(gl->err, "Insufficient memory to add completion action",
11104 END_ERR_MSG);
11105 return 1;
11106 };
11107 /*
11108 * Record the completion callback data.
11109 */
11110 a->fn = fn;
11111 a->data = data;
11112 /*
11113 * Attempt to register the new action.
11114 */
11115 if(_kt_set_action(gl->bindings, name, action_fn, a)) {
11116 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
11117 _del_FreeListNode(gl->cpl_mem, (void *) a);
11118 return 1;
11119 };
11120 };
11121 /*
11122 * Bind the action to a given key-sequence?
11123 */
11124 if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) {
11125 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
11126 return 1;
11127 };
11128 return 0;
11129 }
11130
11131 /*.......................................................................
11132 * Invoke an action function previously registered by a call to
11133 * gl_register_action().
11134 */
11135 static KT_KEY_FN(gl_run_external_action)
11136 {
11137 GlAfterAction status; /* The return value of the action function */
11138 /*
11139 * Get the container of the action function and associated callback data.
11140 */
11141 GlExternalAction *a = (GlExternalAction *) data;
11142 /*
11143 * Invoke the action function.
11144 */
11145 status = a->fn(gl, a->data, count, gl->buff_curpos, gl->line);
11146 /*
11147 * If the callback took us out of raw (possibly non-blocking) input
11148 * mode, restore this mode, and queue a redisplay of the input line.
11149 */
11150 if(_gl_raw_io(gl, 1))
11151 return 1;
11152 /*
11153 * Finally, check to see what the action function wants us to do next.
11154 */
11155 switch(status) {
11156 default:
11157 case GLA_ABORT:
11158 gl_record_status(gl, GLR_ERROR, errno);
11159 return 1;
11160 break;
11161 case GLA_RETURN:
11162 return gl_newline(gl, 1, NULL);
11163 break;
11164 case GLA_CONTINUE:
11165 break;
11166 };
11167 return 0;
11168 }
11169
11170 /*.......................................................................
11171 * In server-I/O mode the terminal is left in raw mode between calls
11172 * to gl_get_line(), so it is necessary for the application to install
11173 * terminal restoring signal handlers for signals that could terminate
11174 * or suspend the process, plus a terminal reconfiguration handler to
11175 * be called when a process resumption signal is received, and finally
11176 * a handler to be called when a terminal-resize signal is received.
11177 *
11178 * Since there are many signals that by default terminate or suspend
11179 * processes, and different systems support different sub-sets of
11180 * these signals, this function provides a convenient wrapper around
11181 * sigaction() for assigning the specified handlers to all appropriate
11182 * signals. It also arranges that when any one of these signals is
11183 * being handled, all other catchable signals are blocked. This is
11184 * necessary so that the specified signal handlers can safely call
11185 * gl_raw_io(), gl_normal_io() and gl_update_size() without
11186 * reentrancy issues.
11187 *
11188 * Input:
11189 * term_handler void (*)(int) The signal handler to invoke when
11190 * a process-terminating signal is
11191 * received.
11192 * susp_handler void (*)(int) The signal handler to invoke when
11193 * a process-suspending signal is
11194 * received.
11195 * cont_handler void (*)(int) The signal handler to invoke when
11196 * a process-resumption signal is
11197 * received (ie. SIGCONT).
11198 * size_handler void (*)(int) The signal handler to invoke when
11199 * a terminal-resize signal (ie. SIGWINCH)
11200 * is received.
11201 * Output:
11202 * return int 0 - OK.
11203 * 1 - Error.
11204 */
11205 int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int),
11206 void (*cont_handler)(int), void (*size_handler)(int))
11207 {
11208 int i;
11209 /*
11210 * Search for signals of the specified classes, and assign the
11211 * associated signal handler to them.
11212 */
11213 for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
11214 const struct GlDefSignal *sig = gl_signal_list + i;
11215 if(sig->attr & GLSA_SUSP) {
11216 if(gl_set_tty_signal(sig->signo, susp_handler))
11217 return 1;
11218 } else if(sig->attr & GLSA_TERM) {
11219 if(gl_set_tty_signal(sig->signo, term_handler))
11220 return 1;
11221 } else if(sig->attr & GLSA_CONT) {
11222 if(gl_set_tty_signal(sig->signo, cont_handler))
11223 return 1;
11224 } else if(sig->attr & GLSA_SIZE) {
11225 if(gl_set_tty_signal(sig->signo, size_handler))
11226 return 1;
11227 };
11228 };
11229 return 0;
11230 }
11231
11232 /*.......................................................................
11233 * This is a private function of gl_tty_signals(). It installs a given
11234 * signal handler, and arranges that when that signal handler is being
11235 * invoked other signals are blocked. The latter is important to allow
11236 * functions like gl_normal_io(), gl_raw_io() and gl_update_size()
11237 * to be called from signal handlers.
11238 *
11239 * Input:
11240 * signo int The signal to be trapped.
11241 * handler void (*)(int) The signal handler to assign to the signal.
11242 */
11243 static int gl_set_tty_signal(int signo, void (*handler)(int))
11244 {
11245 SigAction act; /* The signal handler configuation */
11246 /*
11247 * Arrange to block all trappable signals except the one that is being
11248 * assigned (the trapped signal will be blocked automatically by the
11249 * system).
11250 */
11251 gl_list_trappable_signals(&act.sa_mask);
11252 sigdelset(&act.sa_mask, signo);
11253 /*
11254 * Assign the signal handler.
11255 */
11256 act.sa_handler = handler;
11257 /*
11258 * There is only one portable signal handling flag, and it isn't
11259 * relevant to us, so don't specify any flags.
11260 */
11261 act.sa_flags = 0;
11262 /*
11263 * Register the signal handler.
11264 */
11265 if(sigaction(signo, &act, NULL))
11266 return 1;
11267 return 0;
11268 }
11269
11270 /*.......................................................................
11271 * Display a left-justified string over multiple terminal lines,
11272 * taking account of the current width of the terminal. Optional
11273 * indentation and an optional prefix string can be specified to be
11274 * displayed at the start of each new terminal line used. Similarly,
11275 * an optional suffix can be specified to be displayed at the end of
11276 * each terminal line. If needed, a single paragraph can be broken
11277 * across multiple calls. Note that literal newlines in the input
11278 * string can be used to force a newline at any point and that you
11279 * should use this feature to explicitly end all paragraphs, including
11280 * at the end of the last string that you write. Note that when a new
11281 * line is started between two words that are separated by spaces,
11282 * those spaces are not output, whereas when a new line is started
11283 * because a newline character was found in the string, only the
11284 * spaces before the newline character are discarded.
11285 *
11286 * Input:
11287 * gl GetLine * The resource object of gl_get_line().
11288 * indentation int The number of spaces of indentation to write
11289 * at the beginning of each new terminal line.
11290 * prefix const char * An optional prefix string to write after the
11291 * indentation margin at the start of each new
11292 * terminal line. You can specify NULL if no
11293 * prefix is required.
11294 * suffix const char * An optional suffix string to draw at the end
11295 * of the terminal line. Spaces will be added
11296 * where necessary to ensure that the suffix ends
11297 * in the last column of the terminal line. If
11298 * no suffix is desired, specify NULL.
11299 * fill_char int The padding character to use when indenting
11300 * the line or padding up to the suffix.
11301 * def_width int If the terminal width isn't known, such as when
11302 * writing to a pipe or redirecting to a file,
11303 * this number specifies what width to assume.
11304 * start int The number of characters already written to
11305 * the start of the current terminal line. This
11306 * is primarily used to allow individual
11307 * paragraphs to be written over multiple calls
11308 * to this function, but can also be used to
11309 * allow you to start the first line of a
11310 * paragraph with a different prefix or
11311 * indentation than those specified above.
11312 * string const char * The string to be written.
11313 * Output:
11314 * return int On error -1 is returned. Otherwise the
11315 * return value is the terminal column index at
11316 * which the cursor was left after writing the
11317 * final word in the string. Successful return
11318 * values can thus be passed verbatim to the
11319 * 'start' arguments of subsequent calls to
11320 * gl_display_text() to allow the printing of a
11321 * paragraph to be broken across multiple calls
11322 * to gl_display_text().
11323 */
11324 int gl_display_text(GetLine *gl, int indentation, const char *prefix,
11325 const char *suffix, int fill_char,
11326 int def_width, int start, const char *string)
11327 {
11328 sigset_t oldset; /* The signals that were blocked on entry to this function */
11329 int status; /* The return status of _gl_completion_action() */
11330 /*
11331 * Check the arguments?
11332 */
11333 if(!gl || !string) {
11334 errno = EINVAL;
11335 return -1;
11336 };
11337 /*
11338 * Block all signals.
11339 */
11340 if(gl_mask_signals(gl, &oldset))
11341 return -1;
11342 /*
11343 * Display the text while signals are blocked.
11344 */
11345 status = _io_display_text(_io_write_stdio, gl->output_fp, indentation,
11346 prefix, suffix, fill_char,
11347 gl->ncolumn > 0 ? gl->ncolumn : def_width,
11348 start, string);
11349 /*
11350 * Restore the process signal mask.
11351 */
11352 gl_unmask_signals(gl, &oldset);
11353 return status;
11354 }
11355
11356 /*.......................................................................
11357 * Block all of the signals that we are currently trapping.
11358 *
11359 * Input:
11360 * gl GetLine * The resource object of gl_get_line().
11361 * Input/Output:
11362 * oldset sigset_t * The superseded process signal mask
11363 * will be return in *oldset unless oldset is
11364 * NULL.
11365 * Output:
11366 * return int 0 - OK.
11367 * 1 - Error.
11368 */
11369 static int gl_mask_signals(GetLine *gl, sigset_t *oldset)
11370 {
11371 /*
11372 * Block all signals in all_signal_set, along with any others that are
11373 * already blocked by the application.
11374 */
11375 if(sigprocmask(SIG_BLOCK, &gl->all_signal_set, oldset) >= 0) {
11376 gl->signals_masked = 1;
11377 return 0;
11378 };
11379 /*
11380 * On error attempt to query the current process signal mask, so
11381 * that oldset be the correct process signal mask to restore later
11382 * if the caller of this function ignores the error return value.
11383 */
11384 if(oldset)
11385 (void) sigprocmask(SIG_SETMASK, NULL, oldset);
11386 gl->signals_masked = 0;
11387 return 1;
11388 }
11389
11390 /*.......................................................................
11391 * Restore a process signal mask that was previously returned via the
11392 * oldset argument of gl_mask_signals().
11393 *
11394 * Input:
11395 * gl GetLine * The resource object of gl_get_line().
11396 * Input/Output:
11397 * oldset sigset_t * The process signal mask to be restored.
11398 * Output:
11399 * return int 0 - OK.
11400 * 1 - Error.
11401 */
11402 static int gl_unmask_signals(GetLine *gl, sigset_t *oldset)
11403 {
11404 gl->signals_masked = 0;
11405 return sigprocmask(SIG_SETMASK, oldset, NULL) < 0;
11406 }
11407
11408 /*.......................................................................
11409 * Arrange to temporarily catch the signals marked in gl->use_signal_set.
11410 *
11411 * Input:
11412 * gl GetLine * The resource object of gl_get_line().
11413 * Output:
11414 * return int 0 - OK.
11415 * 1 - Error.
11416 */
11417 static int gl_catch_signals(GetLine *gl)
11418 {
11419 return sigprocmask(SIG_UNBLOCK, &gl->use_signal_set, NULL) < 0;
11420 }
11421
11422 /*.......................................................................
11423 * Select the I/O mode to be used by gl_get_line().
11424 *
11425 * Input:
11426 * gl GetLine * The resource object of gl_get_line().
11427 * mode GlIOMode The I/O mode to establish.
11428 * Output:
11429 * return int 0 - OK.
11430 * 1 - Error.
11431 */
11432 int gl_io_mode(GetLine *gl, GlIOMode mode)
11433 {
11434 sigset_t oldset; /* The signals that were blocked on entry to this function */
11435 int status; /* The return status of _gl_io_mode() */
11436 /*
11437 * Check the arguments.
11438 */
11439 if(!gl) {
11440 errno = EINVAL;
11441 return 1;
11442 };
11443 /*
11444 * Check that the requested mode is known.
11445 */
11446 switch(mode) {
11447 case GL_NORMAL_MODE:
11448 case GL_SERVER_MODE:
11449 break;
11450 default:
11451 errno = EINVAL;
11452 _err_record_msg(gl->err, "Unknown gl_get_line() I/O mode requested.",
11453 END_ERR_MSG);
11454 return 1;
11455 };
11456 /*
11457 * Block all signals.
11458 */
11459 if(gl_mask_signals(gl, &oldset))
11460 return 1;
11461 /*
11462 * Invoke the private body of this function.
11463 */
11464 status = _gl_io_mode(gl, mode);
11465 /*
11466 * Restore the process signal mask.
11467 */
11468 gl_unmask_signals(gl, &oldset);
11469 return status;
11470 }
11471
11472 /*.......................................................................
11473 * This is the private body of the public function, gl_io_mode().
11474 * It assumes that the caller has checked its arguments and blocked the
11475 * delivery of signals.
11476 */
11477 static int _gl_io_mode(GetLine *gl, GlIOMode mode)
11478 {
11479 /*
11480 * Are we already in the specified mode?
11481 */
11482 if(mode == gl->io_mode)
11483 return 0;
11484 /*
11485 * First revert to normal I/O in the current I/O mode.
11486 */
11487 _gl_normal_io(gl);
11488 /*
11489 * Record the new mode.
11490 */
11491 gl->io_mode = mode;
11492 /*
11493 * Perform any actions needed by the new mode.
11494 */
11495 if(mode==GL_SERVER_MODE) {
11496 if(_gl_raw_io(gl, 1))
11497 return 1;
11498 };
11499 return 0;
11500 }
11501
11502 /*.......................................................................
11503 * Return extra information (ie. in addition to that provided by errno)
11504 * about the last error to occur in either gl_get_line() or its
11505 * associated public functions.
11506 *
11507 * Input:
11508 * gl GetLine * The resource object of gl_get_line().
11509 * Input/Output:
11510 * buff char * An optional output buffer. Note that if the
11511 * calling application calls any gl_*()
11512 * functions from signal handlers, it should
11513 * provide a buffer here, so that a copy of
11514 * the latest error message can safely be made
11515 * while signals are blocked.
11516 * n size_t The allocated size of buff[].
11517 * Output:
11518 * return const char * A pointer to the error message. This will
11519 * be the buff argument, unless buff==NULL, in
11520 * which case it will be a pointer to an
11521 * internal error buffer. In the latter case,
11522 * note that the contents of the returned buffer
11523 * will change on subsequent calls to any gl_*()
11524 * functions.
11525 */
11526 const char *gl_error_message(GetLine *gl, char *buff, size_t n)
11527 {
11528 if(!gl) {
11529 static const char *msg = "NULL GetLine argument";
11530 if(buff) {
11531 strncpy(buff, msg, n);
11532 buff[n-1] = '\0';
11533 } else {
11534 return msg;
11535 };
11536 } else if(buff) {
11537 sigset_t oldset; /* The signals that were blocked on entry to this block */
11538 /*
11539 * Temporarily block all signals.
11540 */
11541 gl_mask_signals(gl, &oldset);
11542 /*
11543 * Copy the error message into the specified buffer.
11544 */
11545 if(buff && n > 0) {
11546 strncpy(buff, _err_get_msg(gl->err), n);
11547 buff[n-1] = '\0';
11548 };
11549 /*
11550 * Restore the process signal mask before returning.
11551 */
11552 gl_unmask_signals(gl, &oldset);
11553 } else {
11554 return _err_get_msg(gl->err);
11555 };
11556 return buff;
11557 }
11558
11559 /*.......................................................................
11560 * Return the signal mask used by gl_get_line(). This is the set of
11561 * signals that gl_get_line() is currently configured to trap.
11562 *
11563 * Input:
11564 * gl GetLine * The resource object of gl_get_line().
11565 * Input/Output:
11566 * set sigset_t * The set of signals will be returned in *set,
11567 * in the form of a signal process mask, as
11568 * used by sigaction(), sigprocmask(),
11569 * sigpending(), sigsuspend(), sigsetjmp() and
11570 * other standard POSIX signal-aware
11571 * functions.
11572 * Output:
11573 * return int 0 - OK.
11574 * 1 - Error (examine errno for reason).
11575 */
11576 int gl_list_signals(GetLine *gl, sigset_t *set)
11577 {
11578 /*
11579 * Check the arguments.
11580 */
11581 if(!gl || !set) {
11582 if(gl)
11583 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
11584 errno = EINVAL;
11585 return 1;
11586 };
11587 /*
11588 * Copy the signal mask into *set.
11589 */
11590 memcpy(set, &gl->all_signal_set, sizeof(*set));
11591 return 0;
11592 }
11593
11594 /*.......................................................................
11595 * By default, gl_get_line() doesn't trap signals that are blocked
11596 * when it is called. This default can be changed either on a
11597 * per-signal basis by calling gl_trap_signal(), or on a global basis
11598 * by calling this function. What this function does is add the
11599 * GLS_UNBLOCK_SIG flag to all signals that are currently configured
11600 * to be trapped by gl_get_line(), such that when subsequent calls to
11601 * gl_get_line() wait for I/O, these signals are temporarily
11602 * unblocked. This behavior is useful in non-blocking server-I/O mode,
11603 * where it is used to avoid race conditions related to handling these
11604 * signals externally to gl_get_line(). See the demonstration code in
11605 * demo3.c, or the gl_handle_signal() man page for further
11606 * information.
11607 *
11608 * Input:
11609 * gl GetLine * The resource object of gl_get_line().
11610 */
11611 void gl_catch_blocked(GetLine *gl)
11612 {
11613 sigset_t oldset; /* The process signal mask to restore */
11614 GlSignalNode *sig; /* A signal node in gl->sigs */
11615 /*
11616 * Check the arguments.
11617 */
11618 if(!gl) {
11619 errno = EINVAL;
11620 return;
11621 };
11622 /*
11623 * Temporarily block all signals while we modify the contents of gl.
11624 */
11625 gl_mask_signals(gl, &oldset);
11626 /*
11627 * Add the GLS_UNBLOCK_SIG flag to all configured signals.
11628 */
11629 for(sig=gl->sigs; sig; sig=sig->next)
11630 sig->flags |= GLS_UNBLOCK_SIG;
11631 /*
11632 * Restore the process signal mask that was superseded by the call
11633 * to gl_mask_signals().
11634 */
11635 gl_unmask_signals(gl, &oldset);
11636 return;
11637 }
11638
11639 /*.......................................................................
11640 * Respond to signals who's default effects have important
11641 * consequences to gl_get_line(). This is intended for use in
11642 * non-blocking server mode, where the external event loop is
11643 * responsible for catching signals. Signals that are handled include
11644 * those that by default terminate or suspend the process, and the
11645 * signal that indicates that the terminal size has changed. Note that
11646 * this function is not signal safe and should thus not be called from
11647 * a signal handler itself. See the gl_io_mode() man page for how it
11648 * should be used.
11649 *
11650 * In the case of signals that by default terminate or suspend
11651 * processes, command-line editing will be suspended, the terminal
11652 * returned to a usable state, then the default disposition of the
11653 * signal restored and the signal resent, in order to suspend or
11654 * terminate the process. If the process subsequently resumes,
11655 * command-line editing is resumed.
11656 *
11657 * In the case of signals that indicate that the terminal has been
11658 * resized, the new size will be queried, and any input line that is
11659 * being edited will be redrawn to fit the new dimensions of the
11660 * terminal.
11661 *
11662 * Input:
11663 * signo int The number of the signal to respond to.
11664 * gl GetLine * The first element of an array of 'ngl' GetLine
11665 * objects.
11666 * ngl int The number of elements in the gl[] array. Normally
11667 * this will be one.
11668 */
11669 void gl_handle_signal(int signo, GetLine *gl, int ngl)
11670 {
11671 int attr; /* The attributes of the specified signal */
11672 sigset_t all_signals; /* The set of trappable signals */
11673 sigset_t oldset; /* The process signal mask to restore */
11674 int i;
11675 /*
11676 * NULL operation?
11677 */
11678 if(ngl < 1 || !gl)
11679 return;
11680 /*
11681 * Look up the default attributes of the specified signal.
11682 */
11683 attr = gl_classify_signal(signo);
11684 /*
11685 * If the signal isn't known, we are done.
11686 */
11687 if(!attr)
11688 return;
11689 /*
11690 * Temporarily block all signals while we modify the gl objects.
11691 */
11692 gl_list_trappable_signals(&all_signals);
11693 sigprocmask(SIG_BLOCK, &all_signals, &oldset);
11694 /*
11695 * Suspend or terminate the process?
11696 */
11697 if(attr & (GLSA_SUSP | GLSA_TERM)) {
11698 gl_suspend_process(signo, gl, ngl);
11699 /*
11700 * Resize the terminal? Note that ioctl() isn't defined as being
11701 * signal safe, so we can't call gl_update_size() here. However,
11702 * gl_get_line() checks for resizes on each call, so simply arrange
11703 * for the application's event loop to call gl_get_line() as soon as
11704 * it becomes possible to write to the terminal. Note that if the
11705 * caller is calling select() or poll when this happens, these functions
11706 * get interrupted, since a signal has been caught.
11707 */
11708 } else if(attr & GLSA_SIZE) {
11709 for(i=0; i<ngl; i++)
11710 gl[i].pending_io = GLP_WRITE;
11711 };
11712 /*
11713 * Restore the process signal mask that was superseded by the call
11714 * to gl_mask_signals().
11715 */
11716 sigprocmask(SIG_SETMASK, &oldset, NULL);
11717 return;
11718 }
11719
11720 /*.......................................................................
11721 * Respond to an externally caught process suspension or
11722 * termination signal.
11723 *
11724 * After restoring the terminal to a usable state, suspend or
11725 * terminate the calling process, using the original signal with its
11726 * default disposition restored to do so. If the process subsequently
11727 * resumes, resume editing any input lines that were being entered.
11728 *
11729 * Input:
11730 * signo int The signal number to suspend the process with. Note
11731 * that the default disposition of this signal will be
11732 * restored before the signal is sent, so provided
11733 * that the default disposition of this signal is to
11734 * either suspend or terminate the application,
11735 * that is what wil happen, regardless of what signal
11736 * handler is currently assigned to this signal.
11737 * gl GetLine * The first element of an array of 'ngl' GetLine objects
11738 * whose terminals should be restored to a sane state
11739 * while the application is suspended.
11740 * ngl int The number of elements in the gl[] array.
11741 */
11742 static void gl_suspend_process(int signo, GetLine *gl, int ngl)
11743 {
11744 sigset_t only_signo; /* A signal set containing just signo */
11745 sigset_t oldset; /* The signal mask on entry to this function */
11746 sigset_t all_signals; /* A signal set containing all signals */
11747 struct sigaction old_action; /* The current signal handler */
11748 struct sigaction def_action; /* The default signal handler */
11749 int i;
11750 /*
11751 * Create a signal mask containing the signal that was trapped.
11752 */
11753 sigemptyset(&only_signo);
11754 sigaddset(&only_signo, signo);
11755 /*
11756 * Temporarily block all signals.
11757 */
11758 gl_list_trappable_signals(&all_signals);
11759 sigprocmask(SIG_BLOCK, &all_signals, &oldset);
11760 /*
11761 * Restore the terminal to a usable state.
11762 */
11763 for(i=0; i<ngl; i++) {
11764 GetLine *obj = gl + i;
11765 if(obj->raw_mode) {
11766 _gl_normal_io(obj);
11767 if(!obj->raw_mode) /* Check that gl_normal_io() succeded */
11768 obj->raw_mode = -1; /* Flag raw mode as needing to be restored */
11769 };
11770 };
11771 /*
11772 * Restore the system default disposition of the signal that we
11773 * caught. Note that this signal is currently blocked. Note that we
11774 * don't use memcpy() to copy signal sets here, because the signal safety
11775 * of memcpy() is undefined.
11776 */
11777 def_action.sa_handler = SIG_DFL;
11778 {
11779 char *orig = (char *) &all_signals;
11780 char *dest = (char *) &def_action.sa_mask;
11781 for(i=0; i<sizeof(sigset_t); i++)
11782 *dest++ = *orig++;
11783 };
11784 sigaction(signo, &def_action, &old_action);
11785 /*
11786 * Resend the signal, and unblock it so that it gets delivered to
11787 * the application. This will invoke the default action of this signal.
11788 */
11789 raise(signo);
11790 sigprocmask(SIG_UNBLOCK, &only_signo, NULL);
11791 /*
11792 * If the process resumes again, it will resume here.
11793 * Block the signal again, then restore our signal handler.
11794 */
11795 sigprocmask(SIG_BLOCK, &only_signo, NULL);
11796 sigaction(signo, &old_action, NULL);
11797 /*
11798 * Resume command-line editing.
11799 */
11800 for(i=0; i<ngl; i++) {
11801 GetLine *obj = gl + i;
11802 if(obj->raw_mode == -1) { /* Did we flag the need to restore raw mode? */
11803 obj->raw_mode = 0; /* gl_raw_io() does nothing unless raw_mode==0 */
11804 _gl_raw_io(obj, 1);
11805 };
11806 };
11807 /*
11808 * Restore the process signal mask to the way it was when this function
11809 * was called.
11810 */
11811 sigprocmask(SIG_SETMASK, &oldset, NULL);
11812 return;
11813 }
11814
11815 /*.......................................................................
11816 * Return the information about the default attributes of a given signal.
11817 * The attributes that are returned are as defined by the standards that
11818 * created them, including POSIX, SVR4 and 4.3+BSD, and are taken from a
11819 * table in Richard Steven's book, "Advanced programming in the UNIX
11820 * environment".
11821 *
11822 * Input:
11823 * signo int The signal to be characterized.
11824 * Output:
11825 * return int A bitwise union of GlSigAttr enumerators, or 0
11826 * if the signal isn't known.
11827 */
11828 static int gl_classify_signal(int signo)
11829 {
11830 int i;
11831 /*
11832 * Search for the specified signal in the gl_signal_list[] table.
11833 */
11834 for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
11835 const struct GlDefSignal *sig = gl_signal_list + i;
11836 if(sig->signo == signo)
11837 return sig->attr;
11838 };
11839 /*
11840 * Signal not known.
11841 */
11842 return 0;
11843 }
11844
11845 /*.......................................................................
11846 * When in non-blocking server mode, this function can be used to abandon
11847 * the current incompletely entered input line, and prepare to start
11848 * editing a new line on the next call to gl_get_line().
11849 *
11850 * Input:
11851 * gl GetLine * The line editor resource object.
11852 */
11853 void gl_abandon_line(GetLine *gl)
11854 {
11855 sigset_t oldset; /* The process signal mask to restore */
11856 /*
11857 * Check the arguments.
11858 */
11859 if(!gl) {
11860 errno = EINVAL;
11861 return;
11862 };
11863 /*
11864 * Temporarily block all signals while we modify the contents of gl.
11865 */
11866 gl_mask_signals(gl, &oldset);
11867 /*
11868 * Mark the input line as discarded.
11869 */
11870 _gl_abandon_line(gl);
11871 /*
11872 * Restore the process signal mask that was superseded by the call
11873 * to gl_mask_signals().
11874 */
11875 gl_unmask_signals(gl, &oldset);
11876 return;
11877 }
11878
11879 /*.......................................................................
11880 * This is the private body of the gl_abandon_line() function. It
11881 * assumes that the caller has checked its arguments and blocked the
11882 * delivery of signals.
11883 */
11884 void _gl_abandon_line(GetLine *gl)
11885 {
11886 gl->endline = 1;
11887 gl->pending_io = GLP_WRITE;
11888 }
11889
11890 /*.......................................................................
11891 * How many characters are needed to write a number as an octal string?
11892 *
11893 * Input:
11894 * num unsigned The to be measured.
11895 * Output:
11896 * return int The number of characters needed.
11897 */
11898 static int gl_octal_width(unsigned num)
11899 {
11900 int n; /* The number of characters needed to render the number */
11901 for(n=1; num /= 8; n++)
11902 ;
11903 return n;
11904 }
11905
11906 /*.......................................................................
11907 * Tell gl_get_line() the current terminal size. Note that this is only
11908 * necessary on systems where changes in terminal size aren't reported
11909 * via SIGWINCH.
11910 *
11911 * Input:
11912 * gl GetLine * The resource object of gl_get_line().
11913 * ncolumn int The number of columns in the terminal.
11914 * nline int The number of lines in the terminal.
11915 * Output:
11916 * return int 0 - OK.
11917 * 1 - Error.
11918 */
11919 int gl_set_term_size(GetLine *gl, int ncolumn, int nline)
11920 {
11921 sigset_t oldset; /* The signals that were blocked on entry */
11922 /* to this function */
11923 int status; /* The return status */
11924 /*
11925 * Block all signals while accessing gl.
11926 */
11927 gl_mask_signals(gl, &oldset);
11928 /*
11929 * Install the new terminal size.
11930 */
11931 status = _gl_set_term_size(gl, ncolumn, nline);
11932 /*
11933 * Restore the process signal mask before returning.
11934 */
11935 gl_unmask_signals(gl, &oldset);
11936 return status;
11937 }
11938
11939 /*.......................................................................
11940 * This is the private body of the gl_set_term_size() function. It
11941 * assumes that the caller has checked its arguments and blocked the
11942 * delivery of signals.
11943 */
11944 static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline)
11945 {
11946 /*
11947 * Check the arguments.
11948 */
11949 if(!gl) {
11950 errno = EINVAL;
11951 return 1;
11952 };
11953 /*
11954 * Reject non-sensical dimensions.
11955 */
11956 if(ncolumn <= 0 || nline <= 0) {
11957 _err_record_msg(gl->err, "Invalid terminal size", END_ERR_MSG);
11958 errno = EINVAL;
11959 return 1;
11960 };
11961 /*
11962 * Install the new dimensions in the terminal driver if possible, so
11963 * that future calls to gl_query_size() get the new value.
11964 */
11965 #ifdef TIOCSWINSZ
11966 if(gl->is_term) {
11967 struct winsize size;
11968 size.ws_row = nline;
11969 size.ws_col = ncolumn;
11970 size.ws_xpixel = 0;
11971 size.ws_ypixel = 0;
11972 if(ioctl(gl->output_fd, TIOCSWINSZ, &size) == -1) {
11973 _err_record_msg(gl->err, "Can't change terminal size", END_ERR_MSG);
11974 return 1;
11975 };
11976 };
11977 #endif
11978 /*
11979 * If an input line is in the process of being edited, redisplay it to
11980 * accomodate the new dimensions, and record the new dimensions in
11981 * gl->nline and gl->ncolumn.
11982 */
11983 return gl_handle_tty_resize(gl, ncolumn, nline);
11984 }
11985
11986 /*.......................................................................
11987 * Record a character in the input line buffer at a given position.
11988 *
11989 * Input:
11990 * gl GetLine * The resource object of gl_get_line().
11991 * c char The character to be recorded.
11992 * bufpos int The index in the buffer at which to record the
11993 * character.
11994 * Output:
11995 * return int 0 - OK.
11996 * 1 - Insufficient room.
11997 */
11998 static int gl_buffer_char(GetLine *gl, char c, int bufpos)
11999 {
12000 /*
12001 * Guard against buffer overruns.
12002 */
12003 if(bufpos >= gl->linelen)
12004 return 1;
12005 /*
12006 * Record the new character.
12007 */
12008 gl->line[bufpos] = c;
12009 /*
12010 * If the new character was placed beyond the end of the current input
12011 * line, update gl->ntotal to reflect the increased number of characters
12012 * that are in gl->line, and terminate the string.
12013 */
12014 if(bufpos >= gl->ntotal) {
12015 gl->ntotal = bufpos+1;
12016 gl->line[gl->ntotal] = '\0';
12017 };
12018 return 0;
12019 }
12020
12021 /*.......................................................................
12022 * Copy a given string into the input buffer, overwriting the current
12023 * contents.
12024 *
12025 * Input:
12026 * gl GetLine * The resource object of gl_get_line().
12027 * s const char * The string to be recorded.
12028 * n int The number of characters to be copied from the
12029 * string.
12030 * bufpos int The index in the buffer at which to place the
12031 * the first character of the string.
12032 * Output:
12033 * return int 0 - OK.
12034 * 1 - String truncated to fit.
12035 */
12036 static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos)
12037 {
12038 int nnew; /* The number of characters actually recorded */
12039 int i;
12040 /*
12041 * How many of the characters will fit within the buffer?
12042 */
12043 nnew = bufpos + n <= gl->linelen ? n : (gl->linelen - bufpos);
12044 /*
12045 * Record the first nnew characters of s[] in the buffer.
12046 */
12047 for(i=0; i<nnew; i++)
12048 gl_buffer_char(gl, s[i], bufpos + i);
12049 /*
12050 * Was the string truncated?
12051 */
12052 return nnew < n;
12053 }
12054
12055 /*.......................................................................
12056 * Make room in the input buffer for a string to be inserted. This
12057 * involves moving the characters that follow a specified point, towards
12058 * the end of the buffer.
12059 *
12060 * Input:
12061 * gl GetLine * The resource object of gl_get_line().
12062 * start int The index of the first character to be moved.
12063 * n int The width of the gap.
12064 * Output:
12065 * return int 0 - OK.
12066 * 1 - Insufficient room.
12067 */
12068 static int gl_make_gap_in_buffer(GetLine *gl, int start, int n)
12069 {
12070 /*
12071 * Ensure that the buffer has sufficient space.
12072 */
12073 if(gl->ntotal + n > gl->linelen)
12074 return 1;
12075 /*
12076 * Move everything including and beyond the character at 'start'
12077 * towards the end of the string.
12078 */
12079 memmove(gl->line + start + n, gl->line + start, gl->ntotal - start + 1);
12080 /*
12081 * Update the recorded size of the line.
12082 */
12083 gl->ntotal += n;
12084 return 1;
12085 }
12086
12087 /*.......................................................................
12088 * Remove a given number of characters from the input buffer. This
12089 * involves moving the characters that follow the removed characters to
12090 * where the removed sub-string started in the input buffer.
12091 *
12092 * Input:
12093 * gl GetLine * The resource object of gl_get_line().
12094 * start int The first character to be removed.
12095 * n int The number of characters to remove.
12096 */
12097 static void gl_remove_from_buffer(GetLine *gl, int start, int n)
12098 {
12099 memmove(gl->line + start, gl->line + start + n, gl->ntotal - start - n + 1);
12100 /*
12101 * Update the recorded size of the line.
12102 */
12103 gl->ntotal -= n;
12104 }
12105
12106 /*.......................................................................
12107 * Truncate the string in the input line buffer after a given number of
12108 * characters.
12109 *
12110 * Input:
12111 * gl GetLine * The resource object of gl_get_line().
12112 * n int The new length of the line.
12113 * Output:
12114 * return int 0 - OK.
12115 * 1 - n > gl->linelen.
12116 */
12117 static int gl_truncate_buffer(GetLine *gl, int n)
12118 {
12119 if(n > gl->linelen)
12120 return 1;
12121 gl->line[n] = '\0';
12122 gl->ntotal = n;
12123 return 0;
12124 }
12125
12126 /*.......................................................................
12127 * When the contents of gl->line[] are changed without calling any of the
12128 * gl_ buffer manipulation functions, this function must be called to
12129 * compute the length of this string, and ancillary information.
12130 *
12131 * Input:
12132 * gl GetLine * The resource object of gl_get_line().
12133 */
12134 static void gl_update_buffer(GetLine *gl)
12135 {
12136 int len; /* The length of the line */
12137 /*
12138 * Measure the length of the input line.
12139 */
12140 for(len=0; len <= gl->linelen && gl->line[len]; len++)
12141 ;
12142 /*
12143 * Just in case the string wasn't correctly terminated, do so here.
12144 */
12145 gl->line[len] = '\0';
12146 /*
12147 * Record the number of characters that are now in gl->line[].
12148 */
12149 gl->ntotal = len;
12150 /*
12151 * Ensure that the cursor stays within the bounds of the modified
12152 * input line.
12153 */
12154 if(gl->buff_curpos > gl->ntotal)
12155 gl->buff_curpos = gl->ntotal;
12156 /*
12157 * Arrange for the input line to be redrawn.
12158 */
12159 gl_queue_redisplay(gl);
12160 return;
12161 }
12162
12163 /*.......................................................................
12164 * Erase the displayed input line, including its prompt, and leave the
12165 * cursor where the erased line started. Note that to allow this
12166 * function to be used when responding to a terminal resize, this
12167 * function is designed to work even if the horizontal cursor position
12168 * doesn't match the internally recorded position.
12169 *
12170 * Input:
12171 * gl GetLine * The resource object of gl_get_line().
12172 * Output:
12173 * return int 0 - OK.
12174 * 1 - Error.
12175 */
12176 static int gl_erase_line(GetLine *gl)
12177 {
12178 /*
12179 * Is a line currently displayed?
12180 */
12181 if(gl->displayed) {
12182 /*
12183 * Relative the the start of the input line, which terminal line of
12184 * the current input line is the cursor currently on?
12185 */
12186 int cursor_line = gl->term_curpos / gl->ncolumn;
12187 /*
12188 * Move the cursor to the start of the line.
12189 */
12190 for( ; cursor_line > 0; cursor_line--) {
12191 if(gl_print_control_sequence(gl, 1, gl->up))
12192 return 1;
12193 };
12194 if(gl_print_control_sequence(gl, 1, gl->bol))
12195 return 1;
12196 /*
12197 * Clear from the start of the line to the end of the terminal.
12198 */
12199 if(gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
12200 return 1;
12201 /*
12202 * Mark the line as no longer displayed.
12203 */
12204 gl_line_erased(gl);
12205 };
12206 return 0;
12207 }
12208
12209 /*.......................................................................
12210 * Arrange for the input line to be redisplayed by gl_flush_output(),
12211 * as soon as the output queue becomes empty.
12212 *
12213 * Input:
12214 * gl GetLine * The resource object of gl_get_line().
12215 */
12216 static void gl_queue_redisplay(GetLine *gl)
12217 {
12218 gl->redisplay = 1;
12219 gl->pending_io = GLP_WRITE;
12220 }
12221
12222 /*.......................................................................
12223 * Truncate the displayed input line starting from the current
12224 * terminal cursor position, and leave the cursor at the end of the
12225 * truncated line. The input-line buffer is not affected.
12226 *
12227 * Input:
12228 * gl GetLine * The resource object of gl_get_line().
12229 * Output:
12230 * return int 0 - OK.
12231 * 1 - Error.
12232 */
12233 static int gl_truncate_display(GetLine *gl)
12234 {
12235 /*
12236 * Keep a record of the current terminal cursor position.
12237 */
12238 int term_curpos = gl->term_curpos;
12239 /*
12240 * First clear from the cursor to the end of the current input line.
12241 */
12242 if(gl_print_control_sequence(gl, 1, gl->clear_eol))
12243 return 1;
12244 /*
12245 * If there is more than one line displayed, go to the start of the
12246 * next line and clear from there to the end of the display. Note that
12247 * we can't use clear_eod to do the whole job of clearing from the
12248 * current cursor position to the end of the terminal because
12249 * clear_eod is only defined when used at the start of a terminal line
12250 * (eg. with gnome terminals, clear_eod clears from the start of the
12251 * current terminal line, rather than from the current cursor
12252 * position).
12253 */
12254 if(gl->term_len / gl->ncolumn > gl->term_curpos / gl->ncolumn) {
12255 if(gl_print_control_sequence(gl, 1, gl->down) ||
12256 gl_print_control_sequence(gl, 1, gl->bol) ||
12257 gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
12258 return 1;
12259 /*
12260 * Where is the cursor now?
12261 */
12262 gl->term_curpos = gl->ncolumn * (term_curpos / gl->ncolumn + 1);
12263 /*
12264 * Restore the cursor position.
12265 */
12266 gl_set_term_curpos(gl, term_curpos);
12267 };
12268 /*
12269 * Update the recorded position of the final character.
12270 */
12271 gl->term_len = gl->term_curpos;
12272 return 0;
12273 }
12274
12275 /*.......................................................................
12276 * Return the set of all trappable signals.
12277 *
12278 * Input:
12279 * signals sigset_t * The set of signals will be recorded in
12280 * *signals.
12281 */
12282 static void gl_list_trappable_signals(sigset_t *signals)
12283 {
12284 /*
12285 * Start with the set of all signals.
12286 */
12287 sigfillset(signals);
12288 /*
12289 * Remove un-trappable signals from this set.
12290 */
12291 #ifdef SIGKILL
12292 sigdelset(signals, SIGKILL);
12293 #endif
12294 #ifdef SIGSTOP
12295 sigdelset(signals, SIGSTOP);
12296 #endif
12297 }
12298
12299 /*.......................................................................
12300 * Read an input line from a non-interactive input stream.
12301 *
12302 * Input:
12303 * gl GetLine * The resource object of gl_get_line().
12304 * Output:
12305 * return int 0 - OK
12306 * 1 - Error.
12307 */
12308 static int gl_read_stream_line(GetLine *gl)
12309 {
12310 char c = '\0'; /* The latest character read from fp */
12311 /*
12312 * Record the fact that we are about to read input.
12313 */
12314 gl->pending_io = GLP_READ;
12315 /*
12316 * If we are starting a new line, reset the line-editing parameters,
12317 * and discard the previous input line.
12318 */
12319 if(gl->endline) {
12320 gl_reset_editor(gl);
12321 gl_truncate_buffer(gl, 0);
12322 };
12323 /*
12324 * Read one character at a time.
12325 */
12326 while(gl->ntotal < gl->linelen && c != '\n') {
12327 /*
12328 * Attempt to read one more character.
12329 */
12330 switch(gl_read_input(gl, &c)) {
12331 case GL_READ_OK:
12332 break;
12333 case GL_READ_EOF: /* Reached end-of-file? */
12334 /*
12335 * If any characters were read before the end-of-file condition,
12336 * interpolate a newline character, so that the caller sees a
12337 * properly terminated line. Otherwise return an end-of-file
12338 * condition.
12339 */
12340 if(gl->ntotal > 0) {
12341 c = '\n';
12342 } else {
12343 gl_record_status(gl, GLR_EOF, 0);
12344 return 1;
12345 };
12346 break;
12347 case GL_READ_BLOCKED: /* Input blocked? */
12348 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
12349 return 1;
12350 break;
12351 case GL_READ_ERROR: /* I/O error? */
12352 return 1;
12353 break;
12354 };
12355 /*
12356 * Append the character to the line buffer.
12357 */
12358 if(gl_buffer_char(gl, c, gl->ntotal))
12359 return 1;
12360 };
12361 /*
12362 * Was the end of the input line reached before running out of buffer space?
12363 */
12364 gl->endline = (c == '\n');
12365 return 0;
12366 }
12367
12368 /*.......................................................................
12369 * Read a single character from a non-interactive input stream.
12370 *
12371 * Input:
12372 * gl GetLine * The resource object of gl_get_line().
12373 * Output:
12374 * return int The character, or EOF on error.
12375 */
12376 static int gl_read_stream_char(GetLine *gl)
12377 {
12378 char c = '\0'; /* The latest character read from fp */
12379 int retval = EOF; /* The return value of this function */
12380 /*
12381 * Arrange to discard any incomplete input line.
12382 */
12383 _gl_abandon_line(gl);
12384 /*
12385 * Record the fact that we are about to read input.
12386 */
12387 gl->pending_io = GLP_READ;
12388 /*
12389 * Attempt to read one more character.
12390 */
12391 switch(gl_read_input(gl, &c)) {
12392 case GL_READ_OK: /* Success */
12393 retval = c;
12394 break;
12395 case GL_READ_BLOCKED: /* The read blocked */
12396 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
12397 retval = EOF; /* Failure */
12398 break;
12399 case GL_READ_EOF: /* End of file reached */
12400 gl_record_status(gl, GLR_EOF, 0);
12401 retval = EOF; /* Failure */
12402 break;
12403 case GL_READ_ERROR:
12404 retval = EOF; /* Failure */
12405 break;
12406 };
12407 return retval;
12408 }
12409
12410 /*.......................................................................
12411 * Bind a key sequence to a given action.
12412 *
12413 * Input:
12414 * gl GetLine * The resource object of gl_get_line().
12415 * origin GlKeyOrigin The originator of the key binding.
12416 * key const char * The key-sequence to be bound (or unbound).
12417 * action const char * The name of the action to bind the key to,
12418 * or either NULL or "" to unbind the
12419 * key-sequence.
12420 * Output:
12421 * return int 0 - OK
12422 * 1 - Error.
12423 */
12424 int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin, const char *keyseq,
12425 const char *action)
12426 {
12427 KtBinder binder; /* The private internal equivalent of 'origin' */
12428 /*
12429 * Check the arguments.
12430 */
12431 if(!gl || !keyseq) {
12432 errno = EINVAL;
12433 if(gl)
12434 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
12435 return 1;
12436 };
12437 /*
12438 * An empty action string requests that the key-sequence be unbound.
12439 * This is indicated to _kt_set_keybinding() by passing a NULL action
12440 * string, so convert an empty string to a NULL action pointer.
12441 */
12442 if(action && *action=='\0')
12443 action = NULL;
12444 /*
12445 * Translate the public originator enumeration to the private equivalent.
12446 */
12447 binder = origin==GL_USER_KEY ? KTB_USER : KTB_NORM;
12448 /*
12449 * Bind the action to a given key-sequence?
12450 */
12451 if(keyseq && _kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
12452 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
12453 return 1;
12454 };
12455 return 0;
12456 }
12457
12458 /*.......................................................................
12459 * This is the public wrapper around the gl_clear_termina() function.
12460 * It clears the terminal and leaves the cursor at the home position.
12461 * In server I/O mode, the next call to gl_get_line() will also
12462 * redisplay the current input line.
12463 *
12464 * Input:
12465 * gl GetLine * The resource object of gl_get_line().
12466 * Output:
12467 * return int 0 - OK.
12468 * 1 - Error.
12469 */
12470 int gl_erase_terminal(GetLine *gl)
12471 {
12472 sigset_t oldset; /* The signals that were blocked on entry */
12473 /* to this function */
12474 int status; /* The return status */
12475 /*
12476 * Block all signals while accessing gl.
12477 */
12478 gl_mask_signals(gl, &oldset);
12479 /*
12480 * Clear the terminal.
12481 */
12482 status = gl_clear_screen(gl, 1, NULL);
12483 /*
12484 * Attempt to flush the clear-screen control codes to the terminal.
12485 * If this doesn't complete the job, the next call to gl_get_line()
12486 * will.
12487 */
12488 (void) gl_flush_output(gl);
12489 /*
12490 * Restore the process signal mask before returning.
12491 */
12492 gl_unmask_signals(gl, &oldset);
12493 return status;
12494 }
12495
12496 /*.......................................................................
12497 * This function must be called by any function that erases the input
12498 * line.
12499 *
12500 * Input:
12501 * gl GetLine * The resource object of gl_get_line().
12502 */
12503 static void gl_line_erased(GetLine *gl)
12504 {
12505 gl->displayed = 0;
12506 gl->term_curpos = 0;
12507 gl->term_len = 0;
12508 }
12509
12510 /*.......................................................................
12511 * Append a specified line to the history list.
12512 *
12513 * Input:
12514 * gl GetLine * The resource object of gl_get_line().
12515 * line const char * The line to be added.
12516 * Output:
12517 * return int 0 - OK.
12518 * 1 - Error.
12519 */
12520 int gl_append_history(GetLine *gl, const char *line)
12521 {
12522 sigset_t oldset; /* The signals that were blocked on entry */
12523 /* to this function */
12524 int status; /* The return status */
12525 /*
12526 * Check the arguments.
12527 */
12528 if(!gl || !line) {
12529 errno = EINVAL;
12530 return 1;
12531 };
12532 /*
12533 * Block all signals.
12534 */
12535 if(gl_mask_signals(gl, &oldset))
12536 return 1;
12537 /*
12538 * Execute the private body of the function while signals are blocked.
12539 */
12540 status = _gl_append_history(gl, line);
12541 /*
12542 * Restore the process signal mask.
12543 */
12544 gl_unmask_signals(gl, &oldset);
12545 return status;
12546 }
12547
12548 /*.......................................................................
12549 * This is the private body of the public function, gl_append_history().
12550 * It assumes that the caller has checked its arguments and blocked the
12551 * delivery of signals.
12552 */
12553 static int _gl_append_history(GetLine *gl, const char *line)
12554 {
12555 int status =_glh_add_history(gl->glh, line, 0);
12556 if(status)
12557 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
12558 return status;
12559 }
12560
12561 /*.......................................................................
12562 * Enable or disable the automatic addition of newly entered lines to the
12563 * history list.
12564 *
12565 * Input:
12566 * gl GetLine * The resource object of gl_get_line().
12567 * enable int If true, subsequently entered lines will
12568 * automatically be added to the history list
12569 * before they are returned to the caller of
12570 * gl_get_line(). If 0, the choice of how and
12571 * when to archive lines in the history list,
12572 * is left up to the calling application, which
12573 * can do so via calls to gl_append_history().
12574 * Output:
12575 * return int 0 - OK.
12576 * 1 - Error.
12577 */
12578 int gl_automatic_history(GetLine *gl, int enable)
12579 {
12580 sigset_t oldset; /* The signals that were blocked on entry */
12581 /* to this function */
12582 /*
12583 * Check the arguments.
12584 */
12585 if(!gl) {
12586 errno = EINVAL;
12587 return 1;
12588 };
12589 /*
12590 * Block all signals.
12591 */
12592 if(gl_mask_signals(gl, &oldset))
12593 return 1;
12594 /*
12595 * Execute the private body of the function while signals are blocked.
12596 */
12597 gl->automatic_history = enable;
12598 /*
12599 * Restore the process signal mask.
12600 */
12601 gl_unmask_signals(gl, &oldset);
12602 return 0;
12603 }
12604
12605 /*.......................................................................
12606 * This is a public function that reads a single uninterpretted
12607 * character from the user, without displaying anything.
12608 *
12609 * Input:
12610 * gl GetLine * A resource object previously returned by
12611 * new_GetLine().
12612 * Output:
12613 * return int The character that was read, or EOF if the read
12614 * had to be aborted (in which case you can call
12615 * gl_return_status() to find out why).
12616 */
12617 int gl_read_char(GetLine *gl)
12618 {
12619 int retval; /* The return value of _gl_read_char() */
12620 /*
12621 * This function can be called from application callback functions,
12622 * so check whether signals have already been masked, so that we don't
12623 * do it again, and overwrite gl->old_signal_set.
12624 */
12625 int was_masked = gl->signals_masked;
12626 /*
12627 * Check the arguments.
12628 */
12629 if(!gl) {
12630 errno = EINVAL;
12631 return EOF;
12632 };
12633 /*
12634 * Temporarily block all of the signals that we have been asked to trap.
12635 */
12636 if(!was_masked && gl_mask_signals(gl, &gl->old_signal_set))
12637 return EOF;
12638 /*
12639 * Perform the character reading task.
12640 */
12641 retval = _gl_read_char(gl);
12642 /*
12643 * Restore the process signal mask to how it was when this function was
12644 * first called.
12645 */
12646 if(!was_masked)
12647 gl_unmask_signals(gl, &gl->old_signal_set);
12648 return retval;
12649 }
12650
12651 /*.......................................................................
12652 * This is the main body of the public function gl_read_char().
12653 */
12654 static int _gl_read_char(GetLine *gl)
12655 {
12656 int retval = EOF; /* The return value */
12657 int waserr = 0; /* True if an error occurs */
12658 char c; /* The character read */
12659 /*
12660 * This function can be called from application callback functions,
12661 * so check whether signals have already been overriden, so that we don't
12662 * overwrite the preserved signal handlers with gl_get_line()s. Also
12663 * record whether we are currently in raw I/O mode or not, so that this
12664 * can be left in the same state on leaving this function.
12665 */
12666 int was_overriden = gl->signals_overriden;
12667 int was_raw = gl->raw_mode;
12668 /*
12669 * Also keep a record of the direction of any I/O that gl_get_line()
12670 * is awaiting, so that we can restore this status on return.
12671 */
12672 GlPendingIO old_pending_io = gl->pending_io;
12673 /*
12674 * Assume that this call will successfully complete the input operation
12675 * until proven otherwise.
12676 */
12677 gl_clear_status(gl);
12678 /*
12679 * If this is the first call to this function or gl_get_line(),
12680 * since new_GetLine(), complete any postponed configuration.
12681 */
12682 if(!gl->configured) {
12683 (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
12684 gl->configured = 1;
12685 };
12686 /*
12687 * Before installing our signal handler functions, record the fact
12688 * that there are no pending signals.
12689 */
12690 gl_pending_signal = -1;
12691 /*
12692 * Temporarily override the signal handlers of the calling program,
12693 * so that we can intercept signals that would leave the terminal
12694 * in a bad state.
12695 */
12696 if(!was_overriden)
12697 waserr = gl_override_signal_handlers(gl);
12698 /*
12699 * After recording the current terminal settings, switch the terminal
12700 * into raw input mode, without redisplaying any partially entered input
12701 * line.
12702 */
12703 if(!was_raw)
12704 waserr = waserr || _gl_raw_io(gl, 0);
12705 /*
12706 * Attempt to read the line. This will require more than one attempt if
12707 * either a current temporary input file is opened by gl_get_input_line()
12708 * or the end of a temporary input file is reached by gl_read_stream_line().
12709 */
12710 while(!waserr) {
12711 /*
12712 * Read a line from a non-interactive stream?
12713 */
12714 if(gl->file_fp || !gl->is_term) {
12715 retval = gl_read_stream_char(gl);
12716 if(retval != EOF) { /* Success? */
12717 break;
12718 } else if(gl->file_fp) { /* End of temporary input file? */
12719 gl_revert_input(gl);
12720 gl_record_status(gl, GLR_NEWLINE, 0);
12721 } else { /* An error? */
12722 waserr = 1;
12723 break;
12724 };
12725 };
12726 /*
12727 * Read from the terminal? Note that the above if() block may have
12728 * changed gl->file_fp, so it is necessary to retest it here, rather
12729 * than using an else statement.
12730 */
12731 if(!gl->file_fp && gl->is_term) {
12732 /*
12733 * Flush any pending output to the terminal before waiting
12734 * for the user to type a character.
12735 */
12736 if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl)) {
12737 retval = EOF;
12738 /*
12739 * Read one character. Don't append it to the key buffer, since
12740 * this would subseuqnely appear as bogus input to the line editor.
12741 */
12742 } else if(gl_read_terminal(gl, 0, &c) == 0) {
12743 /*
12744 * Record the character for return.
12745 */
12746 retval = c;
12747 /*
12748 * In this mode, count each character as being a new key-sequence.
12749 */
12750 gl->keyseq_count++;
12751 /*
12752 * Delete the character that was read, from the key-press buffer.
12753 */
12754 gl_discard_chars(gl, 1);
12755 };
12756 if(retval==EOF)
12757 waserr = 1;
12758 else
12759 break;
12760 };
12761 };
12762 /*
12763 * If an error occurred, but gl->rtn_status is still set to
12764 * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
12765 * leave it at whatever specific value was assigned by the function
12766 * that aborted input. This means that only functions that trap
12767 * non-generic errors have to remember to update gl->rtn_status
12768 * themselves.
12769 */
12770 if(waserr && gl->rtn_status == GLR_NEWLINE)
12771 gl_record_status(gl, GLR_ERROR, errno);
12772 /*
12773 * Restore terminal settings, if they were changed by this function.
12774 */
12775 if(!was_raw && gl->io_mode != GL_SERVER_MODE)
12776 _gl_normal_io(gl);
12777 /*
12778 * Restore the signal handlers, if they were overriden by this function.
12779 */
12780 if(!was_overriden)
12781 gl_restore_signal_handlers(gl);
12782 /*
12783 * If this function gets aborted early, the errno value associated
12784 * with the event that caused this to happen is recorded in
12785 * gl->rtn_errno. Since errno may have been overwritten by cleanup
12786 * functions after this, restore its value to the value that it had
12787 * when the error condition occured, so that the caller can examine it
12788 * to find out what happened.
12789 */
12790 errno = gl->rtn_errno;
12791 /*
12792 * Error conditions are signalled to the caller, by setting the returned
12793 * character to EOF.
12794 */
12795 if(gl->rtn_status != GLR_NEWLINE)
12796 retval = EOF;
12797 /*
12798 * Restore the indication of what direction of I/O gl_get_line()
12799 * was awaiting before this call.
12800 */
12801 gl->pending_io = old_pending_io;
12802 /*
12803 * Return the acquired character.
12804 */
12805 return retval;
12806 }
12807
12808 /*.......................................................................
12809 * Reset the GetLine completion status. This function should be called
12810 * at the start of gl_get_line(), gl_read_char() and gl_query_char()
12811 * to discard the completion status and non-zero errno value of any
12812 * preceding calls to these functions.
12813 *
12814 * Input:
12815 * gl GetLine * The resource object of this module.
12816 */
12817 static void gl_clear_status(GetLine *gl)
12818 {
12819 gl_record_status(gl, GLR_NEWLINE, 0);
12820 }
12821
12822 /*.......................................................................
12823 * When an error or other event causes gl_get_line() to return, this
12824 * function should be called to record information about what
12825 * happened, including the value of errno and the value that
12826 * gl_return_status() should return.
12827 *
12828 * Input:
12829 * gl GetLine * The resource object of this module.
12830 * rtn_status GlReturnStatus The completion status. To clear a
12831 * previous abnormal completion status,
12832 * specify GLR_NEWLINE (this is what
12833 * gl_clear_status() does).
12834 * rtn_errno int The associated value of errno.
12835 */
12836 static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
12837 int rtn_errno)
12838 {
12839 /*
12840 * If rtn_status==GLR_NEWLINE, then this resets the completion status, so we
12841 * should always heed this. Otherwise, only record the first abnormal
12842 * condition that occurs after such a reset.
12843 */
12844 if(rtn_status == GLR_NEWLINE || gl->rtn_status == GLR_NEWLINE) {
12845 gl->rtn_status = rtn_status;
12846 gl->rtn_errno = rtn_errno;
12847 };
12848 }
12849
12850