1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
3 *
4 * All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, and/or sell copies of the Software, and to permit persons
11 * to whom the Software is furnished to do so, provided that the above
12 * copyright notice(s) and this permission notice appear in all copies of
13 * the Software and that both the above copyright notice(s) and this
14 * permission notice appear in supporting documentation.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
21 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
22 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
23 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 *
26 * Except as contained in this notice, the name of a copyright holder
27 * shall not be used in advertising or otherwise to promote the sale, use
28 * or other dealings in this Software without prior written authorization
29 * of the copyright holder.
30 */
31
32 /*
33 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
35 */
36
37 #pragma ident "%Z%%M% %I% %E% SMI"
38
39 /*
40 * Standard headers.
41 */
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <signal.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <ctype.h>
48 #include <setjmp.h>
49 #include <stdarg.h>
50
51 /*
52 * UNIX headers.
53 */
54 #include <sys/ioctl.h>
55 #ifdef HAVE_SELECT
56 #ifdef HAVE_SYS_SELECT_H
57 #include <sys/select.h>
58 #endif
59 #include <sys/time.h>
60 #include <sys/types.h>
61 #endif
62
63 /*
64 * Handle the different sources of terminal control string and size
65 * information. Note that if no terminal information database is available,
66 * ANSI VT100 control sequences are used.
67 */
68 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
69 /*
70 * Include curses.h or ncurses/curses.h depending on which is available.
71 */
72 #ifdef HAVE_CURSES_H
73 #include <curses.h>
74 #elif defined(HAVE_NCURSES_CURSES_H)
75 #include <ncurses/curses.h>
76 #endif
77 /*
78 * Include term.h where available.
79 */
80 #if defined(HAVE_TERM_H)
81 #include <term.h>
82 #elif defined(HAVE_NCURSES_TERM_H)
83 #include <ncurses/term.h>
84 #endif
85 /*
86 * When using termcap, include termcap.h on systems that have it.
87 * Otherwise assume that all prototypes are provided by curses.h.
88 */
89 #if defined(USE_TERMCAP) && defined(HAVE_TERMCAP_H)
90 #include <termcap.h>
91 #endif
92
93 /*
94 * Under Solaris default Curses the output function that tputs takes is
95 * declared to have a char argument. On all other systems and on Solaris
96 * X/Open Curses (Issue 4, Version 2) it expects an int argument (using
97 * c89 or options -I /usr/xpg4/include -L /usr/xpg4/lib -R /usr/xpg4/lib
98 * selects XPG4v2 Curses on Solaris 2.6 and later).
99 *
100 * Similarly, under Mac OS X, the return value of the tputs output
101 * function is declared as void, whereas it is declared as int on
102 * other systems.
103 */
104 #if defined __sun && defined __SVR4 && !defined _XOPEN_CURSES
105 typedef int TputsRetType;
106 typedef char TputsArgType; /* int tputs(char c, FILE *fp) */
107 #define TPUTS_RETURNS_VALUE 1
108 #elif defined(__APPLE__) && defined(__MACH__)
109 typedef void TputsRetType;
110 typedef int TputsArgType; /* void tputs(int c, FILE *fp) */
111 #define TPUTS_RETURNS_VALUE 0
112 #else
113 typedef int TputsRetType;
114 typedef int TputsArgType; /* int tputs(int c, FILE *fp) */
115 #define TPUTS_RETURNS_VALUE 1
116 #endif
117
118 /*
119 * Use the above specifications to prototype our tputs callback function.
120 */
121 static TputsRetType gl_tputs_putchar(TputsArgType c);
122
123 #endif /* defined(USE_TERMINFO) || defined(USE_TERMCAP) */
124
125 /*
126 * If the library is being compiled without filesystem access facilities,
127 * ensure that none of the action functions that normally do access the
128 * filesystem are bound by default, and that it they do get bound, that
129 * they don't do anything.
130 */
131 #if WITHOUT_FILE_SYSTEM
132 #define HIDE_FILE_SYSTEM
133 #endif
134
135 /*
136 * POSIX headers.
137 */
138 #include <unistd.h>
139 #include <fcntl.h>
140 #include <termios.h>
141
142 /*
143 * Provide typedefs for standard POSIX structures.
144 */
145 typedef struct sigaction SigAction;
146 typedef struct termios Termios;
147
148 /*
149 * Which flag is used to select non-blocking I/O with fcntl()?
150 */
151 #undef NON_BLOCKING_FLAG
152 #if defined(O_NONBLOCK)
153 #define NON_BLOCKING_FLAG (O_NONBLOCK)
154 #elif defined(O_NDELAY)
155 #define NON_BLOCKING_FLAG (O_NDELAY)
156 #endif
157
158 /*
159 * What value should we give errno if I/O blocks when it shouldn't.
160 */
161 #undef BLOCKED_ERRNO
162 #if defined(EAGAIN)
163 #define BLOCKED_ERRNO (EAGAIN)
164 #elif defined(EWOULDBLOCK)
165 #define BLOCKED_ERRNO (EWOULDBLOCK)
166 #elif defined(EIO)
167 #define BLOCKED_ERRNO (EIO)
168 #else
169 #define BLOCKED_ERRNO 0
170 #endif
171
172 /*
173 * Local headers.
174 */
175 #ifndef WITHOUT_FILE_SYSTEM
176 #include "pathutil.h"
177 #endif
178 #include "libtecla.h"
179 #include "keytab.h"
180 #include "getline.h"
181 #include "ioutil.h"
182 #include "history.h"
183 #include "freelist.h"
184 #include "stringrp.h"
185 #include "chrqueue.h"
186 #include "cplmatch.h"
187 #ifndef WITHOUT_FILE_SYSTEM
188 #include "expand.h"
189 #endif
190 #include "errmsg.h"
191
192 /*
193 * Enumerate the available editing styles.
194 */
195 typedef enum {
196 GL_EMACS_MODE, /* Emacs style editing */
197 GL_VI_MODE, /* Vi style editing */
198 GL_NO_EDITOR /* Fall back to the basic OS-provided editing */
199 } GlEditor;
200
201 /*
202 * Set the largest key-sequence that can be handled.
203 */
204 #define GL_KEY_MAX 64
205
206 /*
207 * In vi mode, the following datatype is used to implement the
208 * undo command. It records a copy of the input line from before
209 * the command-mode action which edited the input line.
210 */
211 typedef struct {
212 char *line; /* A historical copy of the input line */
213 int buff_curpos; /* The historical location of the cursor in */
214 /* line[] when the line was modified. */
215 int ntotal; /* The number of characters in line[] */
216 int saved; /* True once a line has been saved after the */
217 /* last call to gl_interpret_char(). */
218 } ViUndo;
219
220 /*
221 * In vi mode, the following datatype is used to record information
222 * needed by the vi-repeat-change command.
223 */
224 typedef struct {
225 KtAction action; /* The last action function that made a */
226 /* change to the line. */
227 int count; /* The repeat count that was passed to the */
228 /* above command. */
229 int input_curpos; /* Whenever vi command mode is entered, the */
230 /* the position at which it was first left */
231 /* is recorded here. */
232 int command_curpos; /* Whenever vi command mode is entered, the */
233 /* the location of the cursor is recorded */
234 /* here. */
235 char input_char; /* Commands that call gl_read_terminal() */
236 /* record the character here, so that it can */
237 /* used on repeating the function. */
238 int saved; /* True if a function has been saved since the */
239 /* last call to gl_interpret_char(). */
240 int active; /* True while a function is being repeated. */
241 } ViRepeat;
242
243 /*
244 * The following datatype is used to encapsulate information specific
245 * to vi mode.
246 */
247 typedef struct {
248 ViUndo undo; /* Information needed to implement the vi */
249 /* undo command. */
250 ViRepeat repeat; /* Information needed to implement the vi */
251 /* repeat command. */
252 int command; /* True in vi command-mode */
253 int find_forward; /* True if the last character search was in the */
254 /* forward direction. */
255 int find_onto; /* True if the last character search left the */
256 /* on top of the located character, as opposed */
257 /* to just before or after it. */
258 char find_char; /* The last character sought, or '\0' if no */
259 /* searches have been performed yet. */
260 } ViMode;
261
262 #ifdef HAVE_SELECT
263 /*
264 * Define a type for recording a file-descriptor callback and its associated
265 * data.
266 */
267 typedef struct {
268 GlFdEventFn *fn; /* The callback function */
269 void *data; /* Anonymous data to pass to the callback function */
270 } GlFdHandler;
271
272 /*
273 * A list of nodes of the following type is used to record file-activity
274 * event handlers, but only on systems that have the select() system call.
275 */
276 typedef struct GlFdNode GlFdNode;
277 struct GlFdNode {
278 GlFdNode *next; /* The next in the list of nodes */
279 int fd; /* The file descriptor being watched */
280 GlFdHandler rd; /* The callback to call when fd is readable */
281 GlFdHandler wr; /* The callback to call when fd is writable */
282 GlFdHandler ur; /* The callback to call when fd has urgent data */
283 };
284
285 /*
286 * Set the number of the above structures to allocate every time that
287 * the freelist of GlFdNode's becomes exhausted.
288 */
289 #define GLFD_FREELIST_BLOCKING 10
290
291
292 static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
293 GlFdEvent event);
294
295 static int gl_call_timeout_handler(GetLine *gl);
296
297 #endif
298
299 /*
300 * Each signal that gl_get_line() traps is described by a list node
301 * of the following type.
302 */
303 typedef struct GlSignalNode GlSignalNode;
304 struct GlSignalNode {
305 GlSignalNode *next; /* The next signal in the list */
306 int signo; /* The number of the signal */
307 sigset_t proc_mask; /* A process mask which only includes signo */
308 SigAction original; /* The signal disposition of the calling program */
309 /* for this signal. */
310 unsigned flags; /* A bitwise union of GlSignalFlags enumerators */
311 GlAfterSignal after; /* What to do after the signal has been handled */
312 int errno_value; /* What to set errno to */
313 };
314
315 /*
316 * Set the number of the above structures to allocate every time that
317 * the freelist of GlSignalNode's becomes exhausted.
318 */
319 #define GLS_FREELIST_BLOCKING 30
320
321 /*
322 * Completion handlers and their callback data are recorded in
323 * nodes of the following type.
324 */
325 typedef struct GlCplCallback GlCplCallback;
326 struct GlCplCallback {
327 CplMatchFn *fn; /* The completion callback function */
328 void *data; /* Arbitrary callback data */
329 };
330
331 /*
332 * The following function is used as the default completion handler when
333 * the filesystem is to be hidden. It simply reports no completions.
334 */
335 #ifdef HIDE_FILE_SYSTEM
336 static CPL_MATCH_FN(gl_no_completions);
337 #endif
338
339 /*
340 * Specify how many GlCplCallback nodes are added to the GlCplCallback freelist
341 * whenever it becomes exhausted.
342 */
343 #define GL_CPL_FREELIST_BLOCKING 10
344
345 /*
346 * External action functions and their callback data are recorded in
347 * nodes of the following type.
348 */
349 typedef struct GlExternalAction GlExternalAction;
350 struct GlExternalAction {
351 GlActionFn *fn; /* The function which implements the action */
352 void *data; /* Arbitrary callback data */
353 };
354
355 /*
356 * Specify how many GlExternalAction nodes are added to the
357 * GlExternalAction freelist whenever it becomes exhausted.
358 */
359 #define GL_EXT_ACT_FREELIST_BLOCKING 10
360
361 /*
362 * Define the contents of the GetLine object.
363 * Note that the typedef for this object can be found in libtecla.h.
364 */
365 struct GetLine {
366 ErrMsg *err; /* The error-reporting buffer */
367 GlHistory *glh; /* The line-history buffer */
368 WordCompletion *cpl; /* String completion resource object */
369 GlCplCallback cplfn; /* The completion callback */
370 #ifndef WITHOUT_FILE_SYSTEM
371 ExpandFile *ef; /* ~user/, $envvar and wildcard expansion */
372 /* resource object. */
373 #endif
374 StringGroup *capmem; /* Memory for recording terminal capability */
375 /* strings. */
376 GlCharQueue *cq; /* The terminal output character queue */
377 int input_fd; /* The file descriptor to read on */
378 int output_fd; /* The file descriptor to write to */
379 FILE *input_fp; /* A stream wrapper around input_fd */
380 FILE *output_fp; /* A stream wrapper around output_fd */
381 FILE *file_fp; /* When input is being temporarily taken from */
382 /* a file, this is its file-pointer. Otherwise */
383 /* it is NULL. */
384 char *term; /* The terminal type specified on the last call */
385 /* to gl_change_terminal(). */
386 int is_term; /* True if stdin is a terminal */
387 GlWriteFn *flush_fn; /* The function to call to write to the terminal */
388 GlIOMode io_mode; /* The I/O mode established by gl_io_mode() */
389 int raw_mode; /* True while the terminal is in raw mode */
390 GlPendingIO pending_io; /* The type of I/O that is currently pending */
391 GlReturnStatus rtn_status; /* The reason why gl_get_line() returned */
392 int rtn_errno; /* THe value of errno associated with rtn_status */
393 size_t linelen; /* The max number of characters per line */
394 char *line; /* A line-input buffer of allocated size */
395 /* linelen+2. The extra 2 characters are */
396 /* reserved for "\n\0". */
397 char *cutbuf; /* A cut-buffer of the same size as line[] */
398 char *prompt; /* The current prompt string */
399 int prompt_len; /* The length of the prompt string */
400 int prompt_changed; /* True after a callback changes the prompt */
401 int prompt_style; /* How the prompt string is displayed */
402 FreeList *cpl_mem; /* Memory for GlCplCallback objects */
403 FreeList *ext_act_mem; /* Memory for GlExternalAction objects */
404 FreeList *sig_mem; /* Memory for nodes of the signal list */
405 GlSignalNode *sigs; /* The head of the list of signals */
406 int signals_masked; /* True between calls to gl_mask_signals() and */
407 /* gl_unmask_signals() */
408 int signals_overriden; /* True between calls to gl_override_signals() */
409 /* and gl_restore_signals() */
410 sigset_t all_signal_set; /* The set of all signals that we are trapping */
411 sigset_t old_signal_set; /* The set of blocked signals on entry to */
412 /* gl_get_line(). */
413 sigset_t use_signal_set; /* The subset of all_signal_set to unblock */
414 /* while waiting for key-strokes */
415 Termios oldattr; /* Saved terminal attributes. */
416 KeyTab *bindings; /* A table of key-bindings */
417 int ntotal; /* The number of characters in gl->line[] */
418 int buff_curpos; /* The cursor position within gl->line[] */
419 int term_curpos; /* The cursor position on the terminal */
420 int term_len; /* The number of terminal characters used to */
421 /* display the current input line. */
422 int buff_mark; /* A marker location in the buffer */
423 int insert_curpos; /* The cursor position at start of insert */
424 int insert; /* True in insert mode */
425 int number; /* If >= 0, a numeric argument is being read */
426 int endline; /* True to tell gl_get_input_line() to return */
427 /* the current contents of gl->line[] */
428 int displayed; /* True if an input line is currently displayed */
429 int redisplay; /* If true, the input line will be redrawn */
430 /* either after the current action function */
431 /* returns, or when gl_get_input_line() */
432 /* is next called. */
433 int postpone; /* _gl_normal_io() sets this flag, to */
434 /* postpone any redisplays until */
435 /* is next called, to resume line editing. */
436 char keybuf[GL_KEY_MAX+1]; /* A buffer of currently unprocessed key presses */
437 int nbuf; /* The number of characters in keybuf[] */
438 int nread; /* The number of characters read from keybuf[] */
439 KtAction current_action; /* The action function that is being invoked */
440 int current_count; /* The repeat count passed to */
441 /* current_acction.fn() */
442 GlhLineID preload_id; /* When not zero, this should be the ID of a */
443 /* line in the history buffer for potential */
444 /* recall. */
445 int preload_history; /* If true, preload the above history line when */
446 /* gl_get_input_line() is next called. */
447 long keyseq_count; /* The number of key sequences entered by the */
448 /* the user since new_GetLine() was called. */
449 long last_search; /* The value of keyseq_count during the last */
450 /* history search operation. */
451 GlEditor editor; /* The style of editing, (eg. vi or emacs) */
452 int silence_bell; /* True if gl_ring_bell() should do nothing. */
453 int automatic_history; /* True to automatically archive entered lines */
454 /* in the history list. */
455 ViMode vi; /* Parameters used when editing in vi mode */
456 const char *left; /* The string that moves the cursor 1 character */
457 /* left. */
458 const char *right; /* The string that moves the cursor 1 character */
459 /* right. */
460 const char *up; /* The string that moves the cursor 1 character */
461 /* up. */
462 const char *down; /* The string that moves the cursor 1 character */
463 /* down. */
464 const char *home; /* The string that moves the cursor home */
465 const char *bol; /* Move cursor to beginning of line */
466 const char *clear_eol; /* The string that clears from the cursor to */
467 /* the end of the line. */
468 const char *clear_eod; /* The string that clears from the cursor to */
469 /* the end of the display. */
470 const char *u_arrow; /* The string returned by the up-arrow key */
471 const char *d_arrow; /* The string returned by the down-arrow key */
472 const char *l_arrow; /* The string returned by the left-arrow key */
473 const char *r_arrow; /* The string returned by the right-arrow key */
474 const char *sound_bell; /* The string needed to ring the terminal bell */
475 const char *bold; /* Switch to the bold font */
476 const char *underline; /* Underline subsequent characters */
477 const char *standout; /* Turn on standout mode */
478 const char *dim; /* Switch to a dim font */
479 const char *reverse; /* Turn on reverse video */
480 const char *blink; /* Switch to a blinking font */
481 const char *text_attr_off; /* Turn off all text attributes */
482 int nline; /* The height of the terminal in lines */
483 int ncolumn; /* The width of the terminal in columns */
484 #ifdef USE_TERMCAP
485 char *tgetent_buf; /* The buffer that is used by tgetent() to */
486 /* store a terminal description. */
487 char *tgetstr_buf; /* The buffer that is used by tgetstr() to */
488 /* store terminal capabilities. */
489 #endif
490 #ifdef USE_TERMINFO
491 const char *left_n; /* The parameter string that moves the cursor */
492 /* n characters left. */
493 const char *right_n; /* The parameter string that moves the cursor */
494 /* n characters right. */
495 #endif
496 char *app_file; /* The pathname of the application-specific */
497 /* .teclarc configuration file, or NULL. */
498 char *user_file; /* The pathname of the user-specific */
499 /* .teclarc configuration file, or NULL. */
500 int configured; /* True as soon as any teclarc configuration */
501 /* file has been read. */
502 int echo; /* True to display the line as it is being */
503 /* entered. If 0, only the prompt will be */
504 /* displayed, and the line will not be */
505 /* archived in the history list. */
506 int last_signal; /* The last signal that was caught by */
507 /* the last call to gl_get_line(), or -1 */
508 /* if no signal has been caught yet. */
509 #ifdef HAVE_SELECT
510 FreeList *fd_node_mem; /* A freelist of GlFdNode structures */
511 GlFdNode *fd_nodes; /* The list of fd event descriptions */
512 fd_set rfds; /* The set of fds to watch for readability */
513 fd_set wfds; /* The set of fds to watch for writability */
514 fd_set ufds; /* The set of fds to watch for urgent data */
515 int max_fd; /* The maximum file-descriptor being watched */
516 struct { /* Inactivity timeout related data */
517 struct timeval dt; /* The inactivity timeout when timer.fn() */
518 /* isn't 0 */
519 GlTimeoutFn *fn; /* The application callback to call when */
520 /* the inactivity timer expires, or 0 if */
521 /* timeouts are not required. */
522 void *data; /* Application provided data to be passed to */
523 /* timer.fn(). */
524 } timer;
525 #endif
526 };
527
528 /*
529 * Define the max amount of space needed to store a termcap terminal
530 * description. Unfortunately this has to be done by guesswork, so
531 * there is the potential for buffer overflows if we guess too small.
532 * Fortunately termcap has been replaced by terminfo on most
533 * platforms, and with terminfo this isn't an issue. The value that I
534 * am using here is the conventional value, as recommended by certain
535 * web references.
536 */
537 #ifdef USE_TERMCAP
538 #define TERMCAP_BUF_SIZE 2048
539 #endif
540
541 /*
542 * Set the size of the string segments used to store terminal capability
543 * strings.
544 */
545 #define CAPMEM_SEGMENT_SIZE 512
546
547 /*
548 * If no terminal size information is available, substitute the
549 * following vt100 default sizes.
550 */
551 #define GL_DEF_NLINE 24
552 #define GL_DEF_NCOLUMN 80
553
554 /*
555 * Enumerate the attributes needed to classify different types of
556 * signals. These attributes reflect the standard default
557 * characteristics of these signals (according to Richard Steven's
558 * Advanced Programming in the UNIX Environment). Note that these values
559 * are all powers of 2, so that they can be combined in a bitwise union.
560 */
561 typedef enum {
562 GLSA_TERM=1, /* A signal that terminates processes */
563 GLSA_SUSP=2, /* A signal that suspends processes */
564 GLSA_CONT=4, /* A signal that is sent when suspended processes resume */
565 GLSA_IGN=8, /* A signal that is ignored */
566 GLSA_CORE=16, /* A signal that generates a core dump */
567 GLSA_HARD=32, /* A signal generated by a hardware exception */
568 GLSA_SIZE=64 /* A signal indicating terminal size changes */
569 } GlSigAttr;
570
571 /*
572 * List the signals that we need to catch. In general these are
573 * those that by default terminate or suspend the process, since
574 * in such cases we need to restore terminal settings.
575 */
576 static const struct GlDefSignal {
577 int signo; /* The number of the signal */
578 unsigned flags; /* A bitwise union of GlSignalFlags enumerators */
579 GlAfterSignal after; /* What to do after the signal has been delivered */
580 int attr; /* The default attributes of this signal, expressed */
581 /* as a bitwise union of GlSigAttr enumerators */
582 int errno_value; /* What to set errno to */
583 } gl_signal_list[] = {
584 {SIGABRT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
585 {SIGALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
586 {SIGCONT, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_CONT|GLSA_IGN, 0},
587 #if defined(SIGHUP)
588 #ifdef ENOTTY
589 {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, ENOTTY},
590 #else
591 {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
592 #endif
593 #endif
594 {SIGINT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
595 #if defined(SIGPIPE)
596 #ifdef EPIPE
597 {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EPIPE},
598 #else
599 {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
600 #endif
601 #endif
602 #ifdef SIGPOLL
603 {SIGPOLL, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
604 #endif
605 #ifdef SIGPWR
606 {SIGPWR, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_IGN, 0},
607 #endif
608 #ifdef SIGQUIT
609 {SIGQUIT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
610 #endif
611 {SIGTERM, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
612 #ifdef SIGTSTP
613 {SIGTSTP, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
614 #endif
615 #ifdef SIGTTIN
616 {SIGTTIN, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
617 #endif
618 #ifdef SIGTTOU
619 {SIGTTOU, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
620 #endif
621 #ifdef SIGUSR1
622 {SIGUSR1, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
623 #endif
624 #ifdef SIGUSR2
625 {SIGUSR2, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
626 #endif
627 #ifdef SIGVTALRM
628 {SIGVTALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
629 #endif
630 #ifdef SIGWINCH
631 {SIGWINCH, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_SIZE|GLSA_IGN, 0},
632 #endif
633 #ifdef SIGXCPU
634 {SIGXCPU, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
635 #endif
636 #ifdef SIGXFSZ
637 {SIGXFSZ, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
638 #endif
639 };
640
641 /*
642 * Define file-scope variables for use in signal handlers.
643 */
644 static volatile sig_atomic_t gl_pending_signal = -1;
645 static sigjmp_buf gl_setjmp_buffer;
646
647 static void gl_signal_handler(int signo);
648
649 static int gl_check_caught_signal(GetLine *gl);
650
651 /*
652 * Respond to an externally caught process suspension or
653 * termination signal.
654 */
655 static void gl_suspend_process(int signo, GetLine *gl, int ngl);
656
657 /* Return the default attributes of a given signal */
658
659 static int gl_classify_signal(int signo);
660
661 /*
662 * Unfortunately both terminfo and termcap require one to use the tputs()
663 * function to output terminal control characters, and this function
664 * doesn't allow one to specify a file stream. As a result, the following
665 * file-scope variable is used to pass the current output file stream.
666 * This is bad, but there doesn't seem to be any alternative.
667 */
668 static GetLine *tputs_gl = NULL;
669
670 /*
671 * Define a tab to be a string of 8 spaces.
672 */
673 #define TAB_WIDTH 8
674
675 /*
676 * Lookup the current size of the terminal.
677 */
678 static void gl_query_size(GetLine *gl, int *ncolumn, int *nline);
679
680 /*
681 * Getline calls this to temporarily override certain signal handlers
682 * of the calling program.
683 */
684 static int gl_override_signal_handlers(GetLine *gl);
685
686 /*
687 * Getline calls this to restore the signal handlers of the calling
688 * program.
689 */
690 static int gl_restore_signal_handlers(GetLine *gl);
691
692 /*
693 * Temporarily block the delivery of all signals that gl_get_line()
694 * is currently configured to trap.
695 */
696 static int gl_mask_signals(GetLine *gl, sigset_t *oldset);
697
698 /*
699 * Restore the process signal mask that was overriden by a previous
700 * call to gl_mask_signals().
701 */
702 static int gl_unmask_signals(GetLine *gl, sigset_t *oldset);
703
704 /*
705 * Unblock the signals that gl_get_line() has been configured to catch.
706 */
707 static int gl_catch_signals(GetLine *gl);
708
709 /*
710 * Return the set of all trappable signals.
711 */
712 static void gl_list_trappable_signals(sigset_t *signals);
713
714 /*
715 * Put the terminal into raw input mode, after saving the original
716 * terminal attributes in gl->oldattr.
717 */
718 static int gl_raw_terminal_mode(GetLine *gl);
719
720 /*
721 * Restore the terminal attributes from gl->oldattr.
722 */
723 static int gl_restore_terminal_attributes(GetLine *gl);
724
725 /*
726 * Switch to non-blocking I/O if possible.
727 */
728 static int gl_nonblocking_io(GetLine *gl, int fd);
729
730 /*
731 * Switch to blocking I/O if possible.
732 */
733 static int gl_blocking_io(GetLine *gl, int fd);
734
735 /*
736 * Read a line from the user in raw mode.
737 */
738 static int gl_get_input_line(GetLine *gl, const char *prompt,
739 const char *start_line, int start_pos);
740
741 /*
742 * Query the user for a single character.
743 */
744 static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar);
745
746 /*
747 * Read input from a non-interactive input stream.
748 */
749 static int gl_read_stream_line(GetLine *gl);
750
751 /*
752 * Read a single character from a non-interactive input stream.
753 */
754 static int gl_read_stream_char(GetLine *gl);
755
756 /*
757 * Prepare to edit a new line.
758 */
759 static int gl_present_line(GetLine *gl, const char *prompt,
760 const char *start_line, int start_pos);
761
762 /*
763 * Reset all line input parameters for a new input line.
764 */
765 static void gl_reset_input_line(GetLine *gl);
766
767 /*
768 * Handle the receipt of the potential start of a new key-sequence from
769 * the user.
770 */
771 static int gl_interpret_char(GetLine *gl, char c);
772
773 /*
774 * Bind a single control or meta character to an action.
775 */
776 static int gl_bind_control_char(GetLine *gl, KtBinder binder,
777 char c, const char *action);
778
779 /*
780 * Set up terminal-specific key bindings.
781 */
782 static int gl_bind_terminal_keys(GetLine *gl);
783
784 /*
785 * Lookup terminal control string and size information.
786 */
787 static int gl_control_strings(GetLine *gl, const char *term);
788
789 /*
790 * Wrappers around the terminfo and termcap functions that lookup
791 * strings in the terminal information databases.
792 */
793 #ifdef USE_TERMINFO
794 static const char *gl_tigetstr(GetLine *gl, const char *name);
795 #elif defined(USE_TERMCAP)
796 static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr);
797 #endif
798
799 /*
800 * Output a binary string directly to the terminal.
801 */
802 static int gl_print_raw_string(GetLine *gl, int buffered,
803 const char *string, int n);
804
805 /*
806 * Print an informational message, starting and finishing on new lines.
807 * After the list of strings to be printed, the last argument MUST be
808 * GL_END_INFO.
809 */
810 static int gl_print_info(GetLine *gl, ...);
811 #define GL_END_INFO ((const char *)0)
812
813 /*
814 * Start a newline and place the cursor at its start.
815 */
816 static int gl_start_newline(GetLine *gl, int buffered);
817
818 /*
819 * Output a terminal control sequence.
820 */
821 static int gl_print_control_sequence(GetLine *gl, int nline,
822 const char *string);
823
824 /*
825 * Output a character or string to the terminal after converting tabs
826 * to spaces and control characters to a caret followed by the modified
827 * character.
828 */
829 static int gl_print_char(GetLine *gl, char c, char pad);
830 static int gl_print_string(GetLine *gl, const char *string, char pad);
831
832 /*
833 * Delete nc characters starting from the one under the cursor.
834 * Optionally copy the deleted characters to the cut buffer.
835 */
836 static int gl_delete_chars(GetLine *gl, int nc, int cut);
837
838 /*
839 * Add a character to the line buffer at the current cursor position,
840 * inserting or overwriting according the current mode.
841 */
842 static int gl_add_char_to_line(GetLine *gl, char c);
843
844 /*
845 * Insert/append a string to the line buffer and terminal at the current
846 * cursor position.
847 */
848 static int gl_add_string_to_line(GetLine *gl, const char *s);
849
850 /*
851 * Record a new character in the input-line buffer.
852 */
853 static int gl_buffer_char(GetLine *gl, char c, int bufpos);
854
855 /*
856 * Record a string in the input-line buffer.
857 */
858 static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos);
859
860 /*
861 * Make way to insert a string in the input-line buffer.
862 */
863 static int gl_make_gap_in_buffer(GetLine *gl, int start, int n);
864
865 /*
866 * Remove characters from the input-line buffer, and move any characters
867 * that followed them to the start of the vacated space.
868 */
869 static void gl_remove_from_buffer(GetLine *gl, int start, int n);
870
871 /*
872 * Terminate the input-line buffer after a specified number of characters.
873 */
874 static int gl_truncate_buffer(GetLine *gl, int n);
875
876 /*
877 * Delete the displayed part of the input line that follows the current
878 * terminal cursor position.
879 */
880 static int gl_truncate_display(GetLine *gl);
881
882 /*
883 * Accomodate changes to the contents of the input line buffer
884 * that weren't made by the above gl_*buffer functions.
885 */
886 static void gl_update_buffer(GetLine *gl);
887
888 /*
889 * Read a single character from the terminal.
890 */
891 static int gl_read_terminal(GetLine *gl, int keep, char *c);
892
893 /*
894 * Discard processed characters from the key-press lookahead buffer.
895 */
896 static void gl_discard_chars(GetLine *gl, int nused);
897
898 /*
899 * Move the terminal cursor n positions to the left or right.
900 */
901 static int gl_terminal_move_cursor(GetLine *gl, int n);
902
903 /*
904 * Move the terminal cursor to a given position.
905 */
906 static int gl_set_term_curpos(GetLine *gl, int term_curpos);
907
908 /*
909 * Set the position of the cursor both in the line input buffer and on the
910 * terminal.
911 */
912 static int gl_place_cursor(GetLine *gl, int buff_curpos);
913
914 /*
915 * How many characters are needed to write a number as an octal string?
916 */
917 static int gl_octal_width(unsigned num);
918
919 /*
920 * Return the number of spaces needed to display a tab character at
921 * a given location of the terminal.
922 */
923 static int gl_displayed_tab_width(GetLine *gl, int term_curpos);
924
925 /*
926 * Return the number of terminal characters needed to display a
927 * given raw character.
928 */
929 static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos);
930
931 /*
932 * Return the number of terminal characters needed to display a
933 * given substring.
934 */
935 static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
936 int term_curpos);
937
938 /*
939 * Return non-zero if 'c' is to be considered part of a word.
940 */
941 static int gl_is_word_char(int c);
942
943 /*
944 * Read a tecla configuration file.
945 */
946 static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who);
947
948 /*
949 * Read a tecla configuration string.
950 */
951 static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who);
952
953 /*
954 * Define the callback function used by _gl_parse_config_line() to
955 * read the next character of a configuration stream.
956 */
957 #define GLC_GETC_FN(fn) int (fn)(void *stream)
958 typedef GLC_GETC_FN(GlcGetcFn);
959
960 static GLC_GETC_FN(glc_file_getc); /* Read from a file */
961 static GLC_GETC_FN(glc_buff_getc); /* Read from a string */
962
963 /*
964 * Parse a single configuration command line.
965 */
966 static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
967 const char *origin, KtBinder who, int *lineno);
968 static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
969 const char *errmsg);
970
971 /*
972 * Bind the actual arrow key bindings to match those of the symbolic
973 * arrow-key bindings.
974 */
975 static int _gl_bind_arrow_keys(GetLine *gl);
976
977 /*
978 * Copy the binding of the specified symbolic arrow-key binding to
979 * the terminal specific, and default arrow-key key-sequences.
980 */
981 static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
982 const char *term_seq,
983 const char *def_seq1,
984 const char *def_seq2);
985
986 /*
987 * After the gl_read_from_file() action has been used to tell gl_get_line()
988 * to temporarily read input from a file, gl_revert_input() arranges
989 * for input to be reverted to the input stream last registered with
990 * gl_change_terminal().
991 */
992 static void gl_revert_input(GetLine *gl);
993
994 /*
995 * Flush unwritten characters to the terminal.
996 */
997 static int gl_flush_output(GetLine *gl);
998
999 /*
1000 * The callback through which all terminal output is routed.
1001 * This simply appends characters to a queue buffer, which is
1002 * subsequently flushed to the output channel by gl_flush_output().
1003 */
1004 static GL_WRITE_FN(gl_write_fn);
1005
1006 /*
1007 * The callback function which the output character queue object
1008 * calls to transfer characters to the output channel.
1009 */
1010 static GL_WRITE_FN(gl_flush_terminal);
1011
1012 /*
1013 * Enumerate the possible return statuses of gl_read_input().
1014 */
1015 typedef enum {
1016 GL_READ_OK, /* A character was read successfully */
1017 GL_READ_ERROR, /* A read-error occurred */
1018 GL_READ_BLOCKED, /* The read would have blocked the caller */
1019 GL_READ_EOF /* The end of the current input file was reached */
1020 } GlReadStatus;
1021
1022 static GlReadStatus gl_read_input(GetLine *gl, char *c);
1023 /*
1024 * Private functions of gl_read_input().
1025 */
1026 static int gl_event_handler(GetLine *gl, int fd);
1027 static int gl_read_unmasked(GetLine *gl, int fd, char *c);
1028
1029
1030 /*
1031 * A private function of gl_tty_signals().
1032 */
1033 static int gl_set_tty_signal(int signo, void (*handler)(int));
1034
1035 /*
1036 * Change the editor style being emulated.
1037 */
1038 static int gl_change_editor(GetLine *gl, GlEditor editor);
1039
1040 /*
1041 * Searching in a given direction, return the index of a given (or
1042 * read) character in the input line, or the character that precedes
1043 * it in the specified search direction. Return -1 if not found.
1044 */
1045 static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c);
1046
1047 /*
1048 * Return the buffer index of the nth word ending after the cursor.
1049 */
1050 static int gl_nth_word_end_forward(GetLine *gl, int n);
1051
1052 /*
1053 * Return the buffer index of the nth word start after the cursor.
1054 */
1055 static int gl_nth_word_start_forward(GetLine *gl, int n);
1056
1057 /*
1058 * Return the buffer index of the nth word start before the cursor.
1059 */
1060 static int gl_nth_word_start_backward(GetLine *gl, int n);
1061
1062 /*
1063 * When called when vi command mode is enabled, this function saves the
1064 * current line and cursor position for potential restoration later
1065 * by the vi undo command.
1066 */
1067 static void gl_save_for_undo(GetLine *gl);
1068
1069 /*
1070 * If in vi mode, switch to vi command mode.
1071 */
1072 static void gl_vi_command_mode(GetLine *gl);
1073
1074 /*
1075 * In vi mode this is used to delete up to or onto a given or read
1076 * character in the input line. Also switch to insert mode if requested
1077 * after the deletion.
1078 */
1079 static int gl_delete_find(GetLine *gl, int count, char c, int forward,
1080 int onto, int change);
1081
1082 /*
1083 * Copy the characters between the cursor and the count'th instance of
1084 * a specified (or read) character in the input line, into the cut buffer.
1085 */
1086 static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto);
1087
1088 /*
1089 * Return the line index of the parenthesis that either matches the one under
1090 * the cursor, or not over a parenthesis character, the index of the next
1091 * close parenthesis. Return -1 if not found.
1092 */
1093 static int gl_index_of_matching_paren(GetLine *gl);
1094
1095 /*
1096 * Replace a malloc'd string (or NULL), with another malloc'd copy of
1097 * a string (or NULL).
1098 */
1099 static int gl_record_string(char **sptr, const char *string);
1100
1101 /*
1102 * Enumerate text display attributes as powers of two, suitable for
1103 * use in a bit-mask.
1104 */
1105 typedef enum {
1106 GL_TXT_STANDOUT=1, /* Display text highlighted */
1107 GL_TXT_UNDERLINE=2, /* Display text underlined */
1108 GL_TXT_REVERSE=4, /* Display text with reverse video */
1109 GL_TXT_BLINK=8, /* Display blinking text */
1110 GL_TXT_DIM=16, /* Display text in a dim font */
1111 GL_TXT_BOLD=32 /* Display text using a bold font */
1112 } GlTextAttr;
1113
1114 /*
1115 * Display the prompt regardless of the current visibility mode.
1116 */
1117 static int gl_display_prompt(GetLine *gl);
1118
1119 /*
1120 * Return the number of characters used by the prompt on the terminal.
1121 */
1122 static int gl_displayed_prompt_width(GetLine *gl);
1123
1124 /*
1125 * Prepare to return the current input line to the caller of gl_get_line().
1126 */
1127 static int gl_line_ended(GetLine *gl, int newline_char);
1128
1129 /*
1130 * Arrange for the input line to be redisplayed when the current contents
1131 * of the output queue have been flushed.
1132 */
1133 static void gl_queue_redisplay(GetLine *gl);
1134
1135 /*
1136 * Erase the displayed representation of the input line, without
1137 * touching the buffered copy.
1138 */
1139 static int gl_erase_line(GetLine *gl);
1140
1141 /*
1142 * This function is called whenever the input line has been erased.
1143 */
1144 static void gl_line_erased(GetLine *gl);
1145
1146 /*
1147 * Arrange for the current input line to be discarded.
1148 */
1149 void _gl_abandon_line(GetLine *gl);
1150
1151 /*
1152 * The following are private internally callable versions of pertinent
1153 * public functions. Unlike their public wrapper functions, they don't
1154 * block signals while running, and assume that their arguments are valid.
1155 * They are designed to be called from places where signals are already
1156 * blocked, and where simple sanity checks have already been applied to
1157 * their arguments.
1158 */
1159 static char *_gl_get_line(GetLine *gl, const char *prompt,
1160 const char *start_line, int start_pos);
1161 static int _gl_query_char(GetLine *gl, const char *prompt, char defchar);
1162 static int _gl_read_char(GetLine *gl);
1163 static int _gl_update_size(GetLine *gl);
1164 /*
1165 * Redraw the current input line to account for a change in the terminal
1166 * size. Also install the new size in gl.
1167 */
1168 static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline);
1169
1170 static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
1171 const char *term);
1172 static int _gl_configure_getline(GetLine *gl, const char *app_string,
1173 const char *app_file, const char *user_file);
1174 static int _gl_save_history(GetLine *gl, const char *filename,
1175 const char *comment, int max_lines);
1176 static int _gl_load_history(GetLine *gl, const char *filename,
1177 const char *comment);
1178 static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
1179 GlFdEventFn *callback, void *data);
1180 static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
1181 GlTerminalSize *size);
1182 static void _gl_replace_prompt(GetLine *gl, const char *prompt);
1183 static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
1184 GlAfterSignal after, int errno_value);
1185 static int _gl_raw_io(GetLine *gl, int redisplay);
1186 static int _gl_normal_io(GetLine *gl);
1187 static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
1188 int list_only, const char *name,
1189 const char *keyseq);
1190 static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
1191 const char *name, const char *keyseq);
1192 static int _gl_io_mode(GetLine *gl, GlIOMode mode);
1193 static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline);
1194 static int _gl_append_history(GetLine *gl, const char *line);
1195
1196 /*
1197 * Reset the completion status and associated errno value in
1198 * gl->rtn_status and gl->rtn_errno.
1199 */
1200 static void gl_clear_status(GetLine *gl);
1201
1202 /*
1203 * Record a completion status, unless a previous abnormal completion
1204 * status has already been recorded for the current call.
1205 */
1206 static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
1207 int rtn_errno);
1208
1209 /*
1210 * Set the maximum length of a line in a user's tecla configuration
1211 * file (not counting comments).
1212 */
1213 #define GL_CONF_BUFLEN 100
1214
1215 /*
1216 * Set the maximum number of arguments supported by individual commands
1217 * in tecla configuration files.
1218 */
1219 #define GL_CONF_MAXARG 10
1220
1221 /*
1222 * Prototype the available action functions.
1223 */
1224 static KT_KEY_FN(gl_user_interrupt);
1225 static KT_KEY_FN(gl_abort);
1226 static KT_KEY_FN(gl_suspend);
1227 static KT_KEY_FN(gl_stop_output);
1228 static KT_KEY_FN(gl_start_output);
1229 static KT_KEY_FN(gl_literal_next);
1230 static KT_KEY_FN(gl_cursor_left);
1231 static KT_KEY_FN(gl_cursor_right);
1232 static KT_KEY_FN(gl_insert_mode);
1233 static KT_KEY_FN(gl_beginning_of_line);
1234 static KT_KEY_FN(gl_end_of_line);
1235 static KT_KEY_FN(gl_delete_line);
1236 static KT_KEY_FN(gl_kill_line);
1237 static KT_KEY_FN(gl_forward_word);
1238 static KT_KEY_FN(gl_backward_word);
1239 static KT_KEY_FN(gl_forward_delete_char);
1240 static KT_KEY_FN(gl_backward_delete_char);
1241 static KT_KEY_FN(gl_forward_delete_word);
1242 static KT_KEY_FN(gl_backward_delete_word);
1243 static KT_KEY_FN(gl_delete_refind);
1244 static KT_KEY_FN(gl_delete_invert_refind);
1245 static KT_KEY_FN(gl_delete_to_column);
1246 static KT_KEY_FN(gl_delete_to_parenthesis);
1247 static KT_KEY_FN(gl_forward_delete_find);
1248 static KT_KEY_FN(gl_backward_delete_find);
1249 static KT_KEY_FN(gl_forward_delete_to);
1250 static KT_KEY_FN(gl_backward_delete_to);
1251 static KT_KEY_FN(gl_upcase_word);
1252 static KT_KEY_FN(gl_downcase_word);
1253 static KT_KEY_FN(gl_capitalize_word);
1254 static KT_KEY_FN(gl_redisplay);
1255 static KT_KEY_FN(gl_clear_screen);
1256 static KT_KEY_FN(gl_transpose_chars);
1257 static KT_KEY_FN(gl_set_mark);
1258 static KT_KEY_FN(gl_exchange_point_and_mark);
1259 static KT_KEY_FN(gl_kill_region);
1260 static KT_KEY_FN(gl_copy_region_as_kill);
1261 static KT_KEY_FN(gl_yank);
1262 static KT_KEY_FN(gl_up_history);
1263 static KT_KEY_FN(gl_down_history);
1264 static KT_KEY_FN(gl_history_search_backward);
1265 static KT_KEY_FN(gl_history_re_search_backward);
1266 static KT_KEY_FN(gl_history_search_forward);
1267 static KT_KEY_FN(gl_history_re_search_forward);
1268 static KT_KEY_FN(gl_complete_word);
1269 #ifndef HIDE_FILE_SYSTEM
1270 static KT_KEY_FN(gl_expand_filename);
1271 static KT_KEY_FN(gl_read_from_file);
1272 static KT_KEY_FN(gl_read_init_files);
1273 static KT_KEY_FN(gl_list_glob);
1274 #endif
1275 static KT_KEY_FN(gl_del_char_or_list_or_eof);
1276 static KT_KEY_FN(gl_list_or_eof);
1277 static KT_KEY_FN(gl_beginning_of_history);
1278 static KT_KEY_FN(gl_end_of_history);
1279 static KT_KEY_FN(gl_digit_argument);
1280 static KT_KEY_FN(gl_newline);
1281 static KT_KEY_FN(gl_repeat_history);
1282 static KT_KEY_FN(gl_vi_insert);
1283 static KT_KEY_FN(gl_vi_overwrite);
1284 static KT_KEY_FN(gl_change_case);
1285 static KT_KEY_FN(gl_vi_insert_at_bol);
1286 static KT_KEY_FN(gl_vi_append_at_eol);
1287 static KT_KEY_FN(gl_vi_append);
1288 static KT_KEY_FN(gl_backward_kill_line);
1289 static KT_KEY_FN(gl_goto_column);
1290 static KT_KEY_FN(gl_forward_to_word);
1291 static KT_KEY_FN(gl_vi_replace_char);
1292 static KT_KEY_FN(gl_vi_change_rest_of_line);
1293 static KT_KEY_FN(gl_vi_change_line);
1294 static KT_KEY_FN(gl_vi_change_to_bol);
1295 static KT_KEY_FN(gl_vi_change_refind);
1296 static KT_KEY_FN(gl_vi_change_invert_refind);
1297 static KT_KEY_FN(gl_vi_change_to_column);
1298 static KT_KEY_FN(gl_vi_change_to_parenthesis);
1299 static KT_KEY_FN(gl_vi_forward_change_word);
1300 static KT_KEY_FN(gl_vi_backward_change_word);
1301 static KT_KEY_FN(gl_vi_forward_change_find);
1302 static KT_KEY_FN(gl_vi_backward_change_find);
1303 static KT_KEY_FN(gl_vi_forward_change_to);
1304 static KT_KEY_FN(gl_vi_backward_change_to);
1305 static KT_KEY_FN(gl_vi_forward_change_char);
1306 static KT_KEY_FN(gl_vi_backward_change_char);
1307 static KT_KEY_FN(gl_forward_copy_char);
1308 static KT_KEY_FN(gl_backward_copy_char);
1309 static KT_KEY_FN(gl_forward_find_char);
1310 static KT_KEY_FN(gl_backward_find_char);
1311 static KT_KEY_FN(gl_forward_to_char);
1312 static KT_KEY_FN(gl_backward_to_char);
1313 static KT_KEY_FN(gl_repeat_find_char);
1314 static KT_KEY_FN(gl_invert_refind_char);
1315 static KT_KEY_FN(gl_append_yank);
1316 static KT_KEY_FN(gl_backward_copy_word);
1317 static KT_KEY_FN(gl_forward_copy_word);
1318 static KT_KEY_FN(gl_copy_to_bol);
1319 static KT_KEY_FN(gl_copy_refind);
1320 static KT_KEY_FN(gl_copy_invert_refind);
1321 static KT_KEY_FN(gl_copy_to_column);
1322 static KT_KEY_FN(gl_copy_to_parenthesis);
1323 static KT_KEY_FN(gl_copy_rest_of_line);
1324 static KT_KEY_FN(gl_copy_line);
1325 static KT_KEY_FN(gl_backward_copy_find);
1326 static KT_KEY_FN(gl_forward_copy_find);
1327 static KT_KEY_FN(gl_backward_copy_to);
1328 static KT_KEY_FN(gl_forward_copy_to);
1329 static KT_KEY_FN(gl_vi_undo);
1330 static KT_KEY_FN(gl_emacs_editing_mode);
1331 static KT_KEY_FN(gl_vi_editing_mode);
1332 static KT_KEY_FN(gl_ring_bell);
1333 static KT_KEY_FN(gl_vi_repeat_change);
1334 static KT_KEY_FN(gl_find_parenthesis);
1335 static KT_KEY_FN(gl_list_history);
1336 static KT_KEY_FN(gl_list_completions);
1337 static KT_KEY_FN(gl_run_external_action);
1338
1339 /*
1340 * Name the available action functions.
1341 */
1342 static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = {
1343 {"user-interrupt", gl_user_interrupt},
1344 {"abort", gl_abort},
1345 {"suspend", gl_suspend},
1346 {"stop-output", gl_stop_output},
1347 {"start-output", gl_start_output},
1348 {"literal-next", gl_literal_next},
1349 {"cursor-right", gl_cursor_right},
1350 {"cursor-left", gl_cursor_left},
1351 {"insert-mode", gl_insert_mode},
1352 {"beginning-of-line", gl_beginning_of_line},
1353 {"end-of-line", gl_end_of_line},
1354 {"delete-line", gl_delete_line},
1355 {"kill-line", gl_kill_line},
1356 {"forward-word", gl_forward_word},
1357 {"backward-word", gl_backward_word},
1358 {"forward-delete-char", gl_forward_delete_char},
1359 {"backward-delete-char", gl_backward_delete_char},
1360 {"forward-delete-word", gl_forward_delete_word},
1361 {"backward-delete-word", gl_backward_delete_word},
1362 {"delete-refind", gl_delete_refind},
1363 {"delete-invert-refind", gl_delete_invert_refind},
1364 {"delete-to-column", gl_delete_to_column},
1365 {"delete-to-parenthesis", gl_delete_to_parenthesis},
1366 {"forward-delete-find", gl_forward_delete_find},
1367 {"backward-delete-find", gl_backward_delete_find},
1368 {"forward-delete-to", gl_forward_delete_to},
1369 {"backward-delete-to", gl_backward_delete_to},
1370 {"upcase-word", gl_upcase_word},
1371 {"downcase-word", gl_downcase_word},
1372 {"capitalize-word", gl_capitalize_word},
1373 {"redisplay", gl_redisplay},
1374 {"clear-screen", gl_clear_screen},
1375 {"transpose-chars", gl_transpose_chars},
1376 {"set-mark", gl_set_mark},
1377 {"exchange-point-and-mark", gl_exchange_point_and_mark},
1378 {"kill-region", gl_kill_region},
1379 {"copy-region-as-kill", gl_copy_region_as_kill},
1380 {"yank", gl_yank},
1381 {"up-history", gl_up_history},
1382 {"down-history", gl_down_history},
1383 {"history-search-backward", gl_history_search_backward},
1384 {"history-re-search-backward", gl_history_re_search_backward},
1385 {"history-search-forward", gl_history_search_forward},
1386 {"history-re-search-forward", gl_history_re_search_forward},
1387 {"complete-word", gl_complete_word},
1388 #ifndef HIDE_FILE_SYSTEM
1389 {"expand-filename", gl_expand_filename},
1390 {"read-from-file", gl_read_from_file},
1391 {"read-init-files", gl_read_init_files},
1392 {"list-glob", gl_list_glob},
1393 #endif
1394 {"del-char-or-list-or-eof", gl_del_char_or_list_or_eof},
1395 {"beginning-of-history", gl_beginning_of_history},
1396 {"end-of-history", gl_end_of_history},
1397 {"digit-argument", gl_digit_argument},
1398 {"newline", gl_newline},
1399 {"repeat-history", gl_repeat_history},
1400 {"vi-insert", gl_vi_insert},
1401 {"vi-overwrite", gl_vi_overwrite},
1402 {"vi-insert-at-bol", gl_vi_insert_at_bol},
1403 {"vi-append-at-eol", gl_vi_append_at_eol},
1404 {"vi-append", gl_vi_append},
1405 {"change-case", gl_change_case},
1406 {"backward-kill-line", gl_backward_kill_line},
1407 {"goto-column", gl_goto_column},
1408 {"forward-to-word", gl_forward_to_word},
1409 {"vi-replace-char", gl_vi_replace_char},
1410 {"vi-change-rest-of-line", gl_vi_change_rest_of_line},
1411 {"vi-change-line", gl_vi_change_line},
1412 {"vi-change-to-bol", gl_vi_change_to_bol},
1413 {"vi-change-refind", gl_vi_change_refind},
1414 {"vi-change-invert-refind", gl_vi_change_invert_refind},
1415 {"vi-change-to-column", gl_vi_change_to_column},
1416 {"vi-change-to-parenthesis", gl_vi_change_to_parenthesis},
1417 {"forward-copy-char", gl_forward_copy_char},
1418 {"backward-copy-char", gl_backward_copy_char},
1419 {"forward-find-char", gl_forward_find_char},
1420 {"backward-find-char", gl_backward_find_char},
1421 {"forward-to-char", gl_forward_to_char},
1422 {"backward-to-char", gl_backward_to_char},
1423 {"repeat-find-char", gl_repeat_find_char},
1424 {"invert-refind-char", gl_invert_refind_char},
1425 {"append-yank", gl_append_yank},
1426 {"backward-copy-word", gl_backward_copy_word},
1427 {"forward-copy-word", gl_forward_copy_word},
1428 {"copy-to-bol", gl_copy_to_bol},
1429 {"copy-refind", gl_copy_refind},
1430 {"copy-invert-refind", gl_copy_invert_refind},
1431 {"copy-to-column", gl_copy_to_column},
1432 {"copy-to-parenthesis", gl_copy_to_parenthesis},
1433 {"copy-rest-of-line", gl_copy_rest_of_line},
1434 {"copy-line", gl_copy_line},
1435 {"backward-copy-find", gl_backward_copy_find},
1436 {"forward-copy-find", gl_forward_copy_find},
1437 {"backward-copy-to", gl_backward_copy_to},
1438 {"forward-copy-to", gl_forward_copy_to},
1439 {"list-or-eof", gl_list_or_eof},
1440 {"vi-undo", gl_vi_undo},
1441 {"vi-backward-change-word", gl_vi_backward_change_word},
1442 {"vi-forward-change-word", gl_vi_forward_change_word},
1443 {"vi-backward-change-find", gl_vi_backward_change_find},
1444 {"vi-forward-change-find", gl_vi_forward_change_find},
1445 {"vi-backward-change-to", gl_vi_backward_change_to},
1446 {"vi-forward-change-to", gl_vi_forward_change_to},
1447 {"vi-backward-change-char", gl_vi_backward_change_char},
1448 {"vi-forward-change-char", gl_vi_forward_change_char},
1449 {"emacs-mode", gl_emacs_editing_mode},
1450 {"vi-mode", gl_vi_editing_mode},
1451 {"ring-bell", gl_ring_bell},
1452 {"vi-repeat-change", gl_vi_repeat_change},
1453 {"find-parenthesis", gl_find_parenthesis},
1454 {"list-history", gl_list_history},
1455 };
1456
1457 /*
1458 * Define the default key-bindings in emacs mode.
1459 */
1460 static const KtKeyBinding gl_emacs_bindings[] = {
1461 {"right", "cursor-right"},
1462 {"^F", "cursor-right"},
1463 {"left", "cursor-left"},
1464 {"^B", "cursor-left"},
1465 {"M-i", "insert-mode"},
1466 {"M-I", "insert-mode"},
1467 {"^A", "beginning-of-line"},
1468 {"^E", "end-of-line"},
1469 {"^U", "delete-line"},
1470 {"^K", "kill-line"},
1471 {"M-f", "forward-word"},
1472 {"M-F", "forward-word"},
1473 {"M-b", "backward-word"},
1474 {"M-B", "backward-word"},
1475 {"^D", "del-char-or-list-or-eof"},
1476 {"^H", "backward-delete-char"},
1477 {"^?", "backward-delete-char"},
1478 {"M-d", "forward-delete-word"},
1479 {"M-D", "forward-delete-word"},
1480 {"M-^H", "backward-delete-word"},
1481 {"M-^?", "backward-delete-word"},
1482 {"M-u", "upcase-word"},
1483 {"M-U", "upcase-word"},
1484 {"M-l", "downcase-word"},
1485 {"M-L", "downcase-word"},
1486 {"M-c", "capitalize-word"},
1487 {"M-C", "capitalize-word"},
1488 {"^R", "redisplay"},
1489 {"^L", "clear-screen"},
1490 {"^T", "transpose-chars"},
1491 {"^@", "set-mark"},
1492 {"^X^X", "exchange-point-and-mark"},
1493 {"^W", "kill-region"},
1494 {"M-w", "copy-region-as-kill"},
1495 {"M-W", "copy-region-as-kill"},
1496 {"^Y", "yank"},
1497 {"^P", "up-history"},
1498 {"up", "up-history"},
1499 {"^N", "down-history"},
1500 {"down", "down-history"},
1501 {"M-p", "history-search-backward"},
1502 {"M-P", "history-search-backward"},
1503 {"M-n", "history-search-forward"},
1504 {"M-N", "history-search-forward"},
1505 {"\t", "complete-word"},
1506 #ifndef HIDE_FILE_SYSTEM
1507 {"^X*", "expand-filename"},
1508 {"^X^F", "read-from-file"},
1509 {"^X^R", "read-init-files"},
1510 {"^Xg", "list-glob"},
1511 {"^XG", "list-glob"},
1512 #endif
1513 {"^Xh", "list-history"},
1514 {"^XH", "list-history"},
1515 {"M-<", "beginning-of-history"},
1516 {"M->", "end-of-history"},
1517 {"M-0", "digit-argument"},
1518 {"M-1", "digit-argument"},
1519 {"M-2", "digit-argument"},
1520 {"M-3", "digit-argument"},
1521 {"M-4", "digit-argument"},
1522 {"M-5", "digit-argument"},
1523 {"M-6", "digit-argument"},
1524 {"M-7", "digit-argument"},
1525 {"M-8", "digit-argument"},
1526 {"M-9", "digit-argument"},
1527 {"\r", "newline"},
1528 {"\n", "newline"},
1529 {"M-o", "repeat-history"},
1530 {"M-C-v", "vi-mode"},
1531 };
1532
1533 /*
1534 * Define the default key-bindings in vi mode. Note that in vi-mode
1535 * meta-key bindings are command-mode bindings. For example M-i first
1536 * switches to command mode if not already in that mode, then moves
1537 * the cursor one position right, as in vi.
1538 */
1539 static const KtKeyBinding gl_vi_bindings[] = {
1540 {"^D", "list-or-eof"},
1541 #ifndef HIDE_FILE_SYSTEM
1542 {"^G", "list-glob"},
1543 #endif
1544 {"^H", "backward-delete-char"},
1545 {"\t", "complete-word"},
1546 {"\r", "newline"},
1547 {"\n", "newline"},
1548 {"^L", "clear-screen"},
1549 {"^N", "down-history"},
1550 {"^P", "up-history"},
1551 {"^R", "redisplay"},
1552 {"^U", "backward-kill-line"},
1553 {"^W", "backward-delete-word"},
1554 #ifndef HIDE_FILE_SYSTEM
1555 {"^X^F", "read-from-file"},
1556 {"^X^R", "read-init-files"},
1557 {"^X*", "expand-filename"},
1558 #endif
1559 {"^?", "backward-delete-char"},
1560 {"M- ", "cursor-right"},
1561 {"M-$", "end-of-line"},
1562 #ifndef HIDE_FILE_SYSTEM
1563 {"M-*", "expand-filename"},
1564 #endif
1565 {"M-+", "down-history"},
1566 {"M--", "up-history"},
1567 {"M-<", "beginning-of-history"},
1568 {"M->", "end-of-history"},
1569 {"M-^", "beginning-of-line"},
1570 {"M-;", "repeat-find-char"},
1571 {"M-,", "invert-refind-char"},
1572 {"M-|", "goto-column"},
1573 {"M-~", "change-case"},
1574 {"M-.", "vi-repeat-change"},
1575 {"M-%", "find-parenthesis"},
1576 {"M-0", "digit-argument"},
1577 {"M-1", "digit-argument"},
1578 {"M-2", "digit-argument"},
1579 {"M-3", "digit-argument"},
1580 {"M-4", "digit-argument"},
1581 {"M-5", "digit-argument"},
1582 {"M-6", "digit-argument"},
1583 {"M-7", "digit-argument"},
1584 {"M-8", "digit-argument"},
1585 {"M-9", "digit-argument"},
1586 {"M-a", "vi-append"},
1587 {"M-A", "vi-append-at-eol"},
1588 {"M-b", "backward-word"},
1589 {"M-B", "backward-word"},
1590 {"M-C", "vi-change-rest-of-line"},
1591 {"M-cb", "vi-backward-change-word"},
1592 {"M-cB", "vi-backward-change-word"},
1593 {"M-cc", "vi-change-line"},
1594 {"M-ce", "vi-forward-change-word"},
1595 {"M-cE", "vi-forward-change-word"},
1596 {"M-cw", "vi-forward-change-word"},
1597 {"M-cW", "vi-forward-change-word"},
1598 {"M-cF", "vi-backward-change-find"},
1599 {"M-cf", "vi-forward-change-find"},
1600 {"M-cT", "vi-backward-change-to"},
1601 {"M-ct", "vi-forward-change-to"},
1602 {"M-c;", "vi-change-refind"},
1603 {"M-c,", "vi-change-invert-refind"},
1604 {"M-ch", "vi-backward-change-char"},
1605 {"M-c^H", "vi-backward-change-char"},
1606 {"M-c^?", "vi-backward-change-char"},
1607 {"M-cl", "vi-forward-change-char"},
1608 {"M-c ", "vi-forward-change-char"},
1609 {"M-c^", "vi-change-to-bol"},
1610 {"M-c0", "vi-change-to-bol"},
1611 {"M-c$", "vi-change-rest-of-line"},
1612 {"M-c|", "vi-change-to-column"},
1613 {"M-c%", "vi-change-to-parenthesis"},
1614 {"M-dh", "backward-delete-char"},
1615 {"M-d^H", "backward-delete-char"},
1616 {"M-d^?", "backward-delete-char"},
1617 {"M-dl", "forward-delete-char"},
1618 {"M-d ", "forward-delete-char"},
1619 {"M-dd", "delete-line"},
1620 {"M-db", "backward-delete-word"},
1621 {"M-dB", "backward-delete-word"},
1622 {"M-de", "forward-delete-word"},
1623 {"M-dE", "forward-delete-word"},
1624 {"M-dw", "forward-delete-word"},
1625 {"M-dW", "forward-delete-word"},
1626 {"M-dF", "backward-delete-find"},
1627 {"M-df", "forward-delete-find"},
1628 {"M-dT", "backward-delete-to"},
1629 {"M-dt", "forward-delete-to"},
1630 {"M-d;", "delete-refind"},
1631 {"M-d,", "delete-invert-refind"},
1632 {"M-d^", "backward-kill-line"},
1633 {"M-d0", "backward-kill-line"},
1634 {"M-d$", "kill-line"},
1635 {"M-D", "kill-line"},
1636 {"M-d|", "delete-to-column"},
1637 {"M-d%", "delete-to-parenthesis"},
1638 {"M-e", "forward-word"},
1639 {"M-E", "forward-word"},
1640 {"M-f", "forward-find-char"},
1641 {"M-F", "backward-find-char"},
1642 {"M--", "up-history"},
1643 {"M-h", "cursor-left"},
1644 {"M-H", "beginning-of-history"},
1645 {"M-i", "vi-insert"},
1646 {"M-I", "vi-insert-at-bol"},
1647 {"M-j", "down-history"},
1648 {"M-J", "history-search-forward"},
1649 {"M-k", "up-history"},
1650 {"M-K", "history-search-backward"},
1651 {"M-l", "cursor-right"},
1652 {"M-L", "end-of-history"},
1653 {"M-n", "history-re-search-forward"},
1654 {"M-N", "history-re-search-backward"},
1655 {"M-p", "append-yank"},
1656 {"M-P", "yank"},
1657 {"M-r", "vi-replace-char"},
1658 {"M-R", "vi-overwrite"},
1659 {"M-s", "vi-forward-change-char"},
1660 {"M-S", "vi-change-line"},
1661 {"M-t", "forward-to-char"},
1662 {"M-T", "backward-to-char"},
1663 {"M-u", "vi-undo"},
1664 {"M-w", "forward-to-word"},
1665 {"M-W", "forward-to-word"},
1666 {"M-x", "forward-delete-char"},
1667 {"M-X", "backward-delete-char"},
1668 {"M-yh", "backward-copy-char"},
1669 {"M-y^H", "backward-copy-char"},
1670 {"M-y^?", "backward-copy-char"},
1671 {"M-yl", "forward-copy-char"},
1672 {"M-y ", "forward-copy-char"},
1673 {"M-ye", "forward-copy-word"},
1674 {"M-yE", "forward-copy-word"},
1675 {"M-yw", "forward-copy-word"},
1676 {"M-yW", "forward-copy-word"},
1677 {"M-yb", "backward-copy-word"},
1678 {"M-yB", "backward-copy-word"},
1679 {"M-yf", "forward-copy-find"},
1680 {"M-yF", "backward-copy-find"},
1681 {"M-yt", "forward-copy-to"},
1682 {"M-yT", "backward-copy-to"},
1683 {"M-y;", "copy-refind"},
1684 {"M-y,", "copy-invert-refind"},
1685 {"M-y^", "copy-to-bol"},
1686 {"M-y0", "copy-to-bol"},
1687 {"M-y$", "copy-rest-of-line"},
1688 {"M-yy", "copy-line"},
1689 {"M-Y", "copy-line"},
1690 {"M-y|", "copy-to-column"},
1691 {"M-y%", "copy-to-parenthesis"},
1692 {"M-^E", "emacs-mode"},
1693 {"M-^H", "cursor-left"},
1694 {"M-^?", "cursor-left"},
1695 {"M-^L", "clear-screen"},
1696 {"M-^N", "down-history"},
1697 {"M-^P", "up-history"},
1698 {"M-^R", "redisplay"},
1699 {"M-^D", "list-or-eof"},
1700 {"M-\r", "newline"},
1701 {"M-\t", "complete-word"},
1702 {"M-\n", "newline"},
1703 #ifndef HIDE_FILE_SYSTEM
1704 {"M-^X^R", "read-init-files"},
1705 #endif
1706 {"M-^Xh", "list-history"},
1707 {"M-^XH", "list-history"},
1708 {"down", "down-history"},
1709 {"up", "up-history"},
1710 {"left", "cursor-left"},
1711 {"right", "cursor-right"},
1712 };
1713
1714 /*.......................................................................
1715 * Create a new GetLine object.
1716 *
1717 * Input:
1718 * linelen size_t The maximum line length to allow for.
1719 * histlen size_t The number of bytes to allocate for recording
1720 * a circular buffer of history lines.
1721 * Output:
1722 * return GetLine * The new object, or NULL on error.
1723 */
new_GetLine(size_t linelen,size_t histlen)1724 GetLine *new_GetLine(size_t linelen, size_t histlen)
1725 {
1726 GetLine *gl; /* The object to be returned */
1727 int i;
1728 /*
1729 * Check the arguments.
1730 */
1731 if(linelen < 10) {
1732 errno = ENOMEM;
1733 return NULL;
1734 };
1735 /*
1736 * Allocate the container.
1737 */
1738 gl = (GetLine *) malloc(sizeof(GetLine));
1739 if(!gl) {
1740 errno = ENOMEM;
1741 return NULL;
1742 };
1743 /*
1744 * Before attempting any operation that might fail, initialize the
1745 * container at least up to the point at which it can safely be passed
1746 * to del_GetLine().
1747 */
1748 gl->err = NULL;
1749 gl->glh = NULL;
1750 gl->cpl = NULL;
1751 #ifndef HIDE_FILE_SYSTEM
1752 gl->cplfn.fn = cpl_file_completions;
1753 #else
1754 gl->cplfn.fn = gl_no_completions;
1755 #endif
1756 gl->cplfn.data = NULL;
1757 #ifndef WITHOUT_FILE_SYSTEM
1758 gl->ef = NULL;
1759 #endif
1760 gl->capmem = NULL;
1761 gl->cq = NULL;
1762 gl->input_fd = -1;
1763 gl->output_fd = -1;
1764 gl->input_fp = NULL;
1765 gl->output_fp = NULL;
1766 gl->file_fp = NULL;
1767 gl->term = NULL;
1768 gl->is_term = 0;
1769 gl->flush_fn = gl_flush_terminal;
1770 gl->io_mode = GL_NORMAL_MODE;
1771 gl->raw_mode = 0;
1772 gl->pending_io = GLP_WRITE; /* We will start by writing the prompt */
1773 gl_clear_status(gl);
1774 gl->linelen = linelen;
1775 gl->line = NULL;
1776 gl->cutbuf = NULL;
1777 gl->prompt = NULL;
1778 gl->prompt_len = 0;
1779 gl->prompt_changed = 0;
1780 gl->prompt_style = GL_LITERAL_PROMPT;
1781 gl->cpl_mem = NULL;
1782 gl->ext_act_mem = NULL;
1783 gl->sig_mem = NULL;
1784 gl->sigs = NULL;
1785 gl->signals_masked = 0;
1786 gl->signals_overriden = 0;
1787 sigemptyset(&gl->all_signal_set);
1788 sigemptyset(&gl->old_signal_set);
1789 sigemptyset(&gl->use_signal_set);
1790 gl->bindings = NULL;
1791 gl->ntotal = 0;
1792 gl->buff_curpos = 0;
1793 gl->term_curpos = 0;
1794 gl->term_len = 0;
1795 gl->buff_mark = 0;
1796 gl->insert_curpos = 0;
1797 gl->insert = 1;
1798 gl->number = -1;
1799 gl->endline = 1;
1800 gl->displayed = 0;
1801 gl->redisplay = 0;
1802 gl->postpone = 0;
1803 gl->keybuf[0]='\0';
1804 gl->nbuf = 0;
1805 gl->nread = 0;
1806 gl->current_action.fn = 0;
1807 gl->current_action.data = NULL;
1808 gl->current_count = 0;
1809 gl->preload_id = 0;
1810 gl->preload_history = 0;
1811 gl->keyseq_count = 0;
1812 gl->last_search = -1;
1813 gl->editor = GL_EMACS_MODE;
1814 gl->silence_bell = 0;
1815 gl->automatic_history = 1;
1816 gl->vi.undo.line = NULL;
1817 gl->vi.undo.buff_curpos = 0;
1818 gl->vi.undo.ntotal = 0;
1819 gl->vi.undo.saved = 0;
1820 gl->vi.repeat.action.fn = 0;
1821 gl->vi.repeat.action.data = 0;
1822 gl->vi.repeat.count = 0;
1823 gl->vi.repeat.input_curpos = 0;
1824 gl->vi.repeat.command_curpos = 0;
1825 gl->vi.repeat.input_char = '\0';
1826 gl->vi.repeat.saved = 0;
1827 gl->vi.repeat.active = 0;
1828 gl->vi.command = 0;
1829 gl->vi.find_forward = 0;
1830 gl->vi.find_onto = 0;
1831 gl->vi.find_char = '\0';
1832 gl->left = NULL;
1833 gl->right = NULL;
1834 gl->up = NULL;
1835 gl->down = NULL;
1836 gl->home = NULL;
1837 gl->bol = 0;
1838 gl->clear_eol = NULL;
1839 gl->clear_eod = NULL;
1840 gl->u_arrow = NULL;
1841 gl->d_arrow = NULL;
1842 gl->l_arrow = NULL;
1843 gl->r_arrow = NULL;
1844 gl->sound_bell = NULL;
1845 gl->bold = NULL;
1846 gl->underline = NULL;
1847 gl->standout = NULL;
1848 gl->dim = NULL;
1849 gl->reverse = NULL;
1850 gl->blink = NULL;
1851 gl->text_attr_off = NULL;
1852 gl->nline = 0;
1853 gl->ncolumn = 0;
1854 #ifdef USE_TERMINFO
1855 gl->left_n = NULL;
1856 gl->right_n = NULL;
1857 #elif defined(USE_TERMCAP)
1858 gl->tgetent_buf = NULL;
1859 gl->tgetstr_buf = NULL;
1860 #endif
1861 gl->app_file = NULL;
1862 gl->user_file = NULL;
1863 gl->configured = 0;
1864 gl->echo = 1;
1865 gl->last_signal = -1;
1866 #ifdef HAVE_SELECT
1867 gl->fd_node_mem = NULL;
1868 gl->fd_nodes = NULL;
1869 FD_ZERO(&gl->rfds);
1870 FD_ZERO(&gl->wfds);
1871 FD_ZERO(&gl->ufds);
1872 gl->max_fd = 0;
1873 gl->timer.dt.tv_sec = 0;
1874 gl->timer.dt.tv_usec = 0;
1875 gl->timer.fn = 0;
1876 gl->timer.data = NULL;
1877 #endif
1878 /*
1879 * Allocate an error reporting buffer.
1880 */
1881 gl->err = _new_ErrMsg();
1882 if(!gl->err)
1883 return del_GetLine(gl);
1884 /*
1885 * Allocate the history buffer.
1886 */
1887 gl->glh = _new_GlHistory(histlen);
1888 if(!gl->glh)
1889 return del_GetLine(gl);
1890 /*
1891 * Allocate the resource object for file-completion.
1892 */
1893 gl->cpl = new_WordCompletion();
1894 if(!gl->cpl)
1895 return del_GetLine(gl);
1896 /*
1897 * Allocate the resource object for file-completion.
1898 */
1899 #ifndef WITHOUT_FILE_SYSTEM
1900 gl->ef = new_ExpandFile();
1901 if(!gl->ef)
1902 return del_GetLine(gl);
1903 #endif
1904 /*
1905 * Allocate a string-segment memory allocator for use in storing terminal
1906 * capablity strings.
1907 */
1908 gl->capmem = _new_StringGroup(CAPMEM_SEGMENT_SIZE);
1909 if(!gl->capmem)
1910 return del_GetLine(gl);
1911 /*
1912 * Allocate the character queue that is used to buffer terminal output.
1913 */
1914 gl->cq = _new_GlCharQueue();
1915 if(!gl->cq)
1916 return del_GetLine(gl);
1917 /*
1918 * Allocate a line buffer, leaving 2 extra characters for the terminating
1919 * '\n' and '\0' characters
1920 */
1921 gl->line = (char *) malloc(linelen + 2);
1922 if(!gl->line) {
1923 errno = ENOMEM;
1924 return del_GetLine(gl);
1925 };
1926 /*
1927 * Start with an empty input line.
1928 */
1929 gl_truncate_buffer(gl, 0);
1930 /*
1931 * Allocate a cut buffer.
1932 */
1933 gl->cutbuf = (char *) malloc(linelen + 2);
1934 if(!gl->cutbuf) {
1935 errno = ENOMEM;
1936 return del_GetLine(gl);
1937 };
1938 gl->cutbuf[0] = '\0';
1939 /*
1940 * Allocate an initial empty prompt.
1941 */
1942 _gl_replace_prompt(gl, NULL);
1943 if(!gl->prompt) {
1944 errno = ENOMEM;
1945 return del_GetLine(gl);
1946 };
1947 /*
1948 * Allocate a vi undo buffer.
1949 */
1950 gl->vi.undo.line = (char *) malloc(linelen + 2);
1951 if(!gl->vi.undo.line) {
1952 errno = ENOMEM;
1953 return del_GetLine(gl);
1954 };
1955 gl->vi.undo.line[0] = '\0';
1956 /*
1957 * Allocate a freelist from which to allocate nodes for the list
1958 * of completion functions.
1959 */
1960 gl->cpl_mem = _new_FreeList(sizeof(GlCplCallback), GL_CPL_FREELIST_BLOCKING);
1961 if(!gl->cpl_mem)
1962 return del_GetLine(gl);
1963 /*
1964 * Allocate a freelist from which to allocate nodes for the list
1965 * of external action functions.
1966 */
1967 gl->ext_act_mem = _new_FreeList(sizeof(GlExternalAction),
1968 GL_EXT_ACT_FREELIST_BLOCKING);
1969 if(!gl->ext_act_mem)
1970 return del_GetLine(gl);
1971 /*
1972 * Allocate a freelist from which to allocate nodes for the list
1973 * of signals.
1974 */
1975 gl->sig_mem = _new_FreeList(sizeof(GlSignalNode), GLS_FREELIST_BLOCKING);
1976 if(!gl->sig_mem)
1977 return del_GetLine(gl);
1978 /*
1979 * Install initial dispositions for the default list of signals that
1980 * gl_get_line() traps.
1981 */
1982 for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
1983 const struct GlDefSignal *sig = gl_signal_list + i;
1984 if(_gl_trap_signal(gl, sig->signo, sig->flags, sig->after,
1985 sig->errno_value))
1986 return del_GetLine(gl);
1987 };
1988 /*
1989 * Allocate an empty table of key bindings.
1990 */
1991 gl->bindings = _new_KeyTab();
1992 if(!gl->bindings)
1993 return del_GetLine(gl);
1994 /*
1995 * Define the available actions that can be bound to key sequences.
1996 */
1997 for(i=0; i<sizeof(gl_actions)/sizeof(gl_actions[0]); i++) {
1998 if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn, NULL))
1999 return del_GetLine(gl);
2000 };
2001 /*
2002 * Set up the default bindings.
2003 */
2004 if(gl_change_editor(gl, gl->editor))
2005 return del_GetLine(gl);
2006 /*
2007 * Allocate termcap buffers.
2008 */
2009 #ifdef USE_TERMCAP
2010 gl->tgetent_buf = (char *) malloc(TERMCAP_BUF_SIZE);
2011 gl->tgetstr_buf = (char *) malloc(TERMCAP_BUF_SIZE);
2012 if(!gl->tgetent_buf || !gl->tgetstr_buf) {
2013 errno = ENOMEM;
2014 return del_GetLine(gl);
2015 };
2016 #endif
2017 /*
2018 * Set up for I/O assuming stdin and stdout.
2019 */
2020 if(_gl_change_terminal(gl, stdin, stdout, getenv("TERM")))
2021 return del_GetLine(gl);
2022 /*
2023 * Create a freelist for use in allocating GlFdNode list nodes.
2024 */
2025 #ifdef HAVE_SELECT
2026 gl->fd_node_mem = _new_FreeList(sizeof(GlFdNode), GLFD_FREELIST_BLOCKING);
2027 if(!gl->fd_node_mem)
2028 return del_GetLine(gl);
2029 #endif
2030 /*
2031 * We are done for now.
2032 */
2033 return gl;
2034 }
2035
2036 /*.......................................................................
2037 * Delete a GetLine object.
2038 *
2039 * Input:
2040 * gl GetLine * The object to be deleted.
2041 * Output:
2042 * return GetLine * The deleted object (always NULL).
2043 */
del_GetLine(GetLine * gl)2044 GetLine *del_GetLine(GetLine *gl)
2045 {
2046 if(gl) {
2047 /*
2048 * If the terminal is in raw server mode, reset it.
2049 */
2050 _gl_normal_io(gl);
2051 /*
2052 * Deallocate all objects contained by gl.
2053 */
2054 gl->err = _del_ErrMsg(gl->err);
2055 gl->glh = _del_GlHistory(gl->glh);
2056 gl->cpl = del_WordCompletion(gl->cpl);
2057 #ifndef WITHOUT_FILE_SYSTEM
2058 gl->ef = del_ExpandFile(gl->ef);
2059 #endif
2060 gl->capmem = _del_StringGroup(gl->capmem);
2061 gl->cq = _del_GlCharQueue(gl->cq);
2062 if(gl->file_fp)
2063 fclose(gl->file_fp);
2064 if(gl->term)
2065 free(gl->term);
2066 if(gl->line)
2067 free(gl->line);
2068 if(gl->cutbuf)
2069 free(gl->cutbuf);
2070 if(gl->prompt)
2071 free(gl->prompt);
2072 gl->cpl_mem = _del_FreeList(gl->cpl_mem, 1);
2073 gl->ext_act_mem = _del_FreeList(gl->ext_act_mem, 1);
2074 gl->sig_mem = _del_FreeList(gl->sig_mem, 1);
2075 gl->sigs = NULL; /* Already freed by freeing sig_mem */
2076 gl->bindings = _del_KeyTab(gl->bindings);
2077 if(gl->vi.undo.line)
2078 free(gl->vi.undo.line);
2079 #ifdef USE_TERMCAP
2080 if(gl->tgetent_buf)
2081 free(gl->tgetent_buf);
2082 if(gl->tgetstr_buf)
2083 free(gl->tgetstr_buf);
2084 #endif
2085 if(gl->app_file)
2086 free(gl->app_file);
2087 if(gl->user_file)
2088 free(gl->user_file);
2089 #ifdef HAVE_SELECT
2090 gl->fd_node_mem = _del_FreeList(gl->fd_node_mem, 1);
2091 gl->fd_nodes = NULL; /* Already freed by freeing gl->fd_node_mem */
2092 #endif
2093 /*
2094 * Delete the now empty container.
2095 */
2096 free(gl);
2097 };
2098 return NULL;
2099 }
2100
2101 /*.......................................................................
2102 * Bind a control or meta character to an action.
2103 *
2104 * Input:
2105 * gl GetLine * The resource object of this program.
2106 * binder KtBinder The source of the binding.
2107 * c char The control or meta character.
2108 * If this is '\0', the call is ignored.
2109 * action const char * The action name to bind the key to.
2110 * Output:
2111 * return int 0 - OK.
2112 * 1 - Error.
2113 */
gl_bind_control_char(GetLine * gl,KtBinder binder,char c,const char * action)2114 static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c,
2115 const char *action)
2116 {
2117 char keyseq[2];
2118 /*
2119 * Quietly reject binding to the NUL control character, since this
2120 * is an ambiguous prefix of all bindings.
2121 */
2122 if(c == '\0')
2123 return 0;
2124 /*
2125 * Making sure not to bind characters which aren't either control or
2126 * meta characters.
2127 */
2128 if(IS_CTRL_CHAR(c) || IS_META_CHAR(c)) {
2129 keyseq[0] = c;
2130 keyseq[1] = '\0';
2131 } else {
2132 return 0;
2133 };
2134 /*
2135 * Install the binding.
2136 */
2137 if(_kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
2138 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
2139 return 1;
2140 };
2141 return 0;
2142 }
2143
2144 /*.......................................................................
2145 * Read a line from the user.
2146 *
2147 * Input:
2148 * gl GetLine * A resource object returned by new_GetLine().
2149 * prompt char * The prompt to prefix the line with.
2150 * start_line char * The initial contents of the input line, or NULL
2151 * if it should start out empty.
2152 * start_pos int If start_line isn't NULL, this specifies the
2153 * index of the character over which the cursor
2154 * should initially be positioned within the line.
2155 * If you just want it to follow the last character
2156 * of the line, send -1.
2157 * Output:
2158 * return char * An internal buffer containing the input line, or
2159 * NULL at the end of input. If the line fitted in
2160 * the buffer there will be a '\n' newline character
2161 * before the terminating '\0'. If it was truncated
2162 * there will be no newline character, and the remains
2163 * of the line should be retrieved via further calls
2164 * to this function.
2165 */
gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2166 char *gl_get_line(GetLine *gl, const char *prompt,
2167 const char *start_line, int start_pos)
2168 {
2169 char *retval; /* The return value of _gl_get_line() */
2170 /*
2171 * Check the arguments.
2172 */
2173 if(!gl) {
2174 errno = EINVAL;
2175 return NULL;
2176 };
2177 /*
2178 * Temporarily block all of the signals that we have been asked to trap.
2179 */
2180 if(gl_mask_signals(gl, &gl->old_signal_set))
2181 return NULL;
2182 /*
2183 * Perform the command-line editing task.
2184 */
2185 retval = _gl_get_line(gl, prompt, start_line, start_pos);
2186 /*
2187 * Restore the process signal mask to how it was when this function was
2188 * first called.
2189 */
2190 gl_unmask_signals(gl, &gl->old_signal_set);
2191 return retval;
2192 }
2193
2194
2195 /*.......................................................................
2196 * This is the main body of the public function gl_get_line().
2197 */
_gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2198 static char *_gl_get_line(GetLine *gl, const char *prompt,
2199 const char *start_line, int start_pos)
2200 {
2201 int waserr = 0; /* True if an error occurs */
2202 /*
2203 * Assume that this call will successfully complete the input
2204 * line until proven otherwise.
2205 */
2206 gl_clear_status(gl);
2207 /*
2208 * If this is the first call to this function since new_GetLine(),
2209 * complete any postponed configuration.
2210 */
2211 if(!gl->configured) {
2212 (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
2213 gl->configured = 1;
2214 };
2215 /*
2216 * Before installing our signal handler functions, record the fact
2217 * that there are no pending signals.
2218 */
2219 gl_pending_signal = -1;
2220 /*
2221 * Temporarily override the signal handlers of the calling program,
2222 * so that we can intercept signals that would leave the terminal
2223 * in a bad state.
2224 */
2225 waserr = gl_override_signal_handlers(gl);
2226 /*
2227 * After recording the current terminal settings, switch the terminal
2228 * into raw input mode.
2229 */
2230 waserr = waserr || _gl_raw_io(gl, 1);
2231 /*
2232 * Attempt to read the line. This will require more than one attempt if
2233 * either a current temporary input file is opened by gl_get_input_line()
2234 * or the end of a temporary input file is reached by gl_read_stream_line().
2235 */
2236 while(!waserr) {
2237 /*
2238 * Read a line from a non-interactive stream?
2239 */
2240 if(gl->file_fp || !gl->is_term) {
2241 if(gl_read_stream_line(gl)==0) {
2242 break;
2243 } else if(gl->file_fp) {
2244 gl_revert_input(gl);
2245 gl_record_status(gl, GLR_NEWLINE, 0);
2246 } else {
2247 waserr = 1;
2248 break;
2249 };
2250 };
2251 /*
2252 * Read from the terminal? Note that the above if() block may have
2253 * changed gl->file_fp, so it is necessary to retest it here, rather
2254 * than using an else statement.
2255 */
2256 if(!gl->file_fp && gl->is_term) {
2257 if(gl_get_input_line(gl, prompt, start_line, start_pos))
2258 waserr = 1;
2259 else
2260 break;
2261 };
2262 };
2263 /*
2264 * If an error occurred, but gl->rtn_status is still set to
2265 * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
2266 * leave it at whatever specific value was assigned by the function
2267 * that aborted input. This means that only functions that trap
2268 * non-generic errors have to remember to update gl->rtn_status
2269 * themselves.
2270 */
2271 if(waserr && gl->rtn_status == GLR_NEWLINE)
2272 gl_record_status(gl, GLR_ERROR, errno);
2273 /*
2274 * Restore terminal settings.
2275 */
2276 if(gl->io_mode != GL_SERVER_MODE)
2277 _gl_normal_io(gl);
2278 /*
2279 * Restore the signal handlers.
2280 */
2281 gl_restore_signal_handlers(gl);
2282 /*
2283 * If gl_get_line() gets aborted early, the errno value associated
2284 * with the event that caused this to happen is recorded in
2285 * gl->rtn_errno. Since errno may have been overwritten by cleanup
2286 * functions after this, restore its value to the value that it had
2287 * when the error condition occured, so that the caller can examine it
2288 * to find out what happened.
2289 */
2290 errno = gl->rtn_errno;
2291 /*
2292 * Check the completion status to see how to return.
2293 */
2294 switch(gl->rtn_status) {
2295 case GLR_NEWLINE: /* Success */
2296 return gl->line;
2297 case GLR_BLOCKED: /* These events abort the current input line, */
2298 case GLR_SIGNAL: /* when in normal blocking I/O mode, but only */
2299 case GLR_TIMEOUT: /* temporarily pause line editing when in */
2300 case GLR_FDABORT: /* non-blocking server I/O mode. */
2301 if(gl->io_mode != GL_SERVER_MODE)
2302 _gl_abandon_line(gl);
2303 return NULL;
2304 case GLR_ERROR: /* Unrecoverable errors abort the input line, */
2305 case GLR_EOF: /* regardless of the I/O mode. */
2306 default:
2307 _gl_abandon_line(gl);
2308 return NULL;
2309 };
2310 }
2311
2312 /*.......................................................................
2313 * Read a single character from the user.
2314 *
2315 * Input:
2316 * gl GetLine * A resource object returned by new_GetLine().
2317 * prompt char * The prompt to prefix the line with, or NULL if
2318 * no prompt is required.
2319 * defchar char The character to substitute if the
2320 * user simply hits return, or '\n' if you don't
2321 * need to substitute anything.
2322 * Output:
2323 * return int The character that was read, or EOF if the read
2324 * had to be aborted (in which case you can call
2325 * gl_return_status() to find out why).
2326 */
gl_query_char(GetLine * gl,const char * prompt,char defchar)2327 int gl_query_char(GetLine *gl, const char *prompt, char defchar)
2328 {
2329 int retval; /* The return value of _gl_query_char() */
2330 /*
2331 * Check the arguments.
2332 */
2333 if(!gl) {
2334 errno = EINVAL;
2335 return EOF;
2336 };
2337 /*
2338 * Temporarily block all of the signals that we have been asked to trap.
2339 */
2340 if(gl_mask_signals(gl, &gl->old_signal_set))
2341 return EOF;
2342 /*
2343 * Perform the character reading task.
2344 */
2345 retval = _gl_query_char(gl, prompt, defchar);
2346 /*
2347 * Restore the process signal mask to how it was when this function was
2348 * first called.
2349 */
2350 gl_unmask_signals(gl, &gl->old_signal_set);
2351 return retval;
2352 }
2353
2354 /*.......................................................................
2355 * This is the main body of the public function gl_query_char().
2356 */
_gl_query_char(GetLine * gl,const char * prompt,char defchar)2357 static int _gl_query_char(GetLine *gl, const char *prompt, char defchar)
2358 {
2359 int c = EOF; /* The character to be returned */
2360 int waserr = 0; /* True if an error occurs */
2361 /*
2362 * Assume that this call will successfully complete the input operation
2363 * until proven otherwise.
2364 */
2365 gl_clear_status(gl);
2366 /*
2367 * If this is the first call to this function or gl_get_line(),
2368 * since new_GetLine(), complete any postponed configuration.
2369 */
2370 if(!gl->configured) {
2371 (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
2372 gl->configured = 1;
2373 };
2374 /*
2375 * Before installing our signal handler functions, record the fact
2376 * that there are no pending signals.
2377 */
2378 gl_pending_signal = -1;
2379 /*
2380 * Temporarily override the signal handlers of the calling program,
2381 * so that we can intercept signals that would leave the terminal
2382 * in a bad state.
2383 */
2384 waserr = gl_override_signal_handlers(gl);
2385 /*
2386 * After recording the current terminal settings, switch the terminal
2387 * into raw input mode without redisplaying any partially entered
2388 * input line.
2389 */
2390 waserr = waserr || _gl_raw_io(gl, 0);
2391 /*
2392 * Attempt to read the line. This will require more than one attempt if
2393 * either a current temporary input file is opened by gl_get_input_line()
2394 * or the end of a temporary input file is reached by gl_read_stream_line().
2395 */
2396 while(!waserr) {
2397 /*
2398 * Read a line from a non-interactive stream?
2399 */
2400 if(gl->file_fp || !gl->is_term) {
2401 c = gl_read_stream_char(gl);
2402 if(c != EOF) { /* Success? */
2403 if(c=='\n') c = defchar;
2404 break;
2405 } else if(gl->file_fp) { /* End of temporary input file? */
2406 gl_revert_input(gl);
2407 gl_record_status(gl, GLR_NEWLINE, 0);
2408 } else { /* An error? */
2409 waserr = 1;
2410 break;
2411 };
2412 };
2413 /*
2414 * Read from the terminal? Note that the above if() block may have
2415 * changed gl->file_fp, so it is necessary to retest it here, rather
2416 * than using an else statement.
2417 */
2418 if(!gl->file_fp && gl->is_term) {
2419 c = gl_get_query_char(gl, prompt, defchar);
2420 if(c==EOF)
2421 waserr = 1;
2422 else
2423 break;
2424 };
2425 };
2426 /*
2427 * If an error occurred, but gl->rtn_status is still set to
2428 * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
2429 * leave it at whatever specific value was assigned by the function
2430 * that aborted input. This means that only functions that trap
2431 * non-generic errors have to remember to update gl->rtn_status
2432 * themselves.
2433 */
2434 if(waserr && gl->rtn_status == GLR_NEWLINE)
2435 gl_record_status(gl, GLR_ERROR, errno);
2436 /*
2437 * Restore terminal settings.
2438 */
2439 if(gl->io_mode != GL_SERVER_MODE)
2440 _gl_normal_io(gl);
2441 /*
2442 * Restore the signal handlers.
2443 */
2444 gl_restore_signal_handlers(gl);
2445 /*
2446 * If this function gets aborted early, the errno value associated
2447 * with the event that caused this to happen is recorded in
2448 * gl->rtn_errno. Since errno may have been overwritten by cleanup
2449 * functions after this, restore its value to the value that it had
2450 * when the error condition occured, so that the caller can examine it
2451 * to find out what happened.
2452 */
2453 errno = gl->rtn_errno;
2454 /*
2455 * Error conditions are signalled to the caller, by setting the returned
2456 * character to EOF.
2457 */
2458 if(gl->rtn_status != GLR_NEWLINE)
2459 c = EOF;
2460 /*
2461 * In this mode, every character that is read is a completed
2462 * transaction, just like reading a completed input line, so prepare
2463 * for the next input line or character.
2464 */
2465 _gl_abandon_line(gl);
2466 /*
2467 * Return the acquired character.
2468 */
2469 return c;
2470 }
2471
2472 /*.......................................................................
2473 * Record of the signal handlers of the calling program, so that they
2474 * can be restored later.
2475 *
2476 * Input:
2477 * gl GetLine * The resource object of this library.
2478 * Output:
2479 * return int 0 - OK.
2480 * 1 - Error.
2481 */
gl_override_signal_handlers(GetLine * gl)2482 static int gl_override_signal_handlers(GetLine *gl)
2483 {
2484 GlSignalNode *sig; /* A node in the list of signals to be caught */
2485 /*
2486 * Set up our signal handler.
2487 */
2488 SigAction act;
2489 act.sa_handler = gl_signal_handler;
2490 memcpy(&act.sa_mask, &gl->all_signal_set, sizeof(sigset_t));
2491 act.sa_flags = 0;
2492 /*
2493 * Get the subset of the signals that we are supposed to trap that
2494 * should actually be trapped.
2495 */
2496 sigemptyset(&gl->use_signal_set);
2497 for(sig=gl->sigs; sig; sig=sig->next) {
2498 /*
2499 * Trap this signal? If it is blocked by the calling program and we
2500 * haven't been told to unblock it, don't arrange to trap this signal.
2501 */
2502 if(sig->flags & GLS_UNBLOCK_SIG ||
2503 !sigismember(&gl->old_signal_set, sig->signo)) {
2504 if(sigaddset(&gl->use_signal_set, sig->signo) == -1) {
2505 _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
2506 return 1;
2507 };
2508 };
2509 };
2510 /*
2511 * Override the actions of the signals that we are trapping.
2512 */
2513 for(sig=gl->sigs; sig; sig=sig->next) {
2514 if(sigismember(&gl->use_signal_set, sig->signo)) {
2515 sigdelset(&act.sa_mask, sig->signo);
2516 if(sigaction(sig->signo, &act, &sig->original)) {
2517 _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
2518 return 1;
2519 };
2520 sigaddset(&act.sa_mask, sig->signo);
2521 };
2522 };
2523 /*
2524 * Record the fact that the application's signal handlers have now
2525 * been overriden.
2526 */
2527 gl->signals_overriden = 1;
2528 /*
2529 * Just in case a SIGWINCH signal was sent to the process while our
2530 * SIGWINCH signal handler wasn't in place, check to see if the terminal
2531 * size needs updating.
2532 */
2533 if(_gl_update_size(gl))
2534 return 1;
2535 return 0;
2536 }
2537
2538 /*.......................................................................
2539 * Restore the signal handlers of the calling program.
2540 *
2541 * Input:
2542 * gl GetLine * The resource object of this library.
2543 * Output:
2544 * return int 0 - OK.
2545 * 1 - Error.
2546 */
gl_restore_signal_handlers(GetLine * gl)2547 static int gl_restore_signal_handlers(GetLine *gl)
2548 {
2549 GlSignalNode *sig; /* A node in the list of signals to be caught */
2550 /*
2551 * Restore application signal handlers that were overriden
2552 * by gl_override_signal_handlers().
2553 */
2554 for(sig=gl->sigs; sig; sig=sig->next) {
2555 if(sigismember(&gl->use_signal_set, sig->signo) &&
2556 sigaction(sig->signo, &sig->original, NULL)) {
2557 _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
2558 return 1;
2559 };
2560 };
2561 /*
2562 * Record the fact that the application's signal handlers have now
2563 * been restored.
2564 */
2565 gl->signals_overriden = 0;
2566 return 0;
2567 }
2568
2569 /*.......................................................................
2570 * This signal handler simply records the fact that a given signal was
2571 * caught in the file-scope gl_pending_signal variable.
2572 */
gl_signal_handler(int signo)2573 static void gl_signal_handler(int signo)
2574 {
2575 gl_pending_signal = signo;
2576 siglongjmp(gl_setjmp_buffer, 1);
2577 }
2578
2579 /*.......................................................................
2580 * Switch the terminal into raw mode after storing the previous terminal
2581 * settings in gl->attributes.
2582 *
2583 * Input:
2584 * gl GetLine * The resource object of this program.
2585 * Output:
2586 * return int 0 - OK.
2587 * 1 - Error.
2588 */
gl_raw_terminal_mode(GetLine * gl)2589 static int gl_raw_terminal_mode(GetLine *gl)
2590 {
2591 Termios newattr; /* The new terminal attributes */
2592 /*
2593 * If the terminal is already in raw mode, do nothing.
2594 */
2595 if(gl->raw_mode)
2596 return 0;
2597 /*
2598 * Record the current terminal attributes.
2599 */
2600 if(tcgetattr(gl->input_fd, &gl->oldattr)) {
2601 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
2602 return 1;
2603 };
2604 /*
2605 * This function shouldn't do anything but record the current terminal
2606 * attritubes if editing has been disabled.
2607 */
2608 if(gl->editor == GL_NO_EDITOR)
2609 return 0;
2610 /*
2611 * Modify the existing attributes.
2612 */
2613 newattr = gl->oldattr;
2614 /*
2615 * Turn off local echo, canonical input mode and extended input processing.
2616 */
2617 newattr.c_lflag &= ~(ECHO | ICANON | IEXTEN);
2618 /*
2619 * Don't translate carriage return to newline, turn off input parity
2620 * checking, don't strip off 8th bit, turn off output flow control.
2621 */
2622 newattr.c_iflag &= ~(ICRNL | INPCK | ISTRIP);
2623 /*
2624 * Clear size bits, turn off parity checking, and allow 8-bit characters.
2625 */
2626 newattr.c_cflag &= ~(CSIZE | PARENB);
2627 newattr.c_cflag |= CS8;
2628 /*
2629 * Turn off output processing.
2630 */
2631 newattr.c_oflag &= ~(OPOST);
2632 /*
2633 * Request one byte at a time, without waiting.
2634 */
2635 newattr.c_cc[VMIN] = gl->io_mode==GL_SERVER_MODE ? 0:1;
2636 newattr.c_cc[VTIME] = 0;
2637 /*
2638 * Install the new terminal modes.
2639 */
2640 while(tcsetattr(gl->input_fd, TCSADRAIN, &newattr)) {
2641 if(errno != EINTR) {
2642 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
2643 return 1;
2644 };
2645 };
2646 /*
2647 * Record the new terminal mode.
2648 */
2649 gl->raw_mode = 1;
2650 return 0;
2651 }
2652
2653 /*.......................................................................
2654 * Restore the terminal attributes recorded in gl->oldattr.
2655 *
2656 * Input:
2657 * gl GetLine * The resource object of this library.
2658 * Output:
2659 * return int 0 - OK.
2660 * 1 - Error.
2661 */
gl_restore_terminal_attributes(GetLine * gl)2662 static int gl_restore_terminal_attributes(GetLine *gl)
2663 {
2664 int waserr = 0;
2665 /*
2666 * If not in raw mode, do nothing.
2667 */
2668 if(!gl->raw_mode)
2669 return 0;
2670 /*
2671 * Before changing the terminal attributes, make sure that all output
2672 * has been passed to the terminal.
2673 */
2674 if(gl_flush_output(gl))
2675 waserr = 1;
2676 /*
2677 * Reset the terminal attributes to the values that they had on
2678 * entry to gl_get_line().
2679 */
2680 while(tcsetattr(gl->input_fd, TCSADRAIN, &gl->oldattr)) {
2681 if(errno != EINTR) {
2682 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
2683 waserr = 1;
2684 break;
2685 };
2686 };
2687 /*
2688 * Record the new terminal mode.
2689 */
2690 gl->raw_mode = 0;
2691 return waserr;
2692 }
2693
2694 /*.......................................................................
2695 * Switch the terminal file descriptor to use non-blocking I/O.
2696 *
2697 * Input:
2698 * gl GetLine * The resource object of gl_get_line().
2699 * fd int The file descriptor to make non-blocking.
2700 */
gl_nonblocking_io(GetLine * gl,int fd)2701 static int gl_nonblocking_io(GetLine *gl, int fd)
2702 {
2703 int fcntl_flags; /* The new file-descriptor control flags */
2704 /*
2705 * Is non-blocking I/O supported on this system? Note that even
2706 * without non-blocking I/O, the terminal will probably still act as
2707 * though it was non-blocking, because we also set the terminal
2708 * attributes to return immediately if no input is available and we
2709 * use select() to wait to be able to write. If select() also isn't
2710 * available, then input will probably remain fine, but output could
2711 * block, depending on the behaviour of the terminal driver.
2712 */
2713 #if defined(NON_BLOCKING_FLAG)
2714 /*
2715 * Query the current file-control flags, and add the
2716 * non-blocking I/O flag.
2717 */
2718 fcntl_flags = fcntl(fd, F_GETFL) | NON_BLOCKING_FLAG;
2719 /*
2720 * Install the new control flags.
2721 */
2722 if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
2723 _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
2724 return 1;
2725 };
2726 #endif
2727 return 0;
2728 }
2729
2730 /*.......................................................................
2731 * Switch to blocking terminal I/O.
2732 *
2733 * Input:
2734 * gl GetLine * The resource object of gl_get_line().
2735 * fd int The file descriptor to make blocking.
2736 */
gl_blocking_io(GetLine * gl,int fd)2737 static int gl_blocking_io(GetLine *gl, int fd)
2738 {
2739 int fcntl_flags; /* The new file-descriptor control flags */
2740 /*
2741 * Is non-blocking I/O implemented on this system?
2742 */
2743 #if defined(NON_BLOCKING_FLAG)
2744 /*
2745 * Query the current file control flags and remove the non-blocking
2746 * I/O flag.
2747 */
2748 fcntl_flags = fcntl(fd, F_GETFL) & ~NON_BLOCKING_FLAG;
2749 /*
2750 * Install the modified control flags.
2751 */
2752 if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
2753 _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
2754 return 1;
2755 };
2756 #endif
2757 return 0;
2758 }
2759
2760 /*.......................................................................
2761 * Read a new input line from the user.
2762 *
2763 * Input:
2764 * gl GetLine * The resource object of this library.
2765 * prompt char * The prompt to prefix the line with, or NULL to
2766 * use the same prompt that was used by the previous
2767 * line.
2768 * start_line char * The initial contents of the input line, or NULL
2769 * if it should start out empty.
2770 * start_pos int If start_line isn't NULL, this specifies the
2771 * index of the character over which the cursor
2772 * should initially be positioned within the line.
2773 * If you just want it to follow the last character
2774 * of the line, send -1.
2775 * Output:
2776 * return int 0 - OK.
2777 * 1 - Error.
2778 */
gl_get_input_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2779 static int gl_get_input_line(GetLine *gl, const char *prompt,
2780 const char *start_line, int start_pos)
2781 {
2782 char c; /* The character being read */
2783 /*
2784 * Flush any pending output to the terminal.
2785 */
2786 if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
2787 return 1;
2788 /*
2789 * Are we starting a new line?
2790 */
2791 if(gl->endline) {
2792 /*
2793 * Delete any incompletely enterred line.
2794 */
2795 if(gl_erase_line(gl))
2796 return 1;
2797 /*
2798 * Display the new line to be edited.
2799 */
2800 if(gl_present_line(gl, prompt, start_line, start_pos))
2801 return 1;
2802 };
2803 /*
2804 * Read one character at a time.
2805 */
2806 while(gl_read_terminal(gl, 1, &c) == 0) {
2807 /*
2808 * Increment the count of the number of key sequences entered.
2809 */
2810 gl->keyseq_count++;
2811 /*
2812 * Interpret the character either as the start of a new key-sequence,
2813 * as a continuation of a repeat count, or as a printable character
2814 * to be added to the line.
2815 */
2816 if(gl_interpret_char(gl, c))
2817 break;
2818 /*
2819 * If we just ran an action function which temporarily asked for
2820 * input to be taken from a file, abort this call.
2821 */
2822 if(gl->file_fp)
2823 return 0;
2824 /*
2825 * Has the line been completed?
2826 */
2827 if(gl->endline)
2828 return gl_line_ended(gl, c);
2829 };
2830 /*
2831 * To get here, gl_read_terminal() must have returned non-zero. See
2832 * whether a signal was caught that requested that the current line
2833 * be returned.
2834 */
2835 if(gl->endline)
2836 return gl_line_ended(gl, '\n');
2837 /*
2838 * If I/O blocked while attempting to get the latest character
2839 * of the key sequence, rewind the key buffer to allow interpretation of
2840 * the current key sequence to be restarted on the next call to this
2841 * function.
2842 */
2843 if(gl->rtn_status == GLR_BLOCKED && gl->pending_io == GLP_READ)
2844 gl->nread = 0;
2845 return 1;
2846 }
2847
2848 /*.......................................................................
2849 * This is the private function of gl_query_char() that handles
2850 * prompting the user, reading a character from the terminal, and
2851 * displaying what the user entered.
2852 *
2853 * Input:
2854 * gl GetLine * The resource object of this library.
2855 * prompt char * The prompt to prefix the line with.
2856 * defchar char The character to substitute if the
2857 * user simply hits return, or '\n' if you don't
2858 * need to substitute anything.
2859 * Output:
2860 * return int The character that was read, or EOF if something
2861 * prevented a character from being read.
2862 */
gl_get_query_char(GetLine * gl,const char * prompt,int defchar)2863 static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar)
2864 {
2865 char c; /* The character being read */
2866 int retval; /* The return value of this function */
2867 /*
2868 * Flush any pending output to the terminal.
2869 */
2870 if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
2871 return EOF;
2872 /*
2873 * Delete any incompletely entered line.
2874 */
2875 if(gl_erase_line(gl))
2876 return EOF;
2877 /*
2878 * Reset the line input parameters and display the prompt, if any.
2879 */
2880 if(gl_present_line(gl, prompt, NULL, 0))
2881 return EOF;
2882 /*
2883 * Read one character.
2884 */
2885 if(gl_read_terminal(gl, 1, &c) == 0) {
2886 /*
2887 * In this mode, count each character as being a new key-sequence.
2888 */
2889 gl->keyseq_count++;
2890 /*
2891 * Delete the character that was read, from the key-press buffer.
2892 */
2893 gl_discard_chars(gl, gl->nread);
2894 /*
2895 * Convert carriage returns to newlines.
2896 */
2897 if(c == '\r')
2898 c = '\n';
2899 /*
2900 * If the user just hit return, subsitute the default character.
2901 */
2902 if(c == '\n')
2903 c = defchar;
2904 /*
2905 * Display the entered character to the right of the prompt.
2906 */
2907 if(c!='\n') {
2908 if(gl_end_of_line(gl, 1, NULL)==0)
2909 gl_print_char(gl, c, ' ');
2910 };
2911 /*
2912 * Record the return character, and mark the call as successful.
2913 */
2914 retval = c;
2915 gl_record_status(gl, GLR_NEWLINE, 0);
2916 /*
2917 * Was a signal caught whose disposition is to cause the current input
2918 * line to be returned? If so return a newline character.
2919 */
2920 } else if(gl->endline) {
2921 retval = '\n';
2922 gl_record_status(gl, GLR_NEWLINE, 0);
2923 } else {
2924 retval = EOF;
2925 };
2926 /*
2927 * Start a new line.
2928 */
2929 if(gl_start_newline(gl, 1))
2930 return EOF;
2931 /*
2932 * Attempt to flush any pending output.
2933 */
2934 (void) gl_flush_output(gl);
2935 /*
2936 * Return either the character that was read, or EOF if an error occurred.
2937 */
2938 return retval;
2939 }
2940
2941 /*.......................................................................
2942 * Add a character to the line buffer at the current cursor position,
2943 * inserting or overwriting according the current mode.
2944 *
2945 * Input:
2946 * gl GetLine * The resource object of this library.
2947 * c char The character to be added.
2948 * Output:
2949 * return int 0 - OK.
2950 * 1 - Insufficient room.
2951 */
gl_add_char_to_line(GetLine * gl,char c)2952 static int gl_add_char_to_line(GetLine *gl, char c)
2953 {
2954 /*
2955 * Keep a record of the current cursor position.
2956 */
2957 int buff_curpos = gl->buff_curpos;
2958 int term_curpos = gl->term_curpos;
2959 /*
2960 * Work out the displayed width of the new character.
2961 */
2962 int width = gl_displayed_char_width(gl, c, term_curpos);
2963 /*
2964 * If we are in insert mode, or at the end of the line,
2965 * check that we can accomodate a new character in the buffer.
2966 * If not, simply return, leaving it up to the calling program
2967 * to check for the absence of a newline character.
2968 */
2969 if((gl->insert || buff_curpos >= gl->ntotal) && gl->ntotal >= gl->linelen)
2970 return 0;
2971 /*
2972 * Are we adding characters to the line (ie. inserting or appending)?
2973 */
2974 if(gl->insert || buff_curpos >= gl->ntotal) {
2975 /*
2976 * If inserting, make room for the new character.
2977 */
2978 if(buff_curpos < gl->ntotal)
2979 gl_make_gap_in_buffer(gl, buff_curpos, 1);
2980 /*
2981 * Copy the character into the buffer.
2982 */
2983 gl_buffer_char(gl, c, buff_curpos);
2984 gl->buff_curpos++;
2985 /*
2986 * Redraw the line from the cursor position to the end of the line,
2987 * and move the cursor to just after the added character.
2988 */
2989 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
2990 gl_set_term_curpos(gl, term_curpos + width))
2991 return 1;
2992 /*
2993 * Are we overwriting an existing character?
2994 */
2995 } else {
2996 /*
2997 * Get the width of the character being overwritten.
2998 */
2999 int old_width = gl_displayed_char_width(gl, gl->line[buff_curpos],
3000 term_curpos);
3001 /*
3002 * Overwrite the character in the buffer.
3003 */
3004 gl_buffer_char(gl, c, buff_curpos);
3005 /*
3006 * If we are replacing with a narrower character, we need to
3007 * redraw the terminal string to the end of the line, then
3008 * overwrite the trailing old_width - width characters
3009 * with spaces.
3010 */
3011 if(old_width > width) {
3012 if(gl_print_string(gl, gl->line + buff_curpos, '\0'))
3013 return 1;
3014 /*
3015 * Clear to the end of the terminal.
3016 */
3017 if(gl_truncate_display(gl))
3018 return 1;
3019 /*
3020 * Move the cursor to the end of the new character.
3021 */
3022 if(gl_set_term_curpos(gl, term_curpos + width))
3023 return 1;
3024 gl->buff_curpos++;
3025 /*
3026 * If we are replacing with a wider character, then we will be
3027 * inserting new characters, and thus extending the line.
3028 */
3029 } else if(width > old_width) {
3030 /*
3031 * Redraw the line from the cursor position to the end of the line,
3032 * and move the cursor to just after the added character.
3033 */
3034 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
3035 gl_set_term_curpos(gl, term_curpos + width))
3036 return 1;
3037 gl->buff_curpos++;
3038 /*
3039 * The original and replacement characters have the same width,
3040 * so simply overwrite.
3041 */
3042 } else {
3043 /*
3044 * Copy the character into the buffer.
3045 */
3046 gl_buffer_char(gl, c, buff_curpos);
3047 gl->buff_curpos++;
3048 /*
3049 * Overwrite the original character.
3050 */
3051 if(gl_print_char(gl, c, gl->line[gl->buff_curpos]))
3052 return 1;
3053 };
3054 };
3055 return 0;
3056 }
3057
3058 /*.......................................................................
3059 * Insert/append a string to the line buffer and terminal at the current
3060 * cursor position.
3061 *
3062 * Input:
3063 * gl GetLine * The resource object of this library.
3064 * s char * The string to be added.
3065 * Output:
3066 * return int 0 - OK.
3067 * 1 - Insufficient room.
3068 */
gl_add_string_to_line(GetLine * gl,const char * s)3069 static int gl_add_string_to_line(GetLine *gl, const char *s)
3070 {
3071 int buff_slen; /* The length of the string being added to line[] */
3072 int term_slen; /* The length of the string being written to the terminal */
3073 int buff_curpos; /* The original value of gl->buff_curpos */
3074 int term_curpos; /* The original value of gl->term_curpos */
3075 /*
3076 * Keep a record of the current cursor position.
3077 */
3078 buff_curpos = gl->buff_curpos;
3079 term_curpos = gl->term_curpos;
3080 /*
3081 * How long is the string to be added?
3082 */
3083 buff_slen = strlen(s);
3084 term_slen = gl_displayed_string_width(gl, s, buff_slen, term_curpos);
3085 /*
3086 * Check that we can accomodate the string in the buffer.
3087 * If not, simply return, leaving it up to the calling program
3088 * to check for the absence of a newline character.
3089 */
3090 if(gl->ntotal + buff_slen > gl->linelen)
3091 return 0;
3092 /*
3093 * Move the characters that follow the cursor in the buffer by
3094 * buff_slen characters to the right.
3095 */
3096 if(gl->ntotal > gl->buff_curpos)
3097 gl_make_gap_in_buffer(gl, gl->buff_curpos, buff_slen);
3098 /*
3099 * Copy the string into the buffer.
3100 */
3101 gl_buffer_string(gl, s, buff_slen, gl->buff_curpos);
3102 gl->buff_curpos += buff_slen;
3103 /*
3104 * Write the modified part of the line to the terminal, then move
3105 * the terminal cursor to the end of the displayed input string.
3106 */
3107 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
3108 gl_set_term_curpos(gl, term_curpos + term_slen))
3109 return 1;
3110 return 0;
3111 }
3112
3113 /*.......................................................................
3114 * Read a single character from the terminal.
3115 *
3116 * Input:
3117 * gl GetLine * The resource object of this library.
3118 * keep int If true, the returned character will be kept in
3119 * the input buffer, for potential replays. It should
3120 * subsequently be removed from the buffer when the
3121 * key sequence that it belongs to has been fully
3122 * processed, by calling gl_discard_chars().
3123 * Input/Output:
3124 * c char * The character that is read, is assigned to *c.
3125 * Output:
3126 * return int 0 - OK.
3127 * 1 - Either an I/O error occurred, or a signal was
3128 * caught who's disposition is to abort gl_get_line()
3129 * or to have gl_get_line() return the current line
3130 * as though the user had pressed return. In the
3131 * latter case gl->endline will be non-zero.
3132 */
gl_read_terminal(GetLine * gl,int keep,char * c)3133 static int gl_read_terminal(GetLine *gl, int keep, char *c)
3134 {
3135 /*
3136 * Before waiting for a new character to be input, flush unwritten
3137 * characters to the terminal.
3138 */
3139 if(gl_flush_output(gl))
3140 return 1;
3141 /*
3142 * Record the fact that we are about to read from the terminal.
3143 */
3144 gl->pending_io = GLP_READ;
3145 /*
3146 * If there is already an unread character in the buffer,
3147 * return it.
3148 */
3149 if(gl->nread < gl->nbuf) {
3150 *c = gl->keybuf[gl->nread];
3151 /*
3152 * Retain the character in the key buffer, but mark it as having been read?
3153 */
3154 if(keep) {
3155 gl->nread++;
3156 /*
3157 * Completely remove the character from the key buffer?
3158 */
3159 } else {
3160 memmove(gl->keybuf + gl->nread, gl->keybuf + gl->nread + 1,
3161 gl->nbuf - gl->nread - 1);
3162 };
3163 return 0;
3164 };
3165 /*
3166 * Make sure that there is space in the key buffer for one more character.
3167 * This should always be true if gl_interpret_char() is called for each
3168 * new character added, since it will clear the buffer once it has recognized
3169 * or rejected a key sequence.
3170 */
3171 if(gl->nbuf + 1 > GL_KEY_MAX) {
3172 gl_print_info(gl, "gl_read_terminal: Buffer overflow avoided.",
3173 GL_END_INFO);
3174 errno = EIO;
3175 return 1;
3176 };
3177 /*
3178 * Read one character from the terminal.
3179 */
3180 switch(gl_read_input(gl, c)) {
3181 case GL_READ_OK:
3182 break;
3183 case GL_READ_BLOCKED:
3184 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
3185 return 1;
3186 break;
3187 default:
3188 return 1;
3189 break;
3190 };
3191 /*
3192 * Append the character to the key buffer?
3193 */
3194 if(keep) {
3195 gl->keybuf[gl->nbuf] = *c;
3196 gl->nread = ++gl->nbuf;
3197 };
3198 return 0;
3199 }
3200
3201 /*.......................................................................
3202 * Read one or more keypresses from the terminal of an input stream.
3203 *
3204 * Input:
3205 * gl GetLine * The resource object of this module.
3206 * c char * The character that was read is assigned to *c.
3207 * Output:
3208 * return GlReadStatus The completion status of the read operation.
3209 */
gl_read_input(GetLine * gl,char * c)3210 static GlReadStatus gl_read_input(GetLine *gl, char *c)
3211 {
3212 /*
3213 * We may have to repeat the read if window change signals are received.
3214 */
3215 for(;;) {
3216 /*
3217 * Which file descriptor should we read from? Mark this volatile, so
3218 * that siglongjmp() can't clobber it.
3219 */
3220 volatile int fd = gl->file_fp ? fileno(gl->file_fp) : gl->input_fd;
3221 /*
3222 * If the endline flag becomes set, don't wait for another character.
3223 */
3224 if(gl->endline)
3225 return GL_READ_ERROR;
3226 /*
3227 * Since the code in this function can block, trap signals.
3228 */
3229 if(sigsetjmp(gl_setjmp_buffer, 1)==0) {
3230 /*
3231 * Handle the different I/O modes.
3232 */
3233 switch(gl->io_mode) {
3234 /*
3235 * In normal I/O mode, we call the event handler before attempting
3236 * to read, since read() blocks.
3237 */
3238 case GL_NORMAL_MODE:
3239 if(gl_event_handler(gl, fd))
3240 return GL_READ_ERROR;
3241 return gl_read_unmasked(gl, fd, c); /* Read one character */
3242 break;
3243 /*
3244 * In non-blocking server I/O mode, we attempt to read a character,
3245 * and only if this fails, call the event handler to wait for a any
3246 * user-configured timeout and any other user-configured events. In
3247 * addition, we turn off the fcntl() non-blocking flag when reading
3248 * from the terminal, to work around a bug in Solaris. We can do this
3249 * without causing the read() to block, because when in non-blocking
3250 * server-I/O mode, gl_raw_io() sets the VMIN terminal attribute to 0,
3251 * which tells the terminal driver to return immediately if no
3252 * characters are available to be read.
3253 */
3254 case GL_SERVER_MODE:
3255 {
3256 GlReadStatus status; /* The return status */
3257 if(isatty(fd)) /* If we reading from a terminal, */
3258 gl_blocking_io(gl, fd); /* switch to blocking I/O */
3259 status = gl_read_unmasked(gl, fd, c); /* Try reading */
3260 if(status == GL_READ_BLOCKED) { /* Nothing readable yet */
3261 if(gl_event_handler(gl, fd)) /* Wait for input */
3262 status = GL_READ_ERROR;
3263 else
3264 status = gl_read_unmasked(gl, fd, c); /* Try reading again */
3265 };
3266 gl_nonblocking_io(gl, fd); /* Restore non-blocking I/O */
3267 return status;
3268 };
3269 break;
3270 };
3271 };
3272 /*
3273 * To get here, one of the signals that we are trapping must have
3274 * been received. Note that by using sigsetjmp() instead of setjmp()
3275 * the signal mask that was blocking these signals will have been
3276 * reinstated, so we can be sure that no more of these signals will
3277 * be received until we explicitly unblock them again.
3278 *
3279 * First, if non-blocking I/O was temporarily disabled, reinstate it.
3280 */
3281 if(gl->io_mode == GL_SERVER_MODE)
3282 gl_nonblocking_io(gl, fd);
3283 /*
3284 * Now respond to the signal that was caught.
3285 */
3286 if(gl_check_caught_signal(gl))
3287 return GL_READ_ERROR;
3288 };
3289 }
3290
3291 /*.......................................................................
3292 * This is a private function of gl_read_input(), which unblocks signals
3293 * temporarily while it reads a single character from the specified file
3294 * descriptor.
3295 *
3296 * Input:
3297 * gl GetLine * The resource object of this module.
3298 * fd int The file descriptor to read from.
3299 * c char * The character that was read is assigned to *c.
3300 * Output:
3301 * return GlReadStatus The completion status of the read.
3302 */
gl_read_unmasked(GetLine * gl,int fd,char * c)3303 static int gl_read_unmasked(GetLine *gl, int fd, char *c)
3304 {
3305 int nread; /* The return value of read() */
3306 /*
3307 * Unblock the signals that we are trapping, while waiting for I/O.
3308 */
3309 gl_catch_signals(gl);
3310 /*
3311 * Attempt to read one character from the terminal, restarting the read
3312 * if any signals that we aren't trapping, are received.
3313 */
3314 do {
3315 errno = 0;
3316 nread = read(fd, c, 1);
3317 } while(nread < 0 && errno==EINTR);
3318 /*
3319 * Block all of the signals that we are trapping.
3320 */
3321 gl_mask_signals(gl, NULL);
3322 /*
3323 * Check the completion status of the read.
3324 */
3325 switch(nread) {
3326 case 1:
3327 return GL_READ_OK;
3328 case 0:
3329 return (isatty(fd) || errno != 0) ? GL_READ_BLOCKED : GL_READ_EOF;
3330 default:
3331 return GL_READ_ERROR;
3332 };
3333 }
3334
3335 /*.......................................................................
3336 * Remove a specified number of characters from the start of the
3337 * key-press lookahead buffer, gl->keybuf[], and arrange for the next
3338 * read to start from the character at the start of the shifted buffer.
3339 *
3340 * Input:
3341 * gl GetLine * The resource object of this module.
3342 * nused int The number of characters to discard from the start
3343 * of the buffer.
3344 */
gl_discard_chars(GetLine * gl,int nused)3345 static void gl_discard_chars(GetLine *gl, int nused)
3346 {
3347 int nkeep = gl->nbuf - nused;
3348 if(nkeep > 0) {
3349 memmove(gl->keybuf, gl->keybuf + nused, nkeep);
3350 gl->nbuf = nkeep;
3351 gl->nread = 0;
3352 } else {
3353 gl->nbuf = gl->nread = 0;
3354 };
3355 }
3356
3357 /*.......................................................................
3358 * This function is called to handle signals caught between calls to
3359 * sigsetjmp() and siglongjmp().
3360 *
3361 * Input:
3362 * gl GetLine * The resource object of this library.
3363 * Output:
3364 * return int 0 - Signal handled internally.
3365 * 1 - Signal requires gl_get_line() to abort.
3366 */
gl_check_caught_signal(GetLine * gl)3367 static int gl_check_caught_signal(GetLine *gl)
3368 {
3369 GlSignalNode *sig; /* The signal disposition */
3370 SigAction keep_action; /* The signal disposition of tecla signal handlers */
3371 unsigned flags; /* The signal processing flags to use */
3372 int signo; /* The signal to be handled */
3373 /*
3374 * Was no signal caught?
3375 */
3376 if(gl_pending_signal == -1)
3377 return 0;
3378 /*
3379 * Get the signal to be handled.
3380 */
3381 signo = gl_pending_signal;
3382 /*
3383 * Mark the signal as handled. Note that at this point, all of
3384 * the signals that we are trapping are blocked from delivery.
3385 */
3386 gl_pending_signal = -1;
3387 /*
3388 * Record the signal that was caught, so that the user can query it later.
3389 */
3390 gl->last_signal = signo;
3391 /*
3392 * In non-blocking server mode, the application is responsible for
3393 * responding to terminal signals, and we don't want gl_get_line()s
3394 * normal signal handling to clash with this, so whenever a signal
3395 * is caught, we arrange for gl_get_line() to abort and requeue the
3396 * signal while signals are still blocked. If the application
3397 * had the signal unblocked when gl_get_line() was called, the signal
3398 * will be delivered again as soon as gl_get_line() restores the
3399 * process signal mask, just before returning to the application.
3400 * Note that the caller of this function should set gl->pending_io
3401 * to the appropriate choice of GLP_READ and GLP_WRITE, before returning.
3402 */
3403 if(gl->io_mode==GL_SERVER_MODE) {
3404 gl_record_status(gl, GLR_SIGNAL, EINTR);
3405 raise(signo);
3406 return 1;
3407 };
3408 /*
3409 * Lookup the requested disposition of this signal.
3410 */
3411 for(sig=gl->sigs; sig && sig->signo != signo; sig=sig->next)
3412 ;
3413 if(!sig)
3414 return 0;
3415 /*
3416 * Get the signal response flags for this signal.
3417 */
3418 flags = sig->flags;
3419 /*
3420 * Did we receive a terminal size signal?
3421 */
3422 #ifdef SIGWINCH
3423 if(signo == SIGWINCH && _gl_update_size(gl))
3424 return 1;
3425 #endif
3426 /*
3427 * Start a fresh line?
3428 */
3429 if(flags & GLS_RESTORE_LINE) {
3430 if(gl_start_newline(gl, 0))
3431 return 1;
3432 };
3433 /*
3434 * Restore terminal settings to how they were before gl_get_line() was
3435 * called?
3436 */
3437 if(flags & GLS_RESTORE_TTY)
3438 gl_restore_terminal_attributes(gl);
3439 /*
3440 * Restore signal handlers to how they were before gl_get_line() was
3441 * called? If this hasn't been requested, only reinstate the signal
3442 * handler of the signal that we are handling.
3443 */
3444 if(flags & GLS_RESTORE_SIG) {
3445 gl_restore_signal_handlers(gl);
3446 gl_unmask_signals(gl, &gl->old_signal_set);
3447 } else {
3448 (void) sigaction(sig->signo, &sig->original, &keep_action);
3449 (void) sigprocmask(SIG_UNBLOCK, &sig->proc_mask, NULL);
3450 };
3451 /*
3452 * Forward the signal to the application's signal handler.
3453 */
3454 if(!(flags & GLS_DONT_FORWARD))
3455 raise(signo);
3456 /*
3457 * Reinstate our signal handlers.
3458 */
3459 if(flags & GLS_RESTORE_SIG) {
3460 gl_mask_signals(gl, NULL);
3461 gl_override_signal_handlers(gl);
3462 } else {
3463 (void) sigaction(sig->signo, &keep_action, NULL);
3464 (void) sigprocmask(SIG_BLOCK, &sig->proc_mask, NULL);
3465 };
3466 /*
3467 * Do we need to reinstate our terminal settings?
3468 */
3469 if(flags & GLS_RESTORE_TTY)
3470 gl_raw_terminal_mode(gl);
3471 /*
3472 * Redraw the line?
3473 */
3474 if(flags & GLS_REDRAW_LINE)
3475 gl_queue_redisplay(gl);
3476 /*
3477 * What next?
3478 */
3479 switch(sig->after) {
3480 case GLS_RETURN:
3481 gl_newline(gl, 1, NULL);
3482 return gl_flush_output(gl);
3483 break;
3484 case GLS_ABORT:
3485 gl_record_status(gl, GLR_SIGNAL, sig->errno_value);
3486 return 1;
3487 break;
3488 case GLS_CONTINUE:
3489 return gl_flush_output(gl);
3490 break;
3491 };
3492 return 0;
3493 }
3494
3495 /*.......................................................................
3496 * Get pertinent terminal control strings and the initial terminal size.
3497 *
3498 * Input:
3499 * gl GetLine * The resource object of this library.
3500 * term char * The type of the terminal.
3501 * Output:
3502 * return int 0 - OK.
3503 * 1 - Error.
3504 */
gl_control_strings(GetLine * gl,const char * term)3505 static int gl_control_strings(GetLine *gl, const char *term)
3506 {
3507 int bad_term = 0; /* True if term is unusable */
3508 /*
3509 * Discard any existing control strings from a previous terminal.
3510 */
3511 gl->left = NULL;
3512 gl->right = NULL;
3513 gl->up = NULL;
3514 gl->down = NULL;
3515 gl->home = NULL;
3516 gl->bol = 0;
3517 gl->clear_eol = NULL;
3518 gl->clear_eod = NULL;
3519 gl->u_arrow = NULL;
3520 gl->d_arrow = NULL;
3521 gl->l_arrow = NULL;
3522 gl->r_arrow = NULL;
3523 gl->sound_bell = NULL;
3524 gl->bold = NULL;
3525 gl->underline = NULL;
3526 gl->standout = NULL;
3527 gl->dim = NULL;
3528 gl->reverse = NULL;
3529 gl->blink = NULL;
3530 gl->text_attr_off = NULL;
3531 gl->nline = 0;
3532 gl->ncolumn = 0;
3533 #ifdef USE_TERMINFO
3534 gl->left_n = NULL;
3535 gl->right_n = NULL;
3536 #endif
3537 /*
3538 * If possible lookup the information in a terminal information
3539 * database.
3540 */
3541 #ifdef USE_TERMINFO
3542 {
3543 int errret;
3544 if(!term || setupterm((char *)term, gl->input_fd, &errret) == ERR) {
3545 bad_term = 1;
3546 } else {
3547 _clr_StringGroup(gl->capmem);
3548 gl->left = gl_tigetstr(gl, "cub1");
3549 gl->right = gl_tigetstr(gl, "cuf1");
3550 gl->up = gl_tigetstr(gl, "cuu1");
3551 gl->down = gl_tigetstr(gl, "cud1");
3552 gl->home = gl_tigetstr(gl, "home");
3553 gl->clear_eol = gl_tigetstr(gl, "el");
3554 gl->clear_eod = gl_tigetstr(gl, "ed");
3555 gl->u_arrow = gl_tigetstr(gl, "kcuu1");
3556 gl->d_arrow = gl_tigetstr(gl, "kcud1");
3557 gl->l_arrow = gl_tigetstr(gl, "kcub1");
3558 gl->r_arrow = gl_tigetstr(gl, "kcuf1");
3559 gl->left_n = gl_tigetstr(gl, "cub");
3560 gl->right_n = gl_tigetstr(gl, "cuf");
3561 gl->sound_bell = gl_tigetstr(gl, "bel");
3562 gl->bold = gl_tigetstr(gl, "bold");
3563 gl->underline = gl_tigetstr(gl, "smul");
3564 gl->standout = gl_tigetstr(gl, "smso");
3565 gl->dim = gl_tigetstr(gl, "dim");
3566 gl->reverse = gl_tigetstr(gl, "rev");
3567 gl->blink = gl_tigetstr(gl, "blink");
3568 gl->text_attr_off = gl_tigetstr(gl, "sgr0");
3569 };
3570 };
3571 #elif defined(USE_TERMCAP)
3572 if(!term || tgetent(gl->tgetent_buf, (char *)term) < 0) {
3573 bad_term = 1;
3574 } else {
3575 char *tgetstr_buf_ptr = gl->tgetstr_buf;
3576 _clr_StringGroup(gl->capmem);
3577 gl->left = gl_tgetstr(gl, "le", &tgetstr_buf_ptr);
3578 gl->right = gl_tgetstr(gl, "nd", &tgetstr_buf_ptr);
3579 gl->up = gl_tgetstr(gl, "up", &tgetstr_buf_ptr);
3580 gl->down = gl_tgetstr(gl, "do", &tgetstr_buf_ptr);
3581 gl->home = gl_tgetstr(gl, "ho", &tgetstr_buf_ptr);
3582 gl->clear_eol = gl_tgetstr(gl, "ce", &tgetstr_buf_ptr);
3583 gl->clear_eod = gl_tgetstr(gl, "cd", &tgetstr_buf_ptr);
3584 gl->u_arrow = gl_tgetstr(gl, "ku", &tgetstr_buf_ptr);
3585 gl->d_arrow = gl_tgetstr(gl, "kd", &tgetstr_buf_ptr);
3586 gl->l_arrow = gl_tgetstr(gl, "kl", &tgetstr_buf_ptr);
3587 gl->r_arrow = gl_tgetstr(gl, "kr", &tgetstr_buf_ptr);
3588 gl->sound_bell = gl_tgetstr(gl, "bl", &tgetstr_buf_ptr);
3589 gl->bold = gl_tgetstr(gl, "md", &tgetstr_buf_ptr);
3590 gl->underline = gl_tgetstr(gl, "us", &tgetstr_buf_ptr);
3591 gl->standout = gl_tgetstr(gl, "so", &tgetstr_buf_ptr);
3592 gl->dim = gl_tgetstr(gl, "mh", &tgetstr_buf_ptr);
3593 gl->reverse = gl_tgetstr(gl, "mr", &tgetstr_buf_ptr);
3594 gl->blink = gl_tgetstr(gl, "mb", &tgetstr_buf_ptr);
3595 gl->text_attr_off = gl_tgetstr(gl, "me", &tgetstr_buf_ptr);
3596 };
3597 #endif
3598 /*
3599 * Report term being unusable.
3600 */
3601 if(bad_term) {
3602 gl_print_info(gl, "Bad terminal type: \"", term ? term : "(null)",
3603 "\". Will assume vt100.", GL_END_INFO);
3604 };
3605 /*
3606 * Fill in missing information with ANSI VT100 strings.
3607 */
3608 if(!gl->left)
3609 gl->left = "\b"; /* ^H */
3610 if(!gl->right)
3611 gl->right = GL_ESC_STR "[C";
3612 if(!gl->up)
3613 gl->up = GL_ESC_STR "[A";
3614 if(!gl->down)
3615 gl->down = "\n";
3616 if(!gl->home)
3617 gl->home = GL_ESC_STR "[H";
3618 if(!gl->bol)
3619 gl->bol = "\r";
3620 if(!gl->clear_eol)
3621 gl->clear_eol = GL_ESC_STR "[K";
3622 if(!gl->clear_eod)
3623 gl->clear_eod = GL_ESC_STR "[J";
3624 if(!gl->u_arrow)
3625 gl->u_arrow = GL_ESC_STR "[A";
3626 if(!gl->d_arrow)
3627 gl->d_arrow = GL_ESC_STR "[B";
3628 if(!gl->l_arrow)
3629 gl->l_arrow = GL_ESC_STR "[D";
3630 if(!gl->r_arrow)
3631 gl->r_arrow = GL_ESC_STR "[C";
3632 if(!gl->sound_bell)
3633 gl->sound_bell = "\a";
3634 if(!gl->bold)
3635 gl->bold = GL_ESC_STR "[1m";
3636 if(!gl->underline)
3637 gl->underline = GL_ESC_STR "[4m";
3638 if(!gl->standout)
3639 gl->standout = GL_ESC_STR "[1;7m";
3640 if(!gl->dim)
3641 gl->dim = ""; /* Not available */
3642 if(!gl->reverse)
3643 gl->reverse = GL_ESC_STR "[7m";
3644 if(!gl->blink)
3645 gl->blink = GL_ESC_STR "[5m";
3646 if(!gl->text_attr_off)
3647 gl->text_attr_off = GL_ESC_STR "[m";
3648 /*
3649 * Find out the current terminal size.
3650 */
3651 (void) _gl_terminal_size(gl, GL_DEF_NCOLUMN, GL_DEF_NLINE, NULL);
3652 return 0;
3653 }
3654
3655 #ifdef USE_TERMINFO
3656 /*.......................................................................
3657 * This is a private function of gl_control_strings() used to look up
3658 * a termninal capability string from the terminfo database and make
3659 * a private copy of it.
3660 *
3661 * Input:
3662 * gl GetLine * The resource object of gl_get_line().
3663 * name const char * The name of the terminfo string to look up.
3664 * Output:
3665 * return const char * The local copy of the capability, or NULL
3666 * if not available.
3667 */
gl_tigetstr(GetLine * gl,const char * name)3668 static const char *gl_tigetstr(GetLine *gl, const char *name)
3669 {
3670 const char *value = tigetstr((char *)name);
3671 if(!value || value == (char *) -1)
3672 return NULL;
3673 return _sg_store_string(gl->capmem, value, 0);
3674 }
3675 #elif defined(USE_TERMCAP)
3676 /*.......................................................................
3677 * This is a private function of gl_control_strings() used to look up
3678 * a termninal capability string from the termcap database and make
3679 * a private copy of it. Note that some emulations of tgetstr(), such
3680 * as that used by Solaris, ignores the buffer pointer that is past to
3681 * it, so we can't assume that a private copy has been made that won't
3682 * be trashed by another call to gl_control_strings() by another
3683 * GetLine object. So we make what may be a redundant private copy
3684 * of the string in gl->capmem.
3685 *
3686 * Input:
3687 * gl GetLine * The resource object of gl_get_line().
3688 * name const char * The name of the terminfo string to look up.
3689 * Input/Output:
3690 * bufptr char ** On input *bufptr points to the location in
3691 * gl->tgetstr_buf at which to record the
3692 * capability string. On output *bufptr is
3693 * incremented over the stored string.
3694 * Output:
3695 * return const char * The local copy of the capability, or NULL
3696 * on error.
3697 */
gl_tgetstr(GetLine * gl,const char * name,char ** bufptr)3698 static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr)
3699 {
3700 const char *value = tgetstr((char *)name, bufptr);
3701 if(!value || value == (char *) -1)
3702 return NULL;
3703 return _sg_store_string(gl->capmem, value, 0);
3704 }
3705 #endif
3706
3707 /*.......................................................................
3708 * This is an action function that implements a user interrupt (eg. ^C).
3709 */
KT_KEY_FN(gl_user_interrupt)3710 static KT_KEY_FN(gl_user_interrupt)
3711 {
3712 raise(SIGINT);
3713 return 1;
3714 }
3715
3716 /*.......................................................................
3717 * This is an action function that implements the abort signal.
3718 */
KT_KEY_FN(gl_abort)3719 static KT_KEY_FN(gl_abort)
3720 {
3721 raise(SIGABRT);
3722 return 1;
3723 }
3724
3725 /*.......................................................................
3726 * This is an action function that sends a suspend signal (eg. ^Z) to the
3727 * the parent process.
3728 */
KT_KEY_FN(gl_suspend)3729 static KT_KEY_FN(gl_suspend)
3730 {
3731 raise(SIGTSTP);
3732 return 0;
3733 }
3734
3735 /*.......................................................................
3736 * This is an action function that halts output to the terminal.
3737 */
KT_KEY_FN(gl_stop_output)3738 static KT_KEY_FN(gl_stop_output)
3739 {
3740 tcflow(gl->output_fd, TCOOFF);
3741 return 0;
3742 }
3743
3744 /*.......................................................................
3745 * This is an action function that resumes halted terminal output.
3746 */
KT_KEY_FN(gl_start_output)3747 static KT_KEY_FN(gl_start_output)
3748 {
3749 tcflow(gl->output_fd, TCOON);
3750 return 0;
3751 }
3752
3753 /*.......................................................................
3754 * This is an action function that allows the next character to be accepted
3755 * without any interpretation as a special character.
3756 */
KT_KEY_FN(gl_literal_next)3757 static KT_KEY_FN(gl_literal_next)
3758 {
3759 char c; /* The character to be added to the line */
3760 int i;
3761 /*
3762 * Get the character to be inserted literally.
3763 */
3764 if(gl_read_terminal(gl, 1, &c))
3765 return 1;
3766 /*
3767 * Add the character to the line 'count' times.
3768 */
3769 for(i=0; i<count; i++)
3770 gl_add_char_to_line(gl, c);
3771 return 0;
3772 }
3773
3774 /*.......................................................................
3775 * Return the width of a tab character at a given position when
3776 * displayed at a given position on the terminal. This is needed
3777 * because the width of tab characters depends on where they are,
3778 * relative to the preceding tab stops.
3779 *
3780 * Input:
3781 * gl GetLine * The resource object of this library.
3782 * term_curpos int The destination terminal location of the character.
3783 * Output:
3784 * return int The number of terminal charaters needed.
3785 */
gl_displayed_tab_width(GetLine * gl,int term_curpos)3786 static int gl_displayed_tab_width(GetLine *gl, int term_curpos)
3787 {
3788 return TAB_WIDTH - ((term_curpos % gl->ncolumn) % TAB_WIDTH);
3789 }
3790
3791 /*.......................................................................
3792 * Return the number of characters needed to display a given character
3793 * on the screen. Tab characters require eight spaces, and control
3794 * characters are represented by a caret followed by the modified
3795 * character.
3796 *
3797 * Input:
3798 * gl GetLine * The resource object of this library.
3799 * c char The character to be displayed.
3800 * term_curpos int The destination terminal location of the character.
3801 * This is needed because the width of tab characters
3802 * depends on where they are, relative to the
3803 * preceding tab stops.
3804 * Output:
3805 * return int The number of terminal charaters needed.
3806 */
gl_displayed_char_width(GetLine * gl,char c,int term_curpos)3807 static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos)
3808 {
3809 if(c=='\t')
3810 return gl_displayed_tab_width(gl, term_curpos);
3811 if(IS_CTRL_CHAR(c))
3812 return 2;
3813 if(!isprint((int)(unsigned char) c))
3814 return gl_octal_width((int)(unsigned char)c) + 1;
3815 return 1;
3816 }
3817
3818
3819 /*.......................................................................
3820 * Work out the length of given string of characters on the terminal.
3821 *
3822 * Input:
3823 * gl GetLine * The resource object of this library.
3824 * string char * The string to be measured.
3825 * nc int The number of characters to be measured, or -1
3826 * to measure the whole string.
3827 * term_curpos int The destination terminal location of the character.
3828 * This is needed because the width of tab characters
3829 * depends on where they are, relative to the
3830 * preceding tab stops.
3831 * Output:
3832 * return int The number of displayed characters.
3833 */
gl_displayed_string_width(GetLine * gl,const char * string,int nc,int term_curpos)3834 static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
3835 int term_curpos)
3836 {
3837 int slen = 0; /* The displayed number of characters */
3838 int i;
3839 /*
3840 * How many characters are to be measured?
3841 */
3842 if(nc < 0)
3843 nc = strlen(string);
3844 /*
3845 * Add up the length of the displayed string.
3846 */
3847 for(i=0; i<nc; i++)
3848 slen += gl_displayed_char_width(gl, string[i], term_curpos + slen);
3849 return slen;
3850 }
3851
3852 /*.......................................................................
3853 * Write a string verbatim to the current terminal or output stream.
3854 *
3855 * Note that when async-signal safety is required, the 'buffered'
3856 * argument must be 0, and n must not be -1.
3857 *
3858 * Input:
3859 * gl GetLine * The resource object of the gl_get_line().
3860 * buffered int If true, used buffered I/O when writing to
3861 * the terminal. Otherwise use async-signal-safe
3862 * unbuffered I/O.
3863 * string const char * The string to be written (this need not be
3864 * '\0' terminated unless n<0).
3865 * n int The number of characters to write from the
3866 * prefix of string[], or -1 to request that
3867 * gl_print_raw_string() use strlen() to figure
3868 * out the length.
3869 * Output:
3870 * return int 0 - OK.
3871 * 1 - Error.
3872 */
gl_print_raw_string(GetLine * gl,int buffered,const char * string,int n)3873 static int gl_print_raw_string(GetLine *gl, int buffered,
3874 const char *string, int n)
3875 {
3876 GlWriteFn *write_fn = buffered ? gl_write_fn : gl->flush_fn;
3877 /*
3878 * Only display output when echoing is turned on.
3879 */
3880 if(gl->echo) {
3881 int ndone = 0; /* The number of characters written so far */
3882 /*
3883 * When using un-buffered I/O, flush pending output first.
3884 */
3885 if(!buffered) {
3886 if(gl_flush_output(gl))
3887 return 1;
3888 };
3889 /*
3890 * If no length has been provided, measure the length of the string.
3891 */
3892 if(n < 0)
3893 n = strlen(string);
3894 /*
3895 * Write the string.
3896 */
3897 if(write_fn(gl, string + ndone, n-ndone) != n)
3898 return 1;
3899 };
3900 return 0;
3901 }
3902
3903 /*.......................................................................
3904 * Output a terminal control sequence. When using terminfo,
3905 * this must be a sequence returned by tgetstr() or tigetstr()
3906 * respectively.
3907 *
3908 * Input:
3909 * gl GetLine * The resource object of this library.
3910 * nline int The number of lines affected by the operation,
3911 * or 1 if not relevant.
3912 * string char * The control sequence to be sent.
3913 * Output:
3914 * return int 0 - OK.
3915 * 1 - Error.
3916 */
gl_print_control_sequence(GetLine * gl,int nline,const char * string)3917 static int gl_print_control_sequence(GetLine *gl, int nline, const char *string)
3918 {
3919 int waserr = 0; /* True if an error occurs */
3920 /*
3921 * Only write characters to the terminal when echoing is enabled.
3922 */
3923 if(gl->echo) {
3924 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
3925 tputs_gl = gl;
3926 errno = 0;
3927 tputs((char *)string, nline, gl_tputs_putchar);
3928 waserr = errno != 0;
3929 #else
3930 waserr = gl_print_raw_string(gl, 1, string, -1);
3931 #endif
3932 };
3933 return waserr;
3934 }
3935
3936 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
3937 /*.......................................................................
3938 * The following callback function is called by tputs() to output a raw
3939 * control character to the terminal.
3940 */
gl_tputs_putchar(TputsArgType c)3941 static TputsRetType gl_tputs_putchar(TputsArgType c)
3942 {
3943 char ch = c;
3944 #if TPUTS_RETURNS_VALUE
3945 return gl_print_raw_string(tputs_gl, 1, &ch, 1);
3946 #else
3947 (void) gl_print_raw_string(tputs_gl, 1, &ch, 1);
3948 #endif
3949 }
3950 #endif
3951
3952 /*.......................................................................
3953 * Move the terminal cursor n characters to the left or right.
3954 *
3955 * Input:
3956 * gl GetLine * The resource object of this program.
3957 * n int number of positions to the right (> 0) or left (< 0).
3958 * Output:
3959 * return int 0 - OK.
3960 * 1 - Error.
3961 */
gl_terminal_move_cursor(GetLine * gl,int n)3962 static int gl_terminal_move_cursor(GetLine *gl, int n)
3963 {
3964 int cur_row, cur_col; /* The current terminal row and column index of */
3965 /* the cursor wrt the start of the input line. */
3966 int new_row, new_col; /* The target terminal row and column index of */
3967 /* the cursor wrt the start of the input line. */
3968 /*
3969 * Do nothing if the input line isn't currently displayed. In this
3970 * case, the cursor will be moved to the right place when the line
3971 * is next redisplayed.
3972 */
3973 if(!gl->displayed)
3974 return 0;
3975 /*
3976 * How far can we move left?
3977 */
3978 if(gl->term_curpos + n < 0)
3979 n = gl->term_curpos;
3980 /*
3981 * Break down the current and target cursor locations into rows and columns.
3982 */
3983 cur_row = gl->term_curpos / gl->ncolumn;
3984 cur_col = gl->term_curpos % gl->ncolumn;
3985 new_row = (gl->term_curpos + n) / gl->ncolumn;
3986 new_col = (gl->term_curpos + n) % gl->ncolumn;
3987 /*
3988 * Move down to the next line.
3989 */
3990 for(; cur_row < new_row; cur_row++) {
3991 if(gl_print_control_sequence(gl, 1, gl->down))
3992 return 1;
3993 };
3994 /*
3995 * Move up to the previous line.
3996 */
3997 for(; cur_row > new_row; cur_row--) {
3998 if(gl_print_control_sequence(gl, 1, gl->up))
3999 return 1;
4000 };
4001 /*
4002 * Move to the right within the target line?
4003 */
4004 if(cur_col < new_col) {
4005 #ifdef USE_TERMINFO
4006 /*
4007 * Use a parameterized control sequence if it generates less control
4008 * characters (guess based on ANSI terminal termcap entry).
4009 */
4010 if(gl->right_n != NULL && new_col - cur_col > 1) {
4011 if(gl_print_control_sequence(gl, 1, tparm((char *)gl->right_n,
4012 (long)(new_col - cur_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
4013 return 1;
4014 } else
4015 #endif
4016 {
4017 for(; cur_col < new_col; cur_col++) {
4018 if(gl_print_control_sequence(gl, 1, gl->right))
4019 return 1;
4020 };
4021 };
4022 /*
4023 * Move to the left within the target line?
4024 */
4025 } else if(cur_col > new_col) {
4026 #ifdef USE_TERMINFO
4027 /*
4028 * Use a parameterized control sequence if it generates less control
4029 * characters (guess based on ANSI terminal termcap entry).
4030 */
4031 if(gl->left_n != NULL && cur_col - new_col > 3) {
4032 if(gl_print_control_sequence(gl, 1, tparm((char *)gl->left_n,
4033 (long)(cur_col - new_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
4034 return 1;
4035 } else
4036 #endif
4037 {
4038 for(; cur_col > new_col; cur_col--) {
4039 if(gl_print_control_sequence(gl, 1, gl->left))
4040 return 1;
4041 };
4042 };
4043 }
4044 /*
4045 * Update the recorded position of the terminal cursor.
4046 */
4047 gl->term_curpos += n;
4048 return 0;
4049 }
4050
4051 /*.......................................................................
4052 * Write a character to the terminal after expanding tabs and control
4053 * characters to their multi-character representations.
4054 *
4055 * Input:
4056 * gl GetLine * The resource object of this program.
4057 * c char The character to be output.
4058 * pad char Many terminals have the irritating feature that
4059 * when one writes a character in the last column of
4060 * of the terminal, the cursor isn't wrapped to the
4061 * start of the next line until one more character
4062 * is written. Some terminals don't do this, so
4063 * after such a write, we don't know where the
4064 * terminal is unless we output an extra character.
4065 * This argument specifies the character to write.
4066 * If at the end of the input line send '\0' or a
4067 * space, and a space will be written. Otherwise,
4068 * pass the next character in the input line
4069 * following the one being written.
4070 * Output:
4071 * return int 0 - OK.
4072 */
gl_print_char(GetLine * gl,char c,char pad)4073 static int gl_print_char(GetLine *gl, char c, char pad)
4074 {
4075 char string[TAB_WIDTH + 4]; /* A work area for composing compound strings */
4076 int nchar; /* The number of terminal characters */
4077 int i;
4078 /*
4079 * Check for special characters.
4080 */
4081 if(c == '\t') {
4082 /*
4083 * How many spaces do we need to represent a tab at the current terminal
4084 * column?
4085 */
4086 nchar = gl_displayed_tab_width(gl, gl->term_curpos);
4087 /*
4088 * Compose the tab string.
4089 */
4090 for(i=0; i<nchar; i++)
4091 string[i] = ' ';
4092 } else if(IS_CTRL_CHAR(c)) {
4093 string[0] = '^';
4094 string[1] = CTRL_TO_CHAR(c);
4095 nchar = 2;
4096 } else if(!isprint((int)(unsigned char) c)) {
4097 snprintf(string, sizeof(string), "\\%o", (int)(unsigned char)c);
4098 nchar = strlen(string);
4099 } else {
4100 string[0] = c;
4101 nchar = 1;
4102 };
4103 /*
4104 * Terminate the string.
4105 */
4106 string[nchar] = '\0';
4107 /*
4108 * Write the string to the terminal.
4109 */
4110 if(gl_print_raw_string(gl, 1, string, -1))
4111 return 1;
4112 /*
4113 * Except for one exception to be described in a moment, the cursor should
4114 * now have been positioned after the character that was just output.
4115 */
4116 gl->term_curpos += nchar;
4117 /*
4118 * Keep a record of the number of characters in the terminal version
4119 * of the input line.
4120 */
4121 if(gl->term_curpos > gl->term_len)
4122 gl->term_len = gl->term_curpos;
4123 /*
4124 * If the new character ended exactly at the end of a line,
4125 * most terminals won't move the cursor onto the next line until we
4126 * have written a character on the next line, so append an extra
4127 * space then move the cursor back.
4128 */
4129 if(gl->term_curpos % gl->ncolumn == 0) {
4130 int term_curpos = gl->term_curpos;
4131 if(gl_print_char(gl, pad ? pad : ' ', ' ') ||
4132 gl_set_term_curpos(gl, term_curpos))
4133 return 1;
4134 };
4135 return 0;
4136 }
4137
4138 /*.......................................................................
4139 * Write a string to the terminal after expanding tabs and control
4140 * characters to their multi-character representations.
4141 *
4142 * Input:
4143 * gl GetLine * The resource object of this program.
4144 * string char * The string to be output.
4145 * pad char Many terminals have the irritating feature that
4146 * when one writes a character in the last column of
4147 * of the terminal, the cursor isn't wrapped to the
4148 * start of the next line until one more character
4149 * is written. Some terminals don't do this, so
4150 * after such a write, we don't know where the
4151 * terminal is unless we output an extra character.
4152 * This argument specifies the character to write.
4153 * If at the end of the input line send '\0' or a
4154 * space, and a space will be written. Otherwise,
4155 * pass the next character in the input line
4156 * following the one being written.
4157 * Output:
4158 * return int 0 - OK.
4159 */
gl_print_string(GetLine * gl,const char * string,char pad)4160 static int gl_print_string(GetLine *gl, const char *string, char pad)
4161 {
4162 const char *cptr; /* A pointer into string[] */
4163 for(cptr=string; *cptr; cptr++) {
4164 char nextc = cptr[1];
4165 if(gl_print_char(gl, *cptr, nextc ? nextc : pad))
4166 return 1;
4167 };
4168 return 0;
4169 }
4170
4171 /*.......................................................................
4172 * Move the terminal cursor position.
4173 *
4174 * Input:
4175 * gl GetLine * The resource object of this library.
4176 * term_curpos int The destination terminal cursor position.
4177 * Output:
4178 * return int 0 - OK.
4179 * 1 - Error.
4180 */
gl_set_term_curpos(GetLine * gl,int term_curpos)4181 static int gl_set_term_curpos(GetLine *gl, int term_curpos)
4182 {
4183 return gl_terminal_move_cursor(gl, term_curpos - gl->term_curpos);
4184 }
4185
4186 /*.......................................................................
4187 * This is an action function that moves the buffer cursor one character
4188 * left, and updates the terminal cursor to match.
4189 */
KT_KEY_FN(gl_cursor_left)4190 static KT_KEY_FN(gl_cursor_left)
4191 {
4192 return gl_place_cursor(gl, gl->buff_curpos - count);
4193 }
4194
4195 /*.......................................................................
4196 * This is an action function that moves the buffer cursor one character
4197 * right, and updates the terminal cursor to match.
4198 */
KT_KEY_FN(gl_cursor_right)4199 static KT_KEY_FN(gl_cursor_right)
4200 {
4201 return gl_place_cursor(gl, gl->buff_curpos + count);
4202 }
4203
4204 /*.......................................................................
4205 * This is an action function that toggles between overwrite and insert
4206 * mode.
4207 */
KT_KEY_FN(gl_insert_mode)4208 static KT_KEY_FN(gl_insert_mode)
4209 {
4210 gl->insert = !gl->insert;
4211 return 0;
4212 }
4213
4214 /*.......................................................................
4215 * This is an action function which moves the cursor to the beginning of
4216 * the line.
4217 */
KT_KEY_FN(gl_beginning_of_line)4218 static KT_KEY_FN(gl_beginning_of_line)
4219 {
4220 return gl_place_cursor(gl, 0);
4221 }
4222
4223 /*.......................................................................
4224 * This is an action function which moves the cursor to the end of
4225 * the line.
4226 */
KT_KEY_FN(gl_end_of_line)4227 static KT_KEY_FN(gl_end_of_line)
4228 {
4229 return gl_place_cursor(gl, gl->ntotal);
4230 }
4231
4232 /*.......................................................................
4233 * This is an action function which deletes the entire contents of the
4234 * current line.
4235 */
KT_KEY_FN(gl_delete_line)4236 static KT_KEY_FN(gl_delete_line)
4237 {
4238 /*
4239 * If in vi command mode, preserve the current line for potential
4240 * use by vi-undo.
4241 */
4242 gl_save_for_undo(gl);
4243 /*
4244 * Copy the contents of the line to the cut buffer.
4245 */
4246 strlcpy(gl->cutbuf, gl->line, gl->linelen);
4247 /*
4248 * Clear the buffer.
4249 */
4250 gl_truncate_buffer(gl, 0);
4251 /*
4252 * Move the terminal cursor to just after the prompt.
4253 */
4254 if(gl_place_cursor(gl, 0))
4255 return 1;
4256 /*
4257 * Clear from the end of the prompt to the end of the terminal.
4258 */
4259 if(gl_truncate_display(gl))
4260 return 1;
4261 return 0;
4262 }
4263
4264 /*.......................................................................
4265 * This is an action function which deletes all characters between the
4266 * current cursor position and the end of the line.
4267 */
KT_KEY_FN(gl_kill_line)4268 static KT_KEY_FN(gl_kill_line)
4269 {
4270 /*
4271 * If in vi command mode, preserve the current line for potential
4272 * use by vi-undo.
4273 */
4274 gl_save_for_undo(gl);
4275 /*
4276 * Copy the part of the line that is about to be deleted to the cut buffer.
4277 */
4278 strlcpy(gl->cutbuf, gl->line + gl->buff_curpos, gl->linelen);
4279 /*
4280 * Terminate the buffered line at the current cursor position.
4281 */
4282 gl_truncate_buffer(gl, gl->buff_curpos);
4283 /*
4284 * Clear the part of the line that follows the cursor.
4285 */
4286 if(gl_truncate_display(gl))
4287 return 1;
4288 /*
4289 * Explicitly reset the cursor position to allow vi command mode
4290 * constraints on its position to be set.
4291 */
4292 return gl_place_cursor(gl, gl->buff_curpos);
4293 }
4294
4295 /*.......................................................................
4296 * This is an action function which deletes all characters between the
4297 * start of the line and the current cursor position.
4298 */
KT_KEY_FN(gl_backward_kill_line)4299 static KT_KEY_FN(gl_backward_kill_line)
4300 {
4301 /*
4302 * How many characters are to be deleted from before the cursor?
4303 */
4304 int nc = gl->buff_curpos - gl->insert_curpos;
4305 if (!nc)
4306 return 0;
4307 /*
4308 * Move the cursor to the start of the line, or in vi input mode,
4309 * the start of the sub-line at which insertion started, and delete
4310 * up to the old cursor position.
4311 */
4312 return gl_place_cursor(gl, gl->insert_curpos) ||
4313 gl_delete_chars(gl, nc, gl->editor == GL_EMACS_MODE || gl->vi.command);
4314 }
4315
4316 /*.......................................................................
4317 * This is an action function which moves the cursor forward by a word.
4318 */
KT_KEY_FN(gl_forward_word)4319 static KT_KEY_FN(gl_forward_word)
4320 {
4321 return gl_place_cursor(gl, gl_nth_word_end_forward(gl, count) +
4322 (gl->editor==GL_EMACS_MODE));
4323 }
4324
4325 /*.......................................................................
4326 * This is an action function which moves the cursor forward to the start
4327 * of the next word.
4328 */
KT_KEY_FN(gl_forward_to_word)4329 static KT_KEY_FN(gl_forward_to_word)
4330 {
4331 return gl_place_cursor(gl, gl_nth_word_start_forward(gl, count));
4332 }
4333
4334 /*.......................................................................
4335 * This is an action function which moves the cursor backward by a word.
4336 */
KT_KEY_FN(gl_backward_word)4337 static KT_KEY_FN(gl_backward_word)
4338 {
4339 return gl_place_cursor(gl, gl_nth_word_start_backward(gl, count));
4340 }
4341
4342 /*.......................................................................
4343 * Delete one or more characters, starting with the one under the cursor.
4344 *
4345 * Input:
4346 * gl GetLine * The resource object of this library.
4347 * nc int The number of characters to delete.
4348 * cut int If true, copy the characters to the cut buffer.
4349 * Output:
4350 * return int 0 - OK.
4351 * 1 - Error.
4352 */
gl_delete_chars(GetLine * gl,int nc,int cut)4353 static int gl_delete_chars(GetLine *gl, int nc, int cut)
4354 {
4355 /*
4356 * If in vi command mode, preserve the current line for potential
4357 * use by vi-undo.
4358 */
4359 gl_save_for_undo(gl);
4360 /*
4361 * If there are fewer than nc characters following the cursor, limit
4362 * nc to the number available.
4363 */
4364 if(gl->buff_curpos + nc > gl->ntotal)
4365 nc = gl->ntotal - gl->buff_curpos;
4366 /*
4367 * Copy the about to be deleted region to the cut buffer.
4368 */
4369 if(cut) {
4370 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, nc);
4371 gl->cutbuf[nc] = '\0';
4372 }
4373 /*
4374 * Nothing to delete?
4375 */
4376 if(nc <= 0)
4377 return 0;
4378 /*
4379 * In vi overwrite mode, restore any previously overwritten characters
4380 * from the undo buffer.
4381 */
4382 if(gl->editor == GL_VI_MODE && !gl->vi.command && !gl->insert) {
4383 /*
4384 * How many of the characters being deleted can be restored from the
4385 * undo buffer?
4386 */
4387 int nrestore = gl->buff_curpos + nc <= gl->vi.undo.ntotal ?
4388 nc : gl->vi.undo.ntotal - gl->buff_curpos;
4389 /*
4390 * Restore any available characters.
4391 */
4392 if(nrestore > 0) {
4393 gl_buffer_string(gl, gl->vi.undo.line + gl->buff_curpos, nrestore,
4394 gl->buff_curpos);
4395 };
4396 /*
4397 * If their were insufficient characters in the undo buffer, then this
4398 * implies that we are deleting from the end of the line, so we need
4399 * to terminate the line either where the undo buffer ran out, or if
4400 * we are deleting from beyond the end of the undo buffer, at the current
4401 * cursor position.
4402 */
4403 if(nc != nrestore) {
4404 gl_truncate_buffer(gl, (gl->vi.undo.ntotal > gl->buff_curpos) ?
4405 gl->vi.undo.ntotal : gl->buff_curpos);
4406 };
4407 } else {
4408 /*
4409 * Copy the remaining part of the line back over the deleted characters.
4410 */
4411 gl_remove_from_buffer(gl, gl->buff_curpos, nc);
4412 };
4413 /*
4414 * Redraw the remaining characters following the cursor.
4415 */
4416 if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0'))
4417 return 1;
4418 /*
4419 * Clear to the end of the terminal.
4420 */
4421 if(gl_truncate_display(gl))
4422 return 1;
4423 /*
4424 * Place the cursor at the start of where the deletion was performed.
4425 */
4426 return gl_place_cursor(gl, gl->buff_curpos);
4427 }
4428
4429 /*.......................................................................
4430 * This is an action function which deletes character(s) under the
4431 * cursor without moving the cursor.
4432 */
KT_KEY_FN(gl_forward_delete_char)4433 static KT_KEY_FN(gl_forward_delete_char)
4434 {
4435 /*
4436 * Delete 'count' characters.
4437 */
4438 return gl_delete_chars(gl, count, gl->vi.command);
4439 }
4440
4441 /*.......................................................................
4442 * This is an action function which deletes character(s) under the
4443 * cursor and moves the cursor back one character.
4444 */
KT_KEY_FN(gl_backward_delete_char)4445 static KT_KEY_FN(gl_backward_delete_char)
4446 {
4447 /*
4448 * Restrict the deletion count to the number of characters that
4449 * precede the insertion point.
4450 */
4451 if(count > gl->buff_curpos - gl->insert_curpos)
4452 count = gl->buff_curpos - gl->insert_curpos;
4453 /*
4454 * If in vi command mode, preserve the current line for potential
4455 * use by vi-undo.
4456 */
4457 gl_save_for_undo(gl);
4458 return gl_cursor_left(gl, count, NULL) ||
4459 gl_delete_chars(gl, count, gl->vi.command);
4460 }
4461
4462 /*.......................................................................
4463 * Starting from the cursor position delete to the specified column.
4464 */
KT_KEY_FN(gl_delete_to_column)4465 static KT_KEY_FN(gl_delete_to_column)
4466 {
4467 if (--count >= gl->buff_curpos)
4468 return gl_forward_delete_char(gl, count - gl->buff_curpos, NULL);
4469 else
4470 return gl_backward_delete_char(gl, gl->buff_curpos - count, NULL);
4471 }
4472
4473 /*.......................................................................
4474 * Starting from the cursor position delete characters to a matching
4475 * parenthesis.
4476 */
KT_KEY_FN(gl_delete_to_parenthesis)4477 static KT_KEY_FN(gl_delete_to_parenthesis)
4478 {
4479 int curpos = gl_index_of_matching_paren(gl);
4480 if(curpos >= 0) {
4481 gl_save_for_undo(gl);
4482 if(curpos >= gl->buff_curpos)
4483 return gl_forward_delete_char(gl, curpos - gl->buff_curpos + 1, NULL);
4484 else
4485 return gl_backward_delete_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
4486 };
4487 return 0;
4488 }
4489
4490 /*.......................................................................
4491 * This is an action function which deletes from the cursor to the end
4492 * of the word that the cursor is either in or precedes.
4493 */
KT_KEY_FN(gl_forward_delete_word)4494 static KT_KEY_FN(gl_forward_delete_word)
4495 {
4496 /*
4497 * If in vi command mode, preserve the current line for potential
4498 * use by vi-undo.
4499 */
4500 gl_save_for_undo(gl);
4501 /*
4502 * In emacs mode delete to the end of the word. In vi mode delete to the
4503 * start of the net word.
4504 */
4505 if(gl->editor == GL_EMACS_MODE) {
4506 return gl_delete_chars(gl,
4507 gl_nth_word_end_forward(gl,count) - gl->buff_curpos + 1, 1);
4508 } else {
4509 return gl_delete_chars(gl,
4510 gl_nth_word_start_forward(gl,count) - gl->buff_curpos,
4511 gl->vi.command);
4512 };
4513 }
4514
4515 /*.......................................................................
4516 * This is an action function which deletes the word that precedes the
4517 * cursor.
4518 */
KT_KEY_FN(gl_backward_delete_word)4519 static KT_KEY_FN(gl_backward_delete_word)
4520 {
4521 /*
4522 * Keep a record of the current cursor position.
4523 */
4524 int buff_curpos = gl->buff_curpos;
4525 /*
4526 * If in vi command mode, preserve the current line for potential
4527 * use by vi-undo.
4528 */
4529 gl_save_for_undo(gl);
4530 /*
4531 * Move back 'count' words.
4532 */
4533 if(gl_backward_word(gl, count, NULL))
4534 return 1;
4535 /*
4536 * Delete from the new cursor position to the original one.
4537 */
4538 return gl_delete_chars(gl, buff_curpos - gl->buff_curpos,
4539 gl->editor == GL_EMACS_MODE || gl->vi.command);
4540 }
4541
4542 /*.......................................................................
4543 * Searching in a given direction, delete to the count'th
4544 * instance of a specified or queried character, in the input line.
4545 *
4546 * Input:
4547 * gl GetLine * The getline resource object.
4548 * count int The number of times to search.
4549 * c char The character to be searched for, or '\0' if
4550 * the character should be read from the user.
4551 * forward int True if searching forward.
4552 * onto int True if the search should end on top of the
4553 * character, false if the search should stop
4554 * one character before the character in the
4555 * specified search direction.
4556 * change int If true, this function is being called upon
4557 * to do a vi change command, in which case the
4558 * user will be left in insert mode after the
4559 * deletion.
4560 * Output:
4561 * return int 0 - OK.
4562 * 1 - Error.
4563 */
gl_delete_find(GetLine * gl,int count,char c,int forward,int onto,int change)4564 static int gl_delete_find(GetLine *gl, int count, char c, int forward,
4565 int onto, int change)
4566 {
4567 /*
4568 * Search for the character, and abort the deletion if not found.
4569 */
4570 int pos = gl_find_char(gl, count, forward, onto, c);
4571 if(pos < 0)
4572 return 0;
4573 /*
4574 * If in vi command mode, preserve the current line for potential
4575 * use by vi-undo.
4576 */
4577 gl_save_for_undo(gl);
4578 /*
4579 * Allow the cursor to be at the end of the line if this is a change
4580 * command.
4581 */
4582 if(change)
4583 gl->vi.command = 0;
4584 /*
4585 * Delete the appropriate span of characters.
4586 */
4587 if(forward) {
4588 if(gl_delete_chars(gl, pos - gl->buff_curpos + 1, 1))
4589 return 1;
4590 } else {
4591 int buff_curpos = gl->buff_curpos;
4592 if(gl_place_cursor(gl, pos) ||
4593 gl_delete_chars(gl, buff_curpos - gl->buff_curpos, 1))
4594 return 1;
4595 };
4596 /*
4597 * If this is a change operation, switch the insert mode.
4598 */
4599 if(change && gl_vi_insert(gl, 0, NULL))
4600 return 1;
4601 return 0;
4602 }
4603
4604 /*.......................................................................
4605 * This is an action function which deletes forward from the cursor up to and
4606 * including a specified character.
4607 */
KT_KEY_FN(gl_forward_delete_find)4608 static KT_KEY_FN(gl_forward_delete_find)
4609 {
4610 return gl_delete_find(gl, count, '\0', 1, 1, 0);
4611 }
4612
4613 /*.......................................................................
4614 * This is an action function which deletes backward from the cursor back to
4615 * and including a specified character.
4616 */
KT_KEY_FN(gl_backward_delete_find)4617 static KT_KEY_FN(gl_backward_delete_find)
4618 {
4619 return gl_delete_find(gl, count, '\0', 0, 1, 0);
4620 }
4621
4622 /*.......................................................................
4623 * This is an action function which deletes forward from the cursor up to but
4624 * not including a specified character.
4625 */
KT_KEY_FN(gl_forward_delete_to)4626 static KT_KEY_FN(gl_forward_delete_to)
4627 {
4628 return gl_delete_find(gl, count, '\0', 1, 0, 0);
4629 }
4630
4631 /*.......................................................................
4632 * This is an action function which deletes backward from the cursor back to
4633 * but not including a specified character.
4634 */
KT_KEY_FN(gl_backward_delete_to)4635 static KT_KEY_FN(gl_backward_delete_to)
4636 {
4637 return gl_delete_find(gl, count, '\0', 0, 0, 0);
4638 }
4639
4640 /*.......................................................................
4641 * This is an action function which deletes to a character specified by a
4642 * previous search.
4643 */
KT_KEY_FN(gl_delete_refind)4644 static KT_KEY_FN(gl_delete_refind)
4645 {
4646 return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
4647 gl->vi.find_onto, 0);
4648 }
4649
4650 /*.......................................................................
4651 * This is an action function which deletes to a character specified by a
4652 * previous search, but in the opposite direction.
4653 */
KT_KEY_FN(gl_delete_invert_refind)4654 static KT_KEY_FN(gl_delete_invert_refind)
4655 {
4656 return gl_delete_find(gl, count, gl->vi.find_char,
4657 !gl->vi.find_forward, gl->vi.find_onto, 0);
4658 }
4659
4660 /*.......................................................................
4661 * This is an action function which converts the characters in the word
4662 * following the cursor to upper case.
4663 */
KT_KEY_FN(gl_upcase_word)4664 static KT_KEY_FN(gl_upcase_word)
4665 {
4666 /*
4667 * Locate the count'th word ending after the cursor.
4668 */
4669 int last = gl_nth_word_end_forward(gl, count);
4670 /*
4671 * If in vi command mode, preserve the current line for potential
4672 * use by vi-undo.
4673 */
4674 gl_save_for_undo(gl);
4675 /*
4676 * Upcase characters from the current cursor position to 'last'.
4677 */
4678 while(gl->buff_curpos <= last) {
4679 char *cptr = gl->line + gl->buff_curpos;
4680 /*
4681 * Convert the character to upper case?
4682 */
4683 if(islower((int)(unsigned char) *cptr))
4684 gl_buffer_char(gl, toupper((int) *cptr), gl->buff_curpos);
4685 gl->buff_curpos++;
4686 /*
4687 * Write the possibly modified character back. Note that for non-modified
4688 * characters we want to do this as well, so as to advance the cursor.
4689 */
4690 if(gl_print_char(gl, *cptr, cptr[1]))
4691 return 1;
4692 };
4693 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4694 }
4695
4696 /*.......................................................................
4697 * This is an action function which converts the characters in the word
4698 * following the cursor to lower case.
4699 */
KT_KEY_FN(gl_downcase_word)4700 static KT_KEY_FN(gl_downcase_word)
4701 {
4702 /*
4703 * Locate the count'th word ending after the cursor.
4704 */
4705 int last = gl_nth_word_end_forward(gl, count);
4706 /*
4707 * If in vi command mode, preserve the current line for potential
4708 * use by vi-undo.
4709 */
4710 gl_save_for_undo(gl);
4711 /*
4712 * Upcase characters from the current cursor position to 'last'.
4713 */
4714 while(gl->buff_curpos <= last) {
4715 char *cptr = gl->line + gl->buff_curpos;
4716 /*
4717 * Convert the character to upper case?
4718 */
4719 if(isupper((int)(unsigned char) *cptr))
4720 gl_buffer_char(gl, tolower((int) *cptr), gl->buff_curpos);
4721 gl->buff_curpos++;
4722 /*
4723 * Write the possibly modified character back. Note that for non-modified
4724 * characters we want to do this as well, so as to advance the cursor.
4725 */
4726 if(gl_print_char(gl, *cptr, cptr[1]))
4727 return 1;
4728 };
4729 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4730 }
4731
4732 /*.......................................................................
4733 * This is an action function which converts the first character of the
4734 * following word to upper case, in order to capitalize the word, and
4735 * leaves the cursor at the end of the word.
4736 */
KT_KEY_FN(gl_capitalize_word)4737 static KT_KEY_FN(gl_capitalize_word)
4738 {
4739 char *cptr; /* &gl->line[gl->buff_curpos] */
4740 int first; /* True for the first letter of the word */
4741 int i;
4742 /*
4743 * Keep a record of the current insert mode and the cursor position.
4744 */
4745 int insert = gl->insert;
4746 /*
4747 * If in vi command mode, preserve the current line for potential
4748 * use by vi-undo.
4749 */
4750 gl_save_for_undo(gl);
4751 /*
4752 * We want to overwrite the modified word.
4753 */
4754 gl->insert = 0;
4755 /*
4756 * Capitalize 'count' words.
4757 */
4758 for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) {
4759 int pos = gl->buff_curpos;
4760 /*
4761 * If we are not already within a word, skip to the start of the word.
4762 */
4763 for(cptr = gl->line + pos ; pos<gl->ntotal && !gl_is_word_char((int) *cptr);
4764 pos++, cptr++)
4765 ;
4766 /*
4767 * Move the cursor to the new position.
4768 */
4769 if(gl_place_cursor(gl, pos))
4770 return 1;
4771 /*
4772 * While searching for the end of the word, change lower case letters
4773 * to upper case.
4774 */
4775 for(first=1; gl->buff_curpos<gl->ntotal && gl_is_word_char((int) *cptr);
4776 gl->buff_curpos++, cptr++) {
4777 /*
4778 * Convert the character to upper case?
4779 */
4780 if(first) {
4781 if(islower((int)(unsigned char) *cptr))
4782 gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
4783 } else {
4784 if(isupper((int)(unsigned char) *cptr))
4785 gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
4786 };
4787 first = 0;
4788 /*
4789 * Write the possibly modified character back. Note that for non-modified
4790 * characters we want to do this as well, so as to advance the cursor.
4791 */
4792 if(gl_print_char(gl, *cptr, cptr[1]))
4793 return 1;
4794 };
4795 };
4796 /*
4797 * Restore the insertion mode.
4798 */
4799 gl->insert = insert;
4800 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4801 }
4802
4803 /*.......................................................................
4804 * This is an action function which redraws the current line.
4805 */
KT_KEY_FN(gl_redisplay)4806 static KT_KEY_FN(gl_redisplay)
4807 {
4808 /*
4809 * Keep a record of the current cursor position.
4810 */
4811 int buff_curpos = gl->buff_curpos;
4812 /*
4813 * Do nothing if there is no line to be redisplayed.
4814 */
4815 if(gl->endline)
4816 return 0;
4817 /*
4818 * Erase the current input line.
4819 */
4820 if(gl_erase_line(gl))
4821 return 1;
4822 /*
4823 * Display the current prompt.
4824 */
4825 if(gl_display_prompt(gl))
4826 return 1;
4827 /*
4828 * Render the part of the line that the user has typed in so far.
4829 */
4830 if(gl_print_string(gl, gl->line, '\0'))
4831 return 1;
4832 /*
4833 * Restore the cursor position.
4834 */
4835 if(gl_place_cursor(gl, buff_curpos))
4836 return 1;
4837 /*
4838 * Mark the redisplay operation as having been completed.
4839 */
4840 gl->redisplay = 0;
4841 /*
4842 * Flush the redisplayed line to the terminal.
4843 */
4844 return gl_flush_output(gl);
4845 }
4846
4847 /*.......................................................................
4848 * This is an action function which clears the display and redraws the
4849 * input line from the home position.
4850 */
KT_KEY_FN(gl_clear_screen)4851 static KT_KEY_FN(gl_clear_screen)
4852 {
4853 /*
4854 * Home the cursor and clear from there to the end of the display.
4855 */
4856 if(gl_print_control_sequence(gl, gl->nline, gl->home) ||
4857 gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
4858 return 1;
4859 /*
4860 * The input line is no longer displayed.
4861 */
4862 gl_line_erased(gl);
4863 /*
4864 * Arrange for the input line to be redisplayed.
4865 */
4866 gl_queue_redisplay(gl);
4867 return 0;
4868 }
4869
4870 /*.......................................................................
4871 * This is an action function which swaps the character under the cursor
4872 * with the character to the left of the cursor.
4873 */
KT_KEY_FN(gl_transpose_chars)4874 static KT_KEY_FN(gl_transpose_chars)
4875 {
4876 char from[3]; /* The original string of 2 characters */
4877 char swap[3]; /* The swapped string of two characters */
4878 /*
4879 * If we are at the beginning or end of the line, there aren't two
4880 * characters to swap.
4881 */
4882 if(gl->buff_curpos < 1 || gl->buff_curpos >= gl->ntotal)
4883 return 0;
4884 /*
4885 * If in vi command mode, preserve the current line for potential
4886 * use by vi-undo.
4887 */
4888 gl_save_for_undo(gl);
4889 /*
4890 * Get the original and swapped strings of the two characters.
4891 */
4892 from[0] = gl->line[gl->buff_curpos - 1];
4893 from[1] = gl->line[gl->buff_curpos];
4894 from[2] = '\0';
4895 swap[0] = gl->line[gl->buff_curpos];
4896 swap[1] = gl->line[gl->buff_curpos - 1];
4897 swap[2] = '\0';
4898 /*
4899 * Move the cursor to the start of the two characters.
4900 */
4901 if(gl_place_cursor(gl, gl->buff_curpos-1))
4902 return 1;
4903 /*
4904 * Swap the two characters in the buffer.
4905 */
4906 gl_buffer_char(gl, swap[0], gl->buff_curpos);
4907 gl_buffer_char(gl, swap[1], gl->buff_curpos+1);
4908 /*
4909 * If the sum of the displayed width of the two characters
4910 * in their current and final positions is the same, swapping can
4911 * be done by just overwriting with the two swapped characters.
4912 */
4913 if(gl_displayed_string_width(gl, from, -1, gl->term_curpos) ==
4914 gl_displayed_string_width(gl, swap, -1, gl->term_curpos)) {
4915 int insert = gl->insert;
4916 gl->insert = 0;
4917 if(gl_print_char(gl, swap[0], swap[1]) ||
4918 gl_print_char(gl, swap[1], gl->line[gl->buff_curpos+2]))
4919 return 1;
4920 gl->insert = insert;
4921 /*
4922 * If the swapped substring has a different displayed size, we need to
4923 * redraw everything after the first of the characters.
4924 */
4925 } else {
4926 if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0') ||
4927 gl_truncate_display(gl))
4928 return 1;
4929 };
4930 /*
4931 * Advance the cursor to the character after the swapped pair.
4932 */
4933 return gl_place_cursor(gl, gl->buff_curpos + 2);
4934 }
4935
4936 /*.......................................................................
4937 * This is an action function which sets a mark at the current cursor
4938 * location.
4939 */
KT_KEY_FN(gl_set_mark)4940 static KT_KEY_FN(gl_set_mark)
4941 {
4942 gl->buff_mark = gl->buff_curpos;
4943 return 0;
4944 }
4945
4946 /*.......................................................................
4947 * This is an action function which swaps the mark location for the
4948 * cursor location.
4949 */
KT_KEY_FN(gl_exchange_point_and_mark)4950 static KT_KEY_FN(gl_exchange_point_and_mark)
4951 {
4952 /*
4953 * Get the old mark position, and limit to the extent of the input
4954 * line.
4955 */
4956 int old_mark = gl->buff_mark <= gl->ntotal ? gl->buff_mark : gl->ntotal;
4957 /*
4958 * Make the current cursor position the new mark.
4959 */
4960 gl->buff_mark = gl->buff_curpos;
4961 /*
4962 * Move the cursor to the old mark position.
4963 */
4964 return gl_place_cursor(gl, old_mark);
4965 }
4966
4967 /*.......................................................................
4968 * This is an action function which deletes the characters between the
4969 * mark and the cursor, recording them in gl->cutbuf for later pasting.
4970 */
KT_KEY_FN(gl_kill_region)4971 static KT_KEY_FN(gl_kill_region)
4972 {
4973 /*
4974 * If in vi command mode, preserve the current line for potential
4975 * use by vi-undo.
4976 */
4977 gl_save_for_undo(gl);
4978 /*
4979 * Limit the mark to be within the line.
4980 */
4981 if(gl->buff_mark > gl->ntotal)
4982 gl->buff_mark = gl->ntotal;
4983 /*
4984 * If there are no characters between the cursor and the mark, simply clear
4985 * the cut buffer.
4986 */
4987 if(gl->buff_mark == gl->buff_curpos) {
4988 gl->cutbuf[0] = '\0';
4989 return 0;
4990 };
4991 /*
4992 * If the mark is before the cursor, swap the cursor and the mark.
4993 */
4994 if(gl->buff_mark < gl->buff_curpos && gl_exchange_point_and_mark(gl,1,NULL))
4995 return 1;
4996 /*
4997 * Delete the characters.
4998 */
4999 if(gl_delete_chars(gl, gl->buff_mark - gl->buff_curpos, 1))
5000 return 1;
5001 /*
5002 * Make the mark the same as the cursor position.
5003 */
5004 gl->buff_mark = gl->buff_curpos;
5005 return 0;
5006 }
5007
5008 /*.......................................................................
5009 * This is an action function which records the characters between the
5010 * mark and the cursor, in gl->cutbuf for later pasting.
5011 */
KT_KEY_FN(gl_copy_region_as_kill)5012 static KT_KEY_FN(gl_copy_region_as_kill)
5013 {
5014 int ca, cb; /* The indexes of the first and last characters in the region */
5015 int mark; /* The position of the mark */
5016 /*
5017 * Get the position of the mark, limiting it to lie within the line.
5018 */
5019 mark = gl->buff_mark > gl->ntotal ? gl->ntotal : gl->buff_mark;
5020 /*
5021 * If there are no characters between the cursor and the mark, clear
5022 * the cut buffer.
5023 */
5024 if(mark == gl->buff_curpos) {
5025 gl->cutbuf[0] = '\0';
5026 return 0;
5027 };
5028 /*
5029 * Get the line indexes of the first and last characters in the region.
5030 */
5031 if(mark < gl->buff_curpos) {
5032 ca = mark;
5033 cb = gl->buff_curpos - 1;
5034 } else {
5035 ca = gl->buff_curpos;
5036 cb = mark - 1;
5037 };
5038 /*
5039 * Copy the region to the cut buffer.
5040 */
5041 memcpy(gl->cutbuf, gl->line + ca, cb + 1 - ca);
5042 gl->cutbuf[cb + 1 - ca] = '\0';
5043 return 0;
5044 }
5045
5046 /*.......................................................................
5047 * This is an action function which inserts the contents of the cut
5048 * buffer at the current cursor location.
5049 */
KT_KEY_FN(gl_yank)5050 static KT_KEY_FN(gl_yank)
5051 {
5052 int i;
5053 /*
5054 * Set the mark at the current location.
5055 */
5056 gl->buff_mark = gl->buff_curpos;
5057 /*
5058 * Do nothing else if the cut buffer is empty.
5059 */
5060 if(gl->cutbuf[0] == '\0')
5061 return gl_ring_bell(gl, 1, NULL);
5062 /*
5063 * If in vi command mode, preserve the current line for potential
5064 * use by vi-undo.
5065 */
5066 gl_save_for_undo(gl);
5067 /*
5068 * Insert the string count times.
5069 */
5070 for(i=0; i<count; i++) {
5071 if(gl_add_string_to_line(gl, gl->cutbuf))
5072 return 1;
5073 };
5074 /*
5075 * gl_add_string_to_line() leaves the cursor after the last character that
5076 * was pasted, whereas vi leaves the cursor over the last character pasted.
5077 */
5078 if(gl->editor == GL_VI_MODE && gl_cursor_left(gl, 1, NULL))
5079 return 1;
5080 return 0;
5081 }
5082
5083 /*.......................................................................
5084 * This is an action function which inserts the contents of the cut
5085 * buffer one character beyond the current cursor location.
5086 */
KT_KEY_FN(gl_append_yank)5087 static KT_KEY_FN(gl_append_yank)
5088 {
5089 int was_command = gl->vi.command;
5090 int i;
5091 /*
5092 * If the cut buffer is empty, ring the terminal bell.
5093 */
5094 if(gl->cutbuf[0] == '\0')
5095 return gl_ring_bell(gl, 1, NULL);
5096 /*
5097 * Set the mark at the current location + 1.
5098 */
5099 gl->buff_mark = gl->buff_curpos + 1;
5100 /*
5101 * If in vi command mode, preserve the current line for potential
5102 * use by vi-undo.
5103 */
5104 gl_save_for_undo(gl);
5105 /*
5106 * Arrange to paste the text in insert mode after the current character.
5107 */
5108 if(gl_vi_append(gl, 0, NULL))
5109 return 1;
5110 /*
5111 * Insert the string count times.
5112 */
5113 for(i=0; i<count; i++) {
5114 if(gl_add_string_to_line(gl, gl->cutbuf))
5115 return 1;
5116 };
5117 /*
5118 * Switch back to command mode if necessary.
5119 */
5120 if(was_command)
5121 gl_vi_command_mode(gl);
5122 return 0;
5123 }
5124
5125 /*.......................................................................
5126 * Attempt to ask the terminal for its current size. On systems that
5127 * don't support the TIOCWINSZ ioctl() for querying the terminal size,
5128 * the current values of gl->ncolumn and gl->nrow are returned.
5129 *
5130 * Input:
5131 * gl GetLine * The resource object of gl_get_line().
5132 * Input/Output:
5133 * ncolumn int * The number of columns will be assigned to *ncolumn.
5134 * nline int * The number of lines will be assigned to *nline.
5135 */
gl_query_size(GetLine * gl,int * ncolumn,int * nline)5136 static void gl_query_size(GetLine *gl, int *ncolumn, int *nline)
5137 {
5138 #ifdef TIOCGWINSZ
5139 /*
5140 * Query the new terminal window size. Ignore invalid responses.
5141 */
5142 struct winsize size;
5143 if(ioctl(gl->output_fd, TIOCGWINSZ, &size) == 0 &&
5144 size.ws_row > 0 && size.ws_col > 0) {
5145 *ncolumn = size.ws_col;
5146 *nline = size.ws_row;
5147 return;
5148 };
5149 #endif
5150 /*
5151 * Return the existing values.
5152 */
5153 *ncolumn = gl->ncolumn;
5154 *nline = gl->nline;
5155 return;
5156 }
5157
5158 /*.......................................................................
5159 * Query the size of the terminal, and if it has changed, redraw the
5160 * current input line accordingly.
5161 *
5162 * Input:
5163 * gl GetLine * The resource object of gl_get_line().
5164 * Output:
5165 * return int 0 - OK.
5166 * 1 - Error.
5167 */
_gl_update_size(GetLine * gl)5168 static int _gl_update_size(GetLine *gl)
5169 {
5170 int ncolumn, nline; /* The new size of the terminal */
5171 /*
5172 * Query the new terminal window size.
5173 */
5174 gl_query_size(gl, &ncolumn, &nline);
5175 /*
5176 * Update gl and the displayed line to fit the new dimensions.
5177 */
5178 return gl_handle_tty_resize(gl, ncolumn, nline);
5179 }
5180
5181 /*.......................................................................
5182 * Redraw the current input line to account for a change in the terminal
5183 * size. Also install the new size in gl.
5184 *
5185 * Input:
5186 * gl GetLine * The resource object of gl_get_line().
5187 * ncolumn int The new number of columns.
5188 * nline int The new number of lines.
5189 * Output:
5190 * return int 0 - OK.
5191 * 1 - Error.
5192 */
gl_handle_tty_resize(GetLine * gl,int ncolumn,int nline)5193 static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline)
5194 {
5195 /*
5196 * If the input device isn't a terminal, just record the new size.
5197 */
5198 if(!gl->is_term) {
5199 gl->nline = nline;
5200 gl->ncolumn = ncolumn;
5201 /*
5202 * Has the size actually changed?
5203 */
5204 } else if(ncolumn != gl->ncolumn || nline != gl->nline) {
5205 /*
5206 * If we are currently editing a line, erase it.
5207 */
5208 if(gl_erase_line(gl))
5209 return 1;
5210 /*
5211 * Update the recorded window size.
5212 */
5213 gl->nline = nline;
5214 gl->ncolumn = ncolumn;
5215 /*
5216 * Arrange for the input line to be redrawn before the next character
5217 * is read from the terminal.
5218 */
5219 gl_queue_redisplay(gl);
5220 };
5221 return 0;
5222 }
5223
5224 /*.......................................................................
5225 * This is the action function that recalls the previous line in the
5226 * history buffer.
5227 */
KT_KEY_FN(gl_up_history)5228 static KT_KEY_FN(gl_up_history)
5229 {
5230 /*
5231 * In vi mode, switch to command mode, since the user is very
5232 * likely to want to move around newly recalled lines.
5233 */
5234 gl_vi_command_mode(gl);
5235 /*
5236 * Forget any previous recall session.
5237 */
5238 gl->preload_id = 0;
5239 /*
5240 * Record the key sequence number of this search action.
5241 */
5242 gl->last_search = gl->keyseq_count;
5243 /*
5244 * We don't want a search prefix for this function.
5245 */
5246 if(_glh_search_prefix(gl->glh, gl->line, 0)) {
5247 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5248 return 1;
5249 };
5250 /*
5251 * Recall the count'th next older line in the history list. If the first one
5252 * fails we can return since nothing has changed, otherwise we must continue
5253 * and update the line state.
5254 */
5255 if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5256 return 0;
5257 while(--count && _glh_find_backwards(gl->glh, gl->line, gl->linelen+1))
5258 ;
5259 /*
5260 * Accomodate the new contents of gl->line[].
5261 */
5262 gl_update_buffer(gl);
5263 /*
5264 * Arrange to have the cursor placed at the end of the new line.
5265 */
5266 gl->buff_curpos = gl->ntotal;
5267 /*
5268 * Erase and display the new line.
5269 */
5270 gl_queue_redisplay(gl);
5271 return 0;
5272 }
5273
5274 /*.......................................................................
5275 * This is the action function that recalls the next line in the
5276 * history buffer.
5277 */
KT_KEY_FN(gl_down_history)5278 static KT_KEY_FN(gl_down_history)
5279 {
5280 /*
5281 * In vi mode, switch to command mode, since the user is very
5282 * likely to want to move around newly recalled lines.
5283 */
5284 gl_vi_command_mode(gl);
5285 /*
5286 * Record the key sequence number of this search action.
5287 */
5288 gl->last_search = gl->keyseq_count;
5289 /*
5290 * If no search is currently in progress continue a previous recall
5291 * session from a previous entered line if possible.
5292 */
5293 if(_glh_line_id(gl->glh, 0) == 0 && gl->preload_id) {
5294 _glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1);
5295 gl->preload_id = 0;
5296 } else {
5297 /*
5298 * We don't want a search prefix for this function.
5299 */
5300 if(_glh_search_prefix(gl->glh, gl->line, 0)) {
5301 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5302 return 1;
5303 };
5304 /*
5305 * Recall the count'th next newer line in the history list. If the first one
5306 * fails we can return since nothing has changed otherwise we must continue
5307 * and update the line state.
5308 */
5309 if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5310 return 0;
5311 while(--count && _glh_find_forwards(gl->glh, gl->line, gl->linelen+1))
5312 ;
5313 };
5314 /*
5315 * Accomodate the new contents of gl->line[].
5316 */
5317 gl_update_buffer(gl);
5318 /*
5319 * Arrange to have the cursor placed at the end of the new line.
5320 */
5321 gl->buff_curpos = gl->ntotal;
5322 /*
5323 * Erase and display the new line.
5324 */
5325 gl_queue_redisplay(gl);
5326 return 0;
5327 }
5328
5329 /*.......................................................................
5330 * This is the action function that recalls the previous line in the
5331 * history buffer whos prefix matches the characters that currently
5332 * precede the cursor. By setting count=-1, this can be used internally
5333 * to force searching for the prefix used in the last search.
5334 */
KT_KEY_FN(gl_history_search_backward)5335 static KT_KEY_FN(gl_history_search_backward)
5336 {
5337 /*
5338 * In vi mode, switch to command mode, since the user is very
5339 * likely to want to move around newly recalled lines.
5340 */
5341 gl_vi_command_mode(gl);
5342 /*
5343 * Forget any previous recall session.
5344 */
5345 gl->preload_id = 0;
5346 /*
5347 * Record the key sequence number of this search action.
5348 */
5349 gl->last_search = gl->keyseq_count;
5350 /*
5351 * If a prefix search isn't already in progress, replace the search
5352 * prefix to the string that precedes the cursor. In vi command mode
5353 * include the character that is under the cursor in the string. If
5354 * count<0 keep the previous search prefix regardless, so as to force
5355 * a repeat search even if the last command wasn't a history command.
5356 */
5357 if(count >= 0 && !_glh_search_active(gl->glh) &&
5358 _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
5359 (gl->editor==GL_VI_MODE && gl->ntotal>0))) {
5360 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5361 return 1;
5362 };
5363 /*
5364 * Search backwards for a match to the part of the line which precedes the
5365 * cursor.
5366 */
5367 if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5368 return 0;
5369 /*
5370 * Accomodate the new contents of gl->line[].
5371 */
5372 gl_update_buffer(gl);
5373 /*
5374 * Arrange to have the cursor placed at the end of the new line.
5375 */
5376 gl->buff_curpos = gl->ntotal;
5377 /*
5378 * Erase and display the new line.
5379 */
5380 gl_queue_redisplay(gl);
5381 return 0;
5382 }
5383
5384 /*.......................................................................
5385 * This is the action function that recalls the previous line in the
5386 * history buffer who's prefix matches that specified in an earlier call
5387 * to gl_history_search_backward() or gl_history_search_forward().
5388 */
KT_KEY_FN(gl_history_re_search_backward)5389 static KT_KEY_FN(gl_history_re_search_backward)
5390 {
5391 return gl_history_search_backward(gl, -1, NULL);
5392 }
5393
5394 /*.......................................................................
5395 * This is the action function that recalls the next line in the
5396 * history buffer who's prefix matches that specified in the earlier call
5397 * to gl_history_search_backward) which started the history search.
5398 * By setting count=-1, this can be used internally to force searching
5399 * for the prefix used in the last search.
5400 */
KT_KEY_FN(gl_history_search_forward)5401 static KT_KEY_FN(gl_history_search_forward)
5402 {
5403 /*
5404 * In vi mode, switch to command mode, since the user is very
5405 * likely to want to move around newly recalled lines.
5406 */
5407 gl_vi_command_mode(gl);
5408 /*
5409 * Record the key sequence number of this search action.
5410 */
5411 gl->last_search = gl->keyseq_count;
5412 /*
5413 * If a prefix search isn't already in progress, replace the search
5414 * prefix to the string that precedes the cursor. In vi command mode
5415 * include the character that is under the cursor in the string. If
5416 * count<0 keep the previous search prefix regardless, so as to force
5417 * a repeat search even if the last command wasn't a history command.
5418 */
5419 if(count >= 0 && !_glh_search_active(gl->glh) &&
5420 _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
5421 (gl->editor==GL_VI_MODE && gl->ntotal>0))) {
5422 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5423 return 1;
5424 };
5425 /*
5426 * Search forwards for the next matching line.
5427 */
5428 if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5429 return 0;
5430 /*
5431 * Accomodate the new contents of gl->line[].
5432 */
5433 gl_update_buffer(gl);
5434 /*
5435 * Arrange for the cursor to be placed at the end of the new line.
5436 */
5437 gl->buff_curpos = gl->ntotal;
5438 /*
5439 * Erase and display the new line.
5440 */
5441 gl_queue_redisplay(gl);
5442 return 0;
5443 }
5444
5445 /*.......................................................................
5446 * This is the action function that recalls the next line in the
5447 * history buffer who's prefix matches that specified in an earlier call
5448 * to gl_history_search_backward() or gl_history_search_forward().
5449 */
KT_KEY_FN(gl_history_re_search_forward)5450 static KT_KEY_FN(gl_history_re_search_forward)
5451 {
5452 return gl_history_search_forward(gl, -1, NULL);
5453 }
5454
5455 #ifdef HIDE_FILE_SYSTEM
5456 /*.......................................................................
5457 * The following function is used as the default completion handler when
5458 * the filesystem is to be hidden. It simply reports no completions.
5459 */
CPL_MATCH_FN(gl_no_completions)5460 static CPL_MATCH_FN(gl_no_completions)
5461 {
5462 return 0;
5463 }
5464 #endif
5465
5466 /*.......................................................................
5467 * This is the tab completion function that completes the filename that
5468 * precedes the cursor position. Its callback data argument must be a
5469 * pointer to a GlCplCallback containing the completion callback function
5470 * and its callback data, or NULL to use the builtin filename completer.
5471 */
KT_KEY_FN(gl_complete_word)5472 static KT_KEY_FN(gl_complete_word)
5473 {
5474 CplMatches *matches; /* The possible completions */
5475 int suffix_len; /* The length of the completion extension */
5476 int cont_len; /* The length of any continuation suffix */
5477 int nextra; /* The number of characters being added to the */
5478 /* total length of the line. */
5479 int buff_pos; /* The buffer index at which the completion is */
5480 /* to be inserted. */
5481 int waserr = 0; /* True after errors */
5482 /*
5483 * Get the container of the completion callback and its callback data.
5484 */
5485 GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
5486 /*
5487 * In vi command mode, switch to append mode so that the character under
5488 * the cursor is included in the completion (otherwise people can't
5489 * complete at the end of the line).
5490 */
5491 if(gl->vi.command && gl_vi_append(gl, 0, NULL))
5492 return 1;
5493 /*
5494 * Get the cursor position at which the completion is to be inserted.
5495 */
5496 buff_pos = gl->buff_curpos;
5497 /*
5498 * Perform the completion.
5499 */
5500 matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos, cb->data,
5501 cb->fn);
5502 /*
5503 * No matching completions?
5504 */
5505 if(!matches) {
5506 waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
5507 /*
5508 * Are there any completions?
5509 */
5510 } else if(matches->nmatch >= 1) {
5511 /*
5512 * If there any ambiguous matches, report them, starting on a new line.
5513 */
5514 if(matches->nmatch > 1 && gl->echo) {
5515 if(_gl_normal_io(gl) ||
5516 _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
5517 waserr = 1;
5518 };
5519 /*
5520 * Get the length of the suffix and any continuation suffix to add to it.
5521 */
5522 suffix_len = strlen(matches->suffix);
5523 cont_len = strlen(matches->cont_suffix);
5524 /*
5525 * If there is an unambiguous match, and the continuation suffix ends in
5526 * a newline, strip that newline and arrange to have getline return
5527 * after this action function returns.
5528 */
5529 if(matches->nmatch==1 && cont_len > 0 &&
5530 matches->cont_suffix[cont_len - 1] == '\n') {
5531 cont_len--;
5532 if(gl_newline(gl, 1, NULL))
5533 waserr = 1;
5534 };
5535 /*
5536 * Work out the number of characters that are to be added.
5537 */
5538 nextra = suffix_len + cont_len;
5539 /*
5540 * Is there anything to be added?
5541 */
5542 if(!waserr && nextra) {
5543 /*
5544 * Will there be space for the expansion in the line buffer?
5545 */
5546 if(gl->ntotal + nextra < gl->linelen) {
5547 /*
5548 * Make room to insert the filename extension.
5549 */
5550 gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
5551 /*
5552 * Insert the filename extension.
5553 */
5554 gl_buffer_string(gl, matches->suffix, suffix_len, gl->buff_curpos);
5555 /*
5556 * Add the terminating characters.
5557 */
5558 gl_buffer_string(gl, matches->cont_suffix, cont_len,
5559 gl->buff_curpos + suffix_len);
5560 /*
5561 * Place the cursor position at the end of the completion.
5562 */
5563 gl->buff_curpos += nextra;
5564 /*
5565 * If we don't have to redisplay the whole line, redisplay the part
5566 * of the line which follows the original cursor position, and place
5567 * the cursor at the end of the completion.
5568 */
5569 if(gl->displayed) {
5570 if(gl_truncate_display(gl) ||
5571 gl_print_string(gl, gl->line + buff_pos, '\0') ||
5572 gl_place_cursor(gl, gl->buff_curpos))
5573 waserr = 1;
5574 };
5575 } else {
5576 (void) gl_print_info(gl,
5577 "Insufficient room in line for file completion.",
5578 GL_END_INFO);
5579 waserr = 1;
5580 };
5581 };
5582 };
5583 /*
5584 * If any output had to be written to the terminal, then editing will
5585 * have been suspended, make sure that we are back in raw line editing
5586 * mode before returning.
5587 */
5588 if(_gl_raw_io(gl, 1))
5589 waserr = 1;
5590 return 0;
5591 }
5592
5593 #ifndef HIDE_FILE_SYSTEM
5594 /*.......................................................................
5595 * This is the function that expands the filename that precedes the
5596 * cursor position. It expands ~user/ expressions, $envvar expressions,
5597 * and wildcards.
5598 */
KT_KEY_FN(gl_expand_filename)5599 static KT_KEY_FN(gl_expand_filename)
5600 {
5601 char *start_path; /* The pointer to the start of the pathname in */
5602 /* gl->line[]. */
5603 FileExpansion *result; /* The results of the filename expansion */
5604 int pathlen; /* The length of the pathname being expanded */
5605 int length; /* The number of characters needed to display the */
5606 /* expanded files. */
5607 int nextra; /* The number of characters to be added */
5608 int i,j;
5609 /*
5610 * In vi command mode, switch to append mode so that the character under
5611 * the cursor is included in the completion (otherwise people can't
5612 * complete at the end of the line).
5613 */
5614 if(gl->vi.command && gl_vi_append(gl, 0, NULL))
5615 return 1;
5616 /*
5617 * Locate the start of the filename that precedes the cursor position.
5618 */
5619 start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
5620 if(!start_path)
5621 return 1;
5622 /*
5623 * Get the length of the string that is to be expanded.
5624 */
5625 pathlen = gl->buff_curpos - (start_path - gl->line);
5626 /*
5627 * Attempt to expand it.
5628 */
5629 result = ef_expand_file(gl->ef, start_path, pathlen);
5630 /*
5631 * If there was an error, report the error on a new line.
5632 */
5633 if(!result)
5634 return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
5635 /*
5636 * If no files matched, report this as well.
5637 */
5638 if(result->nfile == 0 || !result->exists)
5639 return gl_print_info(gl, "No files match.", GL_END_INFO);
5640 /*
5641 * If in vi command mode, preserve the current line for potential use by
5642 * vi-undo.
5643 */
5644 gl_save_for_undo(gl);
5645 /*
5646 * Work out how much space we will need to display all of the matching
5647 * filenames, taking account of the space that we need to place between
5648 * them, and the number of additional '\' characters needed to escape
5649 * spaces, tabs and backslash characters in the individual filenames.
5650 */
5651 length = 0;
5652 for(i=0; i<result->nfile; i++) {
5653 char *file = result->files[i];
5654 while(*file) {
5655 int c = *file++;
5656 switch(c) {
5657 case ' ': case '\t': case '\\': case '*': case '?': case '[':
5658 length++; /* Count extra backslash characters */
5659 };
5660 length++; /* Count the character itself */
5661 };
5662 length++; /* Count the space that follows each filename */
5663 };
5664 /*
5665 * Work out the number of characters that are to be added.
5666 */
5667 nextra = length - pathlen;
5668 /*
5669 * Will there be space for the expansion in the line buffer?
5670 */
5671 if(gl->ntotal + nextra >= gl->linelen) {
5672 return gl_print_info(gl, "Insufficient room in line for file expansion.",
5673 GL_END_INFO);
5674 } else {
5675 /*
5676 * Do we need to move the part of the line that followed the unexpanded
5677 * filename?
5678 */
5679 if(nextra > 0) {
5680 gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
5681 } else if(nextra < 0) {
5682 gl->buff_curpos += nextra;
5683 gl_remove_from_buffer(gl, gl->buff_curpos, -nextra);
5684 };
5685 /*
5686 * Insert the filenames, separated by spaces, and with internal spaces,
5687 * tabs and backslashes escaped with backslashes.
5688 */
5689 for(i=0,j=start_path - gl->line; i<result->nfile; i++) {
5690 char *file = result->files[i];
5691 while(*file) {
5692 int c = *file++;
5693 switch(c) {
5694 case ' ': case '\t': case '\\': case '*': case '?': case '[':
5695 gl_buffer_char(gl, '\\', j++);
5696 };
5697 gl_buffer_char(gl, c, j++);
5698 };
5699 gl_buffer_char(gl, ' ', j++);
5700 };
5701 };
5702 /*
5703 * Redisplay the part of the line which follows the start of
5704 * the original filename.
5705 */
5706 if(gl_place_cursor(gl, start_path - gl->line) ||
5707 gl_truncate_display(gl) ||
5708 gl_print_string(gl, start_path, start_path[length]))
5709 return 1;
5710 /*
5711 * Move the cursor to the end of the expansion.
5712 */
5713 return gl_place_cursor(gl, (start_path - gl->line) + length);
5714 }
5715 #endif
5716
5717 #ifndef HIDE_FILE_SYSTEM
5718 /*.......................................................................
5719 * This is the action function that lists glob expansions of the
5720 * filename that precedes the cursor position. It expands ~user/
5721 * expressions, $envvar expressions, and wildcards.
5722 */
KT_KEY_FN(gl_list_glob)5723 static KT_KEY_FN(gl_list_glob)
5724 {
5725 char *start_path; /* The pointer to the start of the pathname in */
5726 /* gl->line[]. */
5727 FileExpansion *result; /* The results of the filename expansion */
5728 int pathlen; /* The length of the pathname being expanded */
5729 /*
5730 * Locate the start of the filename that precedes the cursor position.
5731 */
5732 start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
5733 if(!start_path)
5734 return 1;
5735 /*
5736 * Get the length of the string that is to be expanded.
5737 */
5738 pathlen = gl->buff_curpos - (start_path - gl->line);
5739 /*
5740 * Attempt to expand it.
5741 */
5742 result = ef_expand_file(gl->ef, start_path, pathlen);
5743 /*
5744 * If there was an error, report it.
5745 */
5746 if(!result) {
5747 return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
5748 /*
5749 * If no files matched, report this as well.
5750 */
5751 } else if(result->nfile == 0 || !result->exists) {
5752 return gl_print_info(gl, "No files match.", GL_END_INFO);
5753 /*
5754 * List the matching expansions.
5755 */
5756 } else if(gl->echo) {
5757 if(gl_start_newline(gl, 1) ||
5758 _ef_output_expansions(result, gl_write_fn, gl, gl->ncolumn))
5759 return 1;
5760 gl_queue_redisplay(gl);
5761 };
5762 return 0;
5763 }
5764 #endif
5765
5766 /*.......................................................................
5767 * Return non-zero if a character should be considered a part of a word.
5768 *
5769 * Input:
5770 * c int The character to be tested.
5771 * Output:
5772 * return int True if the character should be considered part of a word.
5773 */
gl_is_word_char(int c)5774 static int gl_is_word_char(int c)
5775 {
5776 return isalnum((int)(unsigned char)c) || strchr(GL_WORD_CHARS, c) != NULL;
5777 }
5778
5779 /*.......................................................................
5780 * Override the builtin file-completion callback that is bound to the
5781 * "complete_word" action function.
5782 *
5783 * Input:
5784 * gl GetLine * The resource object of the command-line input
5785 * module.
5786 * data void * This is passed to match_fn() whenever it is
5787 * called. It could, for example, point to a
5788 * symbol table where match_fn() could look
5789 * for possible completions.
5790 * match_fn CplMatchFn * The function that will identify the prefix
5791 * to be completed from the input line, and
5792 * report matching symbols.
5793 * Output:
5794 * return int 0 - OK.
5795 * 1 - Error.
5796 */
gl_customize_completion(GetLine * gl,void * data,CplMatchFn * match_fn)5797 int gl_customize_completion(GetLine *gl, void *data, CplMatchFn *match_fn)
5798 {
5799 sigset_t oldset; /* The signals that were blocked on entry to this function */
5800 /*
5801 * Check the arguments.
5802 */
5803 if(!gl || !match_fn) {
5804 if(gl)
5805 _err_record_msg(gl->err, "NULL argument", END_ERR_MSG);
5806 errno = EINVAL;
5807 return 1;
5808 };
5809 /*
5810 * Temporarily block all signals.
5811 */
5812 gl_mask_signals(gl, &oldset);
5813 /*
5814 * Record the new completion function and its callback data.
5815 */
5816 gl->cplfn.fn = match_fn;
5817 gl->cplfn.data = data;
5818 /*
5819 * Restore the process signal mask before returning.
5820 */
5821 gl_unmask_signals(gl, &oldset);
5822 return 0;
5823 }
5824
5825 /*.......................................................................
5826 * Change the terminal (or stream) that getline interacts with.
5827 *
5828 * Input:
5829 * gl GetLine * The resource object of the command-line input
5830 * module.
5831 * input_fp FILE * The stdio stream to read from.
5832 * output_fp FILE * The stdio stream to write to.
5833 * term char * The terminal type. This can be NULL if
5834 * either or both of input_fp and output_fp don't
5835 * refer to a terminal. Otherwise it should refer
5836 * to an entry in the terminal information database.
5837 * Output:
5838 * return int 0 - OK.
5839 * 1 - Error.
5840 */
gl_change_terminal(GetLine * gl,FILE * input_fp,FILE * output_fp,const char * term)5841 int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
5842 const char *term)
5843 {
5844 sigset_t oldset; /* The signals that were blocked on entry to this function */
5845 int status; /* The return status of _gl_change_terminal() */
5846 /*
5847 * Check the arguments.
5848 */
5849 if(!gl) {
5850 errno = EINVAL;
5851 return 1;
5852 };
5853 /*
5854 * Block all signals.
5855 */
5856 if(gl_mask_signals(gl, &oldset))
5857 return 1;
5858 /*
5859 * Execute the private body of the function while signals are blocked.
5860 */
5861 status = _gl_change_terminal(gl, input_fp, output_fp, term);
5862 /*
5863 * Restore the process signal mask.
5864 */
5865 gl_unmask_signals(gl, &oldset);
5866 return status;
5867 }
5868
5869 /*.......................................................................
5870 * This is the private body of the gl_change_terminal() function. It
5871 * assumes that the caller has checked its arguments and blocked the
5872 * delivery of signals.
5873 */
_gl_change_terminal(GetLine * gl,FILE * input_fp,FILE * output_fp,const char * term)5874 static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
5875 const char *term)
5876 {
5877 int is_term = 0; /* True if both input_fd and output_fd are associated */
5878 /* with a terminal. */
5879 /*
5880 * Require that input_fp and output_fp both be valid.
5881 */
5882 if(!input_fp || !output_fp) {
5883 gl_print_info(gl, "Can't change terminal. Bad input/output stream(s).",
5884 GL_END_INFO);
5885 return 1;
5886 };
5887 /*
5888 * Are we displacing an existing terminal (as opposed to setting the
5889 * initial terminal)?
5890 */
5891 if(gl->input_fd >= 0) {
5892 /*
5893 * Make sure to leave the previous terminal in a usable state.
5894 */
5895 if(_gl_normal_io(gl))
5896 return 1;
5897 /*
5898 * Remove the displaced terminal from the list of fds to watch.
5899 */
5900 #ifdef HAVE_SELECT
5901 FD_CLR(gl->input_fd, &gl->rfds);
5902 #endif
5903 };
5904 /*
5905 * Record the file descriptors and streams.
5906 */
5907 gl->input_fp = input_fp;
5908 gl->input_fd = fileno(input_fp);
5909 gl->output_fp = output_fp;
5910 gl->output_fd = fileno(output_fp);
5911 /*
5912 * If needed, expand the record of the maximum file-descriptor that might
5913 * need to be monitored with select().
5914 */
5915 #ifdef HAVE_SELECT
5916 if(gl->input_fd > gl->max_fd)
5917 gl->max_fd = gl->input_fd;
5918 #endif
5919 /*
5920 * Disable terminal interaction until we have enough info to interact
5921 * with the terminal.
5922 */
5923 gl->is_term = 0;
5924 /*
5925 * For terminal editing, we need both output_fd and input_fd to refer to
5926 * a terminal. While we can't verify that they both point to the same
5927 * terminal, we can verify that they point to terminals.
5928 */
5929 is_term = isatty(gl->input_fd) && isatty(gl->output_fd);
5930 /*
5931 * If we are interacting with a terminal and no terminal type has been
5932 * specified, treat it as a generic ANSI terminal.
5933 */
5934 if(is_term && !term)
5935 term = "ansi";
5936 /*
5937 * Make a copy of the terminal type string.
5938 */
5939 if(term != gl->term) {
5940 /*
5941 * Delete any old terminal type string.
5942 */
5943 if(gl->term) {
5944 free(gl->term);
5945 gl->term = NULL;
5946 };
5947 /*
5948 * Make a copy of the new terminal-type string, if any.
5949 */
5950 if(term) {
5951 size_t termsz = strlen(term)+1;
5952
5953 gl->term = (char *) malloc(termsz);
5954 if(gl->term)
5955 strlcpy(gl->term, term, termsz);
5956 };
5957 };
5958 /*
5959 * Clear any terminal-specific key bindings that were taken from the
5960 * settings of the last terminal.
5961 */
5962 _kt_clear_bindings(gl->bindings, KTB_TERM);
5963 /*
5964 * If we have a terminal install new bindings for it.
5965 */
5966 if(is_term) {
5967 /*
5968 * Get the current settings of the terminal.
5969 */
5970 if(tcgetattr(gl->input_fd, &gl->oldattr)) {
5971 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
5972 return 1;
5973 };
5974 /*
5975 * If we don't set this now, gl_control_strings() won't know
5976 * that it is talking to a terminal.
5977 */
5978 gl->is_term = 1;
5979 /*
5980 * Lookup the terminal control string and size information.
5981 */
5982 if(gl_control_strings(gl, term)) {
5983 gl->is_term = 0;
5984 return 1;
5985 };
5986 /*
5987 * Bind terminal-specific keys.
5988 */
5989 if(gl_bind_terminal_keys(gl))
5990 return 1;
5991 };
5992 /*
5993 * Assume that the caller has given us a terminal in a sane state.
5994 */
5995 gl->io_mode = GL_NORMAL_MODE;
5996 /*
5997 * Switch into the currently configured I/O mode.
5998 */
5999 if(_gl_io_mode(gl, gl->io_mode))
6000 return 1;
6001 return 0;
6002 }
6003
6004 /*.......................................................................
6005 * Set up terminal-specific key bindings.
6006 *
6007 * Input:
6008 * gl GetLine * The resource object of the command-line input
6009 * module.
6010 * Output:
6011 * return int 0 - OK.
6012 * 1 - Error.
6013 */
gl_bind_terminal_keys(GetLine * gl)6014 static int gl_bind_terminal_keys(GetLine *gl)
6015 {
6016 /*
6017 * Install key-bindings for the special terminal characters.
6018 */
6019 if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VINTR],
6020 "user-interrupt") ||
6021 gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VQUIT], "abort") ||
6022 gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VSUSP], "suspend"))
6023 return 1;
6024 /*
6025 * In vi-mode, arrange for the above characters to be seen in command
6026 * mode.
6027 */
6028 if(gl->editor == GL_VI_MODE) {
6029 if(gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VINTR]),
6030 "user-interrupt") ||
6031 gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VQUIT]),
6032 "abort") ||
6033 gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VSUSP]),
6034 "suspend"))
6035 return 1;
6036 };
6037 /*
6038 * Non-universal special keys.
6039 */
6040 #ifdef VLNEXT
6041 if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VLNEXT],
6042 "literal-next"))
6043 return 1;
6044 #else
6045 if(_kt_set_keybinding(gl->bindings, KTB_TERM, "^V", "literal-next")) {
6046 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
6047 return 1;
6048 };
6049 #endif
6050 /*
6051 * Bind action functions to the terminal-specific arrow keys
6052 * looked up by gl_control_strings().
6053 */
6054 if(_gl_bind_arrow_keys(gl))
6055 return 1;
6056 return 0;
6057 }
6058
6059 /*.......................................................................
6060 * This function is normally bound to control-D. When it is invoked within
6061 * a line it deletes the character which follows the cursor. When invoked
6062 * at the end of the line it lists possible file completions, and when
6063 * invoked on an empty line it causes gl_get_line() to return EOF. This
6064 * function emulates the one that is normally bound to control-D by tcsh.
6065 */
KT_KEY_FN(gl_del_char_or_list_or_eof)6066 static KT_KEY_FN(gl_del_char_or_list_or_eof)
6067 {
6068 /*
6069 * If we have an empty line arrange to return EOF.
6070 */
6071 if(gl->ntotal < 1) {
6072 gl_record_status(gl, GLR_EOF, 0);
6073 return 1;
6074 /*
6075 * If we are at the end of the line list possible completions.
6076 */
6077 } else if(gl->buff_curpos >= gl->ntotal) {
6078 return gl_list_completions(gl, 1, NULL);
6079 /*
6080 * Within the line delete the character that follows the cursor.
6081 */
6082 } else {
6083 /*
6084 * If in vi command mode, first preserve the current line for potential use
6085 * by vi-undo.
6086 */
6087 gl_save_for_undo(gl);
6088 /*
6089 * Delete 'count' characters.
6090 */
6091 return gl_forward_delete_char(gl, count, NULL);
6092 };
6093 }
6094
6095 /*.......................................................................
6096 * This function is normally bound to control-D in vi mode. When it is
6097 * invoked within a line it lists possible file completions, and when
6098 * invoked on an empty line it causes gl_get_line() to return EOF. This
6099 * function emulates the one that is normally bound to control-D by tcsh.
6100 */
KT_KEY_FN(gl_list_or_eof)6101 static KT_KEY_FN(gl_list_or_eof)
6102 {
6103 /*
6104 * If we have an empty line arrange to return EOF.
6105 */
6106 if(gl->ntotal < 1) {
6107 gl_record_status(gl, GLR_EOF, 0);
6108 return 1;
6109 /*
6110 * Otherwise list possible completions.
6111 */
6112 } else {
6113 return gl_list_completions(gl, 1, NULL);
6114 };
6115 }
6116
6117 /*.......................................................................
6118 * List possible completions of the word that precedes the cursor. The
6119 * callback data argument must either be NULL to select the default
6120 * file completion callback, or be a GlCplCallback object containing the
6121 * completion callback function to call.
6122 */
KT_KEY_FN(gl_list_completions)6123 static KT_KEY_FN(gl_list_completions)
6124 {
6125 int waserr = 0; /* True after errors */
6126 /*
6127 * Get the container of the completion callback and its callback data.
6128 */
6129 GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
6130 /*
6131 * Get the list of possible completions.
6132 */
6133 CplMatches *matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos,
6134 cb->data, cb->fn);
6135 /*
6136 * No matching completions?
6137 */
6138 if(!matches) {
6139 waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
6140 /*
6141 * List the matches.
6142 */
6143 } else if(matches->nmatch > 0 && gl->echo) {
6144 if(_gl_normal_io(gl) ||
6145 _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
6146 waserr = 1;
6147 };
6148 /*
6149 * If any output had to be written to the terminal, then editing will
6150 * have been suspended, make sure that we are back in raw line editing
6151 * mode before returning.
6152 */
6153 if(_gl_raw_io(gl, 1))
6154 waserr = 1;
6155 return waserr;
6156 }
6157
6158 /*.......................................................................
6159 * Where the user has used the symbolic arrow-key names to specify
6160 * arrow key bindings, bind the specified action functions to the default
6161 * and terminal specific arrow key sequences.
6162 *
6163 * Input:
6164 * gl GetLine * The getline resource object.
6165 * Output:
6166 * return int 0 - OK.
6167 * 1 - Error.
6168 */
_gl_bind_arrow_keys(GetLine * gl)6169 static int _gl_bind_arrow_keys(GetLine *gl)
6170 {
6171 /*
6172 * Process each of the arrow keys.
6173 */
6174 if(_gl_rebind_arrow_key(gl, "up", gl->u_arrow, "^[[A", "^[OA") ||
6175 _gl_rebind_arrow_key(gl, "down", gl->d_arrow, "^[[B", "^[OB") ||
6176 _gl_rebind_arrow_key(gl, "left", gl->l_arrow, "^[[D", "^[OD") ||
6177 _gl_rebind_arrow_key(gl, "right", gl->r_arrow, "^[[C", "^[OC"))
6178 return 1;
6179 return 0;
6180 }
6181
6182 /*.......................................................................
6183 * Lookup the action function of a symbolic arrow-key binding, and bind
6184 * it to the terminal-specific and default arrow-key sequences. Note that
6185 * we don't trust the terminal-specified key sequences to be correct.
6186 * The main reason for this is that on some machines the xterm terminfo
6187 * entry is for hardware X-terminals, rather than xterm terminal emulators
6188 * and the two terminal types emit different character sequences when the
6189 * their cursor keys are pressed. As a result we also supply a couple
6190 * of default key sequences.
6191 *
6192 * Input:
6193 * gl GetLine * The resource object of gl_get_line().
6194 * name char * The symbolic name of the arrow key.
6195 * term_seq char * The terminal-specific arrow-key sequence.
6196 * def_seq1 char * The first default arrow-key sequence.
6197 * def_seq2 char * The second arrow-key sequence.
6198 * Output:
6199 * return int 0 - OK.
6200 * 1 - Error.
6201 */
_gl_rebind_arrow_key(GetLine * gl,const char * name,const char * term_seq,const char * def_seq1,const char * def_seq2)6202 static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
6203 const char *term_seq, const char *def_seq1,
6204 const char *def_seq2)
6205 {
6206 KeySym *keysym; /* The binding-table entry matching the arrow-key name */
6207 int nsym; /* The number of ambiguous matches */
6208 /*
6209 * Lookup the key binding for the symbolic name of the arrow key. This
6210 * will either be the default action, or a user provided one.
6211 */
6212 if(_kt_lookup_keybinding(gl->bindings, name, strlen(name), &keysym, &nsym)
6213 == KT_EXACT_MATCH) {
6214 /*
6215 * Get the action function.
6216 */
6217 KtAction *action = keysym->actions + keysym->binder;
6218 KtKeyFn *fn = action->fn;
6219 void *data = action->data;
6220 /*
6221 * Bind this to each of the specified key sequences.
6222 */
6223 if((term_seq &&
6224 _kt_set_keyfn(gl->bindings, KTB_TERM, term_seq, fn, data)) ||
6225 (def_seq1 &&
6226 _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq1, fn, data)) ||
6227 (def_seq2 &&
6228 _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq2, fn, data))) {
6229 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
6230 return 1;
6231 };
6232 };
6233 return 0;
6234 }
6235
6236 /*.......................................................................
6237 * Read getline configuration information from a given file.
6238 *
6239 * Input:
6240 * gl GetLine * The getline resource object.
6241 * filename const char * The name of the file to read configuration
6242 * information from. The contents of this file
6243 * are as described in the gl_get_line(3) man
6244 * page for the default ~/.teclarc configuration
6245 * file.
6246 * who KtBinder Who bindings are to be installed for.
6247 * Output:
6248 * return int 0 - OK.
6249 * 1 - Irrecoverable error.
6250 */
_gl_read_config_file(GetLine * gl,const char * filename,KtBinder who)6251 static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who)
6252 {
6253 /*
6254 * If filesystem access is to be excluded, configuration files can't
6255 * be read.
6256 */
6257 #ifdef WITHOUT_FILE_SYSTEM
6258 _err_record_msg(gl->err,
6259 "Can't read configuration files without filesystem access",
6260 END_ERR_MSG);
6261 errno = EINVAL;
6262 return 1;
6263 #else
6264 FileExpansion *expansion; /* The expansion of the filename */
6265 FILE *fp; /* The opened file */
6266 int waserr = 0; /* True if an error occurred while reading */
6267 int lineno = 1; /* The line number being processed */
6268 /*
6269 * Check the arguments.
6270 */
6271 if(!gl || !filename) {
6272 if(gl)
6273 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
6274 errno = EINVAL;
6275 return 1;
6276 };
6277 /*
6278 * Expand the filename.
6279 */
6280 expansion = ef_expand_file(gl->ef, filename, -1);
6281 if(!expansion) {
6282 gl_print_info(gl, "Unable to expand ", filename, " (",
6283 ef_last_error(gl->ef), ").", GL_END_INFO);
6284 return 1;
6285 };
6286 /*
6287 * Attempt to open the file.
6288 */
6289 fp = fopen(expansion->files[0], "r");
6290 /*
6291 * It isn't an error for there to be no configuration file.
6292 */
6293 if(!fp)
6294 return 0;
6295 /*
6296 * Parse the contents of the file.
6297 */
6298 while(!waserr && !feof(fp))
6299 waserr = _gl_parse_config_line(gl, fp, glc_file_getc, filename, who,
6300 &lineno);
6301 /*
6302 * Bind action functions to the terminal-specific arrow keys.
6303 */
6304 if(_gl_bind_arrow_keys(gl))
6305 return 1;
6306 /*
6307 * Clean up.
6308 */
6309 (void) fclose(fp);
6310 return waserr;
6311 #endif
6312 }
6313
6314 /*.......................................................................
6315 * Read GetLine configuration information from a string. The contents of
6316 * the string are the same as those described in the gl_get_line(3)
6317 * man page for the contents of the ~/.teclarc configuration file.
6318 */
_gl_read_config_string(GetLine * gl,const char * buffer,KtBinder who)6319 static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who)
6320 {
6321 const char *bptr; /* A pointer into buffer[] */
6322 int waserr = 0; /* True if an error occurred while reading */
6323 int lineno = 1; /* The line number being processed */
6324 /*
6325 * Check the arguments.
6326 */
6327 if(!gl || !buffer) {
6328 if(gl)
6329 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
6330 errno = EINVAL;
6331 return 1;
6332 };
6333 /*
6334 * Get a pointer to the start of the buffer.
6335 */
6336 bptr = buffer;
6337 /*
6338 * Parse the contents of the buffer.
6339 */
6340 while(!waserr && *bptr)
6341 waserr = _gl_parse_config_line(gl, &bptr, glc_buff_getc, "", who, &lineno);
6342 /*
6343 * Bind action functions to the terminal-specific arrow keys.
6344 */
6345 if(_gl_bind_arrow_keys(gl))
6346 return 1;
6347 return waserr;
6348 }
6349
6350 /*.......................................................................
6351 * Parse the next line of a getline configuration file.
6352 *
6353 * Input:
6354 * gl GetLine * The getline resource object.
6355 * stream void * The pointer representing the stream to be read
6356 * by getc_fn().
6357 * getc_fn GlcGetcFn * A callback function which when called with
6358 * 'stream' as its argument, returns the next
6359 * unread character from the stream.
6360 * origin const char * The name of the entity being read (eg. a
6361 * file name).
6362 * who KtBinder Who bindings are to be installed for.
6363 * Input/Output:
6364 * lineno int * The line number being processed is to be
6365 * maintained in *lineno.
6366 * Output:
6367 * return int 0 - OK.
6368 * 1 - Irrecoverable error.
6369 */
_gl_parse_config_line(GetLine * gl,void * stream,GlcGetcFn * getc_fn,const char * origin,KtBinder who,int * lineno)6370 static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
6371 const char *origin, KtBinder who, int *lineno)
6372 {
6373 char buffer[GL_CONF_BUFLEN+1]; /* The input line buffer */
6374 char *argv[GL_CONF_MAXARG]; /* The argument list */
6375 int argc = 0; /* The number of arguments in argv[] */
6376 int c; /* A character from the file */
6377 int escaped = 0; /* True if the next character is escaped */
6378 int i;
6379 /*
6380 * Skip spaces and tabs.
6381 */
6382 do c = getc_fn(stream); while(c==' ' || c=='\t');
6383 /*
6384 * Comments extend to the end of the line.
6385 */
6386 if(c=='#')
6387 do c = getc_fn(stream); while(c != '\n' && c != EOF);
6388 /*
6389 * Ignore empty lines.
6390 */
6391 if(c=='\n' || c==EOF) {
6392 (*lineno)++;
6393 return 0;
6394 };
6395 /*
6396 * Record the buffer location of the start of the first argument.
6397 */
6398 argv[argc] = buffer;
6399 /*
6400 * Read the rest of the line, stopping early if a comment is seen, or
6401 * the buffer overflows, and replacing sequences of spaces with a
6402 * '\0', and recording the thus terminated string as an argument.
6403 */
6404 i = 0;
6405 while(i<GL_CONF_BUFLEN) {
6406 /*
6407 * Did we hit the end of the latest argument?
6408 */
6409 if(c==EOF || (!escaped && (c==' ' || c=='\n' || c=='\t' || c=='#'))) {
6410 /*
6411 * Terminate the argument.
6412 */
6413 buffer[i++] = '\0';
6414 argc++;
6415 /*
6416 * Skip spaces and tabs.
6417 */
6418 while(c==' ' || c=='\t')
6419 c = getc_fn(stream);
6420 /*
6421 * If we hit the end of the line, or the start of a comment, exit the loop.
6422 */
6423 if(c==EOF || c=='\n' || c=='#')
6424 break;
6425 /*
6426 * Start recording the next argument.
6427 */
6428 if(argc >= GL_CONF_MAXARG) {
6429 gl_report_config_error(gl, origin, *lineno, "Too many arguments.");
6430 do c = getc_fn(stream); while(c!='\n' && c!=EOF); /* Skip past eol */
6431 return 0;
6432 };
6433 argv[argc] = buffer + i;
6434 /*
6435 * The next character was preceded by spaces, so it isn't escaped.
6436 */
6437 escaped = 0;
6438 } else {
6439 /*
6440 * If we hit an unescaped backslash, this means that we should arrange
6441 * to treat the next character like a simple alphabetical character.
6442 */
6443 if(c=='\\' && !escaped) {
6444 escaped = 1;
6445 /*
6446 * Splice lines where the newline is escaped.
6447 */
6448 } else if(c=='\n' && escaped) {
6449 (*lineno)++;
6450 /*
6451 * Record a normal character, preserving any preceding backslash.
6452 */
6453 } else {
6454 if(escaped)
6455 buffer[i++] = '\\';
6456 if(i>=GL_CONF_BUFLEN)
6457 break;
6458 escaped = 0;
6459 buffer[i++] = c;
6460 };
6461 /*
6462 * Get the next character.
6463 */
6464 c = getc_fn(stream);
6465 };
6466 };
6467 /*
6468 * Did the buffer overflow?
6469 */
6470 if(i>=GL_CONF_BUFLEN) {
6471 gl_report_config_error(gl, origin, *lineno, "Line too long.");
6472 return 0;
6473 };
6474 /*
6475 * The first argument should be a command name.
6476 */
6477 if(strcmp(argv[0], "bind") == 0) {
6478 const char *action = NULL; /* A NULL action removes a keybinding */
6479 const char *keyseq = NULL;
6480 switch(argc) {
6481 case 3:
6482 action = argv[2];
6483 case 2: /* Note the intentional fallthrough */
6484 keyseq = argv[1];
6485 /*
6486 * Attempt to record the new keybinding.
6487 */
6488 if(_kt_set_keybinding(gl->bindings, who, keyseq, action)) {
6489 gl_report_config_error(gl, origin, *lineno,
6490 _kt_last_error(gl->bindings));
6491 };
6492 break;
6493 default:
6494 gl_report_config_error(gl, origin, *lineno, "Wrong number of arguments.");
6495 };
6496 } else if(strcmp(argv[0], "edit-mode") == 0) {
6497 if(argc == 2 && strcmp(argv[1], "emacs") == 0) {
6498 gl_change_editor(gl, GL_EMACS_MODE);
6499 } else if(argc == 2 && strcmp(argv[1], "vi") == 0) {
6500 gl_change_editor(gl, GL_VI_MODE);
6501 } else if(argc == 2 && strcmp(argv[1], "none") == 0) {
6502 gl_change_editor(gl, GL_NO_EDITOR);
6503 } else {
6504 gl_report_config_error(gl, origin, *lineno,
6505 "The argument of editor should be vi or emacs.");
6506 };
6507 } else if(strcmp(argv[0], "nobeep") == 0) {
6508 gl->silence_bell = 1;
6509 } else {
6510 gl_report_config_error(gl, origin, *lineno, "Unknown command name.");
6511 };
6512 /*
6513 * Skip any trailing comment.
6514 */
6515 while(c != '\n' && c != EOF)
6516 c = getc_fn(stream);
6517 (*lineno)++;
6518 return 0;
6519 }
6520
6521 /*.......................................................................
6522 * This is a private function of _gl_parse_config_line() which prints
6523 * out an error message about the contents of the line, prefixed by the
6524 * name of the origin of the line and its line number.
6525 *
6526 * Input:
6527 * gl GetLine * The resource object of gl_get_line().
6528 * origin const char * The name of the entity being read (eg. a
6529 * file name).
6530 * lineno int The line number at which the error occurred.
6531 * errmsg const char * The error message.
6532 * Output:
6533 * return int 0 - OK.
6534 * 1 - Error.
6535 */
gl_report_config_error(GetLine * gl,const char * origin,int lineno,const char * errmsg)6536 static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
6537 const char *errmsg)
6538 {
6539 char lnum[20]; /* A buffer in which to render a single integer */
6540 /*
6541 * Convert the line number into a string.
6542 */
6543 snprintf(lnum, sizeof(lnum), "%d", lineno);
6544 /*
6545 * Have the string printed on the terminal.
6546 */
6547 return gl_print_info(gl, origin, ":", lnum, ": ", errmsg, GL_END_INFO);
6548 }
6549
6550 /*.......................................................................
6551 * This is the _gl_parse_config_line() callback function which reads the
6552 * next character from a configuration file.
6553 */
GLC_GETC_FN(glc_file_getc)6554 static GLC_GETC_FN(glc_file_getc)
6555 {
6556 return fgetc((FILE *) stream);
6557 }
6558
6559 /*.......................................................................
6560 * This is the _gl_parse_config_line() callback function which reads the
6561 * next character from a buffer. Its stream argument is a pointer to a
6562 * variable which is, in turn, a pointer into the buffer being read from.
6563 */
GLC_GETC_FN(glc_buff_getc)6564 static GLC_GETC_FN(glc_buff_getc)
6565 {
6566 const char **lptr = (char const **) stream;
6567 return **lptr ? *(*lptr)++ : EOF;
6568 }
6569
6570 #ifndef HIDE_FILE_SYSTEM
6571 /*.......................................................................
6572 * When this action is triggered, it arranges to temporarily read command
6573 * lines from the regular file whos name precedes the cursor.
6574 * The current line is first discarded.
6575 */
KT_KEY_FN(gl_read_from_file)6576 static KT_KEY_FN(gl_read_from_file)
6577 {
6578 char *start_path; /* The pointer to the start of the pathname in */
6579 /* gl->line[]. */
6580 FileExpansion *result; /* The results of the filename expansion */
6581 int pathlen; /* The length of the pathname being expanded */
6582 /*
6583 * Locate the start of the filename that precedes the cursor position.
6584 */
6585 start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
6586 if(!start_path)
6587 return 1;
6588 /*
6589 * Get the length of the pathname string.
6590 */
6591 pathlen = gl->buff_curpos - (start_path - gl->line);
6592 /*
6593 * Attempt to expand the pathname.
6594 */
6595 result = ef_expand_file(gl->ef, start_path, pathlen);
6596 /*
6597 * If there was an error, report the error on a new line.
6598 */
6599 if(!result) {
6600 return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
6601 /*
6602 * If no files matched, report this as well.
6603 */
6604 } else if(result->nfile == 0 || !result->exists) {
6605 return gl_print_info(gl, "No files match.", GL_END_INFO);
6606 /*
6607 * Complain if more than one file matches.
6608 */
6609 } else if(result->nfile > 1) {
6610 return gl_print_info(gl, "More than one file matches.", GL_END_INFO);
6611 /*
6612 * Disallow input from anything but normal files. In principle we could
6613 * also support input from named pipes. Terminal files would be a problem
6614 * since we wouldn't know the terminal type, and other types of files
6615 * might cause the library to lock up.
6616 */
6617 } else if(!_pu_path_is_file(result->files[0])) {
6618 return gl_print_info(gl, "Not a normal file.", GL_END_INFO);
6619 } else {
6620 /*
6621 * Attempt to open and install the specified file for reading.
6622 */
6623 gl->file_fp = fopen(result->files[0], "r");
6624 if(!gl->file_fp) {
6625 return gl_print_info(gl, "Unable to open: ", result->files[0],
6626 GL_END_INFO);
6627 };
6628 /*
6629 * If needed, expand the record of the maximum file-descriptor that might
6630 * need to be monitored with select().
6631 */
6632 #ifdef HAVE_SELECT
6633 if(fileno(gl->file_fp) > gl->max_fd)
6634 gl->max_fd = fileno(gl->file_fp);
6635 #endif
6636 /*
6637 * Is non-blocking I/O needed?
6638 */
6639 if(gl->raw_mode && gl->io_mode==GL_SERVER_MODE &&
6640 gl_nonblocking_io(gl, fileno(gl->file_fp))) {
6641 gl_revert_input(gl);
6642 return gl_print_info(gl, "Can't read file %s with non-blocking I/O",
6643 result->files[0]);
6644 };
6645 /*
6646 * Inform the user what is happening.
6647 */
6648 if(gl_print_info(gl, "<Taking input from ", result->files[0], ">",
6649 GL_END_INFO))
6650 return 1;
6651 };
6652 return 0;
6653 }
6654 #endif
6655
6656 /*.......................................................................
6657 * Close any temporary file that is being used for input.
6658 *
6659 * Input:
6660 * gl GetLine * The getline resource object.
6661 */
gl_revert_input(GetLine * gl)6662 static void gl_revert_input(GetLine *gl)
6663 {
6664 if(gl->file_fp)
6665 fclose(gl->file_fp);
6666 gl->file_fp = NULL;
6667 gl->endline = 1;
6668 }
6669
6670 /*.......................................................................
6671 * This is the action function that recalls the oldest line in the
6672 * history buffer.
6673 */
KT_KEY_FN(gl_beginning_of_history)6674 static KT_KEY_FN(gl_beginning_of_history)
6675 {
6676 /*
6677 * In vi mode, switch to command mode, since the user is very
6678 * likely to want to move around newly recalled lines.
6679 */
6680 gl_vi_command_mode(gl);
6681 /*
6682 * Forget any previous recall session.
6683 */
6684 gl->preload_id = 0;
6685 /*
6686 * Record the key sequence number of this search action.
6687 */
6688 gl->last_search = gl->keyseq_count;
6689 /*
6690 * Recall the next oldest line in the history list.
6691 */
6692 if(_glh_oldest_line(gl->glh, gl->line, gl->linelen+1) == NULL)
6693 return 0;
6694 /*
6695 * Accomodate the new contents of gl->line[].
6696 */
6697 gl_update_buffer(gl);
6698 /*
6699 * Arrange to have the cursor placed at the end of the new line.
6700 */
6701 gl->buff_curpos = gl->ntotal;
6702 /*
6703 * Erase and display the new line.
6704 */
6705 gl_queue_redisplay(gl);
6706 return 0;
6707 }
6708
6709 /*.......................................................................
6710 * If a history session is currently in progress, this action function
6711 * recalls the line that was being edited when the session started. If
6712 * no history session is in progress, it does nothing.
6713 */
KT_KEY_FN(gl_end_of_history)6714 static KT_KEY_FN(gl_end_of_history)
6715 {
6716 /*
6717 * In vi mode, switch to command mode, since the user is very
6718 * likely to want to move around newly recalled lines.
6719 */
6720 gl_vi_command_mode(gl);
6721 /*
6722 * Forget any previous recall session.
6723 */
6724 gl->preload_id = 0;
6725 /*
6726 * Record the key sequence number of this search action.
6727 */
6728 gl->last_search = gl->keyseq_count;
6729 /*
6730 * Recall the next oldest line in the history list.
6731 */
6732 if(_glh_current_line(gl->glh, gl->line, gl->linelen+1) == NULL)
6733 return 0;
6734 /*
6735 * Accomodate the new contents of gl->line[].
6736 */
6737 gl_update_buffer(gl);
6738 /*
6739 * Arrange to have the cursor placed at the end of the new line.
6740 */
6741 gl->buff_curpos = gl->ntotal;
6742 /*
6743 * Erase and display the new line.
6744 */
6745 gl_queue_redisplay(gl);
6746 return 0;
6747 }
6748
6749 /*.......................................................................
6750 * This action function is treated specially, in that its count argument
6751 * is set to the end keystroke of the keysequence that activated it.
6752 * It accumulates a numeric argument, adding one digit on each call in
6753 * which the last keystroke was a numeric digit.
6754 */
KT_KEY_FN(gl_digit_argument)6755 static KT_KEY_FN(gl_digit_argument)
6756 {
6757 /*
6758 * Was the last keystroke a digit?
6759 */
6760 int is_digit = isdigit((int)(unsigned char) count);
6761 /*
6762 * In vi command mode, a lone '0' means goto-start-of-line.
6763 */
6764 if(gl->vi.command && gl->number < 0 && count == '0')
6765 return gl_beginning_of_line(gl, count, NULL);
6766 /*
6767 * Are we starting to accumulate a new number?
6768 */
6769 if(gl->number < 0 || !is_digit)
6770 gl->number = 0;
6771 /*
6772 * Was the last keystroke a digit?
6773 */
6774 if(is_digit) {
6775 /*
6776 * Read the numeric value of the digit, without assuming ASCII.
6777 */
6778 int n;
6779 char s[2]; s[0] = count; s[1] = '\0';
6780 n = atoi(s);
6781 /*
6782 * Append the new digit.
6783 */
6784 gl->number = gl->number * 10 + n;
6785 };
6786 return 0;
6787 }
6788
6789 /*.......................................................................
6790 * The newline action function sets gl->endline to tell
6791 * gl_get_input_line() that the line is now complete.
6792 */
KT_KEY_FN(gl_newline)6793 static KT_KEY_FN(gl_newline)
6794 {
6795 GlhLineID id; /* The last history line recalled while entering this line */
6796 /*
6797 * Flag the line as ended.
6798 */
6799 gl->endline = 1;
6800 /*
6801 * Record the next position in the history buffer, for potential
6802 * recall by an action function on the next call to gl_get_line().
6803 */
6804 id = _glh_line_id(gl->glh, 1);
6805 if(id)
6806 gl->preload_id = id;
6807 return 0;
6808 }
6809
6810 /*.......................................................................
6811 * The 'repeat' action function sets gl->endline to tell
6812 * gl_get_input_line() that the line is now complete, and records the
6813 * ID of the next history line in gl->preload_id so that the next call
6814 * to gl_get_input_line() will preload the line with that history line.
6815 */
KT_KEY_FN(gl_repeat_history)6816 static KT_KEY_FN(gl_repeat_history)
6817 {
6818 gl->endline = 1;
6819 gl->preload_id = _glh_line_id(gl->glh, 1);
6820 gl->preload_history = 1;
6821 return 0;
6822 }
6823
6824 /*.......................................................................
6825 * Flush unwritten characters to the terminal.
6826 *
6827 * Input:
6828 * gl GetLine * The getline resource object.
6829 * Output:
6830 * return int 0 - OK.
6831 * 1 - Either an error occured, or the output
6832 * blocked and non-blocking I/O is being used.
6833 * See gl->rtn_status for details.
6834 */
gl_flush_output(GetLine * gl)6835 static int gl_flush_output(GetLine *gl)
6836 {
6837 /*
6838 * Record the fact that we are about to write to the terminal.
6839 */
6840 gl->pending_io = GLP_WRITE;
6841 /*
6842 * Attempt to flush the output to the terminal.
6843 */
6844 errno = 0;
6845 switch(_glq_flush_queue(gl->cq, gl->flush_fn, gl)) {
6846 case GLQ_FLUSH_DONE:
6847 return gl->redisplay && !gl->postpone && gl_redisplay(gl, 1, NULL);
6848 break;
6849 case GLQ_FLUSH_AGAIN: /* Output blocked */
6850 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
6851 return 1;
6852 break;
6853 default: /* Abort the line if an error occurs */
6854 gl_record_status(gl, errno==EINTR ? GLR_SIGNAL : GLR_ERROR, errno);
6855 return 1;
6856 break;
6857 };
6858 }
6859
6860 /*.......................................................................
6861 * This is the callback which _glq_flush_queue() uses to write buffered
6862 * characters to the terminal.
6863 */
GL_WRITE_FN(gl_flush_terminal)6864 static GL_WRITE_FN(gl_flush_terminal)
6865 {
6866 int ndone = 0; /* The number of characters written so far */
6867 /*
6868 * Get the line-editor resource object.
6869 */
6870 GetLine *gl = (GetLine *) data;
6871 /*
6872 * Transfer the latest array of characters to stdio.
6873 */
6874 while(ndone < n) {
6875 int nnew = write(gl->output_fd, s, n-ndone);
6876 /*
6877 * If the write was successful, add to the recorded number of bytes
6878 * that have now been written.
6879 */
6880 if(nnew > 0) {
6881 ndone += nnew;
6882 /*
6883 * If a signal interrupted the call, restart the write(), since all of
6884 * the signals that gl_get_line() has been told to watch for are
6885 * currently blocked.
6886 */
6887 } else if(errno == EINTR) {
6888 continue;
6889 /*
6890 * If we managed to write something before an I/O error occurred, or
6891 * output blocked before anything was written, report the number of
6892 * bytes that were successfully written before this happened.
6893 */
6894 } else if(ndone > 0
6895 #if defined(EAGAIN)
6896 || errno==EAGAIN
6897 #endif
6898 #if defined(EWOULDBLOCK)
6899 || errno==EWOULDBLOCK
6900 #endif
6901 ) {
6902 return ndone;
6903
6904 /*
6905 * To get here, an error must have occurred before anything new could
6906 * be written.
6907 */
6908 } else {
6909 return -1;
6910 };
6911 };
6912 /*
6913 * To get here, we must have successfully written the number of
6914 * bytes that was specified.
6915 */
6916 return n;
6917 }
6918
6919 /*.......................................................................
6920 * Change the style of editing to emulate a given editor.
6921 *
6922 * Input:
6923 * gl GetLine * The getline resource object.
6924 * editor GlEditor The type of editor to emulate.
6925 * Output:
6926 * return int 0 - OK.
6927 * 1 - Error.
6928 */
gl_change_editor(GetLine * gl,GlEditor editor)6929 static int gl_change_editor(GetLine *gl, GlEditor editor)
6930 {
6931 /*
6932 * Install the default key-bindings of the requested editor.
6933 */
6934 switch(editor) {
6935 case GL_EMACS_MODE:
6936 _kt_clear_bindings(gl->bindings, KTB_NORM);
6937 _kt_clear_bindings(gl->bindings, KTB_TERM);
6938 (void) _kt_add_bindings(gl->bindings, KTB_NORM, gl_emacs_bindings,
6939 sizeof(gl_emacs_bindings)/sizeof(gl_emacs_bindings[0]));
6940 break;
6941 case GL_VI_MODE:
6942 _kt_clear_bindings(gl->bindings, KTB_NORM);
6943 _kt_clear_bindings(gl->bindings, KTB_TERM);
6944 (void) _kt_add_bindings(gl->bindings, KTB_NORM, gl_vi_bindings,
6945 sizeof(gl_vi_bindings)/sizeof(gl_vi_bindings[0]));
6946 break;
6947 case GL_NO_EDITOR:
6948 break;
6949 default:
6950 _err_record_msg(gl->err, "Unknown editor", END_ERR_MSG);
6951 errno = EINVAL;
6952 return 1;
6953 };
6954 /*
6955 * Record the new editing mode.
6956 */
6957 gl->editor = editor;
6958 gl->vi.command = 0; /* Start in input mode */
6959 gl->insert_curpos = 0;
6960 /*
6961 * Reinstate terminal-specific bindings.
6962 */
6963 if(gl->editor != GL_NO_EDITOR && gl->input_fp)
6964 (void) gl_bind_terminal_keys(gl);
6965 return 0;
6966 }
6967
6968 /*.......................................................................
6969 * This is an action function that switches to editing using emacs bindings
6970 */
KT_KEY_FN(gl_emacs_editing_mode)6971 static KT_KEY_FN(gl_emacs_editing_mode)
6972 {
6973 return gl_change_editor(gl, GL_EMACS_MODE);
6974 }
6975
6976 /*.......................................................................
6977 * This is an action function that switches to editing using vi bindings
6978 */
KT_KEY_FN(gl_vi_editing_mode)6979 static KT_KEY_FN(gl_vi_editing_mode)
6980 {
6981 return gl_change_editor(gl, GL_VI_MODE);
6982 }
6983
6984 /*.......................................................................
6985 * This is the action function that switches to insert mode.
6986 */
KT_KEY_FN(gl_vi_insert)6987 static KT_KEY_FN(gl_vi_insert)
6988 {
6989 /*
6990 * If in vi command mode, preserve the current line for potential
6991 * use by vi-undo.
6992 */
6993 gl_save_for_undo(gl);
6994 /*
6995 * Switch to vi insert mode.
6996 */
6997 gl->insert = 1;
6998 gl->vi.command = 0;
6999 gl->insert_curpos = gl->buff_curpos;
7000 return 0;
7001 }
7002
7003 /*.......................................................................
7004 * This is an action function that switches to overwrite mode.
7005 */
KT_KEY_FN(gl_vi_overwrite)7006 static KT_KEY_FN(gl_vi_overwrite)
7007 {
7008 /*
7009 * If in vi command mode, preserve the current line for potential
7010 * use by vi-undo.
7011 */
7012 gl_save_for_undo(gl);
7013 /*
7014 * Switch to vi overwrite mode.
7015 */
7016 gl->insert = 0;
7017 gl->vi.command = 0;
7018 gl->insert_curpos = gl->buff_curpos;
7019 return 0;
7020 }
7021
7022 /*.......................................................................
7023 * This action function toggles the case of the character under the
7024 * cursor.
7025 */
KT_KEY_FN(gl_change_case)7026 static KT_KEY_FN(gl_change_case)
7027 {
7028 int i;
7029 /*
7030 * Keep a record of the current insert mode and the cursor position.
7031 */
7032 int insert = gl->insert;
7033 /*
7034 * If in vi command mode, preserve the current line for potential
7035 * use by vi-undo.
7036 */
7037 gl_save_for_undo(gl);
7038 /*
7039 * We want to overwrite the modified word.
7040 */
7041 gl->insert = 0;
7042 /*
7043 * Toggle the case of 'count' characters.
7044 */
7045 for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) {
7046 char *cptr = gl->line + gl->buff_curpos++;
7047 /*
7048 * Convert the character to upper case?
7049 */
7050 if(islower((int)(unsigned char) *cptr))
7051 gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
7052 else if(isupper((int)(unsigned char) *cptr))
7053 gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
7054 /*
7055 * Write the possibly modified character back. Note that for non-modified
7056 * characters we want to do this as well, so as to advance the cursor.
7057 */
7058 if(gl_print_char(gl, *cptr, cptr[1]))
7059 return 1;
7060 };
7061 /*
7062 * Restore the insertion mode.
7063 */
7064 gl->insert = insert;
7065 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
7066 }
7067
7068 /*.......................................................................
7069 * This is the action function which implements the vi-style action which
7070 * moves the cursor to the start of the line, then switches to insert mode.
7071 */
KT_KEY_FN(gl_vi_insert_at_bol)7072 static KT_KEY_FN(gl_vi_insert_at_bol)
7073 {
7074 gl_save_for_undo(gl);
7075 return gl_beginning_of_line(gl, 0, NULL) ||
7076 gl_vi_insert(gl, 0, NULL);
7077
7078 }
7079
7080 /*.......................................................................
7081 * This is the action function which implements the vi-style action which
7082 * moves the cursor to the end of the line, then switches to insert mode
7083 * to allow text to be appended to the line.
7084 */
KT_KEY_FN(gl_vi_append_at_eol)7085 static KT_KEY_FN(gl_vi_append_at_eol)
7086 {
7087 gl_save_for_undo(gl);
7088 gl->vi.command = 0; /* Allow cursor at EOL */
7089 return gl_end_of_line(gl, 0, NULL) ||
7090 gl_vi_insert(gl, 0, NULL);
7091 }
7092
7093 /*.......................................................................
7094 * This is the action function which implements the vi-style action which
7095 * moves the cursor to right one then switches to insert mode, thus
7096 * allowing text to be appended after the next character.
7097 */
KT_KEY_FN(gl_vi_append)7098 static KT_KEY_FN(gl_vi_append)
7099 {
7100 gl_save_for_undo(gl);
7101 gl->vi.command = 0; /* Allow cursor at EOL */
7102 return gl_cursor_right(gl, 1, NULL) ||
7103 gl_vi_insert(gl, 0, NULL);
7104 }
7105
7106 /*.......................................................................
7107 * This action function moves the cursor to the column specified by the
7108 * numeric argument. Column indexes start at 1.
7109 */
KT_KEY_FN(gl_goto_column)7110 static KT_KEY_FN(gl_goto_column)
7111 {
7112 return gl_place_cursor(gl, count - 1);
7113 }
7114
7115 /*.......................................................................
7116 * Starting with the character under the cursor, replace 'count'
7117 * characters with the next character that the user types.
7118 */
KT_KEY_FN(gl_vi_replace_char)7119 static KT_KEY_FN(gl_vi_replace_char)
7120 {
7121 char c; /* The replacement character */
7122 int i;
7123 /*
7124 * Keep a record of the current insert mode.
7125 */
7126 int insert = gl->insert;
7127 /*
7128 * Get the replacement character.
7129 */
7130 if(gl->vi.repeat.active) {
7131 c = gl->vi.repeat.input_char;
7132 } else {
7133 if(gl_read_terminal(gl, 1, &c))
7134 return 1;
7135 gl->vi.repeat.input_char = c;
7136 };
7137 /*
7138 * Are there 'count' characters to be replaced?
7139 */
7140 if(gl->ntotal - gl->buff_curpos >= count) {
7141 /*
7142 * If in vi command mode, preserve the current line for potential
7143 * use by vi-undo.
7144 */
7145 gl_save_for_undo(gl);
7146 /*
7147 * Temporarily switch to overwrite mode.
7148 */
7149 gl->insert = 0;
7150 /*
7151 * Overwrite the current character plus count-1 subsequent characters
7152 * with the replacement character.
7153 */
7154 for(i=0; i<count; i++)
7155 gl_add_char_to_line(gl, c);
7156 /*
7157 * Restore the original insert/overwrite mode.
7158 */
7159 gl->insert = insert;
7160 };
7161 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
7162 }
7163
7164 /*.......................................................................
7165 * This is an action function which changes all characters between the
7166 * current cursor position and the end of the line.
7167 */
KT_KEY_FN(gl_vi_change_rest_of_line)7168 static KT_KEY_FN(gl_vi_change_rest_of_line)
7169 {
7170 gl_save_for_undo(gl);
7171 gl->vi.command = 0; /* Allow cursor at EOL */
7172 return gl_kill_line(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
7173 }
7174
7175 /*.......................................................................
7176 * This is an action function which changes all characters between the
7177 * start of the line and the current cursor position.
7178 */
KT_KEY_FN(gl_vi_change_to_bol)7179 static KT_KEY_FN(gl_vi_change_to_bol)
7180 {
7181 return gl_backward_kill_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL);
7182 }
7183
7184 /*.......................................................................
7185 * This is an action function which deletes the entire contents of the
7186 * current line and switches to insert mode.
7187 */
KT_KEY_FN(gl_vi_change_line)7188 static KT_KEY_FN(gl_vi_change_line)
7189 {
7190 return gl_delete_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL);
7191 }
7192
7193 /*.......................................................................
7194 * Starting from the cursor position and looking towards the end of the
7195 * line, copy 'count' characters to the cut buffer.
7196 */
KT_KEY_FN(gl_forward_copy_char)7197 static KT_KEY_FN(gl_forward_copy_char)
7198 {
7199 /*
7200 * Limit the count to the number of characters available.
7201 */
7202 if(gl->buff_curpos + count >= gl->ntotal)
7203 count = gl->ntotal - gl->buff_curpos;
7204 if(count < 0)
7205 count = 0;
7206 /*
7207 * Copy the characters to the cut buffer.
7208 */
7209 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, count);
7210 gl->cutbuf[count] = '\0';
7211 return 0;
7212 }
7213
7214 /*.......................................................................
7215 * Starting from the character before the cursor position and looking
7216 * backwards towards the start of the line, copy 'count' characters to
7217 * the cut buffer.
7218 */
KT_KEY_FN(gl_backward_copy_char)7219 static KT_KEY_FN(gl_backward_copy_char)
7220 {
7221 /*
7222 * Limit the count to the number of characters available.
7223 */
7224 if(count > gl->buff_curpos)
7225 count = gl->buff_curpos;
7226 if(count < 0)
7227 count = 0;
7228 gl_place_cursor(gl, gl->buff_curpos - count);
7229 /*
7230 * Copy the characters to the cut buffer.
7231 */
7232 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, count);
7233 gl->cutbuf[count] = '\0';
7234 return 0;
7235 }
7236
7237 /*.......................................................................
7238 * Starting from the cursor position copy to the specified column into the
7239 * cut buffer.
7240 */
KT_KEY_FN(gl_copy_to_column)7241 static KT_KEY_FN(gl_copy_to_column)
7242 {
7243 if (--count >= gl->buff_curpos)
7244 return gl_forward_copy_char(gl, count - gl->buff_curpos, NULL);
7245 else
7246 return gl_backward_copy_char(gl, gl->buff_curpos - count, NULL);
7247 }
7248
7249 /*.......................................................................
7250 * Starting from the cursor position copy characters up to a matching
7251 * parenthesis into the cut buffer.
7252 */
KT_KEY_FN(gl_copy_to_parenthesis)7253 static KT_KEY_FN(gl_copy_to_parenthesis)
7254 {
7255 int curpos = gl_index_of_matching_paren(gl);
7256 if(curpos >= 0) {
7257 gl_save_for_undo(gl);
7258 if(curpos >= gl->buff_curpos)
7259 return gl_forward_copy_char(gl, curpos - gl->buff_curpos + 1, NULL);
7260 else
7261 return gl_backward_copy_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
7262 };
7263 return 0;
7264 }
7265
7266 /*.......................................................................
7267 * Starting from the cursor position copy the rest of the line into the
7268 * cut buffer.
7269 */
KT_KEY_FN(gl_copy_rest_of_line)7270 static KT_KEY_FN(gl_copy_rest_of_line)
7271 {
7272 /*
7273 * Copy the characters to the cut buffer.
7274 */
7275 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, gl->ntotal - gl->buff_curpos);
7276 gl->cutbuf[gl->ntotal - gl->buff_curpos] = '\0';
7277 return 0;
7278 }
7279
7280 /*.......................................................................
7281 * Copy from the beginning of the line to the cursor position into the
7282 * cut buffer.
7283 */
KT_KEY_FN(gl_copy_to_bol)7284 static KT_KEY_FN(gl_copy_to_bol)
7285 {
7286 /*
7287 * Copy the characters to the cut buffer.
7288 */
7289 memcpy(gl->cutbuf, gl->line, gl->buff_curpos);
7290 gl->cutbuf[gl->buff_curpos] = '\0';
7291 gl_place_cursor(gl, 0);
7292 return 0;
7293 }
7294
7295 /*.......................................................................
7296 * Copy the entire line into the cut buffer.
7297 */
KT_KEY_FN(gl_copy_line)7298 static KT_KEY_FN(gl_copy_line)
7299 {
7300 /*
7301 * Copy the characters to the cut buffer.
7302 */
7303 memcpy(gl->cutbuf, gl->line, gl->ntotal);
7304 gl->cutbuf[gl->ntotal] = '\0';
7305 return 0;
7306 }
7307
7308 /*.......................................................................
7309 * Search forwards for the next character that the user enters.
7310 */
KT_KEY_FN(gl_forward_find_char)7311 static KT_KEY_FN(gl_forward_find_char)
7312 {
7313 int pos = gl_find_char(gl, count, 1, 1, '\0');
7314 return pos >= 0 && gl_place_cursor(gl, pos);
7315 }
7316
7317 /*.......................................................................
7318 * Search backwards for the next character that the user enters.
7319 */
KT_KEY_FN(gl_backward_find_char)7320 static KT_KEY_FN(gl_backward_find_char)
7321 {
7322 int pos = gl_find_char(gl, count, 0, 1, '\0');
7323 return pos >= 0 && gl_place_cursor(gl, pos);
7324 }
7325
7326 /*.......................................................................
7327 * Search forwards for the next character that the user enters. Move up to,
7328 * but not onto, the found character.
7329 */
KT_KEY_FN(gl_forward_to_char)7330 static KT_KEY_FN(gl_forward_to_char)
7331 {
7332 int pos = gl_find_char(gl, count, 1, 0, '\0');
7333 return pos >= 0 && gl_place_cursor(gl, pos);
7334 }
7335
7336 /*.......................................................................
7337 * Search backwards for the next character that the user enters. Move back to,
7338 * but not onto, the found character.
7339 */
KT_KEY_FN(gl_backward_to_char)7340 static KT_KEY_FN(gl_backward_to_char)
7341 {
7342 int pos = gl_find_char(gl, count, 0, 0, '\0');
7343 return pos >= 0 && gl_place_cursor(gl, pos);
7344 }
7345
7346 /*.......................................................................
7347 * Searching in a given direction, return the index of a given (or
7348 * read) character in the input line, or the character that precedes
7349 * it in the specified search direction. Return -1 if not found.
7350 *
7351 * Input:
7352 * gl GetLine * The getline resource object.
7353 * count int The number of times to search.
7354 * forward int True if searching forward.
7355 * onto int True if the search should end on top of the
7356 * character, false if the search should stop
7357 * one character before the character in the
7358 * specified search direction.
7359 * c char The character to be sought, or '\0' if the
7360 * character should be read from the user.
7361 * Output:
7362 * return int The index of the character in gl->line[], or
7363 * -1 if not found.
7364 */
gl_find_char(GetLine * gl,int count,int forward,int onto,char c)7365 static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c)
7366 {
7367 int pos; /* The index reached in searching the input line */
7368 int i;
7369 /*
7370 * Get a character from the user?
7371 */
7372 if(!c) {
7373 /*
7374 * If we are in the process of repeating a previous change command, substitute
7375 * the last find character.
7376 */
7377 if(gl->vi.repeat.active) {
7378 c = gl->vi.find_char;
7379 } else {
7380 if(gl_read_terminal(gl, 1, &c))
7381 return -1;
7382 /*
7383 * Record the details of the new search, for use by repeat finds.
7384 */
7385 gl->vi.find_forward = forward;
7386 gl->vi.find_onto = onto;
7387 gl->vi.find_char = c;
7388 };
7389 };
7390 /*
7391 * Which direction should we search?
7392 */
7393 if(forward) {
7394 /*
7395 * Search forwards 'count' times for the character, starting with the
7396 * character that follows the cursor.
7397 */
7398 for(i=0, pos=gl->buff_curpos; i<count && pos < gl->ntotal; i++) {
7399 /*
7400 * Advance past the last match (or past the current cursor position
7401 * on the first search).
7402 */
7403 pos++;
7404 /*
7405 * Search for the next instance of c.
7406 */
7407 for( ; pos<gl->ntotal && c!=gl->line[pos]; pos++)
7408 ;
7409 };
7410 /*
7411 * If the character was found and we have been requested to return the
7412 * position of the character that precedes the desired character, then
7413 * we have gone one character too far.
7414 */
7415 if(!onto && pos<gl->ntotal)
7416 pos--;
7417 } else {
7418 /*
7419 * Search backwards 'count' times for the character, starting with the
7420 * character that precedes the cursor.
7421 */
7422 for(i=0, pos=gl->buff_curpos; i<count && pos >= gl->insert_curpos; i++) {
7423 /*
7424 * Step back one from the last match (or from the current cursor
7425 * position on the first search).
7426 */
7427 pos--;
7428 /*
7429 * Search for the next instance of c.
7430 */
7431 for( ; pos>=gl->insert_curpos && c!=gl->line[pos]; pos--)
7432 ;
7433 };
7434 /*
7435 * If the character was found and we have been requested to return the
7436 * position of the character that precedes the desired character, then
7437 * we have gone one character too far.
7438 */
7439 if(!onto && pos>=gl->insert_curpos)
7440 pos++;
7441 };
7442 /*
7443 * If found, return the cursor position of the count'th match.
7444 * Otherwise ring the terminal bell.
7445 */
7446 if(pos >= gl->insert_curpos && pos < gl->ntotal) {
7447 return pos;
7448 } else {
7449 (void) gl_ring_bell(gl, 1, NULL);
7450 return -1;
7451 }
7452 }
7453
7454 /*.......................................................................
7455 * Repeat the last character search in the same direction as the last
7456 * search.
7457 */
KT_KEY_FN(gl_repeat_find_char)7458 static KT_KEY_FN(gl_repeat_find_char)
7459 {
7460 int pos = gl->vi.find_char ?
7461 gl_find_char(gl, count, gl->vi.find_forward, gl->vi.find_onto,
7462 gl->vi.find_char) : -1;
7463 return pos >= 0 && gl_place_cursor(gl, pos);
7464 }
7465
7466 /*.......................................................................
7467 * Repeat the last character search in the opposite direction as the last
7468 * search.
7469 */
KT_KEY_FN(gl_invert_refind_char)7470 static KT_KEY_FN(gl_invert_refind_char)
7471 {
7472 int pos = gl->vi.find_char ?
7473 gl_find_char(gl, count, !gl->vi.find_forward, gl->vi.find_onto,
7474 gl->vi.find_char) : -1;
7475 return pos >= 0 && gl_place_cursor(gl, pos);
7476 }
7477
7478 /*.......................................................................
7479 * Search forward from the current position of the cursor for 'count'
7480 * word endings, returning the index of the last one found, or the end of
7481 * the line if there were less than 'count' words.
7482 *
7483 * Input:
7484 * gl GetLine * The getline resource object.
7485 * n int The number of word boundaries to search for.
7486 * Output:
7487 * return int The buffer index of the located position.
7488 */
gl_nth_word_end_forward(GetLine * gl,int n)7489 static int gl_nth_word_end_forward(GetLine *gl, int n)
7490 {
7491 int bufpos; /* The buffer index being checked. */
7492 int i;
7493 /*
7494 * In order to guarantee forward motion to the next word ending,
7495 * we need to start from one position to the right of the cursor
7496 * position, since this may already be at the end of a word.
7497 */
7498 bufpos = gl->buff_curpos + 1;
7499 /*
7500 * If we are at the end of the line, return the index of the last
7501 * real character on the line. Note that this will be -1 if the line
7502 * is empty.
7503 */
7504 if(bufpos >= gl->ntotal)
7505 return gl->ntotal - 1;
7506 /*
7507 * Search 'n' times, unless the end of the input line is reached first.
7508 */
7509 for(i=0; i<n && bufpos<gl->ntotal; i++) {
7510 /*
7511 * If we are not already within a word, skip to the start of the next word.
7512 */
7513 for( ; bufpos<gl->ntotal && !gl_is_word_char((int)gl->line[bufpos]);
7514 bufpos++)
7515 ;
7516 /*
7517 * Find the end of the next word.
7518 */
7519 for( ; bufpos<gl->ntotal && gl_is_word_char((int)gl->line[bufpos]);
7520 bufpos++)
7521 ;
7522 };
7523 /*
7524 * We will have overshot.
7525 */
7526 return bufpos > 0 ? bufpos-1 : bufpos;
7527 }
7528
7529 /*.......................................................................
7530 * Search forward from the current position of the cursor for 'count'
7531 * word starts, returning the index of the last one found, or the end of
7532 * the line if there were less than 'count' words.
7533 *
7534 * Input:
7535 * gl GetLine * The getline resource object.
7536 * n int The number of word boundaries to search for.
7537 * Output:
7538 * return int The buffer index of the located position.
7539 */
gl_nth_word_start_forward(GetLine * gl,int n)7540 static int gl_nth_word_start_forward(GetLine *gl, int n)
7541 {
7542 int bufpos; /* The buffer index being checked. */
7543 int i;
7544 /*
7545 * Get the current cursor position.
7546 */
7547 bufpos = gl->buff_curpos;
7548 /*
7549 * Search 'n' times, unless the end of the input line is reached first.
7550 */
7551 for(i=0; i<n && bufpos<gl->ntotal; i++) {
7552 /*
7553 * Find the end of the current word.
7554 */
7555 for( ; bufpos<gl->ntotal && gl_is_word_char((int)gl->line[bufpos]);
7556 bufpos++)
7557 ;
7558 /*
7559 * Skip to the start of the next word.
7560 */
7561 for( ; bufpos<gl->ntotal && !gl_is_word_char((int)gl->line[bufpos]);
7562 bufpos++)
7563 ;
7564 };
7565 return bufpos;
7566 }
7567
7568 /*.......................................................................
7569 * Search backward from the current position of the cursor for 'count'
7570 * word starts, returning the index of the last one found, or the start
7571 * of the line if there were less than 'count' words.
7572 *
7573 * Input:
7574 * gl GetLine * The getline resource object.
7575 * n int The number of word boundaries to search for.
7576 * Output:
7577 * return int The buffer index of the located position.
7578 */
gl_nth_word_start_backward(GetLine * gl,int n)7579 static int gl_nth_word_start_backward(GetLine *gl, int n)
7580 {
7581 int bufpos; /* The buffer index being checked. */
7582 int i;
7583 /*
7584 * Get the current cursor position.
7585 */
7586 bufpos = gl->buff_curpos;
7587 /*
7588 * Search 'n' times, unless the beginning of the input line (or vi insertion
7589 * point) is reached first.
7590 */
7591 for(i=0; i<n && bufpos > gl->insert_curpos; i++) {
7592 /*
7593 * Starting one character back from the last search, so as not to keep
7594 * settling on the same word-start, search backwards until finding a
7595 * word character.
7596 */
7597 while(--bufpos >= gl->insert_curpos &&
7598 !gl_is_word_char((int)gl->line[bufpos]))
7599 ;
7600 /*
7601 * Find the start of the word.
7602 */
7603 while(--bufpos >= gl->insert_curpos &&
7604 gl_is_word_char((int)gl->line[bufpos]))
7605 ;
7606 /*
7607 * We will have gone one character too far.
7608 */
7609 bufpos++;
7610 };
7611 return bufpos >= gl->insert_curpos ? bufpos : gl->insert_curpos;
7612 }
7613
7614 /*.......................................................................
7615 * Copy one or more words into the cut buffer without moving the cursor
7616 * or deleting text.
7617 */
KT_KEY_FN(gl_forward_copy_word)7618 static KT_KEY_FN(gl_forward_copy_word)
7619 {
7620 /*
7621 * Find the location of the count'th start or end of a word
7622 * after the cursor, depending on whether in emacs or vi mode.
7623 */
7624 int next = gl->editor == GL_EMACS_MODE ?
7625 gl_nth_word_end_forward(gl, count) :
7626 gl_nth_word_start_forward(gl, count);
7627 /*
7628 * How many characters are to be copied into the cut buffer?
7629 */
7630 int n = next - gl->buff_curpos;
7631 /*
7632 * Copy the specified segment and terminate the string.
7633 */
7634 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, n);
7635 gl->cutbuf[n] = '\0';
7636 return 0;
7637 }
7638
7639 /*.......................................................................
7640 * Copy one or more words preceding the cursor into the cut buffer,
7641 * without moving the cursor or deleting text.
7642 */
KT_KEY_FN(gl_backward_copy_word)7643 static KT_KEY_FN(gl_backward_copy_word)
7644 {
7645 /*
7646 * Find the location of the count'th start of word before the cursor.
7647 */
7648 int next = gl_nth_word_start_backward(gl, count);
7649 /*
7650 * How many characters are to be copied into the cut buffer?
7651 */
7652 int n = gl->buff_curpos - next;
7653 gl_place_cursor(gl, next);
7654 /*
7655 * Copy the specified segment and terminate the string.
7656 */
7657 memcpy(gl->cutbuf, gl->line + next, n);
7658 gl->cutbuf[n] = '\0';
7659 return 0;
7660 }
7661
7662 /*.......................................................................
7663 * Copy the characters between the cursor and the count'th instance of
7664 * a specified character in the input line, into the cut buffer.
7665 *
7666 * Input:
7667 * gl GetLine * The getline resource object.
7668 * count int The number of times to search.
7669 * c char The character to be searched for, or '\0' if
7670 * the character should be read from the user.
7671 * forward int True if searching forward.
7672 * onto int True if the search should end on top of the
7673 * character, false if the search should stop
7674 * one character before the character in the
7675 * specified search direction.
7676 * Output:
7677 * return int 0 - OK.
7678 * 1 - Error.
7679 *
7680 */
gl_copy_find(GetLine * gl,int count,char c,int forward,int onto)7681 static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto)
7682 {
7683 int n; /* The number of characters in the cut buffer */
7684 /*
7685 * Search for the character, and abort the operation if not found.
7686 */
7687 int pos = gl_find_char(gl, count, forward, onto, c);
7688 if(pos < 0)
7689 return 0;
7690 /*
7691 * Copy the specified segment.
7692 */
7693 if(forward) {
7694 n = pos + 1 - gl->buff_curpos;
7695 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, n);
7696 } else {
7697 n = gl->buff_curpos - pos;
7698 memcpy(gl->cutbuf, gl->line + pos, n);
7699 if(gl->editor == GL_VI_MODE)
7700 gl_place_cursor(gl, pos);
7701 }
7702 /*
7703 * Terminate the copy.
7704 */
7705 gl->cutbuf[n] = '\0';
7706 return 0;
7707 }
7708
7709 /*.......................................................................
7710 * Copy a section up to and including a specified character into the cut
7711 * buffer without moving the cursor or deleting text.
7712 */
KT_KEY_FN(gl_forward_copy_find)7713 static KT_KEY_FN(gl_forward_copy_find)
7714 {
7715 return gl_copy_find(gl, count, '\0', 1, 1);
7716 }
7717
7718 /*.......................................................................
7719 * Copy a section back to and including a specified character into the cut
7720 * buffer without moving the cursor or deleting text.
7721 */
KT_KEY_FN(gl_backward_copy_find)7722 static KT_KEY_FN(gl_backward_copy_find)
7723 {
7724 return gl_copy_find(gl, count, '\0', 0, 1);
7725 }
7726
7727 /*.......................................................................
7728 * Copy a section up to and not including a specified character into the cut
7729 * buffer without moving the cursor or deleting text.
7730 */
KT_KEY_FN(gl_forward_copy_to)7731 static KT_KEY_FN(gl_forward_copy_to)
7732 {
7733 return gl_copy_find(gl, count, '\0', 1, 0);
7734 }
7735
7736 /*.......................................................................
7737 * Copy a section back to and not including a specified character into the cut
7738 * buffer without moving the cursor or deleting text.
7739 */
KT_KEY_FN(gl_backward_copy_to)7740 static KT_KEY_FN(gl_backward_copy_to)
7741 {
7742 return gl_copy_find(gl, count, '\0', 0, 0);
7743 }
7744
7745 /*.......................................................................
7746 * Copy to a character specified in a previous search into the cut
7747 * buffer without moving the cursor or deleting text.
7748 */
KT_KEY_FN(gl_copy_refind)7749 static KT_KEY_FN(gl_copy_refind)
7750 {
7751 return gl_copy_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
7752 gl->vi.find_onto);
7753 }
7754
7755 /*.......................................................................
7756 * Copy to a character specified in a previous search, but in the opposite
7757 * direction, into the cut buffer without moving the cursor or deleting text.
7758 */
KT_KEY_FN(gl_copy_invert_refind)7759 static KT_KEY_FN(gl_copy_invert_refind)
7760 {
7761 return gl_copy_find(gl, count, gl->vi.find_char, !gl->vi.find_forward,
7762 gl->vi.find_onto);
7763 }
7764
7765 /*.......................................................................
7766 * Set the position of the cursor in the line input buffer and the
7767 * terminal.
7768 *
7769 * Input:
7770 * gl GetLine * The getline resource object.
7771 * buff_curpos int The new buffer cursor position.
7772 * Output:
7773 * return int 0 - OK.
7774 * 1 - Error.
7775 */
gl_place_cursor(GetLine * gl,int buff_curpos)7776 static int gl_place_cursor(GetLine *gl, int buff_curpos)
7777 {
7778 /*
7779 * Don't allow the cursor position to go out of the bounds of the input
7780 * line.
7781 */
7782 if(buff_curpos >= gl->ntotal)
7783 buff_curpos = gl->vi.command ? gl->ntotal-1 : gl->ntotal;
7784 if(buff_curpos < 0)
7785 buff_curpos = 0;
7786 /*
7787 * Record the new buffer position.
7788 */
7789 gl->buff_curpos = buff_curpos;
7790 /*
7791 * Move the terminal cursor to the corresponding character.
7792 */
7793 return gl_set_term_curpos(gl, gl->prompt_len +
7794 gl_displayed_string_width(gl, gl->line, buff_curpos, gl->prompt_len));
7795 }
7796
7797 /*.......................................................................
7798 * In vi command mode, this function saves the current line to the
7799 * historical buffer needed by the undo command. In emacs mode it does
7800 * nothing. In order to allow action functions to call other action
7801 * functions, gl_interpret_char() sets gl->vi.undo.saved to 0 before
7802 * invoking an action, and thereafter once any call to this function
7803 * has set it to 1, further calls are ignored.
7804 *
7805 * Input:
7806 * gl GetLine * The getline resource object.
7807 */
gl_save_for_undo(GetLine * gl)7808 static void gl_save_for_undo(GetLine *gl)
7809 {
7810 if(gl->vi.command && !gl->vi.undo.saved) {
7811 strlcpy(gl->vi.undo.line, gl->line, gl->linelen);
7812 gl->vi.undo.buff_curpos = gl->buff_curpos;
7813 gl->vi.undo.ntotal = gl->ntotal;
7814 gl->vi.undo.saved = 1;
7815 };
7816 if(gl->vi.command && !gl->vi.repeat.saved &&
7817 gl->current_action.fn != gl_vi_repeat_change) {
7818 gl->vi.repeat.action = gl->current_action;
7819 gl->vi.repeat.count = gl->current_count;
7820 gl->vi.repeat.saved = 1;
7821 };
7822 return;
7823 }
7824
7825 /*.......................................................................
7826 * In vi mode, restore the line to the way it was before the last command
7827 * mode operation, storing the current line in the buffer so that the
7828 * undo operation itself can subsequently be undone.
7829 */
KT_KEY_FN(gl_vi_undo)7830 static KT_KEY_FN(gl_vi_undo)
7831 {
7832 /*
7833 * Get pointers into the two lines.
7834 */
7835 char *undo_ptr = gl->vi.undo.line;
7836 char *line_ptr = gl->line;
7837 /*
7838 * Swap the characters of the two buffers up to the length of the shortest
7839 * line.
7840 */
7841 while(*undo_ptr && *line_ptr) {
7842 char c = *undo_ptr;
7843 *undo_ptr++ = *line_ptr;
7844 *line_ptr++ = c;
7845 };
7846 /*
7847 * Copy the rest directly.
7848 */
7849 if(gl->ntotal > gl->vi.undo.ntotal) {
7850 strlcpy(undo_ptr, line_ptr, gl->linelen);
7851 *line_ptr = '\0';
7852 } else {
7853 strlcpy(line_ptr, undo_ptr, gl->linelen);
7854 *undo_ptr = '\0';
7855 };
7856 /*
7857 * Record the length of the stored string.
7858 */
7859 gl->vi.undo.ntotal = gl->ntotal;
7860 /*
7861 * Accomodate the new contents of gl->line[].
7862 */
7863 gl_update_buffer(gl);
7864 /*
7865 * Set both cursor positions to the leftmost of the saved and current
7866 * cursor positions to emulate what vi does.
7867 */
7868 if(gl->buff_curpos < gl->vi.undo.buff_curpos)
7869 gl->vi.undo.buff_curpos = gl->buff_curpos;
7870 else
7871 gl->buff_curpos = gl->vi.undo.buff_curpos;
7872 /*
7873 * Since we have bipassed calling gl_save_for_undo(), record repeat
7874 * information inline.
7875 */
7876 gl->vi.repeat.action.fn = gl_vi_undo;
7877 gl->vi.repeat.action.data = NULL;
7878 gl->vi.repeat.count = 1;
7879 /*
7880 * Display the restored line.
7881 */
7882 gl_queue_redisplay(gl);
7883 return 0;
7884 }
7885
7886 /*.......................................................................
7887 * Delete the following word and leave the user in vi insert mode.
7888 */
KT_KEY_FN(gl_vi_forward_change_word)7889 static KT_KEY_FN(gl_vi_forward_change_word)
7890 {
7891 gl_save_for_undo(gl);
7892 gl->vi.command = 0; /* Allow cursor at EOL */
7893 return gl_forward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
7894 }
7895
7896 /*.......................................................................
7897 * Delete the preceding word and leave the user in vi insert mode.
7898 */
KT_KEY_FN(gl_vi_backward_change_word)7899 static KT_KEY_FN(gl_vi_backward_change_word)
7900 {
7901 return gl_backward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
7902 }
7903
7904 /*.......................................................................
7905 * Delete the following section and leave the user in vi insert mode.
7906 */
KT_KEY_FN(gl_vi_forward_change_find)7907 static KT_KEY_FN(gl_vi_forward_change_find)
7908 {
7909 return gl_delete_find(gl, count, '\0', 1, 1, 1);
7910 }
7911
7912 /*.......................................................................
7913 * Delete the preceding section and leave the user in vi insert mode.
7914 */
KT_KEY_FN(gl_vi_backward_change_find)7915 static KT_KEY_FN(gl_vi_backward_change_find)
7916 {
7917 return gl_delete_find(gl, count, '\0', 0, 1, 1);
7918 }
7919
7920 /*.......................................................................
7921 * Delete the following section and leave the user in vi insert mode.
7922 */
KT_KEY_FN(gl_vi_forward_change_to)7923 static KT_KEY_FN(gl_vi_forward_change_to)
7924 {
7925 return gl_delete_find(gl, count, '\0', 1, 0, 1);
7926 }
7927
7928 /*.......................................................................
7929 * Delete the preceding section and leave the user in vi insert mode.
7930 */
KT_KEY_FN(gl_vi_backward_change_to)7931 static KT_KEY_FN(gl_vi_backward_change_to)
7932 {
7933 return gl_delete_find(gl, count, '\0', 0, 0, 1);
7934 }
7935
7936 /*.......................................................................
7937 * Delete to a character specified by a previous search and leave the user
7938 * in vi insert mode.
7939 */
KT_KEY_FN(gl_vi_change_refind)7940 static KT_KEY_FN(gl_vi_change_refind)
7941 {
7942 return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
7943 gl->vi.find_onto, 1);
7944 }
7945
7946 /*.......................................................................
7947 * Delete to a character specified by a previous search, but in the opposite
7948 * direction, and leave the user in vi insert mode.
7949 */
KT_KEY_FN(gl_vi_change_invert_refind)7950 static KT_KEY_FN(gl_vi_change_invert_refind)
7951 {
7952 return gl_delete_find(gl, count, gl->vi.find_char, !gl->vi.find_forward,
7953 gl->vi.find_onto, 1);
7954 }
7955
7956 /*.......................................................................
7957 * Delete the following character and leave the user in vi insert mode.
7958 */
KT_KEY_FN(gl_vi_forward_change_char)7959 static KT_KEY_FN(gl_vi_forward_change_char)
7960 {
7961 gl_save_for_undo(gl);
7962 gl->vi.command = 0; /* Allow cursor at EOL */
7963 return gl_delete_chars(gl, count, 1) || gl_vi_insert(gl, 0, NULL);
7964 }
7965
7966 /*.......................................................................
7967 * Delete the preceding character and leave the user in vi insert mode.
7968 */
KT_KEY_FN(gl_vi_backward_change_char)7969 static KT_KEY_FN(gl_vi_backward_change_char)
7970 {
7971 return gl_backward_delete_char(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
7972 }
7973
7974 /*.......................................................................
7975 * Starting from the cursor position change characters to the specified column.
7976 */
KT_KEY_FN(gl_vi_change_to_column)7977 static KT_KEY_FN(gl_vi_change_to_column)
7978 {
7979 if (--count >= gl->buff_curpos)
7980 return gl_vi_forward_change_char(gl, count - gl->buff_curpos, NULL);
7981 else
7982 return gl_vi_backward_change_char(gl, gl->buff_curpos - count, NULL);
7983 }
7984
7985 /*.......................................................................
7986 * Starting from the cursor position change characters to a matching
7987 * parenthesis.
7988 */
KT_KEY_FN(gl_vi_change_to_parenthesis)7989 static KT_KEY_FN(gl_vi_change_to_parenthesis)
7990 {
7991 int curpos = gl_index_of_matching_paren(gl);
7992 if(curpos >= 0) {
7993 gl_save_for_undo(gl);
7994 if(curpos >= gl->buff_curpos)
7995 return gl_vi_forward_change_char(gl, curpos - gl->buff_curpos + 1, NULL);
7996 else
7997 return gl_vi_backward_change_char(gl, ++gl->buff_curpos - curpos + 1,
7998 NULL);
7999 };
8000 return 0;
8001 }
8002
8003 /*.......................................................................
8004 * If in vi mode, switch to vi command mode.
8005 *
8006 * Input:
8007 * gl GetLine * The getline resource object.
8008 */
gl_vi_command_mode(GetLine * gl)8009 static void gl_vi_command_mode(GetLine *gl)
8010 {
8011 if(gl->editor == GL_VI_MODE && !gl->vi.command) {
8012 gl->insert = 1;
8013 gl->vi.command = 1;
8014 gl->vi.repeat.input_curpos = gl->insert_curpos;
8015 gl->vi.repeat.command_curpos = gl->buff_curpos;
8016 gl->insert_curpos = 0; /* unrestrict left motion boundary */
8017 gl_cursor_left(gl, 1, NULL); /* Vi moves 1 left on entering command mode */
8018 };
8019 }
8020
8021 /*.......................................................................
8022 * This is an action function which rings the terminal bell.
8023 */
KT_KEY_FN(gl_ring_bell)8024 static KT_KEY_FN(gl_ring_bell)
8025 {
8026 return gl->silence_bell ? 0 :
8027 gl_print_control_sequence(gl, 1, gl->sound_bell);
8028 }
8029
8030 /*.......................................................................
8031 * This is the action function which implements the vi-repeat-change
8032 * action.
8033 */
KT_KEY_FN(gl_vi_repeat_change)8034 static KT_KEY_FN(gl_vi_repeat_change)
8035 {
8036 int status; /* The return status of the repeated action function */
8037 int i;
8038 /*
8039 * Nothing to repeat?
8040 */
8041 if(!gl->vi.repeat.action.fn)
8042 return gl_ring_bell(gl, 1, NULL);
8043 /*
8044 * Provide a way for action functions to know whether they are being
8045 * called by us.
8046 */
8047 gl->vi.repeat.active = 1;
8048 /*
8049 * Re-run the recorded function.
8050 */
8051 status = gl->vi.repeat.action.fn(gl, gl->vi.repeat.count,
8052 gl->vi.repeat.action.data);
8053 /*
8054 * Mark the repeat as completed.
8055 */
8056 gl->vi.repeat.active = 0;
8057 /*
8058 * Is we are repeating a function that has just switched to input
8059 * mode to allow the user to type, re-enter the text that the user
8060 * previously entered.
8061 */
8062 if(status==0 && !gl->vi.command) {
8063 /*
8064 * Make sure that the current line has been saved.
8065 */
8066 gl_save_for_undo(gl);
8067 /*
8068 * Repeat a previous insertion or overwrite?
8069 */
8070 if(gl->vi.repeat.input_curpos >= 0 &&
8071 gl->vi.repeat.input_curpos <= gl->vi.repeat.command_curpos &&
8072 gl->vi.repeat.command_curpos <= gl->vi.undo.ntotal) {
8073 /*
8074 * Using the current line which is saved in the undo buffer, plus
8075 * the range of characters therein, as recorded by gl_vi_command_mode(),
8076 * add the characters that the user previously entered, to the input
8077 * line.
8078 */
8079 for(i=gl->vi.repeat.input_curpos; i<gl->vi.repeat.command_curpos; i++) {
8080 if(gl_add_char_to_line(gl, gl->vi.undo.line[i]))
8081 return 1;
8082 };
8083 };
8084 /*
8085 * Switch back to command mode, now that the insertion has been repeated.
8086 */
8087 gl_vi_command_mode(gl);
8088 };
8089 return status;
8090 }
8091
8092 /*.......................................................................
8093 * If the cursor is currently over a parenthesis character, return the
8094 * index of its matching parenthesis. If not currently over a parenthesis
8095 * character, return the next close parenthesis character to the right of
8096 * the cursor. If the respective parenthesis character isn't found,
8097 * ring the terminal bell and return -1.
8098 *
8099 * Input:
8100 * gl GetLine * The getline resource object.
8101 * Output:
8102 * return int Either the index of the matching parenthesis,
8103 * or -1 if not found.
8104 */
gl_index_of_matching_paren(GetLine * gl)8105 static int gl_index_of_matching_paren(GetLine *gl)
8106 {
8107 int i;
8108 /*
8109 * List the recognized parentheses, and their matches.
8110 */
8111 const char *o_paren = "([{";
8112 const char *c_paren = ")]}";
8113 const char *cptr;
8114 /*
8115 * Get the character that is currently under the cursor.
8116 */
8117 char c = gl->line[gl->buff_curpos];
8118 /*
8119 * If the character under the cursor is an open parenthesis, look forward
8120 * for the matching close parenthesis.
8121 */
8122 if((cptr=strchr(o_paren, c))) {
8123 char match = c_paren[cptr - o_paren];
8124 int matches_needed = 1;
8125 for(i=gl->buff_curpos+1; i<gl->ntotal; i++) {
8126 if(gl->line[i] == c)
8127 matches_needed++;
8128 else if(gl->line[i] == match && --matches_needed==0)
8129 return i;
8130 };
8131 /*
8132 * If the character under the cursor is an close parenthesis, look forward
8133 * for the matching open parenthesis.
8134 */
8135 } else if((cptr=strchr(c_paren, c))) {
8136 char match = o_paren[cptr - c_paren];
8137 int matches_needed = 1;
8138 for(i=gl->buff_curpos-1; i>=0; i--) {
8139 if(gl->line[i] == c)
8140 matches_needed++;
8141 else if(gl->line[i] == match && --matches_needed==0)
8142 return i;
8143 };
8144 /*
8145 * If not currently over a parenthesis character, search forwards for
8146 * the first close parenthesis (this is what the vi % binding does).
8147 */
8148 } else {
8149 for(i=gl->buff_curpos+1; i<gl->ntotal; i++)
8150 if(strchr(c_paren, gl->line[i]) != NULL)
8151 return i;
8152 };
8153 /*
8154 * Not found.
8155 */
8156 (void) gl_ring_bell(gl, 1, NULL);
8157 return -1;
8158 }
8159
8160 /*.......................................................................
8161 * If the cursor is currently over a parenthesis character, this action
8162 * function moves the cursor to its matching parenthesis.
8163 */
KT_KEY_FN(gl_find_parenthesis)8164 static KT_KEY_FN(gl_find_parenthesis)
8165 {
8166 int curpos = gl_index_of_matching_paren(gl);
8167 if(curpos >= 0)
8168 return gl_place_cursor(gl, curpos);
8169 return 0;
8170 }
8171
8172 /*.......................................................................
8173 * Handle the receipt of the potential start of a new key-sequence from
8174 * the user.
8175 *
8176 * Input:
8177 * gl GetLine * The resource object of this library.
8178 * first_char char The first character of the sequence.
8179 * Output:
8180 * return int 0 - OK.
8181 * 1 - Error.
8182 */
gl_interpret_char(GetLine * gl,char first_char)8183 static int gl_interpret_char(GetLine *gl, char first_char)
8184 {
8185 char keyseq[GL_KEY_MAX+1]; /* A special key sequence being read */
8186 int nkey=0; /* The number of characters in the key sequence */
8187 int count; /* The repeat count of an action function */
8188 int ret; /* The return value of an action function */
8189 int i;
8190 /*
8191 * Get the first character.
8192 */
8193 char c = first_char;
8194 /*
8195 * If editing is disabled, just add newly entered characters to the
8196 * input line buffer, and watch for the end of the line.
8197 */
8198 if(gl->editor == GL_NO_EDITOR) {
8199 gl_discard_chars(gl, 1);
8200 if(gl->ntotal >= gl->linelen)
8201 return 0;
8202 if(c == '\n' || c == '\r')
8203 return gl_newline(gl, 1, NULL);
8204 gl_buffer_char(gl, c, gl->ntotal);
8205 return 0;
8206 };
8207 /*
8208 * If the user is in the process of specifying a repeat count and the
8209 * new character is a digit, increment the repeat count accordingly.
8210 */
8211 if(gl->number >= 0 && isdigit((int)(unsigned char) c)) {
8212 gl_discard_chars(gl, 1);
8213 return gl_digit_argument(gl, c, NULL);
8214 /*
8215 * In vi command mode, all key-sequences entered need to be
8216 * either implicitly or explicitly prefixed with an escape character.
8217 */
8218 } else if(gl->vi.command && c != GL_ESC_CHAR) {
8219 keyseq[nkey++] = GL_ESC_CHAR;
8220 /*
8221 * If the first character of the sequence is a printable character,
8222 * then to avoid confusion with the special "up", "down", "left"
8223 * or "right" cursor key bindings, we need to prefix the
8224 * printable character with a backslash escape before looking it up.
8225 */
8226 } else if(!IS_META_CHAR(c) && !IS_CTRL_CHAR(c)) {
8227 keyseq[nkey++] = '\\';
8228 };
8229 /*
8230 * Compose a potentially multiple key-sequence in gl->keyseq.
8231 */
8232 while(nkey < GL_KEY_MAX) {
8233 KtAction *action; /* An action function */
8234 KeySym *keysym; /* The symbol-table entry of a key-sequence */
8235 int nsym; /* The number of ambiguously matching key-sequences */
8236 /*
8237 * If the character is an unprintable meta character, split it
8238 * into two characters, an escape character and the character
8239 * that was modified by the meta key.
8240 */
8241 if(IS_META_CHAR(c)) {
8242 keyseq[nkey++] = GL_ESC_CHAR;
8243 c = META_TO_CHAR(c);
8244 continue;
8245 };
8246 /*
8247 * Append the latest character to the key sequence.
8248 */
8249 keyseq[nkey++] = c;
8250 /*
8251 * When doing vi-style editing, an escape at the beginning of any binding
8252 * switches to command mode.
8253 */
8254 if(keyseq[0] == GL_ESC_CHAR && !gl->vi.command)
8255 gl_vi_command_mode(gl);
8256 /*
8257 * Lookup the key sequence.
8258 */
8259 switch(_kt_lookup_keybinding(gl->bindings, keyseq, nkey, &keysym, &nsym)) {
8260 case KT_EXACT_MATCH:
8261 /*
8262 * Get the matching action function.
8263 */
8264 action = keysym->actions + keysym->binder;
8265 /*
8266 * Get the repeat count, passing the last keystroke if executing the
8267 * digit-argument action.
8268 */
8269 if(action->fn == gl_digit_argument) {
8270 count = c;
8271 } else {
8272 count = gl->number >= 0 ? gl->number : 1;
8273 };
8274 /*
8275 * Record the function that is being invoked.
8276 */
8277 gl->current_action = *action;
8278 gl->current_count = count;
8279 /*
8280 * Mark the current line as not yet preserved for use by the vi undo command.
8281 */
8282 gl->vi.undo.saved = 0;
8283 gl->vi.repeat.saved = 0;
8284 /*
8285 * Execute the action function. Note the action function can tell
8286 * whether the provided repeat count was defaulted or specified
8287 * explicitly by looking at whether gl->number is -1 or not. If
8288 * it is negative, then no repeat count was specified by the user.
8289 */
8290 ret = action->fn(gl, count, action->data);
8291 /*
8292 * In server mode, the action will return immediately if it tries to
8293 * read input from the terminal, and no input is currently available.
8294 * If this happens, abort. Note that gl_get_input_line() will rewind
8295 * the read-ahead buffer to allow the next call to redo the function
8296 * from scratch.
8297 */
8298 if(gl->rtn_status == GLR_BLOCKED && gl->pending_io==GLP_READ)
8299 return 1;
8300 /*
8301 * Discard the now processed characters from the key sequence buffer.
8302 */
8303 gl_discard_chars(gl, gl->nread);
8304 /*
8305 * If the latest action function wasn't a history action, cancel any
8306 * current history search.
8307 */
8308 if(gl->last_search != gl->keyseq_count)
8309 _glh_cancel_search(gl->glh);
8310 /*
8311 * Reset the repeat count after running action functions.
8312 */
8313 if(action->fn != gl_digit_argument)
8314 gl->number = -1;
8315 return ret ? 1 : 0;
8316 break;
8317 case KT_AMBIG_MATCH: /* Ambiguous match - so read the next character */
8318 if(gl_read_terminal(gl, 1, &c))
8319 return 1;
8320 break;
8321 case KT_NO_MATCH:
8322 /*
8323 * If the first character looked like it might be a prefix of a key-sequence
8324 * but it turned out not to be, ring the bell to tell the user that it
8325 * wasn't recognised.
8326 */
8327 if(keyseq[0] != '\\' && keyseq[0] != '\t') {
8328 gl_ring_bell(gl, 1, NULL);
8329 } else {
8330 /*
8331 * The user typed a single printable character that doesn't match
8332 * the start of any keysequence, so add it to the line in accordance
8333 * with the current repeat count.
8334 */
8335 count = gl->number >= 0 ? gl->number : 1;
8336 for(i=0; i<count; i++)
8337 gl_add_char_to_line(gl, first_char);
8338 gl->number = -1;
8339 };
8340 gl_discard_chars(gl, 1);
8341 _glh_cancel_search(gl->glh);
8342 return 0;
8343 break;
8344 case KT_BAD_MATCH:
8345 gl_ring_bell(gl, 1, NULL);
8346 gl_discard_chars(gl, gl->nread);
8347 _glh_cancel_search(gl->glh);
8348 return 1;
8349 break;
8350 };
8351 };
8352 /*
8353 * If the key sequence was too long to match, ring the bell, then
8354 * discard the first character, so that the next attempt to match a
8355 * key-sequence continues with the next key press. In practice this
8356 * shouldn't happen, since one isn't allowed to bind action functions
8357 * to keysequences that are longer than GL_KEY_MAX.
8358 */
8359 gl_ring_bell(gl, 1, NULL);
8360 gl_discard_chars(gl, 1);
8361 return 0;
8362 }
8363
8364 /*.......................................................................
8365 * Configure the application and/or user-specific behavior of
8366 * gl_get_line().
8367 *
8368 * Note that calling this function between calling new_GetLine() and
8369 * the first call to gl_get_line(), disables the otherwise automatic
8370 * reading of ~/.teclarc on the first call to gl_get_line().
8371 *
8372 * Input:
8373 * gl GetLine * The resource object of this library.
8374 * app_string const char * Either NULL, or a string containing one
8375 * or more .teclarc command lines, separated
8376 * by newline characters. This can be used to
8377 * establish an application-specific
8378 * configuration, without the need for an external
8379 * file. This is particularly useful in embedded
8380 * environments where there is no filesystem.
8381 * app_file const char * Either NULL, or the pathname of an
8382 * application-specific .teclarc file. The
8383 * contents of this file, if provided, are
8384 * read after the contents of app_string[].
8385 * user_file const char * Either NULL, or the pathname of a
8386 * user-specific .teclarc file. Except in
8387 * embedded applications, this should
8388 * usually be "~/.teclarc".
8389 * Output:
8390 * return int 0 - OK.
8391 * 1 - Bad argument(s).
8392 */
gl_configure_getline(GetLine * gl,const char * app_string,const char * app_file,const char * user_file)8393 int gl_configure_getline(GetLine *gl, const char *app_string,
8394 const char *app_file, const char *user_file)
8395 {
8396 sigset_t oldset; /* The signals that were blocked on entry to this function */
8397 int status; /* The return status of _gl_configure_getline() */
8398 /*
8399 * Check the arguments.
8400 */
8401 if(!gl) {
8402 errno = EINVAL;
8403 return 1;
8404 };
8405 /*
8406 * Block all signals.
8407 */
8408 if(gl_mask_signals(gl, &oldset))
8409 return 1;
8410 /*
8411 * Execute the private body of the function while signals are blocked.
8412 */
8413 status = _gl_configure_getline(gl, app_string, app_file, user_file);
8414 /*
8415 * Restore the process signal mask.
8416 */
8417 gl_unmask_signals(gl, &oldset);
8418 return status;
8419 }
8420
8421 /*.......................................................................
8422 * This is the private body of the gl_configure_getline() function. It
8423 * assumes that the caller has checked its arguments and blocked the
8424 * delivery of signals.
8425 */
_gl_configure_getline(GetLine * gl,const char * app_string,const char * app_file,const char * user_file)8426 static int _gl_configure_getline(GetLine *gl, const char *app_string,
8427 const char *app_file, const char *user_file)
8428 {
8429 /*
8430 * Mark getline as having been explicitly configured.
8431 */
8432 gl->configured = 1;
8433 /*
8434 * Start by parsing the configuration string, if provided.
8435 */
8436 if(app_string)
8437 (void) _gl_read_config_string(gl, app_string, KTB_NORM);
8438 /*
8439 * Now parse the application-specific configuration file, if provided.
8440 */
8441 if(app_file)
8442 (void) _gl_read_config_file(gl, app_file, KTB_NORM);
8443 /*
8444 * Finally, parse the user-specific configuration file, if provided.
8445 */
8446 if(user_file)
8447 (void) _gl_read_config_file(gl, user_file, KTB_USER);
8448 /*
8449 * Record the names of the configuration files to allow them to
8450 * be re-read if requested at a later time.
8451 */
8452 if(gl_record_string(&gl->app_file, app_file) ||
8453 gl_record_string(&gl->user_file, user_file)) {
8454 errno = ENOMEM;
8455 _err_record_msg(gl->err,
8456 "Insufficient memory to record tecla configuration file names",
8457 END_ERR_MSG);
8458 return 1;
8459 };
8460 return 0;
8461 }
8462
8463 /*.......................................................................
8464 * Replace a malloc'd string (or NULL), with another malloc'd copy of
8465 * a string (or NULL).
8466 *
8467 * Input:
8468 * sptr char ** On input if *sptr!=NULL, *sptr will be
8469 * free'd and *sptr will be set to NULL. Then,
8470 * on output, if string!=NULL a malloc'd copy
8471 * of this string will be assigned to *sptr.
8472 * string const char * The string to be copied, or NULL to simply
8473 * discard any existing string.
8474 * Output:
8475 * return int 0 - OK.
8476 * 1 - Malloc failure (no error message is generated).
8477 */
gl_record_string(char ** sptr,const char * string)8478 static int gl_record_string(char **sptr, const char *string)
8479 {
8480 /*
8481 * If the original string is the same string, don't do anything.
8482 */
8483 if(*sptr == string || (*sptr && string && strcmp(*sptr, string)==0))
8484 return 0;
8485 /*
8486 * Discard any existing cached string.
8487 */
8488 if(*sptr) {
8489 free(*sptr);
8490 *sptr = NULL;
8491 };
8492 /*
8493 * Allocate memory for a copy of the specified string.
8494 */
8495 if(string) {
8496 size_t ssz = strlen(string) + 1;
8497 *sptr = (char *) malloc(ssz);
8498 if(!*sptr)
8499 return 1;
8500 /*
8501 * Copy the string.
8502 */
8503 strlcpy(*sptr, string, ssz);
8504 };
8505 return 0;
8506 }
8507
8508 #ifndef HIDE_FILE_SYSTEM
8509 /*.......................................................................
8510 * Re-read any application-specific and user-specific files previously
8511 * specified via the gl_configure_getline() function.
8512 */
KT_KEY_FN(gl_read_init_files)8513 static KT_KEY_FN(gl_read_init_files)
8514 {
8515 return _gl_configure_getline(gl, NULL, gl->app_file, gl->user_file);
8516 }
8517 #endif
8518
8519 /*.......................................................................
8520 * Save the contents of the history buffer to a given new file.
8521 *
8522 * Input:
8523 * gl GetLine * The resource object of this library.
8524 * filename const char * The name of the new file to write to.
8525 * comment const char * Extra information such as timestamps will
8526 * be recorded on a line started with this
8527 * string, the idea being that the file can
8528 * double as a command file. Specify "" if
8529 * you don't care.
8530 * max_lines int The maximum number of lines to save, or -1
8531 * to save all of the lines in the history
8532 * list.
8533 * Output:
8534 * return int 0 - OK.
8535 * 1 - Error.
8536 */
gl_save_history(GetLine * gl,const char * filename,const char * comment,int max_lines)8537 int gl_save_history(GetLine *gl, const char *filename, const char *comment,
8538 int max_lines)
8539 {
8540 sigset_t oldset; /* The signals that were blocked on entry to this function */
8541 int status; /* The return status of _gl_save_history() */
8542 /*
8543 * Check the arguments.
8544 */
8545 if(!gl || !filename || !comment) {
8546 if(gl)
8547 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
8548 errno = EINVAL;
8549 return 1;
8550 };
8551 /*
8552 * Block all signals.
8553 */
8554 if(gl_mask_signals(gl, &oldset))
8555 return 1;
8556 /*
8557 * Execute the private body of the function while signals are blocked.
8558 */
8559 status = _gl_save_history(gl, filename, comment, max_lines);
8560 /*
8561 * Restore the process signal mask.
8562 */
8563 gl_unmask_signals(gl, &oldset);
8564 return status;
8565 }
8566
8567 /*.......................................................................
8568 * This is the private body of the gl_save_history() function. It
8569 * assumes that the caller has checked its arguments and blocked the
8570 * delivery of signals.
8571 */
_gl_save_history(GetLine * gl,const char * filename,const char * comment,int max_lines)8572 static int _gl_save_history(GetLine *gl, const char *filename,
8573 const char *comment, int max_lines)
8574 {
8575 /*
8576 * If filesystem access is to be excluded, then history files can't
8577 * be written.
8578 */
8579 #ifdef WITHOUT_FILE_SYSTEM
8580 _err_record_msg(gl->err, "Can't save history without filesystem access",
8581 END_ERR_MSG);
8582 errno = EINVAL;
8583 return 1;
8584 #else
8585 FileExpansion *expansion; /* The expansion of the filename */
8586 /*
8587 * Expand the filename.
8588 */
8589 expansion = ef_expand_file(gl->ef, filename, -1);
8590 if(!expansion) {
8591 gl_print_info(gl, "Unable to expand ", filename, " (",
8592 ef_last_error(gl->ef), ").", GL_END_INFO);
8593 return 1;
8594 };
8595 /*
8596 * Attempt to save to the specified file.
8597 */
8598 if(_glh_save_history(gl->glh, expansion->files[0], comment, max_lines)) {
8599 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
8600 return 1;
8601 };
8602 return 0;
8603 #endif
8604 }
8605
8606 /*.......................................................................
8607 * Restore the contents of the history buffer from a given new file.
8608 *
8609 * Input:
8610 * gl GetLine * The resource object of this library.
8611 * filename const char * The name of the new file to write to.
8612 * comment const char * This must be the same string that was
8613 * passed to gl_save_history() when the file
8614 * was written.
8615 * Output:
8616 * return int 0 - OK.
8617 * 1 - Error.
8618 */
gl_load_history(GetLine * gl,const char * filename,const char * comment)8619 int gl_load_history(GetLine *gl, const char *filename, const char *comment)
8620 {
8621 sigset_t oldset; /* The signals that were blocked on entry to this function */
8622 int status; /* The return status of _gl_load_history() */
8623 /*
8624 * Check the arguments.
8625 */
8626 if(!gl || !filename || !comment) {
8627 if(gl)
8628 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
8629 errno = EINVAL;
8630 return 1;
8631 };
8632 /*
8633 * Block all signals.
8634 */
8635 if(gl_mask_signals(gl, &oldset))
8636 return 1;
8637 /*
8638 * Execute the private body of the function while signals are blocked.
8639 */
8640 status = _gl_load_history(gl, filename, comment);
8641 /*
8642 * Restore the process signal mask.
8643 */
8644 gl_unmask_signals(gl, &oldset);
8645 return status;
8646 }
8647
8648 /*.......................................................................
8649 * This is the private body of the gl_load_history() function. It
8650 * assumes that the caller has checked its arguments and blocked the
8651 * delivery of signals.
8652 */
_gl_load_history(GetLine * gl,const char * filename,const char * comment)8653 static int _gl_load_history(GetLine *gl, const char *filename,
8654 const char *comment)
8655 {
8656 /*
8657 * If filesystem access is to be excluded, then history files can't
8658 * be read.
8659 */
8660 #ifdef WITHOUT_FILE_SYSTEM
8661 _err_record_msg(gl->err, "Can't load history without filesystem access",
8662 END_ERR_MSG);
8663 errno = EINVAL;
8664 return 1;
8665 #else
8666 FileExpansion *expansion; /* The expansion of the filename */
8667 /*
8668 * Expand the filename.
8669 */
8670 expansion = ef_expand_file(gl->ef, filename, -1);
8671 if(!expansion) {
8672 gl_print_info(gl, "Unable to expand ", filename, " (",
8673 ef_last_error(gl->ef), ").", GL_END_INFO);
8674 return 1;
8675 };
8676 /*
8677 * Attempt to load from the specified file.
8678 */
8679 if(_glh_load_history(gl->glh, expansion->files[0], comment,
8680 gl->cutbuf, gl->linelen+1)) {
8681 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
8682 gl->cutbuf[0] = '\0';
8683 return 1;
8684 };
8685 gl->cutbuf[0] = '\0';
8686 return 0;
8687 #endif
8688 }
8689
8690 /*.......................................................................
8691 * Where possible, register a function and associated data to be called
8692 * whenever a specified event is seen on a file descriptor.
8693 *
8694 * Input:
8695 * gl GetLine * The resource object of the command-line input
8696 * module.
8697 * fd int The file descriptor to watch.
8698 * event GlFdEvent The type of activity to watch for.
8699 * callback GlFdEventFn * The function to call when the specified
8700 * event occurs. Setting this to 0 removes
8701 * any existing callback.
8702 * data void * A pointer to arbitrary data to pass to the
8703 * callback function.
8704 * Output:
8705 * return int 0 - OK.
8706 * 1 - Either gl==NULL, or this facility isn't
8707 * available on the the host system
8708 * (ie. select() isn't available). No
8709 * error message is generated in the latter
8710 * case.
8711 */
gl_watch_fd(GetLine * gl,int fd,GlFdEvent event,GlFdEventFn * callback,void * data)8712 int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
8713 GlFdEventFn *callback, void *data)
8714 {
8715 sigset_t oldset; /* The signals that were blocked on entry to this function */
8716 int status; /* The return status of _gl_watch_fd() */
8717 /*
8718 * Check the arguments.
8719 */
8720 if(!gl) {
8721 errno = EINVAL;
8722 return 1;
8723 };
8724 if(fd < 0) {
8725 _err_record_msg(gl->err, "Error: fd < 0", END_ERR_MSG);
8726 errno = EINVAL;
8727 return 1;
8728 };
8729 /*
8730 * Block all signals.
8731 */
8732 if(gl_mask_signals(gl, &oldset))
8733 return 1;
8734 /*
8735 * Execute the private body of the function while signals are blocked.
8736 */
8737 status = _gl_watch_fd(gl, fd, event, callback, data);
8738 /*
8739 * Restore the process signal mask.
8740 */
8741 gl_unmask_signals(gl, &oldset);
8742 return status;
8743 }
8744
8745 /*.......................................................................
8746 * This is the private body of the gl_watch_fd() function. It
8747 * assumes that the caller has checked its arguments and blocked the
8748 * delivery of signals.
8749 */
_gl_watch_fd(GetLine * gl,int fd,GlFdEvent event,GlFdEventFn * callback,void * data)8750 static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
8751 GlFdEventFn *callback, void *data)
8752 #if !defined(HAVE_SELECT)
8753 {return 1;} /* The facility isn't supported on this system */
8754 #else
8755 {
8756 GlFdNode *prev; /* The node that precedes 'node' in gl->fd_nodes */
8757 GlFdNode *node; /* The file-descriptor node being checked */
8758 /*
8759 * Search the list of already registered fd activity nodes for the specified
8760 * file descriptor.
8761 */
8762 for(prev=NULL,node=gl->fd_nodes; node && node->fd != fd;
8763 prev=node, node=node->next)
8764 ;
8765 /*
8766 * Hasn't a node been allocated for this fd yet?
8767 */
8768 if(!node) {
8769 /*
8770 * If there is no callback to record, just ignore the call.
8771 */
8772 if(!callback)
8773 return 0;
8774 /*
8775 * Allocate the new node.
8776 */
8777 node = (GlFdNode *) _new_FreeListNode(gl->fd_node_mem);
8778 if(!node) {
8779 errno = ENOMEM;
8780 _err_record_msg(gl->err, "Insufficient memory", END_ERR_MSG);
8781 return 1;
8782 };
8783 /*
8784 * Prepend the node to the list.
8785 */
8786 node->next = gl->fd_nodes;
8787 gl->fd_nodes = node;
8788 /*
8789 * Initialize the node.
8790 */
8791 node->fd = fd;
8792 node->rd.fn = 0;
8793 node->rd.data = NULL;
8794 node->ur = node->wr = node->rd;
8795 };
8796 /*
8797 * Record the new callback.
8798 */
8799 switch(event) {
8800 case GLFD_READ:
8801 node->rd.fn = callback;
8802 node->rd.data = data;
8803 if(callback)
8804 FD_SET(fd, &gl->rfds);
8805 else
8806 FD_CLR(fd, &gl->rfds);
8807 break;
8808 case GLFD_WRITE:
8809 node->wr.fn = callback;
8810 node->wr.data = data;
8811 if(callback)
8812 FD_SET(fd, &gl->wfds);
8813 else
8814 FD_CLR(fd, &gl->wfds);
8815 break;
8816 case GLFD_URGENT:
8817 node->ur.fn = callback;
8818 node->ur.data = data;
8819 if(callback)
8820 FD_SET(fd, &gl->ufds);
8821 else
8822 FD_CLR(fd, &gl->ufds);
8823 break;
8824 };
8825 /*
8826 * Keep a record of the largest file descriptor being watched.
8827 */
8828 if(fd > gl->max_fd)
8829 gl->max_fd = fd;
8830 /*
8831 * If we are deleting an existing callback, also delete the parent
8832 * activity node if no callbacks are registered to the fd anymore.
8833 */
8834 if(!callback) {
8835 if(!node->rd.fn && !node->wr.fn && !node->ur.fn) {
8836 if(prev)
8837 prev->next = node->next;
8838 else
8839 gl->fd_nodes = node->next;
8840 node = (GlFdNode *) _del_FreeListNode(gl->fd_node_mem, node);
8841 };
8842 };
8843 return 0;
8844 }
8845 #endif
8846
8847 /*.......................................................................
8848 * On systems with the select() system call, the gl_inactivity_timeout()
8849 * function provides the option of setting (or cancelling) an
8850 * inactivity timeout. Inactivity, in this case, refers both to
8851 * terminal input received from the user, and to I/O on any file
8852 * descriptors registered by calls to gl_watch_fd(). If at any time,
8853 * no activity is seen for the requested time period, the specified
8854 * timeout callback function is called. On returning, this callback
8855 * returns a code which tells gl_get_line() what to do next. Note that
8856 * each call to gl_inactivity_timeout() replaces any previously installed
8857 * timeout callback, and that specifying a callback of 0, turns off
8858 * inactivity timing.
8859 *
8860 * Beware that although the timeout argument includes a nano-second
8861 * component, few computer clocks presently have resolutions finer
8862 * than a few milliseconds, so asking for less than a few milliseconds
8863 * is equivalent to zero on a lot of systems.
8864 *
8865 * Input:
8866 * gl GetLine * The resource object of the command-line input
8867 * module.
8868 * callback GlTimeoutFn * The function to call when the inactivity
8869 * timeout is exceeded. To turn off
8870 * inactivity timeouts altogether, send 0.
8871 * data void * A pointer to arbitrary data to pass to the
8872 * callback function.
8873 * sec unsigned long The number of whole seconds in the timeout.
8874 * nsec unsigned long The fractional number of seconds in the
8875 * timeout, expressed in nano-seconds (see
8876 * the caveat above).
8877 * Output:
8878 * return int 0 - OK.
8879 * 1 - Either gl==NULL, or this facility isn't
8880 * available on the the host system
8881 * (ie. select() isn't available). No
8882 * error message is generated in the latter
8883 * case.
8884 */
gl_inactivity_timeout(GetLine * gl,GlTimeoutFn * timeout_fn,void * data,unsigned long sec,unsigned long nsec)8885 int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *timeout_fn, void *data,
8886 unsigned long sec, unsigned long nsec)
8887 #if !defined(HAVE_SELECT)
8888 {return 1;} /* The facility isn't supported on this system */
8889 #else
8890 {
8891 sigset_t oldset; /* The signals that were blocked on entry to this function */
8892 /*
8893 * Check the arguments.
8894 */
8895 if(!gl) {
8896 errno = EINVAL;
8897 return 1;
8898 };
8899 /*
8900 * Block all signals.
8901 */
8902 if(gl_mask_signals(gl, &oldset))
8903 return 1;
8904 /*
8905 * Install a new timeout?
8906 */
8907 if(timeout_fn) {
8908 gl->timer.dt.tv_sec = sec;
8909 gl->timer.dt.tv_usec = nsec / 1000;
8910 gl->timer.fn = timeout_fn;
8911 gl->timer.data = data;
8912 } else {
8913 gl->timer.fn = 0;
8914 gl->timer.data = NULL;
8915 };
8916 /*
8917 * Restore the process signal mask.
8918 */
8919 gl_unmask_signals(gl, &oldset);
8920 return 0;
8921 }
8922 #endif
8923
8924 /*.......................................................................
8925 * When select() is available, this is a private function of
8926 * gl_read_input() which responds to file-descriptor events registered by
8927 * the caller. Note that it assumes that it is being called from within
8928 * gl_read_input()'s sigsetjump() clause.
8929 *
8930 * Input:
8931 * gl GetLine * The resource object of this module.
8932 * fd int The file descriptor to be watched for user input.
8933 * Output:
8934 * return int 0 - OK.
8935 * 1 - An error occurred.
8936 */
gl_event_handler(GetLine * gl,int fd)8937 static int gl_event_handler(GetLine *gl, int fd)
8938 {
8939 #if !defined(HAVE_SELECT)
8940 return 0;
8941 #else
8942 /*
8943 * Set up a zero-second timeout.
8944 */
8945 struct timeval zero;
8946 zero.tv_sec = zero.tv_usec = 0;
8947 /*
8948 * If at any time no external callbacks remain, quit the loop return,
8949 * so that we can simply wait in read(). This is designed as an
8950 * optimization for when no callbacks have been registered on entry to
8951 * this function, but since callbacks can delete themselves, it can
8952 * also help later.
8953 */
8954 while(gl->fd_nodes || gl->timer.fn) {
8955 int nready; /* The number of file descriptors that are ready for I/O */
8956 /*
8957 * Get the set of descriptors to be watched.
8958 */
8959 fd_set rfds = gl->rfds;
8960 fd_set wfds = gl->wfds;
8961 fd_set ufds = gl->ufds;
8962 /*
8963 * Get the appropriate timeout.
8964 */
8965 struct timeval dt = gl->timer.fn ? gl->timer.dt : zero;
8966 /*
8967 * Add the specified user-input file descriptor tot he set that is to
8968 * be watched.
8969 */
8970 FD_SET(fd, &rfds);
8971 /*
8972 * Unblock the signals that we are watching, while select is blocked
8973 * waiting for I/O.
8974 */
8975 gl_catch_signals(gl);
8976 /*
8977 * Wait for activity on any of the file descriptors.
8978 */
8979 nready = select(gl->max_fd+1, &rfds, &wfds, &ufds,
8980 (gl->timer.fn || gl->io_mode==GL_SERVER_MODE) ? &dt : NULL);
8981 /*
8982 * We don't want to do a longjmp in the middle of a callback that
8983 * might be modifying global or heap data, so block all the signals
8984 * that we are trapping before executing callback functions. Note that
8985 * the caller will unblock them again when it needs to, so there is
8986 * no need to undo this before returning.
8987 */
8988 gl_mask_signals(gl, NULL);
8989 /*
8990 * If select() returns but none of the file descriptors are reported
8991 * to have activity, then select() timed out.
8992 */
8993 if(nready == 0) {
8994 /*
8995 * Note that in non-blocking server mode, the inactivity timer is used
8996 * to allow I/O to block for a specified amount of time, so in this
8997 * mode we return the postponed blocked status when an abort is
8998 * requested.
8999 */
9000 if(gl_call_timeout_handler(gl)) {
9001 return 1;
9002 } else if(gl->io_mode == GL_SERVER_MODE) {
9003 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
9004 return 1;
9005 };
9006 /*
9007 * If nready < 0, this means an error occurred.
9008 */
9009 } else if(nready < 0) {
9010 if(errno != EINTR) {
9011 gl_record_status(gl, GLR_ERROR, errno);
9012 return 1;
9013 };
9014 /*
9015 * If the user-input file descriptor has data available, return.
9016 */
9017 } else if(FD_ISSET(fd, &rfds)) {
9018 return 0;
9019 /*
9020 * Check for activity on any of the file descriptors registered by the
9021 * calling application, and call the associated callback functions.
9022 */
9023 } else {
9024 GlFdNode *node; /* The fd event node being checked */
9025 /*
9026 * Search the list for the file descriptor that caused select() to return.
9027 */
9028 for(node=gl->fd_nodes; node; node=node->next) {
9029 /*
9030 * Is there urgent out of band data waiting to be read on fd?
9031 */
9032 if(node->ur.fn && FD_ISSET(node->fd, &ufds)) {
9033 if(gl_call_fd_handler(gl, &node->ur, node->fd, GLFD_URGENT))
9034 return 1;
9035 break; /* The callback may have changed the list of nodes */
9036 /*
9037 * Is the fd readable?
9038 */
9039 } else if(node->rd.fn && FD_ISSET(node->fd, &rfds)) {
9040 if(gl_call_fd_handler(gl, &node->rd, node->fd, GLFD_READ))
9041 return 1;
9042 break; /* The callback may have changed the list of nodes */
9043 /*
9044 * Is the fd writable?
9045 */
9046 } else if(node->wr.fn && FD_ISSET(node->fd, &wfds)) {
9047 if(gl_call_fd_handler(gl, &node->wr, node->fd, GLFD_WRITE))
9048 return 1;
9049 break; /* The callback may have changed the list of nodes */
9050 };
9051 };
9052 };
9053 /*
9054 * Just in case the above event handlers asked for the input line to
9055 * be redrawn, flush any pending output.
9056 */
9057 if(gl_flush_output(gl))
9058 return 1;
9059 };
9060 return 0;
9061 }
9062 #endif
9063
9064 #if defined(HAVE_SELECT)
9065 /*.......................................................................
9066 * This is a private function of gl_event_handler(), used to call a
9067 * file-descriptor callback.
9068 *
9069 * Input:
9070 * gl GetLine * The resource object of gl_get_line().
9071 * gfh GlFdHandler * The I/O handler.
9072 * fd int The file-descriptor being reported.
9073 * event GlFdEvent The I/O event being reported.
9074 * Output:
9075 * return int 0 - OK.
9076 * 1 - Error.
9077 */
9078 static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
9079 GlFdEvent event)
9080 {
9081 Termios attr; /* The terminal attributes */
9082 int waserr = 0; /* True after any error */
9083 /*
9084 * Re-enable conversion of newline characters to carriage-return/linefeed,
9085 * so that the callback can write to the terminal without having to do
9086 * anything special.
9087 */
9088 if(tcgetattr(gl->input_fd, &attr)) {
9089 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
9090 return 1;
9091 };
9092 attr.c_oflag |= OPOST;
9093 while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
9094 if(errno != EINTR) {
9095 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
9096 return 1;
9097 };
9098 };
9099 /*
9100 * Invoke the application's callback function.
9101 */
9102 switch(gfh->fn(gl, gfh->data, fd, event)) {
9103 default:
9104 case GLFD_ABORT:
9105 gl_record_status(gl, GLR_FDABORT, 0);
9106 waserr = 1;
9107 break;
9108 case GLFD_REFRESH:
9109 gl_queue_redisplay(gl);
9110 break;
9111 case GLFD_CONTINUE:
9112 break;
9113 };
9114 /*
9115 * Disable conversion of newline characters to carriage-return/linefeed.
9116 */
9117 attr.c_oflag &= ~(OPOST);
9118 while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
9119 if(errno != EINTR) {
9120 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
9121 return 1;
9122 };
9123 };
9124 return waserr;
9125 }
9126
9127 /*.......................................................................
9128 * This is a private function of gl_event_handler(), used to call a
9129 * inactivity timer callbacks.
9130 *
9131 * Input:
9132 * gl GetLine * The resource object of gl_get_line().
9133 * Output:
9134 * return int 0 - OK.
9135 * 1 - Error.
9136 */
9137 static int gl_call_timeout_handler(GetLine *gl)
9138 {
9139 Termios attr; /* The terminal attributes */
9140 int waserr = 0; /* True after any error */
9141 /*
9142 * Make sure that there is an inactivity timeout callback.
9143 */
9144 if(!gl->timer.fn)
9145 return 0;
9146 /*
9147 * Re-enable conversion of newline characters to carriage-return/linefeed,
9148 * so that the callback can write to the terminal without having to do
9149 * anything special.
9150 */
9151 if(tcgetattr(gl->input_fd, &attr)) {
9152 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
9153 return 1;
9154 };
9155 attr.c_oflag |= OPOST;
9156 while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
9157 if(errno != EINTR) {
9158 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
9159 return 1;
9160 };
9161 };
9162 /*
9163 * Invoke the application's callback function.
9164 */
9165 switch(gl->timer.fn(gl, gl->timer.data)) {
9166 default:
9167 case GLTO_ABORT:
9168 gl_record_status(gl, GLR_TIMEOUT, 0);
9169 waserr = 1;
9170 break;
9171 case GLTO_REFRESH:
9172 gl_queue_redisplay(gl);
9173 break;
9174 case GLTO_CONTINUE:
9175 break;
9176 };
9177 /*
9178 * Disable conversion of newline characters to carriage-return/linefeed.
9179 */
9180 attr.c_oflag &= ~(OPOST);
9181 while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
9182 if(errno != EINTR) {
9183 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
9184 return 1;
9185 };
9186 };
9187 return waserr;
9188 }
9189 #endif /* HAVE_SELECT */
9190
9191 /*.......................................................................
9192 * Switch history groups. History groups represent separate history
9193 * lists recorded within a single history buffer. Different groups
9194 * are distinguished by integer identifiers chosen by the calling
9195 * appplicaton. Initially new_GetLine() sets the group identifier to
9196 * 0. Whenever a new line is appended to the history list, the current
9197 * group identifier is recorded with it, and history lookups only
9198 * consider lines marked with the current group identifier.
9199 *
9200 * Input:
9201 * gl GetLine * The resource object of gl_get_line().
9202 * id unsigned The new history group identifier.
9203 * Output:
9204 * return int 0 - OK.
9205 * 1 - Error.
9206 */
9207 int gl_group_history(GetLine *gl, unsigned id)
9208 {
9209 sigset_t oldset; /* The signals that were blocked on entry to this function */
9210 int status; /* The return status of this function */
9211 /*
9212 * Check the arguments.
9213 */
9214 if(!gl) {
9215 errno = EINVAL;
9216 return 1;
9217 };
9218 /*
9219 * Block all signals while we install the new configuration.
9220 */
9221 if(gl_mask_signals(gl, &oldset))
9222 return 1;
9223 /*
9224 * If the group isn't being changed, do nothing.
9225 */
9226 if(_glh_get_group(gl->glh) == id) {
9227 status = 0;
9228 /*
9229 * Establish the new group.
9230 */
9231 } else if(_glh_set_group(gl->glh, id)) {
9232 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
9233 status = 1;
9234 /*
9235 * Prevent history information from the previous group being
9236 * inappropriately used by the next call to gl_get_line().
9237 */
9238 } else {
9239 gl->preload_history = 0;
9240 gl->last_search = -1;
9241 status = 0;
9242 };
9243 /*
9244 * Restore the process signal mask.
9245 */
9246 gl_unmask_signals(gl, &oldset);
9247 return status;
9248 }
9249
9250 /*.......................................................................
9251 * Display the contents of the history list.
9252 *
9253 * Input:
9254 * gl GetLine * The resource object of gl_get_line().
9255 * fp FILE * The stdio output stream to write to.
9256 * fmt const char * A format string. This containing characters to be
9257 * written verbatim, plus any of the following
9258 * format directives:
9259 * %D - The date, formatted like 2001-11-20
9260 * %T - The time of day, formatted like 23:59:59
9261 * %N - The sequential entry number of the
9262 * line in the history buffer.
9263 * %G - The number of the history group that
9264 * the line belongs to.
9265 * %% - A literal % character.
9266 * %H - The history line itself.
9267 * Note that a '\n' newline character is not
9268 * appended by default.
9269 * all_groups int If true, display history lines from all
9270 * history groups. Otherwise only display
9271 * those of the current history group.
9272 * max_lines int If max_lines is < 0, all available lines
9273 * are displayed. Otherwise only the most
9274 * recent max_lines lines will be displayed.
9275 * Output:
9276 * return int 0 - OK.
9277 * 1 - Error.
9278 */
9279 int gl_show_history(GetLine *gl, FILE *fp, const char *fmt, int all_groups,
9280 int max_lines)
9281 {
9282 sigset_t oldset; /* The signals that were blocked on entry to this function */
9283 int status; /* The return status of this function */
9284 /*
9285 * Check the arguments.
9286 */
9287 if(!gl || !fp || !fmt) {
9288 if(gl)
9289 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
9290 errno = EINVAL;
9291 return 1;
9292 };
9293 /*
9294 * Block all signals.
9295 */
9296 if(gl_mask_signals(gl, &oldset))
9297 return 1;
9298 /*
9299 * Display the specified history group(s) while signals are blocked.
9300 */
9301 status = _glh_show_history(gl->glh, _io_write_stdio, fp, fmt, all_groups,
9302 max_lines) || fflush(fp)==EOF;
9303 if(!status)
9304 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
9305 /*
9306 * Restore the process signal mask.
9307 */
9308 gl_unmask_signals(gl, &oldset);
9309 return status;
9310 }
9311
9312 /*.......................................................................
9313 * Update if necessary, and return the current size of the terminal.
9314 *
9315 * Input:
9316 * gl GetLine * The resource object of gl_get_line().
9317 * def_ncolumn int If the number of columns in the terminal
9318 * can't be determined, substitute this number.
9319 * def_nline int If the number of lines in the terminal can't
9320 * be determined, substitute this number.
9321 * Output:
9322 * return GlTerminalSize The current terminal size.
9323 */
9324 GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline)
9325 {
9326 GlTerminalSize size; /* The object to be returned */
9327 sigset_t oldset; /* The signals that were blocked on entry */
9328 /* to this function */
9329 /*
9330 * Block all signals while accessing gl.
9331 */
9332 gl_mask_signals(gl, &oldset);
9333 /*
9334 * Lookup/configure the terminal size.
9335 */
9336 _gl_terminal_size(gl, def_ncolumn, def_nline, &size);
9337 /*
9338 * Restore the process signal mask before returning.
9339 */
9340 gl_unmask_signals(gl, &oldset);
9341 return size;
9342 }
9343
9344 /*.......................................................................
9345 * This is the private body of the gl_terminal_size() function. It
9346 * assumes that the caller has checked its arguments and blocked the
9347 * delivery of signals.
9348 */
9349 static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
9350 GlTerminalSize *size)
9351 {
9352 const char *env; /* The value of an environment variable */
9353 int n; /* A number read from env[] */
9354 /*
9355 * Set the number of lines and columns to non-sensical values so that
9356 * we know later if they have been set.
9357 */
9358 gl->nline = 0;
9359 gl->ncolumn = 0;
9360 /*
9361 * Are we reading from a terminal?
9362 */
9363 if(gl->is_term) {
9364 /*
9365 * Ask the terminal directly if possible.
9366 */
9367 (void) _gl_update_size(gl);
9368 /*
9369 * If gl_update_size() couldn't ask the terminal, it will have
9370 * left gl->nrow and gl->ncolumn unchanged. If these values haven't
9371 * been changed from their initial values of zero, we need to find
9372 * a different method to get the terminal size.
9373 *
9374 * If the number of lines isn't known yet, first see if the
9375 * LINES environment ariable exists and specifies a believable number.
9376 * If this doesn't work, look up the default size in the terminal
9377 * information database.
9378 */
9379 if(gl->nline < 1) {
9380 if((env = getenv("LINES")) && (n=atoi(env)) > 0)
9381 gl->nline = n;
9382 #ifdef USE_TERMINFO
9383 else
9384 gl->nline = tigetnum((char *)"lines");
9385 #elif defined(USE_TERMCAP)
9386 else
9387 gl->nline = tgetnum("li");
9388 #endif
9389 };
9390 /*
9391 * If the number of lines isn't known yet, first see if the COLUMNS
9392 * environment ariable exists and specifies a believable number. If
9393 * this doesn't work, look up the default size in the terminal
9394 * information database.
9395 */
9396 if(gl->ncolumn < 1) {
9397 if((env = getenv("COLUMNS")) && (n=atoi(env)) > 0)
9398 gl->ncolumn = n;
9399 #ifdef USE_TERMINFO
9400 else
9401 gl->ncolumn = tigetnum((char *)"cols");
9402 #elif defined(USE_TERMCAP)
9403 else
9404 gl->ncolumn = tgetnum("co");
9405 #endif
9406 };
9407 };
9408 /*
9409 * If we still haven't been able to acquire reasonable values, substitute
9410 * the default values specified by the caller.
9411 */
9412 if(gl->nline <= 0)
9413 gl->nline = def_nline;
9414 if(gl->ncolumn <= 0)
9415 gl->ncolumn = def_ncolumn;
9416 /*
9417 * Copy the new size into the return value.
9418 */
9419 if(size) {
9420 size->nline = gl->nline;
9421 size->ncolumn = gl->ncolumn;
9422 };
9423 return;
9424 }
9425
9426 /*.......................................................................
9427 * Resize or delete the history buffer.
9428 *
9429 * Input:
9430 * gl GetLine * The resource object of gl_get_line().
9431 * bufsize size_t The number of bytes in the history buffer, or 0
9432 * to delete the buffer completely.
9433 * Output:
9434 * return int 0 - OK.
9435 * 1 - Insufficient memory (the previous buffer
9436 * will have been retained). No error message
9437 * will be displayed.
9438 */
9439 int gl_resize_history(GetLine *gl, size_t bufsize)
9440 {
9441 sigset_t oldset; /* The signals that were blocked on entry to this function */
9442 int status; /* The return status of this function */
9443 /*
9444 * Check the arguments.
9445 */
9446 if(!gl)
9447 return 1;
9448 /*
9449 * Block all signals while modifying the contents of gl.
9450 */
9451 if(gl_mask_signals(gl, &oldset))
9452 return 1;
9453 /*
9454 * Perform the resize while signals are blocked.
9455 */
9456 status = _glh_resize_history(gl->glh, bufsize);
9457 if(status)
9458 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
9459 /*
9460 * Restore the process signal mask before returning.
9461 */
9462 gl_unmask_signals(gl, &oldset);
9463 return status;
9464 }
9465
9466 /*.......................................................................
9467 * Set an upper limit to the number of lines that can be recorded in the
9468 * history list, or remove a previously specified limit.
9469 *
9470 * Input:
9471 * gl GetLine * The resource object of gl_get_line().
9472 * max_lines int The maximum number of lines to allow, or -1 to
9473 * cancel a previous limit and allow as many lines
9474 * as will fit in the current history buffer size.
9475 */
9476 void gl_limit_history(GetLine *gl, int max_lines)
9477 {
9478 if(gl) {
9479 sigset_t oldset; /* The signals that were blocked on entry to this block */
9480 /*
9481 * Temporarily block all signals.
9482 */
9483 gl_mask_signals(gl, &oldset);
9484 /*
9485 * Apply the limit while signals are blocked.
9486 */
9487 _glh_limit_history(gl->glh, max_lines);
9488 /*
9489 * Restore the process signal mask before returning.
9490 */
9491 gl_unmask_signals(gl, &oldset);
9492 };
9493 }
9494
9495 /*.......................................................................
9496 * Discard either all historical lines, or just those associated with the
9497 * current history group.
9498 *
9499 * Input:
9500 * gl GetLine * The resource object of gl_get_line().
9501 * all_groups int If true, clear all of the history. If false,
9502 * clear only the stored lines associated with the
9503 * currently selected history group.
9504 */
9505 void gl_clear_history(GetLine *gl, int all_groups)
9506 {
9507 if(gl) {
9508 sigset_t oldset; /* The signals that were blocked on entry to this block */
9509 /*
9510 * Temporarily block all signals.
9511 */
9512 gl_mask_signals(gl, &oldset);
9513 /*
9514 * Clear the history buffer while signals are blocked.
9515 */
9516 _glh_clear_history(gl->glh, all_groups);
9517 /*
9518 * Restore the process signal mask before returning.
9519 */
9520 gl_unmask_signals(gl, &oldset);
9521 };
9522 }
9523
9524 /*.......................................................................
9525 * Temporarily enable or disable the gl_get_line() history mechanism.
9526 *
9527 * Input:
9528 * gl GetLine * The resource object of gl_get_line().
9529 * enable int If true, turn on the history mechanism. If
9530 * false, disable it.
9531 */
9532 void gl_toggle_history(GetLine *gl, int enable)
9533 {
9534 if(gl) {
9535 sigset_t oldset; /* The signals that were blocked on entry to this block */
9536 /*
9537 * Temporarily block all signals.
9538 */
9539 gl_mask_signals(gl, &oldset);
9540 /*
9541 * Change the history recording mode while signals are blocked.
9542 */
9543 _glh_toggle_history(gl->glh, enable);
9544 /*
9545 * Restore the process signal mask before returning.
9546 */
9547 gl_unmask_signals(gl, &oldset);
9548 };
9549 }
9550
9551 /*.......................................................................
9552 * Lookup a history line by its sequential number of entry in the
9553 * history buffer.
9554 *
9555 * Input:
9556 * gl GetLine * The resource object of gl_get_line().
9557 * id unsigned long The identification number of the line to
9558 * be returned, where 0 denotes the first line
9559 * that was entered in the history list, and
9560 * each subsequently added line has a number
9561 * one greater than the previous one. For
9562 * the range of lines currently in the list,
9563 * see the gl_range_of_history() function.
9564 * Input/Output:
9565 * line GlHistoryLine * A pointer to the variable in which to
9566 * return the details of the line.
9567 * Output:
9568 * return int 0 - The line is no longer in the history
9569 * list, and *line has not been changed.
9570 * 1 - The requested line can be found in
9571 * *line. Note that line->line is part
9572 * of the history buffer, so a
9573 * private copy should be made if you
9574 * wish to use it after subsequent calls
9575 * to any functions that take *gl as an
9576 * argument.
9577 */
9578 int gl_lookup_history(GetLine *gl, unsigned long id, GlHistoryLine *line)
9579 {
9580 sigset_t oldset; /* The signals that were blocked on entry to this function */
9581 int status; /* The return status of this function */
9582 /*
9583 * Check the arguments.
9584 */
9585 if(!gl)
9586 return 0;
9587 /*
9588 * Block all signals while modifying the contents of gl.
9589 */
9590 if(gl_mask_signals(gl, &oldset))
9591 return 1;
9592 /*
9593 * Perform the lookup while signals are blocked.
9594 */
9595 status = _glh_lookup_history(gl->glh, (GlhLineID) id, &line->line,
9596 &line->group, &line->timestamp);
9597 if(status)
9598 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
9599 /*
9600 * Restore the process signal mask before returning.
9601 */
9602 gl_unmask_signals(gl, &oldset);
9603 return status;
9604 }
9605
9606 /*.......................................................................
9607 * Query the state of the history list. Note that any of the input/output
9608 * pointers can be specified as NULL.
9609 *
9610 * Input:
9611 * gl GetLine * The resource object of gl_get_line().
9612 * Input/Output:
9613 * state GlHistoryState * A pointer to the variable in which to record
9614 * the return values.
9615 */
9616 void gl_state_of_history(GetLine *gl, GlHistoryState *state)
9617 {
9618 if(gl && state) {
9619 sigset_t oldset; /* The signals that were blocked on entry to this block */
9620 /*
9621 * Temporarily block all signals.
9622 */
9623 gl_mask_signals(gl, &oldset);
9624 /*
9625 * Lookup the status while signals are blocked.
9626 */
9627 _glh_state_of_history(gl->glh, &state->enabled, &state->group,
9628 &state->max_lines);
9629 /*
9630 * Restore the process signal mask before returning.
9631 */
9632 gl_unmask_signals(gl, &oldset);
9633 };
9634 }
9635
9636 /*.......................................................................
9637 * Query the number and range of lines in the history buffer.
9638 *
9639 * Input:
9640 * gl GetLine * The resource object of gl_get_line().
9641 * range GlHistoryRange * A pointer to the variable in which to record
9642 * the return values. If range->nline=0, the
9643 * range of lines will be given as 0-0.
9644 */
9645 void gl_range_of_history(GetLine *gl, GlHistoryRange *range)
9646 {
9647 if(gl && range) {
9648 sigset_t oldset; /* The signals that were blocked on entry to this block */
9649 /*
9650 * Temporarily block all signals.
9651 */
9652 gl_mask_signals(gl, &oldset);
9653 /*
9654 * Lookup the information while signals are blocked.
9655 */
9656 _glh_range_of_history(gl->glh, &range->oldest, &range->newest,
9657 &range->nlines);
9658 /*
9659 * Restore the process signal mask before returning.
9660 */
9661 gl_unmask_signals(gl, &oldset);
9662 };
9663 }
9664
9665 /*.......................................................................
9666 * Return the size of the history buffer and the amount of the
9667 * buffer that is currently in use.
9668 *
9669 * Input:
9670 * gl GetLine * The gl_get_line() resource object.
9671 * Input/Output:
9672 * GlHistorySize size * A pointer to the variable in which to return
9673 * the results.
9674 */
9675 void gl_size_of_history(GetLine *gl, GlHistorySize *size)
9676 {
9677 if(gl && size) {
9678 sigset_t oldset; /* The signals that were blocked on entry to this block */
9679 /*
9680 * Temporarily block all signals.
9681 */
9682 gl_mask_signals(gl, &oldset);
9683 /*
9684 * Lookup the information while signals are blocked.
9685 */
9686 _glh_size_of_history(gl->glh, &size->size, &size->used);
9687 /*
9688 * Restore the process signal mask before returning.
9689 */
9690 gl_unmask_signals(gl, &oldset);
9691 };
9692 }
9693
9694 /*.......................................................................
9695 * This is the action function that lists the contents of the history
9696 * list.
9697 */
9698 static KT_KEY_FN(gl_list_history)
9699 {
9700 /*
9701 * Start a new line.
9702 */
9703 if(gl_start_newline(gl, 1))
9704 return 1;
9705 /*
9706 * List history lines that belong to the current group.
9707 */
9708 _glh_show_history(gl->glh, gl_write_fn, gl, "%N %T %H\r\n", 0,
9709 count<=1 ? -1 : count);
9710 /*
9711 * Arrange for the input line to be redisplayed.
9712 */
9713 gl_queue_redisplay(gl);
9714 return 0;
9715 }
9716
9717 /*.......................................................................
9718 * Specify whether text that users type should be displayed or hidden.
9719 * In the latter case, only the prompt is displayed, and the final
9720 * input line is not archived in the history list.
9721 *
9722 * Input:
9723 * gl GetLine * The gl_get_line() resource object.
9724 * enable int 0 - Disable echoing.
9725 * 1 - Enable echoing.
9726 * -1 - Just query the mode without changing it.
9727 * Output:
9728 * return int The echoing disposition that was in effect
9729 * before this function was called:
9730 * 0 - Echoing was disabled.
9731 * 1 - Echoing was enabled.
9732 */
9733 int gl_echo_mode(GetLine *gl, int enable)
9734 {
9735 if(gl) {
9736 sigset_t oldset; /* The signals that were blocked on entry to this block */
9737 int was_echoing; /* The echoing disposition on entry to this function */
9738 /*
9739 * Temporarily block all signals.
9740 */
9741 gl_mask_signals(gl, &oldset);
9742 /*
9743 * Install the new disposition while signals are blocked.
9744 */
9745 was_echoing = gl->echo;
9746 if(enable >= 0)
9747 gl->echo = enable;
9748 /*
9749 * Restore the process signal mask before returning.
9750 */
9751 gl_unmask_signals(gl, &oldset);
9752 /*
9753 * Return the original echoing disposition.
9754 */
9755 return was_echoing;
9756 };
9757 return 1;
9758 }
9759
9760 /*.......................................................................
9761 * Display the prompt.
9762 *
9763 * Input:
9764 * gl GetLine * The resource object of gl_get_line().
9765 * Output:
9766 * return int 0 - OK.
9767 * 1 - Error.
9768 */
9769 static int gl_display_prompt(GetLine *gl)
9770 {
9771 const char *pptr; /* A pointer into gl->prompt[] */
9772 unsigned old_attr=0; /* The current text display attributes */
9773 unsigned new_attr=0; /* The requested text display attributes */
9774 /*
9775 * Temporarily switch to echoing output characters.
9776 */
9777 int kept_echo = gl->echo;
9778 gl->echo = 1;
9779 /*
9780 * In case the screen got messed up, send a carriage return to
9781 * put the cursor at the beginning of the current terminal line.
9782 */
9783 if(gl_print_control_sequence(gl, 1, gl->bol))
9784 return 1;
9785 /*
9786 * Mark the line as partially displayed.
9787 */
9788 gl->displayed = 1;
9789 /*
9790 * Write the prompt, using the currently selected prompt style.
9791 */
9792 switch(gl->prompt_style) {
9793 case GL_LITERAL_PROMPT:
9794 if(gl_print_string(gl, gl->prompt, '\0'))
9795 return 1;
9796 break;
9797 case GL_FORMAT_PROMPT:
9798 for(pptr=gl->prompt; *pptr; pptr++) {
9799 /*
9800 * Does the latest character appear to be the start of a directive?
9801 */
9802 if(*pptr == '%') {
9803 /*
9804 * Check for and act on attribute changing directives.
9805 */
9806 switch(pptr[1]) {
9807 /*
9808 * Add or remove a text attribute from the new set of attributes.
9809 */
9810 case 'B': case 'U': case 'S': case 'P': case 'F': case 'V':
9811 case 'b': case 'u': case 's': case 'p': case 'f': case 'v':
9812 switch(*++pptr) {
9813 case 'B': /* Switch to a bold font */
9814 new_attr |= GL_TXT_BOLD;
9815 break;
9816 case 'b': /* Switch to a non-bold font */
9817 new_attr &= ~GL_TXT_BOLD;
9818 break;
9819 case 'U': /* Start underlining */
9820 new_attr |= GL_TXT_UNDERLINE;
9821 break;
9822 case 'u': /* Stop underlining */
9823 new_attr &= ~GL_TXT_UNDERLINE;
9824 break;
9825 case 'S': /* Start highlighting */
9826 new_attr |= GL_TXT_STANDOUT;
9827 break;
9828 case 's': /* Stop highlighting */
9829 new_attr &= ~GL_TXT_STANDOUT;
9830 break;
9831 case 'P': /* Switch to a pale font */
9832 new_attr |= GL_TXT_DIM;
9833 break;
9834 case 'p': /* Switch to a non-pale font */
9835 new_attr &= ~GL_TXT_DIM;
9836 break;
9837 case 'F': /* Switch to a flashing font */
9838 new_attr |= GL_TXT_BLINK;
9839 break;
9840 case 'f': /* Switch to a steady font */
9841 new_attr &= ~GL_TXT_BLINK;
9842 break;
9843 case 'V': /* Switch to reverse video */
9844 new_attr |= GL_TXT_REVERSE;
9845 break;
9846 case 'v': /* Switch out of reverse video */
9847 new_attr &= ~GL_TXT_REVERSE;
9848 break;
9849 };
9850 continue;
9851 /*
9852 * A literal % is represented by %%. Skip the leading %.
9853 */
9854 case '%':
9855 pptr++;
9856 break;
9857 };
9858 };
9859 /*
9860 * Many terminals, when asked to turn off a single text attribute, turn
9861 * them all off, so the portable way to turn one off individually is to
9862 * explicitly turn them all off, then specify those that we want from
9863 * scratch.
9864 */
9865 if(old_attr & ~new_attr) {
9866 if(gl_print_control_sequence(gl, 1, gl->text_attr_off))
9867 return 1;
9868 old_attr = 0;
9869 };
9870 /*
9871 * Install new text attributes?
9872 */
9873 if(new_attr != old_attr) {
9874 if(new_attr & GL_TXT_BOLD && !(old_attr & GL_TXT_BOLD) &&
9875 gl_print_control_sequence(gl, 1, gl->bold))
9876 return 1;
9877 if(new_attr & GL_TXT_UNDERLINE && !(old_attr & GL_TXT_UNDERLINE) &&
9878 gl_print_control_sequence(gl, 1, gl->underline))
9879 return 1;
9880 if(new_attr & GL_TXT_STANDOUT && !(old_attr & GL_TXT_STANDOUT) &&
9881 gl_print_control_sequence(gl, 1, gl->standout))
9882 return 1;
9883 if(new_attr & GL_TXT_DIM && !(old_attr & GL_TXT_DIM) &&
9884 gl_print_control_sequence(gl, 1, gl->dim))
9885 return 1;
9886 if(new_attr & GL_TXT_REVERSE && !(old_attr & GL_TXT_REVERSE) &&
9887 gl_print_control_sequence(gl, 1, gl->reverse))
9888 return 1;
9889 if(new_attr & GL_TXT_BLINK && !(old_attr & GL_TXT_BLINK) &&
9890 gl_print_control_sequence(gl, 1, gl->blink))
9891 return 1;
9892 old_attr = new_attr;
9893 };
9894 /*
9895 * Display the latest character.
9896 */
9897 if(gl_print_char(gl, *pptr, pptr[1]))
9898 return 1;
9899 };
9900 /*
9901 * Turn off all text attributes now that we have finished drawing
9902 * the prompt.
9903 */
9904 if(gl_print_control_sequence(gl, 1, gl->text_attr_off))
9905 return 1;
9906 break;
9907 };
9908 /*
9909 * Restore the original echo mode.
9910 */
9911 gl->echo = kept_echo;
9912 /*
9913 * The prompt has now been displayed at least once.
9914 */
9915 gl->prompt_changed = 0;
9916 return 0;
9917 }
9918
9919 /*.......................................................................
9920 * This function can be called from gl_get_line() callbacks to have
9921 * the prompt changed when they return. It has no effect if gl_get_line()
9922 * is not currently being invoked.
9923 *
9924 * Input:
9925 * gl GetLine * The resource object of gl_get_line().
9926 * prompt const char * The new prompt.
9927 */
9928 void gl_replace_prompt(GetLine *gl, const char *prompt)
9929 {
9930 if(gl) {
9931 sigset_t oldset; /* The signals that were blocked on entry to this block */
9932 /*
9933 * Temporarily block all signals.
9934 */
9935 gl_mask_signals(gl, &oldset);
9936 /*
9937 * Replace the prompt.
9938 */
9939 _gl_replace_prompt(gl, prompt);
9940 /*
9941 * Restore the process signal mask before returning.
9942 */
9943 gl_unmask_signals(gl, &oldset);
9944 };
9945 }
9946
9947 /*.......................................................................
9948 * This is the private body of the gl_replace_prompt() function. It
9949 * assumes that the caller has checked its arguments and blocked the
9950 * delivery of signals.
9951 */
9952 static void _gl_replace_prompt(GetLine *gl, const char *prompt)
9953 {
9954 size_t size;
9955
9956 /*
9957 * Substitute an empty prompt?
9958 */
9959 if(!prompt)
9960 prompt = "";
9961 /*
9962 * Gaurd against aliasing between prompt and gl->prompt.
9963 */
9964 if(gl->prompt != prompt) {
9965 /*
9966 * Get the length of the new prompt string.
9967 */
9968 size_t slen = strlen(prompt);
9969 /*
9970 * If needed, allocate a new buffer for the prompt string.
9971 */
9972 size = sizeof(char) * (slen + 1);
9973 if(!gl->prompt || slen > strlen(gl->prompt)) {
9974 char *new_prompt = gl->prompt ? realloc(gl->prompt, size) : malloc(size);
9975 if(!new_prompt)
9976 return;
9977 gl->prompt = new_prompt;
9978 };
9979 /*
9980 * Make a copy of the new prompt.
9981 */
9982 strlcpy(gl->prompt, prompt, size);
9983 };
9984 /*
9985 * Record the statistics of the new prompt.
9986 */
9987 gl->prompt_len = gl_displayed_prompt_width(gl);
9988 gl->prompt_changed = 1;
9989 gl_queue_redisplay(gl);
9990 return;
9991 }
9992
9993 /*.......................................................................
9994 * Work out the length of the current prompt on the terminal, according
9995 * to the current prompt formatting style.
9996 *
9997 * Input:
9998 * gl GetLine * The resource object of this library.
9999 * Output:
10000 * return int The number of displayed characters.
10001 */
10002 static int gl_displayed_prompt_width(GetLine *gl)
10003 {
10004 int slen=0; /* The displayed number of characters */
10005 const char *pptr; /* A pointer into prompt[] */
10006 /*
10007 * The length differs according to the prompt display style.
10008 */
10009 switch(gl->prompt_style) {
10010 case GL_LITERAL_PROMPT:
10011 return gl_displayed_string_width(gl, gl->prompt, -1, 0);
10012 break;
10013 case GL_FORMAT_PROMPT:
10014 /*
10015 * Add up the length of the displayed string, while filtering out
10016 * attribute directives.
10017 */
10018 for(pptr=gl->prompt; *pptr; pptr++) {
10019 /*
10020 * Does the latest character appear to be the start of a directive?
10021 */
10022 if(*pptr == '%') {
10023 /*
10024 * Check for and skip attribute changing directives.
10025 */
10026 switch(pptr[1]) {
10027 case 'B': case 'b': case 'U': case 'u': case 'S': case 's':
10028 pptr++;
10029 continue;
10030 /*
10031 * A literal % is represented by %%. Skip the leading %.
10032 */
10033 case '%':
10034 pptr++;
10035 break;
10036 };
10037 };
10038 slen += gl_displayed_char_width(gl, *pptr, slen);
10039 };
10040 break;
10041 };
10042 return slen;
10043 }
10044
10045 /*.......................................................................
10046 * Specify whether to heed text attribute directives within prompt
10047 * strings.
10048 *
10049 * Input:
10050 * gl GetLine * The resource object of gl_get_line().
10051 * style GlPromptStyle The style of prompt (see the definition of
10052 * GlPromptStyle in libtecla.h for details).
10053 */
10054 void gl_prompt_style(GetLine *gl, GlPromptStyle style)
10055 {
10056 if(gl) {
10057 sigset_t oldset; /* The signals that were blocked on entry to this block */
10058 /*
10059 * Temporarily block all signals.
10060 */
10061 gl_mask_signals(gl, &oldset);
10062 /*
10063 * Install the new style in gl while signals are blocked.
10064 */
10065 if(style != gl->prompt_style) {
10066 gl->prompt_style = style;
10067 gl->prompt_len = gl_displayed_prompt_width(gl);
10068 gl->prompt_changed = 1;
10069 gl_queue_redisplay(gl);
10070 };
10071 /*
10072 * Restore the process signal mask before returning.
10073 */
10074 gl_unmask_signals(gl, &oldset);
10075 };
10076 }
10077
10078 /*.......................................................................
10079 * Tell gl_get_line() how to respond to a given signal. This can be used
10080 * both to override the default responses to signals that gl_get_line()
10081 * normally catches and to add new signals to the list that are to be
10082 * caught.
10083 *
10084 * Input:
10085 * gl GetLine * The resource object of gl_get_line().
10086 * signo int The number of the signal to be caught.
10087 * flags unsigned A bitwise union of GlSignalFlags enumerators.
10088 * after GlAfterSignal What to do after the application's signal
10089 * handler has been called.
10090 * errno_value int The value to set errno to.
10091 * Output:
10092 * return int 0 - OK.
10093 * 1 - Error.
10094 */
10095 int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
10096 GlAfterSignal after, int errno_value)
10097 {
10098 sigset_t oldset; /* The signals that were blocked on entry to this function */
10099 int status; /* The return status of this function */
10100 /*
10101 * Check the arguments.
10102 */
10103 if(!gl) {
10104 errno = EINVAL;
10105 return 1;
10106 };
10107 /*
10108 * Block all signals while modifying the contents of gl.
10109 */
10110 if(gl_mask_signals(gl, &oldset))
10111 return 1;
10112 /*
10113 * Perform the modification while signals are blocked.
10114 */
10115 status = _gl_trap_signal(gl, signo, flags, after, errno_value);
10116 /*
10117 * Restore the process signal mask before returning.
10118 */
10119 gl_unmask_signals(gl, &oldset);
10120 return status;
10121 }
10122
10123 /*.......................................................................
10124 * This is the private body of the gl_trap_signal() function. It
10125 * assumes that the caller has checked its arguments and blocked the
10126 * delivery of signals.
10127 */
10128 static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
10129 GlAfterSignal after, int errno_value)
10130 {
10131 GlSignalNode *sig;
10132 /*
10133 * Complain if an attempt is made to trap untrappable signals.
10134 * These would otherwise cause errors later in gl_mask_signals().
10135 */
10136 if(0
10137 #ifdef SIGKILL
10138 || signo==SIGKILL
10139 #endif
10140 #ifdef SIGBLOCK
10141 || signo==SIGBLOCK
10142 #endif
10143 ) {
10144 return 1;
10145 };
10146 /*
10147 * See if the signal has already been registered.
10148 */
10149 for(sig=gl->sigs; sig && sig->signo != signo; sig = sig->next)
10150 ;
10151 /*
10152 * If the signal hasn't already been registered, allocate a node for
10153 * it.
10154 */
10155 if(!sig) {
10156 sig = (GlSignalNode *) _new_FreeListNode(gl->sig_mem);
10157 if(!sig)
10158 return 1;
10159 /*
10160 * Add the new node to the head of the list.
10161 */
10162 sig->next = gl->sigs;
10163 gl->sigs = sig;
10164 /*
10165 * Record the signal number.
10166 */
10167 sig->signo = signo;
10168 /*
10169 * Create a signal set that includes just this signal.
10170 */
10171 sigemptyset(&sig->proc_mask);
10172 if(sigaddset(&sig->proc_mask, signo) == -1) {
10173 _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
10174 sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig);
10175 return 1;
10176 };
10177 /*
10178 * Add the signal to the bit-mask of signals being trapped.
10179 */
10180 sigaddset(&gl->all_signal_set, signo);
10181 };
10182 /*
10183 * Record the new signal attributes.
10184 */
10185 sig->flags = flags;
10186 sig->after = after;
10187 sig->errno_value = errno_value;
10188 return 0;
10189 }
10190
10191 /*.......................................................................
10192 * Remove a signal from the list of signals that gl_get_line() traps.
10193 *
10194 * Input:
10195 * gl GetLine * The resource object of gl_get_line().
10196 * signo int The number of the signal to be ignored.
10197 * Output:
10198 * return int 0 - OK.
10199 * 1 - Error.
10200 */
10201 int gl_ignore_signal(GetLine *gl, int signo)
10202 {
10203 GlSignalNode *sig; /* The gl->sigs list node of the specified signal */
10204 GlSignalNode *prev; /* The node that precedes sig in the list */
10205 sigset_t oldset; /* The signals that were blocked on entry to this */
10206 /* function. */
10207 /*
10208 * Check the arguments.
10209 */
10210 if(!gl) {
10211 errno = EINVAL;
10212 return 1;
10213 };
10214 /*
10215 * Block all signals while modifying the contents of gl.
10216 */
10217 if(gl_mask_signals(gl, &oldset))
10218 return 1;
10219 /*
10220 * Find the node of the gl->sigs list which records the disposition
10221 * of the specified signal.
10222 */
10223 for(prev=NULL,sig=gl->sigs; sig && sig->signo != signo;
10224 prev=sig,sig=sig->next)
10225 ;
10226 if(sig) {
10227 /*
10228 * Remove the node from the list.
10229 */
10230 if(prev)
10231 prev->next = sig->next;
10232 else
10233 gl->sigs = sig->next;
10234 /*
10235 * Return the node to the freelist.
10236 */
10237 sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig);
10238 /*
10239 * Remove the signal from the bit-mask union of signals being trapped.
10240 */
10241 sigdelset(&gl->all_signal_set, signo);
10242 };
10243 /*
10244 * Restore the process signal mask before returning.
10245 */
10246 gl_unmask_signals(gl, &oldset);
10247 return 0;
10248 }
10249
10250 /*.......................................................................
10251 * This function is called when an input line has been completed. It
10252 * appends the specified newline character, terminates the line,
10253 * records the line in the history buffer if appropriate, and positions
10254 * the terminal cursor at the start of the next line.
10255 *
10256 * Input:
10257 * gl GetLine * The resource object of gl_get_line().
10258 * newline_char int The newline character to add to the end
10259 * of the line.
10260 * Output:
10261 * return int 0 - OK.
10262 * 1 - Error.
10263 */
10264 static int gl_line_ended(GetLine *gl, int newline_char)
10265 {
10266 /*
10267 * If the newline character is printable, display it at the end of
10268 * the line, and add it to the input line buffer.
10269 */
10270 if(isprint((int)(unsigned char) newline_char)) {
10271 if(gl_end_of_line(gl, 1, NULL) || gl_add_char_to_line(gl, newline_char))
10272 return 1;
10273 } else {
10274 /*
10275 * Otherwise just append a newline character to the input line buffer.
10276 */
10277 newline_char = '\n';
10278 gl_buffer_char(gl, newline_char, gl->ntotal);
10279 };
10280 /*
10281 * Add the line to the history buffer if it was entered with a
10282 * newline character.
10283 */
10284 if(gl->echo && gl->automatic_history && newline_char=='\n')
10285 (void) _gl_append_history(gl, gl->line);
10286 /*
10287 * Except when depending on the system-provided line editing, start a new
10288 * line after the end of the line that has just been entered.
10289 */
10290 if(gl->editor != GL_NO_EDITOR && gl_start_newline(gl, 1))
10291 return 1;
10292 /*
10293 * Record the successful return status.
10294 */
10295 gl_record_status(gl, GLR_NEWLINE, 0);
10296 /*
10297 * Attempt to flush any pending output.
10298 */
10299 (void) gl_flush_output(gl);
10300 /*
10301 * The next call to gl_get_line() will write the prompt for a new line
10302 * (or continue the above flush if incomplete), so if we manage to
10303 * flush the terminal now, report that we are waiting to write to the
10304 * terminal.
10305 */
10306 gl->pending_io = GLP_WRITE;
10307 return 0;
10308 }
10309
10310 /*.......................................................................
10311 * Return the last signal that was caught by the most recent call to
10312 * gl_get_line(), or -1 if no signals were caught. This is useful if
10313 * gl_get_line() returns errno=EINTR and you need to find out what signal
10314 * caused it to abort.
10315 *
10316 * Input:
10317 * gl GetLine * The resource object of gl_get_line().
10318 * Output:
10319 * return int The last signal caught by the most recent
10320 * call to gl_get_line(), or -1 if no signals
10321 * were caught.
10322 */
10323 int gl_last_signal(GetLine *gl)
10324 {
10325 int signo = -1; /* The requested signal number */
10326 if(gl) {
10327 sigset_t oldset; /* The signals that were blocked on entry to this block */
10328 /*
10329 * Temporarily block all signals.
10330 */
10331 gl_mask_signals(gl, &oldset);
10332 /*
10333 * Access gl now that signals are blocked.
10334 */
10335 signo = gl->last_signal;
10336 /*
10337 * Restore the process signal mask before returning.
10338 */
10339 gl_unmask_signals(gl, &oldset);
10340 };
10341 return signo;
10342 }
10343
10344 /*.......................................................................
10345 * Prepare to edit a new line.
10346 *
10347 * Input:
10348 * gl GetLine * The resource object of this library.
10349 * prompt char * The prompt to prefix the line with, or NULL to
10350 * use the same prompt that was used by the previous
10351 * line.
10352 * start_line char * The initial contents of the input line, or NULL
10353 * if it should start out empty.
10354 * start_pos int If start_line isn't NULL, this specifies the
10355 * index of the character over which the cursor
10356 * should initially be positioned within the line.
10357 * If you just want it to follow the last character
10358 * of the line, send -1.
10359 * Output:
10360 * return int 0 - OK.
10361 * 1 - Error.
10362 */
10363 static int gl_present_line(GetLine *gl, const char *prompt,
10364 const char *start_line, int start_pos)
10365 {
10366 /*
10367 * Reset the properties of the line.
10368 */
10369 gl_reset_input_line(gl);
10370 /*
10371 * Record the new prompt and its displayed width.
10372 */
10373 if(prompt)
10374 _gl_replace_prompt(gl, prompt);
10375 /*
10376 * Reset the history search pointers.
10377 */
10378 if(_glh_cancel_search(gl->glh)) {
10379 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
10380 return 1;
10381 };
10382 /*
10383 * If the previous line was entered via the repeat-history action,
10384 * preload the specified history line.
10385 */
10386 if(gl->preload_history) {
10387 gl->preload_history = 0;
10388 if(gl->preload_id) {
10389 if(_glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1)) {
10390 gl_update_buffer(gl); /* Compute gl->ntotal etc.. */
10391 gl->buff_curpos = gl->ntotal;
10392 } else {
10393 gl_truncate_buffer(gl, 0);
10394 };
10395 gl->preload_id = 0;
10396 };
10397 /*
10398 * Present a specified initial line?
10399 */
10400 } else if(start_line) {
10401 char *cptr; /* A pointer into gl->line[] */
10402 /*
10403 * Measure the length of the starting line.
10404 */
10405 int start_len = strlen(start_line);
10406 /*
10407 * If the length of the line is greater than the available space,
10408 * truncate it.
10409 */
10410 if(start_len > gl->linelen)
10411 start_len = gl->linelen;
10412 /*
10413 * Load the line into the buffer.
10414 */
10415 if(start_line != gl->line)
10416 gl_buffer_string(gl, start_line, start_len, 0);
10417 /*
10418 * Strip off any trailing newline and carriage return characters.
10419 */
10420 for(cptr=gl->line + gl->ntotal - 1; cptr >= gl->line &&
10421 (*cptr=='\n' || *cptr=='\r'); cptr--,gl->ntotal--)
10422 ;
10423 gl_truncate_buffer(gl, gl->ntotal < 0 ? 0 : gl->ntotal);
10424 /*
10425 * Where should the cursor be placed within the line?
10426 */
10427 if(start_pos < 0 || start_pos > gl->ntotal) {
10428 if(gl_place_cursor(gl, gl->ntotal))
10429 return 1;
10430 } else {
10431 if(gl_place_cursor(gl, start_pos))
10432 return 1;
10433 };
10434 /*
10435 * Clear the input line?
10436 */
10437 } else {
10438 gl_truncate_buffer(gl, 0);
10439 };
10440 /*
10441 * Arrange for the line to be displayed by gl_flush_output().
10442 */
10443 gl_queue_redisplay(gl);
10444 /*
10445 * Update the display.
10446 */
10447 return gl_flush_output(gl);
10448 }
10449
10450 /*.......................................................................
10451 * Reset all line input parameters for a new input line.
10452 *
10453 * Input:
10454 * gl GetLine * The line editor resource object.
10455 */
10456 static void gl_reset_input_line(GetLine *gl)
10457 {
10458 gl->ntotal = 0;
10459 gl->line[0] = '\0';
10460 gl->buff_curpos = 0;
10461 gl->term_curpos = 0;
10462 gl->term_len = 0;
10463 gl->insert_curpos = 0;
10464 gl->number = -1;
10465 gl->displayed = 0;
10466 gl->endline = 0;
10467 gl->redisplay = 0;
10468 gl->postpone = 0;
10469 gl->nbuf = 0;
10470 gl->nread = 0;
10471 gl->vi.command = 0;
10472 gl->vi.undo.line[0] = '\0';
10473 gl->vi.undo.ntotal = 0;
10474 gl->vi.undo.buff_curpos = 0;
10475 gl->vi.repeat.action.fn = 0;
10476 gl->vi.repeat.action.data = 0;
10477 gl->last_signal = -1;
10478 }
10479
10480 /*.......................................................................
10481 * Print an informational message to the terminal, after starting a new
10482 * line.
10483 *
10484 * Input:
10485 * gl GetLine * The line editor resource object.
10486 * ... const char * Zero or more strings to be printed.
10487 * ... void * The last argument must always be GL_END_INFO.
10488 * Output:
10489 * return int 0 - OK.
10490 * 1 - Error.
10491 */
10492 static int gl_print_info(GetLine *gl, ...)
10493 {
10494 va_list ap; /* The variable argument list */
10495 const char *s; /* The string being printed */
10496 int waserr = 0; /* True after an error */
10497 /*
10498 * Only display output when echoing is on.
10499 */
10500 if(gl->echo) {
10501 /*
10502 * Skip to the start of the next empty line before displaying the message.
10503 */
10504 if(gl_start_newline(gl, 1))
10505 return 1;
10506 /*
10507 * Display the list of provided messages.
10508 */
10509 va_start(ap, gl);
10510 while(!waserr && (s = va_arg(ap, const char *)) != GL_END_INFO)
10511 waserr = gl_print_raw_string(gl, 1, s, -1);
10512 va_end(ap);
10513 /*
10514 * Start a newline.
10515 */
10516 waserr = waserr || gl_print_raw_string(gl, 1, "\n\r", -1);
10517 /*
10518 * Arrange for the input line to be redrawn.
10519 */
10520 gl_queue_redisplay(gl);
10521 };
10522 return waserr;
10523 }
10524
10525 /*.......................................................................
10526 * Go to the start of the next empty line, ready to output miscellaneous
10527 * text to the screen.
10528 *
10529 * Note that when async-signal safety is required, the 'buffered'
10530 * argument must be 0.
10531 *
10532 * Input:
10533 * gl GetLine * The line editor resource object.
10534 * buffered int If true, used buffered I/O when writing to
10535 * the terminal. Otherwise use async-signal-safe
10536 * unbuffered I/O.
10537 * Output:
10538 * return int 0 - OK.
10539 * 1 - Error.
10540 */
10541 static int gl_start_newline(GetLine *gl, int buffered)
10542 {
10543 int waserr = 0; /* True after any I/O error */
10544 /*
10545 * Move the cursor to the start of the terminal line that follows the
10546 * last line of the partially enterred line. In order that this
10547 * function remain async-signal safe when write_fn is signal safe, we
10548 * can't call our normal output functions, since they call tputs(),
10549 * who's signal saftey isn't defined. Fortunately, we can simply use
10550 * \r and \n to move the cursor to the right place.
10551 */
10552 if(gl->displayed) { /* Is an input line currently displayed? */
10553 /*
10554 * On which terminal lines are the cursor and the last character of the
10555 * input line?
10556 */
10557 int curs_line = gl->term_curpos / gl->ncolumn;
10558 int last_line = gl->term_len / gl->ncolumn;
10559 /*
10560 * Move the cursor to the start of the line that follows the last
10561 * terminal line that is occupied by the input line.
10562 */
10563 for( ; curs_line < last_line + 1; curs_line++)
10564 waserr = waserr || gl_print_raw_string(gl, buffered, "\n", 1);
10565 waserr = waserr || gl_print_raw_string(gl, buffered, "\r", 1);
10566 /*
10567 * Mark the line as no longer displayed.
10568 */
10569 gl_line_erased(gl);
10570 };
10571 return waserr;
10572 }
10573
10574 /*.......................................................................
10575 * The callback through which all terminal output is routed.
10576 * This simply appends characters to a queue buffer, which is
10577 * subsequently flushed to the output channel by gl_flush_output().
10578 *
10579 * Input:
10580 * data void * The pointer to a GetLine line editor resource object
10581 * cast to (void *).
10582 * s const char * The string to be written.
10583 * n int The number of characters to write from s[].
10584 * Output:
10585 * return int The number of characters written. This will always
10586 * be equal to 'n' unless an error occurs.
10587 */
10588 static GL_WRITE_FN(gl_write_fn)
10589 {
10590 GetLine *gl = (GetLine *) data;
10591 int ndone = _glq_append_chars(gl->cq, s, n, gl->flush_fn, gl);
10592 if(ndone != n)
10593 _err_record_msg(gl->err, _glq_last_error(gl->cq), END_ERR_MSG);
10594 return ndone;
10595 }
10596
10597 /*.......................................................................
10598 * Ask gl_get_line() what caused it to return.
10599 *
10600 * Input:
10601 * gl GetLine * The line editor resource object.
10602 * Output:
10603 * return GlReturnStatus The return status of the last call to
10604 * gl_get_line().
10605 */
10606 GlReturnStatus gl_return_status(GetLine *gl)
10607 {
10608 GlReturnStatus rtn_status = GLR_ERROR; /* The requested status */
10609 if(gl) {
10610 sigset_t oldset; /* The signals that were blocked on entry to this block */
10611 /*
10612 * Temporarily block all signals.
10613 */
10614 gl_mask_signals(gl, &oldset);
10615 /*
10616 * Access gl while signals are blocked.
10617 */
10618 rtn_status = gl->rtn_status;
10619 /*
10620 * Restore the process signal mask before returning.
10621 */
10622 gl_unmask_signals(gl, &oldset);
10623 };
10624 return rtn_status;
10625 }
10626
10627 /*.......................................................................
10628 * In non-blocking server-I/O mode, this function should be called
10629 * from the application's external event loop to see what type of
10630 * terminal I/O is being waited for by gl_get_line(), and thus what
10631 * direction of I/O to wait for with select() or poll().
10632 *
10633 * Input:
10634 * gl GetLine * The resource object of gl_get_line().
10635 * Output:
10636 * return GlPendingIO The type of pending I/O being waited for.
10637 */
10638 GlPendingIO gl_pending_io(GetLine *gl)
10639 {
10640 GlPendingIO pending_io = GLP_WRITE; /* The requested information */
10641 if(gl) {
10642 sigset_t oldset; /* The signals that were blocked on entry to this block */
10643 /*
10644 * Temporarily block all signals.
10645 */
10646 gl_mask_signals(gl, &oldset);
10647 /*
10648 * Access gl while signals are blocked.
10649 */
10650 pending_io = gl->pending_io;
10651 /*
10652 * Restore the process signal mask before returning.
10653 */
10654 gl_unmask_signals(gl, &oldset);
10655 };
10656 return pending_io;
10657 }
10658
10659 /*.......................................................................
10660 * In server mode, this function configures the terminal for non-blocking
10661 * raw terminal I/O. In normal I/O mode it does nothing.
10662 *
10663 * Callers of this function must be careful to trap all signals that
10664 * terminate or suspend the program, and call gl_normal_io()
10665 * from the corresponding signal handlers in order to restore the
10666 * terminal to its original settings before the program is terminated
10667 * or suspended. They should also trap the SIGCONT signal to detect
10668 * when the program resumes, and ensure that its signal handler
10669 * call gl_raw_io() to redisplay the line and resume editing.
10670 *
10671 * This function is async signal safe.
10672 *
10673 * Input:
10674 * gl GetLine * The line editor resource object.
10675 * Output:
10676 * return int 0 - OK.
10677 * 1 - Error.
10678 */
10679 int gl_raw_io(GetLine *gl)
10680 {
10681 sigset_t oldset; /* The signals that were blocked on entry to this function */
10682 int status; /* The return status of _gl_raw_io() */
10683 /*
10684 * Check the arguments.
10685 */
10686 if(!gl) {
10687 errno = EINVAL;
10688 return 1;
10689 };
10690 /*
10691 * Block all signals.
10692 */
10693 if(gl_mask_signals(gl, &oldset))
10694 return 1;
10695 /*
10696 * Don't allow applications to switch into raw mode unless in server mode.
10697 */
10698 if(gl->io_mode != GL_SERVER_MODE) {
10699 _err_record_msg(gl->err, "Can't switch to raw I/O unless in server mode",
10700 END_ERR_MSG);
10701 errno = EPERM;
10702 status = 1;
10703 } else {
10704 /*
10705 * Execute the private body of the function while signals are blocked.
10706 */
10707 status = _gl_raw_io(gl, 1);
10708 };
10709 /*
10710 * Restore the process signal mask.
10711 */
10712 gl_unmask_signals(gl, &oldset);
10713 return status;
10714 }
10715
10716 /*.......................................................................
10717 * This is the private body of the public function, gl_raw_io().
10718 * It assumes that the caller has checked its arguments and blocked the
10719 * delivery of signals.
10720 *
10721 * This function is async signal safe.
10722 */
10723 static int _gl_raw_io(GetLine *gl, int redisplay)
10724 {
10725 /*
10726 * If we are already in the correct mode, do nothing.
10727 */
10728 if(gl->raw_mode)
10729 return 0;
10730 /*
10731 * Switch the terminal to raw mode.
10732 */
10733 if(gl->is_term && gl_raw_terminal_mode(gl))
10734 return 1;
10735 /*
10736 * Switch to non-blocking I/O mode?
10737 */
10738 if(gl->io_mode==GL_SERVER_MODE &&
10739 (gl_nonblocking_io(gl, gl->input_fd) ||
10740 gl_nonblocking_io(gl, gl->output_fd) ||
10741 (gl->file_fp && gl_nonblocking_io(gl, fileno(gl->file_fp))))) {
10742 if(gl->is_term)
10743 gl_restore_terminal_attributes(gl);
10744 return 1;
10745 };
10746 /*
10747 * If an input line is being entered, arrange for it to be
10748 * displayed.
10749 */
10750 if(redisplay) {
10751 gl->postpone = 0;
10752 gl_queue_redisplay(gl);
10753 };
10754 return 0;
10755 }
10756
10757 /*.......................................................................
10758 * Restore the terminal to the state that it had when
10759 * gl_raw_io() was last called. After calling
10760 * gl_raw_io(), this function must be called before
10761 * terminating or suspending the program, and before attempting other
10762 * uses of the terminal from within the program. See gl_raw_io()
10763 * for more details.
10764 *
10765 * Input:
10766 * gl GetLine * The line editor resource object.
10767 * Output:
10768 * return int 0 - OK.
10769 * 1 - Error.
10770 */
10771 int gl_normal_io(GetLine *gl)
10772 {
10773 sigset_t oldset; /* The signals that were blocked on entry to this function */
10774 int status; /* The return status of _gl_normal_io() */
10775 /*
10776 * Check the arguments.
10777 */
10778 if(!gl) {
10779 errno = EINVAL;
10780 return 1;
10781 };
10782 /*
10783 * Block all signals.
10784 */
10785 if(gl_mask_signals(gl, &oldset))
10786 return 1;
10787 /*
10788 * Execute the private body of the function while signals are blocked.
10789 */
10790 status = _gl_normal_io(gl);
10791 /*
10792 * Restore the process signal mask.
10793 */
10794 gl_unmask_signals(gl, &oldset);
10795 return status;
10796 }
10797
10798 /*.......................................................................
10799 * This is the private body of the public function, gl_normal_io().
10800 * It assumes that the caller has checked its arguments and blocked the
10801 * delivery of signals.
10802 */
10803 static int _gl_normal_io(GetLine *gl)
10804 {
10805 /*
10806 * If we are already in normal mode, do nothing.
10807 */
10808 if(!gl->raw_mode)
10809 return 0;
10810 /*
10811 * Postpone subsequent redisplays until after _gl_raw_io(gl, 1)
10812 * is next called.
10813 */
10814 gl->postpone = 1;
10815 /*
10816 * Switch back to blocking I/O. Note that this is essential to do
10817 * here, because when using non-blocking I/O, the terminal output
10818 * buffering code can't always make room for new output without calling
10819 * malloc(), and a call to malloc() would mean that this function
10820 * couldn't safely be called from signal handlers.
10821 */
10822 if(gl->io_mode==GL_SERVER_MODE &&
10823 (gl_blocking_io(gl, gl->input_fd) ||
10824 gl_blocking_io(gl, gl->output_fd) ||
10825 (gl->file_fp && gl_blocking_io(gl, fileno(gl->file_fp)))))
10826 return 1;
10827 /*
10828 * Move the cursor to the next empty terminal line. Note that
10829 * unbuffered I/O is requested, to ensure that gl_start_newline() be
10830 * async-signal-safe.
10831 */
10832 if(gl->is_term && gl_start_newline(gl, 0))
10833 return 1;
10834 /*
10835 * Switch the terminal to normal mode.
10836 */
10837 if(gl->is_term && gl_restore_terminal_attributes(gl)) {
10838 /*
10839 * On error, revert to non-blocking I/O if needed, so that on failure
10840 * we remain in raw mode.
10841 */
10842 if(gl->io_mode==GL_SERVER_MODE) {
10843 gl_nonblocking_io(gl, gl->input_fd);
10844 gl_nonblocking_io(gl, gl->output_fd);
10845 if(gl->file_fp)
10846 gl_nonblocking_io(gl, fileno(gl->file_fp));
10847 };
10848 return 1;
10849 };
10850 return 0;
10851 }
10852
10853 /*.......................................................................
10854 * This function allows you to install an additional completion
10855 * action, or to change the completion function of an existing
10856 * one. This should be called before the first call to gl_get_line()
10857 * so that the name of the action be defined before the user's
10858 * configuration file is read.
10859 *
10860 * Input:
10861 * gl GetLine * The resource object of the command-line input
10862 * module.
10863 * data void * This is passed to match_fn() whenever it is
10864 * called. It could, for example, point to a
10865 * symbol table that match_fn() would look up
10866 * matches in.
10867 * match_fn CplMatchFn * The function that will identify the prefix
10868 * to be completed from the input line, and
10869 * report matching symbols.
10870 * list_only int If non-zero, install an action that only lists
10871 * possible completions, rather than attempting
10872 * to perform the completion.
10873 * name const char * The name with which users can refer to the
10874 * binding in tecla configuration files.
10875 * keyseq const char * Either NULL, or a key sequence with which
10876 * to invoke the binding. This should be
10877 * specified in the same manner as key-sequences
10878 * in tecla configuration files (eg. "M-^I").
10879 * Output:
10880 * return int 0 - OK.
10881 * 1 - Error.
10882 */
10883 int gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
10884 int list_only, const char *name, const char *keyseq)
10885 {
10886 sigset_t oldset; /* The signals that were blocked on entry to this function */
10887 int status; /* The return status of _gl_completion_action() */
10888 /*
10889 * Check the arguments.
10890 */
10891 if(!gl || !name || !match_fn) {
10892 errno = EINVAL;
10893 return 1;
10894 };
10895 /*
10896 * Block all signals.
10897 */
10898 if(gl_mask_signals(gl, &oldset))
10899 return 1;
10900 /*
10901 * Install the new action while signals are blocked.
10902 */
10903 status = _gl_completion_action(gl, data, match_fn, list_only, name, keyseq);
10904 /*
10905 * Restore the process signal mask.
10906 */
10907 gl_unmask_signals(gl, &oldset);
10908 return status;
10909 }
10910
10911 /*.......................................................................
10912 * This is the private body of the public function, gl_completion_action().
10913 * It assumes that the caller has checked its arguments and blocked the
10914 * delivery of signals.
10915 */
10916 static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
10917 int list_only, const char *name,
10918 const char *keyseq)
10919 {
10920 KtKeyFn *current_fn; /* An existing action function */
10921 void *current_data; /* The action-function callback data */
10922 /*
10923 * Which action function is desired?
10924 */
10925 KtKeyFn *action_fn = list_only ? gl_list_completions : gl_complete_word;
10926 /*
10927 * Is there already an action of the specified name?
10928 */
10929 if(_kt_lookup_action(gl->bindings, name, ¤t_fn, ¤t_data) == 0) {
10930 /*
10931 * If the action has the same type as the one being requested,
10932 * simply change the contents of its GlCplCallback callback data.
10933 */
10934 if(current_fn == action_fn) {
10935 GlCplCallback *cb = (GlCplCallback *) current_data;
10936 cb->fn = match_fn;
10937 cb->data = data;
10938 } else {
10939 errno = EINVAL;
10940 _err_record_msg(gl->err,
10941 "Illegal attempt to change the type of an existing completion action",
10942 END_ERR_MSG);
10943 return 1;
10944 };
10945 /*
10946 * No existing action has the specified name.
10947 */
10948 } else {
10949 /*
10950 * Allocate a new GlCplCallback callback object.
10951 */
10952 GlCplCallback *cb = (GlCplCallback *) _new_FreeListNode(gl->cpl_mem);
10953 if(!cb) {
10954 errno = ENOMEM;
10955 _err_record_msg(gl->err, "Insufficient memory to add completion action",
10956 END_ERR_MSG);
10957 return 1;
10958 };
10959 /*
10960 * Record the completion callback data.
10961 */
10962 cb->fn = match_fn;
10963 cb->data = data;
10964 /*
10965 * Attempt to register the new action.
10966 */
10967 if(_kt_set_action(gl->bindings, name, action_fn, cb)) {
10968 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
10969 _del_FreeListNode(gl->cpl_mem, (void *) cb);
10970 return 1;
10971 };
10972 };
10973 /*
10974 * Bind the action to a given key-sequence?
10975 */
10976 if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) {
10977 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
10978 return 1;
10979 };
10980 return 0;
10981 }
10982
10983 /*.......................................................................
10984 * Register an application-provided function as an action function.
10985 * This should preferably be called before the first call to gl_get_line()
10986 * so that the name of the action becomes defined before the user's
10987 * configuration file is read.
10988 *
10989 * Input:
10990 * gl GetLine * The resource object of the command-line input
10991 * module.
10992 * data void * Arbitrary application-specific callback
10993 * data to be passed to the callback
10994 * function, fn().
10995 * fn GlActionFn * The application-specific function that
10996 * implements the action. This will be invoked
10997 * whenever the user presses any
10998 * key-sequence which is bound to this action.
10999 * name const char * The name with which users can refer to the
11000 * binding in tecla configuration files.
11001 * keyseq const char * The key sequence with which to invoke
11002 * the binding. This should be specified in the
11003 * same manner as key-sequences in tecla
11004 * configuration files (eg. "M-^I").
11005 * Output:
11006 * return int 0 - OK.
11007 * 1 - Error.
11008 */
11009 int gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
11010 const char *name, const char *keyseq)
11011 {
11012 sigset_t oldset; /* The signals that were blocked on entry to this function */
11013 int status; /* The return status of _gl_register_action() */
11014 /*
11015 * Check the arguments.
11016 */
11017 if(!gl || !name || !fn) {
11018 errno = EINVAL;
11019 return 1;
11020 };
11021 /*
11022 * Block all signals.
11023 */
11024 if(gl_mask_signals(gl, &oldset))
11025 return 1;
11026 /*
11027 * Install the new action while signals are blocked.
11028 */
11029 status = _gl_register_action(gl, data, fn, name, keyseq);
11030 /*
11031 * Restore the process signal mask.
11032 */
11033 gl_unmask_signals(gl, &oldset);
11034 return status;
11035 }
11036
11037 /*.......................................................................
11038 * This is the private body of the public function, gl_register_action().
11039 * It assumes that the caller has checked its arguments and blocked the
11040 * delivery of signals.
11041 */
11042 static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
11043 const char *name, const char *keyseq)
11044 {
11045 KtKeyFn *current_fn; /* An existing action function */
11046 void *current_data; /* The action-function callback data */
11047 /*
11048 * Get the action function which actually runs the application-provided
11049 * function.
11050 */
11051 KtKeyFn *action_fn = gl_run_external_action;
11052 /*
11053 * Is there already an action of the specified name?
11054 */
11055 if(_kt_lookup_action(gl->bindings, name, ¤t_fn, ¤t_data) == 0) {
11056 /*
11057 * If the action has the same type as the one being requested,
11058 * simply change the contents of its GlCplCallback callback data.
11059 */
11060 if(current_fn == action_fn) {
11061 GlExternalAction *a = (GlExternalAction *) current_data;
11062 a->fn = fn;
11063 a->data = data;
11064 } else {
11065 errno = EINVAL;
11066 _err_record_msg(gl->err,
11067 "Illegal attempt to change the type of an existing action",
11068 END_ERR_MSG);
11069 return 1;
11070 };
11071 /*
11072 * No existing action has the specified name.
11073 */
11074 } else {
11075 /*
11076 * Allocate a new GlCplCallback callback object.
11077 */
11078 GlExternalAction *a =
11079 (GlExternalAction *) _new_FreeListNode(gl->ext_act_mem);
11080 if(!a) {
11081 errno = ENOMEM;
11082 _err_record_msg(gl->err, "Insufficient memory to add completion action",
11083 END_ERR_MSG);
11084 return 1;
11085 };
11086 /*
11087 * Record the completion callback data.
11088 */
11089 a->fn = fn;
11090 a->data = data;
11091 /*
11092 * Attempt to register the new action.
11093 */
11094 if(_kt_set_action(gl->bindings, name, action_fn, a)) {
11095 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
11096 _del_FreeListNode(gl->cpl_mem, (void *) a);
11097 return 1;
11098 };
11099 };
11100 /*
11101 * Bind the action to a given key-sequence?
11102 */
11103 if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) {
11104 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
11105 return 1;
11106 };
11107 return 0;
11108 }
11109
11110 /*.......................................................................
11111 * Invoke an action function previously registered by a call to
11112 * gl_register_action().
11113 */
11114 static KT_KEY_FN(gl_run_external_action)
11115 {
11116 GlAfterAction status; /* The return value of the action function */
11117 /*
11118 * Get the container of the action function and associated callback data.
11119 */
11120 GlExternalAction *a = (GlExternalAction *) data;
11121 /*
11122 * Invoke the action function.
11123 */
11124 status = a->fn(gl, a->data, count, gl->buff_curpos, gl->line);
11125 /*
11126 * If the callback took us out of raw (possibly non-blocking) input
11127 * mode, restore this mode, and queue a redisplay of the input line.
11128 */
11129 if(_gl_raw_io(gl, 1))
11130 return 1;
11131 /*
11132 * Finally, check to see what the action function wants us to do next.
11133 */
11134 switch(status) {
11135 default:
11136 case GLA_ABORT:
11137 gl_record_status(gl, GLR_ERROR, errno);
11138 return 1;
11139 break;
11140 case GLA_RETURN:
11141 return gl_newline(gl, 1, NULL);
11142 break;
11143 case GLA_CONTINUE:
11144 break;
11145 };
11146 return 0;
11147 }
11148
11149 /*.......................................................................
11150 * In server-I/O mode the terminal is left in raw mode between calls
11151 * to gl_get_line(), so it is necessary for the application to install
11152 * terminal restoring signal handlers for signals that could terminate
11153 * or suspend the process, plus a terminal reconfiguration handler to
11154 * be called when a process resumption signal is received, and finally
11155 * a handler to be called when a terminal-resize signal is received.
11156 *
11157 * Since there are many signals that by default terminate or suspend
11158 * processes, and different systems support different sub-sets of
11159 * these signals, this function provides a convenient wrapper around
11160 * sigaction() for assigning the specified handlers to all appropriate
11161 * signals. It also arranges that when any one of these signals is
11162 * being handled, all other catchable signals are blocked. This is
11163 * necessary so that the specified signal handlers can safely call
11164 * gl_raw_io(), gl_normal_io() and gl_update_size() without
11165 * reentrancy issues.
11166 *
11167 * Input:
11168 * term_handler void (*)(int) The signal handler to invoke when
11169 * a process terminating signal is
11170 * received.
11171 * susp_handler void (*)(int) The signal handler to invoke when
11172 * a process suspending signal is
11173 * received.
11174 * cont_handler void (*)(int) The signal handler to invoke when
11175 * a process resumption signal is
11176 * received (ie. SIGCONT).
11177 * size_handler void (*)(int) The signal handler to invoke when
11178 * a terminal-resize signal (ie. SIGWINCH)
11179 * is received.
11180 * Output:
11181 * return int 0 - OK.
11182 * 1 - Error.
11183 */
11184 int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int),
11185 void (*cont_handler)(int), void (*size_handler)(int))
11186 {
11187 int i;
11188 /*
11189 * Search for signals of the specified classes, and assign the
11190 * associated signal handler to them.
11191 */
11192 for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
11193 const struct GlDefSignal *sig = gl_signal_list + i;
11194 if(sig->attr & GLSA_SUSP) {
11195 if(gl_set_tty_signal(sig->signo, term_handler))
11196 return 1;
11197 } else if(sig->attr & GLSA_TERM) {
11198 if(gl_set_tty_signal(sig->signo, susp_handler))
11199 return 1;
11200 } else if(sig->attr & GLSA_CONT) {
11201 if(gl_set_tty_signal(sig->signo, cont_handler))
11202 return 1;
11203 } else if(sig->attr & GLSA_SIZE) {
11204 if(gl_set_tty_signal(sig->signo, size_handler))
11205 return 1;
11206 };
11207 };
11208 return 0;
11209 }
11210
11211 /*.......................................................................
11212 * This is a private function of gl_tty_signals(). It installs a given
11213 * signal handler, and arranges that when that signal handler is being
11214 * invoked other signals are blocked. The latter is important to allow
11215 * functions like gl_normal_io(), gl_raw_io() and gl_update_size()
11216 * to be called from signal handlers.
11217 *
11218 * Input:
11219 * signo int The signal to be trapped.
11220 * handler void (*)(int) The signal handler to assign to the signal.
11221 */
11222 static int gl_set_tty_signal(int signo, void (*handler)(int))
11223 {
11224 SigAction act; /* The signal handler configuation */
11225 /*
11226 * Arrange to block all trappable signals except the one that is being
11227 * assigned (the trapped signal will be blocked automatically by the
11228 * system).
11229 */
11230 gl_list_trappable_signals(&act.sa_mask);
11231 sigdelset(&act.sa_mask, signo);
11232 /*
11233 * Assign the signal handler.
11234 */
11235 act.sa_handler = handler;
11236 /*
11237 * There is only one portable signal handling flag, and it isn't
11238 * relevant to us, so don't specify any flags.
11239 */
11240 act.sa_flags = 0;
11241 /*
11242 * Register the signal handler.
11243 */
11244 if(sigaction(signo, &act, NULL))
11245 return 1;
11246 return 0;
11247 }
11248
11249 /*.......................................................................
11250 * Display a left-justified string over multiple terminal lines,
11251 * taking account of the current width of the terminal. Optional
11252 * indentation and an optional prefix string can be specified to be
11253 * displayed at the start of each new terminal line used. Similarly,
11254 * an optional suffix can be specified to be displayed at the end of
11255 * each terminal line. If needed, a single paragraph can be broken
11256 * across multiple calls. Note that literal newlines in the input
11257 * string can be used to force a newline at any point and that you
11258 * should use this feature to explicitly end all paragraphs, including
11259 * at the end of the last string that you write. Note that when a new
11260 * line is started between two words that are separated by spaces,
11261 * those spaces are not output, whereas when a new line is started
11262 * because a newline character was found in the string, only the
11263 * spaces before the newline character are discarded.
11264 *
11265 * Input:
11266 * gl GetLine * The resource object of gl_get_line().
11267 * indentation int The number of spaces of indentation to write
11268 * at the beginning of each new terminal line.
11269 * prefix const char * An optional prefix string to write after the
11270 * indentation margin at the start of each new
11271 * terminal line. You can specify NULL if no
11272 * prefix is required.
11273 * suffix const char * An optional suffix string to draw at the end
11274 * of the terminal line. Spaces will be added
11275 * where necessary to ensure that the suffix ends
11276 * in the last column of the terminal line. If
11277 * no suffix is desired, specify NULL.
11278 * fill_char int The padding character to use when indenting
11279 * the line or padding up to the suffix.
11280 * def_width int If the terminal width isn't known, such as when
11281 * writing to a pipe or redirecting to a file,
11282 * this number specifies what width to assume.
11283 * start int The number of characters already written to
11284 * the start of the current terminal line. This
11285 * is primarily used to allow individual
11286 * paragraphs to be written over multiple calls
11287 * to this function, but can also be used to
11288 * allow you to start the first line of a
11289 * paragraph with a different prefix or
11290 * indentation than those specified above.
11291 * string const char * The string to be written.
11292 * Output:
11293 * return int On error -1 is returned. Otherwise the
11294 * return value is the terminal column index at
11295 * which the cursor was left after writing the
11296 * final word in the string. Successful return
11297 * values can thus be passed verbatim to the
11298 * 'start' arguments of subsequent calls to
11299 * gl_display_text() to allow the printing of a
11300 * paragraph to be broken across multiple calls
11301 * to gl_display_text().
11302 */
11303 int gl_display_text(GetLine *gl, int indentation, const char *prefix,
11304 const char *suffix, int fill_char,
11305 int def_width, int start, const char *string)
11306 {
11307 sigset_t oldset; /* The signals that were blocked on entry to this function */
11308 int status; /* The return status of _gl_completion_action() */
11309 /*
11310 * Check the arguments?
11311 */
11312 if(!gl || !string) {
11313 errno = EINVAL;
11314 return -1;
11315 };
11316 /*
11317 * Block all signals.
11318 */
11319 if(gl_mask_signals(gl, &oldset))
11320 return -1;
11321 /*
11322 * Display the text while signals are blocked.
11323 */
11324 status = _io_display_text(_io_write_stdio, gl->output_fp, indentation,
11325 prefix, suffix, fill_char,
11326 gl->ncolumn > 0 ? gl->ncolumn : def_width,
11327 start, string);
11328 /*
11329 * Restore the process signal mask.
11330 */
11331 gl_unmask_signals(gl, &oldset);
11332 return status;
11333 }
11334
11335 /*.......................................................................
11336 * Block all of the signals that we are currently trapping.
11337 *
11338 * Input:
11339 * gl GetLine * The resource object of gl_get_line().
11340 * Input/Output:
11341 * oldset sigset_t * The superseded process signal mask
11342 * will be return in *oldset unless oldset is
11343 * NULL.
11344 * Output:
11345 * return int 0 - OK.
11346 * 1 - Error.
11347 */
11348 static int gl_mask_signals(GetLine *gl, sigset_t *oldset)
11349 {
11350 /*
11351 * Block all signals in all_signal_set, along with any others that are
11352 * already blocked by the application.
11353 */
11354 if(sigprocmask(SIG_BLOCK, &gl->all_signal_set, oldset) >= 0) {
11355 gl->signals_masked = 1;
11356 return 0;
11357 };
11358 /*
11359 * On error attempt to query the current process signal mask, so
11360 * that oldset be the correct process signal mask to restore later
11361 * if the caller of this function ignores the error return value.
11362 */
11363 if(oldset)
11364 (void) sigprocmask(SIG_SETMASK, NULL, oldset);
11365 gl->signals_masked = 0;
11366 return 1;
11367 }
11368
11369 /*.......................................................................
11370 * Restore a process signal mask that was previously returned via the
11371 * oldset argument of gl_mask_signals().
11372 *
11373 * Input:
11374 * gl GetLine * The resource object of gl_get_line().
11375 * Input/Output:
11376 * oldset sigset_t * The process signal mask to be restored.
11377 * Output:
11378 * return int 0 - OK.
11379 * 1 - Error.
11380 */
11381 static int gl_unmask_signals(GetLine *gl, sigset_t *oldset)
11382 {
11383 gl->signals_masked = 0;
11384 return sigprocmask(SIG_SETMASK, oldset, NULL) < 0;
11385 }
11386
11387 /*.......................................................................
11388 * Arrange to temporarily catch the signals marked in gl->use_signal_set.
11389 *
11390 * Input:
11391 * gl GetLine * The resource object of gl_get_line().
11392 * Output:
11393 * return int 0 - OK.
11394 * 1 - Error.
11395 */
11396 static int gl_catch_signals(GetLine *gl)
11397 {
11398 return sigprocmask(SIG_UNBLOCK, &gl->use_signal_set, NULL) < 0;
11399 }
11400
11401 /*.......................................................................
11402 * Select the I/O mode to be used by gl_get_line().
11403 *
11404 * Input:
11405 * gl GetLine * The resource object of gl_get_line().
11406 * mode GlIOMode The I/O mode to establish.
11407 * Output:
11408 * return int 0 - OK.
11409 * 1 - Error.
11410 */
11411 int gl_io_mode(GetLine *gl, GlIOMode mode)
11412 {
11413 sigset_t oldset; /* The signals that were blocked on entry to this function */
11414 int status; /* The return status of _gl_io_mode() */
11415 /*
11416 * Check the arguments.
11417 */
11418 if(!gl) {
11419 errno = EINVAL;
11420 return 1;
11421 };
11422 /*
11423 * Check that the requested mode is known.
11424 */
11425 switch(mode) {
11426 case GL_NORMAL_MODE:
11427 case GL_SERVER_MODE:
11428 break;
11429 default:
11430 errno = EINVAL;
11431 _err_record_msg(gl->err, "Unknown gl_get_line() I/O mode requested.",
11432 END_ERR_MSG);
11433 return 1;
11434 };
11435 /*
11436 * Block all signals.
11437 */
11438 if(gl_mask_signals(gl, &oldset))
11439 return 1;
11440 /*
11441 * Invoke the private body of this function.
11442 */
11443 status = _gl_io_mode(gl, mode);
11444 /*
11445 * Restore the process signal mask.
11446 */
11447 gl_unmask_signals(gl, &oldset);
11448 return status;
11449 }
11450
11451 /*.......................................................................
11452 * This is the private body of the public function, gl_io_mode().
11453 * It assumes that the caller has checked its arguments and blocked the
11454 * delivery of signals.
11455 */
11456 static int _gl_io_mode(GetLine *gl, GlIOMode mode)
11457 {
11458 /*
11459 * Are we already in the specified mode?
11460 */
11461 if(mode == gl->io_mode)
11462 return 0;
11463 /*
11464 * First revert to normal I/O in the current I/O mode.
11465 */
11466 _gl_normal_io(gl);
11467 /*
11468 * Record the new mode.
11469 */
11470 gl->io_mode = mode;
11471 /*
11472 * Perform any actions needed by the new mode.
11473 */
11474 if(mode==GL_SERVER_MODE) {
11475 if(_gl_raw_io(gl, 1))
11476 return 1;
11477 };
11478 return 0;
11479 }
11480
11481 /*.......................................................................
11482 * Return extra information (ie. in addition to that provided by errno)
11483 * about the last error to occur in either gl_get_line() or its
11484 * associated public functions.
11485 *
11486 * Input:
11487 * gl GetLine * The resource object of gl_get_line().
11488 * Input/Output:
11489 * buff char * An optional output buffer. Note that if the
11490 * calling application calls any gl_*()
11491 * functions from signal handlers, it should
11492 * provide a buffer here, so that a copy of
11493 * the latest error message can safely be made
11494 * while signals are blocked.
11495 * n size_t The allocated size of buff[].
11496 * Output:
11497 * return const char * A pointer to the error message. This will
11498 * be the buff argument, unless buff==NULL, in
11499 * which case it will be a pointer to an
11500 * internal error buffer. In the latter case,
11501 * note that the contents of the returned buffer
11502 * will change on subsequent calls to any gl_*()
11503 * functions.
11504 */
11505 const char *gl_error_message(GetLine *gl, char *buff, size_t n)
11506 {
11507 if(!gl) {
11508 static const char *msg = "NULL GetLine argument";
11509 if(buff) {
11510 strncpy(buff, msg, n);
11511 buff[n-1] = '\0';
11512 } else {
11513 return msg;
11514 };
11515 } else if(buff) {
11516 sigset_t oldset; /* The signals that were blocked on entry to this block */
11517 /*
11518 * Temporarily block all signals.
11519 */
11520 gl_mask_signals(gl, &oldset);
11521 /*
11522 * Copy the error message into the specified buffer.
11523 */
11524 if(buff && n > 0) {
11525 strncpy(buff, _err_get_msg(gl->err), n);
11526 buff[n-1] = '\0';
11527 };
11528 /*
11529 * Restore the process signal mask before returning.
11530 */
11531 gl_unmask_signals(gl, &oldset);
11532 } else {
11533 return _err_get_msg(gl->err);
11534 };
11535 return buff;
11536 }
11537
11538 /*.......................................................................
11539 * Return the signal mask used by gl_get_line(). This is the set of
11540 * signals that gl_get_line() is currently configured to trap.
11541 *
11542 * Input:
11543 * gl GetLine * The resource object of gl_get_line().
11544 * Input/Output:
11545 * set sigset_t * The set of signals will be returned in *set,
11546 * in the form of a signal process mask, as
11547 * used by sigaction(), sigprocmask(),
11548 * sigpending(), sigsuspend(), sigsetjmp() and
11549 * other standard POSIX signal-aware
11550 * functions.
11551 * Output:
11552 * return int 0 - OK.
11553 * 1 - Error (examine errno for reason).
11554 */
11555 int gl_list_signals(GetLine *gl, sigset_t *set)
11556 {
11557 /*
11558 * Check the arguments.
11559 */
11560 if(!gl || !set) {
11561 if(gl)
11562 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
11563 errno = EINVAL;
11564 return 1;
11565 };
11566 /*
11567 * Copy the signal mask into *set.
11568 */
11569 memcpy(set, &gl->all_signal_set, sizeof(*set));
11570 return 0;
11571 }
11572
11573 /*.......................................................................
11574 * By default, gl_get_line() doesn't trap signals that are blocked
11575 * when it is called. This default can be changed either on a
11576 * per-signal basis by calling gl_trap_signal(), or on a global basis
11577 * by calling this function. What this function does is add the
11578 * GLS_UNBLOCK_SIG flag to all signals that are currently configured
11579 * to be trapped by gl_get_line(), such that when subsequent calls to
11580 * gl_get_line() wait for I/O, these signals are temporarily
11581 * unblocked. This behavior is useful in non-blocking server-I/O mode,
11582 * where it is used to avoid race conditions related to handling these
11583 * signals externally to gl_get_line(). See the demonstration code in
11584 * demo3.c, or the gl_handle_signal() man page for further
11585 * information.
11586 *
11587 * Input:
11588 * gl GetLine * The resource object of gl_get_line().
11589 */
11590 void gl_catch_blocked(GetLine *gl)
11591 {
11592 sigset_t oldset; /* The process signal mask to restore */
11593 GlSignalNode *sig; /* A signal node in gl->sigs */
11594 /*
11595 * Check the arguments.
11596 */
11597 if(!gl) {
11598 errno = EINVAL;
11599 return;
11600 };
11601 /*
11602 * Temporarily block all signals while we modify the contents of gl.
11603 */
11604 gl_mask_signals(gl, &oldset);
11605 /*
11606 * Add the GLS_UNBLOCK_SIG flag to all configured signals.
11607 */
11608 for(sig=gl->sigs; sig; sig=sig->next)
11609 sig->flags |= GLS_UNBLOCK_SIG;
11610 /*
11611 * Restore the process signal mask that was superseded by the call
11612 * to gl_mask_signals().
11613 */
11614 gl_unmask_signals(gl, &oldset);
11615 return;
11616 }
11617
11618 /*.......................................................................
11619 * Respond to signals who's default effects have important
11620 * consequences to gl_get_line(). This is intended for use in
11621 * non-blocking server mode, where the external event loop is
11622 * responsible for catching signals. Signals that are handled include
11623 * those that by default terminate or suspend the process, and the
11624 * signal that indicates that the terminal size has changed. Note that
11625 * this function is not signal safe and should thus not be called from
11626 * a signal handler itself. See the gl_io_mode() man page for how it
11627 * should be used.
11628 *
11629 * In the case of signals that by default terminate or suspend
11630 * processes, command-line editing will be suspended, the terminal
11631 * returned to a usable state, then the default disposition of the
11632 * signal restored and the signal resent, in order to suspend or
11633 * terminate the process. If the process subsequently resumes,
11634 * command-line editing is resumed.
11635 *
11636 * In the case of signals that indicate that the terminal has been
11637 * resized, the new size will be queried, and any input line that is
11638 * being edited will be redrawn to fit the new dimensions of the
11639 * terminal.
11640 *
11641 * Input:
11642 * signo int The number of the signal to respond to.
11643 * gl GetLine * The first element of an array of 'ngl' GetLine
11644 * objects.
11645 * ngl int The number of elements in the gl[] array. Normally
11646 * this will be one.
11647 */
11648 void gl_handle_signal(int signo, GetLine *gl, int ngl)
11649 {
11650 int attr; /* The attributes of the specified signal */
11651 sigset_t all_signals; /* The set of trappable signals */
11652 sigset_t oldset; /* The process signal mask to restore */
11653 int i;
11654 /*
11655 * NULL operation?
11656 */
11657 if(ngl < 1 || !gl)
11658 return;
11659 /*
11660 * Look up the default attributes of the specified signal.
11661 */
11662 attr = gl_classify_signal(signo);
11663 /*
11664 * If the signal isn't known, we are done.
11665 */
11666 if(!attr)
11667 return;
11668 /*
11669 * Temporarily block all signals while we modify the gl objects.
11670 */
11671 gl_list_trappable_signals(&all_signals);
11672 sigprocmask(SIG_BLOCK, &all_signals, &oldset);
11673 /*
11674 * Suspend or terminate the process?
11675 */
11676 if(attr & (GLSA_SUSP | GLSA_TERM)) {
11677 gl_suspend_process(signo, gl, ngl);
11678 /*
11679 * Resize the terminal? Note that ioctl() isn't defined as being
11680 * signal safe, so we can't call gl_update_size() here. However,
11681 * gl_get_line() checks for resizes on each call, so simply arrange
11682 * for the application's event loop to call gl_get_line() as soon as
11683 * it becomes possible to write to the terminal. Note that if the
11684 * caller is calling select() or poll when this happens, these functions
11685 * get interrupted, since a signal has been caught.
11686 */
11687 } else if(attr & GLSA_SIZE) {
11688 for(i=0; i<ngl; i++)
11689 gl[i].pending_io = GLP_WRITE;
11690 };
11691 /*
11692 * Restore the process signal mask that was superseded by the call
11693 * to gl_mask_signals().
11694 */
11695 sigprocmask(SIG_SETMASK, &oldset, NULL);
11696 return;
11697 }
11698
11699 /*.......................................................................
11700 * Respond to an externally caught process suspension or
11701 * termination signal.
11702 *
11703 * After restoring the terminal to a usable state, suspend or
11704 * terminate the calling process, using the original signal with its
11705 * default disposition restored to do so. If the process subsequently
11706 * resumes, resume editing any input lines that were being entered.
11707 *
11708 * Input:
11709 * signo int The signal number to suspend the process with. Note
11710 * that the default disposition of this signal will be
11711 * restored before the signal is sent, so provided
11712 * that the default disposition of this signal is to
11713 * either suspend or terminate the application,
11714 * that is what wil happen, regardless of what signal
11715 * handler is currently assigned to this signal.
11716 * gl GetLine * The first element of an array of 'ngl' GetLine objects
11717 * whose terminals should be restored to a sane state
11718 * while the application is suspended.
11719 * ngl int The number of elements in the gl[] array.
11720 */
11721 static void gl_suspend_process(int signo, GetLine *gl, int ngl)
11722 {
11723 sigset_t only_signo; /* A signal set containing just signo */
11724 sigset_t oldset; /* The signal mask on entry to this function */
11725 sigset_t all_signals; /* A signal set containing all signals */
11726 struct sigaction old_action; /* The current signal handler */
11727 struct sigaction def_action; /* The default signal handler */
11728 int i;
11729 /*
11730 * Create a signal mask containing the signal that was trapped.
11731 */
11732 sigemptyset(&only_signo);
11733 sigaddset(&only_signo, signo);
11734 /*
11735 * Temporarily block all signals.
11736 */
11737 gl_list_trappable_signals(&all_signals);
11738 sigprocmask(SIG_BLOCK, &all_signals, &oldset);
11739 /*
11740 * Restore the terminal to a usable state.
11741 */
11742 for(i=0; i<ngl; i++) {
11743 GetLine *obj = gl + i;
11744 if(obj->raw_mode) {
11745 _gl_normal_io(obj);
11746 if(!obj->raw_mode) /* Check that gl_normal_io() succeded */
11747 obj->raw_mode = -1; /* Flag raw mode as needing to be restored */
11748 };
11749 };
11750 /*
11751 * Restore the system default disposition of the signal that we
11752 * caught. Note that this signal is currently blocked. Note that we
11753 * don't use memcpy() to copy signal sets here, because the signal safety
11754 * of memcpy() is undefined.
11755 */
11756 def_action.sa_handler = SIG_DFL;
11757 {
11758 char *orig = (char *) &all_signals;
11759 char *dest = (char *) &def_action.sa_mask;
11760 for(i=0; i<sizeof(sigset_t); i++)
11761 *dest++ = *orig++;
11762 };
11763 sigaction(signo, &def_action, &old_action);
11764 /*
11765 * Resend the signal, and unblock it so that it gets delivered to
11766 * the application. This will invoke the default action of this signal.
11767 */
11768 raise(signo);
11769 sigprocmask(SIG_UNBLOCK, &only_signo, NULL);
11770 /*
11771 * If the process resumes again, it will resume here.
11772 * Block the signal again, then restore our signal handler.
11773 */
11774 sigprocmask(SIG_BLOCK, &only_signo, NULL);
11775 sigaction(signo, &old_action, NULL);
11776 /*
11777 * Resume command-line editing.
11778 */
11779 for(i=0; i<ngl; i++) {
11780 GetLine *obj = gl + i;
11781 if(obj->raw_mode == -1) { /* Did we flag the need to restore raw mode? */
11782 obj->raw_mode = 0; /* gl_raw_io() does nothing unless raw_mode==0 */
11783 _gl_raw_io(obj, 1);
11784 };
11785 };
11786 /*
11787 * Restore the process signal mask to the way it was when this function
11788 * was called.
11789 */
11790 sigprocmask(SIG_SETMASK, &oldset, NULL);
11791 return;
11792 }
11793
11794 /*.......................................................................
11795 * Return the information about the default attributes of a given signal.
11796 * The attributes that are returned are as defined by the standards that
11797 * created them, including POSIX, SVR4 and 4.3+BSD, and are taken from a
11798 * table in Richard Steven's book, "Advanced programming in the UNIX
11799 * environment".
11800 *
11801 * Input:
11802 * signo int The signal to be characterized.
11803 * Output:
11804 * return int A bitwise union of GlSigAttr enumerators, or 0
11805 * if the signal isn't known.
11806 */
11807 static int gl_classify_signal(int signo)
11808 {
11809 int i;
11810 /*
11811 * Search for the specified signal in the gl_signal_list[] table.
11812 */
11813 for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
11814 const struct GlDefSignal *sig = gl_signal_list + i;
11815 if(sig->signo == signo)
11816 return sig->attr;
11817 };
11818 /*
11819 * Signal not known.
11820 */
11821 return 0;
11822 }
11823
11824 /*.......................................................................
11825 * When in non-blocking server mode, this function can be used to abandon
11826 * the current incompletely entered input line, and prepare to start
11827 * editing a new line on the next call to gl_get_line().
11828 *
11829 * Input:
11830 * gl GetLine * The line editor resource object.
11831 */
11832 void gl_abandon_line(GetLine *gl)
11833 {
11834 sigset_t oldset; /* The process signal mask to restore */
11835 /*
11836 * Check the arguments.
11837 */
11838 if(!gl) {
11839 errno = EINVAL;
11840 return;
11841 };
11842 /*
11843 * Temporarily block all signals while we modify the contents of gl.
11844 */
11845 gl_mask_signals(gl, &oldset);
11846 /*
11847 * Mark the input line as discarded.
11848 */
11849 _gl_abandon_line(gl);
11850 /*
11851 * Restore the process signal mask that was superseded by the call
11852 * to gl_mask_signals().
11853 */
11854 gl_unmask_signals(gl, &oldset);
11855 return;
11856 }
11857
11858 /*.......................................................................
11859 * This is the private body of the gl_abandon_line() function. It
11860 * assumes that the caller has checked its arguments and blocked the
11861 * delivery of signals.
11862 */
11863 void _gl_abandon_line(GetLine *gl)
11864 {
11865 gl->endline = 1;
11866 gl->pending_io = GLP_WRITE;
11867 }
11868
11869 /*.......................................................................
11870 * How many characters are needed to write a number as an octal string?
11871 *
11872 * Input:
11873 * num unsigned The to be measured.
11874 * Output:
11875 * return int The number of characters needed.
11876 */
11877 static int gl_octal_width(unsigned num)
11878 {
11879 int n; /* The number of characters needed to render the number */
11880 for(n=1; num /= 8; n++)
11881 ;
11882 return n;
11883 }
11884
11885 /*.......................................................................
11886 * Tell gl_get_line() the current terminal size. Note that this is only
11887 * necessary on systems where changes in terminal size aren't reported
11888 * via SIGWINCH.
11889 *
11890 * Input:
11891 * gl GetLine * The resource object of gl_get_line().
11892 * ncolumn int The number of columns in the terminal.
11893 * nline int The number of lines in the terminal.
11894 * Output:
11895 * return int 0 - OK.
11896 * 1 - Error.
11897 */
11898 int gl_set_term_size(GetLine *gl, int ncolumn, int nline)
11899 {
11900 sigset_t oldset; /* The signals that were blocked on entry */
11901 /* to this function */
11902 int status; /* The return status */
11903 /*
11904 * Block all signals while accessing gl.
11905 */
11906 gl_mask_signals(gl, &oldset);
11907 /*
11908 * Install the new terminal size.
11909 */
11910 status = _gl_set_term_size(gl, ncolumn, nline);
11911 /*
11912 * Restore the process signal mask before returning.
11913 */
11914 gl_unmask_signals(gl, &oldset);
11915 return status;
11916 }
11917
11918 /*.......................................................................
11919 * This is the private body of the gl_set_term_size() function. It
11920 * assumes that the caller has checked its arguments and blocked the
11921 * delivery of signals.
11922 */
11923 static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline)
11924 {
11925 /*
11926 * Check the arguments.
11927 */
11928 if(!gl) {
11929 errno = EINVAL;
11930 return 1;
11931 };
11932 /*
11933 * Reject non-sensical dimensions.
11934 */
11935 if(ncolumn <= 0 || nline <= 0) {
11936 _err_record_msg(gl->err, "Invalid terminal size", END_ERR_MSG);
11937 errno = EINVAL;
11938 return 1;
11939 };
11940 /*
11941 * Install the new dimensions in the terminal driver if possible, so
11942 * that future calls to gl_query_size() get the new value.
11943 */
11944 #ifdef TIOCSWINSZ
11945 if(gl->is_term) {
11946 struct winsize size;
11947 size.ws_row = nline;
11948 size.ws_col = ncolumn;
11949 size.ws_xpixel = 0;
11950 size.ws_ypixel = 0;
11951 if(ioctl(gl->output_fd, TIOCSWINSZ, &size) == -1) {
11952 _err_record_msg(gl->err, "Can't change terminal size", END_ERR_MSG);
11953 return 1;
11954 };
11955 };
11956 #endif
11957 /*
11958 * If an input line is in the process of being edited, redisplay it to
11959 * accomodate the new dimensions, and record the new dimensions in
11960 * gl->nline and gl->ncolumn.
11961 */
11962 return gl_handle_tty_resize(gl, ncolumn, nline);
11963 }
11964
11965 /*.......................................................................
11966 * Record a character in the input line buffer at a given position.
11967 *
11968 * Input:
11969 * gl GetLine * The resource object of gl_get_line().
11970 * c char The character to be recorded.
11971 * bufpos int The index in the buffer at which to record the
11972 * character.
11973 * Output:
11974 * return int 0 - OK.
11975 * 1 - Insufficient room.
11976 */
11977 static int gl_buffer_char(GetLine *gl, char c, int bufpos)
11978 {
11979 /*
11980 * Guard against buffer overruns.
11981 */
11982 if(bufpos >= gl->linelen)
11983 return 1;
11984 /*
11985 * Record the new character.
11986 */
11987 gl->line[bufpos] = c;
11988 /*
11989 * If the new character was placed beyond the end of the current input
11990 * line, update gl->ntotal to reflect the increased number of characters
11991 * that are in gl->line, and terminate the string.
11992 */
11993 if(bufpos >= gl->ntotal) {
11994 gl->ntotal = bufpos+1;
11995 gl->line[gl->ntotal] = '\0';
11996 };
11997 return 0;
11998 }
11999
12000 /*.......................................................................
12001 * Copy a given string into the input buffer, overwriting the current
12002 * contents.
12003 *
12004 * Input:
12005 * gl GetLine * The resource object of gl_get_line().
12006 * s const char * The string to be recorded.
12007 * n int The number of characters to be copied from the
12008 * string.
12009 * bufpos int The index in the buffer at which to place the
12010 * the first character of the string.
12011 * Output:
12012 * return int 0 - OK.
12013 * 1 - String truncated to fit.
12014 */
12015 static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos)
12016 {
12017 int nnew; /* The number of characters actually recorded */
12018 int i;
12019 /*
12020 * How many of the characters will fit within the buffer?
12021 */
12022 nnew = bufpos + n <= gl->linelen ? n : (gl->linelen - bufpos);
12023 /*
12024 * Record the first nnew characters of s[] in the buffer.
12025 */
12026 for(i=0; i<nnew; i++)
12027 gl_buffer_char(gl, s[i], bufpos + i);
12028 /*
12029 * Was the string truncated?
12030 */
12031 return nnew < n;
12032 }
12033
12034 /*.......................................................................
12035 * Make room in the input buffer for a string to be inserted. This
12036 * involves moving the characters that follow a specified point, towards
12037 * the end of the buffer.
12038 *
12039 * Input:
12040 * gl GetLine * The resource object of gl_get_line().
12041 * start int The index of the first character to be moved.
12042 * n int The width of the gap.
12043 * Output:
12044 * return int 0 - OK.
12045 * 1 - Insufficient room.
12046 */
12047 static int gl_make_gap_in_buffer(GetLine *gl, int start, int n)
12048 {
12049 /*
12050 * Ensure that the buffer has sufficient space.
12051 */
12052 if(gl->ntotal + n > gl->linelen)
12053 return 1;
12054 /*
12055 * Move everything including and beyond the character at 'start'
12056 * towards the end of the string.
12057 */
12058 memmove(gl->line + start + n, gl->line + start, gl->ntotal - start + 1);
12059 /*
12060 * Update the recorded size of the line.
12061 */
12062 gl->ntotal += n;
12063 return 1;
12064 }
12065
12066 /*.......................................................................
12067 * Remove a given number of characters from the input buffer. This
12068 * involves moving the characters that follow the removed characters to
12069 * where the removed sub-string started in the input buffer.
12070 *
12071 * Input:
12072 * gl GetLine * The resource object of gl_get_line().
12073 * start int The first character to be removed.
12074 * n int The number of characters to remove.
12075 */
12076 static void gl_remove_from_buffer(GetLine *gl, int start, int n)
12077 {
12078 memmove(gl->line + start, gl->line + start + n, gl->ntotal - start - n + 1);
12079 /*
12080 * Update the recorded size of the line.
12081 */
12082 gl->ntotal -= n;
12083 }
12084
12085 /*.......................................................................
12086 * Truncate the string in the input line buffer after a given number of
12087 * characters.
12088 *
12089 * Input:
12090 * gl GetLine * The resource object of gl_get_line().
12091 * n int The new length of the line.
12092 * Output:
12093 * return int 0 - OK.
12094 * 1 - n > gl->linelen.
12095 */
12096 static int gl_truncate_buffer(GetLine *gl, int n)
12097 {
12098 if(n > gl->linelen)
12099 return 1;
12100 gl->line[n] = '\0';
12101 gl->ntotal = n;
12102 return 0;
12103 }
12104
12105 /*.......................................................................
12106 * When the contents of gl->line[] are changed without calling any of the
12107 * gl_ buffer manipulation functions, this function must be called to
12108 * compute the length of this string, and ancillary information.
12109 *
12110 * Input:
12111 * gl GetLine * The resource object of gl_get_line().
12112 */
12113 static void gl_update_buffer(GetLine *gl)
12114 {
12115 int len; /* The length of the line */
12116 /*
12117 * Measure the length of the input line.
12118 */
12119 for(len=0; len <= gl->linelen && gl->line[len]; len++)
12120 ;
12121 /*
12122 * Just in case the string wasn't correctly terminated, do so here.
12123 */
12124 gl->line[len] = '\0';
12125 /*
12126 * Record the number of characters that are now in gl->line[].
12127 */
12128 gl->ntotal = len;
12129 /*
12130 * Ensure that the cursor stays within the bounds of the modified
12131 * input line.
12132 */
12133 if(gl->buff_curpos > gl->ntotal)
12134 gl->buff_curpos = gl->ntotal;
12135 /*
12136 * Arrange for the input line to be redrawn.
12137 */
12138 gl_queue_redisplay(gl);
12139 return;
12140 }
12141
12142 /*.......................................................................
12143 * Erase the displayed input line, including its prompt, and leave the
12144 * cursor where the erased line started. Note that to allow this
12145 * function to be used when responding to a terminal resize, this
12146 * function is designed to work even if the horizontal cursor position
12147 * doesn't match the internally recorded position.
12148 *
12149 * Input:
12150 * gl GetLine * The resource object of gl_get_line().
12151 * Output:
12152 * return int 0 - OK.
12153 * 1 - Error.
12154 */
12155 static int gl_erase_line(GetLine *gl)
12156 {
12157 /*
12158 * Is a line currently displayed?
12159 */
12160 if(gl->displayed) {
12161 /*
12162 * Relative the the start of the input line, which terminal line of
12163 * the current input line is the cursor currently on?
12164 */
12165 int cursor_line = gl->term_curpos / gl->ncolumn;
12166 /*
12167 * Move the cursor to the start of the line.
12168 */
12169 for( ; cursor_line > 0; cursor_line--) {
12170 if(gl_print_control_sequence(gl, 1, gl->up))
12171 return 1;
12172 };
12173 if(gl_print_control_sequence(gl, 1, gl->bol))
12174 return 1;
12175 /*
12176 * Clear from the start of the line to the end of the terminal.
12177 */
12178 if(gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
12179 return 1;
12180 /*
12181 * Mark the line as no longer displayed.
12182 */
12183 gl_line_erased(gl);
12184 };
12185 return 0;
12186 }
12187
12188 /*.......................................................................
12189 * Arrange for the input line to be redisplayed by gl_flush_output(),
12190 * as soon as the output queue becomes empty.
12191 *
12192 * Input:
12193 * gl GetLine * The resource object of gl_get_line().
12194 */
12195 static void gl_queue_redisplay(GetLine *gl)
12196 {
12197 gl->redisplay = 1;
12198 gl->pending_io = GLP_WRITE;
12199 }
12200
12201 /*.......................................................................
12202 * Truncate the displayed input line starting from the current
12203 * terminal cursor position, and leave the cursor at the end of the
12204 * truncated line. The input-line buffer is not affected.
12205 *
12206 * Input:
12207 * gl GetLine * The resource object of gl_get_line().
12208 * Output:
12209 * return int 0 - OK.
12210 * 1 - Error.
12211 */
12212 static int gl_truncate_display(GetLine *gl)
12213 {
12214 /*
12215 * Keep a record of the current terminal cursor position.
12216 */
12217 int term_curpos = gl->term_curpos;
12218 /*
12219 * First clear from the cursor to the end of the current input line.
12220 */
12221 if(gl_print_control_sequence(gl, 1, gl->clear_eol))
12222 return 1;
12223 /*
12224 * If there is more than one line displayed, go to the start of the
12225 * next line and clear from there to the end of the display. Note that
12226 * we can't use clear_eod to do the whole job of clearing from the
12227 * current cursor position to the end of the terminal because
12228 * clear_eod is only defined when used at the start of a terminal line
12229 * (eg. with gnome terminals, clear_eod clears from the start of the
12230 * current terminal line, rather than from the current cursor
12231 * position).
12232 */
12233 if(gl->term_len / gl->ncolumn > gl->term_curpos / gl->ncolumn) {
12234 if(gl_print_control_sequence(gl, 1, gl->down) ||
12235 gl_print_control_sequence(gl, 1, gl->bol) ||
12236 gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
12237 return 1;
12238 /*
12239 * Where is the cursor now?
12240 */
12241 gl->term_curpos = gl->ncolumn * (term_curpos / gl->ncolumn + 1);
12242 /*
12243 * Restore the cursor position.
12244 */
12245 gl_set_term_curpos(gl, term_curpos);
12246 };
12247 /*
12248 * Update the recorded position of the final character.
12249 */
12250 gl->term_len = gl->term_curpos;
12251 return 0;
12252 }
12253
12254 /*.......................................................................
12255 * Return the set of all trappable signals.
12256 *
12257 * Input:
12258 * signals sigset_t * The set of signals will be recorded in
12259 * *signals.
12260 */
12261 static void gl_list_trappable_signals(sigset_t *signals)
12262 {
12263 /*
12264 * Start with the set of all signals.
12265 */
12266 sigfillset(signals);
12267 /*
12268 * Remove un-trappable signals from this set.
12269 */
12270 #ifdef SIGKILL
12271 sigdelset(signals, SIGKILL);
12272 #endif
12273 #ifdef SIGSTOP
12274 sigdelset(signals, SIGSTOP);
12275 #endif
12276 }
12277
12278 /*.......................................................................
12279 * Read an input line from a non-interactive input stream.
12280 *
12281 * Input:
12282 * gl GetLine * The resource object of gl_get_line().
12283 * Output:
12284 * return int 0 - OK
12285 * 1 - Error.
12286 */
12287 static int gl_read_stream_line(GetLine *gl)
12288 {
12289 char c = '\0'; /* The latest character read from fp */
12290 /*
12291 * Record the fact that we are about to read input.
12292 */
12293 gl->pending_io = GLP_READ;
12294 /*
12295 * If we are starting a new line, reset the line-input parameters.
12296 */
12297 if(gl->endline)
12298 gl_reset_input_line(gl);
12299 /*
12300 * Read one character at a time.
12301 */
12302 while(gl->ntotal < gl->linelen && c != '\n') {
12303 /*
12304 * Attempt to read one more character.
12305 */
12306 switch(gl_read_input(gl, &c)) {
12307 case GL_READ_OK:
12308 break;
12309 case GL_READ_EOF: /* Reached end-of-file? */
12310 /*
12311 * If any characters were read before the end-of-file condition,
12312 * interpolate a newline character, so that the caller sees a
12313 * properly terminated line. Otherwise return an end-of-file
12314 * condition.
12315 */
12316 if(gl->ntotal > 0) {
12317 c = '\n';
12318 } else {
12319 gl_record_status(gl, GLR_EOF, 0);
12320 return 1;
12321 };
12322 break;
12323 case GL_READ_BLOCKED: /* Input blocked? */
12324 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
12325 return 1;
12326 break;
12327 case GL_READ_ERROR: /* I/O error? */
12328 return 1;
12329 break;
12330 };
12331 /*
12332 * Append the character to the line buffer.
12333 */
12334 if(gl_buffer_char(gl, c, gl->ntotal))
12335 return 1;
12336 };
12337 /*
12338 * Was the end of the input line reached before running out of buffer space?
12339 */
12340 gl->endline = (c == '\n');
12341 return 0;
12342 }
12343
12344 /*.......................................................................
12345 * Read a single character from a non-interactive input stream.
12346 *
12347 * Input:
12348 * gl GetLine * The resource object of gl_get_line().
12349 * Output:
12350 * return int The character, or EOF on error.
12351 */
12352 static int gl_read_stream_char(GetLine *gl)
12353 {
12354 char c = '\0'; /* The latest character read from fp */
12355 int retval = EOF; /* The return value of this function */
12356 /*
12357 * Arrange to discard any incomplete input line.
12358 */
12359 _gl_abandon_line(gl);
12360 /*
12361 * Record the fact that we are about to read input.
12362 */
12363 gl->pending_io = GLP_READ;
12364 /*
12365 * Attempt to read one more character.
12366 */
12367 switch(gl_read_input(gl, &c)) {
12368 case GL_READ_OK: /* Success */
12369 retval = c;
12370 break;
12371 case GL_READ_BLOCKED: /* The read blocked */
12372 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
12373 retval = EOF; /* Failure */
12374 break;
12375 case GL_READ_EOF: /* End of file reached */
12376 gl_record_status(gl, GLR_EOF, 0);
12377 retval = EOF; /* Failure */
12378 break;
12379 case GL_READ_ERROR:
12380 retval = EOF; /* Failure */
12381 break;
12382 };
12383 return retval;
12384 }
12385
12386 /*.......................................................................
12387 * Bind a key sequence to a given action.
12388 *
12389 * Input:
12390 * gl GetLine * The resource object of gl_get_line().
12391 * origin GlKeyOrigin The originator of the key binding.
12392 * key const char * The key-sequence to be bound (or unbound).
12393 * action const char * The name of the action to bind the key to,
12394 * or either NULL or "" to unbind the
12395 * key-sequence.
12396 * Output:
12397 * return int 0 - OK
12398 * 1 - Error.
12399 */
12400 int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin, const char *keyseq,
12401 const char *action)
12402 {
12403 KtBinder binder; /* The private internal equivalent of 'origin' */
12404 /*
12405 * Check the arguments.
12406 */
12407 if(!gl || !keyseq) {
12408 errno = EINVAL;
12409 if(gl)
12410 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
12411 return 1;
12412 };
12413 /*
12414 * An empty action string requests that the key-sequence be unbound.
12415 * This is indicated to _kt_set_keybinding() by passing a NULL action
12416 * string, so convert an empty string to a NULL action pointer.
12417 */
12418 if(action && *action=='\0')
12419 action = NULL;
12420 /*
12421 * Translate the public originator enumeration to the private equivalent.
12422 */
12423 binder = origin==GL_USER_KEY ? KTB_USER : KTB_NORM;
12424 /*
12425 * Bind the action to a given key-sequence?
12426 */
12427 if(keyseq && _kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
12428 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
12429 return 1;
12430 };
12431 return 0;
12432 }
12433
12434 /*.......................................................................
12435 * This is the public wrapper around the gl_clear_termina() function.
12436 * It clears the terminal and leaves the cursor at the home position.
12437 * In server I/O mode, the next call to gl_get_line() will also
12438 * redisplay the current input line.
12439 *
12440 * Input:
12441 * gl GetLine * The resource object of gl_get_line().
12442 * Output:
12443 * return int 0 - OK.
12444 * 1 - Error.
12445 */
12446 int gl_erase_terminal(GetLine *gl)
12447 {
12448 sigset_t oldset; /* The signals that were blocked on entry */
12449 /* to this function */
12450 int status; /* The return status */
12451 /*
12452 * Block all signals while accessing gl.
12453 */
12454 gl_mask_signals(gl, &oldset);
12455 /*
12456 * Clear the terminal.
12457 */
12458 status = gl_clear_screen(gl, 1, NULL);
12459 /*
12460 * Attempt to flush the clear-screen control codes to the terminal.
12461 * If this doesn't complete the job, the next call to gl_get_line()
12462 * will.
12463 */
12464 (void) gl_flush_output(gl);
12465 /*
12466 * Restore the process signal mask before returning.
12467 */
12468 gl_unmask_signals(gl, &oldset);
12469 return status;
12470 }
12471
12472 /*.......................................................................
12473 * This function must be called by any function that erases the input
12474 * line.
12475 *
12476 * Input:
12477 * gl GetLine * The resource object of gl_get_line().
12478 */
12479 static void gl_line_erased(GetLine *gl)
12480 {
12481 gl->displayed = 0;
12482 gl->term_curpos = 0;
12483 gl->term_len = 0;
12484 }
12485
12486 /*.......................................................................
12487 * Append a specified line to the history list.
12488 *
12489 * Input:
12490 * gl GetLine * The resource object of gl_get_line().
12491 * line const char * The line to be added.
12492 * Output:
12493 * return int 0 - OK.
12494 * 1 - Error.
12495 */
12496 int gl_append_history(GetLine *gl, const char *line)
12497 {
12498 sigset_t oldset; /* The signals that were blocked on entry */
12499 /* to this function */
12500 int status; /* The return status */
12501 /*
12502 * Check the arguments.
12503 */
12504 if(!gl || !line) {
12505 errno = EINVAL;
12506 return 1;
12507 };
12508 /*
12509 * Block all signals.
12510 */
12511 if(gl_mask_signals(gl, &oldset))
12512 return 1;
12513 /*
12514 * Execute the private body of the function while signals are blocked.
12515 */
12516 status = _gl_append_history(gl, line);
12517 /*
12518 * Restore the process signal mask.
12519 */
12520 gl_unmask_signals(gl, &oldset);
12521 return status;
12522 }
12523
12524 /*.......................................................................
12525 * This is the private body of the public function, gl_append_history().
12526 * It assumes that the caller has checked its arguments and blocked the
12527 * delivery of signals.
12528 */
12529 static int _gl_append_history(GetLine *gl, const char *line)
12530 {
12531 int status =_glh_add_history(gl->glh, line, 0);
12532 if(status)
12533 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
12534 return status;
12535 }
12536
12537 /*.......................................................................
12538 * Enable or disable the automatic addition of newly entered lines to the
12539 * history list.
12540 *
12541 * Input:
12542 * gl GetLine * The resource object of gl_get_line().
12543 * enable int If true, subsequently entered lines will
12544 * automatically be added to the history list
12545 * before they are returned to the caller of
12546 * gl_get_line(). If 0, the choice of how and
12547 * when to archive lines in the history list,
12548 * is left up to the calling application, which
12549 * can do so via calls to gl_append_history().
12550 * Output:
12551 * return int 0 - OK.
12552 * 1 - Error.
12553 */
12554 int gl_automatic_history(GetLine *gl, int enable)
12555 {
12556 sigset_t oldset; /* The signals that were blocked on entry */
12557 /* to this function */
12558 /*
12559 * Check the arguments.
12560 */
12561 if(!gl) {
12562 errno = EINVAL;
12563 return 1;
12564 };
12565 /*
12566 * Block all signals.
12567 */
12568 if(gl_mask_signals(gl, &oldset))
12569 return 1;
12570 /*
12571 * Execute the private body of the function while signals are blocked.
12572 */
12573 gl->automatic_history = enable;
12574 /*
12575 * Restore the process signal mask.
12576 */
12577 gl_unmask_signals(gl, &oldset);
12578 return 0;
12579 }
12580
12581 /*.......................................................................
12582 * This is a public function that reads a single uninterpretted
12583 * character from the user, without displaying anything.
12584 *
12585 * Input:
12586 * gl GetLine * A resource object previously returned by
12587 * new_GetLine().
12588 * Output:
12589 * return int The character that was read, or EOF if the read
12590 * had to be aborted (in which case you can call
12591 * gl_return_status() to find out why).
12592 */
12593 int gl_read_char(GetLine *gl)
12594 {
12595 int retval; /* The return value of _gl_read_char() */
12596 /*
12597 * This function can be called from application callback functions,
12598 * so check whether signals have already been masked, so that we don't
12599 * do it again, and overwrite gl->old_signal_set.
12600 */
12601 int was_masked = gl->signals_masked;
12602 /*
12603 * Check the arguments.
12604 */
12605 if(!gl) {
12606 errno = EINVAL;
12607 return EOF;
12608 };
12609 /*
12610 * Temporarily block all of the signals that we have been asked to trap.
12611 */
12612 if(!was_masked && gl_mask_signals(gl, &gl->old_signal_set))
12613 return EOF;
12614 /*
12615 * Perform the character reading task.
12616 */
12617 retval = _gl_read_char(gl);
12618 /*
12619 * Restore the process signal mask to how it was when this function was
12620 * first called.
12621 */
12622 if(!was_masked)
12623 gl_unmask_signals(gl, &gl->old_signal_set);
12624 return retval;
12625 }
12626
12627 /*.......................................................................
12628 * This is the main body of the public function gl_read_char().
12629 */
12630 static int _gl_read_char(GetLine *gl)
12631 {
12632 int retval = EOF; /* The return value */
12633 int waserr = 0; /* True if an error occurs */
12634 char c; /* The character read */
12635 /*
12636 * This function can be called from application callback functions,
12637 * so check whether signals have already been overriden, so that we don't
12638 * overwrite the preserved signal handlers with gl_get_line()s. Also
12639 * record whether we are currently in raw I/O mode or not, so that this
12640 * can be left in the same state on leaving this function.
12641 */
12642 int was_overriden = gl->signals_overriden;
12643 int was_raw = gl->raw_mode;
12644 /*
12645 * Also keep a record of the direction of any I/O that gl_get_line()
12646 * is awaiting, so that we can restore this status on return.
12647 */
12648 GlPendingIO old_pending_io = gl->pending_io;
12649 /*
12650 * Assume that this call will successfully complete the input operation
12651 * until proven otherwise.
12652 */
12653 gl_clear_status(gl);
12654 /*
12655 * If this is the first call to this function or gl_get_line(),
12656 * since new_GetLine(), complete any postponed configuration.
12657 */
12658 if(!gl->configured) {
12659 (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
12660 gl->configured = 1;
12661 };
12662 /*
12663 * Before installing our signal handler functions, record the fact
12664 * that there are no pending signals.
12665 */
12666 gl_pending_signal = -1;
12667 /*
12668 * Temporarily override the signal handlers of the calling program,
12669 * so that we can intercept signals that would leave the terminal
12670 * in a bad state.
12671 */
12672 if(!was_overriden)
12673 waserr = gl_override_signal_handlers(gl);
12674 /*
12675 * After recording the current terminal settings, switch the terminal
12676 * into raw input mode, without redisplaying any partially entered input
12677 * line.
12678 */
12679 if(!was_raw)
12680 waserr = waserr || _gl_raw_io(gl, 0);
12681 /*
12682 * Attempt to read the line. This will require more than one attempt if
12683 * either a current temporary input file is opened by gl_get_input_line()
12684 * or the end of a temporary input file is reached by gl_read_stream_line().
12685 */
12686 while(!waserr) {
12687 /*
12688 * Read a line from a non-interactive stream?
12689 */
12690 if(gl->file_fp || !gl->is_term) {
12691 retval = gl_read_stream_char(gl);
12692 if(retval != EOF) { /* Success? */
12693 break;
12694 } else if(gl->file_fp) { /* End of temporary input file? */
12695 gl_revert_input(gl);
12696 gl_record_status(gl, GLR_NEWLINE, 0);
12697 } else { /* An error? */
12698 waserr = 1;
12699 break;
12700 };
12701 };
12702 /*
12703 * Read from the terminal? Note that the above if() block may have
12704 * changed gl->file_fp, so it is necessary to retest it here, rather
12705 * than using an else statement.
12706 */
12707 if(!gl->file_fp && gl->is_term) {
12708 /*
12709 * Flush any pending output to the terminal before waiting
12710 * for the user to type a character.
12711 */
12712 if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl)) {
12713 retval = EOF;
12714 /*
12715 * Read one character. Don't append it to the key buffer, since
12716 * this would subseuqnely appear as bogus input to the line editor.
12717 */
12718 } else if(gl_read_terminal(gl, 0, &c) == 0) {
12719 /*
12720 * Record the character for return.
12721 */
12722 retval = c;
12723 /*
12724 * In this mode, count each character as being a new key-sequence.
12725 */
12726 gl->keyseq_count++;
12727 /*
12728 * Delete the character that was read, from the key-press buffer.
12729 */
12730 gl_discard_chars(gl, 1);
12731 };
12732 if(retval==EOF)
12733 waserr = 1;
12734 else
12735 break;
12736 };
12737 };
12738 /*
12739 * If an error occurred, but gl->rtn_status is still set to
12740 * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
12741 * leave it at whatever specific value was assigned by the function
12742 * that aborted input. This means that only functions that trap
12743 * non-generic errors have to remember to update gl->rtn_status
12744 * themselves.
12745 */
12746 if(waserr && gl->rtn_status == GLR_NEWLINE)
12747 gl_record_status(gl, GLR_ERROR, errno);
12748 /*
12749 * Restore terminal settings, if they were changed by this function.
12750 */
12751 if(!was_raw && gl->io_mode != GL_SERVER_MODE)
12752 _gl_normal_io(gl);
12753 /*
12754 * Restore the signal handlers, if they were overriden by this function.
12755 */
12756 if(!was_overriden)
12757 gl_restore_signal_handlers(gl);
12758 /*
12759 * If this function gets aborted early, the errno value associated
12760 * with the event that caused this to happen is recorded in
12761 * gl->rtn_errno. Since errno may have been overwritten by cleanup
12762 * functions after this, restore its value to the value that it had
12763 * when the error condition occured, so that the caller can examine it
12764 * to find out what happened.
12765 */
12766 errno = gl->rtn_errno;
12767 /*
12768 * Error conditions are signalled to the caller, by setting the returned
12769 * character to EOF.
12770 */
12771 if(gl->rtn_status != GLR_NEWLINE)
12772 retval = EOF;
12773 /*
12774 * Restore the indication of what direction of I/O gl_get_line()
12775 * was awaiting before this call.
12776 */
12777 gl->pending_io = old_pending_io;
12778 /*
12779 * Return the acquired character.
12780 */
12781 return retval;
12782 }
12783
12784 /*.......................................................................
12785 * Reset the GetLine completion status. This function should be called
12786 * at the start of gl_get_line(), gl_read_char() and gl_query_char()
12787 * to discard the completion status and non-zero errno value of any
12788 * preceding calls to these functions.
12789 *
12790 * Input:
12791 * gl GetLine * The resource object of this module.
12792 */
12793 static void gl_clear_status(GetLine *gl)
12794 {
12795 gl_record_status(gl, GLR_NEWLINE, 0);
12796 }
12797
12798 /*.......................................................................
12799 * When an error or other event causes gl_get_line() to return, this
12800 * function should be called to record information about what
12801 * happened, including the value of errno and the value that
12802 * gl_return_status() should return.
12803 *
12804 * Input:
12805 * gl GetLine * The resource object of this module.
12806 * rtn_status GlReturnStatus The completion status. To clear a
12807 * previous abnormal completion status,
12808 * specify GLR_NEWLINE (this is what
12809 * gl_clear_status() does).
12810 * rtn_errno int The associated value of errno.
12811 */
12812 static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
12813 int rtn_errno)
12814 {
12815 /*
12816 * If rtn_status==GLR_NEWLINE, then this resets the completion status, so we
12817 * should always heed this. Otherwise, only record the first abnormal
12818 * condition that occurs after such a reset.
12819 */
12820 if(rtn_status == GLR_NEWLINE || gl->rtn_status == GLR_NEWLINE) {
12821 gl->rtn_status = rtn_status;
12822 gl->rtn_errno = rtn_errno;
12823 };
12824 }
12825
12826