1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
3 *
4 * All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, and/or sell copies of the Software, and to permit persons
11 * to whom the Software is furnished to do so, provided that the above
12 * copyright notice(s) and this permission notice appear in all copies of
13 * the Software and that both the above copyright notice(s) and this
14 * permission notice appear in supporting documentation.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
21 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
22 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
23 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 *
26 * Except as contained in this notice, the name of a copyright holder
27 * shall not be used in advertising or otherwise to promote the sale, use
28 * or other dealings in this Software without prior written authorization
29 * of the copyright holder.
30 */
31
32 /*
33 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
35 * Copyright (c) 2016 by Delphix. All rights reserved.
36 */
37
38 /*
39 * Standard headers.
40 */
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <signal.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <ctype.h>
47 #include <setjmp.h>
48 #include <stdarg.h>
49
50 /*
51 * UNIX headers.
52 */
53 #include <sys/ioctl.h>
54 #ifdef HAVE_SELECT
55 #ifdef HAVE_SYS_SELECT_H
56 #include <sys/select.h>
57 #endif
58 #include <sys/time.h>
59 #include <sys/types.h>
60 #endif
61
62 /*
63 * Handle the different sources of terminal control string and size
64 * information. Note that if no terminal information database is available,
65 * ANSI VT100 control sequences are used.
66 */
67 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
68 /*
69 * Include curses.h or ncurses/curses.h depending on which is available.
70 */
71 #ifdef HAVE_CURSES_H
72 #include <curses.h>
73 #elif defined(HAVE_NCURSES_CURSES_H)
74 #include <ncurses/curses.h>
75 #endif
76 /*
77 * Include term.h where available.
78 */
79 #if defined(HAVE_TERM_H)
80 #include <term.h>
81 #elif defined(HAVE_NCURSES_TERM_H)
82 #include <ncurses/term.h>
83 #endif
84 /*
85 * When using termcap, include termcap.h on systems that have it.
86 * Otherwise assume that all prototypes are provided by curses.h.
87 */
88 #if defined(USE_TERMCAP) && defined(HAVE_TERMCAP_H)
89 #include <termcap.h>
90 #endif
91
92 /*
93 * Under Solaris default Curses the output function that tputs takes is
94 * declared to have a char argument. On all other systems and on Solaris
95 * X/Open Curses (Issue 4, Version 2) it expects an int argument (using
96 * c89 or options -I /usr/xpg4/include -L /usr/xpg4/lib -R /usr/xpg4/lib
97 * selects XPG4v2 Curses on Solaris 2.6 and later).
98 *
99 * Similarly, under Mac OS X, the return value of the tputs output
100 * function is declared as void, whereas it is declared as int on
101 * other systems.
102 */
103 #if defined __sun && defined __SVR4 && !defined _XOPEN_CURSES
104 typedef int TputsRetType;
105 typedef char TputsArgType; /* int tputs(char c, FILE *fp) */
106 #define TPUTS_RETURNS_VALUE 1
107 #elif defined(__APPLE__) && defined(__MACH__)
108 typedef void TputsRetType;
109 typedef int TputsArgType; /* void tputs(int c, FILE *fp) */
110 #define TPUTS_RETURNS_VALUE 0
111 #else
112 typedef int TputsRetType;
113 typedef int TputsArgType; /* int tputs(int c, FILE *fp) */
114 #define TPUTS_RETURNS_VALUE 1
115 #endif
116
117 /*
118 * Use the above specifications to prototype our tputs callback function.
119 */
120 static TputsRetType gl_tputs_putchar(TputsArgType c);
121
122 #endif /* defined(USE_TERMINFO) || defined(USE_TERMCAP) */
123
124 /*
125 * If the library is being compiled without filesystem access facilities,
126 * ensure that none of the action functions that normally do access the
127 * filesystem are bound by default, and that it they do get bound, that
128 * they don't do anything.
129 */
130 #if WITHOUT_FILE_SYSTEM
131 #define HIDE_FILE_SYSTEM
132 #endif
133
134 /*
135 * POSIX headers.
136 */
137 #include <unistd.h>
138 #include <fcntl.h>
139 #include <termios.h>
140
141 /*
142 * Provide typedefs for standard POSIX structures.
143 */
144 typedef struct sigaction SigAction;
145 typedef struct termios Termios;
146
147 /*
148 * Which flag is used to select non-blocking I/O with fcntl()?
149 */
150 #undef NON_BLOCKING_FLAG
151 #if defined(O_NONBLOCK)
152 #define NON_BLOCKING_FLAG (O_NONBLOCK)
153 #elif defined(O_NDELAY)
154 #define NON_BLOCKING_FLAG (O_NDELAY)
155 #endif
156
157 /*
158 * What value should we give errno if I/O blocks when it shouldn't.
159 */
160 #undef BLOCKED_ERRNO
161 #if defined(EAGAIN)
162 #define BLOCKED_ERRNO (EAGAIN)
163 #elif defined(EWOULDBLOCK)
164 #define BLOCKED_ERRNO (EWOULDBLOCK)
165 #elif defined(EIO)
166 #define BLOCKED_ERRNO (EIO)
167 #else
168 #define BLOCKED_ERRNO 0
169 #endif
170
171 /*
172 * Local headers.
173 */
174 #ifndef WITHOUT_FILE_SYSTEM
175 #include "pathutil.h"
176 #endif
177 #include "libtecla.h"
178 #include "keytab.h"
179 #include "getline.h"
180 #include "ioutil.h"
181 #include "history.h"
182 #include "freelist.h"
183 #include "stringrp.h"
184 #include "chrqueue.h"
185 #include "cplmatch.h"
186 #ifndef WITHOUT_FILE_SYSTEM
187 #include "expand.h"
188 #endif
189 #include "errmsg.h"
190
191 /*
192 * Enumerate the available editing styles.
193 */
194 typedef enum {
195 GL_EMACS_MODE, /* Emacs style editing */
196 GL_VI_MODE, /* Vi style editing */
197 GL_NO_EDITOR /* Fall back to the basic OS-provided editing */
198 } GlEditor;
199
200 /*
201 * Set the largest key-sequence that can be handled.
202 */
203 #define GL_KEY_MAX 64
204
205 /*
206 * In vi mode, the following datatype is used to implement the
207 * undo command. It records a copy of the input line from before
208 * the command-mode action which edited the input line.
209 */
210 typedef struct {
211 char *line; /* A historical copy of the input line */
212 int buff_curpos; /* The historical location of the cursor in */
213 /* line[] when the line was modified. */
214 int ntotal; /* The number of characters in line[] */
215 int saved; /* True once a line has been saved after the */
216 /* last call to gl_interpret_char(). */
217 } ViUndo;
218
219 /*
220 * In vi mode, the following datatype is used to record information
221 * needed by the vi-repeat-change command.
222 */
223 typedef struct {
224 KtAction action; /* The last action function that made a */
225 /* change to the line. */
226 int count; /* The repeat count that was passed to the */
227 /* above command. */
228 int input_curpos; /* Whenever vi command mode is entered, the */
229 /* the position at which it was first left */
230 /* is recorded here. */
231 int command_curpos; /* Whenever vi command mode is entered, the */
232 /* the location of the cursor is recorded */
233 /* here. */
234 char input_char; /* Commands that call gl_read_terminal() */
235 /* record the character here, so that it can */
236 /* used on repeating the function. */
237 int saved; /* True if a function has been saved since the */
238 /* last call to gl_interpret_char(). */
239 int active; /* True while a function is being repeated. */
240 } ViRepeat;
241
242 /*
243 * The following datatype is used to encapsulate information specific
244 * to vi mode.
245 */
246 typedef struct {
247 ViUndo undo; /* Information needed to implement the vi */
248 /* undo command. */
249 ViRepeat repeat; /* Information needed to implement the vi */
250 /* repeat command. */
251 int command; /* True in vi command-mode */
252 int find_forward; /* True if the last character search was in the */
253 /* forward direction. */
254 int find_onto; /* True if the last character search left the */
255 /* on top of the located character, as opposed */
256 /* to just before or after it. */
257 char find_char; /* The last character sought, or '\0' if no */
258 /* searches have been performed yet. */
259 } ViMode;
260
261 #ifdef HAVE_SELECT
262 /*
263 * Define a type for recording a file-descriptor callback and its associated
264 * data.
265 */
266 typedef struct {
267 GlFdEventFn *fn; /* The callback function */
268 void *data; /* Anonymous data to pass to the callback function */
269 } GlFdHandler;
270
271 /*
272 * A list of nodes of the following type is used to record file-activity
273 * event handlers, but only on systems that have the select() system call.
274 */
275 typedef struct GlFdNode GlFdNode;
276 struct GlFdNode {
277 GlFdNode *next; /* The next in the list of nodes */
278 int fd; /* The file descriptor being watched */
279 GlFdHandler rd; /* The callback to call when fd is readable */
280 GlFdHandler wr; /* The callback to call when fd is writable */
281 GlFdHandler ur; /* The callback to call when fd has urgent data */
282 };
283
284 /*
285 * Set the number of the above structures to allocate every time that
286 * the freelist of GlFdNode's becomes exhausted.
287 */
288 #define GLFD_FREELIST_BLOCKING 10
289
290
291 static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
292 GlFdEvent event);
293
294 static int gl_call_timeout_handler(GetLine *gl);
295
296 #endif
297
298 /*
299 * Each signal that gl_get_line() traps is described by a list node
300 * of the following type.
301 */
302 typedef struct GlSignalNode GlSignalNode;
303 struct GlSignalNode {
304 GlSignalNode *next; /* The next signal in the list */
305 int signo; /* The number of the signal */
306 sigset_t proc_mask; /* A process mask which only includes signo */
307 SigAction original; /* The signal disposition of the calling program */
308 /* for this signal. */
309 unsigned flags; /* A bitwise union of GlSignalFlags enumerators */
310 GlAfterSignal after; /* What to do after the signal has been handled */
311 int errno_value; /* What to set errno to */
312 };
313
314 /*
315 * Set the number of the above structures to allocate every time that
316 * the freelist of GlSignalNode's becomes exhausted.
317 */
318 #define GLS_FREELIST_BLOCKING 30
319
320 /*
321 * Completion handlers and their callback data are recorded in
322 * nodes of the following type.
323 */
324 typedef struct GlCplCallback GlCplCallback;
325 struct GlCplCallback {
326 CplMatchFn *fn; /* The completion callback function */
327 void *data; /* Arbitrary callback data */
328 };
329
330 /*
331 * The following function is used as the default completion handler when
332 * the filesystem is to be hidden. It simply reports no completions.
333 */
334 #ifdef HIDE_FILE_SYSTEM
335 static CPL_MATCH_FN(gl_no_completions);
336 #endif
337
338 /*
339 * Specify how many GlCplCallback nodes are added to the GlCplCallback freelist
340 * whenever it becomes exhausted.
341 */
342 #define GL_CPL_FREELIST_BLOCKING 10
343
344 /*
345 * External action functions and their callback data are recorded in
346 * nodes of the following type.
347 */
348 typedef struct GlExternalAction GlExternalAction;
349 struct GlExternalAction {
350 GlActionFn *fn; /* The function which implements the action */
351 void *data; /* Arbitrary callback data */
352 };
353
354 /*
355 * Specify how many GlExternalAction nodes are added to the
356 * GlExternalAction freelist whenever it becomes exhausted.
357 */
358 #define GL_EXT_ACT_FREELIST_BLOCKING 10
359
360 /*
361 * Define the contents of the GetLine object.
362 * Note that the typedef for this object can be found in libtecla.h.
363 */
364 struct GetLine {
365 ErrMsg *err; /* The error-reporting buffer */
366 GlHistory *glh; /* The line-history buffer */
367 WordCompletion *cpl; /* String completion resource object */
368 GlCplCallback cplfn; /* The completion callback */
369 #ifndef WITHOUT_FILE_SYSTEM
370 ExpandFile *ef; /* ~user/, $envvar and wildcard expansion */
371 /* resource object. */
372 #endif
373 StringGroup *capmem; /* Memory for recording terminal capability */
374 /* strings. */
375 GlCharQueue *cq; /* The terminal output character queue */
376 int input_fd; /* The file descriptor to read on */
377 int output_fd; /* The file descriptor to write to */
378 FILE *input_fp; /* A stream wrapper around input_fd */
379 FILE *output_fp; /* A stream wrapper around output_fd */
380 FILE *file_fp; /* When input is being temporarily taken from */
381 /* a file, this is its file-pointer. Otherwise */
382 /* it is NULL. */
383 char *term; /* The terminal type specified on the last call */
384 /* to gl_change_terminal(). */
385 int is_term; /* True if stdin is a terminal */
386 GlWriteFn *flush_fn; /* The function to call to write to the terminal */
387 GlIOMode io_mode; /* The I/O mode established by gl_io_mode() */
388 int raw_mode; /* True while the terminal is in raw mode */
389 GlPendingIO pending_io; /* The type of I/O that is currently pending */
390 GlReturnStatus rtn_status; /* The reason why gl_get_line() returned */
391 int rtn_errno; /* THe value of errno associated with rtn_status */
392 size_t linelen; /* The max number of characters per line */
393 char *line; /* A line-input buffer of allocated size */
394 /* linelen+2. The extra 2 characters are */
395 /* reserved for "\n\0". */
396 char *cutbuf; /* A cut-buffer of the same size as line[] */
397 char *prompt; /* The current prompt string */
398 int prompt_len; /* The length of the prompt string */
399 int prompt_changed; /* True after a callback changes the prompt */
400 int prompt_style; /* How the prompt string is displayed */
401 FreeList *cpl_mem; /* Memory for GlCplCallback objects */
402 FreeList *ext_act_mem; /* Memory for GlExternalAction objects */
403 FreeList *sig_mem; /* Memory for nodes of the signal list */
404 GlSignalNode *sigs; /* The head of the list of signals */
405 int signals_masked; /* True between calls to gl_mask_signals() and */
406 /* gl_unmask_signals() */
407 int signals_overriden; /* True between calls to gl_override_signals() */
408 /* and gl_restore_signals() */
409 sigset_t all_signal_set; /* The set of all signals that we are trapping */
410 sigset_t old_signal_set; /* The set of blocked signals on entry to */
411 /* gl_get_line(). */
412 sigset_t use_signal_set; /* The subset of all_signal_set to unblock */
413 /* while waiting for key-strokes */
414 Termios oldattr; /* Saved terminal attributes. */
415 KeyTab *bindings; /* A table of key-bindings */
416 int ntotal; /* The number of characters in gl->line[] */
417 int buff_curpos; /* The cursor position within gl->line[] */
418 int term_curpos; /* The cursor position on the terminal */
419 int term_len; /* The number of terminal characters used to */
420 /* display the current input line. */
421 int buff_mark; /* A marker location in the buffer */
422 int insert_curpos; /* The cursor position at start of insert */
423 int insert; /* True in insert mode */
424 int number; /* If >= 0, a numeric argument is being read */
425 int endline; /* True to tell gl_get_input_line() to return */
426 /* the current contents of gl->line[] */
427 int displayed; /* True if an input line is currently displayed */
428 int redisplay; /* If true, the input line will be redrawn */
429 /* either after the current action function */
430 /* returns, or when gl_get_input_line() */
431 /* is next called. */
432 int postpone; /* _gl_normal_io() sets this flag, to */
433 /* postpone any redisplays until */
434 /* is next called, to resume line editing. */
435 char keybuf[GL_KEY_MAX+1]; /* A buffer of currently unprocessed key presses */
436 int nbuf; /* The number of characters in keybuf[] */
437 int nread; /* The number of characters read from keybuf[] */
438 KtAction current_action; /* The action function that is being invoked */
439 int current_count; /* The repeat count passed to */
440 /* current_acction.fn() */
441 GlhLineID preload_id; /* When not zero, this should be the ID of a */
442 /* line in the history buffer for potential */
443 /* recall. */
444 int preload_history; /* If true, preload the above history line when */
445 /* gl_get_input_line() is next called. */
446 long keyseq_count; /* The number of key sequences entered by the */
447 /* the user since new_GetLine() was called. */
448 long last_search; /* The value of keyseq_count during the last */
449 /* history search operation. */
450 GlEditor editor; /* The style of editing, (eg. vi or emacs) */
451 int silence_bell; /* True if gl_ring_bell() should do nothing. */
452 int automatic_history; /* True to automatically archive entered lines */
453 /* in the history list. */
454 ViMode vi; /* Parameters used when editing in vi mode */
455 const char *left; /* The string that moves the cursor 1 character */
456 /* left. */
457 const char *right; /* The string that moves the cursor 1 character */
458 /* right. */
459 const char *up; /* The string that moves the cursor 1 character */
460 /* up. */
461 const char *down; /* The string that moves the cursor 1 character */
462 /* down. */
463 const char *home; /* The string that moves the cursor home */
464 const char *bol; /* Move cursor to beginning of line */
465 const char *clear_eol; /* The string that clears from the cursor to */
466 /* the end of the line. */
467 const char *clear_eod; /* The string that clears from the cursor to */
468 /* the end of the display. */
469 const char *u_arrow; /* The string returned by the up-arrow key */
470 const char *d_arrow; /* The string returned by the down-arrow key */
471 const char *l_arrow; /* The string returned by the left-arrow key */
472 const char *r_arrow; /* The string returned by the right-arrow key */
473 const char *sound_bell; /* The string needed to ring the terminal bell */
474 const char *bold; /* Switch to the bold font */
475 const char *underline; /* Underline subsequent characters */
476 const char *standout; /* Turn on standout mode */
477 const char *dim; /* Switch to a dim font */
478 const char *reverse; /* Turn on reverse video */
479 const char *blink; /* Switch to a blinking font */
480 const char *text_attr_off; /* Turn off all text attributes */
481 int nline; /* The height of the terminal in lines */
482 int ncolumn; /* The width of the terminal in columns */
483 #ifdef USE_TERMCAP
484 char *tgetent_buf; /* The buffer that is used by tgetent() to */
485 /* store a terminal description. */
486 char *tgetstr_buf; /* The buffer that is used by tgetstr() to */
487 /* store terminal capabilities. */
488 #endif
489 #ifdef USE_TERMINFO
490 const char *left_n; /* The parameter string that moves the cursor */
491 /* n characters left. */
492 const char *right_n; /* The parameter string that moves the cursor */
493 /* n characters right. */
494 #endif
495 char *app_file; /* The pathname of the application-specific */
496 /* .teclarc configuration file, or NULL. */
497 char *user_file; /* The pathname of the user-specific */
498 /* .teclarc configuration file, or NULL. */
499 int configured; /* True as soon as any teclarc configuration */
500 /* file has been read. */
501 int echo; /* True to display the line as it is being */
502 /* entered. If 0, only the prompt will be */
503 /* displayed, and the line will not be */
504 /* archived in the history list. */
505 int last_signal; /* The last signal that was caught by */
506 /* the last call to gl_get_line(), or -1 */
507 /* if no signal has been caught yet. */
508 #ifdef HAVE_SELECT
509 FreeList *fd_node_mem; /* A freelist of GlFdNode structures */
510 GlFdNode *fd_nodes; /* The list of fd event descriptions */
511 fd_set rfds; /* The set of fds to watch for readability */
512 fd_set wfds; /* The set of fds to watch for writability */
513 fd_set ufds; /* The set of fds to watch for urgent data */
514 int max_fd; /* The maximum file-descriptor being watched */
515 struct { /* Inactivity timeout related data */
516 struct timeval dt; /* The inactivity timeout when timer.fn() */
517 /* isn't 0 */
518 GlTimeoutFn *fn; /* The application callback to call when */
519 /* the inactivity timer expires, or 0 if */
520 /* timeouts are not required. */
521 void *data; /* Application provided data to be passed to */
522 /* timer.fn(). */
523 } timer;
524 #endif
525 };
526
527 /*
528 * Define the max amount of space needed to store a termcap terminal
529 * description. Unfortunately this has to be done by guesswork, so
530 * there is the potential for buffer overflows if we guess too small.
531 * Fortunately termcap has been replaced by terminfo on most
532 * platforms, and with terminfo this isn't an issue. The value that I
533 * am using here is the conventional value, as recommended by certain
534 * web references.
535 */
536 #ifdef USE_TERMCAP
537 #define TERMCAP_BUF_SIZE 2048
538 #endif
539
540 /*
541 * Set the size of the string segments used to store terminal capability
542 * strings.
543 */
544 #define CAPMEM_SEGMENT_SIZE 512
545
546 /*
547 * If no terminal size information is available, substitute the
548 * following vt100 default sizes.
549 */
550 #define GL_DEF_NLINE 24
551 #define GL_DEF_NCOLUMN 80
552
553 /*
554 * Enumerate the attributes needed to classify different types of
555 * signals. These attributes reflect the standard default
556 * characteristics of these signals (according to Richard Steven's
557 * Advanced Programming in the UNIX Environment). Note that these values
558 * are all powers of 2, so that they can be combined in a bitwise union.
559 */
560 typedef enum {
561 GLSA_TERM=1, /* A signal that terminates processes */
562 GLSA_SUSP=2, /* A signal that suspends processes */
563 GLSA_CONT=4, /* A signal that is sent when suspended processes resume */
564 GLSA_IGN=8, /* A signal that is ignored */
565 GLSA_CORE=16, /* A signal that generates a core dump */
566 GLSA_HARD=32, /* A signal generated by a hardware exception */
567 GLSA_SIZE=64 /* A signal indicating terminal size changes */
568 } GlSigAttr;
569
570 /*
571 * List the signals that we need to catch. In general these are
572 * those that by default terminate or suspend the process, since
573 * in such cases we need to restore terminal settings.
574 */
575 static const struct GlDefSignal {
576 int signo; /* The number of the signal */
577 unsigned flags; /* A bitwise union of GlSignalFlags enumerators */
578 GlAfterSignal after; /* What to do after the signal has been delivered */
579 int attr; /* The default attributes of this signal, expressed */
580 /* as a bitwise union of GlSigAttr enumerators */
581 int errno_value; /* What to set errno to */
582 } gl_signal_list[] = {
583 {SIGABRT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
584 {SIGALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
585 {SIGCONT, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_CONT|GLSA_IGN, 0},
586 #if defined(SIGHUP)
587 #ifdef ENOTTY
588 {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, ENOTTY},
589 #else
590 {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
591 #endif
592 #endif
593 {SIGINT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
594 #if defined(SIGPIPE)
595 #ifdef EPIPE
596 {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EPIPE},
597 #else
598 {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
599 #endif
600 #endif
601 #ifdef SIGPOLL
602 {SIGPOLL, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
603 #endif
604 #ifdef SIGPWR
605 {SIGPWR, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_IGN, 0},
606 #endif
607 #ifdef SIGQUIT
608 {SIGQUIT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
609 #endif
610 {SIGTERM, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR},
611 #ifdef SIGTSTP
612 {SIGTSTP, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
613 #endif
614 #ifdef SIGTTIN
615 {SIGTTIN, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
616 #endif
617 #ifdef SIGTTOU
618 {SIGTTOU, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0},
619 #endif
620 #ifdef SIGUSR1
621 {SIGUSR1, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
622 #endif
623 #ifdef SIGUSR2
624 {SIGUSR2, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
625 #endif
626 #ifdef SIGVTALRM
627 {SIGVTALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0},
628 #endif
629 #ifdef SIGWINCH
630 {SIGWINCH, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_SIZE|GLSA_IGN, 0},
631 #endif
632 #ifdef SIGXCPU
633 {SIGXCPU, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
634 #endif
635 #ifdef SIGXFSZ
636 {SIGXFSZ, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
637 #endif
638 };
639
640 /*
641 * Define file-scope variables for use in signal handlers.
642 */
643 static volatile sig_atomic_t gl_pending_signal = -1;
644 static sigjmp_buf gl_setjmp_buffer;
645
646 static void gl_signal_handler(int signo);
647
648 static int gl_check_caught_signal(GetLine *gl);
649
650 /*
651 * Respond to an externally caught process suspension or
652 * termination signal.
653 */
654 static void gl_suspend_process(int signo, GetLine *gl, int ngl);
655
656 /* Return the default attributes of a given signal */
657
658 static int gl_classify_signal(int signo);
659
660 /*
661 * Unfortunately both terminfo and termcap require one to use the tputs()
662 * function to output terminal control characters, and this function
663 * doesn't allow one to specify a file stream. As a result, the following
664 * file-scope variable is used to pass the current output file stream.
665 * This is bad, but there doesn't seem to be any alternative.
666 */
667 static GetLine *tputs_gl = NULL;
668
669 /*
670 * Define a tab to be a string of 8 spaces.
671 */
672 #define TAB_WIDTH 8
673
674 /*
675 * Lookup the current size of the terminal.
676 */
677 static void gl_query_size(GetLine *gl, int *ncolumn, int *nline);
678
679 /*
680 * Getline calls this to temporarily override certain signal handlers
681 * of the calling program.
682 */
683 static int gl_override_signal_handlers(GetLine *gl);
684
685 /*
686 * Getline calls this to restore the signal handlers of the calling
687 * program.
688 */
689 static int gl_restore_signal_handlers(GetLine *gl);
690
691 /*
692 * Temporarily block the delivery of all signals that gl_get_line()
693 * is currently configured to trap.
694 */
695 static int gl_mask_signals(GetLine *gl, sigset_t *oldset);
696
697 /*
698 * Restore the process signal mask that was overriden by a previous
699 * call to gl_mask_signals().
700 */
701 static int gl_unmask_signals(GetLine *gl, sigset_t *oldset);
702
703 /*
704 * Unblock the signals that gl_get_line() has been configured to catch.
705 */
706 static int gl_catch_signals(GetLine *gl);
707
708 /*
709 * Return the set of all trappable signals.
710 */
711 static void gl_list_trappable_signals(sigset_t *signals);
712
713 /*
714 * Put the terminal into raw input mode, after saving the original
715 * terminal attributes in gl->oldattr.
716 */
717 static int gl_raw_terminal_mode(GetLine *gl);
718
719 /*
720 * Restore the terminal attributes from gl->oldattr.
721 */
722 static int gl_restore_terminal_attributes(GetLine *gl);
723
724 /*
725 * Switch to non-blocking I/O if possible.
726 */
727 static int gl_nonblocking_io(GetLine *gl, int fd);
728
729 /*
730 * Switch to blocking I/O if possible.
731 */
732 static int gl_blocking_io(GetLine *gl, int fd);
733
734 /*
735 * Read a line from the user in raw mode.
736 */
737 static int gl_get_input_line(GetLine *gl, const char *prompt,
738 const char *start_line, int start_pos);
739
740 /*
741 * Query the user for a single character.
742 */
743 static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar);
744
745 /*
746 * Read input from a non-interactive input stream.
747 */
748 static int gl_read_stream_line(GetLine *gl);
749
750 /*
751 * Read a single character from a non-interactive input stream.
752 */
753 static int gl_read_stream_char(GetLine *gl);
754
755 /*
756 * Prepare to edit a new line.
757 */
758 static int gl_present_line(GetLine *gl, const char *prompt,
759 const char *start_line, int start_pos);
760
761 /*
762 * Reset all line input parameters for a new input line.
763 */
764 static void gl_reset_input_line(GetLine *gl);
765
766 /*
767 * Handle the receipt of the potential start of a new key-sequence from
768 * the user.
769 */
770 static int gl_interpret_char(GetLine *gl, char c);
771
772 /*
773 * Bind a single control or meta character to an action.
774 */
775 static int gl_bind_control_char(GetLine *gl, KtBinder binder,
776 char c, const char *action);
777
778 /*
779 * Set up terminal-specific key bindings.
780 */
781 static int gl_bind_terminal_keys(GetLine *gl);
782
783 /*
784 * Lookup terminal control string and size information.
785 */
786 static int gl_control_strings(GetLine *gl, const char *term);
787
788 /*
789 * Wrappers around the terminfo and termcap functions that lookup
790 * strings in the terminal information databases.
791 */
792 #ifdef USE_TERMINFO
793 static const char *gl_tigetstr(GetLine *gl, const char *name);
794 #elif defined(USE_TERMCAP)
795 static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr);
796 #endif
797
798 /*
799 * Output a binary string directly to the terminal.
800 */
801 static int gl_print_raw_string(GetLine *gl, int buffered,
802 const char *string, int n);
803
804 /*
805 * Print an informational message, starting and finishing on new lines.
806 * After the list of strings to be printed, the last argument MUST be
807 * GL_END_INFO.
808 */
809 static int gl_print_info(GetLine *gl, ...);
810 #define GL_END_INFO ((const char *)0)
811
812 /*
813 * Start a newline and place the cursor at its start.
814 */
815 static int gl_start_newline(GetLine *gl, int buffered);
816
817 /*
818 * Output a terminal control sequence.
819 */
820 static int gl_print_control_sequence(GetLine *gl, int nline,
821 const char *string);
822
823 /*
824 * Output a character or string to the terminal after converting tabs
825 * to spaces and control characters to a caret followed by the modified
826 * character.
827 */
828 static int gl_print_char(GetLine *gl, char c, char pad);
829 static int gl_print_string(GetLine *gl, const char *string, char pad);
830
831 /*
832 * Delete nc characters starting from the one under the cursor.
833 * Optionally copy the deleted characters to the cut buffer.
834 */
835 static int gl_delete_chars(GetLine *gl, int nc, int cut);
836
837 /*
838 * Add a character to the line buffer at the current cursor position,
839 * inserting or overwriting according the current mode.
840 */
841 static int gl_add_char_to_line(GetLine *gl, char c);
842
843 /*
844 * Insert/append a string to the line buffer and terminal at the current
845 * cursor position.
846 */
847 static int gl_add_string_to_line(GetLine *gl, const char *s);
848
849 /*
850 * Record a new character in the input-line buffer.
851 */
852 static int gl_buffer_char(GetLine *gl, char c, int bufpos);
853
854 /*
855 * Record a string in the input-line buffer.
856 */
857 static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos);
858
859 /*
860 * Make way to insert a string in the input-line buffer.
861 */
862 static int gl_make_gap_in_buffer(GetLine *gl, int start, int n);
863
864 /*
865 * Remove characters from the input-line buffer, and move any characters
866 * that followed them to the start of the vacated space.
867 */
868 static void gl_remove_from_buffer(GetLine *gl, int start, int n);
869
870 /*
871 * Terminate the input-line buffer after a specified number of characters.
872 */
873 static int gl_truncate_buffer(GetLine *gl, int n);
874
875 /*
876 * Delete the displayed part of the input line that follows the current
877 * terminal cursor position.
878 */
879 static int gl_truncate_display(GetLine *gl);
880
881 /*
882 * Accomodate changes to the contents of the input line buffer
883 * that weren't made by the above gl_*buffer functions.
884 */
885 static void gl_update_buffer(GetLine *gl);
886
887 /*
888 * Read a single character from the terminal.
889 */
890 static int gl_read_terminal(GetLine *gl, int keep, char *c);
891
892 /*
893 * Discard processed characters from the key-press lookahead buffer.
894 */
895 static void gl_discard_chars(GetLine *gl, int nused);
896
897 /*
898 * Move the terminal cursor n positions to the left or right.
899 */
900 static int gl_terminal_move_cursor(GetLine *gl, int n);
901
902 /*
903 * Move the terminal cursor to a given position.
904 */
905 static int gl_set_term_curpos(GetLine *gl, int term_curpos);
906
907 /*
908 * Set the position of the cursor both in the line input buffer and on the
909 * terminal.
910 */
911 static int gl_place_cursor(GetLine *gl, int buff_curpos);
912
913 /*
914 * How many characters are needed to write a number as an octal string?
915 */
916 static int gl_octal_width(unsigned num);
917
918 /*
919 * Return the number of spaces needed to display a tab character at
920 * a given location of the terminal.
921 */
922 static int gl_displayed_tab_width(GetLine *gl, int term_curpos);
923
924 /*
925 * Return the number of terminal characters needed to display a
926 * given raw character.
927 */
928 static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos);
929
930 /*
931 * Return the number of terminal characters needed to display a
932 * given substring.
933 */
934 static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
935 int term_curpos);
936
937 /*
938 * Return non-zero if 'c' is to be considered part of a word.
939 */
940 static int gl_is_word_char(int c);
941
942 /*
943 * Read a tecla configuration file.
944 */
945 static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who);
946
947 /*
948 * Read a tecla configuration string.
949 */
950 static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who);
951
952 /*
953 * Define the callback function used by _gl_parse_config_line() to
954 * read the next character of a configuration stream.
955 */
956 #define GLC_GETC_FN(fn) int (fn)(void *stream)
957 typedef GLC_GETC_FN(GlcGetcFn);
958
959 static GLC_GETC_FN(glc_file_getc); /* Read from a file */
960 static GLC_GETC_FN(glc_buff_getc); /* Read from a string */
961
962 /*
963 * Parse a single configuration command line.
964 */
965 static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
966 const char *origin, KtBinder who, int *lineno);
967 static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
968 const char *errmsg);
969
970 /*
971 * Bind the actual arrow key bindings to match those of the symbolic
972 * arrow-key bindings.
973 */
974 static int _gl_bind_arrow_keys(GetLine *gl);
975
976 /*
977 * Copy the binding of the specified symbolic arrow-key binding to
978 * the terminal specific, and default arrow-key key-sequences.
979 */
980 static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
981 const char *term_seq,
982 const char *def_seq1,
983 const char *def_seq2);
984
985 /*
986 * After the gl_read_from_file() action has been used to tell gl_get_line()
987 * to temporarily read input from a file, gl_revert_input() arranges
988 * for input to be reverted to the input stream last registered with
989 * gl_change_terminal().
990 */
991 static void gl_revert_input(GetLine *gl);
992
993 /*
994 * Flush unwritten characters to the terminal.
995 */
996 static int gl_flush_output(GetLine *gl);
997
998 /*
999 * The callback through which all terminal output is routed.
1000 * This simply appends characters to a queue buffer, which is
1001 * subsequently flushed to the output channel by gl_flush_output().
1002 */
1003 static GL_WRITE_FN(gl_write_fn);
1004
1005 /*
1006 * The callback function which the output character queue object
1007 * calls to transfer characters to the output channel.
1008 */
1009 static GL_WRITE_FN(gl_flush_terminal);
1010
1011 /*
1012 * Enumerate the possible return statuses of gl_read_input().
1013 */
1014 typedef enum {
1015 GL_READ_OK, /* A character was read successfully */
1016 GL_READ_ERROR, /* A read-error occurred */
1017 GL_READ_BLOCKED, /* The read would have blocked the caller */
1018 GL_READ_EOF /* The end of the current input file was reached */
1019 } GlReadStatus;
1020
1021 static GlReadStatus gl_read_input(GetLine *gl, char *c);
1022 /*
1023 * Private functions of gl_read_input().
1024 */
1025 static int gl_event_handler(GetLine *gl, int fd);
1026 static int gl_read_unmasked(GetLine *gl, int fd, char *c);
1027
1028
1029 /*
1030 * A private function of gl_tty_signals().
1031 */
1032 static int gl_set_tty_signal(int signo, void (*handler)(int));
1033
1034 /*
1035 * Change the editor style being emulated.
1036 */
1037 static int gl_change_editor(GetLine *gl, GlEditor editor);
1038
1039 /*
1040 * Searching in a given direction, return the index of a given (or
1041 * read) character in the input line, or the character that precedes
1042 * it in the specified search direction. Return -1 if not found.
1043 */
1044 static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c);
1045
1046 /*
1047 * Return the buffer index of the nth word ending after the cursor.
1048 */
1049 static int gl_nth_word_end_forward(GetLine *gl, int n);
1050
1051 /*
1052 * Return the buffer index of the nth word start after the cursor.
1053 */
1054 static int gl_nth_word_start_forward(GetLine *gl, int n);
1055
1056 /*
1057 * Return the buffer index of the nth word start before the cursor.
1058 */
1059 static int gl_nth_word_start_backward(GetLine *gl, int n);
1060
1061 /*
1062 * When called when vi command mode is enabled, this function saves the
1063 * current line and cursor position for potential restoration later
1064 * by the vi undo command.
1065 */
1066 static void gl_save_for_undo(GetLine *gl);
1067
1068 /*
1069 * If in vi mode, switch to vi command mode.
1070 */
1071 static void gl_vi_command_mode(GetLine *gl);
1072
1073 /*
1074 * In vi mode this is used to delete up to or onto a given or read
1075 * character in the input line. Also switch to insert mode if requested
1076 * after the deletion.
1077 */
1078 static int gl_delete_find(GetLine *gl, int count, char c, int forward,
1079 int onto, int change);
1080
1081 /*
1082 * Copy the characters between the cursor and the count'th instance of
1083 * a specified (or read) character in the input line, into the cut buffer.
1084 */
1085 static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto);
1086
1087 /*
1088 * Return the line index of the parenthesis that either matches the one under
1089 * the cursor, or not over a parenthesis character, the index of the next
1090 * close parenthesis. Return -1 if not found.
1091 */
1092 static int gl_index_of_matching_paren(GetLine *gl);
1093
1094 /*
1095 * Replace a malloc'd string (or NULL), with another malloc'd copy of
1096 * a string (or NULL).
1097 */
1098 static int gl_record_string(char **sptr, const char *string);
1099
1100 /*
1101 * Enumerate text display attributes as powers of two, suitable for
1102 * use in a bit-mask.
1103 */
1104 typedef enum {
1105 GL_TXT_STANDOUT=1, /* Display text highlighted */
1106 GL_TXT_UNDERLINE=2, /* Display text underlined */
1107 GL_TXT_REVERSE=4, /* Display text with reverse video */
1108 GL_TXT_BLINK=8, /* Display blinking text */
1109 GL_TXT_DIM=16, /* Display text in a dim font */
1110 GL_TXT_BOLD=32 /* Display text using a bold font */
1111 } GlTextAttr;
1112
1113 /*
1114 * Display the prompt regardless of the current visibility mode.
1115 */
1116 static int gl_display_prompt(GetLine *gl);
1117
1118 /*
1119 * Return the number of characters used by the prompt on the terminal.
1120 */
1121 static int gl_displayed_prompt_width(GetLine *gl);
1122
1123 /*
1124 * Prepare to return the current input line to the caller of gl_get_line().
1125 */
1126 static int gl_line_ended(GetLine *gl, int newline_char);
1127
1128 /*
1129 * Arrange for the input line to be redisplayed when the current contents
1130 * of the output queue have been flushed.
1131 */
1132 static void gl_queue_redisplay(GetLine *gl);
1133
1134 /*
1135 * Erase the displayed representation of the input line, without
1136 * touching the buffered copy.
1137 */
1138 static int gl_erase_line(GetLine *gl);
1139
1140 /*
1141 * This function is called whenever the input line has been erased.
1142 */
1143 static void gl_line_erased(GetLine *gl);
1144
1145 /*
1146 * Arrange for the current input line to be discarded.
1147 */
1148 void _gl_abandon_line(GetLine *gl);
1149
1150 /*
1151 * The following are private internally callable versions of pertinent
1152 * public functions. Unlike their public wrapper functions, they don't
1153 * block signals while running, and assume that their arguments are valid.
1154 * They are designed to be called from places where signals are already
1155 * blocked, and where simple sanity checks have already been applied to
1156 * their arguments.
1157 */
1158 static char *_gl_get_line(GetLine *gl, const char *prompt,
1159 const char *start_line, int start_pos);
1160 static int _gl_query_char(GetLine *gl, const char *prompt, char defchar);
1161 static int _gl_read_char(GetLine *gl);
1162 static int _gl_update_size(GetLine *gl);
1163 /*
1164 * Redraw the current input line to account for a change in the terminal
1165 * size. Also install the new size in gl.
1166 */
1167 static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline);
1168
1169 static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
1170 const char *term);
1171 static int _gl_configure_getline(GetLine *gl, const char *app_string,
1172 const char *app_file, const char *user_file);
1173 static int _gl_save_history(GetLine *gl, const char *filename,
1174 const char *comment, int max_lines);
1175 static int _gl_load_history(GetLine *gl, const char *filename,
1176 const char *comment);
1177 static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
1178 GlFdEventFn *callback, void *data);
1179 static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
1180 GlTerminalSize *size);
1181 static void _gl_replace_prompt(GetLine *gl, const char *prompt);
1182 static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
1183 GlAfterSignal after, int errno_value);
1184 static int _gl_raw_io(GetLine *gl, int redisplay);
1185 static int _gl_normal_io(GetLine *gl);
1186 static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
1187 int list_only, const char *name,
1188 const char *keyseq);
1189 static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
1190 const char *name, const char *keyseq);
1191 static int _gl_io_mode(GetLine *gl, GlIOMode mode);
1192 static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline);
1193 static int _gl_append_history(GetLine *gl, const char *line);
1194
1195 /*
1196 * Reset the completion status and associated errno value in
1197 * gl->rtn_status and gl->rtn_errno.
1198 */
1199 static void gl_clear_status(GetLine *gl);
1200
1201 /*
1202 * Record a completion status, unless a previous abnormal completion
1203 * status has already been recorded for the current call.
1204 */
1205 static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
1206 int rtn_errno);
1207
1208 /*
1209 * Set the maximum length of a line in a user's tecla configuration
1210 * file (not counting comments).
1211 */
1212 #define GL_CONF_BUFLEN 100
1213
1214 /*
1215 * Set the maximum number of arguments supported by individual commands
1216 * in tecla configuration files.
1217 */
1218 #define GL_CONF_MAXARG 10
1219
1220 /*
1221 * Prototype the available action functions.
1222 */
1223 static KT_KEY_FN(gl_user_interrupt);
1224 static KT_KEY_FN(gl_abort);
1225 static KT_KEY_FN(gl_suspend);
1226 static KT_KEY_FN(gl_stop_output);
1227 static KT_KEY_FN(gl_start_output);
1228 static KT_KEY_FN(gl_literal_next);
1229 static KT_KEY_FN(gl_cursor_left);
1230 static KT_KEY_FN(gl_cursor_right);
1231 static KT_KEY_FN(gl_insert_mode);
1232 static KT_KEY_FN(gl_beginning_of_line);
1233 static KT_KEY_FN(gl_end_of_line);
1234 static KT_KEY_FN(gl_delete_line);
1235 static KT_KEY_FN(gl_kill_line);
1236 static KT_KEY_FN(gl_forward_word);
1237 static KT_KEY_FN(gl_backward_word);
1238 static KT_KEY_FN(gl_forward_delete_char);
1239 static KT_KEY_FN(gl_backward_delete_char);
1240 static KT_KEY_FN(gl_forward_delete_word);
1241 static KT_KEY_FN(gl_backward_delete_word);
1242 static KT_KEY_FN(gl_delete_refind);
1243 static KT_KEY_FN(gl_delete_invert_refind);
1244 static KT_KEY_FN(gl_delete_to_column);
1245 static KT_KEY_FN(gl_delete_to_parenthesis);
1246 static KT_KEY_FN(gl_forward_delete_find);
1247 static KT_KEY_FN(gl_backward_delete_find);
1248 static KT_KEY_FN(gl_forward_delete_to);
1249 static KT_KEY_FN(gl_backward_delete_to);
1250 static KT_KEY_FN(gl_upcase_word);
1251 static KT_KEY_FN(gl_downcase_word);
1252 static KT_KEY_FN(gl_capitalize_word);
1253 static KT_KEY_FN(gl_redisplay);
1254 static KT_KEY_FN(gl_clear_screen);
1255 static KT_KEY_FN(gl_transpose_chars);
1256 static KT_KEY_FN(gl_set_mark);
1257 static KT_KEY_FN(gl_exchange_point_and_mark);
1258 static KT_KEY_FN(gl_kill_region);
1259 static KT_KEY_FN(gl_copy_region_as_kill);
1260 static KT_KEY_FN(gl_yank);
1261 static KT_KEY_FN(gl_up_history);
1262 static KT_KEY_FN(gl_down_history);
1263 static KT_KEY_FN(gl_history_search_backward);
1264 static KT_KEY_FN(gl_history_re_search_backward);
1265 static KT_KEY_FN(gl_history_search_forward);
1266 static KT_KEY_FN(gl_history_re_search_forward);
1267 static KT_KEY_FN(gl_complete_word);
1268 #ifndef HIDE_FILE_SYSTEM
1269 static KT_KEY_FN(gl_expand_filename);
1270 static KT_KEY_FN(gl_read_from_file);
1271 static KT_KEY_FN(gl_read_init_files);
1272 static KT_KEY_FN(gl_list_glob);
1273 #endif
1274 static KT_KEY_FN(gl_del_char_or_list_or_eof);
1275 static KT_KEY_FN(gl_list_or_eof);
1276 static KT_KEY_FN(gl_beginning_of_history);
1277 static KT_KEY_FN(gl_end_of_history);
1278 static KT_KEY_FN(gl_digit_argument);
1279 static KT_KEY_FN(gl_newline);
1280 static KT_KEY_FN(gl_repeat_history);
1281 static KT_KEY_FN(gl_vi_insert);
1282 static KT_KEY_FN(gl_vi_overwrite);
1283 static KT_KEY_FN(gl_change_case);
1284 static KT_KEY_FN(gl_vi_insert_at_bol);
1285 static KT_KEY_FN(gl_vi_append_at_eol);
1286 static KT_KEY_FN(gl_vi_append);
1287 static KT_KEY_FN(gl_backward_kill_line);
1288 static KT_KEY_FN(gl_goto_column);
1289 static KT_KEY_FN(gl_forward_to_word);
1290 static KT_KEY_FN(gl_vi_replace_char);
1291 static KT_KEY_FN(gl_vi_change_rest_of_line);
1292 static KT_KEY_FN(gl_vi_change_line);
1293 static KT_KEY_FN(gl_vi_change_to_bol);
1294 static KT_KEY_FN(gl_vi_change_refind);
1295 static KT_KEY_FN(gl_vi_change_invert_refind);
1296 static KT_KEY_FN(gl_vi_change_to_column);
1297 static KT_KEY_FN(gl_vi_change_to_parenthesis);
1298 static KT_KEY_FN(gl_vi_forward_change_word);
1299 static KT_KEY_FN(gl_vi_backward_change_word);
1300 static KT_KEY_FN(gl_vi_forward_change_find);
1301 static KT_KEY_FN(gl_vi_backward_change_find);
1302 static KT_KEY_FN(gl_vi_forward_change_to);
1303 static KT_KEY_FN(gl_vi_backward_change_to);
1304 static KT_KEY_FN(gl_vi_forward_change_char);
1305 static KT_KEY_FN(gl_vi_backward_change_char);
1306 static KT_KEY_FN(gl_forward_copy_char);
1307 static KT_KEY_FN(gl_backward_copy_char);
1308 static KT_KEY_FN(gl_forward_find_char);
1309 static KT_KEY_FN(gl_backward_find_char);
1310 static KT_KEY_FN(gl_forward_to_char);
1311 static KT_KEY_FN(gl_backward_to_char);
1312 static KT_KEY_FN(gl_repeat_find_char);
1313 static KT_KEY_FN(gl_invert_refind_char);
1314 static KT_KEY_FN(gl_append_yank);
1315 static KT_KEY_FN(gl_backward_copy_word);
1316 static KT_KEY_FN(gl_forward_copy_word);
1317 static KT_KEY_FN(gl_copy_to_bol);
1318 static KT_KEY_FN(gl_copy_refind);
1319 static KT_KEY_FN(gl_copy_invert_refind);
1320 static KT_KEY_FN(gl_copy_to_column);
1321 static KT_KEY_FN(gl_copy_to_parenthesis);
1322 static KT_KEY_FN(gl_copy_rest_of_line);
1323 static KT_KEY_FN(gl_copy_line);
1324 static KT_KEY_FN(gl_backward_copy_find);
1325 static KT_KEY_FN(gl_forward_copy_find);
1326 static KT_KEY_FN(gl_backward_copy_to);
1327 static KT_KEY_FN(gl_forward_copy_to);
1328 static KT_KEY_FN(gl_vi_undo);
1329 static KT_KEY_FN(gl_emacs_editing_mode);
1330 static KT_KEY_FN(gl_vi_editing_mode);
1331 static KT_KEY_FN(gl_ring_bell);
1332 static KT_KEY_FN(gl_vi_repeat_change);
1333 static KT_KEY_FN(gl_find_parenthesis);
1334 static KT_KEY_FN(gl_list_history);
1335 static KT_KEY_FN(gl_list_completions);
1336 static KT_KEY_FN(gl_run_external_action);
1337
1338 /*
1339 * Name the available action functions.
1340 */
1341 static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = {
1342 {"user-interrupt", gl_user_interrupt},
1343 {"abort", gl_abort},
1344 {"suspend", gl_suspend},
1345 {"stop-output", gl_stop_output},
1346 {"start-output", gl_start_output},
1347 {"literal-next", gl_literal_next},
1348 {"cursor-right", gl_cursor_right},
1349 {"cursor-left", gl_cursor_left},
1350 {"insert-mode", gl_insert_mode},
1351 {"beginning-of-line", gl_beginning_of_line},
1352 {"end-of-line", gl_end_of_line},
1353 {"delete-line", gl_delete_line},
1354 {"kill-line", gl_kill_line},
1355 {"forward-word", gl_forward_word},
1356 {"backward-word", gl_backward_word},
1357 {"forward-delete-char", gl_forward_delete_char},
1358 {"backward-delete-char", gl_backward_delete_char},
1359 {"forward-delete-word", gl_forward_delete_word},
1360 {"backward-delete-word", gl_backward_delete_word},
1361 {"delete-refind", gl_delete_refind},
1362 {"delete-invert-refind", gl_delete_invert_refind},
1363 {"delete-to-column", gl_delete_to_column},
1364 {"delete-to-parenthesis", gl_delete_to_parenthesis},
1365 {"forward-delete-find", gl_forward_delete_find},
1366 {"backward-delete-find", gl_backward_delete_find},
1367 {"forward-delete-to", gl_forward_delete_to},
1368 {"backward-delete-to", gl_backward_delete_to},
1369 {"upcase-word", gl_upcase_word},
1370 {"downcase-word", gl_downcase_word},
1371 {"capitalize-word", gl_capitalize_word},
1372 {"redisplay", gl_redisplay},
1373 {"clear-screen", gl_clear_screen},
1374 {"transpose-chars", gl_transpose_chars},
1375 {"set-mark", gl_set_mark},
1376 {"exchange-point-and-mark", gl_exchange_point_and_mark},
1377 {"kill-region", gl_kill_region},
1378 {"copy-region-as-kill", gl_copy_region_as_kill},
1379 {"yank", gl_yank},
1380 {"up-history", gl_up_history},
1381 {"down-history", gl_down_history},
1382 {"history-search-backward", gl_history_search_backward},
1383 {"history-re-search-backward", gl_history_re_search_backward},
1384 {"history-search-forward", gl_history_search_forward},
1385 {"history-re-search-forward", gl_history_re_search_forward},
1386 {"complete-word", gl_complete_word},
1387 #ifndef HIDE_FILE_SYSTEM
1388 {"expand-filename", gl_expand_filename},
1389 {"read-from-file", gl_read_from_file},
1390 {"read-init-files", gl_read_init_files},
1391 {"list-glob", gl_list_glob},
1392 #endif
1393 {"del-char-or-list-or-eof", gl_del_char_or_list_or_eof},
1394 {"beginning-of-history", gl_beginning_of_history},
1395 {"end-of-history", gl_end_of_history},
1396 {"digit-argument", gl_digit_argument},
1397 {"newline", gl_newline},
1398 {"repeat-history", gl_repeat_history},
1399 {"vi-insert", gl_vi_insert},
1400 {"vi-overwrite", gl_vi_overwrite},
1401 {"vi-insert-at-bol", gl_vi_insert_at_bol},
1402 {"vi-append-at-eol", gl_vi_append_at_eol},
1403 {"vi-append", gl_vi_append},
1404 {"change-case", gl_change_case},
1405 {"backward-kill-line", gl_backward_kill_line},
1406 {"goto-column", gl_goto_column},
1407 {"forward-to-word", gl_forward_to_word},
1408 {"vi-replace-char", gl_vi_replace_char},
1409 {"vi-change-rest-of-line", gl_vi_change_rest_of_line},
1410 {"vi-change-line", gl_vi_change_line},
1411 {"vi-change-to-bol", gl_vi_change_to_bol},
1412 {"vi-change-refind", gl_vi_change_refind},
1413 {"vi-change-invert-refind", gl_vi_change_invert_refind},
1414 {"vi-change-to-column", gl_vi_change_to_column},
1415 {"vi-change-to-parenthesis", gl_vi_change_to_parenthesis},
1416 {"forward-copy-char", gl_forward_copy_char},
1417 {"backward-copy-char", gl_backward_copy_char},
1418 {"forward-find-char", gl_forward_find_char},
1419 {"backward-find-char", gl_backward_find_char},
1420 {"forward-to-char", gl_forward_to_char},
1421 {"backward-to-char", gl_backward_to_char},
1422 {"repeat-find-char", gl_repeat_find_char},
1423 {"invert-refind-char", gl_invert_refind_char},
1424 {"append-yank", gl_append_yank},
1425 {"backward-copy-word", gl_backward_copy_word},
1426 {"forward-copy-word", gl_forward_copy_word},
1427 {"copy-to-bol", gl_copy_to_bol},
1428 {"copy-refind", gl_copy_refind},
1429 {"copy-invert-refind", gl_copy_invert_refind},
1430 {"copy-to-column", gl_copy_to_column},
1431 {"copy-to-parenthesis", gl_copy_to_parenthesis},
1432 {"copy-rest-of-line", gl_copy_rest_of_line},
1433 {"copy-line", gl_copy_line},
1434 {"backward-copy-find", gl_backward_copy_find},
1435 {"forward-copy-find", gl_forward_copy_find},
1436 {"backward-copy-to", gl_backward_copy_to},
1437 {"forward-copy-to", gl_forward_copy_to},
1438 {"list-or-eof", gl_list_or_eof},
1439 {"vi-undo", gl_vi_undo},
1440 {"vi-backward-change-word", gl_vi_backward_change_word},
1441 {"vi-forward-change-word", gl_vi_forward_change_word},
1442 {"vi-backward-change-find", gl_vi_backward_change_find},
1443 {"vi-forward-change-find", gl_vi_forward_change_find},
1444 {"vi-backward-change-to", gl_vi_backward_change_to},
1445 {"vi-forward-change-to", gl_vi_forward_change_to},
1446 {"vi-backward-change-char", gl_vi_backward_change_char},
1447 {"vi-forward-change-char", gl_vi_forward_change_char},
1448 {"emacs-mode", gl_emacs_editing_mode},
1449 {"vi-mode", gl_vi_editing_mode},
1450 {"ring-bell", gl_ring_bell},
1451 {"vi-repeat-change", gl_vi_repeat_change},
1452 {"find-parenthesis", gl_find_parenthesis},
1453 {"list-history", gl_list_history},
1454 };
1455
1456 /*
1457 * Define the default key-bindings in emacs mode.
1458 */
1459 static const KtKeyBinding gl_emacs_bindings[] = {
1460 {"right", "cursor-right"},
1461 {"^F", "cursor-right"},
1462 {"left", "cursor-left"},
1463 {"^B", "cursor-left"},
1464 {"M-i", "insert-mode"},
1465 {"M-I", "insert-mode"},
1466 {"^A", "beginning-of-line"},
1467 {"^E", "end-of-line"},
1468 {"^U", "delete-line"},
1469 {"^K", "kill-line"},
1470 {"M-f", "forward-word"},
1471 {"M-F", "forward-word"},
1472 {"M-b", "backward-word"},
1473 {"M-B", "backward-word"},
1474 {"^D", "del-char-or-list-or-eof"},
1475 {"^H", "backward-delete-char"},
1476 {"^?", "backward-delete-char"},
1477 {"M-d", "forward-delete-word"},
1478 {"M-D", "forward-delete-word"},
1479 {"M-^H", "backward-delete-word"},
1480 {"M-^?", "backward-delete-word"},
1481 {"M-u", "upcase-word"},
1482 {"M-U", "upcase-word"},
1483 {"M-l", "downcase-word"},
1484 {"M-L", "downcase-word"},
1485 {"M-c", "capitalize-word"},
1486 {"M-C", "capitalize-word"},
1487 {"^R", "redisplay"},
1488 {"^L", "clear-screen"},
1489 {"^T", "transpose-chars"},
1490 {"^@", "set-mark"},
1491 {"^X^X", "exchange-point-and-mark"},
1492 {"^W", "kill-region"},
1493 {"M-w", "copy-region-as-kill"},
1494 {"M-W", "copy-region-as-kill"},
1495 {"^Y", "yank"},
1496 {"^P", "up-history"},
1497 {"up", "up-history"},
1498 {"^N", "down-history"},
1499 {"down", "down-history"},
1500 {"M-p", "history-search-backward"},
1501 {"M-P", "history-search-backward"},
1502 {"M-n", "history-search-forward"},
1503 {"M-N", "history-search-forward"},
1504 {"\t", "complete-word"},
1505 #ifndef HIDE_FILE_SYSTEM
1506 {"^X*", "expand-filename"},
1507 {"^X^F", "read-from-file"},
1508 {"^X^R", "read-init-files"},
1509 {"^Xg", "list-glob"},
1510 {"^XG", "list-glob"},
1511 #endif
1512 {"^Xh", "list-history"},
1513 {"^XH", "list-history"},
1514 {"M-<", "beginning-of-history"},
1515 {"M->", "end-of-history"},
1516 {"M-0", "digit-argument"},
1517 {"M-1", "digit-argument"},
1518 {"M-2", "digit-argument"},
1519 {"M-3", "digit-argument"},
1520 {"M-4", "digit-argument"},
1521 {"M-5", "digit-argument"},
1522 {"M-6", "digit-argument"},
1523 {"M-7", "digit-argument"},
1524 {"M-8", "digit-argument"},
1525 {"M-9", "digit-argument"},
1526 {"\r", "newline"},
1527 {"\n", "newline"},
1528 {"M-o", "repeat-history"},
1529 {"M-C-v", "vi-mode"},
1530 };
1531
1532 /*
1533 * Define the default key-bindings in vi mode. Note that in vi-mode
1534 * meta-key bindings are command-mode bindings. For example M-i first
1535 * switches to command mode if not already in that mode, then moves
1536 * the cursor one position right, as in vi.
1537 */
1538 static const KtKeyBinding gl_vi_bindings[] = {
1539 {"^D", "list-or-eof"},
1540 #ifndef HIDE_FILE_SYSTEM
1541 {"^G", "list-glob"},
1542 #endif
1543 {"^H", "backward-delete-char"},
1544 {"\t", "complete-word"},
1545 {"\r", "newline"},
1546 {"\n", "newline"},
1547 {"^L", "clear-screen"},
1548 {"^N", "down-history"},
1549 {"^P", "up-history"},
1550 {"^R", "redisplay"},
1551 {"^U", "backward-kill-line"},
1552 {"^W", "backward-delete-word"},
1553 #ifndef HIDE_FILE_SYSTEM
1554 {"^X^F", "read-from-file"},
1555 {"^X^R", "read-init-files"},
1556 {"^X*", "expand-filename"},
1557 #endif
1558 {"^?", "backward-delete-char"},
1559 {"M- ", "cursor-right"},
1560 {"M-$", "end-of-line"},
1561 #ifndef HIDE_FILE_SYSTEM
1562 {"M-*", "expand-filename"},
1563 #endif
1564 {"M-+", "down-history"},
1565 {"M--", "up-history"},
1566 {"M-<", "beginning-of-history"},
1567 {"M->", "end-of-history"},
1568 {"M-^", "beginning-of-line"},
1569 {"M-;", "repeat-find-char"},
1570 {"M-,", "invert-refind-char"},
1571 {"M-|", "goto-column"},
1572 {"M-~", "change-case"},
1573 {"M-.", "vi-repeat-change"},
1574 {"M-%", "find-parenthesis"},
1575 {"M-0", "digit-argument"},
1576 {"M-1", "digit-argument"},
1577 {"M-2", "digit-argument"},
1578 {"M-3", "digit-argument"},
1579 {"M-4", "digit-argument"},
1580 {"M-5", "digit-argument"},
1581 {"M-6", "digit-argument"},
1582 {"M-7", "digit-argument"},
1583 {"M-8", "digit-argument"},
1584 {"M-9", "digit-argument"},
1585 {"M-a", "vi-append"},
1586 {"M-A", "vi-append-at-eol"},
1587 {"M-b", "backward-word"},
1588 {"M-B", "backward-word"},
1589 {"M-C", "vi-change-rest-of-line"},
1590 {"M-cb", "vi-backward-change-word"},
1591 {"M-cB", "vi-backward-change-word"},
1592 {"M-cc", "vi-change-line"},
1593 {"M-ce", "vi-forward-change-word"},
1594 {"M-cE", "vi-forward-change-word"},
1595 {"M-cw", "vi-forward-change-word"},
1596 {"M-cW", "vi-forward-change-word"},
1597 {"M-cF", "vi-backward-change-find"},
1598 {"M-cf", "vi-forward-change-find"},
1599 {"M-cT", "vi-backward-change-to"},
1600 {"M-ct", "vi-forward-change-to"},
1601 {"M-c;", "vi-change-refind"},
1602 {"M-c,", "vi-change-invert-refind"},
1603 {"M-ch", "vi-backward-change-char"},
1604 {"M-c^H", "vi-backward-change-char"},
1605 {"M-c^?", "vi-backward-change-char"},
1606 {"M-cl", "vi-forward-change-char"},
1607 {"M-c ", "vi-forward-change-char"},
1608 {"M-c^", "vi-change-to-bol"},
1609 {"M-c0", "vi-change-to-bol"},
1610 {"M-c$", "vi-change-rest-of-line"},
1611 {"M-c|", "vi-change-to-column"},
1612 {"M-c%", "vi-change-to-parenthesis"},
1613 {"M-dh", "backward-delete-char"},
1614 {"M-d^H", "backward-delete-char"},
1615 {"M-d^?", "backward-delete-char"},
1616 {"M-dl", "forward-delete-char"},
1617 {"M-d ", "forward-delete-char"},
1618 {"M-dd", "delete-line"},
1619 {"M-db", "backward-delete-word"},
1620 {"M-dB", "backward-delete-word"},
1621 {"M-de", "forward-delete-word"},
1622 {"M-dE", "forward-delete-word"},
1623 {"M-dw", "forward-delete-word"},
1624 {"M-dW", "forward-delete-word"},
1625 {"M-dF", "backward-delete-find"},
1626 {"M-df", "forward-delete-find"},
1627 {"M-dT", "backward-delete-to"},
1628 {"M-dt", "forward-delete-to"},
1629 {"M-d;", "delete-refind"},
1630 {"M-d,", "delete-invert-refind"},
1631 {"M-d^", "backward-kill-line"},
1632 {"M-d0", "backward-kill-line"},
1633 {"M-d$", "kill-line"},
1634 {"M-D", "kill-line"},
1635 {"M-d|", "delete-to-column"},
1636 {"M-d%", "delete-to-parenthesis"},
1637 {"M-e", "forward-word"},
1638 {"M-E", "forward-word"},
1639 {"M-f", "forward-find-char"},
1640 {"M-F", "backward-find-char"},
1641 {"M--", "up-history"},
1642 {"M-h", "cursor-left"},
1643 {"M-H", "beginning-of-history"},
1644 {"M-i", "vi-insert"},
1645 {"M-I", "vi-insert-at-bol"},
1646 {"M-j", "down-history"},
1647 {"M-J", "history-search-forward"},
1648 {"M-k", "up-history"},
1649 {"M-K", "history-search-backward"},
1650 {"M-l", "cursor-right"},
1651 {"M-L", "end-of-history"},
1652 {"M-n", "history-re-search-forward"},
1653 {"M-N", "history-re-search-backward"},
1654 {"M-p", "append-yank"},
1655 {"M-P", "yank"},
1656 {"M-r", "vi-replace-char"},
1657 {"M-R", "vi-overwrite"},
1658 {"M-s", "vi-forward-change-char"},
1659 {"M-S", "vi-change-line"},
1660 {"M-t", "forward-to-char"},
1661 {"M-T", "backward-to-char"},
1662 {"M-u", "vi-undo"},
1663 {"M-w", "forward-to-word"},
1664 {"M-W", "forward-to-word"},
1665 {"M-x", "forward-delete-char"},
1666 {"M-X", "backward-delete-char"},
1667 {"M-yh", "backward-copy-char"},
1668 {"M-y^H", "backward-copy-char"},
1669 {"M-y^?", "backward-copy-char"},
1670 {"M-yl", "forward-copy-char"},
1671 {"M-y ", "forward-copy-char"},
1672 {"M-ye", "forward-copy-word"},
1673 {"M-yE", "forward-copy-word"},
1674 {"M-yw", "forward-copy-word"},
1675 {"M-yW", "forward-copy-word"},
1676 {"M-yb", "backward-copy-word"},
1677 {"M-yB", "backward-copy-word"},
1678 {"M-yf", "forward-copy-find"},
1679 {"M-yF", "backward-copy-find"},
1680 {"M-yt", "forward-copy-to"},
1681 {"M-yT", "backward-copy-to"},
1682 {"M-y;", "copy-refind"},
1683 {"M-y,", "copy-invert-refind"},
1684 {"M-y^", "copy-to-bol"},
1685 {"M-y0", "copy-to-bol"},
1686 {"M-y$", "copy-rest-of-line"},
1687 {"M-yy", "copy-line"},
1688 {"M-Y", "copy-line"},
1689 {"M-y|", "copy-to-column"},
1690 {"M-y%", "copy-to-parenthesis"},
1691 {"M-^E", "emacs-mode"},
1692 {"M-^H", "cursor-left"},
1693 {"M-^?", "cursor-left"},
1694 {"M-^L", "clear-screen"},
1695 {"M-^N", "down-history"},
1696 {"M-^P", "up-history"},
1697 {"M-^R", "redisplay"},
1698 {"M-^D", "list-or-eof"},
1699 {"M-\r", "newline"},
1700 {"M-\t", "complete-word"},
1701 {"M-\n", "newline"},
1702 #ifndef HIDE_FILE_SYSTEM
1703 {"M-^X^R", "read-init-files"},
1704 #endif
1705 {"M-^Xh", "list-history"},
1706 {"M-^XH", "list-history"},
1707 {"down", "down-history"},
1708 {"up", "up-history"},
1709 {"left", "cursor-left"},
1710 {"right", "cursor-right"},
1711 };
1712
1713 /*.......................................................................
1714 * Create a new GetLine object.
1715 *
1716 * Input:
1717 * linelen size_t The maximum line length to allow for.
1718 * histlen size_t The number of bytes to allocate for recording
1719 * a circular buffer of history lines.
1720 * Output:
1721 * return GetLine * The new object, or NULL on error.
1722 */
new_GetLine(size_t linelen,size_t histlen)1723 GetLine *new_GetLine(size_t linelen, size_t histlen)
1724 {
1725 GetLine *gl; /* The object to be returned */
1726 int i;
1727 /*
1728 * Check the arguments.
1729 */
1730 if(linelen < 10) {
1731 errno = ENOMEM;
1732 return NULL;
1733 };
1734 /*
1735 * Allocate the container.
1736 */
1737 gl = (GetLine *) malloc(sizeof(GetLine));
1738 if(!gl) {
1739 errno = ENOMEM;
1740 return NULL;
1741 };
1742 /*
1743 * Before attempting any operation that might fail, initialize the
1744 * container at least up to the point at which it can safely be passed
1745 * to del_GetLine().
1746 */
1747 gl->err = NULL;
1748 gl->glh = NULL;
1749 gl->cpl = NULL;
1750 #ifndef HIDE_FILE_SYSTEM
1751 gl->cplfn.fn = cpl_file_completions;
1752 #else
1753 gl->cplfn.fn = gl_no_completions;
1754 #endif
1755 gl->cplfn.data = NULL;
1756 #ifndef WITHOUT_FILE_SYSTEM
1757 gl->ef = NULL;
1758 #endif
1759 gl->capmem = NULL;
1760 gl->cq = NULL;
1761 gl->input_fd = -1;
1762 gl->output_fd = -1;
1763 gl->input_fp = NULL;
1764 gl->output_fp = NULL;
1765 gl->file_fp = NULL;
1766 gl->term = NULL;
1767 gl->is_term = 0;
1768 gl->flush_fn = gl_flush_terminal;
1769 gl->io_mode = GL_NORMAL_MODE;
1770 gl->raw_mode = 0;
1771 gl->pending_io = GLP_WRITE; /* We will start by writing the prompt */
1772 gl_clear_status(gl);
1773 gl->linelen = linelen;
1774 gl->line = NULL;
1775 gl->cutbuf = NULL;
1776 gl->prompt = NULL;
1777 gl->prompt_len = 0;
1778 gl->prompt_changed = 0;
1779 gl->prompt_style = GL_LITERAL_PROMPT;
1780 gl->cpl_mem = NULL;
1781 gl->ext_act_mem = NULL;
1782 gl->sig_mem = NULL;
1783 gl->sigs = NULL;
1784 gl->signals_masked = 0;
1785 gl->signals_overriden = 0;
1786 sigemptyset(&gl->all_signal_set);
1787 sigemptyset(&gl->old_signal_set);
1788 sigemptyset(&gl->use_signal_set);
1789 gl->bindings = NULL;
1790 gl->ntotal = 0;
1791 gl->buff_curpos = 0;
1792 gl->term_curpos = 0;
1793 gl->term_len = 0;
1794 gl->buff_mark = 0;
1795 gl->insert_curpos = 0;
1796 gl->insert = 1;
1797 gl->number = -1;
1798 gl->endline = 1;
1799 gl->displayed = 0;
1800 gl->redisplay = 0;
1801 gl->postpone = 0;
1802 gl->keybuf[0]='\0';
1803 gl->nbuf = 0;
1804 gl->nread = 0;
1805 gl->current_action.fn = 0;
1806 gl->current_action.data = NULL;
1807 gl->current_count = 0;
1808 gl->preload_id = 0;
1809 gl->preload_history = 0;
1810 gl->keyseq_count = 0;
1811 gl->last_search = -1;
1812 gl->editor = GL_EMACS_MODE;
1813 gl->silence_bell = 0;
1814 gl->automatic_history = 1;
1815 gl->vi.undo.line = NULL;
1816 gl->vi.undo.buff_curpos = 0;
1817 gl->vi.undo.ntotal = 0;
1818 gl->vi.undo.saved = 0;
1819 gl->vi.repeat.action.fn = 0;
1820 gl->vi.repeat.action.data = 0;
1821 gl->vi.repeat.count = 0;
1822 gl->vi.repeat.input_curpos = 0;
1823 gl->vi.repeat.command_curpos = 0;
1824 gl->vi.repeat.input_char = '\0';
1825 gl->vi.repeat.saved = 0;
1826 gl->vi.repeat.active = 0;
1827 gl->vi.command = 0;
1828 gl->vi.find_forward = 0;
1829 gl->vi.find_onto = 0;
1830 gl->vi.find_char = '\0';
1831 gl->left = NULL;
1832 gl->right = NULL;
1833 gl->up = NULL;
1834 gl->down = NULL;
1835 gl->home = NULL;
1836 gl->bol = 0;
1837 gl->clear_eol = NULL;
1838 gl->clear_eod = NULL;
1839 gl->u_arrow = NULL;
1840 gl->d_arrow = NULL;
1841 gl->l_arrow = NULL;
1842 gl->r_arrow = NULL;
1843 gl->sound_bell = NULL;
1844 gl->bold = NULL;
1845 gl->underline = NULL;
1846 gl->standout = NULL;
1847 gl->dim = NULL;
1848 gl->reverse = NULL;
1849 gl->blink = NULL;
1850 gl->text_attr_off = NULL;
1851 gl->nline = 0;
1852 gl->ncolumn = 0;
1853 #ifdef USE_TERMINFO
1854 gl->left_n = NULL;
1855 gl->right_n = NULL;
1856 #elif defined(USE_TERMCAP)
1857 gl->tgetent_buf = NULL;
1858 gl->tgetstr_buf = NULL;
1859 #endif
1860 gl->app_file = NULL;
1861 gl->user_file = NULL;
1862 gl->configured = 0;
1863 gl->echo = 1;
1864 gl->last_signal = -1;
1865 #ifdef HAVE_SELECT
1866 gl->fd_node_mem = NULL;
1867 gl->fd_nodes = NULL;
1868 FD_ZERO(&gl->rfds);
1869 FD_ZERO(&gl->wfds);
1870 FD_ZERO(&gl->ufds);
1871 gl->max_fd = 0;
1872 gl->timer.dt.tv_sec = 0;
1873 gl->timer.dt.tv_usec = 0;
1874 gl->timer.fn = 0;
1875 gl->timer.data = NULL;
1876 #endif
1877 /*
1878 * Allocate an error reporting buffer.
1879 */
1880 gl->err = _new_ErrMsg();
1881 if(!gl->err)
1882 return del_GetLine(gl);
1883 /*
1884 * Allocate the history buffer.
1885 */
1886 gl->glh = _new_GlHistory(histlen);
1887 if(!gl->glh)
1888 return del_GetLine(gl);
1889 /*
1890 * Allocate the resource object for file-completion.
1891 */
1892 gl->cpl = new_WordCompletion();
1893 if(!gl->cpl)
1894 return del_GetLine(gl);
1895 /*
1896 * Allocate the resource object for file-completion.
1897 */
1898 #ifndef WITHOUT_FILE_SYSTEM
1899 gl->ef = new_ExpandFile();
1900 if(!gl->ef)
1901 return del_GetLine(gl);
1902 #endif
1903 /*
1904 * Allocate a string-segment memory allocator for use in storing terminal
1905 * capablity strings.
1906 */
1907 gl->capmem = _new_StringGroup(CAPMEM_SEGMENT_SIZE);
1908 if(!gl->capmem)
1909 return del_GetLine(gl);
1910 /*
1911 * Allocate the character queue that is used to buffer terminal output.
1912 */
1913 gl->cq = _new_GlCharQueue();
1914 if(!gl->cq)
1915 return del_GetLine(gl);
1916 /*
1917 * Allocate a line buffer, leaving 2 extra characters for the terminating
1918 * '\n' and '\0' characters
1919 */
1920 gl->line = (char *) malloc(linelen + 2);
1921 if(!gl->line) {
1922 errno = ENOMEM;
1923 return del_GetLine(gl);
1924 };
1925 /*
1926 * Start with an empty input line.
1927 */
1928 gl_truncate_buffer(gl, 0);
1929 /*
1930 * Allocate a cut buffer.
1931 */
1932 gl->cutbuf = (char *) malloc(linelen + 2);
1933 if(!gl->cutbuf) {
1934 errno = ENOMEM;
1935 return del_GetLine(gl);
1936 };
1937 gl->cutbuf[0] = '\0';
1938 /*
1939 * Allocate an initial empty prompt.
1940 */
1941 _gl_replace_prompt(gl, NULL);
1942 if(!gl->prompt) {
1943 errno = ENOMEM;
1944 return del_GetLine(gl);
1945 };
1946 /*
1947 * Allocate a vi undo buffer.
1948 */
1949 gl->vi.undo.line = (char *) malloc(linelen + 2);
1950 if(!gl->vi.undo.line) {
1951 errno = ENOMEM;
1952 return del_GetLine(gl);
1953 };
1954 gl->vi.undo.line[0] = '\0';
1955 /*
1956 * Allocate a freelist from which to allocate nodes for the list
1957 * of completion functions.
1958 */
1959 gl->cpl_mem = _new_FreeList(sizeof(GlCplCallback), GL_CPL_FREELIST_BLOCKING);
1960 if(!gl->cpl_mem)
1961 return del_GetLine(gl);
1962 /*
1963 * Allocate a freelist from which to allocate nodes for the list
1964 * of external action functions.
1965 */
1966 gl->ext_act_mem = _new_FreeList(sizeof(GlExternalAction),
1967 GL_EXT_ACT_FREELIST_BLOCKING);
1968 if(!gl->ext_act_mem)
1969 return del_GetLine(gl);
1970 /*
1971 * Allocate a freelist from which to allocate nodes for the list
1972 * of signals.
1973 */
1974 gl->sig_mem = _new_FreeList(sizeof(GlSignalNode), GLS_FREELIST_BLOCKING);
1975 if(!gl->sig_mem)
1976 return del_GetLine(gl);
1977 /*
1978 * Install initial dispositions for the default list of signals that
1979 * gl_get_line() traps.
1980 */
1981 for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
1982 const struct GlDefSignal *sig = gl_signal_list + i;
1983 if(_gl_trap_signal(gl, sig->signo, sig->flags, sig->after,
1984 sig->errno_value))
1985 return del_GetLine(gl);
1986 };
1987 /*
1988 * Allocate an empty table of key bindings.
1989 */
1990 gl->bindings = _new_KeyTab();
1991 if(!gl->bindings)
1992 return del_GetLine(gl);
1993 /*
1994 * Define the available actions that can be bound to key sequences.
1995 */
1996 for(i=0; i<sizeof(gl_actions)/sizeof(gl_actions[0]); i++) {
1997 if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn, NULL))
1998 return del_GetLine(gl);
1999 };
2000 /*
2001 * Set up the default bindings.
2002 */
2003 if(gl_change_editor(gl, gl->editor))
2004 return del_GetLine(gl);
2005 /*
2006 * Allocate termcap buffers.
2007 */
2008 #ifdef USE_TERMCAP
2009 gl->tgetent_buf = (char *) malloc(TERMCAP_BUF_SIZE);
2010 gl->tgetstr_buf = (char *) malloc(TERMCAP_BUF_SIZE);
2011 if(!gl->tgetent_buf || !gl->tgetstr_buf) {
2012 errno = ENOMEM;
2013 return del_GetLine(gl);
2014 };
2015 #endif
2016 /*
2017 * Set up for I/O assuming stdin and stdout.
2018 */
2019 if(_gl_change_terminal(gl, stdin, stdout, getenv("TERM")))
2020 return del_GetLine(gl);
2021 /*
2022 * Create a freelist for use in allocating GlFdNode list nodes.
2023 */
2024 #ifdef HAVE_SELECT
2025 gl->fd_node_mem = _new_FreeList(sizeof(GlFdNode), GLFD_FREELIST_BLOCKING);
2026 if(!gl->fd_node_mem)
2027 return del_GetLine(gl);
2028 #endif
2029 /*
2030 * We are done for now.
2031 */
2032 return gl;
2033 }
2034
2035 /*.......................................................................
2036 * Delete a GetLine object.
2037 *
2038 * Input:
2039 * gl GetLine * The object to be deleted.
2040 * Output:
2041 * return GetLine * The deleted object (always NULL).
2042 */
del_GetLine(GetLine * gl)2043 GetLine *del_GetLine(GetLine *gl)
2044 {
2045 if(gl) {
2046 /*
2047 * If the terminal is in raw server mode, reset it.
2048 */
2049 _gl_normal_io(gl);
2050 /*
2051 * Deallocate all objects contained by gl.
2052 */
2053 gl->err = _del_ErrMsg(gl->err);
2054 gl->glh = _del_GlHistory(gl->glh);
2055 gl->cpl = del_WordCompletion(gl->cpl);
2056 #ifndef WITHOUT_FILE_SYSTEM
2057 gl->ef = del_ExpandFile(gl->ef);
2058 #endif
2059 gl->capmem = _del_StringGroup(gl->capmem);
2060 gl->cq = _del_GlCharQueue(gl->cq);
2061 if(gl->file_fp)
2062 fclose(gl->file_fp);
2063 if(gl->term)
2064 free(gl->term);
2065 if(gl->line)
2066 free(gl->line);
2067 if(gl->cutbuf)
2068 free(gl->cutbuf);
2069 if(gl->prompt)
2070 free(gl->prompt);
2071 gl->cpl_mem = _del_FreeList(gl->cpl_mem, 1);
2072 gl->ext_act_mem = _del_FreeList(gl->ext_act_mem, 1);
2073 gl->sig_mem = _del_FreeList(gl->sig_mem, 1);
2074 gl->sigs = NULL; /* Already freed by freeing sig_mem */
2075 gl->bindings = _del_KeyTab(gl->bindings);
2076 if(gl->vi.undo.line)
2077 free(gl->vi.undo.line);
2078 #ifdef USE_TERMCAP
2079 if(gl->tgetent_buf)
2080 free(gl->tgetent_buf);
2081 if(gl->tgetstr_buf)
2082 free(gl->tgetstr_buf);
2083 #endif
2084 if(gl->app_file)
2085 free(gl->app_file);
2086 if(gl->user_file)
2087 free(gl->user_file);
2088 #ifdef HAVE_SELECT
2089 gl->fd_node_mem = _del_FreeList(gl->fd_node_mem, 1);
2090 gl->fd_nodes = NULL; /* Already freed by freeing gl->fd_node_mem */
2091 #endif
2092 /*
2093 * Delete the now empty container.
2094 */
2095 free(gl);
2096 };
2097 return NULL;
2098 }
2099
2100 /*.......................................................................
2101 * Bind a control or meta character to an action.
2102 *
2103 * Input:
2104 * gl GetLine * The resource object of this program.
2105 * binder KtBinder The source of the binding.
2106 * c char The control or meta character.
2107 * If this is '\0', the call is ignored.
2108 * action const char * The action name to bind the key to.
2109 * Output:
2110 * return int 0 - OK.
2111 * 1 - Error.
2112 */
gl_bind_control_char(GetLine * gl,KtBinder binder,char c,const char * action)2113 static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c,
2114 const char *action)
2115 {
2116 char keyseq[2];
2117 /*
2118 * Quietly reject binding to the NUL control character, since this
2119 * is an ambiguous prefix of all bindings.
2120 */
2121 if(c == '\0')
2122 return 0;
2123 /*
2124 * Making sure not to bind characters which aren't either control or
2125 * meta characters.
2126 */
2127 if(IS_CTRL_CHAR(c) || IS_META_CHAR(c)) {
2128 keyseq[0] = c;
2129 keyseq[1] = '\0';
2130 } else {
2131 return 0;
2132 };
2133 /*
2134 * Install the binding.
2135 */
2136 if(_kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
2137 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
2138 return 1;
2139 };
2140 return 0;
2141 }
2142
2143 /*.......................................................................
2144 * Read a line from the user.
2145 *
2146 * Input:
2147 * gl GetLine * A resource object returned by new_GetLine().
2148 * prompt char * The prompt to prefix the line with.
2149 * start_line char * The initial contents of the input line, or NULL
2150 * if it should start out empty.
2151 * start_pos int If start_line isn't NULL, this specifies the
2152 * index of the character over which the cursor
2153 * should initially be positioned within the line.
2154 * If you just want it to follow the last character
2155 * of the line, send -1.
2156 * Output:
2157 * return char * An internal buffer containing the input line, or
2158 * NULL at the end of input. If the line fitted in
2159 * the buffer there will be a '\n' newline character
2160 * before the terminating '\0'. If it was truncated
2161 * there will be no newline character, and the remains
2162 * of the line should be retrieved via further calls
2163 * to this function.
2164 */
gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2165 char *gl_get_line(GetLine *gl, const char *prompt,
2166 const char *start_line, int start_pos)
2167 {
2168 char *retval; /* The return value of _gl_get_line() */
2169 /*
2170 * Check the arguments.
2171 */
2172 if(!gl) {
2173 errno = EINVAL;
2174 return NULL;
2175 };
2176 /*
2177 * Temporarily block all of the signals that we have been asked to trap.
2178 */
2179 if(gl_mask_signals(gl, &gl->old_signal_set))
2180 return NULL;
2181 /*
2182 * Perform the command-line editing task.
2183 */
2184 retval = _gl_get_line(gl, prompt, start_line, start_pos);
2185 /*
2186 * Restore the process signal mask to how it was when this function was
2187 * first called.
2188 */
2189 gl_unmask_signals(gl, &gl->old_signal_set);
2190 return retval;
2191 }
2192
2193
2194 /*.......................................................................
2195 * This is the main body of the public function gl_get_line().
2196 */
_gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2197 static char *_gl_get_line(GetLine *gl, const char *prompt,
2198 const char *start_line, int start_pos)
2199 {
2200 int waserr = 0; /* True if an error occurs */
2201 /*
2202 * Assume that this call will successfully complete the input
2203 * line until proven otherwise.
2204 */
2205 gl_clear_status(gl);
2206 /*
2207 * If this is the first call to this function since new_GetLine(),
2208 * complete any postponed configuration.
2209 */
2210 if(!gl->configured) {
2211 (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
2212 gl->configured = 1;
2213 };
2214 /*
2215 * Before installing our signal handler functions, record the fact
2216 * that there are no pending signals.
2217 */
2218 gl_pending_signal = -1;
2219 /*
2220 * Temporarily override the signal handlers of the calling program,
2221 * so that we can intercept signals that would leave the terminal
2222 * in a bad state.
2223 */
2224 waserr = gl_override_signal_handlers(gl);
2225 /*
2226 * After recording the current terminal settings, switch the terminal
2227 * into raw input mode.
2228 */
2229 waserr = waserr || _gl_raw_io(gl, 1);
2230 /*
2231 * Attempt to read the line. This will require more than one attempt if
2232 * either a current temporary input file is opened by gl_get_input_line()
2233 * or the end of a temporary input file is reached by gl_read_stream_line().
2234 */
2235 while(!waserr) {
2236 /*
2237 * Read a line from a non-interactive stream?
2238 */
2239 if(gl->file_fp || !gl->is_term) {
2240 if(gl_read_stream_line(gl)==0) {
2241 break;
2242 } else if(gl->file_fp) {
2243 gl_revert_input(gl);
2244 gl_record_status(gl, GLR_NEWLINE, 0);
2245 } else {
2246 waserr = 1;
2247 break;
2248 };
2249 };
2250 /*
2251 * Read from the terminal? Note that the above if() block may have
2252 * changed gl->file_fp, so it is necessary to retest it here, rather
2253 * than using an else statement.
2254 */
2255 if(!gl->file_fp && gl->is_term) {
2256 if(gl_get_input_line(gl, prompt, start_line, start_pos))
2257 waserr = 1;
2258 else
2259 break;
2260 };
2261 };
2262 /*
2263 * If an error occurred, but gl->rtn_status is still set to
2264 * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
2265 * leave it at whatever specific value was assigned by the function
2266 * that aborted input. This means that only functions that trap
2267 * non-generic errors have to remember to update gl->rtn_status
2268 * themselves.
2269 */
2270 if(waserr && gl->rtn_status == GLR_NEWLINE)
2271 gl_record_status(gl, GLR_ERROR, errno);
2272 /*
2273 * Restore terminal settings.
2274 */
2275 if(gl->io_mode != GL_SERVER_MODE)
2276 _gl_normal_io(gl);
2277 /*
2278 * Restore the signal handlers.
2279 */
2280 gl_restore_signal_handlers(gl);
2281 /*
2282 * If gl_get_line() gets aborted early, the errno value associated
2283 * with the event that caused this to happen is recorded in
2284 * gl->rtn_errno. Since errno may have been overwritten by cleanup
2285 * functions after this, restore its value to the value that it had
2286 * when the error condition occured, so that the caller can examine it
2287 * to find out what happened.
2288 */
2289 errno = gl->rtn_errno;
2290 /*
2291 * Check the completion status to see how to return.
2292 */
2293 switch(gl->rtn_status) {
2294 case GLR_NEWLINE: /* Success */
2295 return gl->line;
2296 case GLR_BLOCKED: /* These events abort the current input line, */
2297 case GLR_SIGNAL: /* when in normal blocking I/O mode, but only */
2298 case GLR_TIMEOUT: /* temporarily pause line editing when in */
2299 case GLR_FDABORT: /* non-blocking server I/O mode. */
2300 if(gl->io_mode != GL_SERVER_MODE)
2301 _gl_abandon_line(gl);
2302 return NULL;
2303 case GLR_ERROR: /* Unrecoverable errors abort the input line, */
2304 case GLR_EOF: /* regardless of the I/O mode. */
2305 default:
2306 _gl_abandon_line(gl);
2307 return NULL;
2308 };
2309 }
2310
2311 /*.......................................................................
2312 * Read a single character from the user.
2313 *
2314 * Input:
2315 * gl GetLine * A resource object returned by new_GetLine().
2316 * prompt char * The prompt to prefix the line with, or NULL if
2317 * no prompt is required.
2318 * defchar char The character to substitute if the
2319 * user simply hits return, or '\n' if you don't
2320 * need to substitute anything.
2321 * Output:
2322 * return int The character that was read, or EOF if the read
2323 * had to be aborted (in which case you can call
2324 * gl_return_status() to find out why).
2325 */
gl_query_char(GetLine * gl,const char * prompt,char defchar)2326 int gl_query_char(GetLine *gl, const char *prompt, char defchar)
2327 {
2328 int retval; /* The return value of _gl_query_char() */
2329 /*
2330 * Check the arguments.
2331 */
2332 if(!gl) {
2333 errno = EINVAL;
2334 return EOF;
2335 };
2336 /*
2337 * Temporarily block all of the signals that we have been asked to trap.
2338 */
2339 if(gl_mask_signals(gl, &gl->old_signal_set))
2340 return EOF;
2341 /*
2342 * Perform the character reading task.
2343 */
2344 retval = _gl_query_char(gl, prompt, defchar);
2345 /*
2346 * Restore the process signal mask to how it was when this function was
2347 * first called.
2348 */
2349 gl_unmask_signals(gl, &gl->old_signal_set);
2350 return retval;
2351 }
2352
2353 /*.......................................................................
2354 * This is the main body of the public function gl_query_char().
2355 */
_gl_query_char(GetLine * gl,const char * prompt,char defchar)2356 static int _gl_query_char(GetLine *gl, const char *prompt, char defchar)
2357 {
2358 int c = EOF; /* The character to be returned */
2359 int waserr = 0; /* True if an error occurs */
2360 /*
2361 * Assume that this call will successfully complete the input operation
2362 * until proven otherwise.
2363 */
2364 gl_clear_status(gl);
2365 /*
2366 * If this is the first call to this function or gl_get_line(),
2367 * since new_GetLine(), complete any postponed configuration.
2368 */
2369 if(!gl->configured) {
2370 (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
2371 gl->configured = 1;
2372 };
2373 /*
2374 * Before installing our signal handler functions, record the fact
2375 * that there are no pending signals.
2376 */
2377 gl_pending_signal = -1;
2378 /*
2379 * Temporarily override the signal handlers of the calling program,
2380 * so that we can intercept signals that would leave the terminal
2381 * in a bad state.
2382 */
2383 waserr = gl_override_signal_handlers(gl);
2384 /*
2385 * After recording the current terminal settings, switch the terminal
2386 * into raw input mode without redisplaying any partially entered
2387 * input line.
2388 */
2389 waserr = waserr || _gl_raw_io(gl, 0);
2390 /*
2391 * Attempt to read the line. This will require more than one attempt if
2392 * either a current temporary input file is opened by gl_get_input_line()
2393 * or the end of a temporary input file is reached by gl_read_stream_line().
2394 */
2395 while(!waserr) {
2396 /*
2397 * Read a line from a non-interactive stream?
2398 */
2399 if(gl->file_fp || !gl->is_term) {
2400 c = gl_read_stream_char(gl);
2401 if(c != EOF) { /* Success? */
2402 if(c=='\n') c = defchar;
2403 break;
2404 } else if(gl->file_fp) { /* End of temporary input file? */
2405 gl_revert_input(gl);
2406 gl_record_status(gl, GLR_NEWLINE, 0);
2407 } else { /* An error? */
2408 waserr = 1;
2409 break;
2410 };
2411 };
2412 /*
2413 * Read from the terminal? Note that the above if() block may have
2414 * changed gl->file_fp, so it is necessary to retest it here, rather
2415 * than using an else statement.
2416 */
2417 if(!gl->file_fp && gl->is_term) {
2418 c = gl_get_query_char(gl, prompt, defchar);
2419 if(c==EOF)
2420 waserr = 1;
2421 else
2422 break;
2423 };
2424 };
2425 /*
2426 * If an error occurred, but gl->rtn_status is still set to
2427 * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
2428 * leave it at whatever specific value was assigned by the function
2429 * that aborted input. This means that only functions that trap
2430 * non-generic errors have to remember to update gl->rtn_status
2431 * themselves.
2432 */
2433 if(waserr && gl->rtn_status == GLR_NEWLINE)
2434 gl_record_status(gl, GLR_ERROR, errno);
2435 /*
2436 * Restore terminal settings.
2437 */
2438 if(gl->io_mode != GL_SERVER_MODE)
2439 _gl_normal_io(gl);
2440 /*
2441 * Restore the signal handlers.
2442 */
2443 gl_restore_signal_handlers(gl);
2444 /*
2445 * If this function gets aborted early, the errno value associated
2446 * with the event that caused this to happen is recorded in
2447 * gl->rtn_errno. Since errno may have been overwritten by cleanup
2448 * functions after this, restore its value to the value that it had
2449 * when the error condition occured, so that the caller can examine it
2450 * to find out what happened.
2451 */
2452 errno = gl->rtn_errno;
2453 /*
2454 * Error conditions are signalled to the caller, by setting the returned
2455 * character to EOF.
2456 */
2457 if(gl->rtn_status != GLR_NEWLINE)
2458 c = EOF;
2459 /*
2460 * In this mode, every character that is read is a completed
2461 * transaction, just like reading a completed input line, so prepare
2462 * for the next input line or character.
2463 */
2464 _gl_abandon_line(gl);
2465 /*
2466 * Return the acquired character.
2467 */
2468 return c;
2469 }
2470
2471 /*.......................................................................
2472 * Record of the signal handlers of the calling program, so that they
2473 * can be restored later.
2474 *
2475 * Input:
2476 * gl GetLine * The resource object of this library.
2477 * Output:
2478 * return int 0 - OK.
2479 * 1 - Error.
2480 */
gl_override_signal_handlers(GetLine * gl)2481 static int gl_override_signal_handlers(GetLine *gl)
2482 {
2483 GlSignalNode *sig; /* A node in the list of signals to be caught */
2484 /*
2485 * Set up our signal handler.
2486 */
2487 SigAction act;
2488 act.sa_handler = gl_signal_handler;
2489 memcpy(&act.sa_mask, &gl->all_signal_set, sizeof(sigset_t));
2490 act.sa_flags = 0;
2491 /*
2492 * Get the subset of the signals that we are supposed to trap that
2493 * should actually be trapped.
2494 */
2495 sigemptyset(&gl->use_signal_set);
2496 for(sig=gl->sigs; sig; sig=sig->next) {
2497 /*
2498 * Trap this signal? If it is blocked by the calling program and we
2499 * haven't been told to unblock it, don't arrange to trap this signal.
2500 */
2501 if(sig->flags & GLS_UNBLOCK_SIG ||
2502 !sigismember(&gl->old_signal_set, sig->signo)) {
2503 if(sigaddset(&gl->use_signal_set, sig->signo) == -1) {
2504 _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
2505 return 1;
2506 };
2507 };
2508 };
2509 /*
2510 * Override the actions of the signals that we are trapping.
2511 */
2512 for(sig=gl->sigs; sig; sig=sig->next) {
2513 if(sigismember(&gl->use_signal_set, sig->signo)) {
2514 sigdelset(&act.sa_mask, sig->signo);
2515 if(sigaction(sig->signo, &act, &sig->original)) {
2516 _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
2517 return 1;
2518 };
2519 sigaddset(&act.sa_mask, sig->signo);
2520 };
2521 };
2522 /*
2523 * Record the fact that the application's signal handlers have now
2524 * been overriden.
2525 */
2526 gl->signals_overriden = 1;
2527 /*
2528 * Just in case a SIGWINCH signal was sent to the process while our
2529 * SIGWINCH signal handler wasn't in place, check to see if the terminal
2530 * size needs updating.
2531 */
2532 if(_gl_update_size(gl))
2533 return 1;
2534 return 0;
2535 }
2536
2537 /*.......................................................................
2538 * Restore the signal handlers of the calling program.
2539 *
2540 * Input:
2541 * gl GetLine * The resource object of this library.
2542 * Output:
2543 * return int 0 - OK.
2544 * 1 - Error.
2545 */
gl_restore_signal_handlers(GetLine * gl)2546 static int gl_restore_signal_handlers(GetLine *gl)
2547 {
2548 GlSignalNode *sig; /* A node in the list of signals to be caught */
2549 /*
2550 * Restore application signal handlers that were overriden
2551 * by gl_override_signal_handlers().
2552 */
2553 for(sig=gl->sigs; sig; sig=sig->next) {
2554 if(sigismember(&gl->use_signal_set, sig->signo) &&
2555 sigaction(sig->signo, &sig->original, NULL)) {
2556 _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
2557 return 1;
2558 };
2559 };
2560 /*
2561 * Record the fact that the application's signal handlers have now
2562 * been restored.
2563 */
2564 gl->signals_overriden = 0;
2565 return 0;
2566 }
2567
2568 /*.......................................................................
2569 * This signal handler simply records the fact that a given signal was
2570 * caught in the file-scope gl_pending_signal variable.
2571 */
gl_signal_handler(int signo)2572 static void gl_signal_handler(int signo)
2573 {
2574 gl_pending_signal = signo;
2575 siglongjmp(gl_setjmp_buffer, 1);
2576 }
2577
2578 /*.......................................................................
2579 * Switch the terminal into raw mode after storing the previous terminal
2580 * settings in gl->attributes.
2581 *
2582 * Input:
2583 * gl GetLine * The resource object of this program.
2584 * Output:
2585 * return int 0 - OK.
2586 * 1 - Error.
2587 */
gl_raw_terminal_mode(GetLine * gl)2588 static int gl_raw_terminal_mode(GetLine *gl)
2589 {
2590 Termios newattr; /* The new terminal attributes */
2591 /*
2592 * If the terminal is already in raw mode, do nothing.
2593 */
2594 if(gl->raw_mode)
2595 return 0;
2596 /*
2597 * Record the current terminal attributes.
2598 */
2599 if(tcgetattr(gl->input_fd, &gl->oldattr)) {
2600 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
2601 return 1;
2602 };
2603 /*
2604 * This function shouldn't do anything but record the current terminal
2605 * attritubes if editing has been disabled.
2606 */
2607 if(gl->editor == GL_NO_EDITOR)
2608 return 0;
2609 /*
2610 * Modify the existing attributes.
2611 */
2612 newattr = gl->oldattr;
2613 /*
2614 * Turn off local echo, canonical input mode and extended input processing.
2615 */
2616 newattr.c_lflag &= ~(ECHO | ICANON | IEXTEN);
2617 /*
2618 * Don't translate carriage return to newline, turn off input parity
2619 * checking, don't strip off 8th bit, turn off output flow control.
2620 */
2621 newattr.c_iflag &= ~(ICRNL | INPCK | ISTRIP);
2622 /*
2623 * Clear size bits, turn off parity checking, and allow 8-bit characters.
2624 */
2625 newattr.c_cflag &= ~(CSIZE | PARENB);
2626 newattr.c_cflag |= CS8;
2627 /*
2628 * Turn off output processing.
2629 */
2630 newattr.c_oflag &= ~(OPOST);
2631 /*
2632 * Request one byte at a time, without waiting.
2633 */
2634 newattr.c_cc[VMIN] = gl->io_mode==GL_SERVER_MODE ? 0:1;
2635 newattr.c_cc[VTIME] = 0;
2636 /*
2637 * Install the new terminal modes.
2638 */
2639 while(tcsetattr(gl->input_fd, TCSADRAIN, &newattr)) {
2640 if(errno != EINTR) {
2641 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
2642 return 1;
2643 };
2644 };
2645 /*
2646 * Record the new terminal mode.
2647 */
2648 gl->raw_mode = 1;
2649 return 0;
2650 }
2651
2652 /*.......................................................................
2653 * Restore the terminal attributes recorded in gl->oldattr.
2654 *
2655 * Input:
2656 * gl GetLine * The resource object of this library.
2657 * Output:
2658 * return int 0 - OK.
2659 * 1 - Error.
2660 */
gl_restore_terminal_attributes(GetLine * gl)2661 static int gl_restore_terminal_attributes(GetLine *gl)
2662 {
2663 int waserr = 0;
2664 /*
2665 * If not in raw mode, do nothing.
2666 */
2667 if(!gl->raw_mode)
2668 return 0;
2669 /*
2670 * Before changing the terminal attributes, make sure that all output
2671 * has been passed to the terminal.
2672 */
2673 if(gl_flush_output(gl))
2674 waserr = 1;
2675 /*
2676 * Reset the terminal attributes to the values that they had on
2677 * entry to gl_get_line().
2678 */
2679 while(tcsetattr(gl->input_fd, TCSADRAIN, &gl->oldattr)) {
2680 if(errno != EINTR) {
2681 _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
2682 waserr = 1;
2683 break;
2684 };
2685 };
2686 /*
2687 * Record the new terminal mode.
2688 */
2689 gl->raw_mode = 0;
2690 return waserr;
2691 }
2692
2693 /*.......................................................................
2694 * Switch the terminal file descriptor to use non-blocking I/O.
2695 *
2696 * Input:
2697 * gl GetLine * The resource object of gl_get_line().
2698 * fd int The file descriptor to make non-blocking.
2699 */
gl_nonblocking_io(GetLine * gl,int fd)2700 static int gl_nonblocking_io(GetLine *gl, int fd)
2701 {
2702 int fcntl_flags; /* The new file-descriptor control flags */
2703 /*
2704 * Is non-blocking I/O supported on this system? Note that even
2705 * without non-blocking I/O, the terminal will probably still act as
2706 * though it was non-blocking, because we also set the terminal
2707 * attributes to return immediately if no input is available and we
2708 * use select() to wait to be able to write. If select() also isn't
2709 * available, then input will probably remain fine, but output could
2710 * block, depending on the behaviour of the terminal driver.
2711 */
2712 #if defined(NON_BLOCKING_FLAG)
2713 /*
2714 * Query the current file-control flags, and add the
2715 * non-blocking I/O flag.
2716 */
2717 fcntl_flags = fcntl(fd, F_GETFL) | NON_BLOCKING_FLAG;
2718 /*
2719 * Install the new control flags.
2720 */
2721 if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
2722 _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
2723 return 1;
2724 };
2725 #endif
2726 return 0;
2727 }
2728
2729 /*.......................................................................
2730 * Switch to blocking terminal I/O.
2731 *
2732 * Input:
2733 * gl GetLine * The resource object of gl_get_line().
2734 * fd int The file descriptor to make blocking.
2735 */
gl_blocking_io(GetLine * gl,int fd)2736 static int gl_blocking_io(GetLine *gl, int fd)
2737 {
2738 int fcntl_flags; /* The new file-descriptor control flags */
2739 /*
2740 * Is non-blocking I/O implemented on this system?
2741 */
2742 #if defined(NON_BLOCKING_FLAG)
2743 /*
2744 * Query the current file control flags and remove the non-blocking
2745 * I/O flag.
2746 */
2747 fcntl_flags = fcntl(fd, F_GETFL) & ~NON_BLOCKING_FLAG;
2748 /*
2749 * Install the modified control flags.
2750 */
2751 if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
2752 _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
2753 return 1;
2754 };
2755 #endif
2756 return 0;
2757 }
2758
2759 /*.......................................................................
2760 * Read a new input line from the user.
2761 *
2762 * Input:
2763 * gl GetLine * The resource object of this library.
2764 * prompt char * The prompt to prefix the line with, or NULL to
2765 * use the same prompt that was used by the previous
2766 * line.
2767 * start_line char * The initial contents of the input line, or NULL
2768 * if it should start out empty.
2769 * start_pos int If start_line isn't NULL, this specifies the
2770 * index of the character over which the cursor
2771 * should initially be positioned within the line.
2772 * If you just want it to follow the last character
2773 * of the line, send -1.
2774 * Output:
2775 * return int 0 - OK.
2776 * 1 - Error.
2777 */
gl_get_input_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)2778 static int gl_get_input_line(GetLine *gl, const char *prompt,
2779 const char *start_line, int start_pos)
2780 {
2781 char c; /* The character being read */
2782 /*
2783 * Flush any pending output to the terminal.
2784 */
2785 if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
2786 return 1;
2787 /*
2788 * Are we starting a new line?
2789 */
2790 if(gl->endline) {
2791 /*
2792 * Delete any incompletely enterred line.
2793 */
2794 if(gl_erase_line(gl))
2795 return 1;
2796 /*
2797 * Display the new line to be edited.
2798 */
2799 if(gl_present_line(gl, prompt, start_line, start_pos))
2800 return 1;
2801 };
2802 /*
2803 * Read one character at a time.
2804 */
2805 while(gl_read_terminal(gl, 1, &c) == 0) {
2806 /*
2807 * Increment the count of the number of key sequences entered.
2808 */
2809 gl->keyseq_count++;
2810 /*
2811 * Interpret the character either as the start of a new key-sequence,
2812 * as a continuation of a repeat count, or as a printable character
2813 * to be added to the line.
2814 */
2815 if(gl_interpret_char(gl, c))
2816 break;
2817 /*
2818 * If we just ran an action function which temporarily asked for
2819 * input to be taken from a file, abort this call.
2820 */
2821 if(gl->file_fp)
2822 return 0;
2823 /*
2824 * Has the line been completed?
2825 */
2826 if(gl->endline)
2827 return gl_line_ended(gl, c);
2828 };
2829 /*
2830 * To get here, gl_read_terminal() must have returned non-zero. See
2831 * whether a signal was caught that requested that the current line
2832 * be returned.
2833 */
2834 if(gl->endline)
2835 return gl_line_ended(gl, '\n');
2836 /*
2837 * If I/O blocked while attempting to get the latest character
2838 * of the key sequence, rewind the key buffer to allow interpretation of
2839 * the current key sequence to be restarted on the next call to this
2840 * function.
2841 */
2842 if(gl->rtn_status == GLR_BLOCKED && gl->pending_io == GLP_READ)
2843 gl->nread = 0;
2844 return 1;
2845 }
2846
2847 /*.......................................................................
2848 * This is the private function of gl_query_char() that handles
2849 * prompting the user, reading a character from the terminal, and
2850 * displaying what the user entered.
2851 *
2852 * Input:
2853 * gl GetLine * The resource object of this library.
2854 * prompt char * The prompt to prefix the line with.
2855 * defchar char The character to substitute if the
2856 * user simply hits return, or '\n' if you don't
2857 * need to substitute anything.
2858 * Output:
2859 * return int The character that was read, or EOF if something
2860 * prevented a character from being read.
2861 */
gl_get_query_char(GetLine * gl,const char * prompt,int defchar)2862 static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar)
2863 {
2864 char c; /* The character being read */
2865 int retval; /* The return value of this function */
2866 /*
2867 * Flush any pending output to the terminal.
2868 */
2869 if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
2870 return EOF;
2871 /*
2872 * Delete any incompletely entered line.
2873 */
2874 if(gl_erase_line(gl))
2875 return EOF;
2876 /*
2877 * Reset the line input parameters and display the prompt, if any.
2878 */
2879 if(gl_present_line(gl, prompt, NULL, 0))
2880 return EOF;
2881 /*
2882 * Read one character.
2883 */
2884 if(gl_read_terminal(gl, 1, &c) == 0) {
2885 /*
2886 * In this mode, count each character as being a new key-sequence.
2887 */
2888 gl->keyseq_count++;
2889 /*
2890 * Delete the character that was read, from the key-press buffer.
2891 */
2892 gl_discard_chars(gl, gl->nread);
2893 /*
2894 * Convert carriage returns to newlines.
2895 */
2896 if(c == '\r')
2897 c = '\n';
2898 /*
2899 * If the user just hit return, subsitute the default character.
2900 */
2901 if(c == '\n')
2902 c = defchar;
2903 /*
2904 * Display the entered character to the right of the prompt.
2905 */
2906 if(c!='\n') {
2907 if(gl_end_of_line(gl, 1, NULL)==0)
2908 gl_print_char(gl, c, ' ');
2909 };
2910 /*
2911 * Record the return character, and mark the call as successful.
2912 */
2913 retval = c;
2914 gl_record_status(gl, GLR_NEWLINE, 0);
2915 /*
2916 * Was a signal caught whose disposition is to cause the current input
2917 * line to be returned? If so return a newline character.
2918 */
2919 } else if(gl->endline) {
2920 retval = '\n';
2921 gl_record_status(gl, GLR_NEWLINE, 0);
2922 } else {
2923 retval = EOF;
2924 };
2925 /*
2926 * Start a new line.
2927 */
2928 if(gl_start_newline(gl, 1))
2929 return EOF;
2930 /*
2931 * Attempt to flush any pending output.
2932 */
2933 (void) gl_flush_output(gl);
2934 /*
2935 * Return either the character that was read, or EOF if an error occurred.
2936 */
2937 return retval;
2938 }
2939
2940 /*.......................................................................
2941 * Add a character to the line buffer at the current cursor position,
2942 * inserting or overwriting according the current mode.
2943 *
2944 * Input:
2945 * gl GetLine * The resource object of this library.
2946 * c char The character to be added.
2947 * Output:
2948 * return int 0 - OK.
2949 * 1 - Insufficient room.
2950 */
gl_add_char_to_line(GetLine * gl,char c)2951 static int gl_add_char_to_line(GetLine *gl, char c)
2952 {
2953 /*
2954 * Keep a record of the current cursor position.
2955 */
2956 int buff_curpos = gl->buff_curpos;
2957 int term_curpos = gl->term_curpos;
2958 /*
2959 * Work out the displayed width of the new character.
2960 */
2961 int width = gl_displayed_char_width(gl, c, term_curpos);
2962 /*
2963 * If we are in insert mode, or at the end of the line,
2964 * check that we can accomodate a new character in the buffer.
2965 * If not, simply return, leaving it up to the calling program
2966 * to check for the absence of a newline character.
2967 */
2968 if((gl->insert || buff_curpos >= gl->ntotal) && gl->ntotal >= gl->linelen)
2969 return 0;
2970 /*
2971 * Are we adding characters to the line (ie. inserting or appending)?
2972 */
2973 if(gl->insert || buff_curpos >= gl->ntotal) {
2974 /*
2975 * If inserting, make room for the new character.
2976 */
2977 if(buff_curpos < gl->ntotal)
2978 gl_make_gap_in_buffer(gl, buff_curpos, 1);
2979 /*
2980 * Copy the character into the buffer.
2981 */
2982 gl_buffer_char(gl, c, buff_curpos);
2983 gl->buff_curpos++;
2984 /*
2985 * Redraw the line from the cursor position to the end of the line,
2986 * and move the cursor to just after the added character.
2987 */
2988 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
2989 gl_set_term_curpos(gl, term_curpos + width))
2990 return 1;
2991 /*
2992 * Are we overwriting an existing character?
2993 */
2994 } else {
2995 /*
2996 * Get the width of the character being overwritten.
2997 */
2998 int old_width = gl_displayed_char_width(gl, gl->line[buff_curpos],
2999 term_curpos);
3000 /*
3001 * Overwrite the character in the buffer.
3002 */
3003 gl_buffer_char(gl, c, buff_curpos);
3004 /*
3005 * If we are replacing with a narrower character, we need to
3006 * redraw the terminal string to the end of the line, then
3007 * overwrite the trailing old_width - width characters
3008 * with spaces.
3009 */
3010 if(old_width > width) {
3011 if(gl_print_string(gl, gl->line + buff_curpos, '\0'))
3012 return 1;
3013 /*
3014 * Clear to the end of the terminal.
3015 */
3016 if(gl_truncate_display(gl))
3017 return 1;
3018 /*
3019 * Move the cursor to the end of the new character.
3020 */
3021 if(gl_set_term_curpos(gl, term_curpos + width))
3022 return 1;
3023 gl->buff_curpos++;
3024 /*
3025 * If we are replacing with a wider character, then we will be
3026 * inserting new characters, and thus extending the line.
3027 */
3028 } else if(width > old_width) {
3029 /*
3030 * Redraw the line from the cursor position to the end of the line,
3031 * and move the cursor to just after the added character.
3032 */
3033 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
3034 gl_set_term_curpos(gl, term_curpos + width))
3035 return 1;
3036 gl->buff_curpos++;
3037 /*
3038 * The original and replacement characters have the same width,
3039 * so simply overwrite.
3040 */
3041 } else {
3042 /*
3043 * Copy the character into the buffer.
3044 */
3045 gl_buffer_char(gl, c, buff_curpos);
3046 gl->buff_curpos++;
3047 /*
3048 * Overwrite the original character.
3049 */
3050 if(gl_print_char(gl, c, gl->line[gl->buff_curpos]))
3051 return 1;
3052 };
3053 };
3054 return 0;
3055 }
3056
3057 /*.......................................................................
3058 * Insert/append a string to the line buffer and terminal at the current
3059 * cursor position.
3060 *
3061 * Input:
3062 * gl GetLine * The resource object of this library.
3063 * s char * The string to be added.
3064 * Output:
3065 * return int 0 - OK.
3066 * 1 - Insufficient room.
3067 */
gl_add_string_to_line(GetLine * gl,const char * s)3068 static int gl_add_string_to_line(GetLine *gl, const char *s)
3069 {
3070 int buff_slen; /* The length of the string being added to line[] */
3071 int term_slen; /* The length of the string being written to the terminal */
3072 int buff_curpos; /* The original value of gl->buff_curpos */
3073 int term_curpos; /* The original value of gl->term_curpos */
3074 /*
3075 * Keep a record of the current cursor position.
3076 */
3077 buff_curpos = gl->buff_curpos;
3078 term_curpos = gl->term_curpos;
3079 /*
3080 * How long is the string to be added?
3081 */
3082 buff_slen = strlen(s);
3083 term_slen = gl_displayed_string_width(gl, s, buff_slen, term_curpos);
3084 /*
3085 * Check that we can accomodate the string in the buffer.
3086 * If not, simply return, leaving it up to the calling program
3087 * to check for the absence of a newline character.
3088 */
3089 if(gl->ntotal + buff_slen > gl->linelen)
3090 return 0;
3091 /*
3092 * Move the characters that follow the cursor in the buffer by
3093 * buff_slen characters to the right.
3094 */
3095 if(gl->ntotal > gl->buff_curpos)
3096 gl_make_gap_in_buffer(gl, gl->buff_curpos, buff_slen);
3097 /*
3098 * Copy the string into the buffer.
3099 */
3100 gl_buffer_string(gl, s, buff_slen, gl->buff_curpos);
3101 gl->buff_curpos += buff_slen;
3102 /*
3103 * Write the modified part of the line to the terminal, then move
3104 * the terminal cursor to the end of the displayed input string.
3105 */
3106 if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
3107 gl_set_term_curpos(gl, term_curpos + term_slen))
3108 return 1;
3109 return 0;
3110 }
3111
3112 /*.......................................................................
3113 * Read a single character from the terminal.
3114 *
3115 * Input:
3116 * gl GetLine * The resource object of this library.
3117 * keep int If true, the returned character will be kept in
3118 * the input buffer, for potential replays. It should
3119 * subsequently be removed from the buffer when the
3120 * key sequence that it belongs to has been fully
3121 * processed, by calling gl_discard_chars().
3122 * Input/Output:
3123 * c char * The character that is read, is assigned to *c.
3124 * Output:
3125 * return int 0 - OK.
3126 * 1 - Either an I/O error occurred, or a signal was
3127 * caught who's disposition is to abort gl_get_line()
3128 * or to have gl_get_line() return the current line
3129 * as though the user had pressed return. In the
3130 * latter case gl->endline will be non-zero.
3131 */
gl_read_terminal(GetLine * gl,int keep,char * c)3132 static int gl_read_terminal(GetLine *gl, int keep, char *c)
3133 {
3134 /*
3135 * Before waiting for a new character to be input, flush unwritten
3136 * characters to the terminal.
3137 */
3138 if(gl_flush_output(gl))
3139 return 1;
3140 /*
3141 * Record the fact that we are about to read from the terminal.
3142 */
3143 gl->pending_io = GLP_READ;
3144 /*
3145 * If there is already an unread character in the buffer,
3146 * return it.
3147 */
3148 if(gl->nread < gl->nbuf) {
3149 *c = gl->keybuf[gl->nread];
3150 /*
3151 * Retain the character in the key buffer, but mark it as having been read?
3152 */
3153 if(keep) {
3154 gl->nread++;
3155 /*
3156 * Completely remove the character from the key buffer?
3157 */
3158 } else {
3159 memmove(gl->keybuf + gl->nread, gl->keybuf + gl->nread + 1,
3160 gl->nbuf - gl->nread - 1);
3161 };
3162 return 0;
3163 };
3164 /*
3165 * Make sure that there is space in the key buffer for one more character.
3166 * This should always be true if gl_interpret_char() is called for each
3167 * new character added, since it will clear the buffer once it has recognized
3168 * or rejected a key sequence.
3169 */
3170 if(gl->nbuf + 1 > GL_KEY_MAX) {
3171 gl_print_info(gl, "gl_read_terminal: Buffer overflow avoided.",
3172 GL_END_INFO);
3173 errno = EIO;
3174 return 1;
3175 };
3176 /*
3177 * Read one character from the terminal.
3178 */
3179 switch(gl_read_input(gl, c)) {
3180 case GL_READ_OK:
3181 break;
3182 case GL_READ_BLOCKED:
3183 gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
3184 return 1;
3185 break;
3186 default:
3187 return 1;
3188 break;
3189 };
3190 /*
3191 * Append the character to the key buffer?
3192 */
3193 if(keep) {
3194 gl->keybuf[gl->nbuf] = *c;
3195 gl->nread = ++gl->nbuf;
3196 };
3197 return 0;
3198 }
3199
3200 /*.......................................................................
3201 * Read one or more keypresses from the terminal of an input stream.
3202 *
3203 * Input:
3204 * gl GetLine * The resource object of this module.
3205 * c char * The character that was read is assigned to *c.
3206 * Output:
3207 * return GlReadStatus The completion status of the read operation.
3208 */
gl_read_input(GetLine * gl,char * c)3209 static GlReadStatus gl_read_input(GetLine *gl, char *c)
3210 {
3211 /*
3212 * We may have to repeat the read if window change signals are received.
3213 */
3214 for(;;) {
3215 /*
3216 * Which file descriptor should we read from? Mark this volatile, so
3217 * that siglongjmp() can't clobber it.
3218 */
3219 volatile int fd = gl->file_fp ? fileno(gl->file_fp) : gl->input_fd;
3220 /*
3221 * If the endline flag becomes set, don't wait for another character.
3222 */
3223 if(gl->endline)
3224 return GL_READ_ERROR;
3225 /*
3226 * Since the code in this function can block, trap signals.
3227 */
3228 if(sigsetjmp(gl_setjmp_buffer, 1)==0) {
3229 /*
3230 * Handle the different I/O modes.
3231 */
3232 switch(gl->io_mode) {
3233 /*
3234 * In normal I/O mode, we call the event handler before attempting
3235 * to read, since read() blocks.
3236 */
3237 case GL_NORMAL_MODE:
3238 if(gl_event_handler(gl, fd))
3239 return GL_READ_ERROR;
3240 return gl_read_unmasked(gl, fd, c); /* Read one character */
3241 break;
3242 /*
3243 * In non-blocking server I/O mode, we attempt to read a character,
3244 * and only if this fails, call the event handler to wait for a any
3245 * user-configured timeout and any other user-configured events. In
3246 * addition, we turn off the fcntl() non-blocking flag when reading
3247 * from the terminal, to work around a bug in Solaris. We can do this
3248 * without causing the read() to block, because when in non-blocking
3249 * server-I/O mode, gl_raw_io() sets the VMIN terminal attribute to 0,
3250 * which tells the terminal driver to return immediately if no
3251 * characters are available to be read.
3252 */
3253 case GL_SERVER_MODE:
3254 {
3255 GlReadStatus status; /* The return status */
3256 if(isatty(fd)) /* If we reading from a terminal, */
3257 gl_blocking_io(gl, fd); /* switch to blocking I/O */
3258 status = gl_read_unmasked(gl, fd, c); /* Try reading */
3259 if(status == GL_READ_BLOCKED) { /* Nothing readable yet */
3260 if(gl_event_handler(gl, fd)) /* Wait for input */
3261 status = GL_READ_ERROR;
3262 else
3263 status = gl_read_unmasked(gl, fd, c); /* Try reading again */
3264 };
3265 gl_nonblocking_io(gl, fd); /* Restore non-blocking I/O */
3266 return status;
3267 };
3268 break;
3269 };
3270 };
3271 /*
3272 * To get here, one of the signals that we are trapping must have
3273 * been received. Note that by using sigsetjmp() instead of setjmp()
3274 * the signal mask that was blocking these signals will have been
3275 * reinstated, so we can be sure that no more of these signals will
3276 * be received until we explicitly unblock them again.
3277 *
3278 * First, if non-blocking I/O was temporarily disabled, reinstate it.
3279 */
3280 if(gl->io_mode == GL_SERVER_MODE)
3281 gl_nonblocking_io(gl, fd);
3282 /*
3283 * Now respond to the signal that was caught.
3284 */
3285 if(gl_check_caught_signal(gl))
3286 return GL_READ_ERROR;
3287 };
3288 }
3289
3290 /*.......................................................................
3291 * This is a private function of gl_read_input(), which unblocks signals
3292 * temporarily while it reads a single character from the specified file
3293 * descriptor.
3294 *
3295 * Input:
3296 * gl GetLine * The resource object of this module.
3297 * fd int The file descriptor to read from.
3298 * c char * The character that was read is assigned to *c.
3299 * Output:
3300 * return GlReadStatus The completion status of the read.
3301 */
gl_read_unmasked(GetLine * gl,int fd,char * c)3302 static int gl_read_unmasked(GetLine *gl, int fd, char *c)
3303 {
3304 int nread; /* The return value of read() */
3305 /*
3306 * Unblock the signals that we are trapping, while waiting for I/O.
3307 */
3308 gl_catch_signals(gl);
3309 /*
3310 * Attempt to read one character from the terminal, restarting the read
3311 * if any signals that we aren't trapping, are received.
3312 */
3313 do {
3314 errno = 0;
3315 nread = read(fd, c, 1);
3316 } while(nread < 0 && errno==EINTR);
3317 /*
3318 * Block all of the signals that we are trapping.
3319 */
3320 gl_mask_signals(gl, NULL);
3321 /*
3322 * Check the completion status of the read.
3323 */
3324 switch(nread) {
3325 case 1:
3326 return GL_READ_OK;
3327 case 0:
3328 return (errno != 0 || isatty(fd)) ? GL_READ_BLOCKED : GL_READ_EOF;
3329 default:
3330 return GL_READ_ERROR;
3331 };
3332 }
3333
3334 /*.......................................................................
3335 * Remove a specified number of characters from the start of the
3336 * key-press lookahead buffer, gl->keybuf[], and arrange for the next
3337 * read to start from the character at the start of the shifted buffer.
3338 *
3339 * Input:
3340 * gl GetLine * The resource object of this module.
3341 * nused int The number of characters to discard from the start
3342 * of the buffer.
3343 */
gl_discard_chars(GetLine * gl,int nused)3344 static void gl_discard_chars(GetLine *gl, int nused)
3345 {
3346 int nkeep = gl->nbuf - nused;
3347 if(nkeep > 0) {
3348 memmove(gl->keybuf, gl->keybuf + nused, nkeep);
3349 gl->nbuf = nkeep;
3350 gl->nread = 0;
3351 } else {
3352 gl->nbuf = gl->nread = 0;
3353 };
3354 }
3355
3356 /*.......................................................................
3357 * This function is called to handle signals caught between calls to
3358 * sigsetjmp() and siglongjmp().
3359 *
3360 * Input:
3361 * gl GetLine * The resource object of this library.
3362 * Output:
3363 * return int 0 - Signal handled internally.
3364 * 1 - Signal requires gl_get_line() to abort.
3365 */
gl_check_caught_signal(GetLine * gl)3366 static int gl_check_caught_signal(GetLine *gl)
3367 {
3368 GlSignalNode *sig; /* The signal disposition */
3369 SigAction keep_action; /* The signal disposition of tecla signal handlers */
3370 unsigned flags; /* The signal processing flags to use */
3371 int signo; /* The signal to be handled */
3372 /*
3373 * Was no signal caught?
3374 */
3375 if(gl_pending_signal == -1)
3376 return 0;
3377 /*
3378 * Get the signal to be handled.
3379 */
3380 signo = gl_pending_signal;
3381 /*
3382 * Mark the signal as handled. Note that at this point, all of
3383 * the signals that we are trapping are blocked from delivery.
3384 */
3385 gl_pending_signal = -1;
3386 /*
3387 * Record the signal that was caught, so that the user can query it later.
3388 */
3389 gl->last_signal = signo;
3390 /*
3391 * In non-blocking server mode, the application is responsible for
3392 * responding to terminal signals, and we don't want gl_get_line()s
3393 * normal signal handling to clash with this, so whenever a signal
3394 * is caught, we arrange for gl_get_line() to abort and requeue the
3395 * signal while signals are still blocked. If the application
3396 * had the signal unblocked when gl_get_line() was called, the signal
3397 * will be delivered again as soon as gl_get_line() restores the
3398 * process signal mask, just before returning to the application.
3399 * Note that the caller of this function should set gl->pending_io
3400 * to the appropriate choice of GLP_READ and GLP_WRITE, before returning.
3401 */
3402 if(gl->io_mode==GL_SERVER_MODE) {
3403 gl_record_status(gl, GLR_SIGNAL, EINTR);
3404 raise(signo);
3405 return 1;
3406 };
3407 /*
3408 * Lookup the requested disposition of this signal.
3409 */
3410 for(sig=gl->sigs; sig && sig->signo != signo; sig=sig->next)
3411 ;
3412 if(!sig)
3413 return 0;
3414 /*
3415 * Get the signal response flags for this signal.
3416 */
3417 flags = sig->flags;
3418 /*
3419 * Did we receive a terminal size signal?
3420 */
3421 #ifdef SIGWINCH
3422 if(signo == SIGWINCH && _gl_update_size(gl))
3423 return 1;
3424 #endif
3425 /*
3426 * Start a fresh line?
3427 */
3428 if(flags & GLS_RESTORE_LINE) {
3429 if(gl_start_newline(gl, 0))
3430 return 1;
3431 };
3432 /*
3433 * Restore terminal settings to how they were before gl_get_line() was
3434 * called?
3435 */
3436 if(flags & GLS_RESTORE_TTY)
3437 gl_restore_terminal_attributes(gl);
3438 /*
3439 * Restore signal handlers to how they were before gl_get_line() was
3440 * called? If this hasn't been requested, only reinstate the signal
3441 * handler of the signal that we are handling.
3442 */
3443 if(flags & GLS_RESTORE_SIG) {
3444 gl_restore_signal_handlers(gl);
3445 gl_unmask_signals(gl, &gl->old_signal_set);
3446 } else {
3447 (void) sigaction(sig->signo, &sig->original, &keep_action);
3448 (void) sigprocmask(SIG_UNBLOCK, &sig->proc_mask, NULL);
3449 };
3450 /*
3451 * Forward the signal to the application's signal handler.
3452 */
3453 if(!(flags & GLS_DONT_FORWARD))
3454 raise(signo);
3455 /*
3456 * Reinstate our signal handlers.
3457 */
3458 if(flags & GLS_RESTORE_SIG) {
3459 gl_mask_signals(gl, NULL);
3460 gl_override_signal_handlers(gl);
3461 } else {
3462 (void) sigaction(sig->signo, &keep_action, NULL);
3463 (void) sigprocmask(SIG_BLOCK, &sig->proc_mask, NULL);
3464 };
3465 /*
3466 * Do we need to reinstate our terminal settings?
3467 */
3468 if(flags & GLS_RESTORE_TTY)
3469 gl_raw_terminal_mode(gl);
3470 /*
3471 * Redraw the line?
3472 */
3473 if(flags & GLS_REDRAW_LINE)
3474 gl_queue_redisplay(gl);
3475 /*
3476 * What next?
3477 */
3478 switch(sig->after) {
3479 case GLS_RETURN:
3480 gl_newline(gl, 1, NULL);
3481 return gl_flush_output(gl);
3482 break;
3483 case GLS_ABORT:
3484 gl_record_status(gl, GLR_SIGNAL, sig->errno_value);
3485 return 1;
3486 break;
3487 case GLS_CONTINUE:
3488 return gl_flush_output(gl);
3489 break;
3490 };
3491 return 0;
3492 }
3493
3494 /*.......................................................................
3495 * Get pertinent terminal control strings and the initial terminal size.
3496 *
3497 * Input:
3498 * gl GetLine * The resource object of this library.
3499 * term char * The type of the terminal.
3500 * Output:
3501 * return int 0 - OK.
3502 * 1 - Error.
3503 */
gl_control_strings(GetLine * gl,const char * term)3504 static int gl_control_strings(GetLine *gl, const char *term)
3505 {
3506 int bad_term = 0; /* True if term is unusable */
3507 /*
3508 * Discard any existing control strings from a previous terminal.
3509 */
3510 gl->left = NULL;
3511 gl->right = NULL;
3512 gl->up = NULL;
3513 gl->down = NULL;
3514 gl->home = NULL;
3515 gl->bol = 0;
3516 gl->clear_eol = NULL;
3517 gl->clear_eod = NULL;
3518 gl->u_arrow = NULL;
3519 gl->d_arrow = NULL;
3520 gl->l_arrow = NULL;
3521 gl->r_arrow = NULL;
3522 gl->sound_bell = NULL;
3523 gl->bold = NULL;
3524 gl->underline = NULL;
3525 gl->standout = NULL;
3526 gl->dim = NULL;
3527 gl->reverse = NULL;
3528 gl->blink = NULL;
3529 gl->text_attr_off = NULL;
3530 gl->nline = 0;
3531 gl->ncolumn = 0;
3532 #ifdef USE_TERMINFO
3533 gl->left_n = NULL;
3534 gl->right_n = NULL;
3535 #endif
3536 /*
3537 * If possible lookup the information in a terminal information
3538 * database.
3539 */
3540 #ifdef USE_TERMINFO
3541 {
3542 int errret;
3543 if(!term || setupterm((char *)term, gl->input_fd, &errret) == ERR) {
3544 bad_term = 1;
3545 } else {
3546 _clr_StringGroup(gl->capmem);
3547 gl->left = gl_tigetstr(gl, "cub1");
3548 gl->right = gl_tigetstr(gl, "cuf1");
3549 gl->up = gl_tigetstr(gl, "cuu1");
3550 gl->down = gl_tigetstr(gl, "cud1");
3551 gl->home = gl_tigetstr(gl, "home");
3552 gl->clear_eol = gl_tigetstr(gl, "el");
3553 gl->clear_eod = gl_tigetstr(gl, "ed");
3554 gl->u_arrow = gl_tigetstr(gl, "kcuu1");
3555 gl->d_arrow = gl_tigetstr(gl, "kcud1");
3556 gl->l_arrow = gl_tigetstr(gl, "kcub1");
3557 gl->r_arrow = gl_tigetstr(gl, "kcuf1");
3558 gl->left_n = gl_tigetstr(gl, "cub");
3559 gl->right_n = gl_tigetstr(gl, "cuf");
3560 gl->sound_bell = gl_tigetstr(gl, "bel");
3561 gl->bold = gl_tigetstr(gl, "bold");
3562 gl->underline = gl_tigetstr(gl, "smul");
3563 gl->standout = gl_tigetstr(gl, "smso");
3564 gl->dim = gl_tigetstr(gl, "dim");
3565 gl->reverse = gl_tigetstr(gl, "rev");
3566 gl->blink = gl_tigetstr(gl, "blink");
3567 gl->text_attr_off = gl_tigetstr(gl, "sgr0");
3568 };
3569 };
3570 #elif defined(USE_TERMCAP)
3571 if(!term || tgetent(gl->tgetent_buf, (char *)term) < 0) {
3572 bad_term = 1;
3573 } else {
3574 char *tgetstr_buf_ptr = gl->tgetstr_buf;
3575 _clr_StringGroup(gl->capmem);
3576 gl->left = gl_tgetstr(gl, "le", &tgetstr_buf_ptr);
3577 gl->right = gl_tgetstr(gl, "nd", &tgetstr_buf_ptr);
3578 gl->up = gl_tgetstr(gl, "up", &tgetstr_buf_ptr);
3579 gl->down = gl_tgetstr(gl, "do", &tgetstr_buf_ptr);
3580 gl->home = gl_tgetstr(gl, "ho", &tgetstr_buf_ptr);
3581 gl->clear_eol = gl_tgetstr(gl, "ce", &tgetstr_buf_ptr);
3582 gl->clear_eod = gl_tgetstr(gl, "cd", &tgetstr_buf_ptr);
3583 gl->u_arrow = gl_tgetstr(gl, "ku", &tgetstr_buf_ptr);
3584 gl->d_arrow = gl_tgetstr(gl, "kd", &tgetstr_buf_ptr);
3585 gl->l_arrow = gl_tgetstr(gl, "kl", &tgetstr_buf_ptr);
3586 gl->r_arrow = gl_tgetstr(gl, "kr", &tgetstr_buf_ptr);
3587 gl->sound_bell = gl_tgetstr(gl, "bl", &tgetstr_buf_ptr);
3588 gl->bold = gl_tgetstr(gl, "md", &tgetstr_buf_ptr);
3589 gl->underline = gl_tgetstr(gl, "us", &tgetstr_buf_ptr);
3590 gl->standout = gl_tgetstr(gl, "so", &tgetstr_buf_ptr);
3591 gl->dim = gl_tgetstr(gl, "mh", &tgetstr_buf_ptr);
3592 gl->reverse = gl_tgetstr(gl, "mr", &tgetstr_buf_ptr);
3593 gl->blink = gl_tgetstr(gl, "mb", &tgetstr_buf_ptr);
3594 gl->text_attr_off = gl_tgetstr(gl, "me", &tgetstr_buf_ptr);
3595 };
3596 #endif
3597 /*
3598 * Report term being unusable.
3599 */
3600 if(bad_term) {
3601 gl_print_info(gl, "Bad terminal type: \"", term ? term : "(null)",
3602 "\". Will assume vt100.", GL_END_INFO);
3603 };
3604 /*
3605 * Fill in missing information with ANSI VT100 strings.
3606 */
3607 if(!gl->left)
3608 gl->left = "\b"; /* ^H */
3609 if(!gl->right)
3610 gl->right = GL_ESC_STR "[C";
3611 if(!gl->up)
3612 gl->up = GL_ESC_STR "[A";
3613 if(!gl->down)
3614 gl->down = "\n";
3615 if(!gl->home)
3616 gl->home = GL_ESC_STR "[H";
3617 if(!gl->bol)
3618 gl->bol = "\r";
3619 if(!gl->clear_eol)
3620 gl->clear_eol = GL_ESC_STR "[K";
3621 if(!gl->clear_eod)
3622 gl->clear_eod = GL_ESC_STR "[J";
3623 if(!gl->u_arrow)
3624 gl->u_arrow = GL_ESC_STR "[A";
3625 if(!gl->d_arrow)
3626 gl->d_arrow = GL_ESC_STR "[B";
3627 if(!gl->l_arrow)
3628 gl->l_arrow = GL_ESC_STR "[D";
3629 if(!gl->r_arrow)
3630 gl->r_arrow = GL_ESC_STR "[C";
3631 if(!gl->sound_bell)
3632 gl->sound_bell = "\a";
3633 if(!gl->bold)
3634 gl->bold = GL_ESC_STR "[1m";
3635 if(!gl->underline)
3636 gl->underline = GL_ESC_STR "[4m";
3637 if(!gl->standout)
3638 gl->standout = GL_ESC_STR "[1;7m";
3639 if(!gl->dim)
3640 gl->dim = ""; /* Not available */
3641 if(!gl->reverse)
3642 gl->reverse = GL_ESC_STR "[7m";
3643 if(!gl->blink)
3644 gl->blink = GL_ESC_STR "[5m";
3645 if(!gl->text_attr_off)
3646 gl->text_attr_off = GL_ESC_STR "[m";
3647 /*
3648 * Find out the current terminal size.
3649 */
3650 (void) _gl_terminal_size(gl, GL_DEF_NCOLUMN, GL_DEF_NLINE, NULL);
3651 return 0;
3652 }
3653
3654 #ifdef USE_TERMINFO
3655 /*.......................................................................
3656 * This is a private function of gl_control_strings() used to look up
3657 * a termninal capability string from the terminfo database and make
3658 * a private copy of it.
3659 *
3660 * Input:
3661 * gl GetLine * The resource object of gl_get_line().
3662 * name const char * The name of the terminfo string to look up.
3663 * Output:
3664 * return const char * The local copy of the capability, or NULL
3665 * if not available.
3666 */
gl_tigetstr(GetLine * gl,const char * name)3667 static const char *gl_tigetstr(GetLine *gl, const char *name)
3668 {
3669 const char *value = tigetstr((char *)name);
3670 if(!value || value == (char *) -1)
3671 return NULL;
3672 return _sg_store_string(gl->capmem, value, 0);
3673 }
3674 #elif defined(USE_TERMCAP)
3675 /*.......................................................................
3676 * This is a private function of gl_control_strings() used to look up
3677 * a termninal capability string from the termcap database and make
3678 * a private copy of it. Note that some emulations of tgetstr(), such
3679 * as that used by Solaris, ignores the buffer pointer that is past to
3680 * it, so we can't assume that a private copy has been made that won't
3681 * be trashed by another call to gl_control_strings() by another
3682 * GetLine object. So we make what may be a redundant private copy
3683 * of the string in gl->capmem.
3684 *
3685 * Input:
3686 * gl GetLine * The resource object of gl_get_line().
3687 * name const char * The name of the terminfo string to look up.
3688 * Input/Output:
3689 * bufptr char ** On input *bufptr points to the location in
3690 * gl->tgetstr_buf at which to record the
3691 * capability string. On output *bufptr is
3692 * incremented over the stored string.
3693 * Output:
3694 * return const char * The local copy of the capability, or NULL
3695 * on error.
3696 */
gl_tgetstr(GetLine * gl,const char * name,char ** bufptr)3697 static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr)
3698 {
3699 const char *value = tgetstr((char *)name, bufptr);
3700 if(!value || value == (char *) -1)
3701 return NULL;
3702 return _sg_store_string(gl->capmem, value, 0);
3703 }
3704 #endif
3705
3706 /*.......................................................................
3707 * This is an action function that implements a user interrupt (eg. ^C).
3708 */
KT_KEY_FN(gl_user_interrupt)3709 static KT_KEY_FN(gl_user_interrupt)
3710 {
3711 raise(SIGINT);
3712 return 1;
3713 }
3714
3715 /*.......................................................................
3716 * This is an action function that implements the abort signal.
3717 */
KT_KEY_FN(gl_abort)3718 static KT_KEY_FN(gl_abort)
3719 {
3720 raise(SIGABRT);
3721 return 1;
3722 }
3723
3724 /*.......................................................................
3725 * This is an action function that sends a suspend signal (eg. ^Z) to the
3726 * the parent process.
3727 */
KT_KEY_FN(gl_suspend)3728 static KT_KEY_FN(gl_suspend)
3729 {
3730 raise(SIGTSTP);
3731 return 0;
3732 }
3733
3734 /*.......................................................................
3735 * This is an action function that halts output to the terminal.
3736 */
KT_KEY_FN(gl_stop_output)3737 static KT_KEY_FN(gl_stop_output)
3738 {
3739 tcflow(gl->output_fd, TCOOFF);
3740 return 0;
3741 }
3742
3743 /*.......................................................................
3744 * This is an action function that resumes halted terminal output.
3745 */
KT_KEY_FN(gl_start_output)3746 static KT_KEY_FN(gl_start_output)
3747 {
3748 tcflow(gl->output_fd, TCOON);
3749 return 0;
3750 }
3751
3752 /*.......................................................................
3753 * This is an action function that allows the next character to be accepted
3754 * without any interpretation as a special character.
3755 */
KT_KEY_FN(gl_literal_next)3756 static KT_KEY_FN(gl_literal_next)
3757 {
3758 char c; /* The character to be added to the line */
3759 int i;
3760 /*
3761 * Get the character to be inserted literally.
3762 */
3763 if(gl_read_terminal(gl, 1, &c))
3764 return 1;
3765 /*
3766 * Add the character to the line 'count' times.
3767 */
3768 for(i=0; i<count; i++)
3769 gl_add_char_to_line(gl, c);
3770 return 0;
3771 }
3772
3773 /*.......................................................................
3774 * Return the width of a tab character at a given position when
3775 * displayed at a given position on the terminal. This is needed
3776 * because the width of tab characters depends on where they are,
3777 * relative to the preceding tab stops.
3778 *
3779 * Input:
3780 * gl GetLine * The resource object of this library.
3781 * term_curpos int The destination terminal location of the character.
3782 * Output:
3783 * return int The number of terminal charaters needed.
3784 */
gl_displayed_tab_width(GetLine * gl,int term_curpos)3785 static int gl_displayed_tab_width(GetLine *gl, int term_curpos)
3786 {
3787 return TAB_WIDTH - ((term_curpos % gl->ncolumn) % TAB_WIDTH);
3788 }
3789
3790 /*.......................................................................
3791 * Return the number of characters needed to display a given character
3792 * on the screen. Tab characters require eight spaces, and control
3793 * characters are represented by a caret followed by the modified
3794 * character.
3795 *
3796 * Input:
3797 * gl GetLine * The resource object of this library.
3798 * c char The character to be displayed.
3799 * term_curpos int The destination terminal location of the character.
3800 * This is needed because the width of tab characters
3801 * depends on where they are, relative to the
3802 * preceding tab stops.
3803 * Output:
3804 * return int The number of terminal charaters needed.
3805 */
gl_displayed_char_width(GetLine * gl,char c,int term_curpos)3806 static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos)
3807 {
3808 if(c=='\t')
3809 return gl_displayed_tab_width(gl, term_curpos);
3810 if(IS_CTRL_CHAR(c))
3811 return 2;
3812 if(!isprint((int)(unsigned char) c))
3813 return gl_octal_width((int)(unsigned char)c) + 1;
3814 return 1;
3815 }
3816
3817
3818 /*.......................................................................
3819 * Work out the length of given string of characters on the terminal.
3820 *
3821 * Input:
3822 * gl GetLine * The resource object of this library.
3823 * string char * The string to be measured.
3824 * nc int The number of characters to be measured, or -1
3825 * to measure the whole string.
3826 * term_curpos int The destination terminal location of the character.
3827 * This is needed because the width of tab characters
3828 * depends on where they are, relative to the
3829 * preceding tab stops.
3830 * Output:
3831 * return int The number of displayed characters.
3832 */
gl_displayed_string_width(GetLine * gl,const char * string,int nc,int term_curpos)3833 static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
3834 int term_curpos)
3835 {
3836 int slen = 0; /* The displayed number of characters */
3837 int i;
3838 /*
3839 * How many characters are to be measured?
3840 */
3841 if(nc < 0)
3842 nc = strlen(string);
3843 /*
3844 * Add up the length of the displayed string.
3845 */
3846 for(i=0; i<nc; i++)
3847 slen += gl_displayed_char_width(gl, string[i], term_curpos + slen);
3848 return slen;
3849 }
3850
3851 /*.......................................................................
3852 * Write a string verbatim to the current terminal or output stream.
3853 *
3854 * Note that when async-signal safety is required, the 'buffered'
3855 * argument must be 0, and n must not be -1.
3856 *
3857 * Input:
3858 * gl GetLine * The resource object of the gl_get_line().
3859 * buffered int If true, used buffered I/O when writing to
3860 * the terminal. Otherwise use async-signal-safe
3861 * unbuffered I/O.
3862 * string const char * The string to be written (this need not be
3863 * '\0' terminated unless n<0).
3864 * n int The number of characters to write from the
3865 * prefix of string[], or -1 to request that
3866 * gl_print_raw_string() use strlen() to figure
3867 * out the length.
3868 * Output:
3869 * return int 0 - OK.
3870 * 1 - Error.
3871 */
gl_print_raw_string(GetLine * gl,int buffered,const char * string,int n)3872 static int gl_print_raw_string(GetLine *gl, int buffered,
3873 const char *string, int n)
3874 {
3875 GlWriteFn *write_fn = buffered ? gl_write_fn : gl->flush_fn;
3876 /*
3877 * Only display output when echoing is turned on.
3878 */
3879 if(gl->echo) {
3880 int ndone = 0; /* The number of characters written so far */
3881 /*
3882 * When using un-buffered I/O, flush pending output first.
3883 */
3884 if(!buffered) {
3885 if(gl_flush_output(gl))
3886 return 1;
3887 };
3888 /*
3889 * If no length has been provided, measure the length of the string.
3890 */
3891 if(n < 0)
3892 n = strlen(string);
3893 /*
3894 * Write the string.
3895 */
3896 if(write_fn(gl, string + ndone, n-ndone) != n)
3897 return 1;
3898 };
3899 return 0;
3900 }
3901
3902 /*.......................................................................
3903 * Output a terminal control sequence. When using terminfo,
3904 * this must be a sequence returned by tgetstr() or tigetstr()
3905 * respectively.
3906 *
3907 * Input:
3908 * gl GetLine * The resource object of this library.
3909 * nline int The number of lines affected by the operation,
3910 * or 1 if not relevant.
3911 * string char * The control sequence to be sent.
3912 * Output:
3913 * return int 0 - OK.
3914 * 1 - Error.
3915 */
gl_print_control_sequence(GetLine * gl,int nline,const char * string)3916 static int gl_print_control_sequence(GetLine *gl, int nline, const char *string)
3917 {
3918 int waserr = 0; /* True if an error occurs */
3919 /*
3920 * Only write characters to the terminal when echoing is enabled.
3921 */
3922 if(gl->echo) {
3923 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
3924 tputs_gl = gl;
3925 errno = 0;
3926 tputs((char *)string, nline, gl_tputs_putchar);
3927 waserr = errno != 0;
3928 #else
3929 waserr = gl_print_raw_string(gl, 1, string, -1);
3930 #endif
3931 };
3932 return waserr;
3933 }
3934
3935 #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
3936 /*.......................................................................
3937 * The following callback function is called by tputs() to output a raw
3938 * control character to the terminal.
3939 */
gl_tputs_putchar(TputsArgType c)3940 static TputsRetType gl_tputs_putchar(TputsArgType c)
3941 {
3942 char ch = c;
3943 #if TPUTS_RETURNS_VALUE
3944 return gl_print_raw_string(tputs_gl, 1, &ch, 1);
3945 #else
3946 (void) gl_print_raw_string(tputs_gl, 1, &ch, 1);
3947 #endif
3948 }
3949 #endif
3950
3951 /*.......................................................................
3952 * Move the terminal cursor n characters to the left or right.
3953 *
3954 * Input:
3955 * gl GetLine * The resource object of this program.
3956 * n int number of positions to the right (> 0) or left (< 0).
3957 * Output:
3958 * return int 0 - OK.
3959 * 1 - Error.
3960 */
gl_terminal_move_cursor(GetLine * gl,int n)3961 static int gl_terminal_move_cursor(GetLine *gl, int n)
3962 {
3963 int cur_row, cur_col; /* The current terminal row and column index of */
3964 /* the cursor wrt the start of the input line. */
3965 int new_row, new_col; /* The target terminal row and column index of */
3966 /* the cursor wrt the start of the input line. */
3967 /*
3968 * Do nothing if the input line isn't currently displayed. In this
3969 * case, the cursor will be moved to the right place when the line
3970 * is next redisplayed.
3971 */
3972 if(!gl->displayed)
3973 return 0;
3974 /*
3975 * How far can we move left?
3976 */
3977 if(gl->term_curpos + n < 0)
3978 n = gl->term_curpos;
3979 /*
3980 * Break down the current and target cursor locations into rows and columns.
3981 */
3982 cur_row = gl->term_curpos / gl->ncolumn;
3983 cur_col = gl->term_curpos % gl->ncolumn;
3984 new_row = (gl->term_curpos + n) / gl->ncolumn;
3985 new_col = (gl->term_curpos + n) % gl->ncolumn;
3986 /*
3987 * Move down to the next line.
3988 */
3989 for(; cur_row < new_row; cur_row++) {
3990 if(gl_print_control_sequence(gl, 1, gl->down))
3991 return 1;
3992 };
3993 /*
3994 * Move up to the previous line.
3995 */
3996 for(; cur_row > new_row; cur_row--) {
3997 if(gl_print_control_sequence(gl, 1, gl->up))
3998 return 1;
3999 };
4000 /*
4001 * Move to the right within the target line?
4002 */
4003 if(cur_col < new_col) {
4004 #ifdef USE_TERMINFO
4005 /*
4006 * Use a parameterized control sequence if it generates less control
4007 * characters (guess based on ANSI terminal termcap entry).
4008 */
4009 if(gl->right_n != NULL && new_col - cur_col > 1) {
4010 if(gl_print_control_sequence(gl, 1, tparm((char *)gl->right_n,
4011 (long)(new_col - cur_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
4012 return 1;
4013 } else
4014 #endif
4015 {
4016 for(; cur_col < new_col; cur_col++) {
4017 if(gl_print_control_sequence(gl, 1, gl->right))
4018 return 1;
4019 };
4020 };
4021 /*
4022 * Move to the left within the target line?
4023 */
4024 } else if(cur_col > new_col) {
4025 #ifdef USE_TERMINFO
4026 /*
4027 * Use a parameterized control sequence if it generates less control
4028 * characters (guess based on ANSI terminal termcap entry).
4029 */
4030 if(gl->left_n != NULL && cur_col - new_col > 3) {
4031 if(gl_print_control_sequence(gl, 1, tparm((char *)gl->left_n,
4032 (long)(cur_col - new_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
4033 return 1;
4034 } else
4035 #endif
4036 {
4037 for(; cur_col > new_col; cur_col--) {
4038 if(gl_print_control_sequence(gl, 1, gl->left))
4039 return 1;
4040 };
4041 };
4042 }
4043 /*
4044 * Update the recorded position of the terminal cursor.
4045 */
4046 gl->term_curpos += n;
4047 return 0;
4048 }
4049
4050 /*.......................................................................
4051 * Write a character to the terminal after expanding tabs and control
4052 * characters to their multi-character representations.
4053 *
4054 * Input:
4055 * gl GetLine * The resource object of this program.
4056 * c char The character to be output.
4057 * pad char Many terminals have the irritating feature that
4058 * when one writes a character in the last column of
4059 * of the terminal, the cursor isn't wrapped to the
4060 * start of the next line until one more character
4061 * is written. Some terminals don't do this, so
4062 * after such a write, we don't know where the
4063 * terminal is unless we output an extra character.
4064 * This argument specifies the character to write.
4065 * If at the end of the input line send '\0' or a
4066 * space, and a space will be written. Otherwise,
4067 * pass the next character in the input line
4068 * following the one being written.
4069 * Output:
4070 * return int 0 - OK.
4071 */
gl_print_char(GetLine * gl,char c,char pad)4072 static int gl_print_char(GetLine *gl, char c, char pad)
4073 {
4074 char string[TAB_WIDTH + 4]; /* A work area for composing compound strings */
4075 int nchar; /* The number of terminal characters */
4076 int i;
4077 /*
4078 * Check for special characters.
4079 */
4080 if(c == '\t') {
4081 /*
4082 * How many spaces do we need to represent a tab at the current terminal
4083 * column?
4084 */
4085 nchar = gl_displayed_tab_width(gl, gl->term_curpos);
4086 /*
4087 * Compose the tab string.
4088 */
4089 for(i=0; i<nchar; i++)
4090 string[i] = ' ';
4091 } else if(IS_CTRL_CHAR(c)) {
4092 string[0] = '^';
4093 string[1] = CTRL_TO_CHAR(c);
4094 nchar = 2;
4095 } else if(!isprint((int)(unsigned char) c)) {
4096 snprintf(string, sizeof(string), "\\%o", (int)(unsigned char)c);
4097 nchar = strlen(string);
4098 } else {
4099 string[0] = c;
4100 nchar = 1;
4101 };
4102 /*
4103 * Terminate the string.
4104 */
4105 string[nchar] = '\0';
4106 /*
4107 * Write the string to the terminal.
4108 */
4109 if(gl_print_raw_string(gl, 1, string, -1))
4110 return 1;
4111 /*
4112 * Except for one exception to be described in a moment, the cursor should
4113 * now have been positioned after the character that was just output.
4114 */
4115 gl->term_curpos += nchar;
4116 /*
4117 * Keep a record of the number of characters in the terminal version
4118 * of the input line.
4119 */
4120 if(gl->term_curpos > gl->term_len)
4121 gl->term_len = gl->term_curpos;
4122 /*
4123 * If the new character ended exactly at the end of a line,
4124 * most terminals won't move the cursor onto the next line until we
4125 * have written a character on the next line, so append an extra
4126 * space then move the cursor back.
4127 */
4128 if(gl->term_curpos % gl->ncolumn == 0) {
4129 int term_curpos = gl->term_curpos;
4130 if(gl_print_char(gl, pad ? pad : ' ', ' ') ||
4131 gl_set_term_curpos(gl, term_curpos))
4132 return 1;
4133 };
4134 return 0;
4135 }
4136
4137 /*.......................................................................
4138 * Write a string to the terminal after expanding tabs and control
4139 * characters to their multi-character representations.
4140 *
4141 * Input:
4142 * gl GetLine * The resource object of this program.
4143 * string char * The string to be output.
4144 * pad char Many terminals have the irritating feature that
4145 * when one writes a character in the last column of
4146 * of the terminal, the cursor isn't wrapped to the
4147 * start of the next line until one more character
4148 * is written. Some terminals don't do this, so
4149 * after such a write, we don't know where the
4150 * terminal is unless we output an extra character.
4151 * This argument specifies the character to write.
4152 * If at the end of the input line send '\0' or a
4153 * space, and a space will be written. Otherwise,
4154 * pass the next character in the input line
4155 * following the one being written.
4156 * Output:
4157 * return int 0 - OK.
4158 */
gl_print_string(GetLine * gl,const char * string,char pad)4159 static int gl_print_string(GetLine *gl, const char *string, char pad)
4160 {
4161 const char *cptr; /* A pointer into string[] */
4162 for(cptr=string; *cptr; cptr++) {
4163 char nextc = cptr[1];
4164 if(gl_print_char(gl, *cptr, nextc ? nextc : pad))
4165 return 1;
4166 };
4167 return 0;
4168 }
4169
4170 /*.......................................................................
4171 * Move the terminal cursor position.
4172 *
4173 * Input:
4174 * gl GetLine * The resource object of this library.
4175 * term_curpos int The destination terminal cursor position.
4176 * Output:
4177 * return int 0 - OK.
4178 * 1 - Error.
4179 */
gl_set_term_curpos(GetLine * gl,int term_curpos)4180 static int gl_set_term_curpos(GetLine *gl, int term_curpos)
4181 {
4182 return gl_terminal_move_cursor(gl, term_curpos - gl->term_curpos);
4183 }
4184
4185 /*.......................................................................
4186 * This is an action function that moves the buffer cursor one character
4187 * left, and updates the terminal cursor to match.
4188 */
KT_KEY_FN(gl_cursor_left)4189 static KT_KEY_FN(gl_cursor_left)
4190 {
4191 return gl_place_cursor(gl, gl->buff_curpos - count);
4192 }
4193
4194 /*.......................................................................
4195 * This is an action function that moves the buffer cursor one character
4196 * right, and updates the terminal cursor to match.
4197 */
KT_KEY_FN(gl_cursor_right)4198 static KT_KEY_FN(gl_cursor_right)
4199 {
4200 return gl_place_cursor(gl, gl->buff_curpos + count);
4201 }
4202
4203 /*.......................................................................
4204 * This is an action function that toggles between overwrite and insert
4205 * mode.
4206 */
KT_KEY_FN(gl_insert_mode)4207 static KT_KEY_FN(gl_insert_mode)
4208 {
4209 gl->insert = !gl->insert;
4210 return 0;
4211 }
4212
4213 /*.......................................................................
4214 * This is an action function which moves the cursor to the beginning of
4215 * the line.
4216 */
KT_KEY_FN(gl_beginning_of_line)4217 static KT_KEY_FN(gl_beginning_of_line)
4218 {
4219 return gl_place_cursor(gl, 0);
4220 }
4221
4222 /*.......................................................................
4223 * This is an action function which moves the cursor to the end of
4224 * the line.
4225 */
KT_KEY_FN(gl_end_of_line)4226 static KT_KEY_FN(gl_end_of_line)
4227 {
4228 return gl_place_cursor(gl, gl->ntotal);
4229 }
4230
4231 /*.......................................................................
4232 * This is an action function which deletes the entire contents of the
4233 * current line.
4234 */
KT_KEY_FN(gl_delete_line)4235 static KT_KEY_FN(gl_delete_line)
4236 {
4237 /*
4238 * If in vi command mode, preserve the current line for potential
4239 * use by vi-undo.
4240 */
4241 gl_save_for_undo(gl);
4242 /*
4243 * Copy the contents of the line to the cut buffer.
4244 */
4245 strlcpy(gl->cutbuf, gl->line, gl->linelen);
4246 /*
4247 * Clear the buffer.
4248 */
4249 gl_truncate_buffer(gl, 0);
4250 /*
4251 * Move the terminal cursor to just after the prompt.
4252 */
4253 if(gl_place_cursor(gl, 0))
4254 return 1;
4255 /*
4256 * Clear from the end of the prompt to the end of the terminal.
4257 */
4258 if(gl_truncate_display(gl))
4259 return 1;
4260 return 0;
4261 }
4262
4263 /*.......................................................................
4264 * This is an action function which deletes all characters between the
4265 * current cursor position and the end of the line.
4266 */
KT_KEY_FN(gl_kill_line)4267 static KT_KEY_FN(gl_kill_line)
4268 {
4269 /*
4270 * If in vi command mode, preserve the current line for potential
4271 * use by vi-undo.
4272 */
4273 gl_save_for_undo(gl);
4274 /*
4275 * Copy the part of the line that is about to be deleted to the cut buffer.
4276 */
4277 strlcpy(gl->cutbuf, gl->line + gl->buff_curpos, gl->linelen);
4278 /*
4279 * Terminate the buffered line at the current cursor position.
4280 */
4281 gl_truncate_buffer(gl, gl->buff_curpos);
4282 /*
4283 * Clear the part of the line that follows the cursor.
4284 */
4285 if(gl_truncate_display(gl))
4286 return 1;
4287 /*
4288 * Explicitly reset the cursor position to allow vi command mode
4289 * constraints on its position to be set.
4290 */
4291 return gl_place_cursor(gl, gl->buff_curpos);
4292 }
4293
4294 /*.......................................................................
4295 * This is an action function which deletes all characters between the
4296 * start of the line and the current cursor position.
4297 */
KT_KEY_FN(gl_backward_kill_line)4298 static KT_KEY_FN(gl_backward_kill_line)
4299 {
4300 /*
4301 * How many characters are to be deleted from before the cursor?
4302 */
4303 int nc = gl->buff_curpos - gl->insert_curpos;
4304 if (!nc)
4305 return 0;
4306 /*
4307 * Move the cursor to the start of the line, or in vi input mode,
4308 * the start of the sub-line at which insertion started, and delete
4309 * up to the old cursor position.
4310 */
4311 return gl_place_cursor(gl, gl->insert_curpos) ||
4312 gl_delete_chars(gl, nc, gl->editor == GL_EMACS_MODE || gl->vi.command);
4313 }
4314
4315 /*.......................................................................
4316 * This is an action function which moves the cursor forward by a word.
4317 */
KT_KEY_FN(gl_forward_word)4318 static KT_KEY_FN(gl_forward_word)
4319 {
4320 return gl_place_cursor(gl, gl_nth_word_end_forward(gl, count) +
4321 (gl->editor==GL_EMACS_MODE));
4322 }
4323
4324 /*.......................................................................
4325 * This is an action function which moves the cursor forward to the start
4326 * of the next word.
4327 */
KT_KEY_FN(gl_forward_to_word)4328 static KT_KEY_FN(gl_forward_to_word)
4329 {
4330 return gl_place_cursor(gl, gl_nth_word_start_forward(gl, count));
4331 }
4332
4333 /*.......................................................................
4334 * This is an action function which moves the cursor backward by a word.
4335 */
KT_KEY_FN(gl_backward_word)4336 static KT_KEY_FN(gl_backward_word)
4337 {
4338 return gl_place_cursor(gl, gl_nth_word_start_backward(gl, count));
4339 }
4340
4341 /*.......................................................................
4342 * Delete one or more characters, starting with the one under the cursor.
4343 *
4344 * Input:
4345 * gl GetLine * The resource object of this library.
4346 * nc int The number of characters to delete.
4347 * cut int If true, copy the characters to the cut buffer.
4348 * Output:
4349 * return int 0 - OK.
4350 * 1 - Error.
4351 */
gl_delete_chars(GetLine * gl,int nc,int cut)4352 static int gl_delete_chars(GetLine *gl, int nc, int cut)
4353 {
4354 /*
4355 * If in vi command mode, preserve the current line for potential
4356 * use by vi-undo.
4357 */
4358 gl_save_for_undo(gl);
4359 /*
4360 * If there are fewer than nc characters following the cursor, limit
4361 * nc to the number available.
4362 */
4363 if(gl->buff_curpos + nc > gl->ntotal)
4364 nc = gl->ntotal - gl->buff_curpos;
4365 /*
4366 * Copy the about to be deleted region to the cut buffer.
4367 */
4368 if(cut) {
4369 memcpy(gl->cutbuf, gl->line + gl->buff_curpos, nc);
4370 gl->cutbuf[nc] = '\0';
4371 }
4372 /*
4373 * Nothing to delete?
4374 */
4375 if(nc <= 0)
4376 return 0;
4377 /*
4378 * In vi overwrite mode, restore any previously overwritten characters
4379 * from the undo buffer.
4380 */
4381 if(gl->editor == GL_VI_MODE && !gl->vi.command && !gl->insert) {
4382 /*
4383 * How many of the characters being deleted can be restored from the
4384 * undo buffer?
4385 */
4386 int nrestore = gl->buff_curpos + nc <= gl->vi.undo.ntotal ?
4387 nc : gl->vi.undo.ntotal - gl->buff_curpos;
4388 /*
4389 * Restore any available characters.
4390 */
4391 if(nrestore > 0) {
4392 gl_buffer_string(gl, gl->vi.undo.line + gl->buff_curpos, nrestore,
4393 gl->buff_curpos);
4394 };
4395 /*
4396 * If their were insufficient characters in the undo buffer, then this
4397 * implies that we are deleting from the end of the line, so we need
4398 * to terminate the line either where the undo buffer ran out, or if
4399 * we are deleting from beyond the end of the undo buffer, at the current
4400 * cursor position.
4401 */
4402 if(nc != nrestore) {
4403 gl_truncate_buffer(gl, (gl->vi.undo.ntotal > gl->buff_curpos) ?
4404 gl->vi.undo.ntotal : gl->buff_curpos);
4405 };
4406 } else {
4407 /*
4408 * Copy the remaining part of the line back over the deleted characters.
4409 */
4410 gl_remove_from_buffer(gl, gl->buff_curpos, nc);
4411 };
4412 /*
4413 * Redraw the remaining characters following the cursor.
4414 */
4415 if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0'))
4416 return 1;
4417 /*
4418 * Clear to the end of the terminal.
4419 */
4420 if(gl_truncate_display(gl))
4421 return 1;
4422 /*
4423 * Place the cursor at the start of where the deletion was performed.
4424 */
4425 return gl_place_cursor(gl, gl->buff_curpos);
4426 }
4427
4428 /*.......................................................................
4429 * This is an action function which deletes character(s) under the
4430 * cursor without moving the cursor.
4431 */
KT_KEY_FN(gl_forward_delete_char)4432 static KT_KEY_FN(gl_forward_delete_char)
4433 {
4434 /*
4435 * Delete 'count' characters.
4436 */
4437 return gl_delete_chars(gl, count, gl->vi.command);
4438 }
4439
4440 /*.......................................................................
4441 * This is an action function which deletes character(s) under the
4442 * cursor and moves the cursor back one character.
4443 */
KT_KEY_FN(gl_backward_delete_char)4444 static KT_KEY_FN(gl_backward_delete_char)
4445 {
4446 /*
4447 * Restrict the deletion count to the number of characters that
4448 * precede the insertion point.
4449 */
4450 if(count > gl->buff_curpos - gl->insert_curpos)
4451 count = gl->buff_curpos - gl->insert_curpos;
4452 /*
4453 * If in vi command mode, preserve the current line for potential
4454 * use by vi-undo.
4455 */
4456 gl_save_for_undo(gl);
4457 return gl_cursor_left(gl, count, NULL) ||
4458 gl_delete_chars(gl, count, gl->vi.command);
4459 }
4460
4461 /*.......................................................................
4462 * Starting from the cursor position delete to the specified column.
4463 */
KT_KEY_FN(gl_delete_to_column)4464 static KT_KEY_FN(gl_delete_to_column)
4465 {
4466 if (--count >= gl->buff_curpos)
4467 return gl_forward_delete_char(gl, count - gl->buff_curpos, NULL);
4468 else
4469 return gl_backward_delete_char(gl, gl->buff_curpos - count, NULL);
4470 }
4471
4472 /*.......................................................................
4473 * Starting from the cursor position delete characters to a matching
4474 * parenthesis.
4475 */
KT_KEY_FN(gl_delete_to_parenthesis)4476 static KT_KEY_FN(gl_delete_to_parenthesis)
4477 {
4478 int curpos = gl_index_of_matching_paren(gl);
4479 if(curpos >= 0) {
4480 gl_save_for_undo(gl);
4481 if(curpos >= gl->buff_curpos)
4482 return gl_forward_delete_char(gl, curpos - gl->buff_curpos + 1, NULL);
4483 else
4484 return gl_backward_delete_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
4485 };
4486 return 0;
4487 }
4488
4489 /*.......................................................................
4490 * This is an action function which deletes from the cursor to the end
4491 * of the word that the cursor is either in or precedes.
4492 */
KT_KEY_FN(gl_forward_delete_word)4493 static KT_KEY_FN(gl_forward_delete_word)
4494 {
4495 /*
4496 * If in vi command mode, preserve the current line for potential
4497 * use by vi-undo.
4498 */
4499 gl_save_for_undo(gl);
4500 /*
4501 * In emacs mode delete to the end of the word. In vi mode delete to the
4502 * start of the net word.
4503 */
4504 if(gl->editor == GL_EMACS_MODE) {
4505 return gl_delete_chars(gl,
4506 gl_nth_word_end_forward(gl,count) - gl->buff_curpos + 1, 1);
4507 } else {
4508 return gl_delete_chars(gl,
4509 gl_nth_word_start_forward(gl,count) - gl->buff_curpos,
4510 gl->vi.command);
4511 };
4512 }
4513
4514 /*.......................................................................
4515 * This is an action function which deletes the word that precedes the
4516 * cursor.
4517 */
KT_KEY_FN(gl_backward_delete_word)4518 static KT_KEY_FN(gl_backward_delete_word)
4519 {
4520 /*
4521 * Keep a record of the current cursor position.
4522 */
4523 int buff_curpos = gl->buff_curpos;
4524 /*
4525 * If in vi command mode, preserve the current line for potential
4526 * use by vi-undo.
4527 */
4528 gl_save_for_undo(gl);
4529 /*
4530 * Move back 'count' words.
4531 */
4532 if(gl_backward_word(gl, count, NULL))
4533 return 1;
4534 /*
4535 * Delete from the new cursor position to the original one.
4536 */
4537 return gl_delete_chars(gl, buff_curpos - gl->buff_curpos,
4538 gl->editor == GL_EMACS_MODE || gl->vi.command);
4539 }
4540
4541 /*.......................................................................
4542 * Searching in a given direction, delete to the count'th
4543 * instance of a specified or queried character, in the input line.
4544 *
4545 * Input:
4546 * gl GetLine * The getline resource object.
4547 * count int The number of times to search.
4548 * c char The character to be searched for, or '\0' if
4549 * the character should be read from the user.
4550 * forward int True if searching forward.
4551 * onto int True if the search should end on top of the
4552 * character, false if the search should stop
4553 * one character before the character in the
4554 * specified search direction.
4555 * change int If true, this function is being called upon
4556 * to do a vi change command, in which case the
4557 * user will be left in insert mode after the
4558 * deletion.
4559 * Output:
4560 * return int 0 - OK.
4561 * 1 - Error.
4562 */
gl_delete_find(GetLine * gl,int count,char c,int forward,int onto,int change)4563 static int gl_delete_find(GetLine *gl, int count, char c, int forward,
4564 int onto, int change)
4565 {
4566 /*
4567 * Search for the character, and abort the deletion if not found.
4568 */
4569 int pos = gl_find_char(gl, count, forward, onto, c);
4570 if(pos < 0)
4571 return 0;
4572 /*
4573 * If in vi command mode, preserve the current line for potential
4574 * use by vi-undo.
4575 */
4576 gl_save_for_undo(gl);
4577 /*
4578 * Allow the cursor to be at the end of the line if this is a change
4579 * command.
4580 */
4581 if(change)
4582 gl->vi.command = 0;
4583 /*
4584 * Delete the appropriate span of characters.
4585 */
4586 if(forward) {
4587 if(gl_delete_chars(gl, pos - gl->buff_curpos + 1, 1))
4588 return 1;
4589 } else {
4590 int buff_curpos = gl->buff_curpos;
4591 if(gl_place_cursor(gl, pos) ||
4592 gl_delete_chars(gl, buff_curpos - gl->buff_curpos, 1))
4593 return 1;
4594 };
4595 /*
4596 * If this is a change operation, switch the insert mode.
4597 */
4598 if(change && gl_vi_insert(gl, 0, NULL))
4599 return 1;
4600 return 0;
4601 }
4602
4603 /*.......................................................................
4604 * This is an action function which deletes forward from the cursor up to and
4605 * including a specified character.
4606 */
KT_KEY_FN(gl_forward_delete_find)4607 static KT_KEY_FN(gl_forward_delete_find)
4608 {
4609 return gl_delete_find(gl, count, '\0', 1, 1, 0);
4610 }
4611
4612 /*.......................................................................
4613 * This is an action function which deletes backward from the cursor back to
4614 * and including a specified character.
4615 */
KT_KEY_FN(gl_backward_delete_find)4616 static KT_KEY_FN(gl_backward_delete_find)
4617 {
4618 return gl_delete_find(gl, count, '\0', 0, 1, 0);
4619 }
4620
4621 /*.......................................................................
4622 * This is an action function which deletes forward from the cursor up to but
4623 * not including a specified character.
4624 */
KT_KEY_FN(gl_forward_delete_to)4625 static KT_KEY_FN(gl_forward_delete_to)
4626 {
4627 return gl_delete_find(gl, count, '\0', 1, 0, 0);
4628 }
4629
4630 /*.......................................................................
4631 * This is an action function which deletes backward from the cursor back to
4632 * but not including a specified character.
4633 */
KT_KEY_FN(gl_backward_delete_to)4634 static KT_KEY_FN(gl_backward_delete_to)
4635 {
4636 return gl_delete_find(gl, count, '\0', 0, 0, 0);
4637 }
4638
4639 /*.......................................................................
4640 * This is an action function which deletes to a character specified by a
4641 * previous search.
4642 */
KT_KEY_FN(gl_delete_refind)4643 static KT_KEY_FN(gl_delete_refind)
4644 {
4645 return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
4646 gl->vi.find_onto, 0);
4647 }
4648
4649 /*.......................................................................
4650 * This is an action function which deletes to a character specified by a
4651 * previous search, but in the opposite direction.
4652 */
KT_KEY_FN(gl_delete_invert_refind)4653 static KT_KEY_FN(gl_delete_invert_refind)
4654 {
4655 return gl_delete_find(gl, count, gl->vi.find_char,
4656 !gl->vi.find_forward, gl->vi.find_onto, 0);
4657 }
4658
4659 /*.......................................................................
4660 * This is an action function which converts the characters in the word
4661 * following the cursor to upper case.
4662 */
KT_KEY_FN(gl_upcase_word)4663 static KT_KEY_FN(gl_upcase_word)
4664 {
4665 /*
4666 * Locate the count'th word ending after the cursor.
4667 */
4668 int last = gl_nth_word_end_forward(gl, count);
4669 /*
4670 * If in vi command mode, preserve the current line for potential
4671 * use by vi-undo.
4672 */
4673 gl_save_for_undo(gl);
4674 /*
4675 * Upcase characters from the current cursor position to 'last'.
4676 */
4677 while(gl->buff_curpos <= last) {
4678 char *cptr = gl->line + gl->buff_curpos;
4679 /*
4680 * Convert the character to upper case?
4681 */
4682 if(islower((int)(unsigned char) *cptr))
4683 gl_buffer_char(gl, toupper((int) *cptr), gl->buff_curpos);
4684 gl->buff_curpos++;
4685 /*
4686 * Write the possibly modified character back. Note that for non-modified
4687 * characters we want to do this as well, so as to advance the cursor.
4688 */
4689 if(gl_print_char(gl, *cptr, cptr[1]))
4690 return 1;
4691 };
4692 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4693 }
4694
4695 /*.......................................................................
4696 * This is an action function which converts the characters in the word
4697 * following the cursor to lower case.
4698 */
KT_KEY_FN(gl_downcase_word)4699 static KT_KEY_FN(gl_downcase_word)
4700 {
4701 /*
4702 * Locate the count'th word ending after the cursor.
4703 */
4704 int last = gl_nth_word_end_forward(gl, count);
4705 /*
4706 * If in vi command mode, preserve the current line for potential
4707 * use by vi-undo.
4708 */
4709 gl_save_for_undo(gl);
4710 /*
4711 * Upcase characters from the current cursor position to 'last'.
4712 */
4713 while(gl->buff_curpos <= last) {
4714 char *cptr = gl->line + gl->buff_curpos;
4715 /*
4716 * Convert the character to upper case?
4717 */
4718 if(isupper((int)(unsigned char) *cptr))
4719 gl_buffer_char(gl, tolower((int) *cptr), gl->buff_curpos);
4720 gl->buff_curpos++;
4721 /*
4722 * Write the possibly modified character back. Note that for non-modified
4723 * characters we want to do this as well, so as to advance the cursor.
4724 */
4725 if(gl_print_char(gl, *cptr, cptr[1]))
4726 return 1;
4727 };
4728 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4729 }
4730
4731 /*.......................................................................
4732 * This is an action function which converts the first character of the
4733 * following word to upper case, in order to capitalize the word, and
4734 * leaves the cursor at the end of the word.
4735 */
KT_KEY_FN(gl_capitalize_word)4736 static KT_KEY_FN(gl_capitalize_word)
4737 {
4738 char *cptr; /* &gl->line[gl->buff_curpos] */
4739 int first; /* True for the first letter of the word */
4740 int i;
4741 /*
4742 * Keep a record of the current insert mode and the cursor position.
4743 */
4744 int insert = gl->insert;
4745 /*
4746 * If in vi command mode, preserve the current line for potential
4747 * use by vi-undo.
4748 */
4749 gl_save_for_undo(gl);
4750 /*
4751 * We want to overwrite the modified word.
4752 */
4753 gl->insert = 0;
4754 /*
4755 * Capitalize 'count' words.
4756 */
4757 for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) {
4758 int pos = gl->buff_curpos;
4759 /*
4760 * If we are not already within a word, skip to the start of the word.
4761 */
4762 for(cptr = gl->line + pos ; pos<gl->ntotal && !gl_is_word_char((int) *cptr);
4763 pos++, cptr++)
4764 ;
4765 /*
4766 * Move the cursor to the new position.
4767 */
4768 if(gl_place_cursor(gl, pos))
4769 return 1;
4770 /*
4771 * While searching for the end of the word, change lower case letters
4772 * to upper case.
4773 */
4774 for(first=1; gl->buff_curpos<gl->ntotal && gl_is_word_char((int) *cptr);
4775 gl->buff_curpos++, cptr++) {
4776 /*
4777 * Convert the character to upper case?
4778 */
4779 if(first) {
4780 if(islower((int)(unsigned char) *cptr))
4781 gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
4782 } else {
4783 if(isupper((int)(unsigned char) *cptr))
4784 gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
4785 };
4786 first = 0;
4787 /*
4788 * Write the possibly modified character back. Note that for non-modified
4789 * characters we want to do this as well, so as to advance the cursor.
4790 */
4791 if(gl_print_char(gl, *cptr, cptr[1]))
4792 return 1;
4793 };
4794 };
4795 /*
4796 * Restore the insertion mode.
4797 */
4798 gl->insert = insert;
4799 return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */
4800 }
4801
4802 /*.......................................................................
4803 * This is an action function which redraws the current line.
4804 */
KT_KEY_FN(gl_redisplay)4805 static KT_KEY_FN(gl_redisplay)
4806 {
4807 /*
4808 * Keep a record of the current cursor position.
4809 */
4810 int buff_curpos = gl->buff_curpos;
4811 /*
4812 * Do nothing if there is no line to be redisplayed.
4813 */
4814 if(gl->endline)
4815 return 0;
4816 /*
4817 * Erase the current input line.
4818 */
4819 if(gl_erase_line(gl))
4820 return 1;
4821 /*
4822 * Display the current prompt.
4823 */
4824 if(gl_display_prompt(gl))
4825 return 1;
4826 /*
4827 * Render the part of the line that the user has typed in so far.
4828 */
4829 if(gl_print_string(gl, gl->line, '\0'))
4830 return 1;
4831 /*
4832 * Restore the cursor position.
4833 */
4834 if(gl_place_cursor(gl, buff_curpos))
4835 return 1;
4836 /*
4837 * Mark the redisplay operation as having been completed.
4838 */
4839 gl->redisplay = 0;
4840 /*
4841 * Flush the redisplayed line to the terminal.
4842 */
4843 return gl_flush_output(gl);
4844 }
4845
4846 /*.......................................................................
4847 * This is an action function which clears the display and redraws the
4848 * input line from the home position.
4849 */
KT_KEY_FN(gl_clear_screen)4850 static KT_KEY_FN(gl_clear_screen)
4851 {
4852 /*
4853 * Home the cursor and clear from there to the end of the display.
4854 */
4855 if(gl_print_control_sequence(gl, gl->nline, gl->home) ||
4856 gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
4857 return 1;
4858 /*
4859 * The input line is no longer displayed.
4860 */
4861 gl_line_erased(gl);
4862 /*
4863 * Arrange for the input line to be redisplayed.
4864 */
4865 gl_queue_redisplay(gl);
4866 return 0;
4867 }
4868
4869 /*.......................................................................
4870 * This is an action function which swaps the character under the cursor
4871 * with the character to the left of the cursor.
4872 */
KT_KEY_FN(gl_transpose_chars)4873 static KT_KEY_FN(gl_transpose_chars)
4874 {
4875 char from[3]; /* The original string of 2 characters */
4876 char swap[3]; /* The swapped string of two characters */
4877 /*
4878 * If we are at the beginning or end of the line, there aren't two
4879 * characters to swap.
4880 */
4881 if(gl->buff_curpos < 1 || gl->buff_curpos >= gl->ntotal)
4882 return 0;
4883 /*
4884 * If in vi command mode, preserve the current line for potential
4885 * use by vi-undo.
4886 */
4887 gl_save_for_undo(gl);
4888 /*
4889 * Get the original and swapped strings of the two characters.
4890 */
4891 from[0] = gl->line[gl->buff_curpos - 1];
4892 from[1] = gl->line[gl->buff_curpos];
4893 from[2] = '\0';
4894 swap[0] = gl->line[gl->buff_curpos];
4895 swap[1] = gl->line[gl->buff_curpos - 1];
4896 swap[2] = '\0';
4897 /*
4898 * Move the cursor to the start of the two characters.
4899 */
4900 if(gl_place_cursor(gl, gl->buff_curpos-1))
4901 return 1;
4902 /*
4903 * Swap the two characters in the buffer.
4904 */
4905 gl_buffer_char(gl, swap[0], gl->buff_curpos);
4906 gl_buffer_char(gl, swap[1], gl->buff_curpos+1);
4907 /*
4908 * If the sum of the displayed width of the two characters
4909 * in their current and final positions is the same, swapping can
4910 * be done by just overwriting with the two swapped characters.
4911 */
4912 if(gl_displayed_string_width(gl, from, -1, gl->term_curpos) ==
4913 gl_displayed_string_width(gl, swap, -1, gl->term_curpos)) {
4914 int insert = gl->insert;
4915 gl->insert = 0;
4916 if(gl_print_char(gl, swap[0], swap[1]) ||
4917 gl_print_char(gl, swap[1], gl->line[gl->buff_curpos+2]))
4918 return 1;
4919 gl->insert = insert;
4920 /*
4921 * If the swapped substring has a different displayed size, we need to
4922 * redraw everything after the first of the characters.
4923 */
4924 } else {
4925 if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0') ||
4926 gl_truncate_display(gl))
4927 return 1;
4928 };
4929 /*
4930 * Advance the cursor to the character after the swapped pair.
4931 */
4932 return gl_place_cursor(gl, gl->buff_curpos + 2);
4933 }
4934
4935 /*.......................................................................
4936 * This is an action function which sets a mark at the current cursor
4937 * location.
4938 */
KT_KEY_FN(gl_set_mark)4939 static KT_KEY_FN(gl_set_mark)
4940 {
4941 gl->buff_mark = gl->buff_curpos;
4942 return 0;
4943 }
4944
4945 /*.......................................................................
4946 * This is an action function which swaps the mark location for the
4947 * cursor location.
4948 */
KT_KEY_FN(gl_exchange_point_and_mark)4949 static KT_KEY_FN(gl_exchange_point_and_mark)
4950 {
4951 /*
4952 * Get the old mark position, and limit to the extent of the input
4953 * line.
4954 */
4955 int old_mark = gl->buff_mark <= gl->ntotal ? gl->buff_mark : gl->ntotal;
4956 /*
4957 * Make the current cursor position the new mark.
4958 */
4959 gl->buff_mark = gl->buff_curpos;
4960 /*
4961 * Move the cursor to the old mark position.
4962 */
4963 return gl_place_cursor(gl, old_mark);
4964 }
4965
4966 /*.......................................................................
4967 * This is an action function which deletes the characters between the
4968 * mark and the cursor, recording them in gl->cutbuf for later pasting.
4969 */
KT_KEY_FN(gl_kill_region)4970 static KT_KEY_FN(gl_kill_region)
4971 {
4972 /*
4973 * If in vi command mode, preserve the current line for potential
4974 * use by vi-undo.
4975 */
4976 gl_save_for_undo(gl);
4977 /*
4978 * Limit the mark to be within the line.
4979 */
4980 if(gl->buff_mark > gl->ntotal)
4981 gl->buff_mark = gl->ntotal;
4982 /*
4983 * If there are no characters between the cursor and the mark, simply clear
4984 * the cut buffer.
4985 */
4986 if(gl->buff_mark == gl->buff_curpos) {
4987 gl->cutbuf[0] = '\0';
4988 return 0;
4989 };
4990 /*
4991 * If the mark is before the cursor, swap the cursor and the mark.
4992 */
4993 if(gl->buff_mark < gl->buff_curpos && gl_exchange_point_and_mark(gl,1,NULL))
4994 return 1;
4995 /*
4996 * Delete the characters.
4997 */
4998 if(gl_delete_chars(gl, gl->buff_mark - gl->buff_curpos, 1))
4999 return 1;
5000 /*
5001 * Make the mark the same as the cursor position.
5002 */
5003 gl->buff_mark = gl->buff_curpos;
5004 return 0;
5005 }
5006
5007 /*.......................................................................
5008 * This is an action function which records the characters between the
5009 * mark and the cursor, in gl->cutbuf for later pasting.
5010 */
KT_KEY_FN(gl_copy_region_as_kill)5011 static KT_KEY_FN(gl_copy_region_as_kill)
5012 {
5013 int ca, cb; /* The indexes of the first and last characters in the region */
5014 int mark; /* The position of the mark */
5015 /*
5016 * Get the position of the mark, limiting it to lie within the line.
5017 */
5018 mark = gl->buff_mark > gl->ntotal ? gl->ntotal : gl->buff_mark;
5019 /*
5020 * If there are no characters between the cursor and the mark, clear
5021 * the cut buffer.
5022 */
5023 if(mark == gl->buff_curpos) {
5024 gl->cutbuf[0] = '\0';
5025 return 0;
5026 };
5027 /*
5028 * Get the line indexes of the first and last characters in the region.
5029 */
5030 if(mark < gl->buff_curpos) {
5031 ca = mark;
5032 cb = gl->buff_curpos - 1;
5033 } else {
5034 ca = gl->buff_curpos;
5035 cb = mark - 1;
5036 };
5037 /*
5038 * Copy the region to the cut buffer.
5039 */
5040 memcpy(gl->cutbuf, gl->line + ca, cb + 1 - ca);
5041 gl->cutbuf[cb + 1 - ca] = '\0';
5042 return 0;
5043 }
5044
5045 /*.......................................................................
5046 * This is an action function which inserts the contents of the cut
5047 * buffer at the current cursor location.
5048 */
KT_KEY_FN(gl_yank)5049 static KT_KEY_FN(gl_yank)
5050 {
5051 int i;
5052 /*
5053 * Set the mark at the current location.
5054 */
5055 gl->buff_mark = gl->buff_curpos;
5056 /*
5057 * Do nothing else if the cut buffer is empty.
5058 */
5059 if(gl->cutbuf[0] == '\0')
5060 return gl_ring_bell(gl, 1, NULL);
5061 /*
5062 * If in vi command mode, preserve the current line for potential
5063 * use by vi-undo.
5064 */
5065 gl_save_for_undo(gl);
5066 /*
5067 * Insert the string count times.
5068 */
5069 for(i=0; i<count; i++) {
5070 if(gl_add_string_to_line(gl, gl->cutbuf))
5071 return 1;
5072 };
5073 /*
5074 * gl_add_string_to_line() leaves the cursor after the last character that
5075 * was pasted, whereas vi leaves the cursor over the last character pasted.
5076 */
5077 if(gl->editor == GL_VI_MODE && gl_cursor_left(gl, 1, NULL))
5078 return 1;
5079 return 0;
5080 }
5081
5082 /*.......................................................................
5083 * This is an action function which inserts the contents of the cut
5084 * buffer one character beyond the current cursor location.
5085 */
KT_KEY_FN(gl_append_yank)5086 static KT_KEY_FN(gl_append_yank)
5087 {
5088 int was_command = gl->vi.command;
5089 int i;
5090 /*
5091 * If the cut buffer is empty, ring the terminal bell.
5092 */
5093 if(gl->cutbuf[0] == '\0')
5094 return gl_ring_bell(gl, 1, NULL);
5095 /*
5096 * Set the mark at the current location + 1.
5097 */
5098 gl->buff_mark = gl->buff_curpos + 1;
5099 /*
5100 * If in vi command mode, preserve the current line for potential
5101 * use by vi-undo.
5102 */
5103 gl_save_for_undo(gl);
5104 /*
5105 * Arrange to paste the text in insert mode after the current character.
5106 */
5107 if(gl_vi_append(gl, 0, NULL))
5108 return 1;
5109 /*
5110 * Insert the string count times.
5111 */
5112 for(i=0; i<count; i++) {
5113 if(gl_add_string_to_line(gl, gl->cutbuf))
5114 return 1;
5115 };
5116 /*
5117 * Switch back to command mode if necessary.
5118 */
5119 if(was_command)
5120 gl_vi_command_mode(gl);
5121 return 0;
5122 }
5123
5124 /*.......................................................................
5125 * Attempt to ask the terminal for its current size. On systems that
5126 * don't support the TIOCWINSZ ioctl() for querying the terminal size,
5127 * the current values of gl->ncolumn and gl->nrow are returned.
5128 *
5129 * Input:
5130 * gl GetLine * The resource object of gl_get_line().
5131 * Input/Output:
5132 * ncolumn int * The number of columns will be assigned to *ncolumn.
5133 * nline int * The number of lines will be assigned to *nline.
5134 */
gl_query_size(GetLine * gl,int * ncolumn,int * nline)5135 static void gl_query_size(GetLine *gl, int *ncolumn, int *nline)
5136 {
5137 #ifdef TIOCGWINSZ
5138 /*
5139 * Query the new terminal window size. Ignore invalid responses.
5140 */
5141 struct winsize size;
5142 if(ioctl(gl->output_fd, TIOCGWINSZ, &size) == 0 &&
5143 size.ws_row > 0 && size.ws_col > 0) {
5144 *ncolumn = size.ws_col;
5145 *nline = size.ws_row;
5146 return;
5147 };
5148 #endif
5149 /*
5150 * Return the existing values.
5151 */
5152 *ncolumn = gl->ncolumn;
5153 *nline = gl->nline;
5154 return;
5155 }
5156
5157 /*.......................................................................
5158 * Query the size of the terminal, and if it has changed, redraw the
5159 * current input line accordingly.
5160 *
5161 * Input:
5162 * gl GetLine * The resource object of gl_get_line().
5163 * Output:
5164 * return int 0 - OK.
5165 * 1 - Error.
5166 */
_gl_update_size(GetLine * gl)5167 static int _gl_update_size(GetLine *gl)
5168 {
5169 int ncolumn, nline; /* The new size of the terminal */
5170 /*
5171 * Query the new terminal window size.
5172 */
5173 gl_query_size(gl, &ncolumn, &nline);
5174 /*
5175 * Update gl and the displayed line to fit the new dimensions.
5176 */
5177 return gl_handle_tty_resize(gl, ncolumn, nline);
5178 }
5179
5180 /*.......................................................................
5181 * Redraw the current input line to account for a change in the terminal
5182 * size. Also install the new size in gl.
5183 *
5184 * Input:
5185 * gl GetLine * The resource object of gl_get_line().
5186 * ncolumn int The new number of columns.
5187 * nline int The new number of lines.
5188 * Output:
5189 * return int 0 - OK.
5190 * 1 - Error.
5191 */
gl_handle_tty_resize(GetLine * gl,int ncolumn,int nline)5192 static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline)
5193 {
5194 /*
5195 * If the input device isn't a terminal, just record the new size.
5196 */
5197 if(!gl->is_term) {
5198 gl->nline = nline;
5199 gl->ncolumn = ncolumn;
5200 /*
5201 * Has the size actually changed?
5202 */
5203 } else if(ncolumn != gl->ncolumn || nline != gl->nline) {
5204 /*
5205 * If we are currently editing a line, erase it.
5206 */
5207 if(gl_erase_line(gl))
5208 return 1;
5209 /*
5210 * Update the recorded window size.
5211 */
5212 gl->nline = nline;
5213 gl->ncolumn = ncolumn;
5214 /*
5215 * Arrange for the input line to be redrawn before the next character
5216 * is read from the terminal.
5217 */
5218 gl_queue_redisplay(gl);
5219 };
5220 return 0;
5221 }
5222
5223 /*.......................................................................
5224 * This is the action function that recalls the previous line in the
5225 * history buffer.
5226 */
KT_KEY_FN(gl_up_history)5227 static KT_KEY_FN(gl_up_history)
5228 {
5229 /*
5230 * In vi mode, switch to command mode, since the user is very
5231 * likely to want to move around newly recalled lines.
5232 */
5233 gl_vi_command_mode(gl);
5234 /*
5235 * Forget any previous recall session.
5236 */
5237 gl->preload_id = 0;
5238 /*
5239 * Record the key sequence number of this search action.
5240 */
5241 gl->last_search = gl->keyseq_count;
5242 /*
5243 * We don't want a search prefix for this function.
5244 */
5245 if(_glh_search_prefix(gl->glh, gl->line, 0)) {
5246 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5247 return 1;
5248 };
5249 /*
5250 * Recall the count'th next older line in the history list. If the first one
5251 * fails we can return since nothing has changed, otherwise we must continue
5252 * and update the line state.
5253 */
5254 if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5255 return 0;
5256 while(--count && _glh_find_backwards(gl->glh, gl->line, gl->linelen+1))
5257 ;
5258 /*
5259 * Accomodate the new contents of gl->line[].
5260 */
5261 gl_update_buffer(gl);
5262 /*
5263 * Arrange to have the cursor placed at the end of the new line.
5264 */
5265 gl->buff_curpos = gl->ntotal;
5266 /*
5267 * Erase and display the new line.
5268 */
5269 gl_queue_redisplay(gl);
5270 return 0;
5271 }
5272
5273 /*.......................................................................
5274 * This is the action function that recalls the next line in the
5275 * history buffer.
5276 */
KT_KEY_FN(gl_down_history)5277 static KT_KEY_FN(gl_down_history)
5278 {
5279 /*
5280 * In vi mode, switch to command mode, since the user is very
5281 * likely to want to move around newly recalled lines.
5282 */
5283 gl_vi_command_mode(gl);
5284 /*
5285 * Record the key sequence number of this search action.
5286 */
5287 gl->last_search = gl->keyseq_count;
5288 /*
5289 * If no search is currently in progress continue a previous recall
5290 * session from a previous entered line if possible.
5291 */
5292 if(_glh_line_id(gl->glh, 0) == 0 && gl->preload_id) {
5293 _glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1);
5294 gl->preload_id = 0;
5295 } else {
5296 /*
5297 * We don't want a search prefix for this function.
5298 */
5299 if(_glh_search_prefix(gl->glh, gl->line, 0)) {
5300 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5301 return 1;
5302 };
5303 /*
5304 * Recall the count'th next newer line in the history list. If the first one
5305 * fails we can return since nothing has changed otherwise we must continue
5306 * and update the line state.
5307 */
5308 if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5309 return 0;
5310 while(--count && _glh_find_forwards(gl->glh, gl->line, gl->linelen+1))
5311 ;
5312 };
5313 /*
5314 * Accomodate the new contents of gl->line[].
5315 */
5316 gl_update_buffer(gl);
5317 /*
5318 * Arrange to have the cursor placed at the end of the new line.
5319 */
5320 gl->buff_curpos = gl->ntotal;
5321 /*
5322 * Erase and display the new line.
5323 */
5324 gl_queue_redisplay(gl);
5325 return 0;
5326 }
5327
5328 /*.......................................................................
5329 * This is the action function that recalls the previous line in the
5330 * history buffer whos prefix matches the characters that currently
5331 * precede the cursor. By setting count=-1, this can be used internally
5332 * to force searching for the prefix used in the last search.
5333 */
KT_KEY_FN(gl_history_search_backward)5334 static KT_KEY_FN(gl_history_search_backward)
5335 {
5336 /*
5337 * In vi mode, switch to command mode, since the user is very
5338 * likely to want to move around newly recalled lines.
5339 */
5340 gl_vi_command_mode(gl);
5341 /*
5342 * Forget any previous recall session.
5343 */
5344 gl->preload_id = 0;
5345 /*
5346 * Record the key sequence number of this search action.
5347 */
5348 gl->last_search = gl->keyseq_count;
5349 /*
5350 * If a prefix search isn't already in progress, replace the search
5351 * prefix to the string that precedes the cursor. In vi command mode
5352 * include the character that is under the cursor in the string. If
5353 * count<0 keep the previous search prefix regardless, so as to force
5354 * a repeat search even if the last command wasn't a history command.
5355 */
5356 if(count >= 0 && !_glh_search_active(gl->glh) &&
5357 _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
5358 (gl->editor==GL_VI_MODE && gl->ntotal>0))) {
5359 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5360 return 1;
5361 };
5362 /*
5363 * Search backwards for a match to the part of the line which precedes the
5364 * cursor.
5365 */
5366 if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5367 return 0;
5368 /*
5369 * Accomodate the new contents of gl->line[].
5370 */
5371 gl_update_buffer(gl);
5372 /*
5373 * Arrange to have the cursor placed at the end of the new line.
5374 */
5375 gl->buff_curpos = gl->ntotal;
5376 /*
5377 * Erase and display the new line.
5378 */
5379 gl_queue_redisplay(gl);
5380 return 0;
5381 }
5382
5383 /*.......................................................................
5384 * This is the action function that recalls the previous line in the
5385 * history buffer who's prefix matches that specified in an earlier call
5386 * to gl_history_search_backward() or gl_history_search_forward().
5387 */
KT_KEY_FN(gl_history_re_search_backward)5388 static KT_KEY_FN(gl_history_re_search_backward)
5389 {
5390 return gl_history_search_backward(gl, -1, NULL);
5391 }
5392
5393 /*.......................................................................
5394 * This is the action function that recalls the next line in the
5395 * history buffer who's prefix matches that specified in the earlier call
5396 * to gl_history_search_backward) which started the history search.
5397 * By setting count=-1, this can be used internally to force searching
5398 * for the prefix used in the last search.
5399 */
KT_KEY_FN(gl_history_search_forward)5400 static KT_KEY_FN(gl_history_search_forward)
5401 {
5402 /*
5403 * In vi mode, switch to command mode, since the user is very
5404 * likely to want to move around newly recalled lines.
5405 */
5406 gl_vi_command_mode(gl);
5407 /*
5408 * Record the key sequence number of this search action.
5409 */
5410 gl->last_search = gl->keyseq_count;
5411 /*
5412 * If a prefix search isn't already in progress, replace the search
5413 * prefix to the string that precedes the cursor. In vi command mode
5414 * include the character that is under the cursor in the string. If
5415 * count<0 keep the previous search prefix regardless, so as to force
5416 * a repeat search even if the last command wasn't a history command.
5417 */
5418 if(count >= 0 && !_glh_search_active(gl->glh) &&
5419 _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
5420 (gl->editor==GL_VI_MODE && gl->ntotal>0))) {
5421 _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
5422 return 1;
5423 };
5424 /*
5425 * Search forwards for the next matching line.
5426 */
5427 if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
5428 return 0;
5429 /*
5430 * Accomodate the new contents of gl->line[].
5431 */
5432 gl_update_buffer(gl);
5433 /*
5434 * Arrange for the cursor to be placed at the end of the new line.
5435 */
5436 gl->buff_curpos = gl->ntotal;
5437 /*
5438 * Erase and display the new line.
5439 */
5440 gl_queue_redisplay(gl);
5441 return 0;
5442 }
5443
5444 /*.......................................................................
5445 * This is the action function that recalls the next line in the
5446 * history buffer who's prefix matches that specified in an earlier call
5447 * to gl_history_search_backward() or gl_history_search_forward().
5448 */
KT_KEY_FN(gl_history_re_search_forward)5449 static KT_KEY_FN(gl_history_re_search_forward)
5450 {
5451 return gl_history_search_forward(gl, -1, NULL);
5452 }
5453
5454 #ifdef HIDE_FILE_SYSTEM
5455 /*.......................................................................
5456 * The following function is used as the default completion handler when
5457 * the filesystem is to be hidden. It simply reports no completions.
5458 */
CPL_MATCH_FN(gl_no_completions)5459 static CPL_MATCH_FN(gl_no_completions)
5460 {
5461 return 0;
5462 }
5463 #endif
5464
5465 /*.......................................................................
5466 * This is the tab completion function that completes the filename that
5467 * precedes the cursor position. Its callback data argument must be a
5468 * pointer to a GlCplCallback containing the completion callback function
5469 * and its callback data, or NULL to use the builtin filename completer.
5470 */
KT_KEY_FN(gl_complete_word)5471 static KT_KEY_FN(gl_complete_word)
5472 {
5473 CplMatches *matches; /* The possible completions */
5474 int suffix_len; /* The length of the completion extension */
5475 int cont_len; /* The length of any continuation suffix */
5476 int nextra; /* The number of characters being added to the */
5477 /* total length of the line. */
5478 int buff_pos; /* The buffer index at which the completion is */
5479 /* to be inserted. */
5480 int waserr = 0; /* True after errors */
5481 /*
5482 * Get the container of the completion callback and its callback data.
5483 */
5484 GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
5485 /*
5486 * In vi command mode, switch to append mode so that the character under
5487 * the cursor is included in the completion (otherwise people can't
5488 * complete at the end of the line).
5489 */
5490 if(gl->vi.command && gl_vi_append(gl, 0, NULL))
5491 return 1;
5492 /*
5493 * Get the cursor position at which the completion is to be inserted.
5494 */
5495 buff_pos = gl->buff_curpos;
5496 /*
5497 * Perform the completion.
5498 */
5499 matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos, cb->data,
5500 cb->fn);
5501 /*
5502 * No matching completions?
5503 */
5504 if(!matches) {
5505 waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
5506 /*
5507 * Are there any completions?
5508 */
5509 } else if(matches->nmatch >= 1) {
5510 /*
5511 * If there any ambiguous matches, report them, starting on a new line.
5512 */
5513 if(matches->nmatch > 1 && gl->echo) {
5514 if(_gl_normal_io(gl) ||
5515 _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
5516 waserr = 1;
5517 };
5518 /*
5519 * Get the length of the suffix and any continuation suffix to add to it.
5520 */
5521 suffix_len = strlen(matches->suffix);
5522 cont_len = strlen(matches->cont_suffix);
5523 /*
5524 * If there is an unambiguous match, and the continuation suffix ends in
5525 * a newline, strip that newline and arrange to have getline return
5526 * after this action function returns.
5527 */
5528 if(matches->nmatch==1 && cont_len > 0 &&
5529 matches->cont_suffix[cont_len - 1] == '\n') {
5530 cont_len--;
5531 if(gl_newline(gl, 1, NULL))
5532 waserr = 1;
5533 };
5534 /*
5535 * Work out the number of characters that are to be added.
5536 */
5537 nextra = suffix_len + cont_len;
5538 /*
5539 * Is there anything to be added?
5540 */
5541 if(!waserr && nextra) {
5542 /*
5543 * Will there be space for the expansion in the line buffer?
5544 */
5545 if(gl->ntotal + nextra < gl->linelen) {
5546 /*
5547 * Make room to insert the filename extension.
5548 */
5549 gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
5550 /*
5551 * Insert the filename extension.
5552 */
5553 gl_buffer_string(gl, matches->suffix, suffix_len, gl->buff_curpos);
5554 /*
5555 * Add the terminating characters.
5556 */
5557 gl_buffer_string(gl, matches->cont_suffix, cont_len,
5558 gl->buff_curpos + suffix_len);
5559 /*
5560 * Place the cursor position at the end of the completion.
5561 */
5562 gl->buff_curpos += nextra;
5563 /*
5564 * If we don't have to redisplay the whole line, redisplay the part
5565 * of the line which follows the original cursor position, and place
5566 * the cursor at the end of the completion.
5567 */
5568 if(gl->displayed) {
5569 if(gl_truncate_display(gl) ||
5570 gl_print_string(gl, gl->line + buff_pos, '\0') ||
5571 gl_place_cursor(gl, gl->buff_curpos))
5572 waserr = 1;
5573 };
5574 } else {
5575 (void) gl_print_info(gl,
5576 "Insufficient room in line for file completion.",
5577 GL_END_INFO);
5578 waserr = 1;
5579 };
5580 };
5581 };
5582 /*
5583 * If any output had to be written to the terminal, then editing will
5584 * have been suspended, make sure that we are back in raw line editing
5585 * mode before returning.
5586 */
5587 if(_gl_raw_io(gl, 1))
5588 waserr = 1;
5589 return 0;
5590 }
5591
5592 #ifndef HIDE_FILE_SYSTEM
5593 /*.......................................................................
5594 * This is the function that expands the filename that precedes the
5595 * cursor position. It expands ~user/ expressions, $envvar expressions,
5596 * and wildcards.
5597 */
KT_KEY_FN(gl_expand_filename)5598 static KT_KEY_FN(gl_expand_filename)
5599 {
5600 char *start_path; /* The pointer to the start of the pathname in */
5601 /* gl->line[]. */
5602 FileExpansion *result; /* The results of the filename expansion */
5603 int pathlen; /* The length of the pathname being expanded */
5604 int length; /* The number of characters needed to display the */
5605 /* expanded files. */
5606 int nextra; /* The number of characters to be added */
5607 int i,j;
5608 /*
5609 * In vi command mode, switch to append mode so that the character under
5610 * the cursor is included in the completion (otherwise people can't
5611 * complete at the end of the line).
5612 */
5613 if(gl->vi.command && gl_vi_append(gl, 0, NULL))
5614 return 1;
5615 /*
5616 * Locate the start of the filename that precedes the cursor position.
5617 */
5618 start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
5619 if(!start_path)
5620 return 1;
5621 /*
5622 * Get the length of the string that is to be expanded.
5623 */
5624 pathlen = gl->buff_curpos - (start_path - gl->line);
5625 /*
5626 * Attempt to expand it.
5627 */
5628 result = ef_expand_file(gl->ef, start_path, pathlen);
5629 /*
5630 * If there was an error, report the error on a new line.
5631 */
5632 if(!result)
5633 return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
5634 /*
5635 * If no files matched, report this as well.
5636 */
5637 if(result->nfile == 0 || !result->exists)
5638 return gl_print_info(gl, "No files match.", GL_END_INFO);
5639 /*
5640 * If in vi command mode, preserve the current line for potential use by
5641 * vi-undo.
5642 */
5643 gl_save_for_undo(gl);
5644 /*
5645 * Work out how much space we will need to display all of the matching
5646 * filenames, taking account of the space that we need to place between
5647 * them, and the number of additional '\' characters needed to escape
5648 * spaces, tabs and backslash characters in the individual filenames.
5649 */
5650 length = 0;
5651 for(i=0; i<result->nfile; i++) {
5652 char *file = result->files[i];
5653 while(*file) {
5654 int c = *file++;
5655 switch(c) {
5656 case ' ': case '\t': case '\\': case '*': case '?': case '[':
5657 length++; /* Count extra backslash characters */
5658 };
5659 length++; /* Count the character itself */
5660 };
5661 length++; /* Count the space that follows each filename */
5662 };
5663 /*
5664 * Work out the number of characters that are to be added.
5665 */
5666 nextra = length - pathlen;
5667 /*
5668 * Will there be space for the expansion in the line buffer?
5669 */
5670 if(gl->ntotal + nextra >= gl->linelen) {
5671 return gl_print_info(gl, "Insufficient room in line for file expansion.",
5672 GL_END_INFO);
5673 } else {
5674 /*
5675 * Do we need to move the part of the line that followed the unexpanded
5676 * filename?
5677 */
5678 if(nextra > 0) {
5679 gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
5680 } else if(nextra < 0) {
5681 gl->buff_curpos += nextra;
5682 gl_remove_from_buffer(gl, gl->buff_curpos, -nextra);
5683 };
5684 /*
5685 * Insert the filenames, separated by spaces, and with internal spaces,
5686 * tabs and backslashes escaped with backslashes.
5687 */
5688 for(i=0,j=start_path - gl->line; i<result->nfile; i++) {
5689 char *file = result->files[i];
5690 while(*file) {
5691 int c = *file++;
5692 switch(c) {
5693 case ' ': case '\t': case '\\': case '*': case '?': case '[':
5694 gl_buffer_char(gl, '\\', j++);
5695 };
5696 gl_buffer_char(gl, c, j++);
5697 };
5698 gl_buffer_char(gl, ' ', j++);
5699 };
5700 };
5701 /*
5702 * Redisplay the part of the line which follows the start of
5703 * the original filename.
5704 */
5705 if(gl_place_cursor(gl, start_path - gl->line) ||
5706 gl_truncate_display(gl) ||
5707 gl_print_string(gl, start_path, start_path[length]))
5708 return 1;
5709 /*
5710 * Move the cursor to the end of the expansion.
5711 */
5712 return gl_place_cursor(gl, (start_path - gl->line) + length);
5713 }
5714 #endif
5715
5716 #ifndef HIDE_FILE_SYSTEM
5717 /*.......................................................................
5718 * This is the action function that lists glob expansions of the
5719 * filename that precedes the cursor position. It expands ~user/
5720 * expressions, $envvar expressions, and wildcards.
5721 */
KT_KEY_FN(gl_list_glob)5722 static KT_KEY_FN(gl_list_glob)
5723 {
5724 char *start_path; /* The pointer to the start of the pathname in */
5725 /* gl->line[]. */
5726 FileExpansion *result; /* The results of the filename expansion */
5727 int pathlen; /* The length of the pathname being expanded */
5728 /*
5729 * Locate the start of the filename that precedes the cursor position.
5730 */
5731 start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
5732 if(!start_path)
5733 return 1;
5734 /*
5735 * Get the length of the string that is to be expanded.
5736 */
5737 pathlen = gl->buff_curpos - (start_path - gl->line);
5738 /*
5739 * Attempt to expand it.
5740 */
5741 result = ef_expand_file(gl->ef, start_path, pathlen);
5742 /*
5743 * If there was an error, report it.
5744 */
5745 if(!result) {
5746 return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
5747 /*
5748 * If no files matched, report this as well.
5749 */
5750 } else if(result->nfile == 0 || !result->exists) {
5751 return gl_print_info(gl, "No files match.", GL_END_INFO);
5752 /*
5753 * List the matching expansions.
5754 */
5755 } else if(gl->echo) {
5756 if(gl_start_newline(gl, 1) ||
5757 _ef_output_expansions(result, gl_write_fn, gl, gl->ncolumn))
5758 return 1;
5759 gl_queue_redisplay(gl);
5760 };
5761 return 0;
5762 }
5763 #endif
5764
5765 /*.......................................................................
5766 * Return non-zero if a character should be considered a part of a word.
5767 *
5768 * Input:
5769 * c int The character to be tested.
5770 * Output:
5771 * return int True if the character should be considered part of a word.
5772 */
gl_is_word_char(int c)5773 static int gl_is_word_char(int c)
5774 {
5775 return isalnum((int)(unsigned char)c) || strchr(GL_WORD_CHARS, c) != NULL;
5776 }
5777
5778 /*.......................................................................
5779 * Override the builtin file-completion callback that is bound to the
5780 * "complete_word" action function.
5781 *
5782 * Input:
5783 * gl GetLine * The resource object of the command-line input
5784 * module.
5785 * data void * This is passed to match_fn() whenever it is
5786 * called. It could, for example, point to a
5787 * symbol table where match_fn() could look
5788 * for possible completions.
5789 * match_fn CplMatchFn * The function that will identify the prefix
5790 * to be completed from the input line, and
5791 * report matching symbols.
5792 * Output:
5793 * return int 0 - OK.
5794 * 1 - Error.
5795 */
gl_customize_completion(GetLine * gl,void * data,CplMatchFn * match_fn)5796 int gl_customize_completion(GetLine *gl, void *data, CplMatchFn *match_fn)
5797 {
5798 sigset_t oldset; /* The signals that were blocked on entry to this function */
5799 /*
5800 * Check the arguments.
5801 */
5802 if(!gl || !match_fn) {
5803 if(gl)
5804 _err_record_msg(gl->err, "NULL argument", END_ERR_MSG);
5805 errno = EINVAL;
5806 return 1;
5807 };
5808 /*
5809 * Temporarily block all signals.
5810 */
5811 gl_mask_signals(gl, &oldset);
5812 /*
5813 * Record the new completion function and its callback data.
5814 */
5815 gl->cplfn.fn = match_fn;
5816 gl->cplfn.data = data;
5817 /*
5818 * Restore the process signal mask before returning.
5819 */
5820 gl_unmask_signals(gl, &oldset);
5821 return 0;
5822 }
5823
5824 /*.......................................................................
5825 * Change the terminal (or stream) that getline interacts with.
5826 *
5827 * Input:
5828 * gl GetLine * The resource object of the command-line input
5829 * module.
5830 * input_fp FILE * The stdio stream to read from.
5831 * output_fp FILE * The stdio stream to write to.
5832 * term char * The terminal type. This can be NULL if
5833 * either or both of input_fp and output_fp don't
5834 * refer to a terminal. Otherwise it should refer
5835 * to an entry in the terminal information database.
5836 * Output:
5837 * return int 0 - OK.
5838 * 1 - Error.
5839 */
gl_change_terminal(GetLine * gl,FILE * input_fp,FILE * output_fp,const char * term)5840 int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
5841 const char *term)
5842 {
5843 sigset_t oldset; /* The signals that were blocked on entry to this function */
5844 int status; /* The return status of _gl_change_terminal() */
5845 /*
5846 * Check the arguments.
5847 */
5848 if(!gl) {
5849 errno = EINVAL;
5850 return 1;
5851 };
5852 /*
5853 * Block all signals.
5854 */
5855 if(gl_mask_signals(gl, &oldset))
5856 return 1;
5857 /*
5858 * Execute the private body of the function while signals are blocked.
5859 */
5860 status = _gl_change_terminal(gl, input_fp, output_fp, term);
5861 /*
5862 * Restore the process signal mask.
5863 */
5864 gl_unmask_signals(gl, &oldset);
5865 return status;
5866 }
5867
5868 /*.......................................................................
5869 * This is the private body of the gl_change_terminal() function. It
5870 * assumes that the caller has checked its arguments and blocked the
5871 * delivery of signals.
5872 */
_gl_change_terminal(GetLine * gl,FILE * input_fp,FILE * output_fp,const char * term)5873 static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
5874 const char *term)
5875 {
5876 int is_term = 0; /* True if both input_fd and output_fd are associated */
5877 /* with a terminal. */
5878 /*
5879 * Require that input_fp and output_fp both be valid.
5880 */
5881 if(!input_fp || !output_fp) {
5882 gl_print_info(gl, "Can't change terminal. Bad input/output stream(s).",
5883 GL_END_INFO);
5884 return 1;
5885 };
5886 /*
5887 * Are we displacing an existing terminal (as opposed to setting the
5888 * initial terminal)?
5889 */
5890 if(gl->input_fd >= 0) {
5891 /*
5892 * Make sure to leave the previous terminal in a usable state.
5893 */
5894 if(_gl_normal_io(gl))
5895 return 1;
5896 /*
5897 * Remove the displaced terminal from the list of fds to watch.
5898 */
5899 #ifdef HAVE_SELECT
5900 FD_CLR(gl->input_fd, &gl->rfds);
5901 #endif
5902 };
5903 /*
5904 * Record the file descriptors and streams.
5905 */
5906 gl->input_fp = input_fp;
5907 gl->input_fd = fileno(input_fp);
5908 gl->output_fp = output_fp;
5909 gl->output_fd = fileno(output_fp);
5910 /*
5911 * If needed, expand the record of the maximum file-descriptor that might
5912 * need to be monitored with select().
5913 */
5914 #ifdef HAVE_SELECT
5915 if(gl->input_fd > gl->max_fd)
5916 gl->max_fd = gl->input_fd;
5917 #endif
5918 /*
5919 * Disable terminal interaction until we have enough info to interact
5920 * with the terminal.
5921 */
5922 gl->is_term = 0;
5923 /*
5924 * For terminal editing, we need both output_fd and input_fd to refer to
5925 * a terminal. While we can't verify that they both point to the same
5926 * terminal, we can verify that they point to terminals.
5927 */
5928 is_term = isatty(gl->input_fd) && isatty(gl->output_fd);
5929 /*
5930 * If we are interacting with a terminal and no terminal type has been
5931 * specified, treat it as a generic ANSI terminal.
5932 */
5933 if(is_term && !term)
5934 term = "ansi";
5935 /*
5936 * Make a copy of the terminal type string.
5937 */
5938 if(term != gl->term) {
5939 /*
5940 * Delete any old terminal type string.
5941 */
5942 if(gl->term) {
5943 free(gl->term);
5944 gl->term = NULL;
5945 };
5946 /*
5947 * Make a copy of the new terminal-type string, if any.
5948 */
5949 if(term) {
5950 size_t termsz = strlen(term)+1;
5951
5952 gl->term = (char *) malloc(termsz);
5953 if(gl->term)
5954 strlcpy(gl->term, term, termsz);
5955 };
5956 };
5957 /*
5958 * Clear any terminal-specific key bindings that were taken from the
5959 * settings of the last terminal.
5960 */
5961 _kt_clear_bindings(gl->bindings, KTB_TERM);
5962 /*
5963 * If we have a terminal install new bindings for it.
5964 */
5965 if(is_term) {
5966 /*
5967 * Get the current settings of the terminal.
5968 */
5969 if(tcgetattr(gl->input_fd, &gl->oldattr)) {
5970 _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
5971 return 1;
5972 };
5973 /*
5974 * If we don't set this now, gl_control_strings() won't know
5975 * that it is talking to a terminal.
5976 */
5977 gl->is_term = 1;
5978 /*
5979 * Lookup the terminal control string and size information.
5980 */
5981 if(gl_control_strings(gl, term)) {
5982 gl->is_term = 0;
5983 return 1;
5984 };
5985 /*
5986 * Bind terminal-specific keys.
5987 */
5988 if(gl_bind_terminal_keys(gl))
5989 return 1;
5990 };
5991 /*
5992 * Assume that the caller has given us a terminal in a sane state.
5993 */
5994 gl->io_mode = GL_NORMAL_MODE;
5995 /*
5996 * Switch into the currently configured I/O mode.
5997 */
5998 if(_gl_io_mode(gl, gl->io_mode))
5999 return 1;
6000 return 0;
6001 }
6002
6003 /*.......................................................................
6004 * Set up terminal-specific key bindings.
6005 *
6006 * Input:
6007 * gl GetLine * The resource object of the command-line input
6008 * module.
6009 * Output:
6010 * return int 0 - OK.
6011 * 1 - Error.
6012 */
gl_bind_terminal_keys(GetLine * gl)6013 static int gl_bind_terminal_keys(GetLine *gl)
6014 {
6015 /*
6016 * Install key-bindings for the special terminal characters.
6017 */
6018 if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VINTR],
6019 "user-interrupt") ||
6020 gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VQUIT], "abort") ||
6021 gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VSUSP], "suspend"))
6022 return 1;
6023 /*
6024 * In vi-mode, arrange for the above characters to be seen in command
6025 * mode.
6026 */
6027 if(gl->editor == GL_VI_MODE) {
6028 if(gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VINTR]),
6029 "user-interrupt") ||
6030 gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VQUIT]),
6031 "abort") ||
6032 gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VSUSP]),
6033 "suspend"))
6034 return 1;
6035 };
6036 /*
6037 * Non-universal special keys.
6038 */
6039 #ifdef VLNEXT
6040 if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VLNEXT],
6041 "literal-next"))
6042 return 1;
6043 #else
6044 if(_kt_set_keybinding(gl->bindings, KTB_TERM, "^V", "literal-next")) {
6045 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
6046 return 1;
6047 };
6048 #endif
6049 /*
6050 * Bind action functions to the terminal-specific arrow keys
6051 * looked up by gl_control_strings().
6052 */
6053 if(_gl_bind_arrow_keys(gl))
6054 return 1;
6055 return 0;
6056 }
6057
6058 /*.......................................................................
6059 * This function is normally bound to control-D. When it is invoked within
6060 * a line it deletes the character which follows the cursor. When invoked
6061 * at the end of the line it lists possible file completions, and when
6062 * invoked on an empty line it causes gl_get_line() to return EOF. This
6063 * function emulates the one that is normally bound to control-D by tcsh.
6064 */
KT_KEY_FN(gl_del_char_or_list_or_eof)6065 static KT_KEY_FN(gl_del_char_or_list_or_eof)
6066 {
6067 /*
6068 * If we have an empty line arrange to return EOF.
6069 */
6070 if(gl->ntotal < 1) {
6071 gl_record_status(gl, GLR_EOF, 0);
6072 return 1;
6073 /*
6074 * If we are at the end of the line list possible completions.
6075 */
6076 } else if(gl->buff_curpos >= gl->ntotal) {
6077 return gl_list_completions(gl, 1, NULL);
6078 /*
6079 * Within the line delete the character that follows the cursor.
6080 */
6081 } else {
6082 /*
6083 * If in vi command mode, first preserve the current line for potential use
6084 * by vi-undo.
6085 */
6086 gl_save_for_undo(gl);
6087 /*
6088 * Delete 'count' characters.
6089 */
6090 return gl_forward_delete_char(gl, count, NULL);
6091 };
6092 }
6093
6094 /*.......................................................................
6095 * This function is normally bound to control-D in vi mode. When it is
6096 * invoked within a line it lists possible file completions, and when
6097 * invoked on an empty line it causes gl_get_line() to return EOF. This
6098 * function emulates the one that is normally bound to control-D by tcsh.
6099 */
KT_KEY_FN(gl_list_or_eof)6100 static KT_KEY_FN(gl_list_or_eof)
6101 {
6102 /*
6103 * If we have an empty line arrange to return EOF.
6104 */
6105 if(gl->ntotal < 1) {
6106 gl_record_status(gl, GLR_EOF, 0);
6107 return 1;
6108 /*
6109 * Otherwise list possible completions.
6110 */
6111 } else {
6112 return gl_list_completions(gl, 1, NULL);
6113 };
6114 }
6115
6116 /*.......................................................................
6117 * List possible completions of the word that precedes the cursor. The
6118 * callback data argument must either be NULL to select the default
6119 * file completion callback, or be a GlCplCallback object containing the
6120 * completion callback function to call.
6121 */
KT_KEY_FN(gl_list_completions)6122 static KT_KEY_FN(gl_list_completions)
6123 {
6124 int waserr = 0; /* True after errors */
6125 /*
6126 * Get the container of the completion callback and its callback data.
6127 */
6128 GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
6129 /*
6130 * Get the list of possible completions.
6131 */
6132 CplMatches *matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos,
6133 cb->data, cb->fn);
6134 /*
6135 * No matching completions?
6136 */
6137 if(!matches) {
6138 waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
6139 /*
6140 * List the matches.
6141 */
6142 } else if(matches->nmatch > 0 && gl->echo) {
6143 if(_gl_normal_io(gl) ||
6144 _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
6145 waserr = 1;
6146 };
6147 /*
6148 * If any output had to be written to the terminal, then editing will
6149 * have been suspended, make sure that we are back in raw line editing
6150 * mode before returning.
6151 */
6152 if(_gl_raw_io(gl, 1))
6153 waserr = 1;
6154 return waserr;
6155 }
6156
6157 /*.......................................................................
6158 * Where the user has used the symbolic arrow-key names to specify
6159 * arrow key bindings, bind the specified action functions to the default
6160 * and terminal specific arrow key sequences.
6161 *
6162 * Input:
6163 * gl GetLine * The getline resource object.
6164 * Output:
6165 * return int 0 - OK.
6166 * 1 - Error.
6167 */
_gl_bind_arrow_keys(GetLine * gl)6168 static int _gl_bind_arrow_keys(GetLine *gl)
6169 {
6170 /*
6171 * Process each of the arrow keys.
6172 */
6173 if(_gl_rebind_arrow_key(gl, "up", gl->u_arrow, "^[[A", "^[OA") ||
6174 _gl_rebind_arrow_key(gl, "down", gl->d_arrow, "^[[B", "^[OB") ||
6175 _gl_rebind_arrow_key(gl, "left", gl->l_arrow, "^[[D", "^[OD") ||
6176 _gl_rebind_arrow_key(gl, "right", gl->r_arrow, "^[[C", "^[OC"))
6177 return 1;
6178 return 0;
6179 }
6180
6181 /*.......................................................................
6182 * Lookup the action function of a symbolic arrow-key binding, and bind
6183 * it to the terminal-specific and default arrow-key sequences. Note that
6184 * we don't trust the terminal-specified key sequences to be correct.
6185 * The main reason for this is that on some machines the xterm terminfo
6186 * entry is for hardware X-terminals, rather than xterm terminal emulators
6187 * and the two terminal types emit different character sequences when the
6188 * their cursor keys are pressed. As a result we also supply a couple
6189 * of default key sequences.
6190 *
6191 * Input:
6192 * gl GetLine * The resource object of gl_get_line().
6193 * name char * The symbolic name of the arrow key.
6194 * term_seq char * The terminal-specific arrow-key sequence.
6195 * def_seq1 char * The first default arrow-key sequence.
6196 * def_seq2 char * The second arrow-key sequence.
6197 * Output:
6198 * return int 0 - OK.
6199 * 1 - Error.
6200 */
_gl_rebind_arrow_key(GetLine * gl,const char * name,const char * term_seq,const char * def_seq1,const char * def_seq2)6201 static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
6202 const char *term_seq, const char *def_seq1,
6203 const char *def_seq2)
6204 {
6205 KeySym *keysym; /* The binding-table entry matching the arrow-key name */
6206 int nsym; /* The number of ambiguous matches */
6207 /*
6208 * Lookup the key binding for the symbolic name of the arrow key. This
6209 * will either be the default action, or a user provided one.
6210 */
6211 if(_kt_lookup_keybinding(gl->bindings, name, strlen(name), &keysym, &nsym)
6212 == KT_EXACT_MATCH) {
6213 /*
6214 * Get the action function.
6215 */
6216 KtAction *action = keysym->actions + keysym->binder;
6217 KtKeyFn *fn = action->fn;
6218 void *data = action->data;
6219 /*
6220 * Bind this to each of the specified key sequences.
6221 */
6222 if((term_seq &&
6223 _kt_set_keyfn(gl->bindings, KTB_TERM, term_seq, fn, data)) ||
6224 (def_seq1 &&
6225 _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq1, fn, data)) ||
6226 (def_seq2 &&
6227 _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq2, fn, data))) {
6228 _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
6229 return 1;
6230 };
6231 };
6232 return 0;
6233 }
6234
6235 /*.......................................................................
6236 * Read getline configuration information from a given file.
6237 *
6238 * Input:
6239 * gl GetLine * The getline resource object.
6240 * filename const char * The name of the file to read configuration
6241 * information from. The contents of this file
6242 * are as described in the gl_get_line(3) man
6243 * page for the default ~/.teclarc configuration
6244 * file.
6245 * who KtBinder Who bindings are to be installed for.
6246 * Output:
6247 * return int 0 - OK.
6248 * 1 - Irrecoverable error.
6249 */
_gl_read_config_file(GetLine * gl,const char * filename,KtBinder who)6250 static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who)
6251 {
6252 /*
6253 * If filesystem access is to be excluded, configuration files can't
6254 * be read.
6255 */
6256 #ifdef WITHOUT_FILE_SYSTEM
6257 _err_record_msg(gl->err,
6258 "Can't read configuration files without filesystem access",
6259 END_ERR_MSG);
6260 errno = EINVAL;
6261 return 1;
6262 #else
6263 FileExpansion *expansion; /* The expansion of the filename */
6264 FILE *fp; /* The opened file */
6265 int waserr = 0; /* True if an error occurred while reading */
6266 int lineno = 1; /* The line number being processed */
6267 /*
6268 * Check the arguments.
6269 */
6270 if(!gl || !filename) {
6271 if(gl)
6272 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
6273 errno = EINVAL;
6274 return 1;
6275 };
6276 /*
6277 * Expand the filename.
6278 */
6279 expansion = ef_expand_file(gl->ef, filename, -1);
6280 if(!expansion) {
6281 gl_print_info(gl, "Unable to expand ", filename, " (",
6282 ef_last_error(gl->ef), ").", GL_END_INFO);
6283 return 1;
6284 };
6285 /*
6286 * Attempt to open the file.
6287 */
6288 fp = fopen(expansion->files[0], "r");
6289 /*
6290 * It isn't an error for there to be no configuration file.
6291 */
6292 if(!fp)
6293 return 0;
6294 /*
6295 * Parse the contents of the file.
6296 */
6297 while(!waserr && !feof(fp))
6298 waserr = _gl_parse_config_line(gl, fp, glc_file_getc, filename, who,
6299 &lineno);
6300 /*
6301 * Bind action functions to the terminal-specific arrow keys.
6302 */
6303 if(_gl_bind_arrow_keys(gl))
6304 return 1;
6305 /*
6306 * Clean up.
6307 */
6308 (void) fclose(fp);
6309 return waserr;
6310 #endif
6311 }
6312
6313 /*.......................................................................
6314 * Read GetLine configuration information from a string. The contents of
6315 * the string are the same as those described in the gl_get_line(3)
6316 * man page for the contents of the ~/.teclarc configuration file.
6317 */
_gl_read_config_string(GetLine * gl,const char * buffer,KtBinder who)6318 static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who)
6319 {
6320 const char *bptr; /* A pointer into buffer[] */
6321 int waserr = 0; /* True if an error occurred while reading */
6322 int lineno = 1; /* The line number being processed */
6323 /*
6324 * Check the arguments.
6325 */
6326 if(!gl || !buffer) {
6327 if(gl)
6328 _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
6329 errno = EINVAL;
6330 return 1;
6331 };
6332 /*
6333 * Get a pointer to the start of the buffer.
6334 */
6335 bptr = buffer;
6336 /*
6337 * Parse the contents of the buffer.
6338 */
6339 while(!waserr && *bptr)
6340 waserr = _gl_parse_config_line(gl, &bptr, glc_buff_getc, "", who, &lineno);
6341 /*
6342 * Bind action functions to the terminal-specific arrow keys.
6343 */
6344 if(_gl_bind_arrow_keys(gl))
6345 return 1;
6346 return waserr;
6347 }
6348
6349 /*.......................................................................
6350 * Parse the next line of a getline configuration file.
6351 *
6352 * Input:
6353 * gl GetLine * The getline resource object.
6354 * stream void * The pointer representing the stream to be read
6355 * by getc_fn().
6356 * getc_fn GlcGetcFn * A callback function which when called with
6357 * 'stream' as its argument, returns the next
6358 * unread character from the stream.
6359 * origin const char * The name of the entity being read (eg. a
6360 * file name).
6361 * who KtBinder Who bindings are to be installed for.
6362 * Input/Output:
6363 * lineno int * The line number being processed is to be
6364 * maintained in *lineno.
6365 * Output:
6366 * return int 0 - OK.
6367 * 1 - Irrecoverable error.
6368 */
_gl_parse_config_line(GetLine * gl,void * stream,GlcGetcFn * getc_fn,const char * origin,KtBinder who,int * lineno)6369 static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
6370 const char *origin, KtBinder who, int *lineno)
6371 {
6372 char buffer[GL_CONF_BUFLEN+1]; /* The input line buffer */
6373 char *argv[GL_CONF_MAXARG]; /* The argument list */
6374 int argc = 0; /* The number of arguments in argv[] */
6375 int c; /* A character from the file */
6376 int escaped = 0; /* True if the next character is escaped */
6377 int i;
6378 /*
6379 * Skip spaces and tabs.
6380 */
6381 do c = getc_fn(stream); while(c==' ' || c=='\t');
6382 /*
6383 * Comments extend to the end of the line.
6384 */
6385 if(c=='#')
6386 do c = getc_fn(stream); while(c != '\n' && c != EOF);
6387 /*
6388 * Ignore empty lines.
6389 */
6390 if(c=='\n' || c==EOF) {
6391 (*lineno)++;
6392 return 0;
6393 };
6394 /*
6395 * Record the buffer location of the start of the first argument.
6396 */
6397 argv[argc] = buffer;
6398 /*
6399 * Read the rest of the line, stopping early if a comment is seen, or
6400 * the buffer overflows, and replacing sequences of spaces with a
6401 * '\0', and recording the thus terminated string as an argument.
6402 */
6403 i = 0;
6404 while(i<GL_CONF_BUFLEN) {
6405 /*
6406 * Did we hit the end of the latest argument?
6407 */
6408 if(c==EOF || (!escaped && (c==' ' || c=='\n' || c=='\t' || c=='#'))) {
6409 /*
6410 * Terminate the argument.
6411 */
6412 buffer[i++] = '\0';
6413 argc++;
6414 /*
6415 * Skip spaces and tabs.
6416 */
6417 while(c==' ' || c=='\t')
6418 c = getc_fn(stream);
6419 /*
6420 * If we hit the end of the line, or the start of a comment, exit the loop.
6421 */
6422 if(c==EOF || c=='\n' || c=='#')
6423 break;
6424 /*
6425 * Start recording the next argument.
6426 */
6427 if(argc >= GL_CONF_MAXARG) {
6428 gl_report_config_error(gl, origin, *lineno, "Too many arguments.");
6429 do c = getc_fn(stream); while(c!='\n' && c!=EOF); /* Skip past eol */
6430 return 0;
6431 };
6432 argv[argc] = buffer + i;
6433 /*
6434 * The next character was preceded by spaces, so it isn't escaped.
6435 */
6436 escaped = 0;
6437 } else {
6438 /*
6439 * If we hit an unescaped backslash, this means that we should arrange
6440 * to treat the next character like a simple alphabetical character.
6441 */
6442 if(c=='\\' && !escaped) {
6443 escaped = 1;
6444 /*
6445 * Splice lines where the newline is escaped.
6446 */
6447 } else if(c=='\n' && escaped) {
6448 (*lineno)++;
6449 /*
6450 * Record a normal character, preserving any preceding backslash.
6451 */
6452 } else {
6453 if(escaped)
6454 buffer[i++] = '\\';
6455 if(i>=GL_CONF_BUFLEN)
6456 break;
6457 escaped = 0;
6458 buffer[i++] = c;
6459 };
6460 /*
6461 * Get the next character.
6462 */
6463 c = getc_fn(stream);
6464 };
6465 };
6466 /*
6467 * Did the buffer overflow?
6468 */
6469 if(i>=GL_CONF_BUFLEN) {
6470 gl_report_config_error(gl, origin, *lineno, "Line too long.");
6471 return 0;
6472 };
6473 /*
6474 * The first argument should be a command name.
6475 */
6476 if(strcmp(argv[0], "bind") == 0) {
6477 const char *action = NULL; /* A NULL action removes a keybinding */
6478 const char *keyseq = NULL;
6479 switch(argc) {
6480 case 3:
6481 action = argv[2];
6482 /* FALLTHROUGH */
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 to the 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