xref: /illumos-gate/usr/src/lib/libtecla/common/getline.c (revision 06ca4e396ecc93ed45a333664a51558b7e84e8f5)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * All rights reserved.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  * Permission is hereby granted, free of charge, to any person obtaining a
77c478bd9Sstevel@tonic-gate  * copy of this software and associated documentation files (the
87c478bd9Sstevel@tonic-gate  * "Software"), to deal in the Software without restriction, including
97c478bd9Sstevel@tonic-gate  * without limitation the rights to use, copy, modify, merge, publish,
107c478bd9Sstevel@tonic-gate  * distribute, and/or sell copies of the Software, and to permit persons
117c478bd9Sstevel@tonic-gate  * to whom the Software is furnished to do so, provided that the above
127c478bd9Sstevel@tonic-gate  * copyright notice(s) and this permission notice appear in all copies of
137c478bd9Sstevel@tonic-gate  * the Software and that both the above copyright notice(s) and this
147c478bd9Sstevel@tonic-gate  * permission notice appear in supporting documentation.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177c478bd9Sstevel@tonic-gate  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
187c478bd9Sstevel@tonic-gate  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
197c478bd9Sstevel@tonic-gate  * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
207c478bd9Sstevel@tonic-gate  * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
217c478bd9Sstevel@tonic-gate  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
227c478bd9Sstevel@tonic-gate  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
237c478bd9Sstevel@tonic-gate  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
247c478bd9Sstevel@tonic-gate  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * Except as contained in this notice, the name of a copyright holder
277c478bd9Sstevel@tonic-gate  * shall not be used in advertising or otherwise to promote the sale, use
287c478bd9Sstevel@tonic-gate  * or other dealings in this Software without prior written authorization
297c478bd9Sstevel@tonic-gate  * of the copyright holder.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
347c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
3548bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * Standard headers.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate #include <stdio.h>
427c478bd9Sstevel@tonic-gate #include <stdlib.h>
437c478bd9Sstevel@tonic-gate #include <signal.h>
447c478bd9Sstevel@tonic-gate #include <string.h>
457c478bd9Sstevel@tonic-gate #include <errno.h>
467c478bd9Sstevel@tonic-gate #include <ctype.h>
477c478bd9Sstevel@tonic-gate #include <setjmp.h>
487c478bd9Sstevel@tonic-gate #include <stdarg.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * UNIX headers.
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
547c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
557c478bd9Sstevel@tonic-gate #ifdef HAVE_SYS_SELECT_H
567c478bd9Sstevel@tonic-gate #include <sys/select.h>
577c478bd9Sstevel@tonic-gate #endif
587c478bd9Sstevel@tonic-gate #include <sys/time.h>
597c478bd9Sstevel@tonic-gate #include <sys/types.h>
607c478bd9Sstevel@tonic-gate #endif
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * Handle the different sources of terminal control string and size
647c478bd9Sstevel@tonic-gate  * information. Note that if no terminal information database is available,
657c478bd9Sstevel@tonic-gate  * ANSI VT100 control sequences are used.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * Include curses.h or ncurses/curses.h depending on which is available.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate #ifdef HAVE_CURSES_H
727c478bd9Sstevel@tonic-gate #include <curses.h>
737c478bd9Sstevel@tonic-gate #elif defined(HAVE_NCURSES_CURSES_H)
747c478bd9Sstevel@tonic-gate #include <ncurses/curses.h>
757c478bd9Sstevel@tonic-gate #endif
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Include term.h where available.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate #if defined(HAVE_TERM_H)
807c478bd9Sstevel@tonic-gate #include <term.h>
817c478bd9Sstevel@tonic-gate #elif defined(HAVE_NCURSES_TERM_H)
827c478bd9Sstevel@tonic-gate #include <ncurses/term.h>
837c478bd9Sstevel@tonic-gate #endif
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * When using termcap, include termcap.h on systems that have it.
867c478bd9Sstevel@tonic-gate  * Otherwise assume that all prototypes are provided by curses.h.
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate #if defined(USE_TERMCAP) && defined(HAVE_TERMCAP_H)
897c478bd9Sstevel@tonic-gate #include <termcap.h>
907c478bd9Sstevel@tonic-gate #endif
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Under Solaris default Curses the output function that tputs takes is
947c478bd9Sstevel@tonic-gate  * declared to have a char argument. On all other systems and on Solaris
957c478bd9Sstevel@tonic-gate  * X/Open Curses (Issue 4, Version 2) it expects an int argument (using
967c478bd9Sstevel@tonic-gate  * c89 or options -I /usr/xpg4/include -L /usr/xpg4/lib -R /usr/xpg4/lib
977c478bd9Sstevel@tonic-gate  * selects XPG4v2 Curses on Solaris 2.6 and later).
987c478bd9Sstevel@tonic-gate  *
997c478bd9Sstevel@tonic-gate  * Similarly, under Mac OS X, the return value of the tputs output
1007c478bd9Sstevel@tonic-gate  * function is declared as void, whereas it is declared as int on
1017c478bd9Sstevel@tonic-gate  * other systems.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate #if defined __sun && defined __SVR4 && !defined _XOPEN_CURSES
1047c478bd9Sstevel@tonic-gate typedef int TputsRetType;
1057c478bd9Sstevel@tonic-gate typedef char TputsArgType;              /* int tputs(char c, FILE *fp) */
1067c478bd9Sstevel@tonic-gate #define TPUTS_RETURNS_VALUE 1
1077c478bd9Sstevel@tonic-gate #elif defined(__APPLE__) && defined(__MACH__)
1087c478bd9Sstevel@tonic-gate typedef void TputsRetType;
1097c478bd9Sstevel@tonic-gate typedef int TputsArgType;               /* void tputs(int c, FILE *fp) */
1107c478bd9Sstevel@tonic-gate #define TPUTS_RETURNS_VALUE 0
1117c478bd9Sstevel@tonic-gate #else
1127c478bd9Sstevel@tonic-gate typedef int TputsRetType;
1137c478bd9Sstevel@tonic-gate typedef int TputsArgType;               /* int tputs(int c, FILE *fp) */
1147c478bd9Sstevel@tonic-gate #define TPUTS_RETURNS_VALUE 1
1157c478bd9Sstevel@tonic-gate #endif
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  * Use the above specifications to prototype our tputs callback function.
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate static TputsRetType gl_tputs_putchar(TputsArgType c);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate #endif  /* defined(USE_TERMINFO) || defined(USE_TERMCAP) */
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * If the library is being compiled without filesystem access facilities,
1267c478bd9Sstevel@tonic-gate  * ensure that none of the action functions that normally do access the
1277c478bd9Sstevel@tonic-gate  * filesystem are bound by default, and that it they do get bound, that
1287c478bd9Sstevel@tonic-gate  * they don't do anything.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate #if WITHOUT_FILE_SYSTEM
1317c478bd9Sstevel@tonic-gate #define HIDE_FILE_SYSTEM
1327c478bd9Sstevel@tonic-gate #endif
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * POSIX headers.
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate #include <unistd.h>
1387c478bd9Sstevel@tonic-gate #include <fcntl.h>
1397c478bd9Sstevel@tonic-gate #include <termios.h>
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * Provide typedefs for standard POSIX structures.
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate typedef struct sigaction SigAction;
1457c478bd9Sstevel@tonic-gate typedef struct termios Termios;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * Which flag is used to select non-blocking I/O with fcntl()?
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate #undef NON_BLOCKING_FLAG
1517c478bd9Sstevel@tonic-gate #if defined(O_NONBLOCK)
1527c478bd9Sstevel@tonic-gate #define NON_BLOCKING_FLAG (O_NONBLOCK)
1537c478bd9Sstevel@tonic-gate #elif defined(O_NDELAY)
1547c478bd9Sstevel@tonic-gate #define NON_BLOCKING_FLAG (O_NDELAY)
1557c478bd9Sstevel@tonic-gate #endif
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate  * What value should we give errno if I/O blocks when it shouldn't.
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate #undef BLOCKED_ERRNO
1617c478bd9Sstevel@tonic-gate #if defined(EAGAIN)
1627c478bd9Sstevel@tonic-gate #define BLOCKED_ERRNO (EAGAIN)
1637c478bd9Sstevel@tonic-gate #elif defined(EWOULDBLOCK)
1647c478bd9Sstevel@tonic-gate #define BLOCKED_ERRNO (EWOULDBLOCK)
1657c478bd9Sstevel@tonic-gate #elif defined(EIO)
1667c478bd9Sstevel@tonic-gate #define BLOCKED_ERRNO (EIO)
1677c478bd9Sstevel@tonic-gate #else
1687c478bd9Sstevel@tonic-gate #define BLOCKED_ERRNO 0
1697c478bd9Sstevel@tonic-gate #endif
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate  * Local headers.
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM
1757c478bd9Sstevel@tonic-gate #include "pathutil.h"
1767c478bd9Sstevel@tonic-gate #endif
1777c478bd9Sstevel@tonic-gate #include "libtecla.h"
1787c478bd9Sstevel@tonic-gate #include "keytab.h"
1797c478bd9Sstevel@tonic-gate #include "getline.h"
1807c478bd9Sstevel@tonic-gate #include "ioutil.h"
1817c478bd9Sstevel@tonic-gate #include "history.h"
1827c478bd9Sstevel@tonic-gate #include "freelist.h"
1837c478bd9Sstevel@tonic-gate #include "stringrp.h"
1847c478bd9Sstevel@tonic-gate #include "chrqueue.h"
1857c478bd9Sstevel@tonic-gate #include "cplmatch.h"
1867c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM
1877c478bd9Sstevel@tonic-gate #include "expand.h"
1887c478bd9Sstevel@tonic-gate #endif
1897c478bd9Sstevel@tonic-gate #include "errmsg.h"
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate  * Enumerate the available editing styles.
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate typedef enum {
1957c478bd9Sstevel@tonic-gate   GL_EMACS_MODE,   /* Emacs style editing */
1967c478bd9Sstevel@tonic-gate   GL_VI_MODE,      /* Vi style editing */
1977c478bd9Sstevel@tonic-gate   GL_NO_EDITOR     /* Fall back to the basic OS-provided editing */
1987c478bd9Sstevel@tonic-gate } GlEditor;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  * Set the largest key-sequence that can be handled.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate #define GL_KEY_MAX 64
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate  * In vi mode, the following datatype is used to implement the
2077c478bd9Sstevel@tonic-gate  * undo command. It records a copy of the input line from before
2087c478bd9Sstevel@tonic-gate  * the command-mode action which edited the input line.
2097c478bd9Sstevel@tonic-gate  */
2107c478bd9Sstevel@tonic-gate typedef struct {
2117c478bd9Sstevel@tonic-gate   char *line;        /* A historical copy of the input line */
2127c478bd9Sstevel@tonic-gate   int buff_curpos;   /* The historical location of the cursor in */
2137c478bd9Sstevel@tonic-gate                      /*  line[] when the line was modified. */
2147c478bd9Sstevel@tonic-gate   int ntotal;        /* The number of characters in line[] */
2157c478bd9Sstevel@tonic-gate   int saved;         /* True once a line has been saved after the */
2167c478bd9Sstevel@tonic-gate                      /*  last call to gl_interpret_char(). */
2177c478bd9Sstevel@tonic-gate } ViUndo;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate  * In vi mode, the following datatype is used to record information
2217c478bd9Sstevel@tonic-gate  * needed by the vi-repeat-change command.
2227c478bd9Sstevel@tonic-gate  */
2237c478bd9Sstevel@tonic-gate typedef struct {
2247c478bd9Sstevel@tonic-gate   KtAction action;           /* The last action function that made a */
2257c478bd9Sstevel@tonic-gate                              /*  change to the line. */
2267c478bd9Sstevel@tonic-gate   int count;                 /* The repeat count that was passed to the */
2277c478bd9Sstevel@tonic-gate                              /*  above command. */
2287c478bd9Sstevel@tonic-gate   int input_curpos;          /* Whenever vi command mode is entered, the */
2297c478bd9Sstevel@tonic-gate                              /*  the position at which it was first left */
2307c478bd9Sstevel@tonic-gate                              /*  is recorded here. */
2317c478bd9Sstevel@tonic-gate   int command_curpos;        /* Whenever vi command mode is entered, the */
2327c478bd9Sstevel@tonic-gate                              /*  the location of the cursor is recorded */
2337c478bd9Sstevel@tonic-gate                              /*  here. */
2347c478bd9Sstevel@tonic-gate   char input_char;           /* Commands that call gl_read_terminal() */
2357c478bd9Sstevel@tonic-gate                              /*  record the character here, so that it can */
2367c478bd9Sstevel@tonic-gate                              /*  used on repeating the function. */
2377c478bd9Sstevel@tonic-gate   int saved;                 /* True if a function has been saved since the */
2387c478bd9Sstevel@tonic-gate                              /*  last call to gl_interpret_char(). */
2397c478bd9Sstevel@tonic-gate   int active;                /* True while a function is being repeated. */
2407c478bd9Sstevel@tonic-gate } ViRepeat;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate  * The following datatype is used to encapsulate information specific
2447c478bd9Sstevel@tonic-gate  * to vi mode.
2457c478bd9Sstevel@tonic-gate  */
2467c478bd9Sstevel@tonic-gate typedef struct {
2477c478bd9Sstevel@tonic-gate   ViUndo undo;               /* Information needed to implement the vi */
2487c478bd9Sstevel@tonic-gate                              /*  undo command. */
2497c478bd9Sstevel@tonic-gate   ViRepeat repeat;           /* Information needed to implement the vi */
2507c478bd9Sstevel@tonic-gate                              /*  repeat command. */
2517c478bd9Sstevel@tonic-gate   int command;               /* True in vi command-mode */
2527c478bd9Sstevel@tonic-gate   int find_forward;          /* True if the last character search was in the */
2537c478bd9Sstevel@tonic-gate                              /*  forward direction. */
2547c478bd9Sstevel@tonic-gate   int find_onto;             /* True if the last character search left the */
2557c478bd9Sstevel@tonic-gate                              /*  on top of the located character, as opposed */
2567c478bd9Sstevel@tonic-gate                              /*  to just before or after it. */
2577c478bd9Sstevel@tonic-gate   char find_char;            /* The last character sought, or '\0' if no */
2587c478bd9Sstevel@tonic-gate                              /*  searches have been performed yet. */
2597c478bd9Sstevel@tonic-gate } ViMode;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate  * Define a type for recording a file-descriptor callback and its associated
2647c478bd9Sstevel@tonic-gate  * data.
2657c478bd9Sstevel@tonic-gate  */
2667c478bd9Sstevel@tonic-gate typedef struct {
2677c478bd9Sstevel@tonic-gate   GlFdEventFn *fn;   /* The callback function */
2687c478bd9Sstevel@tonic-gate   void *data;        /* Anonymous data to pass to the callback function */
2697c478bd9Sstevel@tonic-gate } GlFdHandler;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * A list of nodes of the following type is used to record file-activity
2737c478bd9Sstevel@tonic-gate  * event handlers, but only on systems that have the select() system call.
2747c478bd9Sstevel@tonic-gate  */
2757c478bd9Sstevel@tonic-gate typedef struct GlFdNode GlFdNode;
2767c478bd9Sstevel@tonic-gate struct GlFdNode {
2777c478bd9Sstevel@tonic-gate   GlFdNode *next;    /* The next in the list of nodes */
2787c478bd9Sstevel@tonic-gate   int fd;            /* The file descriptor being watched */
2797c478bd9Sstevel@tonic-gate   GlFdHandler rd;    /* The callback to call when fd is readable */
2807c478bd9Sstevel@tonic-gate   GlFdHandler wr;    /* The callback to call when fd is writable */
2817c478bd9Sstevel@tonic-gate   GlFdHandler ur;    /* The callback to call when fd has urgent data */
2827c478bd9Sstevel@tonic-gate };
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  * Set the number of the above structures to allocate every time that
2867c478bd9Sstevel@tonic-gate  * the freelist of GlFdNode's becomes exhausted.
2877c478bd9Sstevel@tonic-gate  */
2887c478bd9Sstevel@tonic-gate #define GLFD_FREELIST_BLOCKING 10
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
2927c478bd9Sstevel@tonic-gate 			      GlFdEvent event);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate static int gl_call_timeout_handler(GetLine *gl);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate #endif
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate /*
2997c478bd9Sstevel@tonic-gate  * Each signal that gl_get_line() traps is described by a list node
3007c478bd9Sstevel@tonic-gate  * of the following type.
3017c478bd9Sstevel@tonic-gate  */
3027c478bd9Sstevel@tonic-gate typedef struct GlSignalNode GlSignalNode;
3037c478bd9Sstevel@tonic-gate struct GlSignalNode {
3047c478bd9Sstevel@tonic-gate   GlSignalNode *next;  /* The next signal in the list */
3057c478bd9Sstevel@tonic-gate   int signo;           /* The number of the signal */
3067c478bd9Sstevel@tonic-gate   sigset_t proc_mask;  /* A process mask which only includes signo */
3077c478bd9Sstevel@tonic-gate   SigAction original;  /* The signal disposition of the calling program */
3087c478bd9Sstevel@tonic-gate                        /*  for this signal. */
3097c478bd9Sstevel@tonic-gate   unsigned flags;      /* A bitwise union of GlSignalFlags enumerators */
3107c478bd9Sstevel@tonic-gate   GlAfterSignal after; /* What to do after the signal has been handled */
3117c478bd9Sstevel@tonic-gate   int errno_value;     /* What to set errno to */
3127c478bd9Sstevel@tonic-gate };
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate  * Set the number of the above structures to allocate every time that
3167c478bd9Sstevel@tonic-gate  * the freelist of GlSignalNode's becomes exhausted.
3177c478bd9Sstevel@tonic-gate  */
3187c478bd9Sstevel@tonic-gate #define GLS_FREELIST_BLOCKING 30
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate  * Completion handlers and their callback data are recorded in
3227c478bd9Sstevel@tonic-gate  * nodes of the following type.
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate typedef struct GlCplCallback GlCplCallback;
3257c478bd9Sstevel@tonic-gate struct GlCplCallback {
3267c478bd9Sstevel@tonic-gate   CplMatchFn *fn;            /* The completion callback function */
3277c478bd9Sstevel@tonic-gate   void *data;                /* Arbitrary callback data */
3287c478bd9Sstevel@tonic-gate };
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * The following function is used as the default completion handler when
3327c478bd9Sstevel@tonic-gate  * the filesystem is to be hidden. It simply reports no completions.
3337c478bd9Sstevel@tonic-gate  */
3347c478bd9Sstevel@tonic-gate #ifdef HIDE_FILE_SYSTEM
3357c478bd9Sstevel@tonic-gate static CPL_MATCH_FN(gl_no_completions);
3367c478bd9Sstevel@tonic-gate #endif
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate  * Specify how many GlCplCallback nodes are added to the GlCplCallback freelist
3407c478bd9Sstevel@tonic-gate  * whenever it becomes exhausted.
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate #define GL_CPL_FREELIST_BLOCKING 10
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate  * External action functions and their callback data are recorded in
3467c478bd9Sstevel@tonic-gate  * nodes of the following type.
3477c478bd9Sstevel@tonic-gate  */
3487c478bd9Sstevel@tonic-gate typedef struct GlExternalAction GlExternalAction;
3497c478bd9Sstevel@tonic-gate struct GlExternalAction {
3507c478bd9Sstevel@tonic-gate   GlActionFn *fn;          /* The function which implements the action */
3517c478bd9Sstevel@tonic-gate   void *data;              /* Arbitrary callback data */
3527c478bd9Sstevel@tonic-gate };
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate /*
3557c478bd9Sstevel@tonic-gate  * Specify how many GlExternalAction nodes are added to the
3567c478bd9Sstevel@tonic-gate  * GlExternalAction freelist whenever it becomes exhausted.
3577c478bd9Sstevel@tonic-gate  */
3587c478bd9Sstevel@tonic-gate #define GL_EXT_ACT_FREELIST_BLOCKING 10
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate  * Define the contents of the GetLine object.
3627c478bd9Sstevel@tonic-gate  * Note that the typedef for this object can be found in libtecla.h.
3637c478bd9Sstevel@tonic-gate  */
3647c478bd9Sstevel@tonic-gate struct GetLine {
3657c478bd9Sstevel@tonic-gate   ErrMsg *err;               /* The error-reporting buffer */
3667c478bd9Sstevel@tonic-gate   GlHistory *glh;            /* The line-history buffer */
3677c478bd9Sstevel@tonic-gate   WordCompletion *cpl;       /* String completion resource object */
3687c478bd9Sstevel@tonic-gate   GlCplCallback cplfn;       /* The completion callback */
3697c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM
3707c478bd9Sstevel@tonic-gate   ExpandFile *ef;            /* ~user/, $envvar and wildcard expansion */
3717c478bd9Sstevel@tonic-gate                              /*  resource object. */
3727c478bd9Sstevel@tonic-gate #endif
3737c478bd9Sstevel@tonic-gate   StringGroup *capmem;       /* Memory for recording terminal capability */
3747c478bd9Sstevel@tonic-gate                              /*  strings. */
3757c478bd9Sstevel@tonic-gate   GlCharQueue *cq;           /* The terminal output character queue */
3767c478bd9Sstevel@tonic-gate   int input_fd;              /* The file descriptor to read on */
3777c478bd9Sstevel@tonic-gate   int output_fd;             /* The file descriptor to write to */
3787c478bd9Sstevel@tonic-gate   FILE *input_fp;            /* A stream wrapper around input_fd */
3797c478bd9Sstevel@tonic-gate   FILE *output_fp;           /* A stream wrapper around output_fd */
3807c478bd9Sstevel@tonic-gate   FILE *file_fp;             /* When input is being temporarily taken from */
3817c478bd9Sstevel@tonic-gate                              /*  a file, this is its file-pointer. Otherwise */
3827c478bd9Sstevel@tonic-gate                              /*  it is NULL. */
3837c478bd9Sstevel@tonic-gate   char *term;                /* The terminal type specified on the last call */
3847c478bd9Sstevel@tonic-gate                              /*  to gl_change_terminal(). */
3857c478bd9Sstevel@tonic-gate   int is_term;               /* True if stdin is a terminal */
3867c478bd9Sstevel@tonic-gate   GlWriteFn *flush_fn;       /* The function to call to write to the terminal */
3877c478bd9Sstevel@tonic-gate   GlIOMode io_mode;          /* The I/O mode established by gl_io_mode() */
3887c478bd9Sstevel@tonic-gate   int raw_mode;              /* True while the terminal is in raw mode */
3897c478bd9Sstevel@tonic-gate   GlPendingIO pending_io;    /* The type of I/O that is currently pending */
3907c478bd9Sstevel@tonic-gate   GlReturnStatus rtn_status; /* The reason why gl_get_line() returned */
3917c478bd9Sstevel@tonic-gate   int rtn_errno;             /* THe value of errno associated with rtn_status */
3927c478bd9Sstevel@tonic-gate   size_t linelen;            /* The max number of characters per line */
3937c478bd9Sstevel@tonic-gate   char *line;                /* A line-input buffer of allocated size */
3947c478bd9Sstevel@tonic-gate                              /*  linelen+2. The extra 2 characters are */
3957c478bd9Sstevel@tonic-gate                              /*  reserved for "\n\0". */
3967c478bd9Sstevel@tonic-gate   char *cutbuf;              /* A cut-buffer of the same size as line[] */
3977c478bd9Sstevel@tonic-gate   char *prompt;              /* The current prompt string */
3987c478bd9Sstevel@tonic-gate   int prompt_len;            /* The length of the prompt string */
3997c478bd9Sstevel@tonic-gate   int prompt_changed;        /* True after a callback changes the prompt */
4007c478bd9Sstevel@tonic-gate   int prompt_style;          /* How the prompt string is displayed */
4017c478bd9Sstevel@tonic-gate   FreeList *cpl_mem;         /* Memory for GlCplCallback objects */
4027c478bd9Sstevel@tonic-gate   FreeList *ext_act_mem;     /* Memory for GlExternalAction objects */
4037c478bd9Sstevel@tonic-gate   FreeList *sig_mem;         /* Memory for nodes of the signal list */
4047c478bd9Sstevel@tonic-gate   GlSignalNode *sigs;        /* The head of the list of signals */
4057c478bd9Sstevel@tonic-gate   int signals_masked;        /* True between calls to gl_mask_signals() and */
4067c478bd9Sstevel@tonic-gate                              /*  gl_unmask_signals() */
4077c478bd9Sstevel@tonic-gate   int signals_overriden;     /* True between calls to gl_override_signals() */
4087c478bd9Sstevel@tonic-gate                              /*  and gl_restore_signals() */
4097c478bd9Sstevel@tonic-gate   sigset_t all_signal_set;   /* The set of all signals that we are trapping */
4107c478bd9Sstevel@tonic-gate   sigset_t old_signal_set;   /* The set of blocked signals on entry to */
4117c478bd9Sstevel@tonic-gate                              /*  gl_get_line(). */
4127c478bd9Sstevel@tonic-gate   sigset_t use_signal_set;   /* The subset of all_signal_set to unblock */
4137c478bd9Sstevel@tonic-gate                              /*  while waiting for key-strokes */
4147c478bd9Sstevel@tonic-gate   Termios oldattr;           /* Saved terminal attributes. */
4157c478bd9Sstevel@tonic-gate   KeyTab *bindings;          /* A table of key-bindings */
4167c478bd9Sstevel@tonic-gate   int ntotal;                /* The number of characters in gl->line[] */
4177c478bd9Sstevel@tonic-gate   int buff_curpos;           /* The cursor position within gl->line[] */
4187c478bd9Sstevel@tonic-gate   int term_curpos;           /* The cursor position on the terminal */
4197c478bd9Sstevel@tonic-gate   int term_len;              /* The number of terminal characters used to */
4207c478bd9Sstevel@tonic-gate                              /*  display the current input line. */
4217c478bd9Sstevel@tonic-gate   int buff_mark;             /* A marker location in the buffer */
4227c478bd9Sstevel@tonic-gate   int insert_curpos;         /* The cursor position at start of insert */
4237c478bd9Sstevel@tonic-gate   int insert;                /* True in insert mode */
4247c478bd9Sstevel@tonic-gate   int number;                /* If >= 0, a numeric argument is being read */
4257c478bd9Sstevel@tonic-gate   int endline;               /* True to tell gl_get_input_line() to return */
4267c478bd9Sstevel@tonic-gate                              /*  the current contents of gl->line[] */
4277c478bd9Sstevel@tonic-gate   int displayed;             /* True if an input line is currently displayed */
4287c478bd9Sstevel@tonic-gate   int redisplay;             /* If true, the input line will be redrawn */
4297c478bd9Sstevel@tonic-gate                              /*  either after the current action function */
4307c478bd9Sstevel@tonic-gate                              /*  returns, or when gl_get_input_line() */
4317c478bd9Sstevel@tonic-gate                              /*  is next called. */
4327c478bd9Sstevel@tonic-gate   int postpone;              /* _gl_normal_io() sets this flag, to */
4337c478bd9Sstevel@tonic-gate                              /*  postpone any redisplays until */
4347c478bd9Sstevel@tonic-gate                              /*  is next called, to resume line editing. */
4357c478bd9Sstevel@tonic-gate   char keybuf[GL_KEY_MAX+1]; /* A buffer of currently unprocessed key presses */
4367c478bd9Sstevel@tonic-gate   int nbuf;                  /* The number of characters in keybuf[] */
4377c478bd9Sstevel@tonic-gate   int nread;                 /* The number of characters read from keybuf[] */
4387c478bd9Sstevel@tonic-gate   KtAction current_action;   /* The action function that is being invoked */
4397c478bd9Sstevel@tonic-gate   int current_count;         /* The repeat count passed to */
4407c478bd9Sstevel@tonic-gate                              /*  current_acction.fn() */
4417c478bd9Sstevel@tonic-gate   GlhLineID preload_id;      /* When not zero, this should be the ID of a */
4427c478bd9Sstevel@tonic-gate                              /*  line in the history buffer for potential */
4437c478bd9Sstevel@tonic-gate                              /*  recall. */
4447c478bd9Sstevel@tonic-gate   int preload_history;       /* If true, preload the above history line when */
4457c478bd9Sstevel@tonic-gate                              /*  gl_get_input_line() is next called. */
4467c478bd9Sstevel@tonic-gate   long keyseq_count;         /* The number of key sequences entered by the */
4477c478bd9Sstevel@tonic-gate                              /*  the user since new_GetLine() was called. */
4487c478bd9Sstevel@tonic-gate   long last_search;          /* The value of keyseq_count during the last */
4497c478bd9Sstevel@tonic-gate                              /*  history search operation. */
4507c478bd9Sstevel@tonic-gate   GlEditor editor;           /* The style of editing, (eg. vi or emacs) */
4517c478bd9Sstevel@tonic-gate   int silence_bell;          /* True if gl_ring_bell() should do nothing. */
4527c478bd9Sstevel@tonic-gate   int automatic_history;     /* True to automatically archive entered lines */
4537c478bd9Sstevel@tonic-gate                              /*  in the history list. */
4547c478bd9Sstevel@tonic-gate   ViMode vi;                 /* Parameters used when editing in vi mode */
4557c478bd9Sstevel@tonic-gate   const char *left;          /* The string that moves the cursor 1 character */
4567c478bd9Sstevel@tonic-gate                              /*  left. */
4577c478bd9Sstevel@tonic-gate   const char *right;         /* The string that moves the cursor 1 character */
4587c478bd9Sstevel@tonic-gate                              /*  right. */
4597c478bd9Sstevel@tonic-gate   const char *up;            /* The string that moves the cursor 1 character */
4607c478bd9Sstevel@tonic-gate                              /*  up. */
4617c478bd9Sstevel@tonic-gate   const char *down;          /* The string that moves the cursor 1 character */
4627c478bd9Sstevel@tonic-gate                              /*  down. */
4637c478bd9Sstevel@tonic-gate   const char *home;          /* The string that moves the cursor home */
4647c478bd9Sstevel@tonic-gate   const char *bol;           /* Move cursor to beginning of line */
4657c478bd9Sstevel@tonic-gate   const char *clear_eol;     /* The string that clears from the cursor to */
4667c478bd9Sstevel@tonic-gate                              /*  the end of the line. */
4677c478bd9Sstevel@tonic-gate   const char *clear_eod;     /* The string that clears from the cursor to */
4687c478bd9Sstevel@tonic-gate                              /*  the end of the display. */
4697c478bd9Sstevel@tonic-gate   const char *u_arrow;       /* The string returned by the up-arrow key */
4707c478bd9Sstevel@tonic-gate   const char *d_arrow;       /* The string returned by the down-arrow key */
4717c478bd9Sstevel@tonic-gate   const char *l_arrow;       /* The string returned by the left-arrow key */
4727c478bd9Sstevel@tonic-gate   const char *r_arrow;       /* The string returned by the right-arrow key */
4737c478bd9Sstevel@tonic-gate   const char *sound_bell;    /* The string needed to ring the terminal bell */
4747c478bd9Sstevel@tonic-gate   const char *bold;          /* Switch to the bold font */
4757c478bd9Sstevel@tonic-gate   const char *underline;     /* Underline subsequent characters */
4767c478bd9Sstevel@tonic-gate   const char *standout;      /* Turn on standout mode */
4777c478bd9Sstevel@tonic-gate   const char *dim;           /* Switch to a dim font */
4787c478bd9Sstevel@tonic-gate   const char *reverse;       /* Turn on reverse video */
4797c478bd9Sstevel@tonic-gate   const char *blink;         /* Switch to a blinking font */
4807c478bd9Sstevel@tonic-gate   const char *text_attr_off; /* Turn off all text attributes */
4817c478bd9Sstevel@tonic-gate   int nline;                 /* The height of the terminal in lines */
4827c478bd9Sstevel@tonic-gate   int ncolumn;               /* The width of the terminal in columns */
4837c478bd9Sstevel@tonic-gate #ifdef USE_TERMCAP
4847c478bd9Sstevel@tonic-gate   char *tgetent_buf;         /* The buffer that is used by tgetent() to */
4857c478bd9Sstevel@tonic-gate                              /*  store a terminal description. */
4867c478bd9Sstevel@tonic-gate   char *tgetstr_buf;         /* The buffer that is used by tgetstr() to */
4877c478bd9Sstevel@tonic-gate                              /*  store terminal capabilities. */
4887c478bd9Sstevel@tonic-gate #endif
4897c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
4907c478bd9Sstevel@tonic-gate   const char *left_n;        /* The parameter string that moves the cursor */
4917c478bd9Sstevel@tonic-gate                              /*  n characters left. */
4927c478bd9Sstevel@tonic-gate   const char *right_n;       /* The parameter string that moves the cursor */
4937c478bd9Sstevel@tonic-gate                              /*  n characters right. */
4947c478bd9Sstevel@tonic-gate #endif
4957c478bd9Sstevel@tonic-gate   char *app_file;            /* The pathname of the application-specific */
4967c478bd9Sstevel@tonic-gate                              /*  .teclarc configuration file, or NULL. */
4977c478bd9Sstevel@tonic-gate   char *user_file;           /* The pathname of the user-specific */
4987c478bd9Sstevel@tonic-gate                              /*  .teclarc configuration file, or NULL. */
4997c478bd9Sstevel@tonic-gate   int configured;            /* True as soon as any teclarc configuration */
5007c478bd9Sstevel@tonic-gate                              /*  file has been read. */
5017c478bd9Sstevel@tonic-gate   int echo;                  /* True to display the line as it is being */
5027c478bd9Sstevel@tonic-gate                              /*  entered. If 0, only the prompt will be */
5037c478bd9Sstevel@tonic-gate                              /*  displayed, and the line will not be */
5047c478bd9Sstevel@tonic-gate                              /*  archived in the history list. */
5057c478bd9Sstevel@tonic-gate   int last_signal;           /* The last signal that was caught by */
5067c478bd9Sstevel@tonic-gate                              /*  the last call to gl_get_line(), or -1 */
5077c478bd9Sstevel@tonic-gate                              /*  if no signal has been caught yet. */
5087c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
5097c478bd9Sstevel@tonic-gate   FreeList *fd_node_mem;     /* A freelist of GlFdNode structures */
5107c478bd9Sstevel@tonic-gate   GlFdNode *fd_nodes;        /* The list of fd event descriptions */
5117c478bd9Sstevel@tonic-gate   fd_set rfds;               /* The set of fds to watch for readability */
5127c478bd9Sstevel@tonic-gate   fd_set wfds;               /* The set of fds to watch for writability */
5137c478bd9Sstevel@tonic-gate   fd_set ufds;               /* The set of fds to watch for urgent data */
5147c478bd9Sstevel@tonic-gate   int max_fd;                /* The maximum file-descriptor being watched */
5157c478bd9Sstevel@tonic-gate   struct {                   /* Inactivity timeout related data */
5167c478bd9Sstevel@tonic-gate     struct timeval dt;       /* The inactivity timeout when timer.fn() */
5177c478bd9Sstevel@tonic-gate                              /*  isn't 0 */
5187c478bd9Sstevel@tonic-gate     GlTimeoutFn *fn;         /* The application callback to call when */
5197c478bd9Sstevel@tonic-gate                              /*  the inactivity timer expires, or 0 if */
5207c478bd9Sstevel@tonic-gate                              /*  timeouts are not required. */
5217c478bd9Sstevel@tonic-gate     void *data;              /* Application provided data to be passed to */
5227c478bd9Sstevel@tonic-gate                              /*  timer.fn(). */
5237c478bd9Sstevel@tonic-gate   } timer;
5247c478bd9Sstevel@tonic-gate #endif
5257c478bd9Sstevel@tonic-gate };
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate  * Define the max amount of space needed to store a termcap terminal
5297c478bd9Sstevel@tonic-gate  * description. Unfortunately this has to be done by guesswork, so
5307c478bd9Sstevel@tonic-gate  * there is the potential for buffer overflows if we guess too small.
5317c478bd9Sstevel@tonic-gate  * Fortunately termcap has been replaced by terminfo on most
5327c478bd9Sstevel@tonic-gate  * platforms, and with terminfo this isn't an issue. The value that I
5337c478bd9Sstevel@tonic-gate  * am using here is the conventional value, as recommended by certain
5347c478bd9Sstevel@tonic-gate  * web references.
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate #ifdef USE_TERMCAP
5377c478bd9Sstevel@tonic-gate #define TERMCAP_BUF_SIZE 2048
5387c478bd9Sstevel@tonic-gate #endif
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * Set the size of the string segments used to store terminal capability
5427c478bd9Sstevel@tonic-gate  * strings.
5437c478bd9Sstevel@tonic-gate  */
5447c478bd9Sstevel@tonic-gate #define CAPMEM_SEGMENT_SIZE 512
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate /*
5477c478bd9Sstevel@tonic-gate  * If no terminal size information is available, substitute the
5487c478bd9Sstevel@tonic-gate  * following vt100 default sizes.
5497c478bd9Sstevel@tonic-gate  */
5507c478bd9Sstevel@tonic-gate #define GL_DEF_NLINE 24
5517c478bd9Sstevel@tonic-gate #define GL_DEF_NCOLUMN 80
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate /*
5547c478bd9Sstevel@tonic-gate  * Enumerate the attributes needed to classify different types of
5557c478bd9Sstevel@tonic-gate  * signals. These attributes reflect the standard default
5567c478bd9Sstevel@tonic-gate  * characteristics of these signals (according to Richard Steven's
5577c478bd9Sstevel@tonic-gate  * Advanced Programming in the UNIX Environment). Note that these values
5587c478bd9Sstevel@tonic-gate  * are all powers of 2, so that they can be combined in a bitwise union.
5597c478bd9Sstevel@tonic-gate  */
5607c478bd9Sstevel@tonic-gate typedef enum {
5617c478bd9Sstevel@tonic-gate   GLSA_TERM=1,   /* A signal that terminates processes */
5627c478bd9Sstevel@tonic-gate   GLSA_SUSP=2,   /* A signal that suspends processes */
5637c478bd9Sstevel@tonic-gate   GLSA_CONT=4,   /* A signal that is sent when suspended processes resume */
5647c478bd9Sstevel@tonic-gate   GLSA_IGN=8,    /* A signal that is ignored */
5657c478bd9Sstevel@tonic-gate   GLSA_CORE=16,  /* A signal that generates a core dump */
5667c478bd9Sstevel@tonic-gate   GLSA_HARD=32,  /* A signal generated by a hardware exception */
5677c478bd9Sstevel@tonic-gate   GLSA_SIZE=64   /* A signal indicating terminal size changes */
5687c478bd9Sstevel@tonic-gate } GlSigAttr;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate  * List the signals that we need to catch. In general these are
5727c478bd9Sstevel@tonic-gate  * those that by default terminate or suspend the process, since
5737c478bd9Sstevel@tonic-gate  * in such cases we need to restore terminal settings.
5747c478bd9Sstevel@tonic-gate  */
5757c478bd9Sstevel@tonic-gate static const struct GlDefSignal {
5767c478bd9Sstevel@tonic-gate   int signo;            /* The number of the signal */
5777c478bd9Sstevel@tonic-gate   unsigned flags;       /* A bitwise union of GlSignalFlags enumerators */
5787c478bd9Sstevel@tonic-gate   GlAfterSignal after;  /* What to do after the signal has been delivered */
5797c478bd9Sstevel@tonic-gate   int attr;             /* The default attributes of this signal, expressed */
5807c478bd9Sstevel@tonic-gate                         /* as a bitwise union of GlSigAttr enumerators */
5817c478bd9Sstevel@tonic-gate   int errno_value;      /* What to set errno to */
5827c478bd9Sstevel@tonic-gate } gl_signal_list[] = {
5837c478bd9Sstevel@tonic-gate   {SIGABRT,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
5847c478bd9Sstevel@tonic-gate   {SIGALRM,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM,           0},
5857c478bd9Sstevel@tonic-gate   {SIGCONT,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_CONT|GLSA_IGN,  0},
5867c478bd9Sstevel@tonic-gate #if defined(SIGHUP)
5877c478bd9Sstevel@tonic-gate #ifdef ENOTTY
5887c478bd9Sstevel@tonic-gate   {SIGHUP,    GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           ENOTTY},
5897c478bd9Sstevel@tonic-gate #else
5907c478bd9Sstevel@tonic-gate   {SIGHUP,    GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
5917c478bd9Sstevel@tonic-gate #endif
5927c478bd9Sstevel@tonic-gate #endif
5937c478bd9Sstevel@tonic-gate   {SIGINT,    GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
5947c478bd9Sstevel@tonic-gate #if defined(SIGPIPE)
5957c478bd9Sstevel@tonic-gate #ifdef EPIPE
5967c478bd9Sstevel@tonic-gate   {SIGPIPE,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EPIPE},
5977c478bd9Sstevel@tonic-gate #else
5987c478bd9Sstevel@tonic-gate   {SIGPIPE,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
5997c478bd9Sstevel@tonic-gate #endif
6007c478bd9Sstevel@tonic-gate #endif
6017c478bd9Sstevel@tonic-gate #ifdef SIGPOLL
6027c478bd9Sstevel@tonic-gate   {SIGPOLL,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
6037c478bd9Sstevel@tonic-gate #endif
6047c478bd9Sstevel@tonic-gate #ifdef SIGPWR
6057c478bd9Sstevel@tonic-gate   {SIGPWR,    GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_IGN,            0},
6067c478bd9Sstevel@tonic-gate #endif
6077c478bd9Sstevel@tonic-gate #ifdef SIGQUIT
6087c478bd9Sstevel@tonic-gate   {SIGQUIT,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR},
6097c478bd9Sstevel@tonic-gate #endif
6107c478bd9Sstevel@tonic-gate   {SIGTERM,   GLS_SUSPEND_INPUT,    GLS_ABORT, GLSA_TERM,           EINTR},
6117c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
6127c478bd9Sstevel@tonic-gate   {SIGTSTP,   GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP,           0},
6137c478bd9Sstevel@tonic-gate #endif
6147c478bd9Sstevel@tonic-gate #ifdef SIGTTIN
6157c478bd9Sstevel@tonic-gate   {SIGTTIN,   GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP,           0},
6167c478bd9Sstevel@tonic-gate #endif
6177c478bd9Sstevel@tonic-gate #ifdef SIGTTOU
6187c478bd9Sstevel@tonic-gate   {SIGTTOU,   GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP,           0},
6197c478bd9Sstevel@tonic-gate #endif
6207c478bd9Sstevel@tonic-gate #ifdef SIGUSR1
6217c478bd9Sstevel@tonic-gate   {SIGUSR1,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM,           0},
6227c478bd9Sstevel@tonic-gate #endif
6237c478bd9Sstevel@tonic-gate #ifdef SIGUSR2
6247c478bd9Sstevel@tonic-gate   {SIGUSR2,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM,           0},
6257c478bd9Sstevel@tonic-gate #endif
6267c478bd9Sstevel@tonic-gate #ifdef SIGVTALRM
6277c478bd9Sstevel@tonic-gate   {SIGVTALRM, GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM,           0},
6287c478bd9Sstevel@tonic-gate #endif
6297c478bd9Sstevel@tonic-gate #ifdef SIGWINCH
6307c478bd9Sstevel@tonic-gate   {SIGWINCH,  GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_SIZE|GLSA_IGN,  0},
6317c478bd9Sstevel@tonic-gate #endif
6327c478bd9Sstevel@tonic-gate #ifdef SIGXCPU
6337c478bd9Sstevel@tonic-gate   {SIGXCPU,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
6347c478bd9Sstevel@tonic-gate #endif
6357c478bd9Sstevel@tonic-gate #ifdef SIGXFSZ
6367c478bd9Sstevel@tonic-gate   {SIGXFSZ,   GLS_RESTORE_ENV,   GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0},
6377c478bd9Sstevel@tonic-gate #endif
6387c478bd9Sstevel@tonic-gate };
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate  * Define file-scope variables for use in signal handlers.
6427c478bd9Sstevel@tonic-gate  */
6437c478bd9Sstevel@tonic-gate static volatile sig_atomic_t gl_pending_signal = -1;
6447c478bd9Sstevel@tonic-gate static sigjmp_buf gl_setjmp_buffer;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate static void gl_signal_handler(int signo);
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate static int gl_check_caught_signal(GetLine *gl);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate /*
6517c478bd9Sstevel@tonic-gate  * Respond to an externally caught process suspension or
6527c478bd9Sstevel@tonic-gate  * termination signal.
6537c478bd9Sstevel@tonic-gate  */
6547c478bd9Sstevel@tonic-gate static void gl_suspend_process(int signo, GetLine *gl, int ngl);
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate /* Return the default attributes of a given signal */
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate static int gl_classify_signal(int signo);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate  * Unfortunately both terminfo and termcap require one to use the tputs()
6627c478bd9Sstevel@tonic-gate  * function to output terminal control characters, and this function
6637c478bd9Sstevel@tonic-gate  * doesn't allow one to specify a file stream. As a result, the following
6647c478bd9Sstevel@tonic-gate  * file-scope variable is used to pass the current output file stream.
6657c478bd9Sstevel@tonic-gate  * This is bad, but there doesn't seem to be any alternative.
6667c478bd9Sstevel@tonic-gate  */
6677c478bd9Sstevel@tonic-gate static GetLine *tputs_gl = NULL;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate /*
6707c478bd9Sstevel@tonic-gate  * Define a tab to be a string of 8 spaces.
6717c478bd9Sstevel@tonic-gate  */
6727c478bd9Sstevel@tonic-gate #define TAB_WIDTH 8
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate /*
6757c478bd9Sstevel@tonic-gate  * Lookup the current size of the terminal.
6767c478bd9Sstevel@tonic-gate  */
6777c478bd9Sstevel@tonic-gate static void gl_query_size(GetLine *gl, int *ncolumn, int *nline);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate  * Getline calls this to temporarily override certain signal handlers
6817c478bd9Sstevel@tonic-gate  * of the calling program.
6827c478bd9Sstevel@tonic-gate  */
6837c478bd9Sstevel@tonic-gate static int gl_override_signal_handlers(GetLine *gl);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate /*
6867c478bd9Sstevel@tonic-gate  * Getline calls this to restore the signal handlers of the calling
6877c478bd9Sstevel@tonic-gate  * program.
6887c478bd9Sstevel@tonic-gate  */
6897c478bd9Sstevel@tonic-gate static int gl_restore_signal_handlers(GetLine *gl);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate  * Temporarily block the delivery of all signals that gl_get_line()
6937c478bd9Sstevel@tonic-gate  * is currently configured to trap.
6947c478bd9Sstevel@tonic-gate  */
6957c478bd9Sstevel@tonic-gate static int gl_mask_signals(GetLine *gl, sigset_t *oldset);
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate /*
6987c478bd9Sstevel@tonic-gate  * Restore the process signal mask that was overriden by a previous
6997c478bd9Sstevel@tonic-gate  * call to gl_mask_signals().
7007c478bd9Sstevel@tonic-gate  */
7017c478bd9Sstevel@tonic-gate static int gl_unmask_signals(GetLine *gl, sigset_t *oldset);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate /*
7047c478bd9Sstevel@tonic-gate  * Unblock the signals that gl_get_line() has been configured to catch.
7057c478bd9Sstevel@tonic-gate  */
7067c478bd9Sstevel@tonic-gate static int gl_catch_signals(GetLine *gl);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate /*
7097c478bd9Sstevel@tonic-gate  * Return the set of all trappable signals.
7107c478bd9Sstevel@tonic-gate  */
7117c478bd9Sstevel@tonic-gate static void gl_list_trappable_signals(sigset_t *signals);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate /*
7147c478bd9Sstevel@tonic-gate  * Put the terminal into raw input mode, after saving the original
7157c478bd9Sstevel@tonic-gate  * terminal attributes in gl->oldattr.
7167c478bd9Sstevel@tonic-gate  */
7177c478bd9Sstevel@tonic-gate static int gl_raw_terminal_mode(GetLine *gl);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate  * Restore the terminal attributes from gl->oldattr.
7217c478bd9Sstevel@tonic-gate  */
7227c478bd9Sstevel@tonic-gate static int gl_restore_terminal_attributes(GetLine *gl);
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate /*
7257c478bd9Sstevel@tonic-gate  * Switch to non-blocking I/O if possible.
7267c478bd9Sstevel@tonic-gate  */
7277c478bd9Sstevel@tonic-gate static int gl_nonblocking_io(GetLine *gl, int fd);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate /*
7307c478bd9Sstevel@tonic-gate  * Switch to blocking I/O if possible.
7317c478bd9Sstevel@tonic-gate  */
7327c478bd9Sstevel@tonic-gate static int gl_blocking_io(GetLine *gl, int fd);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate /*
7357c478bd9Sstevel@tonic-gate  * Read a line from the user in raw mode.
7367c478bd9Sstevel@tonic-gate  */
7377c478bd9Sstevel@tonic-gate static int gl_get_input_line(GetLine *gl, const char *prompt,
7387c478bd9Sstevel@tonic-gate 			     const char *start_line, int start_pos);
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate  * Query the user for a single character.
7427c478bd9Sstevel@tonic-gate  */
7437c478bd9Sstevel@tonic-gate static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar);
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate /*
7467c478bd9Sstevel@tonic-gate  * Read input from a non-interactive input stream.
7477c478bd9Sstevel@tonic-gate  */
7487c478bd9Sstevel@tonic-gate static int gl_read_stream_line(GetLine *gl);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate /*
7517c478bd9Sstevel@tonic-gate  * Read a single character from a non-interactive input stream.
7527c478bd9Sstevel@tonic-gate  */
7537c478bd9Sstevel@tonic-gate static int gl_read_stream_char(GetLine *gl);
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate /*
7567c478bd9Sstevel@tonic-gate  * Prepare to edit a new line.
7577c478bd9Sstevel@tonic-gate  */
7587c478bd9Sstevel@tonic-gate static int gl_present_line(GetLine *gl, const char *prompt,
7597c478bd9Sstevel@tonic-gate 			   const char *start_line, int start_pos);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate /*
7627c478bd9Sstevel@tonic-gate  * Reset all line input parameters for a new input line.
7637c478bd9Sstevel@tonic-gate  */
7647c478bd9Sstevel@tonic-gate static void gl_reset_input_line(GetLine *gl);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate /*
7677c478bd9Sstevel@tonic-gate  * Handle the receipt of the potential start of a new key-sequence from
7687c478bd9Sstevel@tonic-gate  * the user.
7697c478bd9Sstevel@tonic-gate  */
7707c478bd9Sstevel@tonic-gate static int gl_interpret_char(GetLine *gl, char c);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate /*
7737c478bd9Sstevel@tonic-gate  * Bind a single control or meta character to an action.
7747c478bd9Sstevel@tonic-gate  */
7757c478bd9Sstevel@tonic-gate static int gl_bind_control_char(GetLine *gl, KtBinder binder,
7767c478bd9Sstevel@tonic-gate 				char c, const char *action);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate /*
7797c478bd9Sstevel@tonic-gate  * Set up terminal-specific key bindings.
7807c478bd9Sstevel@tonic-gate  */
7817c478bd9Sstevel@tonic-gate static int gl_bind_terminal_keys(GetLine *gl);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate /*
7847c478bd9Sstevel@tonic-gate  * Lookup terminal control string and size information.
7857c478bd9Sstevel@tonic-gate  */
7867c478bd9Sstevel@tonic-gate static int gl_control_strings(GetLine *gl, const char *term);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate  * Wrappers around the terminfo and termcap functions that lookup
7907c478bd9Sstevel@tonic-gate  * strings in the terminal information databases.
7917c478bd9Sstevel@tonic-gate  */
7927c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
7937c478bd9Sstevel@tonic-gate static const char *gl_tigetstr(GetLine *gl, const char *name);
7947c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP)
7957c478bd9Sstevel@tonic-gate static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr);
7967c478bd9Sstevel@tonic-gate #endif
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate /*
7997c478bd9Sstevel@tonic-gate  * Output a binary string directly to the terminal.
8007c478bd9Sstevel@tonic-gate  */
8017c478bd9Sstevel@tonic-gate static int gl_print_raw_string(GetLine *gl, int buffered,
8027c478bd9Sstevel@tonic-gate 			       const char *string, int n);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate /*
8057c478bd9Sstevel@tonic-gate  * Print an informational message, starting and finishing on new lines.
8067c478bd9Sstevel@tonic-gate  * After the list of strings to be printed, the last argument MUST be
8077c478bd9Sstevel@tonic-gate  * GL_END_INFO.
8087c478bd9Sstevel@tonic-gate  */
8097c478bd9Sstevel@tonic-gate static int gl_print_info(GetLine *gl, ...);
8107c478bd9Sstevel@tonic-gate #define GL_END_INFO ((const char *)0)
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate /*
8137c478bd9Sstevel@tonic-gate  * Start a newline and place the cursor at its start.
8147c478bd9Sstevel@tonic-gate  */
8157c478bd9Sstevel@tonic-gate static int gl_start_newline(GetLine *gl, int buffered);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate /*
8187c478bd9Sstevel@tonic-gate  * Output a terminal control sequence.
8197c478bd9Sstevel@tonic-gate  */
8207c478bd9Sstevel@tonic-gate static int gl_print_control_sequence(GetLine *gl, int nline,
8217c478bd9Sstevel@tonic-gate 				     const char *string);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate /*
8247c478bd9Sstevel@tonic-gate  * Output a character or string to the terminal after converting tabs
8257c478bd9Sstevel@tonic-gate  * to spaces and control characters to a caret followed by the modified
8267c478bd9Sstevel@tonic-gate  * character.
8277c478bd9Sstevel@tonic-gate  */
8287c478bd9Sstevel@tonic-gate static int gl_print_char(GetLine *gl, char c, char pad);
8297c478bd9Sstevel@tonic-gate static int gl_print_string(GetLine *gl, const char *string, char pad);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate /*
8327c478bd9Sstevel@tonic-gate  * Delete nc characters starting from the one under the cursor.
8337c478bd9Sstevel@tonic-gate  * Optionally copy the deleted characters to the cut buffer.
8347c478bd9Sstevel@tonic-gate  */
8357c478bd9Sstevel@tonic-gate static int gl_delete_chars(GetLine *gl, int nc, int cut);
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate /*
8387c478bd9Sstevel@tonic-gate  * Add a character to the line buffer at the current cursor position,
8397c478bd9Sstevel@tonic-gate  * inserting or overwriting according the current mode.
8407c478bd9Sstevel@tonic-gate  */
8417c478bd9Sstevel@tonic-gate static int gl_add_char_to_line(GetLine *gl, char c);
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate  * Insert/append a string to the line buffer and terminal at the current
8457c478bd9Sstevel@tonic-gate  * cursor position.
8467c478bd9Sstevel@tonic-gate  */
8477c478bd9Sstevel@tonic-gate static int gl_add_string_to_line(GetLine *gl, const char *s);
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate /*
8507c478bd9Sstevel@tonic-gate  * Record a new character in the input-line buffer.
8517c478bd9Sstevel@tonic-gate  */
8527c478bd9Sstevel@tonic-gate static int gl_buffer_char(GetLine *gl, char c, int bufpos);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate /*
8557c478bd9Sstevel@tonic-gate  * Record a string in the input-line buffer.
8567c478bd9Sstevel@tonic-gate  */
8577c478bd9Sstevel@tonic-gate static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate /*
8607c478bd9Sstevel@tonic-gate  * Make way to insert a string in the input-line buffer.
8617c478bd9Sstevel@tonic-gate  */
8627c478bd9Sstevel@tonic-gate static int gl_make_gap_in_buffer(GetLine *gl, int start, int n);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate  * Remove characters from the input-line buffer, and move any characters
8667c478bd9Sstevel@tonic-gate  * that followed them to the start of the vacated space.
8677c478bd9Sstevel@tonic-gate  */
8687c478bd9Sstevel@tonic-gate static void gl_remove_from_buffer(GetLine *gl, int start, int n);
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate  * Terminate the input-line buffer after a specified number of characters.
8727c478bd9Sstevel@tonic-gate  */
8737c478bd9Sstevel@tonic-gate static int gl_truncate_buffer(GetLine *gl, int n);
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate /*
8767c478bd9Sstevel@tonic-gate  * Delete the displayed part of the input line that follows the current
8777c478bd9Sstevel@tonic-gate  * terminal cursor position.
8787c478bd9Sstevel@tonic-gate  */
8797c478bd9Sstevel@tonic-gate static int gl_truncate_display(GetLine *gl);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate /*
8827c478bd9Sstevel@tonic-gate  * Accomodate changes to the contents of the input line buffer
8837c478bd9Sstevel@tonic-gate  * that weren't made by the above gl_*buffer functions.
8847c478bd9Sstevel@tonic-gate  */
8857c478bd9Sstevel@tonic-gate static void gl_update_buffer(GetLine *gl);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate /*
8887c478bd9Sstevel@tonic-gate  * Read a single character from the terminal.
8897c478bd9Sstevel@tonic-gate  */
8907c478bd9Sstevel@tonic-gate static int gl_read_terminal(GetLine *gl, int keep, char *c);
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate /*
8937c478bd9Sstevel@tonic-gate  * Discard processed characters from the key-press lookahead buffer.
8947c478bd9Sstevel@tonic-gate  */
8957c478bd9Sstevel@tonic-gate static void gl_discard_chars(GetLine *gl, int nused);
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate /*
8987c478bd9Sstevel@tonic-gate  * Move the terminal cursor n positions to the left or right.
8997c478bd9Sstevel@tonic-gate  */
9007c478bd9Sstevel@tonic-gate static int gl_terminal_move_cursor(GetLine *gl, int n);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate /*
9037c478bd9Sstevel@tonic-gate  * Move the terminal cursor to a given position.
9047c478bd9Sstevel@tonic-gate  */
9057c478bd9Sstevel@tonic-gate static int gl_set_term_curpos(GetLine *gl, int term_curpos);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate /*
9087c478bd9Sstevel@tonic-gate  * Set the position of the cursor both in the line input buffer and on the
9097c478bd9Sstevel@tonic-gate  * terminal.
9107c478bd9Sstevel@tonic-gate  */
9117c478bd9Sstevel@tonic-gate static int gl_place_cursor(GetLine *gl, int buff_curpos);
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate /*
9147c478bd9Sstevel@tonic-gate  * How many characters are needed to write a number as an octal string?
9157c478bd9Sstevel@tonic-gate  */
9167c478bd9Sstevel@tonic-gate static int gl_octal_width(unsigned num);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate /*
9197c478bd9Sstevel@tonic-gate  * Return the number of spaces needed to display a tab character at
9207c478bd9Sstevel@tonic-gate  * a given location of the terminal.
9217c478bd9Sstevel@tonic-gate  */
9227c478bd9Sstevel@tonic-gate static int gl_displayed_tab_width(GetLine *gl, int term_curpos);
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate /*
9257c478bd9Sstevel@tonic-gate  * Return the number of terminal characters needed to display a
9267c478bd9Sstevel@tonic-gate  * given raw character.
9277c478bd9Sstevel@tonic-gate  */
9287c478bd9Sstevel@tonic-gate static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos);
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate /*
9317c478bd9Sstevel@tonic-gate  * Return the number of terminal characters needed to display a
9327c478bd9Sstevel@tonic-gate  * given substring.
9337c478bd9Sstevel@tonic-gate  */
9347c478bd9Sstevel@tonic-gate static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
9357c478bd9Sstevel@tonic-gate 				     int term_curpos);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate /*
9387c478bd9Sstevel@tonic-gate  * Return non-zero if 'c' is to be considered part of a word.
9397c478bd9Sstevel@tonic-gate  */
9407c478bd9Sstevel@tonic-gate static int gl_is_word_char(int c);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate /*
9437c478bd9Sstevel@tonic-gate  * Read a tecla configuration file.
9447c478bd9Sstevel@tonic-gate  */
9457c478bd9Sstevel@tonic-gate static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who);
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate /*
9487c478bd9Sstevel@tonic-gate  * Read a tecla configuration string.
9497c478bd9Sstevel@tonic-gate  */
9507c478bd9Sstevel@tonic-gate static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who);
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate /*
9537c478bd9Sstevel@tonic-gate  * Define the callback function used by _gl_parse_config_line() to
9547c478bd9Sstevel@tonic-gate  * read the next character of a configuration stream.
9557c478bd9Sstevel@tonic-gate  */
9567c478bd9Sstevel@tonic-gate #define GLC_GETC_FN(fn) int (fn)(void *stream)
9577c478bd9Sstevel@tonic-gate typedef GLC_GETC_FN(GlcGetcFn);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate static GLC_GETC_FN(glc_file_getc);  /* Read from a file */
9607c478bd9Sstevel@tonic-gate static GLC_GETC_FN(glc_buff_getc);  /* Read from a string */
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate /*
9637c478bd9Sstevel@tonic-gate  * Parse a single configuration command line.
9647c478bd9Sstevel@tonic-gate  */
9657c478bd9Sstevel@tonic-gate static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
9667c478bd9Sstevel@tonic-gate 				 const char *origin, KtBinder who, int *lineno);
9677c478bd9Sstevel@tonic-gate static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
9687c478bd9Sstevel@tonic-gate 				  const char *errmsg);
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate  * Bind the actual arrow key bindings to match those of the symbolic
9727c478bd9Sstevel@tonic-gate  * arrow-key bindings.
9737c478bd9Sstevel@tonic-gate  */
9747c478bd9Sstevel@tonic-gate static int _gl_bind_arrow_keys(GetLine *gl);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate /*
9777c478bd9Sstevel@tonic-gate  * Copy the binding of the specified symbolic arrow-key binding to
9787c478bd9Sstevel@tonic-gate  * the terminal specific, and default arrow-key key-sequences.
9797c478bd9Sstevel@tonic-gate  */
9807c478bd9Sstevel@tonic-gate static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
9817c478bd9Sstevel@tonic-gate 				const char *term_seq,
9827c478bd9Sstevel@tonic-gate 				const char *def_seq1,
9837c478bd9Sstevel@tonic-gate 				const char *def_seq2);
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate  * After the gl_read_from_file() action has been used to tell gl_get_line()
9877c478bd9Sstevel@tonic-gate  * to temporarily read input from a file, gl_revert_input() arranges
9887c478bd9Sstevel@tonic-gate  * for input to be reverted to the input stream last registered with
9897c478bd9Sstevel@tonic-gate  * gl_change_terminal().
9907c478bd9Sstevel@tonic-gate  */
9917c478bd9Sstevel@tonic-gate static void gl_revert_input(GetLine *gl);
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate /*
9947c478bd9Sstevel@tonic-gate  * Flush unwritten characters to the terminal.
9957c478bd9Sstevel@tonic-gate  */
9967c478bd9Sstevel@tonic-gate static int gl_flush_output(GetLine *gl);
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate  * The callback through which all terminal output is routed.
10007c478bd9Sstevel@tonic-gate  * This simply appends characters to a queue buffer, which is
10017c478bd9Sstevel@tonic-gate  * subsequently flushed to the output channel by gl_flush_output().
10027c478bd9Sstevel@tonic-gate  */
10037c478bd9Sstevel@tonic-gate static GL_WRITE_FN(gl_write_fn);
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate /*
10067c478bd9Sstevel@tonic-gate  * The callback function which the output character queue object
10077c478bd9Sstevel@tonic-gate  * calls to transfer characters to the output channel.
10087c478bd9Sstevel@tonic-gate  */
10097c478bd9Sstevel@tonic-gate static GL_WRITE_FN(gl_flush_terminal);
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate /*
10127c478bd9Sstevel@tonic-gate  * Enumerate the possible return statuses of gl_read_input().
10137c478bd9Sstevel@tonic-gate  */
10147c478bd9Sstevel@tonic-gate typedef enum {
10157c478bd9Sstevel@tonic-gate   GL_READ_OK,      /* A character was read successfully */
10167c478bd9Sstevel@tonic-gate   GL_READ_ERROR,   /* A read-error occurred */
10177c478bd9Sstevel@tonic-gate   GL_READ_BLOCKED, /* The read would have blocked the caller */
10187c478bd9Sstevel@tonic-gate   GL_READ_EOF      /* The end of the current input file was reached */
10197c478bd9Sstevel@tonic-gate } GlReadStatus;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate static GlReadStatus gl_read_input(GetLine *gl, char *c);
10227c478bd9Sstevel@tonic-gate /*
10237c478bd9Sstevel@tonic-gate  * Private functions of gl_read_input().
10247c478bd9Sstevel@tonic-gate  */
10257c478bd9Sstevel@tonic-gate static int gl_event_handler(GetLine *gl, int fd);
10267c478bd9Sstevel@tonic-gate static int gl_read_unmasked(GetLine *gl, int fd, char *c);
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate /*
10307c478bd9Sstevel@tonic-gate  * A private function of gl_tty_signals().
10317c478bd9Sstevel@tonic-gate  */
10327c478bd9Sstevel@tonic-gate static int gl_set_tty_signal(int signo, void (*handler)(int));
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate  * Change the editor style being emulated.
10367c478bd9Sstevel@tonic-gate  */
10377c478bd9Sstevel@tonic-gate static int gl_change_editor(GetLine *gl, GlEditor editor);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate /*
10407c478bd9Sstevel@tonic-gate  * Searching in a given direction, return the index of a given (or
10417c478bd9Sstevel@tonic-gate  * read) character in the input line, or the character that precedes
10427c478bd9Sstevel@tonic-gate  * it in the specified search direction. Return -1 if not found.
10437c478bd9Sstevel@tonic-gate  */
10447c478bd9Sstevel@tonic-gate static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate /*
10477c478bd9Sstevel@tonic-gate  * Return the buffer index of the nth word ending after the cursor.
10487c478bd9Sstevel@tonic-gate  */
10497c478bd9Sstevel@tonic-gate static int gl_nth_word_end_forward(GetLine *gl, int n);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate /*
10527c478bd9Sstevel@tonic-gate  * Return the buffer index of the nth word start after the cursor.
10537c478bd9Sstevel@tonic-gate  */
10547c478bd9Sstevel@tonic-gate static int gl_nth_word_start_forward(GetLine *gl, int n);
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate /*
10577c478bd9Sstevel@tonic-gate  * Return the buffer index of the nth word start before the cursor.
10587c478bd9Sstevel@tonic-gate  */
10597c478bd9Sstevel@tonic-gate static int gl_nth_word_start_backward(GetLine *gl, int n);
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate /*
10627c478bd9Sstevel@tonic-gate  * When called when vi command mode is enabled, this function saves the
10637c478bd9Sstevel@tonic-gate  * current line and cursor position for potential restoration later
10647c478bd9Sstevel@tonic-gate  * by the vi undo command.
10657c478bd9Sstevel@tonic-gate  */
10667c478bd9Sstevel@tonic-gate static void gl_save_for_undo(GetLine *gl);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate /*
10697c478bd9Sstevel@tonic-gate  * If in vi mode, switch to vi command mode.
10707c478bd9Sstevel@tonic-gate  */
10717c478bd9Sstevel@tonic-gate static void gl_vi_command_mode(GetLine *gl);
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate /*
10747c478bd9Sstevel@tonic-gate  * In vi mode this is used to delete up to or onto a given or read
10757c478bd9Sstevel@tonic-gate  * character in the input line. Also switch to insert mode if requested
10767c478bd9Sstevel@tonic-gate  * after the deletion.
10777c478bd9Sstevel@tonic-gate  */
10787c478bd9Sstevel@tonic-gate static int gl_delete_find(GetLine *gl, int count, char c, int forward,
10797c478bd9Sstevel@tonic-gate 			  int onto, int change);
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate /*
10827c478bd9Sstevel@tonic-gate  * Copy the characters between the cursor and the count'th instance of
10837c478bd9Sstevel@tonic-gate  * a specified (or read) character in the input line, into the cut buffer.
10847c478bd9Sstevel@tonic-gate  */
10857c478bd9Sstevel@tonic-gate static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto);
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate /*
10887c478bd9Sstevel@tonic-gate  * Return the line index of the parenthesis that either matches the one under
10897c478bd9Sstevel@tonic-gate  * the cursor, or not over a parenthesis character, the index of the next
10907c478bd9Sstevel@tonic-gate  * close parenthesis. Return -1 if not found.
10917c478bd9Sstevel@tonic-gate  */
10927c478bd9Sstevel@tonic-gate static int gl_index_of_matching_paren(GetLine *gl);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate /*
10957c478bd9Sstevel@tonic-gate  * Replace a malloc'd string (or NULL), with another malloc'd copy of
10967c478bd9Sstevel@tonic-gate  * a string (or NULL).
10977c478bd9Sstevel@tonic-gate  */
10987c478bd9Sstevel@tonic-gate static int gl_record_string(char **sptr, const char *string);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate /*
11017c478bd9Sstevel@tonic-gate  * Enumerate text display attributes as powers of two, suitable for
11027c478bd9Sstevel@tonic-gate  * use in a bit-mask.
11037c478bd9Sstevel@tonic-gate  */
11047c478bd9Sstevel@tonic-gate typedef enum {
11057c478bd9Sstevel@tonic-gate   GL_TXT_STANDOUT=1,   /* Display text highlighted */
11067c478bd9Sstevel@tonic-gate   GL_TXT_UNDERLINE=2,  /* Display text underlined */
11077c478bd9Sstevel@tonic-gate   GL_TXT_REVERSE=4,    /* Display text with reverse video */
11087c478bd9Sstevel@tonic-gate   GL_TXT_BLINK=8,      /* Display blinking text */
11097c478bd9Sstevel@tonic-gate   GL_TXT_DIM=16,       /* Display text in a dim font */
11107c478bd9Sstevel@tonic-gate   GL_TXT_BOLD=32       /* Display text using a bold font */
11117c478bd9Sstevel@tonic-gate } GlTextAttr;
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate /*
11147c478bd9Sstevel@tonic-gate  * Display the prompt regardless of the current visibility mode.
11157c478bd9Sstevel@tonic-gate  */
11167c478bd9Sstevel@tonic-gate static int gl_display_prompt(GetLine *gl);
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate /*
11197c478bd9Sstevel@tonic-gate  * Return the number of characters used by the prompt on the terminal.
11207c478bd9Sstevel@tonic-gate  */
11217c478bd9Sstevel@tonic-gate static int gl_displayed_prompt_width(GetLine *gl);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate /*
11247c478bd9Sstevel@tonic-gate  * Prepare to return the current input line to the caller of gl_get_line().
11257c478bd9Sstevel@tonic-gate  */
11267c478bd9Sstevel@tonic-gate static int gl_line_ended(GetLine *gl, int newline_char);
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate /*
11297c478bd9Sstevel@tonic-gate  * Arrange for the input line to be redisplayed when the current contents
11307c478bd9Sstevel@tonic-gate  * of the output queue have been flushed.
11317c478bd9Sstevel@tonic-gate  */
11327c478bd9Sstevel@tonic-gate static void gl_queue_redisplay(GetLine *gl);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate /*
11357c478bd9Sstevel@tonic-gate  * Erase the displayed representation of the input line, without
11367c478bd9Sstevel@tonic-gate  * touching the buffered copy.
11377c478bd9Sstevel@tonic-gate  */
11387c478bd9Sstevel@tonic-gate static int gl_erase_line(GetLine *gl);
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate /*
11417c478bd9Sstevel@tonic-gate  * This function is called whenever the input line has been erased.
11427c478bd9Sstevel@tonic-gate  */
11437c478bd9Sstevel@tonic-gate static void gl_line_erased(GetLine *gl);
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate /*
11467c478bd9Sstevel@tonic-gate  * Arrange for the current input line to be discarded.
11477c478bd9Sstevel@tonic-gate  */
11487c478bd9Sstevel@tonic-gate void _gl_abandon_line(GetLine *gl);
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate /*
11517c478bd9Sstevel@tonic-gate  * The following are private internally callable versions of pertinent
11527c478bd9Sstevel@tonic-gate  * public functions. Unlike their public wrapper functions, they don't
11537c478bd9Sstevel@tonic-gate  * block signals while running, and assume that their arguments are valid.
11547c478bd9Sstevel@tonic-gate  * They are designed to be called from places where signals are already
11557c478bd9Sstevel@tonic-gate  * blocked, and where simple sanity checks have already been applied to
11567c478bd9Sstevel@tonic-gate  * their arguments.
11577c478bd9Sstevel@tonic-gate  */
11587c478bd9Sstevel@tonic-gate static char *_gl_get_line(GetLine *gl, const char *prompt,
11597c478bd9Sstevel@tonic-gate 			  const char *start_line, int start_pos);
11607c478bd9Sstevel@tonic-gate static int _gl_query_char(GetLine *gl, const char *prompt, char defchar);
11617c478bd9Sstevel@tonic-gate static int _gl_read_char(GetLine *gl);
11627c478bd9Sstevel@tonic-gate static int _gl_update_size(GetLine *gl);
11637c478bd9Sstevel@tonic-gate /*
11647c478bd9Sstevel@tonic-gate  * Redraw the current input line to account for a change in the terminal
11657c478bd9Sstevel@tonic-gate  * size. Also install the new size in gl.
11667c478bd9Sstevel@tonic-gate  */
11677c478bd9Sstevel@tonic-gate static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
11707c478bd9Sstevel@tonic-gate 			       const char *term);
11717c478bd9Sstevel@tonic-gate static int _gl_configure_getline(GetLine *gl, const char *app_string,
11727c478bd9Sstevel@tonic-gate 				 const char *app_file, const char *user_file);
11737c478bd9Sstevel@tonic-gate static int _gl_save_history(GetLine *gl, const char *filename,
11747c478bd9Sstevel@tonic-gate 			    const char *comment, int max_lines);
11757c478bd9Sstevel@tonic-gate static int _gl_load_history(GetLine *gl, const char *filename,
11767c478bd9Sstevel@tonic-gate 			    const char *comment);
11777c478bd9Sstevel@tonic-gate static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
11787c478bd9Sstevel@tonic-gate 			GlFdEventFn *callback, void *data);
11797c478bd9Sstevel@tonic-gate static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
11807c478bd9Sstevel@tonic-gate 			      GlTerminalSize *size);
11817c478bd9Sstevel@tonic-gate static void _gl_replace_prompt(GetLine *gl, const char *prompt);
11827c478bd9Sstevel@tonic-gate static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
11837c478bd9Sstevel@tonic-gate 			   GlAfterSignal after, int errno_value);
11847c478bd9Sstevel@tonic-gate static int _gl_raw_io(GetLine *gl, int redisplay);
11857c478bd9Sstevel@tonic-gate static int _gl_normal_io(GetLine *gl);
11867c478bd9Sstevel@tonic-gate static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
11877c478bd9Sstevel@tonic-gate 				 int list_only, const char *name,
11887c478bd9Sstevel@tonic-gate 				 const char *keyseq);
11897c478bd9Sstevel@tonic-gate static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
11907c478bd9Sstevel@tonic-gate 			       const char *name, const char *keyseq);
11917c478bd9Sstevel@tonic-gate static int _gl_io_mode(GetLine *gl, GlIOMode mode);
11927c478bd9Sstevel@tonic-gate static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline);
11937c478bd9Sstevel@tonic-gate static int _gl_append_history(GetLine *gl, const char *line);
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate /*
11967c478bd9Sstevel@tonic-gate  * Reset the completion status and associated errno value in
11977c478bd9Sstevel@tonic-gate  * gl->rtn_status and gl->rtn_errno.
11987c478bd9Sstevel@tonic-gate  */
11997c478bd9Sstevel@tonic-gate static void gl_clear_status(GetLine *gl);
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate /*
12027c478bd9Sstevel@tonic-gate  * Record a completion status, unless a previous abnormal completion
12037c478bd9Sstevel@tonic-gate  * status has already been recorded for the current call.
12047c478bd9Sstevel@tonic-gate  */
12057c478bd9Sstevel@tonic-gate static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
12067c478bd9Sstevel@tonic-gate 			     int rtn_errno);
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate /*
12097c478bd9Sstevel@tonic-gate  * Set the maximum length of a line in a user's tecla configuration
12107c478bd9Sstevel@tonic-gate  * file (not counting comments).
12117c478bd9Sstevel@tonic-gate  */
12127c478bd9Sstevel@tonic-gate #define GL_CONF_BUFLEN 100
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate /*
12157c478bd9Sstevel@tonic-gate  * Set the maximum number of arguments supported by individual commands
12167c478bd9Sstevel@tonic-gate  * in tecla configuration files.
12177c478bd9Sstevel@tonic-gate  */
12187c478bd9Sstevel@tonic-gate #define GL_CONF_MAXARG 10
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate /*
12217c478bd9Sstevel@tonic-gate  * Prototype the available action functions.
12227c478bd9Sstevel@tonic-gate  */
12237c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_user_interrupt);
12247c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_abort);
12257c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_suspend);
12267c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_stop_output);
12277c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_start_output);
12287c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_literal_next);
12297c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_cursor_left);
12307c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_cursor_right);
12317c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_insert_mode);
12327c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_beginning_of_line);
12337c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_end_of_line);
12347c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_line);
12357c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_kill_line);
12367c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_word);
12377c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_word);
12387c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_char);
12397c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_char);
12407c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_word);
12417c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_word);
12427c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_refind);
12437c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_invert_refind);
12447c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_to_column);
12457c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_to_parenthesis);
12467c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_find);
12477c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_find);
12487c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_to);
12497c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_to);
12507c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_upcase_word);
12517c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_downcase_word);
12527c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_capitalize_word);
12537c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_redisplay);
12547c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_clear_screen);
12557c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_transpose_chars);
12567c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_set_mark);
12577c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_exchange_point_and_mark);
12587c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_kill_region);
12597c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_region_as_kill);
12607c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_yank);
12617c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_up_history);
12627c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_down_history);
12637c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_search_backward);
12647c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_re_search_backward);
12657c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_search_forward);
12667c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_re_search_forward);
12677c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_complete_word);
12687c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
12697c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_expand_filename);
12707c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_read_from_file);
12717c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_read_init_files);
12727c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_glob);
12737c478bd9Sstevel@tonic-gate #endif
12747c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_del_char_or_list_or_eof);
12757c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_or_eof);
12767c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_beginning_of_history);
12777c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_end_of_history);
12787c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_digit_argument);
12797c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_newline);
12807c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_repeat_history);
12817c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_insert);
12827c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_overwrite);
12837c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_change_case);
12847c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_insert_at_bol);
12857c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_append_at_eol);
12867c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_append);
12877c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_kill_line);
12887c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_goto_column);
12897c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_to_word);
12907c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_replace_char);
12917c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_rest_of_line);
12927c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_line);
12937c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_bol);
12947c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_refind);
12957c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_invert_refind);
12967c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_column);
12977c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_parenthesis);
12987c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_word);
12997c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_word);
13007c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_find);
13017c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_find);
13027c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_to);
13037c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_to);
13047c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_char);
13057c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_char);
13067c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_char);
13077c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_char);
13087c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_find_char);
13097c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_find_char);
13107c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_to_char);
13117c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_to_char);
13127c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_repeat_find_char);
13137c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_invert_refind_char);
13147c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_append_yank);
13157c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_word);
13167c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_word);
13177c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_bol);
13187c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_refind);
13197c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_invert_refind);
13207c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_column);
13217c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_parenthesis);
13227c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_rest_of_line);
13237c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_line);
13247c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_find);
13257c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_find);
13267c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_to);
13277c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_to);
13287c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_undo);
13297c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_emacs_editing_mode);
13307c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_editing_mode);
13317c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_ring_bell);
13327c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_repeat_change);
13337c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_find_parenthesis);
13347c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_history);
13357c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_completions);
13367c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_run_external_action);
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate /*
13397c478bd9Sstevel@tonic-gate  * Name the available action functions.
13407c478bd9Sstevel@tonic-gate  */
13417c478bd9Sstevel@tonic-gate static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = {
13427c478bd9Sstevel@tonic-gate   {"user-interrupt",             gl_user_interrupt},
13437c478bd9Sstevel@tonic-gate   {"abort",                      gl_abort},
13447c478bd9Sstevel@tonic-gate   {"suspend",                    gl_suspend},
13457c478bd9Sstevel@tonic-gate   {"stop-output",                gl_stop_output},
13467c478bd9Sstevel@tonic-gate   {"start-output",               gl_start_output},
13477c478bd9Sstevel@tonic-gate   {"literal-next",               gl_literal_next},
13487c478bd9Sstevel@tonic-gate   {"cursor-right",               gl_cursor_right},
13497c478bd9Sstevel@tonic-gate   {"cursor-left",                gl_cursor_left},
13507c478bd9Sstevel@tonic-gate   {"insert-mode",                gl_insert_mode},
13517c478bd9Sstevel@tonic-gate   {"beginning-of-line",          gl_beginning_of_line},
13527c478bd9Sstevel@tonic-gate   {"end-of-line",                gl_end_of_line},
13537c478bd9Sstevel@tonic-gate   {"delete-line",                gl_delete_line},
13547c478bd9Sstevel@tonic-gate   {"kill-line",                  gl_kill_line},
13557c478bd9Sstevel@tonic-gate   {"forward-word",               gl_forward_word},
13567c478bd9Sstevel@tonic-gate   {"backward-word",              gl_backward_word},
13577c478bd9Sstevel@tonic-gate   {"forward-delete-char",        gl_forward_delete_char},
13587c478bd9Sstevel@tonic-gate   {"backward-delete-char",       gl_backward_delete_char},
13597c478bd9Sstevel@tonic-gate   {"forward-delete-word",        gl_forward_delete_word},
13607c478bd9Sstevel@tonic-gate   {"backward-delete-word",       gl_backward_delete_word},
13617c478bd9Sstevel@tonic-gate   {"delete-refind",              gl_delete_refind},
13627c478bd9Sstevel@tonic-gate   {"delete-invert-refind",       gl_delete_invert_refind},
13637c478bd9Sstevel@tonic-gate   {"delete-to-column",           gl_delete_to_column},
13647c478bd9Sstevel@tonic-gate   {"delete-to-parenthesis",      gl_delete_to_parenthesis},
13657c478bd9Sstevel@tonic-gate   {"forward-delete-find",        gl_forward_delete_find},
13667c478bd9Sstevel@tonic-gate   {"backward-delete-find",       gl_backward_delete_find},
13677c478bd9Sstevel@tonic-gate   {"forward-delete-to",          gl_forward_delete_to},
13687c478bd9Sstevel@tonic-gate   {"backward-delete-to",         gl_backward_delete_to},
13697c478bd9Sstevel@tonic-gate   {"upcase-word",                gl_upcase_word},
13707c478bd9Sstevel@tonic-gate   {"downcase-word",              gl_downcase_word},
13717c478bd9Sstevel@tonic-gate   {"capitalize-word",            gl_capitalize_word},
13727c478bd9Sstevel@tonic-gate   {"redisplay",                  gl_redisplay},
13737c478bd9Sstevel@tonic-gate   {"clear-screen",               gl_clear_screen},
13747c478bd9Sstevel@tonic-gate   {"transpose-chars",            gl_transpose_chars},
13757c478bd9Sstevel@tonic-gate   {"set-mark",                   gl_set_mark},
13767c478bd9Sstevel@tonic-gate   {"exchange-point-and-mark",    gl_exchange_point_and_mark},
13777c478bd9Sstevel@tonic-gate   {"kill-region",                gl_kill_region},
13787c478bd9Sstevel@tonic-gate   {"copy-region-as-kill",        gl_copy_region_as_kill},
13797c478bd9Sstevel@tonic-gate   {"yank",                       gl_yank},
13807c478bd9Sstevel@tonic-gate   {"up-history",                 gl_up_history},
13817c478bd9Sstevel@tonic-gate   {"down-history",               gl_down_history},
13827c478bd9Sstevel@tonic-gate   {"history-search-backward",    gl_history_search_backward},
13837c478bd9Sstevel@tonic-gate   {"history-re-search-backward", gl_history_re_search_backward},
13847c478bd9Sstevel@tonic-gate   {"history-search-forward",     gl_history_search_forward},
13857c478bd9Sstevel@tonic-gate   {"history-re-search-forward",  gl_history_re_search_forward},
13867c478bd9Sstevel@tonic-gate   {"complete-word",              gl_complete_word},
13877c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
13887c478bd9Sstevel@tonic-gate   {"expand-filename",            gl_expand_filename},
13897c478bd9Sstevel@tonic-gate   {"read-from-file",             gl_read_from_file},
13907c478bd9Sstevel@tonic-gate   {"read-init-files",            gl_read_init_files},
13917c478bd9Sstevel@tonic-gate   {"list-glob",                  gl_list_glob},
13927c478bd9Sstevel@tonic-gate #endif
13937c478bd9Sstevel@tonic-gate   {"del-char-or-list-or-eof",    gl_del_char_or_list_or_eof},
13947c478bd9Sstevel@tonic-gate   {"beginning-of-history",       gl_beginning_of_history},
13957c478bd9Sstevel@tonic-gate   {"end-of-history",             gl_end_of_history},
13967c478bd9Sstevel@tonic-gate   {"digit-argument",             gl_digit_argument},
13977c478bd9Sstevel@tonic-gate   {"newline",                    gl_newline},
13987c478bd9Sstevel@tonic-gate   {"repeat-history",             gl_repeat_history},
13997c478bd9Sstevel@tonic-gate   {"vi-insert",                  gl_vi_insert},
14007c478bd9Sstevel@tonic-gate   {"vi-overwrite",               gl_vi_overwrite},
14017c478bd9Sstevel@tonic-gate   {"vi-insert-at-bol",           gl_vi_insert_at_bol},
14027c478bd9Sstevel@tonic-gate   {"vi-append-at-eol",           gl_vi_append_at_eol},
14037c478bd9Sstevel@tonic-gate   {"vi-append",                  gl_vi_append},
14047c478bd9Sstevel@tonic-gate   {"change-case",                gl_change_case},
14057c478bd9Sstevel@tonic-gate   {"backward-kill-line",         gl_backward_kill_line},
14067c478bd9Sstevel@tonic-gate   {"goto-column",                gl_goto_column},
14077c478bd9Sstevel@tonic-gate   {"forward-to-word",            gl_forward_to_word},
14087c478bd9Sstevel@tonic-gate   {"vi-replace-char",            gl_vi_replace_char},
14097c478bd9Sstevel@tonic-gate   {"vi-change-rest-of-line",     gl_vi_change_rest_of_line},
14107c478bd9Sstevel@tonic-gate   {"vi-change-line",             gl_vi_change_line},
14117c478bd9Sstevel@tonic-gate   {"vi-change-to-bol",           gl_vi_change_to_bol},
14127c478bd9Sstevel@tonic-gate   {"vi-change-refind",           gl_vi_change_refind},
14137c478bd9Sstevel@tonic-gate   {"vi-change-invert-refind",    gl_vi_change_invert_refind},
14147c478bd9Sstevel@tonic-gate   {"vi-change-to-column",        gl_vi_change_to_column},
14157c478bd9Sstevel@tonic-gate   {"vi-change-to-parenthesis",   gl_vi_change_to_parenthesis},
14167c478bd9Sstevel@tonic-gate   {"forward-copy-char",          gl_forward_copy_char},
14177c478bd9Sstevel@tonic-gate   {"backward-copy-char",         gl_backward_copy_char},
14187c478bd9Sstevel@tonic-gate   {"forward-find-char",          gl_forward_find_char},
14197c478bd9Sstevel@tonic-gate   {"backward-find-char",         gl_backward_find_char},
14207c478bd9Sstevel@tonic-gate   {"forward-to-char",            gl_forward_to_char},
14217c478bd9Sstevel@tonic-gate   {"backward-to-char",           gl_backward_to_char},
14227c478bd9Sstevel@tonic-gate   {"repeat-find-char",           gl_repeat_find_char},
14237c478bd9Sstevel@tonic-gate   {"invert-refind-char",         gl_invert_refind_char},
14247c478bd9Sstevel@tonic-gate   {"append-yank",                gl_append_yank},
14257c478bd9Sstevel@tonic-gate   {"backward-copy-word",         gl_backward_copy_word},
14267c478bd9Sstevel@tonic-gate   {"forward-copy-word",          gl_forward_copy_word},
14277c478bd9Sstevel@tonic-gate   {"copy-to-bol",                gl_copy_to_bol},
14287c478bd9Sstevel@tonic-gate   {"copy-refind",                gl_copy_refind},
14297c478bd9Sstevel@tonic-gate   {"copy-invert-refind",         gl_copy_invert_refind},
14307c478bd9Sstevel@tonic-gate   {"copy-to-column",             gl_copy_to_column},
14317c478bd9Sstevel@tonic-gate   {"copy-to-parenthesis",        gl_copy_to_parenthesis},
14327c478bd9Sstevel@tonic-gate   {"copy-rest-of-line",          gl_copy_rest_of_line},
14337c478bd9Sstevel@tonic-gate   {"copy-line",                  gl_copy_line},
14347c478bd9Sstevel@tonic-gate   {"backward-copy-find",         gl_backward_copy_find},
14357c478bd9Sstevel@tonic-gate   {"forward-copy-find",          gl_forward_copy_find},
14367c478bd9Sstevel@tonic-gate   {"backward-copy-to",           gl_backward_copy_to},
14377c478bd9Sstevel@tonic-gate   {"forward-copy-to",            gl_forward_copy_to},
14387c478bd9Sstevel@tonic-gate   {"list-or-eof",                gl_list_or_eof},
14397c478bd9Sstevel@tonic-gate   {"vi-undo",                    gl_vi_undo},
14407c478bd9Sstevel@tonic-gate   {"vi-backward-change-word",    gl_vi_backward_change_word},
14417c478bd9Sstevel@tonic-gate   {"vi-forward-change-word",     gl_vi_forward_change_word},
14427c478bd9Sstevel@tonic-gate   {"vi-backward-change-find",    gl_vi_backward_change_find},
14437c478bd9Sstevel@tonic-gate   {"vi-forward-change-find",     gl_vi_forward_change_find},
14447c478bd9Sstevel@tonic-gate   {"vi-backward-change-to",      gl_vi_backward_change_to},
14457c478bd9Sstevel@tonic-gate   {"vi-forward-change-to",       gl_vi_forward_change_to},
14467c478bd9Sstevel@tonic-gate   {"vi-backward-change-char",    gl_vi_backward_change_char},
14477c478bd9Sstevel@tonic-gate   {"vi-forward-change-char",     gl_vi_forward_change_char},
14487c478bd9Sstevel@tonic-gate   {"emacs-mode",                 gl_emacs_editing_mode},
14497c478bd9Sstevel@tonic-gate   {"vi-mode",                    gl_vi_editing_mode},
14507c478bd9Sstevel@tonic-gate   {"ring-bell",                  gl_ring_bell},
14517c478bd9Sstevel@tonic-gate   {"vi-repeat-change",           gl_vi_repeat_change},
14527c478bd9Sstevel@tonic-gate   {"find-parenthesis",           gl_find_parenthesis},
14537c478bd9Sstevel@tonic-gate   {"list-history",               gl_list_history},
14547c478bd9Sstevel@tonic-gate };
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate /*
14577c478bd9Sstevel@tonic-gate  * Define the default key-bindings in emacs mode.
14587c478bd9Sstevel@tonic-gate  */
14597c478bd9Sstevel@tonic-gate static const KtKeyBinding gl_emacs_bindings[] = {
14607c478bd9Sstevel@tonic-gate   {"right",        "cursor-right"},
14617c478bd9Sstevel@tonic-gate   {"^F",           "cursor-right"},
14627c478bd9Sstevel@tonic-gate   {"left",         "cursor-left"},
14637c478bd9Sstevel@tonic-gate   {"^B",           "cursor-left"},
14647c478bd9Sstevel@tonic-gate   {"M-i",          "insert-mode"},
14657c478bd9Sstevel@tonic-gate   {"M-I",          "insert-mode"},
14667c478bd9Sstevel@tonic-gate   {"^A",           "beginning-of-line"},
14677c478bd9Sstevel@tonic-gate   {"^E",           "end-of-line"},
14687c478bd9Sstevel@tonic-gate   {"^U",           "delete-line"},
14697c478bd9Sstevel@tonic-gate   {"^K",           "kill-line"},
14707c478bd9Sstevel@tonic-gate   {"M-f",          "forward-word"},
14717c478bd9Sstevel@tonic-gate   {"M-F",          "forward-word"},
14727c478bd9Sstevel@tonic-gate   {"M-b",          "backward-word"},
14737c478bd9Sstevel@tonic-gate   {"M-B",          "backward-word"},
14747c478bd9Sstevel@tonic-gate   {"^D",           "del-char-or-list-or-eof"},
14757c478bd9Sstevel@tonic-gate   {"^H",           "backward-delete-char"},
14767c478bd9Sstevel@tonic-gate   {"^?",           "backward-delete-char"},
14777c478bd9Sstevel@tonic-gate   {"M-d",          "forward-delete-word"},
14787c478bd9Sstevel@tonic-gate   {"M-D",          "forward-delete-word"},
14797c478bd9Sstevel@tonic-gate   {"M-^H",         "backward-delete-word"},
14807c478bd9Sstevel@tonic-gate   {"M-^?",         "backward-delete-word"},
14817c478bd9Sstevel@tonic-gate   {"M-u",          "upcase-word"},
14827c478bd9Sstevel@tonic-gate   {"M-U",          "upcase-word"},
14837c478bd9Sstevel@tonic-gate   {"M-l",          "downcase-word"},
14847c478bd9Sstevel@tonic-gate   {"M-L",          "downcase-word"},
14857c478bd9Sstevel@tonic-gate   {"M-c",          "capitalize-word"},
14867c478bd9Sstevel@tonic-gate   {"M-C",          "capitalize-word"},
14877c478bd9Sstevel@tonic-gate   {"^R",           "redisplay"},
14887c478bd9Sstevel@tonic-gate   {"^L",           "clear-screen"},
14897c478bd9Sstevel@tonic-gate   {"^T",           "transpose-chars"},
14907c478bd9Sstevel@tonic-gate   {"^@",           "set-mark"},
14917c478bd9Sstevel@tonic-gate   {"^X^X",         "exchange-point-and-mark"},
14927c478bd9Sstevel@tonic-gate   {"^W",           "kill-region"},
14937c478bd9Sstevel@tonic-gate   {"M-w",          "copy-region-as-kill"},
14947c478bd9Sstevel@tonic-gate   {"M-W",          "copy-region-as-kill"},
14957c478bd9Sstevel@tonic-gate   {"^Y",           "yank"},
14967c478bd9Sstevel@tonic-gate   {"^P",           "up-history"},
14977c478bd9Sstevel@tonic-gate   {"up",           "up-history"},
14987c478bd9Sstevel@tonic-gate   {"^N",           "down-history"},
14997c478bd9Sstevel@tonic-gate   {"down",         "down-history"},
15007c478bd9Sstevel@tonic-gate   {"M-p",          "history-search-backward"},
15017c478bd9Sstevel@tonic-gate   {"M-P",          "history-search-backward"},
15027c478bd9Sstevel@tonic-gate   {"M-n",          "history-search-forward"},
15037c478bd9Sstevel@tonic-gate   {"M-N",          "history-search-forward"},
15047c478bd9Sstevel@tonic-gate   {"\t",           "complete-word"},
15057c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
15067c478bd9Sstevel@tonic-gate   {"^X*",          "expand-filename"},
15077c478bd9Sstevel@tonic-gate   {"^X^F",         "read-from-file"},
15087c478bd9Sstevel@tonic-gate   {"^X^R",         "read-init-files"},
15097c478bd9Sstevel@tonic-gate   {"^Xg",          "list-glob"},
15107c478bd9Sstevel@tonic-gate   {"^XG",          "list-glob"},
15117c478bd9Sstevel@tonic-gate #endif
15127c478bd9Sstevel@tonic-gate   {"^Xh",          "list-history"},
15137c478bd9Sstevel@tonic-gate   {"^XH",          "list-history"},
15147c478bd9Sstevel@tonic-gate   {"M-<",          "beginning-of-history"},
15157c478bd9Sstevel@tonic-gate   {"M->",          "end-of-history"},
15167c478bd9Sstevel@tonic-gate   {"M-0",          "digit-argument"},
15177c478bd9Sstevel@tonic-gate   {"M-1",          "digit-argument"},
15187c478bd9Sstevel@tonic-gate   {"M-2",          "digit-argument"},
15197c478bd9Sstevel@tonic-gate   {"M-3",          "digit-argument"},
15207c478bd9Sstevel@tonic-gate   {"M-4",          "digit-argument"},
15217c478bd9Sstevel@tonic-gate   {"M-5",          "digit-argument"},
15227c478bd9Sstevel@tonic-gate   {"M-6",          "digit-argument"},
15237c478bd9Sstevel@tonic-gate   {"M-7",          "digit-argument"},
15247c478bd9Sstevel@tonic-gate   {"M-8",          "digit-argument"},
15257c478bd9Sstevel@tonic-gate   {"M-9",          "digit-argument"},
15267c478bd9Sstevel@tonic-gate   {"\r",           "newline"},
15277c478bd9Sstevel@tonic-gate   {"\n",           "newline"},
15287c478bd9Sstevel@tonic-gate   {"M-o",          "repeat-history"},
15297c478bd9Sstevel@tonic-gate   {"M-C-v",        "vi-mode"},
15307c478bd9Sstevel@tonic-gate };
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate /*
15337c478bd9Sstevel@tonic-gate  * Define the default key-bindings in vi mode. Note that in vi-mode
15347c478bd9Sstevel@tonic-gate  * meta-key bindings are command-mode bindings. For example M-i first
15357c478bd9Sstevel@tonic-gate  * switches to command mode if not already in that mode, then moves
15367c478bd9Sstevel@tonic-gate  * the cursor one position right, as in vi.
15377c478bd9Sstevel@tonic-gate  */
15387c478bd9Sstevel@tonic-gate static const KtKeyBinding gl_vi_bindings[] = {
15397c478bd9Sstevel@tonic-gate   {"^D",           "list-or-eof"},
15407c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
15417c478bd9Sstevel@tonic-gate   {"^G",           "list-glob"},
15427c478bd9Sstevel@tonic-gate #endif
15437c478bd9Sstevel@tonic-gate   {"^H",           "backward-delete-char"},
15447c478bd9Sstevel@tonic-gate   {"\t",           "complete-word"},
15457c478bd9Sstevel@tonic-gate   {"\r",           "newline"},
15467c478bd9Sstevel@tonic-gate   {"\n",           "newline"},
15477c478bd9Sstevel@tonic-gate   {"^L",           "clear-screen"},
15487c478bd9Sstevel@tonic-gate   {"^N",           "down-history"},
15497c478bd9Sstevel@tonic-gate   {"^P",           "up-history"},
15507c478bd9Sstevel@tonic-gate   {"^R",           "redisplay"},
15517c478bd9Sstevel@tonic-gate   {"^U",           "backward-kill-line"},
15527c478bd9Sstevel@tonic-gate   {"^W",           "backward-delete-word"},
15537c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
15547c478bd9Sstevel@tonic-gate   {"^X^F",         "read-from-file"},
15557c478bd9Sstevel@tonic-gate   {"^X^R",         "read-init-files"},
15567c478bd9Sstevel@tonic-gate   {"^X*",          "expand-filename"},
15577c478bd9Sstevel@tonic-gate #endif
15587c478bd9Sstevel@tonic-gate   {"^?",           "backward-delete-char"},
15597c478bd9Sstevel@tonic-gate   {"M- ",          "cursor-right"},
15607c478bd9Sstevel@tonic-gate   {"M-$",          "end-of-line"},
15617c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
15627c478bd9Sstevel@tonic-gate   {"M-*",          "expand-filename"},
15637c478bd9Sstevel@tonic-gate #endif
15647c478bd9Sstevel@tonic-gate   {"M-+",          "down-history"},
15657c478bd9Sstevel@tonic-gate   {"M--",          "up-history"},
15667c478bd9Sstevel@tonic-gate   {"M-<",          "beginning-of-history"},
15677c478bd9Sstevel@tonic-gate   {"M->",          "end-of-history"},
15687c478bd9Sstevel@tonic-gate   {"M-^",          "beginning-of-line"},
15697c478bd9Sstevel@tonic-gate   {"M-;",          "repeat-find-char"},
15707c478bd9Sstevel@tonic-gate   {"M-,",          "invert-refind-char"},
15717c478bd9Sstevel@tonic-gate   {"M-|",          "goto-column"},
15727c478bd9Sstevel@tonic-gate   {"M-~",          "change-case"},
15737c478bd9Sstevel@tonic-gate   {"M-.",          "vi-repeat-change"},
15747c478bd9Sstevel@tonic-gate   {"M-%",          "find-parenthesis"},
15757c478bd9Sstevel@tonic-gate   {"M-0",          "digit-argument"},
15767c478bd9Sstevel@tonic-gate   {"M-1",          "digit-argument"},
15777c478bd9Sstevel@tonic-gate   {"M-2",          "digit-argument"},
15787c478bd9Sstevel@tonic-gate   {"M-3",          "digit-argument"},
15797c478bd9Sstevel@tonic-gate   {"M-4",          "digit-argument"},
15807c478bd9Sstevel@tonic-gate   {"M-5",          "digit-argument"},
15817c478bd9Sstevel@tonic-gate   {"M-6",          "digit-argument"},
15827c478bd9Sstevel@tonic-gate   {"M-7",          "digit-argument"},
15837c478bd9Sstevel@tonic-gate   {"M-8",          "digit-argument"},
15847c478bd9Sstevel@tonic-gate   {"M-9",          "digit-argument"},
15857c478bd9Sstevel@tonic-gate   {"M-a",          "vi-append"},
15867c478bd9Sstevel@tonic-gate   {"M-A",          "vi-append-at-eol"},
15877c478bd9Sstevel@tonic-gate   {"M-b",          "backward-word"},
15887c478bd9Sstevel@tonic-gate   {"M-B",          "backward-word"},
15897c478bd9Sstevel@tonic-gate   {"M-C",          "vi-change-rest-of-line"},
15907c478bd9Sstevel@tonic-gate   {"M-cb",         "vi-backward-change-word"},
15917c478bd9Sstevel@tonic-gate   {"M-cB",         "vi-backward-change-word"},
15927c478bd9Sstevel@tonic-gate   {"M-cc",         "vi-change-line"},
15937c478bd9Sstevel@tonic-gate   {"M-ce",         "vi-forward-change-word"},
15947c478bd9Sstevel@tonic-gate   {"M-cE",         "vi-forward-change-word"},
15957c478bd9Sstevel@tonic-gate   {"M-cw",         "vi-forward-change-word"},
15967c478bd9Sstevel@tonic-gate   {"M-cW",         "vi-forward-change-word"},
15977c478bd9Sstevel@tonic-gate   {"M-cF",         "vi-backward-change-find"},
15987c478bd9Sstevel@tonic-gate   {"M-cf",         "vi-forward-change-find"},
15997c478bd9Sstevel@tonic-gate   {"M-cT",         "vi-backward-change-to"},
16007c478bd9Sstevel@tonic-gate   {"M-ct",         "vi-forward-change-to"},
16017c478bd9Sstevel@tonic-gate   {"M-c;",         "vi-change-refind"},
16027c478bd9Sstevel@tonic-gate   {"M-c,",         "vi-change-invert-refind"},
16037c478bd9Sstevel@tonic-gate   {"M-ch",         "vi-backward-change-char"},
16047c478bd9Sstevel@tonic-gate   {"M-c^H",        "vi-backward-change-char"},
16057c478bd9Sstevel@tonic-gate   {"M-c^?",        "vi-backward-change-char"},
16067c478bd9Sstevel@tonic-gate   {"M-cl",         "vi-forward-change-char"},
16077c478bd9Sstevel@tonic-gate   {"M-c ",         "vi-forward-change-char"},
16087c478bd9Sstevel@tonic-gate   {"M-c^",         "vi-change-to-bol"},
16097c478bd9Sstevel@tonic-gate   {"M-c0",         "vi-change-to-bol"},
16107c478bd9Sstevel@tonic-gate   {"M-c$",         "vi-change-rest-of-line"},
16117c478bd9Sstevel@tonic-gate   {"M-c|",         "vi-change-to-column"},
16127c478bd9Sstevel@tonic-gate   {"M-c%",         "vi-change-to-parenthesis"},
16137c478bd9Sstevel@tonic-gate   {"M-dh",         "backward-delete-char"},
16147c478bd9Sstevel@tonic-gate   {"M-d^H",        "backward-delete-char"},
16157c478bd9Sstevel@tonic-gate   {"M-d^?",        "backward-delete-char"},
16167c478bd9Sstevel@tonic-gate   {"M-dl",         "forward-delete-char"},
16177c478bd9Sstevel@tonic-gate   {"M-d ",         "forward-delete-char"},
16187c478bd9Sstevel@tonic-gate   {"M-dd",         "delete-line"},
16197c478bd9Sstevel@tonic-gate   {"M-db",         "backward-delete-word"},
16207c478bd9Sstevel@tonic-gate   {"M-dB",         "backward-delete-word"},
16217c478bd9Sstevel@tonic-gate   {"M-de",         "forward-delete-word"},
16227c478bd9Sstevel@tonic-gate   {"M-dE",         "forward-delete-word"},
16237c478bd9Sstevel@tonic-gate   {"M-dw",         "forward-delete-word"},
16247c478bd9Sstevel@tonic-gate   {"M-dW",         "forward-delete-word"},
16257c478bd9Sstevel@tonic-gate   {"M-dF",         "backward-delete-find"},
16267c478bd9Sstevel@tonic-gate   {"M-df",         "forward-delete-find"},
16277c478bd9Sstevel@tonic-gate   {"M-dT",         "backward-delete-to"},
16287c478bd9Sstevel@tonic-gate   {"M-dt",         "forward-delete-to"},
16297c478bd9Sstevel@tonic-gate   {"M-d;",         "delete-refind"},
16307c478bd9Sstevel@tonic-gate   {"M-d,",         "delete-invert-refind"},
16317c478bd9Sstevel@tonic-gate   {"M-d^",         "backward-kill-line"},
16327c478bd9Sstevel@tonic-gate   {"M-d0",         "backward-kill-line"},
16337c478bd9Sstevel@tonic-gate   {"M-d$",         "kill-line"},
16347c478bd9Sstevel@tonic-gate   {"M-D",          "kill-line"},
16357c478bd9Sstevel@tonic-gate   {"M-d|",         "delete-to-column"},
16367c478bd9Sstevel@tonic-gate   {"M-d%",         "delete-to-parenthesis"},
16377c478bd9Sstevel@tonic-gate   {"M-e",          "forward-word"},
16387c478bd9Sstevel@tonic-gate   {"M-E",          "forward-word"},
16397c478bd9Sstevel@tonic-gate   {"M-f",          "forward-find-char"},
16407c478bd9Sstevel@tonic-gate   {"M-F",          "backward-find-char"},
16417c478bd9Sstevel@tonic-gate   {"M--",          "up-history"},
16427c478bd9Sstevel@tonic-gate   {"M-h",          "cursor-left"},
16437c478bd9Sstevel@tonic-gate   {"M-H",          "beginning-of-history"},
16447c478bd9Sstevel@tonic-gate   {"M-i",          "vi-insert"},
16457c478bd9Sstevel@tonic-gate   {"M-I",          "vi-insert-at-bol"},
16467c478bd9Sstevel@tonic-gate   {"M-j",          "down-history"},
16477c478bd9Sstevel@tonic-gate   {"M-J",          "history-search-forward"},
16487c478bd9Sstevel@tonic-gate   {"M-k",          "up-history"},
16497c478bd9Sstevel@tonic-gate   {"M-K",          "history-search-backward"},
16507c478bd9Sstevel@tonic-gate   {"M-l",          "cursor-right"},
16517c478bd9Sstevel@tonic-gate   {"M-L",          "end-of-history"},
16527c478bd9Sstevel@tonic-gate   {"M-n",          "history-re-search-forward"},
16537c478bd9Sstevel@tonic-gate   {"M-N",          "history-re-search-backward"},
16547c478bd9Sstevel@tonic-gate   {"M-p",          "append-yank"},
16557c478bd9Sstevel@tonic-gate   {"M-P",          "yank"},
16567c478bd9Sstevel@tonic-gate   {"M-r",          "vi-replace-char"},
16577c478bd9Sstevel@tonic-gate   {"M-R",          "vi-overwrite"},
16587c478bd9Sstevel@tonic-gate   {"M-s",          "vi-forward-change-char"},
16597c478bd9Sstevel@tonic-gate   {"M-S",          "vi-change-line"},
16607c478bd9Sstevel@tonic-gate   {"M-t",          "forward-to-char"},
16617c478bd9Sstevel@tonic-gate   {"M-T",          "backward-to-char"},
16627c478bd9Sstevel@tonic-gate   {"M-u",          "vi-undo"},
16637c478bd9Sstevel@tonic-gate   {"M-w",          "forward-to-word"},
16647c478bd9Sstevel@tonic-gate   {"M-W",          "forward-to-word"},
16657c478bd9Sstevel@tonic-gate   {"M-x",          "forward-delete-char"},
16667c478bd9Sstevel@tonic-gate   {"M-X",          "backward-delete-char"},
16677c478bd9Sstevel@tonic-gate   {"M-yh",         "backward-copy-char"},
16687c478bd9Sstevel@tonic-gate   {"M-y^H",        "backward-copy-char"},
16697c478bd9Sstevel@tonic-gate   {"M-y^?",        "backward-copy-char"},
16707c478bd9Sstevel@tonic-gate   {"M-yl",         "forward-copy-char"},
16717c478bd9Sstevel@tonic-gate   {"M-y ",         "forward-copy-char"},
16727c478bd9Sstevel@tonic-gate   {"M-ye",         "forward-copy-word"},
16737c478bd9Sstevel@tonic-gate   {"M-yE",         "forward-copy-word"},
16747c478bd9Sstevel@tonic-gate   {"M-yw",         "forward-copy-word"},
16757c478bd9Sstevel@tonic-gate   {"M-yW",         "forward-copy-word"},
16767c478bd9Sstevel@tonic-gate   {"M-yb",         "backward-copy-word"},
16777c478bd9Sstevel@tonic-gate   {"M-yB",         "backward-copy-word"},
16787c478bd9Sstevel@tonic-gate   {"M-yf",         "forward-copy-find"},
16797c478bd9Sstevel@tonic-gate   {"M-yF",         "backward-copy-find"},
16807c478bd9Sstevel@tonic-gate   {"M-yt",         "forward-copy-to"},
16817c478bd9Sstevel@tonic-gate   {"M-yT",         "backward-copy-to"},
16827c478bd9Sstevel@tonic-gate   {"M-y;",         "copy-refind"},
16837c478bd9Sstevel@tonic-gate   {"M-y,",         "copy-invert-refind"},
16847c478bd9Sstevel@tonic-gate   {"M-y^",         "copy-to-bol"},
16857c478bd9Sstevel@tonic-gate   {"M-y0",         "copy-to-bol"},
16867c478bd9Sstevel@tonic-gate   {"M-y$",         "copy-rest-of-line"},
16877c478bd9Sstevel@tonic-gate   {"M-yy",         "copy-line"},
16887c478bd9Sstevel@tonic-gate   {"M-Y",          "copy-line"},
16897c478bd9Sstevel@tonic-gate   {"M-y|",         "copy-to-column"},
16907c478bd9Sstevel@tonic-gate   {"M-y%",         "copy-to-parenthesis"},
16917c478bd9Sstevel@tonic-gate   {"M-^E",         "emacs-mode"},
16927c478bd9Sstevel@tonic-gate   {"M-^H",         "cursor-left"},
16937c478bd9Sstevel@tonic-gate   {"M-^?",         "cursor-left"},
16947c478bd9Sstevel@tonic-gate   {"M-^L",         "clear-screen"},
16957c478bd9Sstevel@tonic-gate   {"M-^N",         "down-history"},
16967c478bd9Sstevel@tonic-gate   {"M-^P",         "up-history"},
16977c478bd9Sstevel@tonic-gate   {"M-^R",         "redisplay"},
16987c478bd9Sstevel@tonic-gate   {"M-^D",         "list-or-eof"},
16997c478bd9Sstevel@tonic-gate   {"M-\r",         "newline"},
17007c478bd9Sstevel@tonic-gate   {"M-\t",         "complete-word"},
17017c478bd9Sstevel@tonic-gate   {"M-\n",         "newline"},
17027c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
17037c478bd9Sstevel@tonic-gate   {"M-^X^R",       "read-init-files"},
17047c478bd9Sstevel@tonic-gate #endif
17057c478bd9Sstevel@tonic-gate   {"M-^Xh",        "list-history"},
17067c478bd9Sstevel@tonic-gate   {"M-^XH",        "list-history"},
17077c478bd9Sstevel@tonic-gate   {"down",         "down-history"},
17087c478bd9Sstevel@tonic-gate   {"up",           "up-history"},
17097c478bd9Sstevel@tonic-gate   {"left",         "cursor-left"},
17107c478bd9Sstevel@tonic-gate   {"right",        "cursor-right"},
17117c478bd9Sstevel@tonic-gate };
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate /*.......................................................................
17147c478bd9Sstevel@tonic-gate  * Create a new GetLine object.
17157c478bd9Sstevel@tonic-gate  *
17167c478bd9Sstevel@tonic-gate  * Input:
17177c478bd9Sstevel@tonic-gate  *  linelen  size_t    The maximum line length to allow for.
17187c478bd9Sstevel@tonic-gate  *  histlen  size_t    The number of bytes to allocate for recording
17197c478bd9Sstevel@tonic-gate  *                     a circular buffer of history lines.
17207c478bd9Sstevel@tonic-gate  * Output:
17217c478bd9Sstevel@tonic-gate  *  return  GetLine *  The new object, or NULL on error.
17227c478bd9Sstevel@tonic-gate  */
new_GetLine(size_t linelen,size_t histlen)17237c478bd9Sstevel@tonic-gate GetLine *new_GetLine(size_t linelen, size_t histlen)
17247c478bd9Sstevel@tonic-gate {
17257c478bd9Sstevel@tonic-gate   GetLine *gl;  /* The object to be returned */
17267c478bd9Sstevel@tonic-gate   int i;
17277c478bd9Sstevel@tonic-gate /*
17287c478bd9Sstevel@tonic-gate  * Check the arguments.
17297c478bd9Sstevel@tonic-gate  */
17307c478bd9Sstevel@tonic-gate   if(linelen < 10) {
17317c478bd9Sstevel@tonic-gate     errno = ENOMEM;
17327c478bd9Sstevel@tonic-gate     return NULL;
17337c478bd9Sstevel@tonic-gate   };
17347c478bd9Sstevel@tonic-gate /*
17357c478bd9Sstevel@tonic-gate  * Allocate the container.
17367c478bd9Sstevel@tonic-gate  */
17377c478bd9Sstevel@tonic-gate   gl = (GetLine *) malloc(sizeof(GetLine));
17387c478bd9Sstevel@tonic-gate   if(!gl) {
17397c478bd9Sstevel@tonic-gate     errno = ENOMEM;
17407c478bd9Sstevel@tonic-gate     return NULL;
17417c478bd9Sstevel@tonic-gate   };
17427c478bd9Sstevel@tonic-gate /*
17437c478bd9Sstevel@tonic-gate  * Before attempting any operation that might fail, initialize the
17447c478bd9Sstevel@tonic-gate  * container at least up to the point at which it can safely be passed
17457c478bd9Sstevel@tonic-gate  * to del_GetLine().
17467c478bd9Sstevel@tonic-gate  */
17477c478bd9Sstevel@tonic-gate   gl->err = NULL;
17487c478bd9Sstevel@tonic-gate   gl->glh = NULL;
17497c478bd9Sstevel@tonic-gate   gl->cpl = NULL;
17507c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
17517c478bd9Sstevel@tonic-gate   gl->cplfn.fn = cpl_file_completions;
17527c478bd9Sstevel@tonic-gate #else
17537c478bd9Sstevel@tonic-gate   gl->cplfn.fn = gl_no_completions;
17547c478bd9Sstevel@tonic-gate #endif
17557c478bd9Sstevel@tonic-gate   gl->cplfn.data = NULL;
17567c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM
17577c478bd9Sstevel@tonic-gate   gl->ef = NULL;
17587c478bd9Sstevel@tonic-gate #endif
17597c478bd9Sstevel@tonic-gate   gl->capmem = NULL;
17607c478bd9Sstevel@tonic-gate   gl->cq = NULL;
17617c478bd9Sstevel@tonic-gate   gl->input_fd = -1;
17627c478bd9Sstevel@tonic-gate   gl->output_fd = -1;
17637c478bd9Sstevel@tonic-gate   gl->input_fp = NULL;
17647c478bd9Sstevel@tonic-gate   gl->output_fp = NULL;
17657c478bd9Sstevel@tonic-gate   gl->file_fp = NULL;
17667c478bd9Sstevel@tonic-gate   gl->term = NULL;
17677c478bd9Sstevel@tonic-gate   gl->is_term = 0;
17687c478bd9Sstevel@tonic-gate   gl->flush_fn = gl_flush_terminal;
17697c478bd9Sstevel@tonic-gate   gl->io_mode = GL_NORMAL_MODE;
17707c478bd9Sstevel@tonic-gate   gl->raw_mode = 0;
17717c478bd9Sstevel@tonic-gate   gl->pending_io = GLP_WRITE;  /* We will start by writing the prompt */
17727c478bd9Sstevel@tonic-gate   gl_clear_status(gl);
17737c478bd9Sstevel@tonic-gate   gl->linelen = linelen;
17747c478bd9Sstevel@tonic-gate   gl->line = NULL;
17757c478bd9Sstevel@tonic-gate   gl->cutbuf = NULL;
17767c478bd9Sstevel@tonic-gate   gl->prompt = NULL;
17777c478bd9Sstevel@tonic-gate   gl->prompt_len = 0;
17787c478bd9Sstevel@tonic-gate   gl->prompt_changed = 0;
17797c478bd9Sstevel@tonic-gate   gl->prompt_style = GL_LITERAL_PROMPT;
17807c478bd9Sstevel@tonic-gate   gl->cpl_mem = NULL;
17817c478bd9Sstevel@tonic-gate   gl->ext_act_mem = NULL;
17827c478bd9Sstevel@tonic-gate   gl->sig_mem = NULL;
17837c478bd9Sstevel@tonic-gate   gl->sigs = NULL;
17847c478bd9Sstevel@tonic-gate   gl->signals_masked = 0;
17857c478bd9Sstevel@tonic-gate   gl->signals_overriden = 0;
17867c478bd9Sstevel@tonic-gate   sigemptyset(&gl->all_signal_set);
17877c478bd9Sstevel@tonic-gate   sigemptyset(&gl->old_signal_set);
17887c478bd9Sstevel@tonic-gate   sigemptyset(&gl->use_signal_set);
17897c478bd9Sstevel@tonic-gate   gl->bindings = NULL;
17907c478bd9Sstevel@tonic-gate   gl->ntotal = 0;
17917c478bd9Sstevel@tonic-gate   gl->buff_curpos = 0;
17927c478bd9Sstevel@tonic-gate   gl->term_curpos = 0;
17937c478bd9Sstevel@tonic-gate   gl->term_len = 0;
17947c478bd9Sstevel@tonic-gate   gl->buff_mark = 0;
17957c478bd9Sstevel@tonic-gate   gl->insert_curpos = 0;
17967c478bd9Sstevel@tonic-gate   gl->insert = 1;
17977c478bd9Sstevel@tonic-gate   gl->number = -1;
17987c478bd9Sstevel@tonic-gate   gl->endline = 1;
17997c478bd9Sstevel@tonic-gate   gl->displayed = 0;
18007c478bd9Sstevel@tonic-gate   gl->redisplay = 0;
18017c478bd9Sstevel@tonic-gate   gl->postpone = 0;
18027c478bd9Sstevel@tonic-gate   gl->keybuf[0]='\0';
18037c478bd9Sstevel@tonic-gate   gl->nbuf = 0;
18047c478bd9Sstevel@tonic-gate   gl->nread = 0;
18057c478bd9Sstevel@tonic-gate   gl->current_action.fn = 0;
18067c478bd9Sstevel@tonic-gate   gl->current_action.data = NULL;
18077c478bd9Sstevel@tonic-gate   gl->current_count = 0;
18087c478bd9Sstevel@tonic-gate   gl->preload_id = 0;
18097c478bd9Sstevel@tonic-gate   gl->preload_history = 0;
18107c478bd9Sstevel@tonic-gate   gl->keyseq_count = 0;
18117c478bd9Sstevel@tonic-gate   gl->last_search = -1;
18127c478bd9Sstevel@tonic-gate   gl->editor = GL_EMACS_MODE;
18137c478bd9Sstevel@tonic-gate   gl->silence_bell = 0;
18147c478bd9Sstevel@tonic-gate   gl->automatic_history = 1;
18157c478bd9Sstevel@tonic-gate   gl->vi.undo.line = NULL;
18167c478bd9Sstevel@tonic-gate   gl->vi.undo.buff_curpos = 0;
18177c478bd9Sstevel@tonic-gate   gl->vi.undo.ntotal = 0;
18187c478bd9Sstevel@tonic-gate   gl->vi.undo.saved = 0;
18197c478bd9Sstevel@tonic-gate   gl->vi.repeat.action.fn = 0;
18207c478bd9Sstevel@tonic-gate   gl->vi.repeat.action.data = 0;
18217c478bd9Sstevel@tonic-gate   gl->vi.repeat.count = 0;
18227c478bd9Sstevel@tonic-gate   gl->vi.repeat.input_curpos = 0;
18237c478bd9Sstevel@tonic-gate   gl->vi.repeat.command_curpos = 0;
18247c478bd9Sstevel@tonic-gate   gl->vi.repeat.input_char = '\0';
18257c478bd9Sstevel@tonic-gate   gl->vi.repeat.saved = 0;
18267c478bd9Sstevel@tonic-gate   gl->vi.repeat.active = 0;
18277c478bd9Sstevel@tonic-gate   gl->vi.command = 0;
18287c478bd9Sstevel@tonic-gate   gl->vi.find_forward = 0;
18297c478bd9Sstevel@tonic-gate   gl->vi.find_onto = 0;
18307c478bd9Sstevel@tonic-gate   gl->vi.find_char = '\0';
18317c478bd9Sstevel@tonic-gate   gl->left = NULL;
18327c478bd9Sstevel@tonic-gate   gl->right = NULL;
18337c478bd9Sstevel@tonic-gate   gl->up = NULL;
18347c478bd9Sstevel@tonic-gate   gl->down = NULL;
18357c478bd9Sstevel@tonic-gate   gl->home = NULL;
18367c478bd9Sstevel@tonic-gate   gl->bol = 0;
18377c478bd9Sstevel@tonic-gate   gl->clear_eol = NULL;
18387c478bd9Sstevel@tonic-gate   gl->clear_eod = NULL;
18397c478bd9Sstevel@tonic-gate   gl->u_arrow = NULL;
18407c478bd9Sstevel@tonic-gate   gl->d_arrow = NULL;
18417c478bd9Sstevel@tonic-gate   gl->l_arrow = NULL;
18427c478bd9Sstevel@tonic-gate   gl->r_arrow = NULL;
18437c478bd9Sstevel@tonic-gate   gl->sound_bell = NULL;
18447c478bd9Sstevel@tonic-gate   gl->bold = NULL;
18457c478bd9Sstevel@tonic-gate   gl->underline = NULL;
18467c478bd9Sstevel@tonic-gate   gl->standout = NULL;
18477c478bd9Sstevel@tonic-gate   gl->dim = NULL;
18487c478bd9Sstevel@tonic-gate   gl->reverse = NULL;
18497c478bd9Sstevel@tonic-gate   gl->blink = NULL;
18507c478bd9Sstevel@tonic-gate   gl->text_attr_off = NULL;
18517c478bd9Sstevel@tonic-gate   gl->nline = 0;
18527c478bd9Sstevel@tonic-gate   gl->ncolumn = 0;
18537c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
18547c478bd9Sstevel@tonic-gate   gl->left_n = NULL;
18557c478bd9Sstevel@tonic-gate   gl->right_n = NULL;
18567c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP)
18577c478bd9Sstevel@tonic-gate   gl->tgetent_buf = NULL;
18587c478bd9Sstevel@tonic-gate   gl->tgetstr_buf = NULL;
18597c478bd9Sstevel@tonic-gate #endif
18607c478bd9Sstevel@tonic-gate   gl->app_file = NULL;
18617c478bd9Sstevel@tonic-gate   gl->user_file = NULL;
18627c478bd9Sstevel@tonic-gate   gl->configured = 0;
18637c478bd9Sstevel@tonic-gate   gl->echo = 1;
18647c478bd9Sstevel@tonic-gate   gl->last_signal = -1;
18657c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
18667c478bd9Sstevel@tonic-gate   gl->fd_node_mem = NULL;
18677c478bd9Sstevel@tonic-gate   gl->fd_nodes = NULL;
18687c478bd9Sstevel@tonic-gate   FD_ZERO(&gl->rfds);
18697c478bd9Sstevel@tonic-gate   FD_ZERO(&gl->wfds);
18707c478bd9Sstevel@tonic-gate   FD_ZERO(&gl->ufds);
18717c478bd9Sstevel@tonic-gate   gl->max_fd = 0;
18727c478bd9Sstevel@tonic-gate   gl->timer.dt.tv_sec = 0;
18737c478bd9Sstevel@tonic-gate   gl->timer.dt.tv_usec = 0;
18747c478bd9Sstevel@tonic-gate   gl->timer.fn = 0;
18757c478bd9Sstevel@tonic-gate   gl->timer.data = NULL;
18767c478bd9Sstevel@tonic-gate #endif
18777c478bd9Sstevel@tonic-gate /*
18787c478bd9Sstevel@tonic-gate  * Allocate an error reporting buffer.
18797c478bd9Sstevel@tonic-gate  */
18807c478bd9Sstevel@tonic-gate   gl->err = _new_ErrMsg();
18817c478bd9Sstevel@tonic-gate   if(!gl->err)
18827c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
18837c478bd9Sstevel@tonic-gate /*
18847c478bd9Sstevel@tonic-gate  * Allocate the history buffer.
18857c478bd9Sstevel@tonic-gate  */
18867c478bd9Sstevel@tonic-gate   gl->glh = _new_GlHistory(histlen);
18877c478bd9Sstevel@tonic-gate   if(!gl->glh)
18887c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
18897c478bd9Sstevel@tonic-gate /*
18907c478bd9Sstevel@tonic-gate  * Allocate the resource object for file-completion.
18917c478bd9Sstevel@tonic-gate  */
18927c478bd9Sstevel@tonic-gate   gl->cpl = new_WordCompletion();
18937c478bd9Sstevel@tonic-gate   if(!gl->cpl)
18947c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
18957c478bd9Sstevel@tonic-gate /*
18967c478bd9Sstevel@tonic-gate  * Allocate the resource object for file-completion.
18977c478bd9Sstevel@tonic-gate  */
18987c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM
18997c478bd9Sstevel@tonic-gate   gl->ef = new_ExpandFile();
19007c478bd9Sstevel@tonic-gate   if(!gl->ef)
19017c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19027c478bd9Sstevel@tonic-gate #endif
19037c478bd9Sstevel@tonic-gate /*
19047c478bd9Sstevel@tonic-gate  * Allocate a string-segment memory allocator for use in storing terminal
19057c478bd9Sstevel@tonic-gate  * capablity strings.
19067c478bd9Sstevel@tonic-gate  */
19077c478bd9Sstevel@tonic-gate   gl->capmem = _new_StringGroup(CAPMEM_SEGMENT_SIZE);
19087c478bd9Sstevel@tonic-gate   if(!gl->capmem)
19097c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19107c478bd9Sstevel@tonic-gate /*
19117c478bd9Sstevel@tonic-gate  * Allocate the character queue that is used to buffer terminal output.
19127c478bd9Sstevel@tonic-gate  */
19137c478bd9Sstevel@tonic-gate   gl->cq = _new_GlCharQueue();
19147c478bd9Sstevel@tonic-gate   if(!gl->cq)
19157c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19167c478bd9Sstevel@tonic-gate /*
19177c478bd9Sstevel@tonic-gate  * Allocate a line buffer, leaving 2 extra characters for the terminating
19187c478bd9Sstevel@tonic-gate  * '\n' and '\0' characters
19197c478bd9Sstevel@tonic-gate  */
19207c478bd9Sstevel@tonic-gate   gl->line = (char *) malloc(linelen + 2);
19217c478bd9Sstevel@tonic-gate   if(!gl->line) {
19227c478bd9Sstevel@tonic-gate     errno = ENOMEM;
19237c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19247c478bd9Sstevel@tonic-gate   };
19257c478bd9Sstevel@tonic-gate /*
19267c478bd9Sstevel@tonic-gate  * Start with an empty input line.
19277c478bd9Sstevel@tonic-gate  */
19287c478bd9Sstevel@tonic-gate   gl_truncate_buffer(gl, 0);
19297c478bd9Sstevel@tonic-gate /*
19307c478bd9Sstevel@tonic-gate  * Allocate a cut buffer.
19317c478bd9Sstevel@tonic-gate  */
19327c478bd9Sstevel@tonic-gate   gl->cutbuf = (char *) malloc(linelen + 2);
19337c478bd9Sstevel@tonic-gate   if(!gl->cutbuf) {
19347c478bd9Sstevel@tonic-gate     errno = ENOMEM;
19357c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19367c478bd9Sstevel@tonic-gate   };
19377c478bd9Sstevel@tonic-gate   gl->cutbuf[0] = '\0';
19387c478bd9Sstevel@tonic-gate /*
19397c478bd9Sstevel@tonic-gate  * Allocate an initial empty prompt.
19407c478bd9Sstevel@tonic-gate  */
19417c478bd9Sstevel@tonic-gate   _gl_replace_prompt(gl, NULL);
19427c478bd9Sstevel@tonic-gate   if(!gl->prompt) {
19437c478bd9Sstevel@tonic-gate     errno = ENOMEM;
19447c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19457c478bd9Sstevel@tonic-gate   };
19467c478bd9Sstevel@tonic-gate /*
19477c478bd9Sstevel@tonic-gate  * Allocate a vi undo buffer.
19487c478bd9Sstevel@tonic-gate  */
19497c478bd9Sstevel@tonic-gate   gl->vi.undo.line = (char *) malloc(linelen + 2);
19507c478bd9Sstevel@tonic-gate   if(!gl->vi.undo.line) {
19517c478bd9Sstevel@tonic-gate     errno = ENOMEM;
19527c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19537c478bd9Sstevel@tonic-gate   };
19547c478bd9Sstevel@tonic-gate   gl->vi.undo.line[0] = '\0';
19557c478bd9Sstevel@tonic-gate /*
19567c478bd9Sstevel@tonic-gate  * Allocate a freelist from which to allocate nodes for the list
19577c478bd9Sstevel@tonic-gate  * of completion functions.
19587c478bd9Sstevel@tonic-gate  */
19597c478bd9Sstevel@tonic-gate   gl->cpl_mem = _new_FreeList(sizeof(GlCplCallback), GL_CPL_FREELIST_BLOCKING);
19607c478bd9Sstevel@tonic-gate   if(!gl->cpl_mem)
19617c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19627c478bd9Sstevel@tonic-gate /*
19637c478bd9Sstevel@tonic-gate  * Allocate a freelist from which to allocate nodes for the list
19647c478bd9Sstevel@tonic-gate  * of external action functions.
19657c478bd9Sstevel@tonic-gate  */
19667c478bd9Sstevel@tonic-gate   gl->ext_act_mem = _new_FreeList(sizeof(GlExternalAction),
19677c478bd9Sstevel@tonic-gate 				  GL_EXT_ACT_FREELIST_BLOCKING);
19687c478bd9Sstevel@tonic-gate   if(!gl->ext_act_mem)
19697c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19707c478bd9Sstevel@tonic-gate /*
19717c478bd9Sstevel@tonic-gate  * Allocate a freelist from which to allocate nodes for the list
19727c478bd9Sstevel@tonic-gate  * of signals.
19737c478bd9Sstevel@tonic-gate  */
19747c478bd9Sstevel@tonic-gate   gl->sig_mem = _new_FreeList(sizeof(GlSignalNode), GLS_FREELIST_BLOCKING);
19757c478bd9Sstevel@tonic-gate   if(!gl->sig_mem)
19767c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19777c478bd9Sstevel@tonic-gate /*
19787c478bd9Sstevel@tonic-gate  * Install initial dispositions for the default list of signals that
19797c478bd9Sstevel@tonic-gate  * gl_get_line() traps.
19807c478bd9Sstevel@tonic-gate  */
19817c478bd9Sstevel@tonic-gate   for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
19827c478bd9Sstevel@tonic-gate     const struct GlDefSignal *sig = gl_signal_list + i;
19837c478bd9Sstevel@tonic-gate     if(_gl_trap_signal(gl, sig->signo, sig->flags, sig->after,
19847c478bd9Sstevel@tonic-gate 		       sig->errno_value))
19857c478bd9Sstevel@tonic-gate       return del_GetLine(gl);
19867c478bd9Sstevel@tonic-gate   };
19877c478bd9Sstevel@tonic-gate /*
19887c478bd9Sstevel@tonic-gate  * Allocate an empty table of key bindings.
19897c478bd9Sstevel@tonic-gate  */
19907c478bd9Sstevel@tonic-gate   gl->bindings = _new_KeyTab();
19917c478bd9Sstevel@tonic-gate   if(!gl->bindings)
19927c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
19937c478bd9Sstevel@tonic-gate /*
19947c478bd9Sstevel@tonic-gate  * Define the available actions that can be bound to key sequences.
19957c478bd9Sstevel@tonic-gate  */
19967c478bd9Sstevel@tonic-gate   for(i=0; i<sizeof(gl_actions)/sizeof(gl_actions[0]); i++) {
19977c478bd9Sstevel@tonic-gate     if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn, NULL))
19987c478bd9Sstevel@tonic-gate       return del_GetLine(gl);
19997c478bd9Sstevel@tonic-gate   };
20007c478bd9Sstevel@tonic-gate /*
20017c478bd9Sstevel@tonic-gate  * Set up the default bindings.
20027c478bd9Sstevel@tonic-gate  */
20037c478bd9Sstevel@tonic-gate   if(gl_change_editor(gl, gl->editor))
20047c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
20057c478bd9Sstevel@tonic-gate /*
20067c478bd9Sstevel@tonic-gate  * Allocate termcap buffers.
20077c478bd9Sstevel@tonic-gate  */
20087c478bd9Sstevel@tonic-gate #ifdef USE_TERMCAP
20097c478bd9Sstevel@tonic-gate   gl->tgetent_buf = (char *) malloc(TERMCAP_BUF_SIZE);
20107c478bd9Sstevel@tonic-gate   gl->tgetstr_buf = (char *) malloc(TERMCAP_BUF_SIZE);
20117c478bd9Sstevel@tonic-gate   if(!gl->tgetent_buf || !gl->tgetstr_buf) {
20127c478bd9Sstevel@tonic-gate     errno = ENOMEM;
20137c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
20147c478bd9Sstevel@tonic-gate   };
20157c478bd9Sstevel@tonic-gate #endif
20167c478bd9Sstevel@tonic-gate /*
20177c478bd9Sstevel@tonic-gate  * Set up for I/O assuming stdin and stdout.
20187c478bd9Sstevel@tonic-gate  */
20197c478bd9Sstevel@tonic-gate   if(_gl_change_terminal(gl, stdin, stdout, getenv("TERM")))
20207c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
20217c478bd9Sstevel@tonic-gate /*
20227c478bd9Sstevel@tonic-gate  * Create a freelist for use in allocating GlFdNode list nodes.
20237c478bd9Sstevel@tonic-gate  */
20247c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
20257c478bd9Sstevel@tonic-gate   gl->fd_node_mem = _new_FreeList(sizeof(GlFdNode), GLFD_FREELIST_BLOCKING);
20267c478bd9Sstevel@tonic-gate   if(!gl->fd_node_mem)
20277c478bd9Sstevel@tonic-gate     return del_GetLine(gl);
20287c478bd9Sstevel@tonic-gate #endif
20297c478bd9Sstevel@tonic-gate /*
20307c478bd9Sstevel@tonic-gate  * We are done for now.
20317c478bd9Sstevel@tonic-gate  */
20327c478bd9Sstevel@tonic-gate   return gl;
20337c478bd9Sstevel@tonic-gate }
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate /*.......................................................................
20367c478bd9Sstevel@tonic-gate  * Delete a GetLine object.
20377c478bd9Sstevel@tonic-gate  *
20387c478bd9Sstevel@tonic-gate  * Input:
20397c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The object to be deleted.
20407c478bd9Sstevel@tonic-gate  * Output:
20417c478bd9Sstevel@tonic-gate  *  return GetLine *  The deleted object (always NULL).
20427c478bd9Sstevel@tonic-gate  */
del_GetLine(GetLine * gl)20437c478bd9Sstevel@tonic-gate GetLine *del_GetLine(GetLine *gl)
20447c478bd9Sstevel@tonic-gate {
20457c478bd9Sstevel@tonic-gate   if(gl) {
20467c478bd9Sstevel@tonic-gate /*
20477c478bd9Sstevel@tonic-gate  * If the terminal is in raw server mode, reset it.
20487c478bd9Sstevel@tonic-gate  */
20497c478bd9Sstevel@tonic-gate     _gl_normal_io(gl);
20507c478bd9Sstevel@tonic-gate /*
20517c478bd9Sstevel@tonic-gate  * Deallocate all objects contained by gl.
20527c478bd9Sstevel@tonic-gate  */
20537c478bd9Sstevel@tonic-gate     gl->err = _del_ErrMsg(gl->err);
20547c478bd9Sstevel@tonic-gate     gl->glh = _del_GlHistory(gl->glh);
20557c478bd9Sstevel@tonic-gate     gl->cpl = del_WordCompletion(gl->cpl);
20567c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM
20577c478bd9Sstevel@tonic-gate     gl->ef = del_ExpandFile(gl->ef);
20587c478bd9Sstevel@tonic-gate #endif
20597c478bd9Sstevel@tonic-gate     gl->capmem = _del_StringGroup(gl->capmem);
20607c478bd9Sstevel@tonic-gate     gl->cq = _del_GlCharQueue(gl->cq);
20617c478bd9Sstevel@tonic-gate     if(gl->file_fp)
20627c478bd9Sstevel@tonic-gate       fclose(gl->file_fp);
20637c478bd9Sstevel@tonic-gate     if(gl->term)
20647c478bd9Sstevel@tonic-gate       free(gl->term);
20657c478bd9Sstevel@tonic-gate     if(gl->line)
20667c478bd9Sstevel@tonic-gate       free(gl->line);
20677c478bd9Sstevel@tonic-gate     if(gl->cutbuf)
20687c478bd9Sstevel@tonic-gate       free(gl->cutbuf);
20697c478bd9Sstevel@tonic-gate     if(gl->prompt)
20707c478bd9Sstevel@tonic-gate       free(gl->prompt);
20717c478bd9Sstevel@tonic-gate     gl->cpl_mem = _del_FreeList(gl->cpl_mem, 1);
20727c478bd9Sstevel@tonic-gate     gl->ext_act_mem = _del_FreeList(gl->ext_act_mem, 1);
20737c478bd9Sstevel@tonic-gate     gl->sig_mem = _del_FreeList(gl->sig_mem, 1);
20747c478bd9Sstevel@tonic-gate     gl->sigs = NULL;       /* Already freed by freeing sig_mem */
20757c478bd9Sstevel@tonic-gate     gl->bindings = _del_KeyTab(gl->bindings);
20767c478bd9Sstevel@tonic-gate     if(gl->vi.undo.line)
20777c478bd9Sstevel@tonic-gate       free(gl->vi.undo.line);
20787c478bd9Sstevel@tonic-gate #ifdef USE_TERMCAP
20797c478bd9Sstevel@tonic-gate     if(gl->tgetent_buf)
20807c478bd9Sstevel@tonic-gate       free(gl->tgetent_buf);
20817c478bd9Sstevel@tonic-gate     if(gl->tgetstr_buf)
20827c478bd9Sstevel@tonic-gate       free(gl->tgetstr_buf);
20837c478bd9Sstevel@tonic-gate #endif
20847c478bd9Sstevel@tonic-gate     if(gl->app_file)
20857c478bd9Sstevel@tonic-gate       free(gl->app_file);
20867c478bd9Sstevel@tonic-gate     if(gl->user_file)
20877c478bd9Sstevel@tonic-gate       free(gl->user_file);
20887c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
20897c478bd9Sstevel@tonic-gate     gl->fd_node_mem = _del_FreeList(gl->fd_node_mem, 1);
20907c478bd9Sstevel@tonic-gate     gl->fd_nodes = NULL;  /* Already freed by freeing gl->fd_node_mem */
20917c478bd9Sstevel@tonic-gate #endif
20927c478bd9Sstevel@tonic-gate /*
20937c478bd9Sstevel@tonic-gate  * Delete the now empty container.
20947c478bd9Sstevel@tonic-gate  */
20957c478bd9Sstevel@tonic-gate     free(gl);
20967c478bd9Sstevel@tonic-gate   };
20977c478bd9Sstevel@tonic-gate   return NULL;
20987c478bd9Sstevel@tonic-gate }
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate /*.......................................................................
21017c478bd9Sstevel@tonic-gate  * Bind a control or meta character to an action.
21027c478bd9Sstevel@tonic-gate  *
21037c478bd9Sstevel@tonic-gate  * Input:
21047c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of this program.
21057c478bd9Sstevel@tonic-gate  *  binder    KtBinder    The source of the binding.
21067c478bd9Sstevel@tonic-gate  *  c             char    The control or meta character.
21077c478bd9Sstevel@tonic-gate  *                        If this is '\0', the call is ignored.
21087c478bd9Sstevel@tonic-gate  *  action  const char *  The action name to bind the key to.
21097c478bd9Sstevel@tonic-gate  * Output:
21107c478bd9Sstevel@tonic-gate  *  return         int    0 - OK.
21117c478bd9Sstevel@tonic-gate  *                        1 - Error.
21127c478bd9Sstevel@tonic-gate  */
gl_bind_control_char(GetLine * gl,KtBinder binder,char c,const char * action)21137c478bd9Sstevel@tonic-gate static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c,
21147c478bd9Sstevel@tonic-gate 				const char *action)
21157c478bd9Sstevel@tonic-gate {
21167c478bd9Sstevel@tonic-gate   char keyseq[2];
21177c478bd9Sstevel@tonic-gate /*
21187c478bd9Sstevel@tonic-gate  * Quietly reject binding to the NUL control character, since this
21197c478bd9Sstevel@tonic-gate  * is an ambiguous prefix of all bindings.
21207c478bd9Sstevel@tonic-gate  */
21217c478bd9Sstevel@tonic-gate   if(c == '\0')
21227c478bd9Sstevel@tonic-gate     return 0;
21237c478bd9Sstevel@tonic-gate /*
21247c478bd9Sstevel@tonic-gate  * Making sure not to bind characters which aren't either control or
21257c478bd9Sstevel@tonic-gate  * meta characters.
21267c478bd9Sstevel@tonic-gate  */
21277c478bd9Sstevel@tonic-gate   if(IS_CTRL_CHAR(c) || IS_META_CHAR(c)) {
21287c478bd9Sstevel@tonic-gate     keyseq[0] = c;
21297c478bd9Sstevel@tonic-gate     keyseq[1] = '\0';
21307c478bd9Sstevel@tonic-gate   } else {
21317c478bd9Sstevel@tonic-gate     return 0;
21327c478bd9Sstevel@tonic-gate   };
21337c478bd9Sstevel@tonic-gate /*
21347c478bd9Sstevel@tonic-gate  * Install the binding.
21357c478bd9Sstevel@tonic-gate  */
21367c478bd9Sstevel@tonic-gate   if(_kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
21377c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
21387c478bd9Sstevel@tonic-gate     return 1;
21397c478bd9Sstevel@tonic-gate   };
21407c478bd9Sstevel@tonic-gate   return 0;
21417c478bd9Sstevel@tonic-gate }
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate /*.......................................................................
21447c478bd9Sstevel@tonic-gate  * Read a line from the user.
21457c478bd9Sstevel@tonic-gate  *
21467c478bd9Sstevel@tonic-gate  * Input:
21477c478bd9Sstevel@tonic-gate  *  gl       GetLine *  A resource object returned by new_GetLine().
21487c478bd9Sstevel@tonic-gate  *  prompt      char *  The prompt to prefix the line with.
21497c478bd9Sstevel@tonic-gate  *  start_line  char *  The initial contents of the input line, or NULL
21507c478bd9Sstevel@tonic-gate  *                      if it should start out empty.
21517c478bd9Sstevel@tonic-gate  *  start_pos    int    If start_line isn't NULL, this specifies the
21527c478bd9Sstevel@tonic-gate  *                      index of the character over which the cursor
21537c478bd9Sstevel@tonic-gate  *                      should initially be positioned within the line.
21547c478bd9Sstevel@tonic-gate  *                      If you just want it to follow the last character
21557c478bd9Sstevel@tonic-gate  *                      of the line, send -1.
21567c478bd9Sstevel@tonic-gate  * Output:
21577c478bd9Sstevel@tonic-gate  *  return      char *  An internal buffer containing the input line, or
21587c478bd9Sstevel@tonic-gate  *                      NULL at the end of input. If the line fitted in
21597c478bd9Sstevel@tonic-gate  *                      the buffer there will be a '\n' newline character
21607c478bd9Sstevel@tonic-gate  *                      before the terminating '\0'. If it was truncated
21617c478bd9Sstevel@tonic-gate  *                      there will be no newline character, and the remains
21627c478bd9Sstevel@tonic-gate  *                      of the line should be retrieved via further calls
21637c478bd9Sstevel@tonic-gate  *                      to this function.
21647c478bd9Sstevel@tonic-gate  */
gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)21657c478bd9Sstevel@tonic-gate char *gl_get_line(GetLine *gl, const char *prompt,
21667c478bd9Sstevel@tonic-gate 		  const char *start_line, int start_pos)
21677c478bd9Sstevel@tonic-gate {
21687c478bd9Sstevel@tonic-gate   char *retval;   /* The return value of _gl_get_line() */
21697c478bd9Sstevel@tonic-gate /*
21707c478bd9Sstevel@tonic-gate  * Check the arguments.
21717c478bd9Sstevel@tonic-gate  */
21727c478bd9Sstevel@tonic-gate   if(!gl) {
21737c478bd9Sstevel@tonic-gate     errno = EINVAL;
21747c478bd9Sstevel@tonic-gate     return NULL;
21757c478bd9Sstevel@tonic-gate   };
21767c478bd9Sstevel@tonic-gate /*
21777c478bd9Sstevel@tonic-gate  * Temporarily block all of the signals that we have been asked to trap.
21787c478bd9Sstevel@tonic-gate  */
21797c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &gl->old_signal_set))
21807c478bd9Sstevel@tonic-gate     return NULL;
21817c478bd9Sstevel@tonic-gate /*
21827c478bd9Sstevel@tonic-gate  * Perform the command-line editing task.
21837c478bd9Sstevel@tonic-gate  */
21847c478bd9Sstevel@tonic-gate   retval = _gl_get_line(gl, prompt, start_line, start_pos);
21857c478bd9Sstevel@tonic-gate /*
21867c478bd9Sstevel@tonic-gate  * Restore the process signal mask to how it was when this function was
21877c478bd9Sstevel@tonic-gate  * first called.
21887c478bd9Sstevel@tonic-gate  */
21897c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &gl->old_signal_set);
21907c478bd9Sstevel@tonic-gate   return retval;
21917c478bd9Sstevel@tonic-gate }
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate /*.......................................................................
21957c478bd9Sstevel@tonic-gate  * This is the main body of the public function gl_get_line().
21967c478bd9Sstevel@tonic-gate  */
_gl_get_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)21977c478bd9Sstevel@tonic-gate static char *_gl_get_line(GetLine *gl, const char *prompt,
21987c478bd9Sstevel@tonic-gate 			  const char *start_line, int start_pos)
21997c478bd9Sstevel@tonic-gate {
22007c478bd9Sstevel@tonic-gate   int waserr = 0;    /* True if an error occurs */
22017c478bd9Sstevel@tonic-gate /*
22027c478bd9Sstevel@tonic-gate  * Assume that this call will successfully complete the input
22037c478bd9Sstevel@tonic-gate  * line until proven otherwise.
22047c478bd9Sstevel@tonic-gate  */
22057c478bd9Sstevel@tonic-gate   gl_clear_status(gl);
22067c478bd9Sstevel@tonic-gate /*
22077c478bd9Sstevel@tonic-gate  * If this is the first call to this function since new_GetLine(),
22087c478bd9Sstevel@tonic-gate  * complete any postponed configuration.
22097c478bd9Sstevel@tonic-gate  */
22107c478bd9Sstevel@tonic-gate   if(!gl->configured) {
22117c478bd9Sstevel@tonic-gate     (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
22127c478bd9Sstevel@tonic-gate     gl->configured = 1;
22137c478bd9Sstevel@tonic-gate   };
22147c478bd9Sstevel@tonic-gate /*
22157c478bd9Sstevel@tonic-gate  * Before installing our signal handler functions, record the fact
22167c478bd9Sstevel@tonic-gate  * that there are no pending signals.
22177c478bd9Sstevel@tonic-gate  */
22187c478bd9Sstevel@tonic-gate   gl_pending_signal = -1;
22197c478bd9Sstevel@tonic-gate /*
22207c478bd9Sstevel@tonic-gate  * Temporarily override the signal handlers of the calling program,
22217c478bd9Sstevel@tonic-gate  * so that we can intercept signals that would leave the terminal
22227c478bd9Sstevel@tonic-gate  * in a bad state.
22237c478bd9Sstevel@tonic-gate  */
22247c478bd9Sstevel@tonic-gate   waserr = gl_override_signal_handlers(gl);
22257c478bd9Sstevel@tonic-gate /*
22267c478bd9Sstevel@tonic-gate  * After recording the current terminal settings, switch the terminal
22277c478bd9Sstevel@tonic-gate  * into raw input mode.
22287c478bd9Sstevel@tonic-gate  */
22297c478bd9Sstevel@tonic-gate   waserr = waserr || _gl_raw_io(gl, 1);
22307c478bd9Sstevel@tonic-gate /*
22317c478bd9Sstevel@tonic-gate  * Attempt to read the line. This will require more than one attempt if
22327c478bd9Sstevel@tonic-gate  * either a current temporary input file is opened by gl_get_input_line()
22337c478bd9Sstevel@tonic-gate  * or the end of a temporary input file is reached by gl_read_stream_line().
22347c478bd9Sstevel@tonic-gate  */
22357c478bd9Sstevel@tonic-gate   while(!waserr) {
22367c478bd9Sstevel@tonic-gate /*
22377c478bd9Sstevel@tonic-gate  * Read a line from a non-interactive stream?
22387c478bd9Sstevel@tonic-gate  */
22397c478bd9Sstevel@tonic-gate     if(gl->file_fp || !gl->is_term) {
22407c478bd9Sstevel@tonic-gate       if(gl_read_stream_line(gl)==0) {
22417c478bd9Sstevel@tonic-gate 	break;
22427c478bd9Sstevel@tonic-gate       } else if(gl->file_fp) {
22437c478bd9Sstevel@tonic-gate 	gl_revert_input(gl);
22447c478bd9Sstevel@tonic-gate 	gl_record_status(gl, GLR_NEWLINE, 0);
22457c478bd9Sstevel@tonic-gate       } else {
22467c478bd9Sstevel@tonic-gate 	waserr = 1;
22477c478bd9Sstevel@tonic-gate 	break;
22487c478bd9Sstevel@tonic-gate       };
22497c478bd9Sstevel@tonic-gate     };
22507c478bd9Sstevel@tonic-gate /*
22517c478bd9Sstevel@tonic-gate  * Read from the terminal? Note that the above if() block may have
22527c478bd9Sstevel@tonic-gate  * changed gl->file_fp, so it is necessary to retest it here, rather
22537c478bd9Sstevel@tonic-gate  * than using an else statement.
22547c478bd9Sstevel@tonic-gate  */
22557c478bd9Sstevel@tonic-gate     if(!gl->file_fp && gl->is_term) {
22567c478bd9Sstevel@tonic-gate       if(gl_get_input_line(gl, prompt, start_line, start_pos))
22577c478bd9Sstevel@tonic-gate 	waserr = 1;
22587c478bd9Sstevel@tonic-gate       else
22597c478bd9Sstevel@tonic-gate 	break;
22607c478bd9Sstevel@tonic-gate     };
22617c478bd9Sstevel@tonic-gate   };
22627c478bd9Sstevel@tonic-gate /*
22637c478bd9Sstevel@tonic-gate  * If an error occurred, but gl->rtn_status is still set to
22647c478bd9Sstevel@tonic-gate  * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
22657c478bd9Sstevel@tonic-gate  * leave it at whatever specific value was assigned by the function
22667c478bd9Sstevel@tonic-gate  * that aborted input. This means that only functions that trap
22677c478bd9Sstevel@tonic-gate  * non-generic errors have to remember to update gl->rtn_status
22687c478bd9Sstevel@tonic-gate  * themselves.
22697c478bd9Sstevel@tonic-gate  */
22707c478bd9Sstevel@tonic-gate   if(waserr && gl->rtn_status == GLR_NEWLINE)
22717c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_ERROR, errno);
22727c478bd9Sstevel@tonic-gate /*
22737c478bd9Sstevel@tonic-gate  * Restore terminal settings.
22747c478bd9Sstevel@tonic-gate  */
22757c478bd9Sstevel@tonic-gate   if(gl->io_mode != GL_SERVER_MODE)
22767c478bd9Sstevel@tonic-gate     _gl_normal_io(gl);
22777c478bd9Sstevel@tonic-gate /*
22787c478bd9Sstevel@tonic-gate  * Restore the signal handlers.
22797c478bd9Sstevel@tonic-gate  */
22807c478bd9Sstevel@tonic-gate   gl_restore_signal_handlers(gl);
22817c478bd9Sstevel@tonic-gate /*
22827c478bd9Sstevel@tonic-gate  * If gl_get_line() gets aborted early, the errno value associated
22837c478bd9Sstevel@tonic-gate  * with the event that caused this to happen is recorded in
22847c478bd9Sstevel@tonic-gate  * gl->rtn_errno. Since errno may have been overwritten by cleanup
22857c478bd9Sstevel@tonic-gate  * functions after this, restore its value to the value that it had
22867c478bd9Sstevel@tonic-gate  * when the error condition occured, so that the caller can examine it
22877c478bd9Sstevel@tonic-gate  * to find out what happened.
22887c478bd9Sstevel@tonic-gate  */
22897c478bd9Sstevel@tonic-gate   errno = gl->rtn_errno;
22907c478bd9Sstevel@tonic-gate /*
22917c478bd9Sstevel@tonic-gate  * Check the completion status to see how to return.
22927c478bd9Sstevel@tonic-gate  */
22937c478bd9Sstevel@tonic-gate   switch(gl->rtn_status) {
22947c478bd9Sstevel@tonic-gate   case GLR_NEWLINE:    /* Success */
22957c478bd9Sstevel@tonic-gate     return gl->line;
22967c478bd9Sstevel@tonic-gate   case GLR_BLOCKED:    /* These events abort the current input line, */
22977c478bd9Sstevel@tonic-gate   case GLR_SIGNAL:     /*  when in normal blocking I/O mode, but only */
22987c478bd9Sstevel@tonic-gate   case GLR_TIMEOUT:    /*  temporarily pause line editing when in */
22997c478bd9Sstevel@tonic-gate   case GLR_FDABORT:    /*  non-blocking server I/O mode. */
23007c478bd9Sstevel@tonic-gate     if(gl->io_mode != GL_SERVER_MODE)
23017c478bd9Sstevel@tonic-gate       _gl_abandon_line(gl);
23027c478bd9Sstevel@tonic-gate     return NULL;
23037c478bd9Sstevel@tonic-gate   case GLR_ERROR:      /* Unrecoverable errors abort the input line, */
23047c478bd9Sstevel@tonic-gate   case GLR_EOF:        /*  regardless of the I/O mode. */
23057c478bd9Sstevel@tonic-gate   default:
23067c478bd9Sstevel@tonic-gate     _gl_abandon_line(gl);
23077c478bd9Sstevel@tonic-gate     return NULL;
23087c478bd9Sstevel@tonic-gate   };
23097c478bd9Sstevel@tonic-gate }
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate /*.......................................................................
23127c478bd9Sstevel@tonic-gate  * Read a single character from the user.
23137c478bd9Sstevel@tonic-gate  *
23147c478bd9Sstevel@tonic-gate  * Input:
23157c478bd9Sstevel@tonic-gate  *  gl       GetLine *  A resource object returned by new_GetLine().
23167c478bd9Sstevel@tonic-gate  *  prompt      char *  The prompt to prefix the line with, or NULL if
23177c478bd9Sstevel@tonic-gate  *                      no prompt is required.
23187c478bd9Sstevel@tonic-gate  *  defchar     char    The character to substitute if the
23197c478bd9Sstevel@tonic-gate  *                      user simply hits return, or '\n' if you don't
23207c478bd9Sstevel@tonic-gate  *                      need to substitute anything.
23217c478bd9Sstevel@tonic-gate  * Output:
23227c478bd9Sstevel@tonic-gate  *  return       int    The character that was read, or EOF if the read
23237c478bd9Sstevel@tonic-gate  *                      had to be aborted (in which case you can call
23247c478bd9Sstevel@tonic-gate  *                      gl_return_status() to find out why).
23257c478bd9Sstevel@tonic-gate  */
gl_query_char(GetLine * gl,const char * prompt,char defchar)23267c478bd9Sstevel@tonic-gate int gl_query_char(GetLine *gl, const char *prompt, char defchar)
23277c478bd9Sstevel@tonic-gate {
23287c478bd9Sstevel@tonic-gate   int retval;   /* The return value of _gl_query_char() */
23297c478bd9Sstevel@tonic-gate /*
23307c478bd9Sstevel@tonic-gate  * Check the arguments.
23317c478bd9Sstevel@tonic-gate  */
23327c478bd9Sstevel@tonic-gate   if(!gl) {
23337c478bd9Sstevel@tonic-gate     errno = EINVAL;
23347c478bd9Sstevel@tonic-gate     return EOF;
23357c478bd9Sstevel@tonic-gate   };
23367c478bd9Sstevel@tonic-gate /*
23377c478bd9Sstevel@tonic-gate  * Temporarily block all of the signals that we have been asked to trap.
23387c478bd9Sstevel@tonic-gate  */
23397c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &gl->old_signal_set))
23407c478bd9Sstevel@tonic-gate     return EOF;
23417c478bd9Sstevel@tonic-gate /*
23427c478bd9Sstevel@tonic-gate  * Perform the character reading task.
23437c478bd9Sstevel@tonic-gate  */
23447c478bd9Sstevel@tonic-gate   retval = _gl_query_char(gl, prompt, defchar);
23457c478bd9Sstevel@tonic-gate /*
23467c478bd9Sstevel@tonic-gate  * Restore the process signal mask to how it was when this function was
23477c478bd9Sstevel@tonic-gate  * first called.
23487c478bd9Sstevel@tonic-gate  */
23497c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &gl->old_signal_set);
23507c478bd9Sstevel@tonic-gate   return retval;
23517c478bd9Sstevel@tonic-gate }
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate /*.......................................................................
23547c478bd9Sstevel@tonic-gate  * This is the main body of the public function gl_query_char().
23557c478bd9Sstevel@tonic-gate  */
_gl_query_char(GetLine * gl,const char * prompt,char defchar)23567c478bd9Sstevel@tonic-gate static int _gl_query_char(GetLine *gl, const char *prompt, char defchar)
23577c478bd9Sstevel@tonic-gate {
23587c478bd9Sstevel@tonic-gate   int c = EOF;       /* The character to be returned */
23597c478bd9Sstevel@tonic-gate   int waserr = 0;    /* True if an error occurs */
23607c478bd9Sstevel@tonic-gate /*
23617c478bd9Sstevel@tonic-gate  * Assume that this call will successfully complete the input operation
23627c478bd9Sstevel@tonic-gate  * until proven otherwise.
23637c478bd9Sstevel@tonic-gate  */
23647c478bd9Sstevel@tonic-gate   gl_clear_status(gl);
23657c478bd9Sstevel@tonic-gate /*
23667c478bd9Sstevel@tonic-gate  * If this is the first call to this function or gl_get_line(),
23677c478bd9Sstevel@tonic-gate  * since new_GetLine(), complete any postponed configuration.
23687c478bd9Sstevel@tonic-gate  */
23697c478bd9Sstevel@tonic-gate   if(!gl->configured) {
23707c478bd9Sstevel@tonic-gate     (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
23717c478bd9Sstevel@tonic-gate     gl->configured = 1;
23727c478bd9Sstevel@tonic-gate   };
23737c478bd9Sstevel@tonic-gate /*
23747c478bd9Sstevel@tonic-gate  * Before installing our signal handler functions, record the fact
23757c478bd9Sstevel@tonic-gate  * that there are no pending signals.
23767c478bd9Sstevel@tonic-gate  */
23777c478bd9Sstevel@tonic-gate   gl_pending_signal = -1;
23787c478bd9Sstevel@tonic-gate /*
23797c478bd9Sstevel@tonic-gate  * Temporarily override the signal handlers of the calling program,
23807c478bd9Sstevel@tonic-gate  * so that we can intercept signals that would leave the terminal
23817c478bd9Sstevel@tonic-gate  * in a bad state.
23827c478bd9Sstevel@tonic-gate  */
23837c478bd9Sstevel@tonic-gate   waserr = gl_override_signal_handlers(gl);
23847c478bd9Sstevel@tonic-gate /*
23857c478bd9Sstevel@tonic-gate  * After recording the current terminal settings, switch the terminal
23867c478bd9Sstevel@tonic-gate  * into raw input mode without redisplaying any partially entered
23877c478bd9Sstevel@tonic-gate  * input line.
23887c478bd9Sstevel@tonic-gate  */
23897c478bd9Sstevel@tonic-gate   waserr = waserr || _gl_raw_io(gl, 0);
23907c478bd9Sstevel@tonic-gate /*
23917c478bd9Sstevel@tonic-gate  * Attempt to read the line. This will require more than one attempt if
23927c478bd9Sstevel@tonic-gate  * either a current temporary input file is opened by gl_get_input_line()
23937c478bd9Sstevel@tonic-gate  * or the end of a temporary input file is reached by gl_read_stream_line().
23947c478bd9Sstevel@tonic-gate  */
23957c478bd9Sstevel@tonic-gate   while(!waserr) {
23967c478bd9Sstevel@tonic-gate /*
23977c478bd9Sstevel@tonic-gate  * Read a line from a non-interactive stream?
23987c478bd9Sstevel@tonic-gate  */
23997c478bd9Sstevel@tonic-gate     if(gl->file_fp || !gl->is_term) {
24007c478bd9Sstevel@tonic-gate       c = gl_read_stream_char(gl);
24017c478bd9Sstevel@tonic-gate       if(c != EOF) {            /* Success? */
24027c478bd9Sstevel@tonic-gate 	if(c=='\n') c = defchar;
24037c478bd9Sstevel@tonic-gate 	break;
24047c478bd9Sstevel@tonic-gate       } else if(gl->file_fp) {  /* End of temporary input file? */
24057c478bd9Sstevel@tonic-gate 	gl_revert_input(gl);
24067c478bd9Sstevel@tonic-gate 	gl_record_status(gl, GLR_NEWLINE, 0);
24077c478bd9Sstevel@tonic-gate       } else {                  /* An error? */
24087c478bd9Sstevel@tonic-gate 	waserr = 1;
24097c478bd9Sstevel@tonic-gate 	break;
24107c478bd9Sstevel@tonic-gate       };
24117c478bd9Sstevel@tonic-gate     };
24127c478bd9Sstevel@tonic-gate /*
24137c478bd9Sstevel@tonic-gate  * Read from the terminal? Note that the above if() block may have
24147c478bd9Sstevel@tonic-gate  * changed gl->file_fp, so it is necessary to retest it here, rather
24157c478bd9Sstevel@tonic-gate  * than using an else statement.
24167c478bd9Sstevel@tonic-gate  */
24177c478bd9Sstevel@tonic-gate     if(!gl->file_fp && gl->is_term) {
24187c478bd9Sstevel@tonic-gate       c = gl_get_query_char(gl, prompt, defchar);
24197c478bd9Sstevel@tonic-gate       if(c==EOF)
24207c478bd9Sstevel@tonic-gate 	waserr = 1;
24217c478bd9Sstevel@tonic-gate       else
24227c478bd9Sstevel@tonic-gate 	break;
24237c478bd9Sstevel@tonic-gate     };
24247c478bd9Sstevel@tonic-gate   };
24257c478bd9Sstevel@tonic-gate /*
24267c478bd9Sstevel@tonic-gate  * If an error occurred, but gl->rtn_status is still set to
24277c478bd9Sstevel@tonic-gate  * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
24287c478bd9Sstevel@tonic-gate  * leave it at whatever specific value was assigned by the function
24297c478bd9Sstevel@tonic-gate  * that aborted input. This means that only functions that trap
24307c478bd9Sstevel@tonic-gate  * non-generic errors have to remember to update gl->rtn_status
24317c478bd9Sstevel@tonic-gate  * themselves.
24327c478bd9Sstevel@tonic-gate  */
24337c478bd9Sstevel@tonic-gate   if(waserr && gl->rtn_status == GLR_NEWLINE)
24347c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_ERROR, errno);
24357c478bd9Sstevel@tonic-gate /*
24367c478bd9Sstevel@tonic-gate  * Restore terminal settings.
24377c478bd9Sstevel@tonic-gate  */
24387c478bd9Sstevel@tonic-gate   if(gl->io_mode != GL_SERVER_MODE)
24397c478bd9Sstevel@tonic-gate     _gl_normal_io(gl);
24407c478bd9Sstevel@tonic-gate /*
24417c478bd9Sstevel@tonic-gate  * Restore the signal handlers.
24427c478bd9Sstevel@tonic-gate  */
24437c478bd9Sstevel@tonic-gate   gl_restore_signal_handlers(gl);
24447c478bd9Sstevel@tonic-gate /*
24457c478bd9Sstevel@tonic-gate  * If this function gets aborted early, the errno value associated
24467c478bd9Sstevel@tonic-gate  * with the event that caused this to happen is recorded in
24477c478bd9Sstevel@tonic-gate  * gl->rtn_errno. Since errno may have been overwritten by cleanup
24487c478bd9Sstevel@tonic-gate  * functions after this, restore its value to the value that it had
24497c478bd9Sstevel@tonic-gate  * when the error condition occured, so that the caller can examine it
24507c478bd9Sstevel@tonic-gate  * to find out what happened.
24517c478bd9Sstevel@tonic-gate  */
24527c478bd9Sstevel@tonic-gate   errno = gl->rtn_errno;
24537c478bd9Sstevel@tonic-gate /*
24547c478bd9Sstevel@tonic-gate  * Error conditions are signalled to the caller, by setting the returned
24557c478bd9Sstevel@tonic-gate  * character to EOF.
24567c478bd9Sstevel@tonic-gate  */
24577c478bd9Sstevel@tonic-gate   if(gl->rtn_status != GLR_NEWLINE)
24587c478bd9Sstevel@tonic-gate     c = EOF;
24597c478bd9Sstevel@tonic-gate /*
24607c478bd9Sstevel@tonic-gate  * In this mode, every character that is read is a completed
24617c478bd9Sstevel@tonic-gate  * transaction, just like reading a completed input line, so prepare
24627c478bd9Sstevel@tonic-gate  * for the next input line or character.
24637c478bd9Sstevel@tonic-gate  */
24647c478bd9Sstevel@tonic-gate   _gl_abandon_line(gl);
24657c478bd9Sstevel@tonic-gate /*
24667c478bd9Sstevel@tonic-gate  * Return the acquired character.
24677c478bd9Sstevel@tonic-gate  */
24687c478bd9Sstevel@tonic-gate   return c;
24697c478bd9Sstevel@tonic-gate }
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate /*.......................................................................
24727c478bd9Sstevel@tonic-gate  * Record of the signal handlers of the calling program, so that they
24737c478bd9Sstevel@tonic-gate  * can be restored later.
24747c478bd9Sstevel@tonic-gate  *
24757c478bd9Sstevel@tonic-gate  * Input:
24767c478bd9Sstevel@tonic-gate  *  gl    GetLine *   The resource object of this library.
24777c478bd9Sstevel@tonic-gate  * Output:
24787c478bd9Sstevel@tonic-gate  *  return    int     0 - OK.
24797c478bd9Sstevel@tonic-gate  *                    1 - Error.
24807c478bd9Sstevel@tonic-gate  */
gl_override_signal_handlers(GetLine * gl)24817c478bd9Sstevel@tonic-gate static int gl_override_signal_handlers(GetLine *gl)
24827c478bd9Sstevel@tonic-gate {
24837c478bd9Sstevel@tonic-gate   GlSignalNode *sig;   /* A node in the list of signals to be caught */
24847c478bd9Sstevel@tonic-gate /*
24857c478bd9Sstevel@tonic-gate  * Set up our signal handler.
24867c478bd9Sstevel@tonic-gate  */
24877c478bd9Sstevel@tonic-gate   SigAction act;
24887c478bd9Sstevel@tonic-gate   act.sa_handler = gl_signal_handler;
24897c478bd9Sstevel@tonic-gate   memcpy(&act.sa_mask, &gl->all_signal_set, sizeof(sigset_t));
24907c478bd9Sstevel@tonic-gate   act.sa_flags = 0;
24917c478bd9Sstevel@tonic-gate /*
24927c478bd9Sstevel@tonic-gate  * Get the subset of the signals that we are supposed to trap that
24937c478bd9Sstevel@tonic-gate  * should actually be trapped.
24947c478bd9Sstevel@tonic-gate  */
24957c478bd9Sstevel@tonic-gate   sigemptyset(&gl->use_signal_set);
24967c478bd9Sstevel@tonic-gate   for(sig=gl->sigs; sig; sig=sig->next) {
24977c478bd9Sstevel@tonic-gate /*
24987c478bd9Sstevel@tonic-gate  * Trap this signal? If it is blocked by the calling program and we
24997c478bd9Sstevel@tonic-gate  * haven't been told to unblock it, don't arrange to trap this signal.
25007c478bd9Sstevel@tonic-gate  */
25017c478bd9Sstevel@tonic-gate     if(sig->flags & GLS_UNBLOCK_SIG ||
25027c478bd9Sstevel@tonic-gate        !sigismember(&gl->old_signal_set, sig->signo)) {
25037c478bd9Sstevel@tonic-gate       if(sigaddset(&gl->use_signal_set, sig->signo) == -1) {
25047c478bd9Sstevel@tonic-gate 	_err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
25057c478bd9Sstevel@tonic-gate 	return 1;
25067c478bd9Sstevel@tonic-gate       };
25077c478bd9Sstevel@tonic-gate     };
25087c478bd9Sstevel@tonic-gate   };
25097c478bd9Sstevel@tonic-gate /*
25107c478bd9Sstevel@tonic-gate  * Override the actions of the signals that we are trapping.
25117c478bd9Sstevel@tonic-gate  */
25127c478bd9Sstevel@tonic-gate   for(sig=gl->sigs; sig; sig=sig->next) {
25137c478bd9Sstevel@tonic-gate     if(sigismember(&gl->use_signal_set, sig->signo)) {
25147c478bd9Sstevel@tonic-gate       sigdelset(&act.sa_mask, sig->signo);
25157c478bd9Sstevel@tonic-gate       if(sigaction(sig->signo, &act, &sig->original)) {
25167c478bd9Sstevel@tonic-gate 	_err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
25177c478bd9Sstevel@tonic-gate 	return 1;
25187c478bd9Sstevel@tonic-gate       };
25197c478bd9Sstevel@tonic-gate       sigaddset(&act.sa_mask, sig->signo);
25207c478bd9Sstevel@tonic-gate     };
25217c478bd9Sstevel@tonic-gate   };
25227c478bd9Sstevel@tonic-gate /*
25237c478bd9Sstevel@tonic-gate  * Record the fact that the application's signal handlers have now
25247c478bd9Sstevel@tonic-gate  * been overriden.
25257c478bd9Sstevel@tonic-gate  */
25267c478bd9Sstevel@tonic-gate   gl->signals_overriden = 1;
25277c478bd9Sstevel@tonic-gate /*
25287c478bd9Sstevel@tonic-gate  * Just in case a SIGWINCH signal was sent to the process while our
25297c478bd9Sstevel@tonic-gate  * SIGWINCH signal handler wasn't in place, check to see if the terminal
25307c478bd9Sstevel@tonic-gate  * size needs updating.
25317c478bd9Sstevel@tonic-gate  */
25327c478bd9Sstevel@tonic-gate   if(_gl_update_size(gl))
25337c478bd9Sstevel@tonic-gate     return 1;
25347c478bd9Sstevel@tonic-gate   return 0;
25357c478bd9Sstevel@tonic-gate }
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate /*.......................................................................
25387c478bd9Sstevel@tonic-gate  * Restore the signal handlers of the calling program.
25397c478bd9Sstevel@tonic-gate  *
25407c478bd9Sstevel@tonic-gate  * Input:
25417c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The resource object of this library.
25427c478bd9Sstevel@tonic-gate  * Output:
25437c478bd9Sstevel@tonic-gate  *  return     int    0 - OK.
25447c478bd9Sstevel@tonic-gate  *                    1 - Error.
25457c478bd9Sstevel@tonic-gate  */
gl_restore_signal_handlers(GetLine * gl)25467c478bd9Sstevel@tonic-gate static int gl_restore_signal_handlers(GetLine *gl)
25477c478bd9Sstevel@tonic-gate {
25487c478bd9Sstevel@tonic-gate   GlSignalNode *sig;   /* A node in the list of signals to be caught */
25497c478bd9Sstevel@tonic-gate /*
25507c478bd9Sstevel@tonic-gate  * Restore application signal handlers that were overriden
25517c478bd9Sstevel@tonic-gate  * by gl_override_signal_handlers().
25527c478bd9Sstevel@tonic-gate  */
25537c478bd9Sstevel@tonic-gate   for(sig=gl->sigs; sig; sig=sig->next) {
25547c478bd9Sstevel@tonic-gate     if(sigismember(&gl->use_signal_set, sig->signo) &&
25557c478bd9Sstevel@tonic-gate        sigaction(sig->signo, &sig->original, NULL)) {
25567c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "sigaction error", END_ERR_MSG);
25577c478bd9Sstevel@tonic-gate       return 1;
25587c478bd9Sstevel@tonic-gate     };
25597c478bd9Sstevel@tonic-gate   };
25607c478bd9Sstevel@tonic-gate /*
25617c478bd9Sstevel@tonic-gate  * Record the fact that the application's signal handlers have now
25627c478bd9Sstevel@tonic-gate  * been restored.
25637c478bd9Sstevel@tonic-gate  */
25647c478bd9Sstevel@tonic-gate   gl->signals_overriden = 0;
25657c478bd9Sstevel@tonic-gate   return 0;
25667c478bd9Sstevel@tonic-gate }
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate /*.......................................................................
25697c478bd9Sstevel@tonic-gate  * This signal handler simply records the fact that a given signal was
25707c478bd9Sstevel@tonic-gate  * caught in the file-scope gl_pending_signal variable.
25717c478bd9Sstevel@tonic-gate  */
gl_signal_handler(int signo)25727c478bd9Sstevel@tonic-gate static void gl_signal_handler(int signo)
25737c478bd9Sstevel@tonic-gate {
25747c478bd9Sstevel@tonic-gate   gl_pending_signal = signo;
25757c478bd9Sstevel@tonic-gate   siglongjmp(gl_setjmp_buffer, 1);
25767c478bd9Sstevel@tonic-gate }
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate /*.......................................................................
25797c478bd9Sstevel@tonic-gate  * Switch the terminal into raw mode after storing the previous terminal
25807c478bd9Sstevel@tonic-gate  * settings in gl->attributes.
25817c478bd9Sstevel@tonic-gate  *
25827c478bd9Sstevel@tonic-gate  * Input:
25837c478bd9Sstevel@tonic-gate  *  gl     GetLine *   The resource object of this program.
25847c478bd9Sstevel@tonic-gate  * Output:
25857c478bd9Sstevel@tonic-gate  *  return     int     0 - OK.
25867c478bd9Sstevel@tonic-gate  *                     1 - Error.
25877c478bd9Sstevel@tonic-gate  */
gl_raw_terminal_mode(GetLine * gl)25887c478bd9Sstevel@tonic-gate static int gl_raw_terminal_mode(GetLine *gl)
25897c478bd9Sstevel@tonic-gate {
25907c478bd9Sstevel@tonic-gate   Termios newattr;   /* The new terminal attributes */
25917c478bd9Sstevel@tonic-gate /*
25927c478bd9Sstevel@tonic-gate  * If the terminal is already in raw mode, do nothing.
25937c478bd9Sstevel@tonic-gate  */
25947c478bd9Sstevel@tonic-gate   if(gl->raw_mode)
25957c478bd9Sstevel@tonic-gate     return 0;
25967c478bd9Sstevel@tonic-gate /*
25977c478bd9Sstevel@tonic-gate  * Record the current terminal attributes.
25987c478bd9Sstevel@tonic-gate  */
25997c478bd9Sstevel@tonic-gate   if(tcgetattr(gl->input_fd, &gl->oldattr)) {
26007c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
26017c478bd9Sstevel@tonic-gate     return 1;
26027c478bd9Sstevel@tonic-gate   };
26037c478bd9Sstevel@tonic-gate /*
26047c478bd9Sstevel@tonic-gate  * This function shouldn't do anything but record the current terminal
26057c478bd9Sstevel@tonic-gate  * attritubes if editing has been disabled.
26067c478bd9Sstevel@tonic-gate  */
26077c478bd9Sstevel@tonic-gate   if(gl->editor == GL_NO_EDITOR)
26087c478bd9Sstevel@tonic-gate     return 0;
26097c478bd9Sstevel@tonic-gate /*
26107c478bd9Sstevel@tonic-gate  * Modify the existing attributes.
26117c478bd9Sstevel@tonic-gate  */
26127c478bd9Sstevel@tonic-gate   newattr = gl->oldattr;
26137c478bd9Sstevel@tonic-gate /*
26147c478bd9Sstevel@tonic-gate  * Turn off local echo, canonical input mode and extended input processing.
26157c478bd9Sstevel@tonic-gate  */
26167c478bd9Sstevel@tonic-gate   newattr.c_lflag &= ~(ECHO | ICANON | IEXTEN);
26177c478bd9Sstevel@tonic-gate /*
26187c478bd9Sstevel@tonic-gate  * Don't translate carriage return to newline, turn off input parity
26197c478bd9Sstevel@tonic-gate  * checking, don't strip off 8th bit, turn off output flow control.
26207c478bd9Sstevel@tonic-gate  */
26217c478bd9Sstevel@tonic-gate   newattr.c_iflag &= ~(ICRNL | INPCK | ISTRIP);
26227c478bd9Sstevel@tonic-gate /*
26237c478bd9Sstevel@tonic-gate  * Clear size bits, turn off parity checking, and allow 8-bit characters.
26247c478bd9Sstevel@tonic-gate  */
26257c478bd9Sstevel@tonic-gate   newattr.c_cflag &= ~(CSIZE | PARENB);
26267c478bd9Sstevel@tonic-gate   newattr.c_cflag |= CS8;
26277c478bd9Sstevel@tonic-gate /*
26287c478bd9Sstevel@tonic-gate  * Turn off output processing.
26297c478bd9Sstevel@tonic-gate  */
26307c478bd9Sstevel@tonic-gate   newattr.c_oflag &= ~(OPOST);
26317c478bd9Sstevel@tonic-gate /*
26327c478bd9Sstevel@tonic-gate  * Request one byte at a time, without waiting.
26337c478bd9Sstevel@tonic-gate  */
26347c478bd9Sstevel@tonic-gate   newattr.c_cc[VMIN] = gl->io_mode==GL_SERVER_MODE ? 0:1;
26357c478bd9Sstevel@tonic-gate   newattr.c_cc[VTIME] = 0;
26367c478bd9Sstevel@tonic-gate /*
26377c478bd9Sstevel@tonic-gate  * Install the new terminal modes.
26387c478bd9Sstevel@tonic-gate  */
26397c478bd9Sstevel@tonic-gate   while(tcsetattr(gl->input_fd, TCSADRAIN, &newattr)) {
26407c478bd9Sstevel@tonic-gate     if(errno != EINTR) {
26417c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
26427c478bd9Sstevel@tonic-gate       return 1;
26437c478bd9Sstevel@tonic-gate     };
26447c478bd9Sstevel@tonic-gate   };
26457c478bd9Sstevel@tonic-gate /*
26467c478bd9Sstevel@tonic-gate  * Record the new terminal mode.
26477c478bd9Sstevel@tonic-gate  */
26487c478bd9Sstevel@tonic-gate   gl->raw_mode = 1;
26497c478bd9Sstevel@tonic-gate   return 0;
26507c478bd9Sstevel@tonic-gate }
26517c478bd9Sstevel@tonic-gate 
26527c478bd9Sstevel@tonic-gate /*.......................................................................
26537c478bd9Sstevel@tonic-gate  * Restore the terminal attributes recorded in gl->oldattr.
26547c478bd9Sstevel@tonic-gate  *
26557c478bd9Sstevel@tonic-gate  * Input:
26567c478bd9Sstevel@tonic-gate  *  gl     GetLine *   The resource object of this library.
26577c478bd9Sstevel@tonic-gate  * Output:
26587c478bd9Sstevel@tonic-gate  *  return     int     0 - OK.
26597c478bd9Sstevel@tonic-gate  *                     1 - Error.
26607c478bd9Sstevel@tonic-gate  */
gl_restore_terminal_attributes(GetLine * gl)26617c478bd9Sstevel@tonic-gate static int gl_restore_terminal_attributes(GetLine *gl)
26627c478bd9Sstevel@tonic-gate {
26637c478bd9Sstevel@tonic-gate   int waserr = 0;
26647c478bd9Sstevel@tonic-gate /*
26657c478bd9Sstevel@tonic-gate  * If not in raw mode, do nothing.
26667c478bd9Sstevel@tonic-gate  */
26677c478bd9Sstevel@tonic-gate   if(!gl->raw_mode)
26687c478bd9Sstevel@tonic-gate     return 0;
26697c478bd9Sstevel@tonic-gate /*
26707c478bd9Sstevel@tonic-gate  * Before changing the terminal attributes, make sure that all output
26717c478bd9Sstevel@tonic-gate  * has been passed to the terminal.
26727c478bd9Sstevel@tonic-gate  */
26737c478bd9Sstevel@tonic-gate   if(gl_flush_output(gl))
26747c478bd9Sstevel@tonic-gate     waserr = 1;
26757c478bd9Sstevel@tonic-gate /*
26767c478bd9Sstevel@tonic-gate  * Reset the terminal attributes to the values that they had on
26777c478bd9Sstevel@tonic-gate  * entry to gl_get_line().
26787c478bd9Sstevel@tonic-gate  */
26797c478bd9Sstevel@tonic-gate   while(tcsetattr(gl->input_fd, TCSADRAIN, &gl->oldattr)) {
26807c478bd9Sstevel@tonic-gate     if(errno != EINTR) {
26817c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
26827c478bd9Sstevel@tonic-gate       waserr = 1;
26837c478bd9Sstevel@tonic-gate       break;
26847c478bd9Sstevel@tonic-gate     };
26857c478bd9Sstevel@tonic-gate   };
26867c478bd9Sstevel@tonic-gate /*
26877c478bd9Sstevel@tonic-gate  * Record the new terminal mode.
26887c478bd9Sstevel@tonic-gate  */
26897c478bd9Sstevel@tonic-gate   gl->raw_mode = 0;
26907c478bd9Sstevel@tonic-gate   return waserr;
26917c478bd9Sstevel@tonic-gate }
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate /*.......................................................................
26947c478bd9Sstevel@tonic-gate  * Switch the terminal file descriptor to use non-blocking I/O.
26957c478bd9Sstevel@tonic-gate  *
26967c478bd9Sstevel@tonic-gate  * Input:
26977c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
26987c478bd9Sstevel@tonic-gate  *  fd             int    The file descriptor to make non-blocking.
26997c478bd9Sstevel@tonic-gate  */
gl_nonblocking_io(GetLine * gl,int fd)27007c478bd9Sstevel@tonic-gate static int gl_nonblocking_io(GetLine *gl, int fd)
27017c478bd9Sstevel@tonic-gate {
27027c478bd9Sstevel@tonic-gate   int fcntl_flags;   /* The new file-descriptor control flags */
27037c478bd9Sstevel@tonic-gate /*
27047c478bd9Sstevel@tonic-gate  * Is non-blocking I/O supported on this system?  Note that even
27057c478bd9Sstevel@tonic-gate  * without non-blocking I/O, the terminal will probably still act as
27067c478bd9Sstevel@tonic-gate  * though it was non-blocking, because we also set the terminal
27077c478bd9Sstevel@tonic-gate  * attributes to return immediately if no input is available and we
27087c478bd9Sstevel@tonic-gate  * use select() to wait to be able to write. If select() also isn't
27097c478bd9Sstevel@tonic-gate  * available, then input will probably remain fine, but output could
27107c478bd9Sstevel@tonic-gate  * block, depending on the behaviour of the terminal driver.
27117c478bd9Sstevel@tonic-gate  */
27127c478bd9Sstevel@tonic-gate #if defined(NON_BLOCKING_FLAG)
27137c478bd9Sstevel@tonic-gate /*
27147c478bd9Sstevel@tonic-gate  * Query the current file-control flags, and add the
27157c478bd9Sstevel@tonic-gate  * non-blocking I/O flag.
27167c478bd9Sstevel@tonic-gate  */
27177c478bd9Sstevel@tonic-gate   fcntl_flags = fcntl(fd, F_GETFL) | NON_BLOCKING_FLAG;
27187c478bd9Sstevel@tonic-gate /*
27197c478bd9Sstevel@tonic-gate  * Install the new control flags.
27207c478bd9Sstevel@tonic-gate  */
27217c478bd9Sstevel@tonic-gate   if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
27227c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
27237c478bd9Sstevel@tonic-gate     return 1;
27247c478bd9Sstevel@tonic-gate   };
27257c478bd9Sstevel@tonic-gate #endif
27267c478bd9Sstevel@tonic-gate   return 0;
27277c478bd9Sstevel@tonic-gate }
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate /*.......................................................................
27307c478bd9Sstevel@tonic-gate  * Switch to blocking terminal I/O.
27317c478bd9Sstevel@tonic-gate  *
27327c478bd9Sstevel@tonic-gate  * Input:
27337c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
27347c478bd9Sstevel@tonic-gate  *  fd             int    The file descriptor to make blocking.
27357c478bd9Sstevel@tonic-gate  */
gl_blocking_io(GetLine * gl,int fd)27367c478bd9Sstevel@tonic-gate static int gl_blocking_io(GetLine *gl, int fd)
27377c478bd9Sstevel@tonic-gate {
27387c478bd9Sstevel@tonic-gate   int fcntl_flags;   /* The new file-descriptor control flags */
27397c478bd9Sstevel@tonic-gate /*
27407c478bd9Sstevel@tonic-gate  * Is non-blocking I/O implemented on this system?
27417c478bd9Sstevel@tonic-gate  */
27427c478bd9Sstevel@tonic-gate #if defined(NON_BLOCKING_FLAG)
27437c478bd9Sstevel@tonic-gate /*
27447c478bd9Sstevel@tonic-gate  * Query the current file control flags and remove the non-blocking
27457c478bd9Sstevel@tonic-gate  * I/O flag.
27467c478bd9Sstevel@tonic-gate  */
27477c478bd9Sstevel@tonic-gate   fcntl_flags = fcntl(fd, F_GETFL) & ~NON_BLOCKING_FLAG;
27487c478bd9Sstevel@tonic-gate /*
27497c478bd9Sstevel@tonic-gate  * Install the modified control flags.
27507c478bd9Sstevel@tonic-gate  */
27517c478bd9Sstevel@tonic-gate   if(fcntl(fd, F_SETFL, fcntl_flags) == -1) {
27527c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "fcntl error", END_ERR_MSG);
27537c478bd9Sstevel@tonic-gate     return 1;
27547c478bd9Sstevel@tonic-gate   };
27557c478bd9Sstevel@tonic-gate #endif
27567c478bd9Sstevel@tonic-gate   return 0;
27577c478bd9Sstevel@tonic-gate }
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate /*.......................................................................
27607c478bd9Sstevel@tonic-gate  * Read a new input line from the user.
27617c478bd9Sstevel@tonic-gate  *
27627c478bd9Sstevel@tonic-gate  * Input:
27637c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of this library.
27647c478bd9Sstevel@tonic-gate  *  prompt        char *  The prompt to prefix the line with, or NULL to
27657c478bd9Sstevel@tonic-gate  *                        use the same prompt that was used by the previous
27667c478bd9Sstevel@tonic-gate  *                        line.
27677c478bd9Sstevel@tonic-gate  *  start_line    char *  The initial contents of the input line, or NULL
27687c478bd9Sstevel@tonic-gate  *                        if it should start out empty.
27697c478bd9Sstevel@tonic-gate  *  start_pos      int    If start_line isn't NULL, this specifies the
27707c478bd9Sstevel@tonic-gate  *                        index of the character over which the cursor
27717c478bd9Sstevel@tonic-gate  *                        should initially be positioned within the line.
27727c478bd9Sstevel@tonic-gate  *                        If you just want it to follow the last character
27737c478bd9Sstevel@tonic-gate  *                        of the line, send -1.
27747c478bd9Sstevel@tonic-gate  * Output:
27757c478bd9Sstevel@tonic-gate  *  return    int    0 - OK.
27767c478bd9Sstevel@tonic-gate  *                   1 - Error.
27777c478bd9Sstevel@tonic-gate  */
gl_get_input_line(GetLine * gl,const char * prompt,const char * start_line,int start_pos)27787c478bd9Sstevel@tonic-gate static int gl_get_input_line(GetLine *gl, const char *prompt,
27797c478bd9Sstevel@tonic-gate 			     const char *start_line, int start_pos)
27807c478bd9Sstevel@tonic-gate {
27817c478bd9Sstevel@tonic-gate   char c;               /* The character being read */
27827c478bd9Sstevel@tonic-gate /*
27837c478bd9Sstevel@tonic-gate  * Flush any pending output to the terminal.
27847c478bd9Sstevel@tonic-gate  */
27857c478bd9Sstevel@tonic-gate   if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
27867c478bd9Sstevel@tonic-gate     return 1;
27877c478bd9Sstevel@tonic-gate /*
27887c478bd9Sstevel@tonic-gate  * Are we starting a new line?
27897c478bd9Sstevel@tonic-gate  */
27907c478bd9Sstevel@tonic-gate   if(gl->endline) {
27917c478bd9Sstevel@tonic-gate /*
27927c478bd9Sstevel@tonic-gate  * Delete any incompletely enterred line.
27937c478bd9Sstevel@tonic-gate  */
27947c478bd9Sstevel@tonic-gate     if(gl_erase_line(gl))
27957c478bd9Sstevel@tonic-gate       return 1;
27967c478bd9Sstevel@tonic-gate /*
27977c478bd9Sstevel@tonic-gate  * Display the new line to be edited.
27987c478bd9Sstevel@tonic-gate  */
27997c478bd9Sstevel@tonic-gate     if(gl_present_line(gl, prompt, start_line, start_pos))
28007c478bd9Sstevel@tonic-gate       return 1;
28017c478bd9Sstevel@tonic-gate   };
28027c478bd9Sstevel@tonic-gate /*
28037c478bd9Sstevel@tonic-gate  * Read one character at a time.
28047c478bd9Sstevel@tonic-gate  */
28057c478bd9Sstevel@tonic-gate   while(gl_read_terminal(gl, 1, &c) == 0) {
28067c478bd9Sstevel@tonic-gate /*
28077c478bd9Sstevel@tonic-gate  * Increment the count of the number of key sequences entered.
28087c478bd9Sstevel@tonic-gate  */
28097c478bd9Sstevel@tonic-gate     gl->keyseq_count++;
28107c478bd9Sstevel@tonic-gate /*
28117c478bd9Sstevel@tonic-gate  * Interpret the character either as the start of a new key-sequence,
28127c478bd9Sstevel@tonic-gate  * as a continuation of a repeat count, or as a printable character
28137c478bd9Sstevel@tonic-gate  * to be added to the line.
28147c478bd9Sstevel@tonic-gate  */
28157c478bd9Sstevel@tonic-gate     if(gl_interpret_char(gl, c))
28167c478bd9Sstevel@tonic-gate       break;
28177c478bd9Sstevel@tonic-gate /*
28187c478bd9Sstevel@tonic-gate  * If we just ran an action function which temporarily asked for
28197c478bd9Sstevel@tonic-gate  * input to be taken from a file, abort this call.
28207c478bd9Sstevel@tonic-gate  */
28217c478bd9Sstevel@tonic-gate     if(gl->file_fp)
28227c478bd9Sstevel@tonic-gate       return 0;
28237c478bd9Sstevel@tonic-gate /*
28247c478bd9Sstevel@tonic-gate  * Has the line been completed?
28257c478bd9Sstevel@tonic-gate  */
28267c478bd9Sstevel@tonic-gate     if(gl->endline)
28277c478bd9Sstevel@tonic-gate       return gl_line_ended(gl, c);
28287c478bd9Sstevel@tonic-gate   };
28297c478bd9Sstevel@tonic-gate /*
28307c478bd9Sstevel@tonic-gate  * To get here, gl_read_terminal() must have returned non-zero. See
28317c478bd9Sstevel@tonic-gate  * whether a signal was caught that requested that the current line
28327c478bd9Sstevel@tonic-gate  * be returned.
28337c478bd9Sstevel@tonic-gate  */
28347c478bd9Sstevel@tonic-gate   if(gl->endline)
28357c478bd9Sstevel@tonic-gate     return gl_line_ended(gl, '\n');
28367c478bd9Sstevel@tonic-gate /*
28377c478bd9Sstevel@tonic-gate  * If I/O blocked while attempting to get the latest character
28387c478bd9Sstevel@tonic-gate  * of the key sequence, rewind the key buffer to allow interpretation of
28397c478bd9Sstevel@tonic-gate  * the current key sequence to be restarted on the next call to this
28407c478bd9Sstevel@tonic-gate  * function.
28417c478bd9Sstevel@tonic-gate  */
28427c478bd9Sstevel@tonic-gate   if(gl->rtn_status == GLR_BLOCKED && gl->pending_io == GLP_READ)
28437c478bd9Sstevel@tonic-gate     gl->nread = 0;
28447c478bd9Sstevel@tonic-gate   return 1;
28457c478bd9Sstevel@tonic-gate }
28467c478bd9Sstevel@tonic-gate 
28477c478bd9Sstevel@tonic-gate /*.......................................................................
28487c478bd9Sstevel@tonic-gate  * This is the private function of gl_query_char() that handles
28497c478bd9Sstevel@tonic-gate  * prompting the user, reading a character from the terminal, and
28507c478bd9Sstevel@tonic-gate  * displaying what the user entered.
28517c478bd9Sstevel@tonic-gate  *
28527c478bd9Sstevel@tonic-gate  * Input:
28537c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of this library.
28547c478bd9Sstevel@tonic-gate  *  prompt        char *  The prompt to prefix the line with.
28557c478bd9Sstevel@tonic-gate  *  defchar       char    The character to substitute if the
28567c478bd9Sstevel@tonic-gate  *                        user simply hits return, or '\n' if you don't
28577c478bd9Sstevel@tonic-gate  *                        need to substitute anything.
28587c478bd9Sstevel@tonic-gate  * Output:
28597c478bd9Sstevel@tonic-gate  *  return         int    The character that was read, or EOF if something
28607c478bd9Sstevel@tonic-gate  *                        prevented a character from being read.
28617c478bd9Sstevel@tonic-gate  */
gl_get_query_char(GetLine * gl,const char * prompt,int defchar)28627c478bd9Sstevel@tonic-gate static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar)
28637c478bd9Sstevel@tonic-gate {
28647c478bd9Sstevel@tonic-gate   char c;               /* The character being read */
28657c478bd9Sstevel@tonic-gate   int retval;           /* The return value of this function */
28667c478bd9Sstevel@tonic-gate /*
28677c478bd9Sstevel@tonic-gate  * Flush any pending output to the terminal.
28687c478bd9Sstevel@tonic-gate  */
28697c478bd9Sstevel@tonic-gate   if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl))
28707c478bd9Sstevel@tonic-gate     return EOF;
28717c478bd9Sstevel@tonic-gate /*
28727c478bd9Sstevel@tonic-gate  * Delete any incompletely entered line.
28737c478bd9Sstevel@tonic-gate  */
28747c478bd9Sstevel@tonic-gate   if(gl_erase_line(gl))
28757c478bd9Sstevel@tonic-gate     return EOF;
28767c478bd9Sstevel@tonic-gate /*
28777c478bd9Sstevel@tonic-gate  * Reset the line input parameters and display the prompt, if any.
28787c478bd9Sstevel@tonic-gate  */
28797c478bd9Sstevel@tonic-gate   if(gl_present_line(gl, prompt, NULL, 0))
28807c478bd9Sstevel@tonic-gate     return EOF;
28817c478bd9Sstevel@tonic-gate /*
28827c478bd9Sstevel@tonic-gate  * Read one character.
28837c478bd9Sstevel@tonic-gate  */
28847c478bd9Sstevel@tonic-gate   if(gl_read_terminal(gl, 1, &c) == 0) {
28857c478bd9Sstevel@tonic-gate /*
28867c478bd9Sstevel@tonic-gate  * In this mode, count each character as being a new key-sequence.
28877c478bd9Sstevel@tonic-gate  */
28887c478bd9Sstevel@tonic-gate     gl->keyseq_count++;
28897c478bd9Sstevel@tonic-gate /*
28907c478bd9Sstevel@tonic-gate  * Delete the character that was read, from the key-press buffer.
28917c478bd9Sstevel@tonic-gate  */
28927c478bd9Sstevel@tonic-gate     gl_discard_chars(gl, gl->nread);
28937c478bd9Sstevel@tonic-gate /*
28947c478bd9Sstevel@tonic-gate  * Convert carriage returns to newlines.
28957c478bd9Sstevel@tonic-gate  */
28967c478bd9Sstevel@tonic-gate     if(c == '\r')
28977c478bd9Sstevel@tonic-gate       c = '\n';
28987c478bd9Sstevel@tonic-gate /*
28997c478bd9Sstevel@tonic-gate  * If the user just hit return, subsitute the default character.
29007c478bd9Sstevel@tonic-gate  */
29017c478bd9Sstevel@tonic-gate     if(c == '\n')
29027c478bd9Sstevel@tonic-gate       c = defchar;
29037c478bd9Sstevel@tonic-gate /*
29047c478bd9Sstevel@tonic-gate  * Display the entered character to the right of the prompt.
29057c478bd9Sstevel@tonic-gate  */
29067c478bd9Sstevel@tonic-gate     if(c!='\n') {
29077c478bd9Sstevel@tonic-gate       if(gl_end_of_line(gl, 1, NULL)==0)
29087c478bd9Sstevel@tonic-gate 	gl_print_char(gl, c, ' ');
29097c478bd9Sstevel@tonic-gate     };
29107c478bd9Sstevel@tonic-gate /*
29117c478bd9Sstevel@tonic-gate  * Record the return character, and mark the call as successful.
29127c478bd9Sstevel@tonic-gate  */
29137c478bd9Sstevel@tonic-gate     retval = c;
29147c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_NEWLINE, 0);
29157c478bd9Sstevel@tonic-gate /*
29167c478bd9Sstevel@tonic-gate  * Was a signal caught whose disposition is to cause the current input
29177c478bd9Sstevel@tonic-gate  * line to be returned? If so return a newline character.
29187c478bd9Sstevel@tonic-gate  */
29197c478bd9Sstevel@tonic-gate   } else if(gl->endline) {
29207c478bd9Sstevel@tonic-gate     retval = '\n';
29217c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_NEWLINE, 0);
29227c478bd9Sstevel@tonic-gate   } else {
29237c478bd9Sstevel@tonic-gate     retval = EOF;
29247c478bd9Sstevel@tonic-gate   };
29257c478bd9Sstevel@tonic-gate /*
29267c478bd9Sstevel@tonic-gate  * Start a new line.
29277c478bd9Sstevel@tonic-gate  */
29287c478bd9Sstevel@tonic-gate   if(gl_start_newline(gl, 1))
29297c478bd9Sstevel@tonic-gate     return EOF;
29307c478bd9Sstevel@tonic-gate /*
29317c478bd9Sstevel@tonic-gate  * Attempt to flush any pending output.
29327c478bd9Sstevel@tonic-gate  */
29337c478bd9Sstevel@tonic-gate   (void) gl_flush_output(gl);
29347c478bd9Sstevel@tonic-gate /*
29357c478bd9Sstevel@tonic-gate  * Return either the character that was read, or EOF if an error occurred.
29367c478bd9Sstevel@tonic-gate  */
29377c478bd9Sstevel@tonic-gate   return retval;
29387c478bd9Sstevel@tonic-gate }
29397c478bd9Sstevel@tonic-gate 
29407c478bd9Sstevel@tonic-gate /*.......................................................................
29417c478bd9Sstevel@tonic-gate  * Add a character to the line buffer at the current cursor position,
29427c478bd9Sstevel@tonic-gate  * inserting or overwriting according the current mode.
29437c478bd9Sstevel@tonic-gate  *
29447c478bd9Sstevel@tonic-gate  * Input:
29457c478bd9Sstevel@tonic-gate  *  gl   GetLine *   The resource object of this library.
29467c478bd9Sstevel@tonic-gate  *  c       char     The character to be added.
29477c478bd9Sstevel@tonic-gate  * Output:
29487c478bd9Sstevel@tonic-gate  *  return   int     0 - OK.
29497c478bd9Sstevel@tonic-gate  *                   1 - Insufficient room.
29507c478bd9Sstevel@tonic-gate  */
gl_add_char_to_line(GetLine * gl,char c)29517c478bd9Sstevel@tonic-gate static int gl_add_char_to_line(GetLine *gl, char c)
29527c478bd9Sstevel@tonic-gate {
29537c478bd9Sstevel@tonic-gate /*
29547c478bd9Sstevel@tonic-gate  * Keep a record of the current cursor position.
29557c478bd9Sstevel@tonic-gate  */
29567c478bd9Sstevel@tonic-gate   int buff_curpos = gl->buff_curpos;
29577c478bd9Sstevel@tonic-gate   int term_curpos = gl->term_curpos;
29587c478bd9Sstevel@tonic-gate /*
29597c478bd9Sstevel@tonic-gate  * Work out the displayed width of the new character.
29607c478bd9Sstevel@tonic-gate  */
29617c478bd9Sstevel@tonic-gate   int width = gl_displayed_char_width(gl, c, term_curpos);
29627c478bd9Sstevel@tonic-gate /*
29637c478bd9Sstevel@tonic-gate  * If we are in insert mode, or at the end of the line,
29647c478bd9Sstevel@tonic-gate  * check that we can accomodate a new character in the buffer.
29657c478bd9Sstevel@tonic-gate  * If not, simply return, leaving it up to the calling program
29667c478bd9Sstevel@tonic-gate  * to check for the absence of a newline character.
29677c478bd9Sstevel@tonic-gate  */
29687c478bd9Sstevel@tonic-gate   if((gl->insert || buff_curpos >= gl->ntotal) && gl->ntotal >= gl->linelen)
29697c478bd9Sstevel@tonic-gate     return 0;
29707c478bd9Sstevel@tonic-gate /*
29717c478bd9Sstevel@tonic-gate  * Are we adding characters to the line (ie. inserting or appending)?
29727c478bd9Sstevel@tonic-gate  */
29737c478bd9Sstevel@tonic-gate   if(gl->insert || buff_curpos >= gl->ntotal) {
29747c478bd9Sstevel@tonic-gate /*
29757c478bd9Sstevel@tonic-gate  * If inserting, make room for the new character.
29767c478bd9Sstevel@tonic-gate  */
29777c478bd9Sstevel@tonic-gate     if(buff_curpos < gl->ntotal)
29787c478bd9Sstevel@tonic-gate       gl_make_gap_in_buffer(gl, buff_curpos, 1);
29797c478bd9Sstevel@tonic-gate /*
29807c478bd9Sstevel@tonic-gate  * Copy the character into the buffer.
29817c478bd9Sstevel@tonic-gate  */
29827c478bd9Sstevel@tonic-gate     gl_buffer_char(gl, c, buff_curpos);
29837c478bd9Sstevel@tonic-gate     gl->buff_curpos++;
29847c478bd9Sstevel@tonic-gate /*
29857c478bd9Sstevel@tonic-gate  * Redraw the line from the cursor position to the end of the line,
29867c478bd9Sstevel@tonic-gate  * and move the cursor to just after the added character.
29877c478bd9Sstevel@tonic-gate  */
29887c478bd9Sstevel@tonic-gate     if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
29897c478bd9Sstevel@tonic-gate        gl_set_term_curpos(gl, term_curpos + width))
29907c478bd9Sstevel@tonic-gate       return 1;
29917c478bd9Sstevel@tonic-gate /*
29927c478bd9Sstevel@tonic-gate  * Are we overwriting an existing character?
29937c478bd9Sstevel@tonic-gate  */
29947c478bd9Sstevel@tonic-gate   } else {
29957c478bd9Sstevel@tonic-gate /*
29967c478bd9Sstevel@tonic-gate  * Get the width of the character being overwritten.
29977c478bd9Sstevel@tonic-gate  */
29987c478bd9Sstevel@tonic-gate     int old_width = gl_displayed_char_width(gl, gl->line[buff_curpos],
29997c478bd9Sstevel@tonic-gate 					    term_curpos);
30007c478bd9Sstevel@tonic-gate /*
30017c478bd9Sstevel@tonic-gate  * Overwrite the character in the buffer.
30027c478bd9Sstevel@tonic-gate  */
30037c478bd9Sstevel@tonic-gate     gl_buffer_char(gl, c, buff_curpos);
30047c478bd9Sstevel@tonic-gate /*
30057c478bd9Sstevel@tonic-gate  * If we are replacing with a narrower character, we need to
30067c478bd9Sstevel@tonic-gate  * redraw the terminal string to the end of the line, then
30077c478bd9Sstevel@tonic-gate  * overwrite the trailing old_width - width characters
30087c478bd9Sstevel@tonic-gate  * with spaces.
30097c478bd9Sstevel@tonic-gate  */
30107c478bd9Sstevel@tonic-gate     if(old_width > width) {
30117c478bd9Sstevel@tonic-gate       if(gl_print_string(gl, gl->line + buff_curpos, '\0'))
30127c478bd9Sstevel@tonic-gate 	return 1;
30137c478bd9Sstevel@tonic-gate /*
30147c478bd9Sstevel@tonic-gate  * Clear to the end of the terminal.
30157c478bd9Sstevel@tonic-gate  */
30167c478bd9Sstevel@tonic-gate       if(gl_truncate_display(gl))
30177c478bd9Sstevel@tonic-gate 	return 1;
30187c478bd9Sstevel@tonic-gate /*
30197c478bd9Sstevel@tonic-gate  * Move the cursor to the end of the new character.
30207c478bd9Sstevel@tonic-gate  */
30217c478bd9Sstevel@tonic-gate       if(gl_set_term_curpos(gl, term_curpos + width))
30227c478bd9Sstevel@tonic-gate 	return 1;
30237c478bd9Sstevel@tonic-gate       gl->buff_curpos++;
30247c478bd9Sstevel@tonic-gate /*
30257c478bd9Sstevel@tonic-gate  * If we are replacing with a wider character, then we will be
30267c478bd9Sstevel@tonic-gate  * inserting new characters, and thus extending the line.
30277c478bd9Sstevel@tonic-gate  */
30287c478bd9Sstevel@tonic-gate     } else if(width > old_width) {
30297c478bd9Sstevel@tonic-gate /*
30307c478bd9Sstevel@tonic-gate  * Redraw the line from the cursor position to the end of the line,
30317c478bd9Sstevel@tonic-gate  * and move the cursor to just after the added character.
30327c478bd9Sstevel@tonic-gate  */
30337c478bd9Sstevel@tonic-gate       if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
30347c478bd9Sstevel@tonic-gate 	 gl_set_term_curpos(gl, term_curpos + width))
30357c478bd9Sstevel@tonic-gate 	return 1;
30367c478bd9Sstevel@tonic-gate       gl->buff_curpos++;
30377c478bd9Sstevel@tonic-gate /*
30387c478bd9Sstevel@tonic-gate  * The original and replacement characters have the same width,
30397c478bd9Sstevel@tonic-gate  * so simply overwrite.
30407c478bd9Sstevel@tonic-gate  */
30417c478bd9Sstevel@tonic-gate     } else {
30427c478bd9Sstevel@tonic-gate /*
30437c478bd9Sstevel@tonic-gate  * Copy the character into the buffer.
30447c478bd9Sstevel@tonic-gate  */
30457c478bd9Sstevel@tonic-gate       gl_buffer_char(gl, c, buff_curpos);
30467c478bd9Sstevel@tonic-gate       gl->buff_curpos++;
30477c478bd9Sstevel@tonic-gate /*
30487c478bd9Sstevel@tonic-gate  * Overwrite the original character.
30497c478bd9Sstevel@tonic-gate  */
30507c478bd9Sstevel@tonic-gate       if(gl_print_char(gl, c, gl->line[gl->buff_curpos]))
30517c478bd9Sstevel@tonic-gate 	return 1;
30527c478bd9Sstevel@tonic-gate     };
30537c478bd9Sstevel@tonic-gate   };
30547c478bd9Sstevel@tonic-gate   return 0;
30557c478bd9Sstevel@tonic-gate }
30567c478bd9Sstevel@tonic-gate 
30577c478bd9Sstevel@tonic-gate /*.......................................................................
30587c478bd9Sstevel@tonic-gate  * Insert/append a string to the line buffer and terminal at the current
30597c478bd9Sstevel@tonic-gate  * cursor position.
30607c478bd9Sstevel@tonic-gate  *
30617c478bd9Sstevel@tonic-gate  * Input:
30627c478bd9Sstevel@tonic-gate  *  gl   GetLine *   The resource object of this library.
30637c478bd9Sstevel@tonic-gate  *  s       char *   The string to be added.
30647c478bd9Sstevel@tonic-gate  * Output:
30657c478bd9Sstevel@tonic-gate  *  return   int     0 - OK.
30667c478bd9Sstevel@tonic-gate  *                   1 - Insufficient room.
30677c478bd9Sstevel@tonic-gate  */
gl_add_string_to_line(GetLine * gl,const char * s)30687c478bd9Sstevel@tonic-gate static int gl_add_string_to_line(GetLine *gl, const char *s)
30697c478bd9Sstevel@tonic-gate {
30707c478bd9Sstevel@tonic-gate   int buff_slen;   /* The length of the string being added to line[] */
30717c478bd9Sstevel@tonic-gate   int term_slen;   /* The length of the string being written to the terminal */
30727c478bd9Sstevel@tonic-gate   int buff_curpos; /* The original value of gl->buff_curpos */
30737c478bd9Sstevel@tonic-gate   int term_curpos; /* The original value of gl->term_curpos */
30747c478bd9Sstevel@tonic-gate /*
30757c478bd9Sstevel@tonic-gate  * Keep a record of the current cursor position.
30767c478bd9Sstevel@tonic-gate  */
30777c478bd9Sstevel@tonic-gate   buff_curpos = gl->buff_curpos;
30787c478bd9Sstevel@tonic-gate   term_curpos = gl->term_curpos;
30797c478bd9Sstevel@tonic-gate /*
30807c478bd9Sstevel@tonic-gate  * How long is the string to be added?
30817c478bd9Sstevel@tonic-gate  */
30827c478bd9Sstevel@tonic-gate   buff_slen = strlen(s);
30837c478bd9Sstevel@tonic-gate   term_slen = gl_displayed_string_width(gl, s, buff_slen, term_curpos);
30847c478bd9Sstevel@tonic-gate /*
30857c478bd9Sstevel@tonic-gate  * Check that we can accomodate the string in the buffer.
30867c478bd9Sstevel@tonic-gate  * If not, simply return, leaving it up to the calling program
30877c478bd9Sstevel@tonic-gate  * to check for the absence of a newline character.
30887c478bd9Sstevel@tonic-gate  */
30897c478bd9Sstevel@tonic-gate   if(gl->ntotal + buff_slen > gl->linelen)
30907c478bd9Sstevel@tonic-gate     return 0;
30917c478bd9Sstevel@tonic-gate /*
30927c478bd9Sstevel@tonic-gate  * Move the characters that follow the cursor in the buffer by
30937c478bd9Sstevel@tonic-gate  * buff_slen characters to the right.
30947c478bd9Sstevel@tonic-gate  */
30957c478bd9Sstevel@tonic-gate   if(gl->ntotal > gl->buff_curpos)
30967c478bd9Sstevel@tonic-gate     gl_make_gap_in_buffer(gl, gl->buff_curpos, buff_slen);
30977c478bd9Sstevel@tonic-gate /*
30987c478bd9Sstevel@tonic-gate  * Copy the string into the buffer.
30997c478bd9Sstevel@tonic-gate  */
31007c478bd9Sstevel@tonic-gate   gl_buffer_string(gl, s, buff_slen, gl->buff_curpos);
31017c478bd9Sstevel@tonic-gate   gl->buff_curpos += buff_slen;
31027c478bd9Sstevel@tonic-gate /*
31037c478bd9Sstevel@tonic-gate  * Write the modified part of the line to the terminal, then move
31047c478bd9Sstevel@tonic-gate  * the terminal cursor to the end of the displayed input string.
31057c478bd9Sstevel@tonic-gate  */
31067c478bd9Sstevel@tonic-gate   if(gl_print_string(gl, gl->line + buff_curpos, '\0') ||
31077c478bd9Sstevel@tonic-gate      gl_set_term_curpos(gl, term_curpos + term_slen))
31087c478bd9Sstevel@tonic-gate     return 1;
31097c478bd9Sstevel@tonic-gate   return 0;
31107c478bd9Sstevel@tonic-gate }
31117c478bd9Sstevel@tonic-gate 
31127c478bd9Sstevel@tonic-gate /*.......................................................................
31137c478bd9Sstevel@tonic-gate  * Read a single character from the terminal.
31147c478bd9Sstevel@tonic-gate  *
31157c478bd9Sstevel@tonic-gate  * Input:
31167c478bd9Sstevel@tonic-gate  *  gl    GetLine *   The resource object of this library.
31177c478bd9Sstevel@tonic-gate  *  keep      int     If true, the returned character will be kept in
31187c478bd9Sstevel@tonic-gate  *                    the input buffer, for potential replays. It should
31197c478bd9Sstevel@tonic-gate  *                    subsequently be removed from the buffer when the
31207c478bd9Sstevel@tonic-gate  *                    key sequence that it belongs to has been fully
31217c478bd9Sstevel@tonic-gate  *                    processed, by calling gl_discard_chars().
31227c478bd9Sstevel@tonic-gate  * Input/Output:
31237c478bd9Sstevel@tonic-gate  *  c        char *   The character that is read, is assigned to *c.
31247c478bd9Sstevel@tonic-gate  * Output:
31257c478bd9Sstevel@tonic-gate  *  return    int     0 - OK.
31267c478bd9Sstevel@tonic-gate  *                    1 - Either an I/O error occurred, or a signal was
31277c478bd9Sstevel@tonic-gate  *                        caught who's disposition is to abort gl_get_line()
31287c478bd9Sstevel@tonic-gate  *                        or to have gl_get_line() return the current line
31297c478bd9Sstevel@tonic-gate  *                        as though the user had pressed return. In the
31307c478bd9Sstevel@tonic-gate  *                        latter case gl->endline will be non-zero.
31317c478bd9Sstevel@tonic-gate  */
gl_read_terminal(GetLine * gl,int keep,char * c)31327c478bd9Sstevel@tonic-gate static int gl_read_terminal(GetLine *gl, int keep, char *c)
31337c478bd9Sstevel@tonic-gate {
31347c478bd9Sstevel@tonic-gate /*
31357c478bd9Sstevel@tonic-gate  * Before waiting for a new character to be input, flush unwritten
31367c478bd9Sstevel@tonic-gate  * characters to the terminal.
31377c478bd9Sstevel@tonic-gate  */
31387c478bd9Sstevel@tonic-gate   if(gl_flush_output(gl))
31397c478bd9Sstevel@tonic-gate     return 1;
31407c478bd9Sstevel@tonic-gate /*
31417c478bd9Sstevel@tonic-gate  * Record the fact that we are about to read from the terminal.
31427c478bd9Sstevel@tonic-gate  */
31437c478bd9Sstevel@tonic-gate   gl->pending_io = GLP_READ;
31447c478bd9Sstevel@tonic-gate /*
31457c478bd9Sstevel@tonic-gate  * If there is already an unread character in the buffer,
31467c478bd9Sstevel@tonic-gate  * return it.
31477c478bd9Sstevel@tonic-gate  */
31487c478bd9Sstevel@tonic-gate   if(gl->nread < gl->nbuf) {
31497c478bd9Sstevel@tonic-gate     *c = gl->keybuf[gl->nread];
31507c478bd9Sstevel@tonic-gate /*
31517c478bd9Sstevel@tonic-gate  * Retain the character in the key buffer, but mark it as having been read?
31527c478bd9Sstevel@tonic-gate  */
31537c478bd9Sstevel@tonic-gate     if(keep) {
31547c478bd9Sstevel@tonic-gate       gl->nread++;
31557c478bd9Sstevel@tonic-gate /*
31567c478bd9Sstevel@tonic-gate  * Completely remove the character from the key buffer?
31577c478bd9Sstevel@tonic-gate  */
31587c478bd9Sstevel@tonic-gate     } else {
31597c478bd9Sstevel@tonic-gate       memmove(gl->keybuf + gl->nread, gl->keybuf + gl->nread + 1,
31607c478bd9Sstevel@tonic-gate 	      gl->nbuf - gl->nread - 1);
31617c478bd9Sstevel@tonic-gate     };
31627c478bd9Sstevel@tonic-gate     return 0;
31637c478bd9Sstevel@tonic-gate   };
31647c478bd9Sstevel@tonic-gate /*
31657c478bd9Sstevel@tonic-gate  * Make sure that there is space in the key buffer for one more character.
31667c478bd9Sstevel@tonic-gate  * This should always be true if gl_interpret_char() is called for each
31677c478bd9Sstevel@tonic-gate  * new character added, since it will clear the buffer once it has recognized
31687c478bd9Sstevel@tonic-gate  * or rejected a key sequence.
31697c478bd9Sstevel@tonic-gate  */
31707c478bd9Sstevel@tonic-gate   if(gl->nbuf + 1 > GL_KEY_MAX) {
31717c478bd9Sstevel@tonic-gate     gl_print_info(gl, "gl_read_terminal: Buffer overflow avoided.",
31727c478bd9Sstevel@tonic-gate 		  GL_END_INFO);
31737c478bd9Sstevel@tonic-gate     errno = EIO;
31747c478bd9Sstevel@tonic-gate     return 1;
31757c478bd9Sstevel@tonic-gate   };
31767c478bd9Sstevel@tonic-gate /*
31777c478bd9Sstevel@tonic-gate  * Read one character from the terminal.
31787c478bd9Sstevel@tonic-gate  */
31797c478bd9Sstevel@tonic-gate   switch(gl_read_input(gl, c)) {
31807c478bd9Sstevel@tonic-gate   case GL_READ_OK:
31817c478bd9Sstevel@tonic-gate     break;
31827c478bd9Sstevel@tonic-gate   case GL_READ_BLOCKED:
31837c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
31847c478bd9Sstevel@tonic-gate     return 1;
31857c478bd9Sstevel@tonic-gate     break;
31867c478bd9Sstevel@tonic-gate   default:
31877c478bd9Sstevel@tonic-gate     return 1;
31887c478bd9Sstevel@tonic-gate     break;
31897c478bd9Sstevel@tonic-gate   };
31907c478bd9Sstevel@tonic-gate /*
31917c478bd9Sstevel@tonic-gate  * Append the character to the key buffer?
31927c478bd9Sstevel@tonic-gate  */
31937c478bd9Sstevel@tonic-gate   if(keep) {
31947c478bd9Sstevel@tonic-gate     gl->keybuf[gl->nbuf] = *c;
31957c478bd9Sstevel@tonic-gate     gl->nread = ++gl->nbuf;
31967c478bd9Sstevel@tonic-gate   };
31977c478bd9Sstevel@tonic-gate   return 0;
31987c478bd9Sstevel@tonic-gate }
31997c478bd9Sstevel@tonic-gate 
32007c478bd9Sstevel@tonic-gate /*.......................................................................
32017c478bd9Sstevel@tonic-gate  * Read one or more keypresses from the terminal of an input stream.
32027c478bd9Sstevel@tonic-gate  *
32037c478bd9Sstevel@tonic-gate  * Input:
32047c478bd9Sstevel@tonic-gate  *  gl           GetLine *  The resource object of this module.
32057c478bd9Sstevel@tonic-gate  *  c               char *  The character that was read is assigned to *c.
32067c478bd9Sstevel@tonic-gate  * Output:
32077c478bd9Sstevel@tonic-gate  *  return  GlReadStatus    The completion status of the read operation.
32087c478bd9Sstevel@tonic-gate  */
gl_read_input(GetLine * gl,char * c)32097c478bd9Sstevel@tonic-gate static GlReadStatus gl_read_input(GetLine *gl, char *c)
32107c478bd9Sstevel@tonic-gate {
32117c478bd9Sstevel@tonic-gate /*
32127c478bd9Sstevel@tonic-gate  * We may have to repeat the read if window change signals are received.
32137c478bd9Sstevel@tonic-gate  */
32147c478bd9Sstevel@tonic-gate   for(;;) {
32157c478bd9Sstevel@tonic-gate /*
32167c478bd9Sstevel@tonic-gate  * Which file descriptor should we read from? Mark this volatile, so
32177c478bd9Sstevel@tonic-gate  * that siglongjmp() can't clobber it.
32187c478bd9Sstevel@tonic-gate  */
32197c478bd9Sstevel@tonic-gate     volatile int fd = gl->file_fp ? fileno(gl->file_fp) : gl->input_fd;
32207c478bd9Sstevel@tonic-gate /*
32217c478bd9Sstevel@tonic-gate  * If the endline flag becomes set, don't wait for another character.
32227c478bd9Sstevel@tonic-gate  */
32237c478bd9Sstevel@tonic-gate     if(gl->endline)
32247c478bd9Sstevel@tonic-gate       return GL_READ_ERROR;
32257c478bd9Sstevel@tonic-gate /*
32267c478bd9Sstevel@tonic-gate  * Since the code in this function can block, trap signals.
32277c478bd9Sstevel@tonic-gate  */
32287c478bd9Sstevel@tonic-gate     if(sigsetjmp(gl_setjmp_buffer, 1)==0) {
32297c478bd9Sstevel@tonic-gate /*
32307c478bd9Sstevel@tonic-gate  * Handle the different I/O modes.
32317c478bd9Sstevel@tonic-gate  */
32327c478bd9Sstevel@tonic-gate       switch(gl->io_mode) {
32337c478bd9Sstevel@tonic-gate /*
32347c478bd9Sstevel@tonic-gate  * In normal I/O mode, we call the event handler before attempting
32357c478bd9Sstevel@tonic-gate  * to read, since read() blocks.
32367c478bd9Sstevel@tonic-gate  */
32377c478bd9Sstevel@tonic-gate       case GL_NORMAL_MODE:
32387c478bd9Sstevel@tonic-gate 	if(gl_event_handler(gl, fd))
32397c478bd9Sstevel@tonic-gate 	  return GL_READ_ERROR;
32407c478bd9Sstevel@tonic-gate 	return gl_read_unmasked(gl, fd, c);  /* Read one character */
32417c478bd9Sstevel@tonic-gate 	break;
32427c478bd9Sstevel@tonic-gate /*
32437c478bd9Sstevel@tonic-gate  * In non-blocking server I/O mode, we attempt to read a character,
32447c478bd9Sstevel@tonic-gate  * and only if this fails, call the event handler to wait for a any
32457c478bd9Sstevel@tonic-gate  * user-configured timeout and any other user-configured events.  In
32467c478bd9Sstevel@tonic-gate  * addition, we turn off the fcntl() non-blocking flag when reading
32477c478bd9Sstevel@tonic-gate  * from the terminal, to work around a bug in Solaris. We can do this
32487c478bd9Sstevel@tonic-gate  * without causing the read() to block, because when in non-blocking
32497c478bd9Sstevel@tonic-gate  * server-I/O mode, gl_raw_io() sets the VMIN terminal attribute to 0,
32507c478bd9Sstevel@tonic-gate  * which tells the terminal driver to return immediately if no
32517c478bd9Sstevel@tonic-gate  * characters are available to be read.
32527c478bd9Sstevel@tonic-gate  */
32537c478bd9Sstevel@tonic-gate       case GL_SERVER_MODE:
32547c478bd9Sstevel@tonic-gate 	{
32557c478bd9Sstevel@tonic-gate 	  GlReadStatus status;        /* The return status */
32567c478bd9Sstevel@tonic-gate 	  if(isatty(fd))              /* If we reading from a terminal, */
32577c478bd9Sstevel@tonic-gate 	     gl_blocking_io(gl, fd);  /* switch to blocking I/O */
32587c478bd9Sstevel@tonic-gate 	  status = gl_read_unmasked(gl, fd, c); /* Try reading */
32597c478bd9Sstevel@tonic-gate 	  if(status == GL_READ_BLOCKED) {       /* Nothing readable yet */
32607c478bd9Sstevel@tonic-gate 	    if(gl_event_handler(gl, fd))        /* Wait for input */
32617c478bd9Sstevel@tonic-gate 	      status = GL_READ_ERROR;
32627c478bd9Sstevel@tonic-gate 	    else
32637c478bd9Sstevel@tonic-gate 	      status = gl_read_unmasked(gl, fd, c); /* Try reading again */
32647c478bd9Sstevel@tonic-gate 	  };
32657c478bd9Sstevel@tonic-gate 	  gl_nonblocking_io(gl, fd); /* Restore non-blocking I/O */
32667c478bd9Sstevel@tonic-gate 	  return status;
32677c478bd9Sstevel@tonic-gate 	};
32687c478bd9Sstevel@tonic-gate 	break;
32697c478bd9Sstevel@tonic-gate       };
32707c478bd9Sstevel@tonic-gate     };
32717c478bd9Sstevel@tonic-gate /*
32727c478bd9Sstevel@tonic-gate  * To get here, one of the signals that we are trapping must have
32737c478bd9Sstevel@tonic-gate  * been received. Note that by using sigsetjmp() instead of setjmp()
32747c478bd9Sstevel@tonic-gate  * the signal mask that was blocking these signals will have been
32757c478bd9Sstevel@tonic-gate  * reinstated, so we can be sure that no more of these signals will
32767c478bd9Sstevel@tonic-gate  * be received until we explicitly unblock them again.
32777c478bd9Sstevel@tonic-gate  *
32787c478bd9Sstevel@tonic-gate  * First, if non-blocking I/O was temporarily disabled, reinstate it.
32797c478bd9Sstevel@tonic-gate  */
32807c478bd9Sstevel@tonic-gate     if(gl->io_mode == GL_SERVER_MODE)
32817c478bd9Sstevel@tonic-gate       gl_nonblocking_io(gl, fd);
32827c478bd9Sstevel@tonic-gate /*
32837c478bd9Sstevel@tonic-gate  * Now respond to the signal that was caught.
32847c478bd9Sstevel@tonic-gate  */
32857c478bd9Sstevel@tonic-gate     if(gl_check_caught_signal(gl))
32867c478bd9Sstevel@tonic-gate       return GL_READ_ERROR;
32877c478bd9Sstevel@tonic-gate   };
32887c478bd9Sstevel@tonic-gate }
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate /*.......................................................................
32917c478bd9Sstevel@tonic-gate  * This is a private function of gl_read_input(), which unblocks signals
32927c478bd9Sstevel@tonic-gate  * temporarily while it reads a single character from the specified file
32937c478bd9Sstevel@tonic-gate  * descriptor.
32947c478bd9Sstevel@tonic-gate  *
32957c478bd9Sstevel@tonic-gate  * Input:
32967c478bd9Sstevel@tonic-gate  *  gl          GetLine *  The resource object of this module.
32977c478bd9Sstevel@tonic-gate  *  fd              int    The file descriptor to read from.
32987c478bd9Sstevel@tonic-gate  *  c              char *  The character that was read is assigned to *c.
32997c478bd9Sstevel@tonic-gate  * Output:
33007c478bd9Sstevel@tonic-gate  *  return GlReadStatus    The completion status of the read.
33017c478bd9Sstevel@tonic-gate  */
gl_read_unmasked(GetLine * gl,int fd,char * c)33027c478bd9Sstevel@tonic-gate static int gl_read_unmasked(GetLine *gl, int fd, char *c)
33037c478bd9Sstevel@tonic-gate {
33047c478bd9Sstevel@tonic-gate   int nread;  /* The return value of read() */
33057c478bd9Sstevel@tonic-gate /*
33067c478bd9Sstevel@tonic-gate  * Unblock the signals that we are trapping, while waiting for I/O.
33077c478bd9Sstevel@tonic-gate  */
33087c478bd9Sstevel@tonic-gate   gl_catch_signals(gl);
33097c478bd9Sstevel@tonic-gate /*
33107c478bd9Sstevel@tonic-gate  * Attempt to read one character from the terminal, restarting the read
33117c478bd9Sstevel@tonic-gate  * if any signals that we aren't trapping, are received.
33127c478bd9Sstevel@tonic-gate  */
33137c478bd9Sstevel@tonic-gate   do {
33147c478bd9Sstevel@tonic-gate     errno = 0;
33157c478bd9Sstevel@tonic-gate     nread = read(fd, c, 1);
33167c478bd9Sstevel@tonic-gate   } while(nread < 0 && errno==EINTR);
33177c478bd9Sstevel@tonic-gate /*
33187c478bd9Sstevel@tonic-gate  * Block all of the signals that we are trapping.
33197c478bd9Sstevel@tonic-gate  */
33207c478bd9Sstevel@tonic-gate   gl_mask_signals(gl, NULL);
33217c478bd9Sstevel@tonic-gate /*
33227c478bd9Sstevel@tonic-gate  * Check the completion status of the read.
33237c478bd9Sstevel@tonic-gate  */
33247c478bd9Sstevel@tonic-gate   switch(nread) {
33257c478bd9Sstevel@tonic-gate   case 1:
33267c478bd9Sstevel@tonic-gate     return GL_READ_OK;
33277c478bd9Sstevel@tonic-gate   case 0:
3328*06ca4e39SAndy Fiddaman     return (errno != 0 || isatty(fd)) ? GL_READ_BLOCKED : GL_READ_EOF;
33297c478bd9Sstevel@tonic-gate   default:
33307c478bd9Sstevel@tonic-gate     return GL_READ_ERROR;
33317c478bd9Sstevel@tonic-gate   };
33327c478bd9Sstevel@tonic-gate }
33337c478bd9Sstevel@tonic-gate 
33347c478bd9Sstevel@tonic-gate /*.......................................................................
33357c478bd9Sstevel@tonic-gate  * Remove a specified number of characters from the start of the
33367c478bd9Sstevel@tonic-gate  * key-press lookahead buffer, gl->keybuf[], and arrange for the next
33377c478bd9Sstevel@tonic-gate  * read to start from the character at the start of the shifted buffer.
33387c478bd9Sstevel@tonic-gate  *
33397c478bd9Sstevel@tonic-gate  * Input:
33407c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The resource object of this module.
33417c478bd9Sstevel@tonic-gate  *  nused       int    The number of characters to discard from the start
33427c478bd9Sstevel@tonic-gate  *                     of the buffer.
33437c478bd9Sstevel@tonic-gate  */
gl_discard_chars(GetLine * gl,int nused)33447c478bd9Sstevel@tonic-gate static void gl_discard_chars(GetLine *gl, int nused)
33457c478bd9Sstevel@tonic-gate {
33467c478bd9Sstevel@tonic-gate   int nkeep = gl->nbuf - nused;
33477c478bd9Sstevel@tonic-gate   if(nkeep > 0) {
33487c478bd9Sstevel@tonic-gate     memmove(gl->keybuf, gl->keybuf + nused, nkeep);
33497c478bd9Sstevel@tonic-gate     gl->nbuf = nkeep;
33507c478bd9Sstevel@tonic-gate     gl->nread = 0;
33517c478bd9Sstevel@tonic-gate   } else {
33527c478bd9Sstevel@tonic-gate     gl->nbuf = gl->nread = 0;
33537c478bd9Sstevel@tonic-gate   };
33547c478bd9Sstevel@tonic-gate }
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate /*.......................................................................
33577c478bd9Sstevel@tonic-gate  * This function is called to handle signals caught between calls to
33587c478bd9Sstevel@tonic-gate  * sigsetjmp() and siglongjmp().
33597c478bd9Sstevel@tonic-gate  *
33607c478bd9Sstevel@tonic-gate  * Input:
33617c478bd9Sstevel@tonic-gate  *  gl      GetLine *   The resource object of this library.
33627c478bd9Sstevel@tonic-gate  * Output:
33637c478bd9Sstevel@tonic-gate  *  return      int     0 - Signal handled internally.
33647c478bd9Sstevel@tonic-gate  *                      1 - Signal requires gl_get_line() to abort.
33657c478bd9Sstevel@tonic-gate  */
gl_check_caught_signal(GetLine * gl)33667c478bd9Sstevel@tonic-gate static int gl_check_caught_signal(GetLine *gl)
33677c478bd9Sstevel@tonic-gate {
33687c478bd9Sstevel@tonic-gate   GlSignalNode *sig;      /* The signal disposition */
33697c478bd9Sstevel@tonic-gate   SigAction keep_action;  /* The signal disposition of tecla signal handlers */
33707c478bd9Sstevel@tonic-gate   unsigned flags;         /* The signal processing flags to use */
33717c478bd9Sstevel@tonic-gate   int signo;              /* The signal to be handled */
33727c478bd9Sstevel@tonic-gate /*
33737c478bd9Sstevel@tonic-gate  * Was no signal caught?
33747c478bd9Sstevel@tonic-gate  */
33757c478bd9Sstevel@tonic-gate   if(gl_pending_signal == -1)
33767c478bd9Sstevel@tonic-gate     return 0;
33777c478bd9Sstevel@tonic-gate /*
33787c478bd9Sstevel@tonic-gate  * Get the signal to be handled.
33797c478bd9Sstevel@tonic-gate  */
33807c478bd9Sstevel@tonic-gate   signo = gl_pending_signal;
33817c478bd9Sstevel@tonic-gate /*
33827c478bd9Sstevel@tonic-gate  * Mark the signal as handled. Note that at this point, all of
33837c478bd9Sstevel@tonic-gate  * the signals that we are trapping are blocked from delivery.
33847c478bd9Sstevel@tonic-gate  */
33857c478bd9Sstevel@tonic-gate   gl_pending_signal = -1;
33867c478bd9Sstevel@tonic-gate /*
33877c478bd9Sstevel@tonic-gate  * Record the signal that was caught, so that the user can query it later.
33887c478bd9Sstevel@tonic-gate  */
33897c478bd9Sstevel@tonic-gate   gl->last_signal = signo;
33907c478bd9Sstevel@tonic-gate /*
33917c478bd9Sstevel@tonic-gate  * In non-blocking server mode, the application is responsible for
33927c478bd9Sstevel@tonic-gate  * responding to terminal signals, and we don't want gl_get_line()s
33937c478bd9Sstevel@tonic-gate  * normal signal handling to clash with this, so whenever a signal
33947c478bd9Sstevel@tonic-gate  * is caught, we arrange for gl_get_line() to abort and requeue the
33957c478bd9Sstevel@tonic-gate  * signal while signals are still blocked. If the application
33967c478bd9Sstevel@tonic-gate  * had the signal unblocked when gl_get_line() was called, the signal
33977c478bd9Sstevel@tonic-gate  * will be delivered again as soon as gl_get_line() restores the
33987c478bd9Sstevel@tonic-gate  * process signal mask, just before returning to the application.
33997c478bd9Sstevel@tonic-gate  * Note that the caller of this function should set gl->pending_io
34007c478bd9Sstevel@tonic-gate  * to the appropriate choice of GLP_READ and GLP_WRITE, before returning.
34017c478bd9Sstevel@tonic-gate  */
34027c478bd9Sstevel@tonic-gate   if(gl->io_mode==GL_SERVER_MODE) {
34037c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_SIGNAL, EINTR);
34047c478bd9Sstevel@tonic-gate     raise(signo);
34057c478bd9Sstevel@tonic-gate     return 1;
34067c478bd9Sstevel@tonic-gate   };
34077c478bd9Sstevel@tonic-gate /*
34087c478bd9Sstevel@tonic-gate  * Lookup the requested disposition of this signal.
34097c478bd9Sstevel@tonic-gate  */
34107c478bd9Sstevel@tonic-gate   for(sig=gl->sigs; sig && sig->signo != signo; sig=sig->next)
34117c478bd9Sstevel@tonic-gate     ;
34127c478bd9Sstevel@tonic-gate   if(!sig)
34137c478bd9Sstevel@tonic-gate     return 0;
34147c478bd9Sstevel@tonic-gate /*
34157c478bd9Sstevel@tonic-gate  * Get the signal response flags for this signal.
34167c478bd9Sstevel@tonic-gate  */
34177c478bd9Sstevel@tonic-gate   flags = sig->flags;
34187c478bd9Sstevel@tonic-gate /*
34197c478bd9Sstevel@tonic-gate  * Did we receive a terminal size signal?
34207c478bd9Sstevel@tonic-gate  */
34217c478bd9Sstevel@tonic-gate #ifdef SIGWINCH
34227c478bd9Sstevel@tonic-gate   if(signo == SIGWINCH && _gl_update_size(gl))
34237c478bd9Sstevel@tonic-gate     return 1;
34247c478bd9Sstevel@tonic-gate #endif
34257c478bd9Sstevel@tonic-gate /*
34267c478bd9Sstevel@tonic-gate  * Start a fresh line?
34277c478bd9Sstevel@tonic-gate  */
34287c478bd9Sstevel@tonic-gate   if(flags & GLS_RESTORE_LINE) {
34297c478bd9Sstevel@tonic-gate     if(gl_start_newline(gl, 0))
34307c478bd9Sstevel@tonic-gate       return 1;
34317c478bd9Sstevel@tonic-gate   };
34327c478bd9Sstevel@tonic-gate /*
34337c478bd9Sstevel@tonic-gate  * Restore terminal settings to how they were before gl_get_line() was
34347c478bd9Sstevel@tonic-gate  * called?
34357c478bd9Sstevel@tonic-gate  */
34367c478bd9Sstevel@tonic-gate   if(flags & GLS_RESTORE_TTY)
34377c478bd9Sstevel@tonic-gate     gl_restore_terminal_attributes(gl);
34387c478bd9Sstevel@tonic-gate /*
34397c478bd9Sstevel@tonic-gate  * Restore signal handlers to how they were before gl_get_line() was
34407c478bd9Sstevel@tonic-gate  * called? If this hasn't been requested, only reinstate the signal
34417c478bd9Sstevel@tonic-gate  * handler of the signal that we are handling.
34427c478bd9Sstevel@tonic-gate  */
34437c478bd9Sstevel@tonic-gate   if(flags & GLS_RESTORE_SIG) {
34447c478bd9Sstevel@tonic-gate     gl_restore_signal_handlers(gl);
34457c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &gl->old_signal_set);
34467c478bd9Sstevel@tonic-gate   } else {
34477c478bd9Sstevel@tonic-gate     (void) sigaction(sig->signo, &sig->original, &keep_action);
34487c478bd9Sstevel@tonic-gate     (void) sigprocmask(SIG_UNBLOCK, &sig->proc_mask, NULL);
34497c478bd9Sstevel@tonic-gate   };
34507c478bd9Sstevel@tonic-gate /*
34517c478bd9Sstevel@tonic-gate  * Forward the signal to the application's signal handler.
34527c478bd9Sstevel@tonic-gate  */
34537c478bd9Sstevel@tonic-gate   if(!(flags & GLS_DONT_FORWARD))
34547c478bd9Sstevel@tonic-gate     raise(signo);
34557c478bd9Sstevel@tonic-gate /*
34567c478bd9Sstevel@tonic-gate  * Reinstate our signal handlers.
34577c478bd9Sstevel@tonic-gate  */
34587c478bd9Sstevel@tonic-gate   if(flags & GLS_RESTORE_SIG) {
34597c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, NULL);
34607c478bd9Sstevel@tonic-gate     gl_override_signal_handlers(gl);
34617c478bd9Sstevel@tonic-gate   } else {
34627c478bd9Sstevel@tonic-gate     (void) sigaction(sig->signo, &keep_action, NULL);
34637c478bd9Sstevel@tonic-gate     (void) sigprocmask(SIG_BLOCK, &sig->proc_mask, NULL);
34647c478bd9Sstevel@tonic-gate   };
34657c478bd9Sstevel@tonic-gate /*
34667c478bd9Sstevel@tonic-gate  * Do we need to reinstate our terminal settings?
34677c478bd9Sstevel@tonic-gate  */
34687c478bd9Sstevel@tonic-gate   if(flags & GLS_RESTORE_TTY)
34697c478bd9Sstevel@tonic-gate     gl_raw_terminal_mode(gl);
34707c478bd9Sstevel@tonic-gate /*
34717c478bd9Sstevel@tonic-gate  * Redraw the line?
34727c478bd9Sstevel@tonic-gate  */
34737c478bd9Sstevel@tonic-gate   if(flags & GLS_REDRAW_LINE)
34747c478bd9Sstevel@tonic-gate     gl_queue_redisplay(gl);
34757c478bd9Sstevel@tonic-gate /*
34767c478bd9Sstevel@tonic-gate  * What next?
34777c478bd9Sstevel@tonic-gate  */
34787c478bd9Sstevel@tonic-gate   switch(sig->after) {
34797c478bd9Sstevel@tonic-gate   case GLS_RETURN:
34807c478bd9Sstevel@tonic-gate     gl_newline(gl, 1, NULL);
34817c478bd9Sstevel@tonic-gate     return gl_flush_output(gl);
34827c478bd9Sstevel@tonic-gate     break;
34837c478bd9Sstevel@tonic-gate   case GLS_ABORT:
34847c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_SIGNAL, sig->errno_value);
34857c478bd9Sstevel@tonic-gate     return 1;
34867c478bd9Sstevel@tonic-gate     break;
34877c478bd9Sstevel@tonic-gate   case GLS_CONTINUE:
34887c478bd9Sstevel@tonic-gate     return gl_flush_output(gl);
34897c478bd9Sstevel@tonic-gate     break;
34907c478bd9Sstevel@tonic-gate   };
34917c478bd9Sstevel@tonic-gate   return 0;
34927c478bd9Sstevel@tonic-gate }
34937c478bd9Sstevel@tonic-gate 
34947c478bd9Sstevel@tonic-gate /*.......................................................................
34957c478bd9Sstevel@tonic-gate  * Get pertinent terminal control strings and the initial terminal size.
34967c478bd9Sstevel@tonic-gate  *
34977c478bd9Sstevel@tonic-gate  * Input:
34987c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The resource object of this library.
34997c478bd9Sstevel@tonic-gate  *  term      char *  The type of the terminal.
35007c478bd9Sstevel@tonic-gate  * Output:
35017c478bd9Sstevel@tonic-gate  *  return     int    0 - OK.
35027c478bd9Sstevel@tonic-gate  *                    1 - Error.
35037c478bd9Sstevel@tonic-gate  */
gl_control_strings(GetLine * gl,const char * term)35047c478bd9Sstevel@tonic-gate static int gl_control_strings(GetLine *gl, const char *term)
35057c478bd9Sstevel@tonic-gate {
35067c478bd9Sstevel@tonic-gate   int bad_term = 0;   /* True if term is unusable */
35077c478bd9Sstevel@tonic-gate /*
35087c478bd9Sstevel@tonic-gate  * Discard any existing control strings from a previous terminal.
35097c478bd9Sstevel@tonic-gate  */
35107c478bd9Sstevel@tonic-gate   gl->left = NULL;
35117c478bd9Sstevel@tonic-gate   gl->right = NULL;
35127c478bd9Sstevel@tonic-gate   gl->up = NULL;
35137c478bd9Sstevel@tonic-gate   gl->down = NULL;
35147c478bd9Sstevel@tonic-gate   gl->home = NULL;
35157c478bd9Sstevel@tonic-gate   gl->bol = 0;
35167c478bd9Sstevel@tonic-gate   gl->clear_eol = NULL;
35177c478bd9Sstevel@tonic-gate   gl->clear_eod = NULL;
35187c478bd9Sstevel@tonic-gate   gl->u_arrow = NULL;
35197c478bd9Sstevel@tonic-gate   gl->d_arrow = NULL;
35207c478bd9Sstevel@tonic-gate   gl->l_arrow = NULL;
35217c478bd9Sstevel@tonic-gate   gl->r_arrow = NULL;
35227c478bd9Sstevel@tonic-gate   gl->sound_bell = NULL;
35237c478bd9Sstevel@tonic-gate   gl->bold = NULL;
35247c478bd9Sstevel@tonic-gate   gl->underline = NULL;
35257c478bd9Sstevel@tonic-gate   gl->standout = NULL;
35267c478bd9Sstevel@tonic-gate   gl->dim = NULL;
35277c478bd9Sstevel@tonic-gate   gl->reverse = NULL;
35287c478bd9Sstevel@tonic-gate   gl->blink = NULL;
35297c478bd9Sstevel@tonic-gate   gl->text_attr_off = NULL;
35307c478bd9Sstevel@tonic-gate   gl->nline = 0;
35317c478bd9Sstevel@tonic-gate   gl->ncolumn = 0;
35327c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
35337c478bd9Sstevel@tonic-gate   gl->left_n = NULL;
35347c478bd9Sstevel@tonic-gate   gl->right_n = NULL;
35357c478bd9Sstevel@tonic-gate #endif
35367c478bd9Sstevel@tonic-gate /*
35377c478bd9Sstevel@tonic-gate  * If possible lookup the information in a terminal information
35387c478bd9Sstevel@tonic-gate  * database.
35397c478bd9Sstevel@tonic-gate  */
35407c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
3541fa03b00aSjbeck   {
3542fa03b00aSjbeck     int errret;
3543fa03b00aSjbeck     if(!term || setupterm((char *)term, gl->input_fd, &errret) == ERR) {
35447c478bd9Sstevel@tonic-gate       bad_term = 1;
35457c478bd9Sstevel@tonic-gate     } else {
35467c478bd9Sstevel@tonic-gate       _clr_StringGroup(gl->capmem);
35477c478bd9Sstevel@tonic-gate       gl->left = gl_tigetstr(gl, "cub1");
35487c478bd9Sstevel@tonic-gate       gl->right = gl_tigetstr(gl, "cuf1");
35497c478bd9Sstevel@tonic-gate       gl->up = gl_tigetstr(gl, "cuu1");
35507c478bd9Sstevel@tonic-gate       gl->down = gl_tigetstr(gl, "cud1");
35517c478bd9Sstevel@tonic-gate       gl->home = gl_tigetstr(gl, "home");
35527c478bd9Sstevel@tonic-gate       gl->clear_eol = gl_tigetstr(gl, "el");
35537c478bd9Sstevel@tonic-gate       gl->clear_eod = gl_tigetstr(gl, "ed");
35547c478bd9Sstevel@tonic-gate       gl->u_arrow = gl_tigetstr(gl, "kcuu1");
35557c478bd9Sstevel@tonic-gate       gl->d_arrow = gl_tigetstr(gl, "kcud1");
35567c478bd9Sstevel@tonic-gate       gl->l_arrow = gl_tigetstr(gl, "kcub1");
35577c478bd9Sstevel@tonic-gate       gl->r_arrow = gl_tigetstr(gl, "kcuf1");
35587c478bd9Sstevel@tonic-gate       gl->left_n = gl_tigetstr(gl, "cub");
35597c478bd9Sstevel@tonic-gate       gl->right_n = gl_tigetstr(gl, "cuf");
35607c478bd9Sstevel@tonic-gate       gl->sound_bell = gl_tigetstr(gl, "bel");
35617c478bd9Sstevel@tonic-gate       gl->bold = gl_tigetstr(gl, "bold");
35627c478bd9Sstevel@tonic-gate       gl->underline = gl_tigetstr(gl, "smul");
35637c478bd9Sstevel@tonic-gate       gl->standout = gl_tigetstr(gl, "smso");
35647c478bd9Sstevel@tonic-gate       gl->dim = gl_tigetstr(gl, "dim");
35657c478bd9Sstevel@tonic-gate       gl->reverse = gl_tigetstr(gl, "rev");
35667c478bd9Sstevel@tonic-gate       gl->blink = gl_tigetstr(gl, "blink");
35677c478bd9Sstevel@tonic-gate       gl->text_attr_off = gl_tigetstr(gl, "sgr0");
35687c478bd9Sstevel@tonic-gate     };
3569fa03b00aSjbeck   };
35707c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP)
35717c478bd9Sstevel@tonic-gate   if(!term || tgetent(gl->tgetent_buf, (char *)term) < 0) {
35727c478bd9Sstevel@tonic-gate     bad_term = 1;
35737c478bd9Sstevel@tonic-gate   } else {
35747c478bd9Sstevel@tonic-gate     char *tgetstr_buf_ptr = gl->tgetstr_buf;
35757c478bd9Sstevel@tonic-gate     _clr_StringGroup(gl->capmem);
35767c478bd9Sstevel@tonic-gate     gl->left = gl_tgetstr(gl, "le", &tgetstr_buf_ptr);
35777c478bd9Sstevel@tonic-gate     gl->right = gl_tgetstr(gl, "nd", &tgetstr_buf_ptr);
35787c478bd9Sstevel@tonic-gate     gl->up = gl_tgetstr(gl, "up", &tgetstr_buf_ptr);
35797c478bd9Sstevel@tonic-gate     gl->down = gl_tgetstr(gl, "do", &tgetstr_buf_ptr);
35807c478bd9Sstevel@tonic-gate     gl->home = gl_tgetstr(gl, "ho", &tgetstr_buf_ptr);
35817c478bd9Sstevel@tonic-gate     gl->clear_eol = gl_tgetstr(gl, "ce", &tgetstr_buf_ptr);
35827c478bd9Sstevel@tonic-gate     gl->clear_eod = gl_tgetstr(gl, "cd", &tgetstr_buf_ptr);
35837c478bd9Sstevel@tonic-gate     gl->u_arrow = gl_tgetstr(gl, "ku", &tgetstr_buf_ptr);
35847c478bd9Sstevel@tonic-gate     gl->d_arrow = gl_tgetstr(gl, "kd", &tgetstr_buf_ptr);
35857c478bd9Sstevel@tonic-gate     gl->l_arrow = gl_tgetstr(gl, "kl", &tgetstr_buf_ptr);
35867c478bd9Sstevel@tonic-gate     gl->r_arrow = gl_tgetstr(gl, "kr", &tgetstr_buf_ptr);
35877c478bd9Sstevel@tonic-gate     gl->sound_bell = gl_tgetstr(gl, "bl", &tgetstr_buf_ptr);
35887c478bd9Sstevel@tonic-gate     gl->bold = gl_tgetstr(gl, "md", &tgetstr_buf_ptr);
35897c478bd9Sstevel@tonic-gate     gl->underline = gl_tgetstr(gl, "us", &tgetstr_buf_ptr);
35907c478bd9Sstevel@tonic-gate     gl->standout = gl_tgetstr(gl, "so", &tgetstr_buf_ptr);
35917c478bd9Sstevel@tonic-gate     gl->dim = gl_tgetstr(gl, "mh", &tgetstr_buf_ptr);
35927c478bd9Sstevel@tonic-gate     gl->reverse = gl_tgetstr(gl, "mr", &tgetstr_buf_ptr);
35937c478bd9Sstevel@tonic-gate     gl->blink = gl_tgetstr(gl, "mb", &tgetstr_buf_ptr);
35947c478bd9Sstevel@tonic-gate     gl->text_attr_off = gl_tgetstr(gl, "me", &tgetstr_buf_ptr);
35957c478bd9Sstevel@tonic-gate   };
35967c478bd9Sstevel@tonic-gate #endif
35977c478bd9Sstevel@tonic-gate /*
35987c478bd9Sstevel@tonic-gate  * Report term being unusable.
35997c478bd9Sstevel@tonic-gate  */
36007c478bd9Sstevel@tonic-gate   if(bad_term) {
36017c478bd9Sstevel@tonic-gate     gl_print_info(gl, "Bad terminal type: \"", term ? term : "(null)",
36027c478bd9Sstevel@tonic-gate 		  "\". Will assume vt100.", GL_END_INFO);
36037c478bd9Sstevel@tonic-gate   };
36047c478bd9Sstevel@tonic-gate /*
36057c478bd9Sstevel@tonic-gate  * Fill in missing information with ANSI VT100 strings.
36067c478bd9Sstevel@tonic-gate  */
36077c478bd9Sstevel@tonic-gate   if(!gl->left)
36087c478bd9Sstevel@tonic-gate     gl->left = "\b";    /* ^H */
36097c478bd9Sstevel@tonic-gate   if(!gl->right)
36107c478bd9Sstevel@tonic-gate     gl->right = GL_ESC_STR "[C";
36117c478bd9Sstevel@tonic-gate   if(!gl->up)
36127c478bd9Sstevel@tonic-gate     gl->up = GL_ESC_STR "[A";
36137c478bd9Sstevel@tonic-gate   if(!gl->down)
36147c478bd9Sstevel@tonic-gate     gl->down = "\n";
36157c478bd9Sstevel@tonic-gate   if(!gl->home)
36167c478bd9Sstevel@tonic-gate     gl->home = GL_ESC_STR "[H";
36177c478bd9Sstevel@tonic-gate   if(!gl->bol)
36187c478bd9Sstevel@tonic-gate     gl->bol = "\r";
36197c478bd9Sstevel@tonic-gate   if(!gl->clear_eol)
36207c478bd9Sstevel@tonic-gate     gl->clear_eol = GL_ESC_STR "[K";
36217c478bd9Sstevel@tonic-gate   if(!gl->clear_eod)
36227c478bd9Sstevel@tonic-gate     gl->clear_eod = GL_ESC_STR "[J";
36237c478bd9Sstevel@tonic-gate   if(!gl->u_arrow)
36247c478bd9Sstevel@tonic-gate     gl->u_arrow = GL_ESC_STR "[A";
36257c478bd9Sstevel@tonic-gate   if(!gl->d_arrow)
36267c478bd9Sstevel@tonic-gate     gl->d_arrow = GL_ESC_STR "[B";
36277c478bd9Sstevel@tonic-gate   if(!gl->l_arrow)
36287c478bd9Sstevel@tonic-gate     gl->l_arrow = GL_ESC_STR "[D";
36297c478bd9Sstevel@tonic-gate   if(!gl->r_arrow)
36307c478bd9Sstevel@tonic-gate     gl->r_arrow = GL_ESC_STR "[C";
36317c478bd9Sstevel@tonic-gate   if(!gl->sound_bell)
36327c478bd9Sstevel@tonic-gate     gl->sound_bell = "\a";
36337c478bd9Sstevel@tonic-gate   if(!gl->bold)
36347c478bd9Sstevel@tonic-gate     gl->bold = GL_ESC_STR "[1m";
36357c478bd9Sstevel@tonic-gate   if(!gl->underline)
36367c478bd9Sstevel@tonic-gate     gl->underline = GL_ESC_STR "[4m";
36377c478bd9Sstevel@tonic-gate   if(!gl->standout)
36387c478bd9Sstevel@tonic-gate     gl->standout = GL_ESC_STR "[1;7m";
36397c478bd9Sstevel@tonic-gate   if(!gl->dim)
36407c478bd9Sstevel@tonic-gate     gl->dim = "";  /* Not available */
36417c478bd9Sstevel@tonic-gate   if(!gl->reverse)
36427c478bd9Sstevel@tonic-gate     gl->reverse = GL_ESC_STR "[7m";
36437c478bd9Sstevel@tonic-gate   if(!gl->blink)
36447c478bd9Sstevel@tonic-gate     gl->blink = GL_ESC_STR "[5m";
36457c478bd9Sstevel@tonic-gate   if(!gl->text_attr_off)
36467c478bd9Sstevel@tonic-gate     gl->text_attr_off = GL_ESC_STR "[m";
36477c478bd9Sstevel@tonic-gate /*
36487c478bd9Sstevel@tonic-gate  * Find out the current terminal size.
36497c478bd9Sstevel@tonic-gate  */
36507c478bd9Sstevel@tonic-gate   (void) _gl_terminal_size(gl, GL_DEF_NCOLUMN, GL_DEF_NLINE, NULL);
36517c478bd9Sstevel@tonic-gate   return 0;
36527c478bd9Sstevel@tonic-gate }
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
36557c478bd9Sstevel@tonic-gate /*.......................................................................
36567c478bd9Sstevel@tonic-gate  * This is a private function of gl_control_strings() used to look up
36577c478bd9Sstevel@tonic-gate  * a termninal capability string from the terminfo database and make
36587c478bd9Sstevel@tonic-gate  * a private copy of it.
36597c478bd9Sstevel@tonic-gate  *
36607c478bd9Sstevel@tonic-gate  * Input:
36617c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
36627c478bd9Sstevel@tonic-gate  *  name    const char *  The name of the terminfo string to look up.
36637c478bd9Sstevel@tonic-gate  * Output:
36647c478bd9Sstevel@tonic-gate  *  return  const char *  The local copy of the capability, or NULL
36657c478bd9Sstevel@tonic-gate  *                        if not available.
36667c478bd9Sstevel@tonic-gate  */
gl_tigetstr(GetLine * gl,const char * name)36677c478bd9Sstevel@tonic-gate static const char *gl_tigetstr(GetLine *gl, const char *name)
36687c478bd9Sstevel@tonic-gate {
36697c478bd9Sstevel@tonic-gate   const char *value = tigetstr((char *)name);
36707c478bd9Sstevel@tonic-gate   if(!value || value == (char *) -1)
36717c478bd9Sstevel@tonic-gate     return NULL;
36727c478bd9Sstevel@tonic-gate   return _sg_store_string(gl->capmem, value, 0);
36737c478bd9Sstevel@tonic-gate }
36747c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP)
36757c478bd9Sstevel@tonic-gate /*.......................................................................
36767c478bd9Sstevel@tonic-gate  * This is a private function of gl_control_strings() used to look up
36777c478bd9Sstevel@tonic-gate  * a termninal capability string from the termcap database and make
36787c478bd9Sstevel@tonic-gate  * a private copy of it. Note that some emulations of tgetstr(), such
36797c478bd9Sstevel@tonic-gate  * as that used by Solaris, ignores the buffer pointer that is past to
36807c478bd9Sstevel@tonic-gate  * it, so we can't assume that a private copy has been made that won't
36817c478bd9Sstevel@tonic-gate  * be trashed by another call to gl_control_strings() by another
36827c478bd9Sstevel@tonic-gate  * GetLine object. So we make what may be a redundant private copy
36837c478bd9Sstevel@tonic-gate  * of the string in gl->capmem.
36847c478bd9Sstevel@tonic-gate  *
36857c478bd9Sstevel@tonic-gate  * Input:
36867c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
36877c478bd9Sstevel@tonic-gate  *  name    const char *  The name of the terminfo string to look up.
36887c478bd9Sstevel@tonic-gate  * Input/Output:
36897c478bd9Sstevel@tonic-gate  *  bufptr        char ** On input *bufptr points to the location in
36907c478bd9Sstevel@tonic-gate  *                        gl->tgetstr_buf at which to record the
36917c478bd9Sstevel@tonic-gate  *                        capability string. On output *bufptr is
36927c478bd9Sstevel@tonic-gate  *                        incremented over the stored string.
36937c478bd9Sstevel@tonic-gate  * Output:
36947c478bd9Sstevel@tonic-gate  *  return  const char *  The local copy of the capability, or NULL
36957c478bd9Sstevel@tonic-gate  *                        on error.
36967c478bd9Sstevel@tonic-gate  */
gl_tgetstr(GetLine * gl,const char * name,char ** bufptr)36977c478bd9Sstevel@tonic-gate static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr)
36987c478bd9Sstevel@tonic-gate {
36997c478bd9Sstevel@tonic-gate   const char *value = tgetstr((char *)name, bufptr);
37007c478bd9Sstevel@tonic-gate   if(!value || value == (char *) -1)
37017c478bd9Sstevel@tonic-gate     return NULL;
37027c478bd9Sstevel@tonic-gate   return _sg_store_string(gl->capmem, value, 0);
37037c478bd9Sstevel@tonic-gate }
37047c478bd9Sstevel@tonic-gate #endif
37057c478bd9Sstevel@tonic-gate 
37067c478bd9Sstevel@tonic-gate /*.......................................................................
37077c478bd9Sstevel@tonic-gate  * This is an action function that implements a user interrupt (eg. ^C).
37087c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_user_interrupt)37097c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_user_interrupt)
37107c478bd9Sstevel@tonic-gate {
37117c478bd9Sstevel@tonic-gate   raise(SIGINT);
37127c478bd9Sstevel@tonic-gate   return 1;
37137c478bd9Sstevel@tonic-gate }
37147c478bd9Sstevel@tonic-gate 
37157c478bd9Sstevel@tonic-gate /*.......................................................................
37167c478bd9Sstevel@tonic-gate  * This is an action function that implements the abort signal.
37177c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_abort)37187c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_abort)
37197c478bd9Sstevel@tonic-gate {
37207c478bd9Sstevel@tonic-gate   raise(SIGABRT);
37217c478bd9Sstevel@tonic-gate   return 1;
37227c478bd9Sstevel@tonic-gate }
37237c478bd9Sstevel@tonic-gate 
37247c478bd9Sstevel@tonic-gate /*.......................................................................
37257c478bd9Sstevel@tonic-gate  * This is an action function that sends a suspend signal (eg. ^Z) to the
37267c478bd9Sstevel@tonic-gate  * the parent process.
37277c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_suspend)37287c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_suspend)
37297c478bd9Sstevel@tonic-gate {
37307c478bd9Sstevel@tonic-gate   raise(SIGTSTP);
37317c478bd9Sstevel@tonic-gate   return 0;
37327c478bd9Sstevel@tonic-gate }
37337c478bd9Sstevel@tonic-gate 
37347c478bd9Sstevel@tonic-gate /*.......................................................................
37357c478bd9Sstevel@tonic-gate  * This is an action function that halts output to the terminal.
37367c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_stop_output)37377c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_stop_output)
37387c478bd9Sstevel@tonic-gate {
37397c478bd9Sstevel@tonic-gate   tcflow(gl->output_fd, TCOOFF);
37407c478bd9Sstevel@tonic-gate   return 0;
37417c478bd9Sstevel@tonic-gate }
37427c478bd9Sstevel@tonic-gate 
37437c478bd9Sstevel@tonic-gate /*.......................................................................
37447c478bd9Sstevel@tonic-gate  * This is an action function that resumes halted terminal output.
37457c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_start_output)37467c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_start_output)
37477c478bd9Sstevel@tonic-gate {
37487c478bd9Sstevel@tonic-gate   tcflow(gl->output_fd, TCOON);
37497c478bd9Sstevel@tonic-gate   return 0;
37507c478bd9Sstevel@tonic-gate }
37517c478bd9Sstevel@tonic-gate 
37527c478bd9Sstevel@tonic-gate /*.......................................................................
37537c478bd9Sstevel@tonic-gate  * This is an action function that allows the next character to be accepted
37547c478bd9Sstevel@tonic-gate  * without any interpretation as a special character.
37557c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_literal_next)37567c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_literal_next)
37577c478bd9Sstevel@tonic-gate {
37587c478bd9Sstevel@tonic-gate   char c;   /* The character to be added to the line */
37597c478bd9Sstevel@tonic-gate   int i;
37607c478bd9Sstevel@tonic-gate /*
37617c478bd9Sstevel@tonic-gate  * Get the character to be inserted literally.
37627c478bd9Sstevel@tonic-gate  */
37637c478bd9Sstevel@tonic-gate   if(gl_read_terminal(gl, 1, &c))
37647c478bd9Sstevel@tonic-gate     return 1;
37657c478bd9Sstevel@tonic-gate /*
37667c478bd9Sstevel@tonic-gate  * Add the character to the line 'count' times.
37677c478bd9Sstevel@tonic-gate  */
37687c478bd9Sstevel@tonic-gate   for(i=0; i<count; i++)
37697c478bd9Sstevel@tonic-gate     gl_add_char_to_line(gl, c);
37707c478bd9Sstevel@tonic-gate   return 0;
37717c478bd9Sstevel@tonic-gate }
37727c478bd9Sstevel@tonic-gate 
37737c478bd9Sstevel@tonic-gate /*.......................................................................
37747c478bd9Sstevel@tonic-gate  * Return the width of a tab character at a given position when
37757c478bd9Sstevel@tonic-gate  * displayed at a given position on the terminal. This is needed
37767c478bd9Sstevel@tonic-gate  * because the width of tab characters depends on where they are,
37777c478bd9Sstevel@tonic-gate  * relative to the preceding tab stops.
37787c478bd9Sstevel@tonic-gate  *
37797c478bd9Sstevel@tonic-gate  * Input:
37807c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The resource object of this library.
37817c478bd9Sstevel@tonic-gate  *  term_curpos  int    The destination terminal location of the character.
37827c478bd9Sstevel@tonic-gate  * Output:
37837c478bd9Sstevel@tonic-gate  *  return       int    The number of terminal charaters needed.
37847c478bd9Sstevel@tonic-gate  */
gl_displayed_tab_width(GetLine * gl,int term_curpos)37857c478bd9Sstevel@tonic-gate static int gl_displayed_tab_width(GetLine *gl, int term_curpos)
37867c478bd9Sstevel@tonic-gate {
37877c478bd9Sstevel@tonic-gate   return TAB_WIDTH - ((term_curpos % gl->ncolumn) % TAB_WIDTH);
37887c478bd9Sstevel@tonic-gate }
37897c478bd9Sstevel@tonic-gate 
37907c478bd9Sstevel@tonic-gate /*.......................................................................
37917c478bd9Sstevel@tonic-gate  * Return the number of characters needed to display a given character
37927c478bd9Sstevel@tonic-gate  * on the screen. Tab characters require eight spaces, and control
37937c478bd9Sstevel@tonic-gate  * characters are represented by a caret followed by the modified
37947c478bd9Sstevel@tonic-gate  * character.
37957c478bd9Sstevel@tonic-gate  *
37967c478bd9Sstevel@tonic-gate  * Input:
37977c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The resource object of this library.
37987c478bd9Sstevel@tonic-gate  *  c           char    The character to be displayed.
37997c478bd9Sstevel@tonic-gate  *  term_curpos  int    The destination terminal location of the character.
38007c478bd9Sstevel@tonic-gate  *                      This is needed because the width of tab characters
38017c478bd9Sstevel@tonic-gate  *                      depends on where they are, relative to the
38027c478bd9Sstevel@tonic-gate  *                      preceding tab stops.
38037c478bd9Sstevel@tonic-gate  * Output:
38047c478bd9Sstevel@tonic-gate  *  return       int    The number of terminal charaters needed.
38057c478bd9Sstevel@tonic-gate  */
gl_displayed_char_width(GetLine * gl,char c,int term_curpos)38067c478bd9Sstevel@tonic-gate static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos)
38077c478bd9Sstevel@tonic-gate {
38087c478bd9Sstevel@tonic-gate   if(c=='\t')
38097c478bd9Sstevel@tonic-gate     return gl_displayed_tab_width(gl, term_curpos);
38107c478bd9Sstevel@tonic-gate   if(IS_CTRL_CHAR(c))
38117c478bd9Sstevel@tonic-gate     return 2;
38127c478bd9Sstevel@tonic-gate   if(!isprint((int)(unsigned char) c))
38137c478bd9Sstevel@tonic-gate     return gl_octal_width((int)(unsigned char)c) + 1;
38147c478bd9Sstevel@tonic-gate   return 1;
38157c478bd9Sstevel@tonic-gate }
38167c478bd9Sstevel@tonic-gate 
38177c478bd9Sstevel@tonic-gate 
38187c478bd9Sstevel@tonic-gate /*.......................................................................
38197c478bd9Sstevel@tonic-gate  * Work out the length of given string of characters on the terminal.
38207c478bd9Sstevel@tonic-gate  *
38217c478bd9Sstevel@tonic-gate  * Input:
38227c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The resource object of this library.
38237c478bd9Sstevel@tonic-gate  *  string      char *  The string to be measured.
38247c478bd9Sstevel@tonic-gate  *  nc           int    The number of characters to be measured, or -1
38257c478bd9Sstevel@tonic-gate  *                      to measure the whole string.
38267c478bd9Sstevel@tonic-gate  *  term_curpos  int    The destination terminal location of the character.
38277c478bd9Sstevel@tonic-gate  *                      This is needed because the width of tab characters
38287c478bd9Sstevel@tonic-gate  *                      depends on where they are, relative to the
38297c478bd9Sstevel@tonic-gate  *                      preceding tab stops.
38307c478bd9Sstevel@tonic-gate  * Output:
38317c478bd9Sstevel@tonic-gate  *  return       int    The number of displayed characters.
38327c478bd9Sstevel@tonic-gate  */
gl_displayed_string_width(GetLine * gl,const char * string,int nc,int term_curpos)38337c478bd9Sstevel@tonic-gate static int gl_displayed_string_width(GetLine *gl, const char *string, int nc,
38347c478bd9Sstevel@tonic-gate 				     int term_curpos)
38357c478bd9Sstevel@tonic-gate {
38367c478bd9Sstevel@tonic-gate   int slen = 0;   /* The displayed number of characters */
38377c478bd9Sstevel@tonic-gate   int i;
38387c478bd9Sstevel@tonic-gate /*
38397c478bd9Sstevel@tonic-gate  * How many characters are to be measured?
38407c478bd9Sstevel@tonic-gate  */
38417c478bd9Sstevel@tonic-gate   if(nc < 0)
38427c478bd9Sstevel@tonic-gate     nc = strlen(string);
38437c478bd9Sstevel@tonic-gate /*
38447c478bd9Sstevel@tonic-gate  * Add up the length of the displayed string.
38457c478bd9Sstevel@tonic-gate  */
38467c478bd9Sstevel@tonic-gate   for(i=0; i<nc; i++)
38477c478bd9Sstevel@tonic-gate     slen += gl_displayed_char_width(gl, string[i], term_curpos + slen);
38487c478bd9Sstevel@tonic-gate   return slen;
38497c478bd9Sstevel@tonic-gate }
38507c478bd9Sstevel@tonic-gate 
38517c478bd9Sstevel@tonic-gate /*.......................................................................
38527c478bd9Sstevel@tonic-gate  * Write a string verbatim to the current terminal or output stream.
38537c478bd9Sstevel@tonic-gate  *
38547c478bd9Sstevel@tonic-gate  * Note that when async-signal safety is required, the 'buffered'
38557c478bd9Sstevel@tonic-gate  * argument must be 0, and n must not be -1.
38567c478bd9Sstevel@tonic-gate  *
38577c478bd9Sstevel@tonic-gate  * Input:
38587c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of the gl_get_line().
38597c478bd9Sstevel@tonic-gate  *  buffered       int    If true, used buffered I/O when writing to
38607c478bd9Sstevel@tonic-gate  *                        the terminal. Otherwise use async-signal-safe
38617c478bd9Sstevel@tonic-gate  *                        unbuffered I/O.
38627c478bd9Sstevel@tonic-gate  *  string  const char *  The string to be written (this need not be
38637c478bd9Sstevel@tonic-gate  *                        '\0' terminated unless n<0).
38647c478bd9Sstevel@tonic-gate  *  n              int    The number of characters to write from the
38657c478bd9Sstevel@tonic-gate  *                        prefix of string[], or -1 to request that
38667c478bd9Sstevel@tonic-gate  *                        gl_print_raw_string() use strlen() to figure
38677c478bd9Sstevel@tonic-gate  *                        out the length.
38687c478bd9Sstevel@tonic-gate  * Output:
38697c478bd9Sstevel@tonic-gate  *  return         int    0 - OK.
38707c478bd9Sstevel@tonic-gate  *                        1 - Error.
38717c478bd9Sstevel@tonic-gate  */
gl_print_raw_string(GetLine * gl,int buffered,const char * string,int n)38727c478bd9Sstevel@tonic-gate static int gl_print_raw_string(GetLine *gl, int buffered,
38737c478bd9Sstevel@tonic-gate 			       const char *string, int n)
38747c478bd9Sstevel@tonic-gate {
38757c478bd9Sstevel@tonic-gate   GlWriteFn *write_fn = buffered ? gl_write_fn : gl->flush_fn;
38767c478bd9Sstevel@tonic-gate /*
38777c478bd9Sstevel@tonic-gate  * Only display output when echoing is turned on.
38787c478bd9Sstevel@tonic-gate  */
38797c478bd9Sstevel@tonic-gate   if(gl->echo) {
38807c478bd9Sstevel@tonic-gate     int ndone = 0;   /* The number of characters written so far */
38817c478bd9Sstevel@tonic-gate /*
38827c478bd9Sstevel@tonic-gate  * When using un-buffered I/O, flush pending output first.
38837c478bd9Sstevel@tonic-gate  */
38847c478bd9Sstevel@tonic-gate     if(!buffered) {
38857c478bd9Sstevel@tonic-gate       if(gl_flush_output(gl))
38867c478bd9Sstevel@tonic-gate 	return 1;
38877c478bd9Sstevel@tonic-gate     };
38887c478bd9Sstevel@tonic-gate /*
38897c478bd9Sstevel@tonic-gate  * If no length has been provided, measure the length of the string.
38907c478bd9Sstevel@tonic-gate  */
38917c478bd9Sstevel@tonic-gate     if(n < 0)
38927c478bd9Sstevel@tonic-gate       n = strlen(string);
38937c478bd9Sstevel@tonic-gate /*
38947c478bd9Sstevel@tonic-gate  * Write the string.
38957c478bd9Sstevel@tonic-gate  */
38967c478bd9Sstevel@tonic-gate     if(write_fn(gl, string + ndone, n-ndone) != n)
38977c478bd9Sstevel@tonic-gate       return 1;
38987c478bd9Sstevel@tonic-gate   };
38997c478bd9Sstevel@tonic-gate   return 0;
39007c478bd9Sstevel@tonic-gate }
39017c478bd9Sstevel@tonic-gate 
39027c478bd9Sstevel@tonic-gate /*.......................................................................
39037c478bd9Sstevel@tonic-gate  * Output a terminal control sequence. When using terminfo,
39047c478bd9Sstevel@tonic-gate  * this must be a sequence returned by tgetstr() or tigetstr()
39057c478bd9Sstevel@tonic-gate  * respectively.
39067c478bd9Sstevel@tonic-gate  *
39077c478bd9Sstevel@tonic-gate  * Input:
39087c478bd9Sstevel@tonic-gate  *  gl     GetLine *   The resource object of this library.
39097c478bd9Sstevel@tonic-gate  *  nline      int     The number of lines affected by the operation,
39107c478bd9Sstevel@tonic-gate  *                     or 1 if not relevant.
39117c478bd9Sstevel@tonic-gate  *  string    char *   The control sequence to be sent.
39127c478bd9Sstevel@tonic-gate  * Output:
39137c478bd9Sstevel@tonic-gate  *  return     int     0 - OK.
39147c478bd9Sstevel@tonic-gate  *                     1 - Error.
39157c478bd9Sstevel@tonic-gate  */
gl_print_control_sequence(GetLine * gl,int nline,const char * string)39167c478bd9Sstevel@tonic-gate static int gl_print_control_sequence(GetLine *gl, int nline, const char *string)
39177c478bd9Sstevel@tonic-gate {
39187c478bd9Sstevel@tonic-gate   int waserr = 0;   /* True if an error occurs */
39197c478bd9Sstevel@tonic-gate /*
39207c478bd9Sstevel@tonic-gate  * Only write characters to the terminal when echoing is enabled.
39217c478bd9Sstevel@tonic-gate  */
39227c478bd9Sstevel@tonic-gate   if(gl->echo) {
39237c478bd9Sstevel@tonic-gate #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
39247c478bd9Sstevel@tonic-gate     tputs_gl = gl;
39257c478bd9Sstevel@tonic-gate     errno = 0;
39267c478bd9Sstevel@tonic-gate     tputs((char *)string, nline, gl_tputs_putchar);
39277c478bd9Sstevel@tonic-gate     waserr = errno != 0;
39287c478bd9Sstevel@tonic-gate #else
39297c478bd9Sstevel@tonic-gate     waserr = gl_print_raw_string(gl, 1, string, -1);
39307c478bd9Sstevel@tonic-gate #endif
39317c478bd9Sstevel@tonic-gate   };
39327c478bd9Sstevel@tonic-gate   return waserr;
39337c478bd9Sstevel@tonic-gate }
39347c478bd9Sstevel@tonic-gate 
39357c478bd9Sstevel@tonic-gate #if defined(USE_TERMINFO) || defined(USE_TERMCAP)
39367c478bd9Sstevel@tonic-gate /*.......................................................................
39377c478bd9Sstevel@tonic-gate  * The following callback function is called by tputs() to output a raw
39387c478bd9Sstevel@tonic-gate  * control character to the terminal.
39397c478bd9Sstevel@tonic-gate  */
gl_tputs_putchar(TputsArgType c)39407c478bd9Sstevel@tonic-gate static TputsRetType gl_tputs_putchar(TputsArgType c)
39417c478bd9Sstevel@tonic-gate {
39427c478bd9Sstevel@tonic-gate   char ch = c;
39437c478bd9Sstevel@tonic-gate #if TPUTS_RETURNS_VALUE
39447c478bd9Sstevel@tonic-gate   return gl_print_raw_string(tputs_gl, 1, &ch, 1);
39457c478bd9Sstevel@tonic-gate #else
39467c478bd9Sstevel@tonic-gate   (void) gl_print_raw_string(tputs_gl, 1, &ch, 1);
39477c478bd9Sstevel@tonic-gate #endif
39487c478bd9Sstevel@tonic-gate }
39497c478bd9Sstevel@tonic-gate #endif
39507c478bd9Sstevel@tonic-gate 
39517c478bd9Sstevel@tonic-gate /*.......................................................................
39527c478bd9Sstevel@tonic-gate  * Move the terminal cursor n characters to the left or right.
39537c478bd9Sstevel@tonic-gate  *
39547c478bd9Sstevel@tonic-gate  * Input:
39557c478bd9Sstevel@tonic-gate  *  gl     GetLine *   The resource object of this program.
39567c478bd9Sstevel@tonic-gate  *  n          int     number of positions to the right (> 0) or left (< 0).
39577c478bd9Sstevel@tonic-gate  * Output:
39587c478bd9Sstevel@tonic-gate  *  return     int     0 - OK.
39597c478bd9Sstevel@tonic-gate  *                     1 - Error.
39607c478bd9Sstevel@tonic-gate  */
gl_terminal_move_cursor(GetLine * gl,int n)39617c478bd9Sstevel@tonic-gate static int gl_terminal_move_cursor(GetLine *gl, int n)
39627c478bd9Sstevel@tonic-gate {
39637c478bd9Sstevel@tonic-gate   int cur_row, cur_col; /* The current terminal row and column index of */
39647c478bd9Sstevel@tonic-gate                         /*  the cursor wrt the start of the input line. */
39657c478bd9Sstevel@tonic-gate   int new_row, new_col; /* The target terminal row and column index of */
39667c478bd9Sstevel@tonic-gate                         /*  the cursor wrt the start of the input line. */
39677c478bd9Sstevel@tonic-gate /*
39687c478bd9Sstevel@tonic-gate  * Do nothing if the input line isn't currently displayed. In this
39697c478bd9Sstevel@tonic-gate  * case, the cursor will be moved to the right place when the line
39707c478bd9Sstevel@tonic-gate  * is next redisplayed.
39717c478bd9Sstevel@tonic-gate  */
39727c478bd9Sstevel@tonic-gate   if(!gl->displayed)
39737c478bd9Sstevel@tonic-gate     return 0;
39747c478bd9Sstevel@tonic-gate /*
39757c478bd9Sstevel@tonic-gate  * How far can we move left?
39767c478bd9Sstevel@tonic-gate  */
39777c478bd9Sstevel@tonic-gate   if(gl->term_curpos + n < 0)
39787c478bd9Sstevel@tonic-gate     n = gl->term_curpos;
39797c478bd9Sstevel@tonic-gate /*
39807c478bd9Sstevel@tonic-gate  * Break down the current and target cursor locations into rows and columns.
39817c478bd9Sstevel@tonic-gate  */
39827c478bd9Sstevel@tonic-gate   cur_row = gl->term_curpos / gl->ncolumn;
39837c478bd9Sstevel@tonic-gate   cur_col = gl->term_curpos % gl->ncolumn;
39847c478bd9Sstevel@tonic-gate   new_row = (gl->term_curpos + n) / gl->ncolumn;
39857c478bd9Sstevel@tonic-gate   new_col = (gl->term_curpos + n) % gl->ncolumn;
39867c478bd9Sstevel@tonic-gate /*
39877c478bd9Sstevel@tonic-gate  * Move down to the next line.
39887c478bd9Sstevel@tonic-gate  */
39897c478bd9Sstevel@tonic-gate   for(; cur_row < new_row; cur_row++) {
39907c478bd9Sstevel@tonic-gate     if(gl_print_control_sequence(gl, 1, gl->down))
39917c478bd9Sstevel@tonic-gate       return 1;
39927c478bd9Sstevel@tonic-gate   };
39937c478bd9Sstevel@tonic-gate /*
39947c478bd9Sstevel@tonic-gate  * Move up to the previous line.
39957c478bd9Sstevel@tonic-gate  */
39967c478bd9Sstevel@tonic-gate   for(; cur_row > new_row; cur_row--) {
39977c478bd9Sstevel@tonic-gate     if(gl_print_control_sequence(gl, 1, gl->up))
39987c478bd9Sstevel@tonic-gate       return 1;
39997c478bd9Sstevel@tonic-gate   };
40007c478bd9Sstevel@tonic-gate /*
40017c478bd9Sstevel@tonic-gate  * Move to the right within the target line?
40027c478bd9Sstevel@tonic-gate  */
40037c478bd9Sstevel@tonic-gate   if(cur_col < new_col) {
40047c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
40057c478bd9Sstevel@tonic-gate /*
40067c478bd9Sstevel@tonic-gate  * Use a parameterized control sequence if it generates less control
40077c478bd9Sstevel@tonic-gate  * characters (guess based on ANSI terminal termcap entry).
40087c478bd9Sstevel@tonic-gate  */
40097c478bd9Sstevel@tonic-gate     if(gl->right_n != NULL && new_col - cur_col > 1) {
40107c478bd9Sstevel@tonic-gate       if(gl_print_control_sequence(gl, 1, tparm((char *)gl->right_n,
40117c478bd9Sstevel@tonic-gate            (long)(new_col - cur_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
40127c478bd9Sstevel@tonic-gate 	return 1;
40137c478bd9Sstevel@tonic-gate     } else
40147c478bd9Sstevel@tonic-gate #endif
40157c478bd9Sstevel@tonic-gate     {
40167c478bd9Sstevel@tonic-gate       for(; cur_col < new_col; cur_col++) {
40177c478bd9Sstevel@tonic-gate         if(gl_print_control_sequence(gl, 1, gl->right))
40187c478bd9Sstevel@tonic-gate           return 1;
40197c478bd9Sstevel@tonic-gate       };
40207c478bd9Sstevel@tonic-gate     };
40217c478bd9Sstevel@tonic-gate /*
40227c478bd9Sstevel@tonic-gate  * Move to the left within the target line?
40237c478bd9Sstevel@tonic-gate  */
40247c478bd9Sstevel@tonic-gate   } else if(cur_col > new_col) {
40257c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
40267c478bd9Sstevel@tonic-gate /*
40277c478bd9Sstevel@tonic-gate  * Use a parameterized control sequence if it generates less control
40287c478bd9Sstevel@tonic-gate  * characters (guess based on ANSI terminal termcap entry).
40297c478bd9Sstevel@tonic-gate  */
40307c478bd9Sstevel@tonic-gate     if(gl->left_n != NULL && cur_col - new_col > 3) {
40317c478bd9Sstevel@tonic-gate       if(gl_print_control_sequence(gl, 1, tparm((char *)gl->left_n,
40327c478bd9Sstevel@tonic-gate            (long)(cur_col - new_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l)))
40337c478bd9Sstevel@tonic-gate 	return 1;
40347c478bd9Sstevel@tonic-gate     } else
40357c478bd9Sstevel@tonic-gate #endif
40367c478bd9Sstevel@tonic-gate     {
40377c478bd9Sstevel@tonic-gate       for(; cur_col > new_col; cur_col--) {
40387c478bd9Sstevel@tonic-gate         if(gl_print_control_sequence(gl, 1, gl->left))
40397c478bd9Sstevel@tonic-gate           return 1;
40407c478bd9Sstevel@tonic-gate       };
40417c478bd9Sstevel@tonic-gate     };
40427c478bd9Sstevel@tonic-gate   }
40437c478bd9Sstevel@tonic-gate /*
40447c478bd9Sstevel@tonic-gate  * Update the recorded position of the terminal cursor.
40457c478bd9Sstevel@tonic-gate  */
40467c478bd9Sstevel@tonic-gate   gl->term_curpos += n;
40477c478bd9Sstevel@tonic-gate   return 0;
40487c478bd9Sstevel@tonic-gate }
40497c478bd9Sstevel@tonic-gate 
40507c478bd9Sstevel@tonic-gate /*.......................................................................
40517c478bd9Sstevel@tonic-gate  * Write a character to the terminal after expanding tabs and control
40527c478bd9Sstevel@tonic-gate  * characters to their multi-character representations.
40537c478bd9Sstevel@tonic-gate  *
40547c478bd9Sstevel@tonic-gate  * Input:
40557c478bd9Sstevel@tonic-gate  *  gl    GetLine *   The resource object of this program.
40567c478bd9Sstevel@tonic-gate  *  c        char     The character to be output.
40577c478bd9Sstevel@tonic-gate  *  pad      char     Many terminals have the irritating feature that
40587c478bd9Sstevel@tonic-gate  *                    when one writes a character in the last column of
40597c478bd9Sstevel@tonic-gate  *                    of the terminal, the cursor isn't wrapped to the
40607c478bd9Sstevel@tonic-gate  *                    start of the next line until one more character
40617c478bd9Sstevel@tonic-gate  *                    is written. Some terminals don't do this, so
40627c478bd9Sstevel@tonic-gate  *                    after such a write, we don't know where the
40637c478bd9Sstevel@tonic-gate  *                    terminal is unless we output an extra character.
40647c478bd9Sstevel@tonic-gate  *                    This argument specifies the character to write.
40657c478bd9Sstevel@tonic-gate  *                    If at the end of the input line send '\0' or a
40667c478bd9Sstevel@tonic-gate  *                    space, and a space will be written. Otherwise,
40677c478bd9Sstevel@tonic-gate  *                    pass the next character in the input line
40687c478bd9Sstevel@tonic-gate  *                    following the one being written.
40697c478bd9Sstevel@tonic-gate  * Output:
40707c478bd9Sstevel@tonic-gate  *  return    int     0 - OK.
40717c478bd9Sstevel@tonic-gate  */
gl_print_char(GetLine * gl,char c,char pad)40727c478bd9Sstevel@tonic-gate static int gl_print_char(GetLine *gl, char c, char pad)
40737c478bd9Sstevel@tonic-gate {
40747c478bd9Sstevel@tonic-gate   char string[TAB_WIDTH + 4]; /* A work area for composing compound strings */
40757c478bd9Sstevel@tonic-gate   int nchar;                  /* The number of terminal characters */
40767c478bd9Sstevel@tonic-gate   int i;
40777c478bd9Sstevel@tonic-gate /*
40787c478bd9Sstevel@tonic-gate  * Check for special characters.
40797c478bd9Sstevel@tonic-gate  */
40807c478bd9Sstevel@tonic-gate   if(c == '\t') {
40817c478bd9Sstevel@tonic-gate /*
40827c478bd9Sstevel@tonic-gate  * How many spaces do we need to represent a tab at the current terminal
40837c478bd9Sstevel@tonic-gate  * column?
40847c478bd9Sstevel@tonic-gate  */
40857c478bd9Sstevel@tonic-gate     nchar = gl_displayed_tab_width(gl, gl->term_curpos);
40867c478bd9Sstevel@tonic-gate /*
40877c478bd9Sstevel@tonic-gate  * Compose the tab string.
40887c478bd9Sstevel@tonic-gate  */
40897c478bd9Sstevel@tonic-gate     for(i=0; i<nchar; i++)
40907c478bd9Sstevel@tonic-gate       string[i] = ' ';
40917c478bd9Sstevel@tonic-gate   } else if(IS_CTRL_CHAR(c)) {
40927c478bd9Sstevel@tonic-gate     string[0] = '^';
40937c478bd9Sstevel@tonic-gate     string[1] = CTRL_TO_CHAR(c);
40947c478bd9Sstevel@tonic-gate     nchar = 2;
40957c478bd9Sstevel@tonic-gate   } else if(!isprint((int)(unsigned char) c)) {
40967c478bd9Sstevel@tonic-gate     snprintf(string, sizeof(string), "\\%o", (int)(unsigned char)c);
40977c478bd9Sstevel@tonic-gate     nchar = strlen(string);
40987c478bd9Sstevel@tonic-gate   } else {
40997c478bd9Sstevel@tonic-gate     string[0] = c;
41007c478bd9Sstevel@tonic-gate     nchar = 1;
41017c478bd9Sstevel@tonic-gate   };
41027c478bd9Sstevel@tonic-gate /*
41037c478bd9Sstevel@tonic-gate  * Terminate the string.
41047c478bd9Sstevel@tonic-gate  */
41057c478bd9Sstevel@tonic-gate   string[nchar] = '\0';
41067c478bd9Sstevel@tonic-gate /*
41077c478bd9Sstevel@tonic-gate  * Write the string to the terminal.
41087c478bd9Sstevel@tonic-gate  */
41097c478bd9Sstevel@tonic-gate   if(gl_print_raw_string(gl, 1, string, -1))
41107c478bd9Sstevel@tonic-gate     return 1;
41117c478bd9Sstevel@tonic-gate /*
41127c478bd9Sstevel@tonic-gate  * Except for one exception to be described in a moment, the cursor should
41137c478bd9Sstevel@tonic-gate  * now have been positioned after the character that was just output.
41147c478bd9Sstevel@tonic-gate  */
41157c478bd9Sstevel@tonic-gate   gl->term_curpos += nchar;
41167c478bd9Sstevel@tonic-gate /*
41177c478bd9Sstevel@tonic-gate  * Keep a record of the number of characters in the terminal version
41187c478bd9Sstevel@tonic-gate  * of the input line.
41197c478bd9Sstevel@tonic-gate  */
41207c478bd9Sstevel@tonic-gate   if(gl->term_curpos > gl->term_len)
41217c478bd9Sstevel@tonic-gate     gl->term_len = gl->term_curpos;
41227c478bd9Sstevel@tonic-gate /*
41237c478bd9Sstevel@tonic-gate  * If the new character ended exactly at the end of a line,
41247c478bd9Sstevel@tonic-gate  * most terminals won't move the cursor onto the next line until we
41257c478bd9Sstevel@tonic-gate  * have written a character on the next line, so append an extra
41267c478bd9Sstevel@tonic-gate  * space then move the cursor back.
41277c478bd9Sstevel@tonic-gate  */
41287c478bd9Sstevel@tonic-gate   if(gl->term_curpos % gl->ncolumn == 0) {
41297c478bd9Sstevel@tonic-gate     int term_curpos = gl->term_curpos;
41307c478bd9Sstevel@tonic-gate     if(gl_print_char(gl, pad ? pad : ' ', ' ') ||
41317c478bd9Sstevel@tonic-gate        gl_set_term_curpos(gl, term_curpos))
41327c478bd9Sstevel@tonic-gate       return 1;
41337c478bd9Sstevel@tonic-gate   };
41347c478bd9Sstevel@tonic-gate   return 0;
41357c478bd9Sstevel@tonic-gate }
41367c478bd9Sstevel@tonic-gate 
41377c478bd9Sstevel@tonic-gate /*.......................................................................
41387c478bd9Sstevel@tonic-gate  * Write a string to the terminal after expanding tabs and control
41397c478bd9Sstevel@tonic-gate  * characters to their multi-character representations.
41407c478bd9Sstevel@tonic-gate  *
41417c478bd9Sstevel@tonic-gate  * Input:
41427c478bd9Sstevel@tonic-gate  *  gl    GetLine *   The resource object of this program.
41437c478bd9Sstevel@tonic-gate  *  string   char *   The string to be output.
41447c478bd9Sstevel@tonic-gate  *  pad      char     Many terminals have the irritating feature that
41457c478bd9Sstevel@tonic-gate  *                    when one writes a character in the last column of
41467c478bd9Sstevel@tonic-gate  *                    of the terminal, the cursor isn't wrapped to the
41477c478bd9Sstevel@tonic-gate  *                    start of the next line until one more character
41487c478bd9Sstevel@tonic-gate  *                    is written. Some terminals don't do this, so
41497c478bd9Sstevel@tonic-gate  *                    after such a write, we don't know where the
41507c478bd9Sstevel@tonic-gate  *                    terminal is unless we output an extra character.
41517c478bd9Sstevel@tonic-gate  *                    This argument specifies the character to write.
41527c478bd9Sstevel@tonic-gate  *                    If at the end of the input line send '\0' or a
41537c478bd9Sstevel@tonic-gate  *                    space, and a space will be written. Otherwise,
41547c478bd9Sstevel@tonic-gate  *                    pass the next character in the input line
41557c478bd9Sstevel@tonic-gate  *                    following the one being written.
41567c478bd9Sstevel@tonic-gate  * Output:
41577c478bd9Sstevel@tonic-gate  *  return    int     0 - OK.
41587c478bd9Sstevel@tonic-gate  */
gl_print_string(GetLine * gl,const char * string,char pad)41597c478bd9Sstevel@tonic-gate static int gl_print_string(GetLine *gl, const char *string, char pad)
41607c478bd9Sstevel@tonic-gate {
41617c478bd9Sstevel@tonic-gate   const char *cptr;   /* A pointer into string[] */
41627c478bd9Sstevel@tonic-gate   for(cptr=string; *cptr; cptr++) {
41637c478bd9Sstevel@tonic-gate     char nextc = cptr[1];
41647c478bd9Sstevel@tonic-gate     if(gl_print_char(gl, *cptr, nextc ? nextc : pad))
41657c478bd9Sstevel@tonic-gate       return 1;
41667c478bd9Sstevel@tonic-gate   };
41677c478bd9Sstevel@tonic-gate   return 0;
41687c478bd9Sstevel@tonic-gate }
41697c478bd9Sstevel@tonic-gate 
41707c478bd9Sstevel@tonic-gate /*.......................................................................
41717c478bd9Sstevel@tonic-gate  * Move the terminal cursor position.
41727c478bd9Sstevel@tonic-gate  *
41737c478bd9Sstevel@tonic-gate  * Input:
41747c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The resource object of this library.
41757c478bd9Sstevel@tonic-gate  *  term_curpos int    The destination terminal cursor position.
41767c478bd9Sstevel@tonic-gate  * Output:
41777c478bd9Sstevel@tonic-gate  *  return      int    0 - OK.
41787c478bd9Sstevel@tonic-gate  *                     1 - Error.
41797c478bd9Sstevel@tonic-gate  */
gl_set_term_curpos(GetLine * gl,int term_curpos)41807c478bd9Sstevel@tonic-gate static int gl_set_term_curpos(GetLine *gl, int term_curpos)
41817c478bd9Sstevel@tonic-gate {
41827c478bd9Sstevel@tonic-gate   return gl_terminal_move_cursor(gl, term_curpos - gl->term_curpos);
41837c478bd9Sstevel@tonic-gate }
41847c478bd9Sstevel@tonic-gate 
41857c478bd9Sstevel@tonic-gate /*.......................................................................
41867c478bd9Sstevel@tonic-gate  * This is an action function that moves the buffer cursor one character
41877c478bd9Sstevel@tonic-gate  * left, and updates the terminal cursor to match.
41887c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_cursor_left)41897c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_cursor_left)
41907c478bd9Sstevel@tonic-gate {
41917c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos - count);
41927c478bd9Sstevel@tonic-gate }
41937c478bd9Sstevel@tonic-gate 
41947c478bd9Sstevel@tonic-gate /*.......................................................................
41957c478bd9Sstevel@tonic-gate  * This is an action function that moves the buffer cursor one character
41967c478bd9Sstevel@tonic-gate  * right, and updates the terminal cursor to match.
41977c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_cursor_right)41987c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_cursor_right)
41997c478bd9Sstevel@tonic-gate {
42007c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos + count);
42017c478bd9Sstevel@tonic-gate }
42027c478bd9Sstevel@tonic-gate 
42037c478bd9Sstevel@tonic-gate /*.......................................................................
42047c478bd9Sstevel@tonic-gate  * This is an action function that toggles between overwrite and insert
42057c478bd9Sstevel@tonic-gate  * mode.
42067c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_insert_mode)42077c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_insert_mode)
42087c478bd9Sstevel@tonic-gate {
42097c478bd9Sstevel@tonic-gate   gl->insert = !gl->insert;
42107c478bd9Sstevel@tonic-gate   return 0;
42117c478bd9Sstevel@tonic-gate }
42127c478bd9Sstevel@tonic-gate 
42137c478bd9Sstevel@tonic-gate /*.......................................................................
42147c478bd9Sstevel@tonic-gate  * This is an action function which moves the cursor to the beginning of
42157c478bd9Sstevel@tonic-gate  * the line.
42167c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_beginning_of_line)42177c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_beginning_of_line)
42187c478bd9Sstevel@tonic-gate {
42197c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, 0);
42207c478bd9Sstevel@tonic-gate }
42217c478bd9Sstevel@tonic-gate 
42227c478bd9Sstevel@tonic-gate /*.......................................................................
42237c478bd9Sstevel@tonic-gate  * This is an action function which moves the cursor to the end of
42247c478bd9Sstevel@tonic-gate  * the line.
42257c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_end_of_line)42267c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_end_of_line)
42277c478bd9Sstevel@tonic-gate {
42287c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->ntotal);
42297c478bd9Sstevel@tonic-gate }
42307c478bd9Sstevel@tonic-gate 
42317c478bd9Sstevel@tonic-gate /*.......................................................................
42327c478bd9Sstevel@tonic-gate  * This is an action function which deletes the entire contents of the
42337c478bd9Sstevel@tonic-gate  * current line.
42347c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_delete_line)42357c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_line)
42367c478bd9Sstevel@tonic-gate {
42377c478bd9Sstevel@tonic-gate /*
42387c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
42397c478bd9Sstevel@tonic-gate  * use by vi-undo.
42407c478bd9Sstevel@tonic-gate  */
42417c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
42427c478bd9Sstevel@tonic-gate /*
42437c478bd9Sstevel@tonic-gate  * Copy the contents of the line to the cut buffer.
42447c478bd9Sstevel@tonic-gate  */
42457c478bd9Sstevel@tonic-gate   strlcpy(gl->cutbuf, gl->line, gl->linelen);
42467c478bd9Sstevel@tonic-gate /*
42477c478bd9Sstevel@tonic-gate  * Clear the buffer.
42487c478bd9Sstevel@tonic-gate  */
42497c478bd9Sstevel@tonic-gate   gl_truncate_buffer(gl, 0);
42507c478bd9Sstevel@tonic-gate /*
42517c478bd9Sstevel@tonic-gate  * Move the terminal cursor to just after the prompt.
42527c478bd9Sstevel@tonic-gate  */
42537c478bd9Sstevel@tonic-gate   if(gl_place_cursor(gl, 0))
42547c478bd9Sstevel@tonic-gate     return 1;
42557c478bd9Sstevel@tonic-gate /*
42567c478bd9Sstevel@tonic-gate  * Clear from the end of the prompt to the end of the terminal.
42577c478bd9Sstevel@tonic-gate  */
42587c478bd9Sstevel@tonic-gate   if(gl_truncate_display(gl))
42597c478bd9Sstevel@tonic-gate     return 1;
42607c478bd9Sstevel@tonic-gate   return 0;
42617c478bd9Sstevel@tonic-gate }
42627c478bd9Sstevel@tonic-gate 
42637c478bd9Sstevel@tonic-gate /*.......................................................................
42647c478bd9Sstevel@tonic-gate  * This is an action function which deletes all characters between the
42657c478bd9Sstevel@tonic-gate  * current cursor position and the end of the line.
42667c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_kill_line)42677c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_kill_line)
42687c478bd9Sstevel@tonic-gate {
42697c478bd9Sstevel@tonic-gate /*
42707c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
42717c478bd9Sstevel@tonic-gate  * use by vi-undo.
42727c478bd9Sstevel@tonic-gate  */
42737c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
42747c478bd9Sstevel@tonic-gate /*
42757c478bd9Sstevel@tonic-gate  * Copy the part of the line that is about to be deleted to the cut buffer.
42767c478bd9Sstevel@tonic-gate  */
42777c478bd9Sstevel@tonic-gate   strlcpy(gl->cutbuf, gl->line + gl->buff_curpos, gl->linelen);
42787c478bd9Sstevel@tonic-gate /*
42797c478bd9Sstevel@tonic-gate  * Terminate the buffered line at the current cursor position.
42807c478bd9Sstevel@tonic-gate  */
42817c478bd9Sstevel@tonic-gate   gl_truncate_buffer(gl, gl->buff_curpos);
42827c478bd9Sstevel@tonic-gate /*
42837c478bd9Sstevel@tonic-gate  * Clear the part of the line that follows the cursor.
42847c478bd9Sstevel@tonic-gate  */
42857c478bd9Sstevel@tonic-gate   if(gl_truncate_display(gl))
42867c478bd9Sstevel@tonic-gate     return 1;
42877c478bd9Sstevel@tonic-gate /*
42887c478bd9Sstevel@tonic-gate  * Explicitly reset the cursor position to allow vi command mode
42897c478bd9Sstevel@tonic-gate  * constraints on its position to be set.
42907c478bd9Sstevel@tonic-gate  */
42917c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos);
42927c478bd9Sstevel@tonic-gate }
42937c478bd9Sstevel@tonic-gate 
42947c478bd9Sstevel@tonic-gate /*.......................................................................
42957c478bd9Sstevel@tonic-gate  * This is an action function which deletes all characters between the
42967c478bd9Sstevel@tonic-gate  * start of the line and the current cursor position.
42977c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_kill_line)42987c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_kill_line)
42997c478bd9Sstevel@tonic-gate {
43007c478bd9Sstevel@tonic-gate /*
43017c478bd9Sstevel@tonic-gate  * How many characters are to be deleted from before the cursor?
43027c478bd9Sstevel@tonic-gate  */
43037c478bd9Sstevel@tonic-gate   int nc = gl->buff_curpos - gl->insert_curpos;
43047c478bd9Sstevel@tonic-gate   if (!nc)
43057c478bd9Sstevel@tonic-gate     return 0;
43067c478bd9Sstevel@tonic-gate /*
43077c478bd9Sstevel@tonic-gate  * Move the cursor to the start of the line, or in vi input mode,
43087c478bd9Sstevel@tonic-gate  * the start of the sub-line at which insertion started, and delete
43097c478bd9Sstevel@tonic-gate  * up to the old cursor position.
43107c478bd9Sstevel@tonic-gate  */
43117c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->insert_curpos) ||
43127c478bd9Sstevel@tonic-gate          gl_delete_chars(gl, nc, gl->editor == GL_EMACS_MODE || gl->vi.command);
43137c478bd9Sstevel@tonic-gate }
43147c478bd9Sstevel@tonic-gate 
43157c478bd9Sstevel@tonic-gate /*.......................................................................
43167c478bd9Sstevel@tonic-gate  * This is an action function which moves the cursor forward by a word.
43177c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_word)43187c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_word)
43197c478bd9Sstevel@tonic-gate {
43207c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl_nth_word_end_forward(gl, count) +
43217c478bd9Sstevel@tonic-gate 			 (gl->editor==GL_EMACS_MODE));
43227c478bd9Sstevel@tonic-gate }
43237c478bd9Sstevel@tonic-gate 
43247c478bd9Sstevel@tonic-gate /*.......................................................................
43257c478bd9Sstevel@tonic-gate  * This is an action function which moves the cursor forward to the start
43267c478bd9Sstevel@tonic-gate  * of the next word.
43277c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_to_word)43287c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_to_word)
43297c478bd9Sstevel@tonic-gate {
43307c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl_nth_word_start_forward(gl, count));
43317c478bd9Sstevel@tonic-gate }
43327c478bd9Sstevel@tonic-gate 
43337c478bd9Sstevel@tonic-gate /*.......................................................................
43347c478bd9Sstevel@tonic-gate  * This is an action function which moves the cursor backward by a word.
43357c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_word)43367c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_word)
43377c478bd9Sstevel@tonic-gate {
43387c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl_nth_word_start_backward(gl, count));
43397c478bd9Sstevel@tonic-gate }
43407c478bd9Sstevel@tonic-gate 
43417c478bd9Sstevel@tonic-gate /*.......................................................................
43427c478bd9Sstevel@tonic-gate  * Delete one or more characters, starting with the one under the cursor.
43437c478bd9Sstevel@tonic-gate  *
43447c478bd9Sstevel@tonic-gate  * Input:
43457c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The resource object of this library.
43467c478bd9Sstevel@tonic-gate  *  nc         int    The number of characters to delete.
43477c478bd9Sstevel@tonic-gate  *  cut        int    If true, copy the characters to the cut buffer.
43487c478bd9Sstevel@tonic-gate  * Output:
43497c478bd9Sstevel@tonic-gate  *  return     int    0 - OK.
43507c478bd9Sstevel@tonic-gate  *                    1 - Error.
43517c478bd9Sstevel@tonic-gate  */
gl_delete_chars(GetLine * gl,int nc,int cut)43527c478bd9Sstevel@tonic-gate static int gl_delete_chars(GetLine *gl, int nc, int cut)
43537c478bd9Sstevel@tonic-gate {
43547c478bd9Sstevel@tonic-gate /*
43557c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
43567c478bd9Sstevel@tonic-gate  * use by vi-undo.
43577c478bd9Sstevel@tonic-gate  */
43587c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
43597c478bd9Sstevel@tonic-gate /*
43607c478bd9Sstevel@tonic-gate  * If there are fewer than nc characters following the cursor, limit
43617c478bd9Sstevel@tonic-gate  * nc to the number available.
43627c478bd9Sstevel@tonic-gate  */
43637c478bd9Sstevel@tonic-gate   if(gl->buff_curpos + nc > gl->ntotal)
43647c478bd9Sstevel@tonic-gate     nc = gl->ntotal - gl->buff_curpos;
43657c478bd9Sstevel@tonic-gate /*
43667c478bd9Sstevel@tonic-gate  * Copy the about to be deleted region to the cut buffer.
43677c478bd9Sstevel@tonic-gate  */
43687c478bd9Sstevel@tonic-gate   if(cut) {
43697c478bd9Sstevel@tonic-gate     memcpy(gl->cutbuf, gl->line + gl->buff_curpos, nc);
43707c478bd9Sstevel@tonic-gate     gl->cutbuf[nc] = '\0';
43717c478bd9Sstevel@tonic-gate   }
43727c478bd9Sstevel@tonic-gate /*
43737c478bd9Sstevel@tonic-gate  * Nothing to delete?
43747c478bd9Sstevel@tonic-gate  */
43757c478bd9Sstevel@tonic-gate   if(nc <= 0)
43767c478bd9Sstevel@tonic-gate     return 0;
43777c478bd9Sstevel@tonic-gate /*
43787c478bd9Sstevel@tonic-gate  * In vi overwrite mode, restore any previously overwritten characters
43797c478bd9Sstevel@tonic-gate  * from the undo buffer.
43807c478bd9Sstevel@tonic-gate  */
43817c478bd9Sstevel@tonic-gate   if(gl->editor == GL_VI_MODE && !gl->vi.command && !gl->insert) {
43827c478bd9Sstevel@tonic-gate /*
43837c478bd9Sstevel@tonic-gate  * How many of the characters being deleted can be restored from the
43847c478bd9Sstevel@tonic-gate  * undo buffer?
43857c478bd9Sstevel@tonic-gate  */
43867c478bd9Sstevel@tonic-gate     int nrestore = gl->buff_curpos + nc <= gl->vi.undo.ntotal ?
43877c478bd9Sstevel@tonic-gate       nc : gl->vi.undo.ntotal - gl->buff_curpos;
43887c478bd9Sstevel@tonic-gate /*
43897c478bd9Sstevel@tonic-gate  * Restore any available characters.
43907c478bd9Sstevel@tonic-gate  */
43917c478bd9Sstevel@tonic-gate     if(nrestore > 0) {
43927c478bd9Sstevel@tonic-gate       gl_buffer_string(gl, gl->vi.undo.line + gl->buff_curpos, nrestore,
43937c478bd9Sstevel@tonic-gate 		       gl->buff_curpos);
43947c478bd9Sstevel@tonic-gate     };
43957c478bd9Sstevel@tonic-gate /*
43967c478bd9Sstevel@tonic-gate  * If their were insufficient characters in the undo buffer, then this
43977c478bd9Sstevel@tonic-gate  * implies that we are deleting from the end of the line, so we need
43987c478bd9Sstevel@tonic-gate  * to terminate the line either where the undo buffer ran out, or if
43997c478bd9Sstevel@tonic-gate  * we are deleting from beyond the end of the undo buffer, at the current
44007c478bd9Sstevel@tonic-gate  * cursor position.
44017c478bd9Sstevel@tonic-gate  */
44027c478bd9Sstevel@tonic-gate     if(nc != nrestore) {
44037c478bd9Sstevel@tonic-gate       gl_truncate_buffer(gl, (gl->vi.undo.ntotal > gl->buff_curpos) ?
44047c478bd9Sstevel@tonic-gate 			 gl->vi.undo.ntotal : gl->buff_curpos);
44057c478bd9Sstevel@tonic-gate     };
44067c478bd9Sstevel@tonic-gate   } else {
44077c478bd9Sstevel@tonic-gate /*
44087c478bd9Sstevel@tonic-gate  * Copy the remaining part of the line back over the deleted characters.
44097c478bd9Sstevel@tonic-gate  */
44107c478bd9Sstevel@tonic-gate     gl_remove_from_buffer(gl, gl->buff_curpos, nc);
44117c478bd9Sstevel@tonic-gate   };
44127c478bd9Sstevel@tonic-gate /*
44137c478bd9Sstevel@tonic-gate  * Redraw the remaining characters following the cursor.
44147c478bd9Sstevel@tonic-gate  */
44157c478bd9Sstevel@tonic-gate   if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0'))
44167c478bd9Sstevel@tonic-gate     return 1;
44177c478bd9Sstevel@tonic-gate /*
44187c478bd9Sstevel@tonic-gate  * Clear to the end of the terminal.
44197c478bd9Sstevel@tonic-gate  */
44207c478bd9Sstevel@tonic-gate   if(gl_truncate_display(gl))
44217c478bd9Sstevel@tonic-gate     return 1;
44227c478bd9Sstevel@tonic-gate /*
44237c478bd9Sstevel@tonic-gate  * Place the cursor at the start of where the deletion was performed.
44247c478bd9Sstevel@tonic-gate  */
44257c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos);
44267c478bd9Sstevel@tonic-gate }
44277c478bd9Sstevel@tonic-gate 
44287c478bd9Sstevel@tonic-gate /*.......................................................................
44297c478bd9Sstevel@tonic-gate  * This is an action function which deletes character(s) under the
44307c478bd9Sstevel@tonic-gate  * cursor without moving the cursor.
44317c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_delete_char)44327c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_char)
44337c478bd9Sstevel@tonic-gate {
44347c478bd9Sstevel@tonic-gate /*
44357c478bd9Sstevel@tonic-gate  * Delete 'count' characters.
44367c478bd9Sstevel@tonic-gate  */
44377c478bd9Sstevel@tonic-gate   return gl_delete_chars(gl, count, gl->vi.command);
44387c478bd9Sstevel@tonic-gate }
44397c478bd9Sstevel@tonic-gate 
44407c478bd9Sstevel@tonic-gate /*.......................................................................
44417c478bd9Sstevel@tonic-gate  * This is an action function which deletes character(s) under the
44427c478bd9Sstevel@tonic-gate  * cursor and moves the cursor back one character.
44437c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_delete_char)44447c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_char)
44457c478bd9Sstevel@tonic-gate {
44467c478bd9Sstevel@tonic-gate /*
44477c478bd9Sstevel@tonic-gate  * Restrict the deletion count to the number of characters that
44487c478bd9Sstevel@tonic-gate  * precede the insertion point.
44497c478bd9Sstevel@tonic-gate  */
44507c478bd9Sstevel@tonic-gate   if(count > gl->buff_curpos - gl->insert_curpos)
44517c478bd9Sstevel@tonic-gate     count = gl->buff_curpos - gl->insert_curpos;
44527c478bd9Sstevel@tonic-gate /*
44537c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
44547c478bd9Sstevel@tonic-gate  * use by vi-undo.
44557c478bd9Sstevel@tonic-gate  */
44567c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
44577c478bd9Sstevel@tonic-gate   return gl_cursor_left(gl, count, NULL) ||
44587c478bd9Sstevel@tonic-gate     gl_delete_chars(gl, count, gl->vi.command);
44597c478bd9Sstevel@tonic-gate }
44607c478bd9Sstevel@tonic-gate 
44617c478bd9Sstevel@tonic-gate /*.......................................................................
44627c478bd9Sstevel@tonic-gate  * Starting from the cursor position delete to the specified column.
44637c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_delete_to_column)44647c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_to_column)
44657c478bd9Sstevel@tonic-gate {
44667c478bd9Sstevel@tonic-gate   if (--count >= gl->buff_curpos)
44677c478bd9Sstevel@tonic-gate     return gl_forward_delete_char(gl, count - gl->buff_curpos, NULL);
44687c478bd9Sstevel@tonic-gate   else
44697c478bd9Sstevel@tonic-gate     return gl_backward_delete_char(gl, gl->buff_curpos - count, NULL);
44707c478bd9Sstevel@tonic-gate }
44717c478bd9Sstevel@tonic-gate 
44727c478bd9Sstevel@tonic-gate /*.......................................................................
44737c478bd9Sstevel@tonic-gate  * Starting from the cursor position delete characters to a matching
44747c478bd9Sstevel@tonic-gate  * parenthesis.
44757c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_delete_to_parenthesis)44767c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_to_parenthesis)
44777c478bd9Sstevel@tonic-gate {
44787c478bd9Sstevel@tonic-gate   int curpos = gl_index_of_matching_paren(gl);
44797c478bd9Sstevel@tonic-gate   if(curpos >= 0) {
44807c478bd9Sstevel@tonic-gate     gl_save_for_undo(gl);
44817c478bd9Sstevel@tonic-gate     if(curpos >= gl->buff_curpos)
44827c478bd9Sstevel@tonic-gate       return gl_forward_delete_char(gl, curpos - gl->buff_curpos + 1, NULL);
44837c478bd9Sstevel@tonic-gate     else
44847c478bd9Sstevel@tonic-gate       return gl_backward_delete_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
44857c478bd9Sstevel@tonic-gate   };
44867c478bd9Sstevel@tonic-gate   return 0;
44877c478bd9Sstevel@tonic-gate }
44887c478bd9Sstevel@tonic-gate 
44897c478bd9Sstevel@tonic-gate /*.......................................................................
44907c478bd9Sstevel@tonic-gate  * This is an action function which deletes from the cursor to the end
44917c478bd9Sstevel@tonic-gate  * of the word that the cursor is either in or precedes.
44927c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_delete_word)44937c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_word)
44947c478bd9Sstevel@tonic-gate {
44957c478bd9Sstevel@tonic-gate /*
44967c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
44977c478bd9Sstevel@tonic-gate  * use by vi-undo.
44987c478bd9Sstevel@tonic-gate  */
44997c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
45007c478bd9Sstevel@tonic-gate /*
45017c478bd9Sstevel@tonic-gate  * In emacs mode delete to the end of the word. In vi mode delete to the
45027c478bd9Sstevel@tonic-gate  * start of the net word.
45037c478bd9Sstevel@tonic-gate  */
45047c478bd9Sstevel@tonic-gate   if(gl->editor == GL_EMACS_MODE) {
45057c478bd9Sstevel@tonic-gate     return gl_delete_chars(gl,
45067c478bd9Sstevel@tonic-gate 		gl_nth_word_end_forward(gl,count) - gl->buff_curpos + 1, 1);
45077c478bd9Sstevel@tonic-gate   } else {
45087c478bd9Sstevel@tonic-gate     return gl_delete_chars(gl,
45097c478bd9Sstevel@tonic-gate 		gl_nth_word_start_forward(gl,count) - gl->buff_curpos,
45107c478bd9Sstevel@tonic-gate 		gl->vi.command);
45117c478bd9Sstevel@tonic-gate   };
45127c478bd9Sstevel@tonic-gate }
45137c478bd9Sstevel@tonic-gate 
45147c478bd9Sstevel@tonic-gate /*.......................................................................
45157c478bd9Sstevel@tonic-gate  * This is an action function which deletes the word that precedes the
45167c478bd9Sstevel@tonic-gate  * cursor.
45177c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_delete_word)45187c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_word)
45197c478bd9Sstevel@tonic-gate {
45207c478bd9Sstevel@tonic-gate /*
45217c478bd9Sstevel@tonic-gate  * Keep a record of the current cursor position.
45227c478bd9Sstevel@tonic-gate  */
45237c478bd9Sstevel@tonic-gate   int buff_curpos = gl->buff_curpos;
45247c478bd9Sstevel@tonic-gate /*
45257c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
45267c478bd9Sstevel@tonic-gate  * use by vi-undo.
45277c478bd9Sstevel@tonic-gate  */
45287c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
45297c478bd9Sstevel@tonic-gate /*
45307c478bd9Sstevel@tonic-gate  * Move back 'count' words.
45317c478bd9Sstevel@tonic-gate  */
45327c478bd9Sstevel@tonic-gate   if(gl_backward_word(gl, count, NULL))
45337c478bd9Sstevel@tonic-gate     return 1;
45347c478bd9Sstevel@tonic-gate /*
45357c478bd9Sstevel@tonic-gate  * Delete from the new cursor position to the original one.
45367c478bd9Sstevel@tonic-gate  */
45377c478bd9Sstevel@tonic-gate   return gl_delete_chars(gl, buff_curpos - gl->buff_curpos,
45387c478bd9Sstevel@tonic-gate   			 gl->editor == GL_EMACS_MODE || gl->vi.command);
45397c478bd9Sstevel@tonic-gate }
45407c478bd9Sstevel@tonic-gate 
45417c478bd9Sstevel@tonic-gate /*.......................................................................
45427c478bd9Sstevel@tonic-gate  * Searching in a given direction, delete to the count'th
45437c478bd9Sstevel@tonic-gate  * instance of a specified or queried character, in the input line.
45447c478bd9Sstevel@tonic-gate  *
45457c478bd9Sstevel@tonic-gate  * Input:
45467c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
45477c478bd9Sstevel@tonic-gate  *  count        int    The number of times to search.
45487c478bd9Sstevel@tonic-gate  *  c           char    The character to be searched for, or '\0' if
45497c478bd9Sstevel@tonic-gate  *                      the character should be read from the user.
45507c478bd9Sstevel@tonic-gate  *  forward      int    True if searching forward.
45517c478bd9Sstevel@tonic-gate  *  onto         int    True if the search should end on top of the
45527c478bd9Sstevel@tonic-gate  *                      character, false if the search should stop
45537c478bd9Sstevel@tonic-gate  *                      one character before the character in the
45547c478bd9Sstevel@tonic-gate  *                      specified search direction.
45557c478bd9Sstevel@tonic-gate  *  change       int    If true, this function is being called upon
45567c478bd9Sstevel@tonic-gate  *                      to do a vi change command, in which case the
45577c478bd9Sstevel@tonic-gate  *                      user will be left in insert mode after the
45587c478bd9Sstevel@tonic-gate  *                      deletion.
45597c478bd9Sstevel@tonic-gate  * Output:
45607c478bd9Sstevel@tonic-gate  *  return       int    0 - OK.
45617c478bd9Sstevel@tonic-gate  *                      1 - Error.
45627c478bd9Sstevel@tonic-gate  */
gl_delete_find(GetLine * gl,int count,char c,int forward,int onto,int change)45637c478bd9Sstevel@tonic-gate static int gl_delete_find(GetLine *gl, int count, char c, int forward,
45647c478bd9Sstevel@tonic-gate 			  int onto, int change)
45657c478bd9Sstevel@tonic-gate {
45667c478bd9Sstevel@tonic-gate /*
45677c478bd9Sstevel@tonic-gate  * Search for the character, and abort the deletion if not found.
45687c478bd9Sstevel@tonic-gate  */
45697c478bd9Sstevel@tonic-gate   int pos = gl_find_char(gl, count, forward, onto, c);
45707c478bd9Sstevel@tonic-gate   if(pos < 0)
45717c478bd9Sstevel@tonic-gate     return 0;
45727c478bd9Sstevel@tonic-gate /*
45737c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
45747c478bd9Sstevel@tonic-gate  * use by vi-undo.
45757c478bd9Sstevel@tonic-gate  */
45767c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
45777c478bd9Sstevel@tonic-gate /*
45787c478bd9Sstevel@tonic-gate  * Allow the cursor to be at the end of the line if this is a change
45797c478bd9Sstevel@tonic-gate  * command.
45807c478bd9Sstevel@tonic-gate  */
45817c478bd9Sstevel@tonic-gate   if(change)
45827c478bd9Sstevel@tonic-gate     gl->vi.command = 0;
45837c478bd9Sstevel@tonic-gate /*
45847c478bd9Sstevel@tonic-gate  * Delete the appropriate span of characters.
45857c478bd9Sstevel@tonic-gate  */
45867c478bd9Sstevel@tonic-gate   if(forward) {
45877c478bd9Sstevel@tonic-gate     if(gl_delete_chars(gl, pos - gl->buff_curpos + 1, 1))
45887c478bd9Sstevel@tonic-gate       return 1;
45897c478bd9Sstevel@tonic-gate   } else {
45907c478bd9Sstevel@tonic-gate     int buff_curpos = gl->buff_curpos;
45917c478bd9Sstevel@tonic-gate     if(gl_place_cursor(gl, pos) ||
45927c478bd9Sstevel@tonic-gate        gl_delete_chars(gl, buff_curpos - gl->buff_curpos, 1))
45937c478bd9Sstevel@tonic-gate       return 1;
45947c478bd9Sstevel@tonic-gate   };
45957c478bd9Sstevel@tonic-gate /*
45967c478bd9Sstevel@tonic-gate  * If this is a change operation, switch the insert mode.
45977c478bd9Sstevel@tonic-gate  */
45987c478bd9Sstevel@tonic-gate   if(change && gl_vi_insert(gl, 0, NULL))
45997c478bd9Sstevel@tonic-gate     return 1;
46007c478bd9Sstevel@tonic-gate   return 0;
46017c478bd9Sstevel@tonic-gate }
46027c478bd9Sstevel@tonic-gate 
46037c478bd9Sstevel@tonic-gate /*.......................................................................
46047c478bd9Sstevel@tonic-gate  * This is an action function which deletes forward from the cursor up to and
46057c478bd9Sstevel@tonic-gate  * including a specified character.
46067c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_delete_find)46077c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_find)
46087c478bd9Sstevel@tonic-gate {
46097c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, '\0', 1, 1, 0);
46107c478bd9Sstevel@tonic-gate }
46117c478bd9Sstevel@tonic-gate 
46127c478bd9Sstevel@tonic-gate /*.......................................................................
46137c478bd9Sstevel@tonic-gate  * This is an action function which deletes backward from the cursor back to
46147c478bd9Sstevel@tonic-gate  * and including a specified character.
46157c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_delete_find)46167c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_find)
46177c478bd9Sstevel@tonic-gate {
46187c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, '\0', 0, 1, 0);
46197c478bd9Sstevel@tonic-gate }
46207c478bd9Sstevel@tonic-gate 
46217c478bd9Sstevel@tonic-gate /*.......................................................................
46227c478bd9Sstevel@tonic-gate  * This is an action function which deletes forward from the cursor up to but
46237c478bd9Sstevel@tonic-gate  * not including a specified character.
46247c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_delete_to)46257c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_to)
46267c478bd9Sstevel@tonic-gate {
46277c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, '\0', 1, 0, 0);
46287c478bd9Sstevel@tonic-gate }
46297c478bd9Sstevel@tonic-gate 
46307c478bd9Sstevel@tonic-gate /*.......................................................................
46317c478bd9Sstevel@tonic-gate  * This is an action function which deletes backward from the cursor back to
46327c478bd9Sstevel@tonic-gate  * but not including a specified character.
46337c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_delete_to)46347c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_to)
46357c478bd9Sstevel@tonic-gate {
46367c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, '\0', 0, 0, 0);
46377c478bd9Sstevel@tonic-gate }
46387c478bd9Sstevel@tonic-gate 
46397c478bd9Sstevel@tonic-gate /*.......................................................................
46407c478bd9Sstevel@tonic-gate  * This is an action function which deletes to a character specified by a
46417c478bd9Sstevel@tonic-gate  * previous search.
46427c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_delete_refind)46437c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_refind)
46447c478bd9Sstevel@tonic-gate {
46457c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
46467c478bd9Sstevel@tonic-gate 			gl->vi.find_onto, 0);
46477c478bd9Sstevel@tonic-gate }
46487c478bd9Sstevel@tonic-gate 
46497c478bd9Sstevel@tonic-gate /*.......................................................................
46507c478bd9Sstevel@tonic-gate  * This is an action function which deletes to a character specified by a
46517c478bd9Sstevel@tonic-gate  * previous search, but in the opposite direction.
46527c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_delete_invert_refind)46537c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_invert_refind)
46547c478bd9Sstevel@tonic-gate {
46557c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, gl->vi.find_char,
46567c478bd9Sstevel@tonic-gate 			!gl->vi.find_forward, gl->vi.find_onto, 0);
46577c478bd9Sstevel@tonic-gate }
46587c478bd9Sstevel@tonic-gate 
46597c478bd9Sstevel@tonic-gate /*.......................................................................
46607c478bd9Sstevel@tonic-gate  * This is an action function which converts the characters in the word
46617c478bd9Sstevel@tonic-gate  * following the cursor to upper case.
46627c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_upcase_word)46637c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_upcase_word)
46647c478bd9Sstevel@tonic-gate {
46657c478bd9Sstevel@tonic-gate /*
46667c478bd9Sstevel@tonic-gate  * Locate the count'th word ending after the cursor.
46677c478bd9Sstevel@tonic-gate  */
46687c478bd9Sstevel@tonic-gate   int last = gl_nth_word_end_forward(gl, count);
46697c478bd9Sstevel@tonic-gate /*
46707c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
46717c478bd9Sstevel@tonic-gate  * use by vi-undo.
46727c478bd9Sstevel@tonic-gate  */
46737c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
46747c478bd9Sstevel@tonic-gate /*
46757c478bd9Sstevel@tonic-gate  * Upcase characters from the current cursor position to 'last'.
46767c478bd9Sstevel@tonic-gate  */
46777c478bd9Sstevel@tonic-gate   while(gl->buff_curpos <= last) {
46787c478bd9Sstevel@tonic-gate     char *cptr = gl->line + gl->buff_curpos;
46797c478bd9Sstevel@tonic-gate /*
46807c478bd9Sstevel@tonic-gate  * Convert the character to upper case?
46817c478bd9Sstevel@tonic-gate  */
46827c478bd9Sstevel@tonic-gate     if(islower((int)(unsigned char) *cptr))
46837c478bd9Sstevel@tonic-gate       gl_buffer_char(gl, toupper((int) *cptr), gl->buff_curpos);
46847c478bd9Sstevel@tonic-gate     gl->buff_curpos++;
46857c478bd9Sstevel@tonic-gate /*
46867c478bd9Sstevel@tonic-gate  * Write the possibly modified character back. Note that for non-modified
46877c478bd9Sstevel@tonic-gate  * characters we want to do this as well, so as to advance the cursor.
46887c478bd9Sstevel@tonic-gate  */
46897c478bd9Sstevel@tonic-gate     if(gl_print_char(gl, *cptr, cptr[1]))
46907c478bd9Sstevel@tonic-gate       return 1;
46917c478bd9Sstevel@tonic-gate   };
46927c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos);	/* bounds check */
46937c478bd9Sstevel@tonic-gate }
46947c478bd9Sstevel@tonic-gate 
46957c478bd9Sstevel@tonic-gate /*.......................................................................
46967c478bd9Sstevel@tonic-gate  * This is an action function which converts the characters in the word
46977c478bd9Sstevel@tonic-gate  * following the cursor to lower case.
46987c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_downcase_word)46997c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_downcase_word)
47007c478bd9Sstevel@tonic-gate {
47017c478bd9Sstevel@tonic-gate /*
47027c478bd9Sstevel@tonic-gate  * Locate the count'th word ending after the cursor.
47037c478bd9Sstevel@tonic-gate  */
47047c478bd9Sstevel@tonic-gate   int last = gl_nth_word_end_forward(gl, count);
47057c478bd9Sstevel@tonic-gate /*
47067c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
47077c478bd9Sstevel@tonic-gate  * use by vi-undo.
47087c478bd9Sstevel@tonic-gate  */
47097c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
47107c478bd9Sstevel@tonic-gate /*
47117c478bd9Sstevel@tonic-gate  * Upcase characters from the current cursor position to 'last'.
47127c478bd9Sstevel@tonic-gate  */
47137c478bd9Sstevel@tonic-gate   while(gl->buff_curpos <= last) {
47147c478bd9Sstevel@tonic-gate     char *cptr = gl->line + gl->buff_curpos;
47157c478bd9Sstevel@tonic-gate /*
47167c478bd9Sstevel@tonic-gate  * Convert the character to upper case?
47177c478bd9Sstevel@tonic-gate  */
47187c478bd9Sstevel@tonic-gate     if(isupper((int)(unsigned char) *cptr))
47197c478bd9Sstevel@tonic-gate       gl_buffer_char(gl, tolower((int) *cptr), gl->buff_curpos);
47207c478bd9Sstevel@tonic-gate     gl->buff_curpos++;
47217c478bd9Sstevel@tonic-gate /*
47227c478bd9Sstevel@tonic-gate  * Write the possibly modified character back. Note that for non-modified
47237c478bd9Sstevel@tonic-gate  * characters we want to do this as well, so as to advance the cursor.
47247c478bd9Sstevel@tonic-gate  */
47257c478bd9Sstevel@tonic-gate     if(gl_print_char(gl, *cptr, cptr[1]))
47267c478bd9Sstevel@tonic-gate       return 1;
47277c478bd9Sstevel@tonic-gate   };
47287c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos);	/* bounds check */
47297c478bd9Sstevel@tonic-gate }
47307c478bd9Sstevel@tonic-gate 
47317c478bd9Sstevel@tonic-gate /*.......................................................................
47327c478bd9Sstevel@tonic-gate  * This is an action function which converts the first character of the
47337c478bd9Sstevel@tonic-gate  * following word to upper case, in order to capitalize the word, and
47347c478bd9Sstevel@tonic-gate  * leaves the cursor at the end of the word.
47357c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_capitalize_word)47367c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_capitalize_word)
47377c478bd9Sstevel@tonic-gate {
47387c478bd9Sstevel@tonic-gate   char *cptr;   /* &gl->line[gl->buff_curpos] */
47397c478bd9Sstevel@tonic-gate   int first;    /* True for the first letter of the word */
47407c478bd9Sstevel@tonic-gate   int i;
47417c478bd9Sstevel@tonic-gate /*
47427c478bd9Sstevel@tonic-gate  * Keep a record of the current insert mode and the cursor position.
47437c478bd9Sstevel@tonic-gate  */
47447c478bd9Sstevel@tonic-gate   int insert = gl->insert;
47457c478bd9Sstevel@tonic-gate /*
47467c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
47477c478bd9Sstevel@tonic-gate  * use by vi-undo.
47487c478bd9Sstevel@tonic-gate  */
47497c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
47507c478bd9Sstevel@tonic-gate /*
47517c478bd9Sstevel@tonic-gate  * We want to overwrite the modified word.
47527c478bd9Sstevel@tonic-gate  */
47537c478bd9Sstevel@tonic-gate   gl->insert = 0;
47547c478bd9Sstevel@tonic-gate /*
47557c478bd9Sstevel@tonic-gate  * Capitalize 'count' words.
47567c478bd9Sstevel@tonic-gate  */
47577c478bd9Sstevel@tonic-gate   for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) {
47587c478bd9Sstevel@tonic-gate     int pos = gl->buff_curpos;
47597c478bd9Sstevel@tonic-gate /*
47607c478bd9Sstevel@tonic-gate  * If we are not already within a word, skip to the start of the word.
47617c478bd9Sstevel@tonic-gate  */
47627c478bd9Sstevel@tonic-gate     for(cptr = gl->line + pos ; pos<gl->ntotal && !gl_is_word_char((int) *cptr);
47637c478bd9Sstevel@tonic-gate 	pos++, cptr++)
47647c478bd9Sstevel@tonic-gate       ;
47657c478bd9Sstevel@tonic-gate /*
47667c478bd9Sstevel@tonic-gate  * Move the cursor to the new position.
47677c478bd9Sstevel@tonic-gate  */
47687c478bd9Sstevel@tonic-gate     if(gl_place_cursor(gl, pos))
47697c478bd9Sstevel@tonic-gate       return 1;
47707c478bd9Sstevel@tonic-gate /*
47717c478bd9Sstevel@tonic-gate  * While searching for the end of the word, change lower case letters
47727c478bd9Sstevel@tonic-gate  * to upper case.
47737c478bd9Sstevel@tonic-gate  */
47747c478bd9Sstevel@tonic-gate     for(first=1; gl->buff_curpos<gl->ntotal && gl_is_word_char((int) *cptr);
47757c478bd9Sstevel@tonic-gate 	gl->buff_curpos++, cptr++) {
47767c478bd9Sstevel@tonic-gate /*
47777c478bd9Sstevel@tonic-gate  * Convert the character to upper case?
47787c478bd9Sstevel@tonic-gate  */
47797c478bd9Sstevel@tonic-gate       if(first) {
47807c478bd9Sstevel@tonic-gate 	if(islower((int)(unsigned char) *cptr))
47817c478bd9Sstevel@tonic-gate 	  gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
47827c478bd9Sstevel@tonic-gate       } else {
47837c478bd9Sstevel@tonic-gate 	if(isupper((int)(unsigned char) *cptr))
47847c478bd9Sstevel@tonic-gate 	  gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
47857c478bd9Sstevel@tonic-gate       };
47867c478bd9Sstevel@tonic-gate       first = 0;
47877c478bd9Sstevel@tonic-gate /*
47887c478bd9Sstevel@tonic-gate  * Write the possibly modified character back. Note that for non-modified
47897c478bd9Sstevel@tonic-gate  * characters we want to do this as well, so as to advance the cursor.
47907c478bd9Sstevel@tonic-gate  */
47917c478bd9Sstevel@tonic-gate       if(gl_print_char(gl, *cptr, cptr[1]))
47927c478bd9Sstevel@tonic-gate 	return 1;
47937c478bd9Sstevel@tonic-gate     };
47947c478bd9Sstevel@tonic-gate   };
47957c478bd9Sstevel@tonic-gate /*
47967c478bd9Sstevel@tonic-gate  * Restore the insertion mode.
47977c478bd9Sstevel@tonic-gate  */
47987c478bd9Sstevel@tonic-gate   gl->insert = insert;
47997c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos);	/* bounds check */
48007c478bd9Sstevel@tonic-gate }
48017c478bd9Sstevel@tonic-gate 
48027c478bd9Sstevel@tonic-gate /*.......................................................................
48037c478bd9Sstevel@tonic-gate  * This is an action function which redraws the current line.
48047c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_redisplay)48057c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_redisplay)
48067c478bd9Sstevel@tonic-gate {
48077c478bd9Sstevel@tonic-gate /*
48087c478bd9Sstevel@tonic-gate  * Keep a record of the current cursor position.
48097c478bd9Sstevel@tonic-gate  */
48107c478bd9Sstevel@tonic-gate   int buff_curpos = gl->buff_curpos;
48117c478bd9Sstevel@tonic-gate /*
48127c478bd9Sstevel@tonic-gate  * Do nothing if there is no line to be redisplayed.
48137c478bd9Sstevel@tonic-gate  */
48147c478bd9Sstevel@tonic-gate   if(gl->endline)
48157c478bd9Sstevel@tonic-gate     return 0;
48167c478bd9Sstevel@tonic-gate /*
48177c478bd9Sstevel@tonic-gate  * Erase the current input line.
48187c478bd9Sstevel@tonic-gate  */
48197c478bd9Sstevel@tonic-gate   if(gl_erase_line(gl))
48207c478bd9Sstevel@tonic-gate     return 1;
48217c478bd9Sstevel@tonic-gate /*
48227c478bd9Sstevel@tonic-gate  * Display the current prompt.
48237c478bd9Sstevel@tonic-gate  */
48247c478bd9Sstevel@tonic-gate   if(gl_display_prompt(gl))
48257c478bd9Sstevel@tonic-gate     return 1;
48267c478bd9Sstevel@tonic-gate /*
48277c478bd9Sstevel@tonic-gate  * Render the part of the line that the user has typed in so far.
48287c478bd9Sstevel@tonic-gate  */
48297c478bd9Sstevel@tonic-gate   if(gl_print_string(gl, gl->line, '\0'))
48307c478bd9Sstevel@tonic-gate     return 1;
48317c478bd9Sstevel@tonic-gate /*
48327c478bd9Sstevel@tonic-gate  * Restore the cursor position.
48337c478bd9Sstevel@tonic-gate  */
48347c478bd9Sstevel@tonic-gate   if(gl_place_cursor(gl, buff_curpos))
48357c478bd9Sstevel@tonic-gate     return 1;
48367c478bd9Sstevel@tonic-gate /*
48377c478bd9Sstevel@tonic-gate  * Mark the redisplay operation as having been completed.
48387c478bd9Sstevel@tonic-gate  */
48397c478bd9Sstevel@tonic-gate   gl->redisplay = 0;
48407c478bd9Sstevel@tonic-gate /*
48417c478bd9Sstevel@tonic-gate  * Flush the redisplayed line to the terminal.
48427c478bd9Sstevel@tonic-gate  */
48437c478bd9Sstevel@tonic-gate   return gl_flush_output(gl);
48447c478bd9Sstevel@tonic-gate }
48457c478bd9Sstevel@tonic-gate 
48467c478bd9Sstevel@tonic-gate /*.......................................................................
48477c478bd9Sstevel@tonic-gate  * This is an action function which clears the display and redraws the
48487c478bd9Sstevel@tonic-gate  * input line from the home position.
48497c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_clear_screen)48507c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_clear_screen)
48517c478bd9Sstevel@tonic-gate {
48527c478bd9Sstevel@tonic-gate /*
48537c478bd9Sstevel@tonic-gate  * Home the cursor and clear from there to the end of the display.
48547c478bd9Sstevel@tonic-gate  */
48557c478bd9Sstevel@tonic-gate   if(gl_print_control_sequence(gl, gl->nline, gl->home) ||
48567c478bd9Sstevel@tonic-gate      gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
48577c478bd9Sstevel@tonic-gate     return 1;
48587c478bd9Sstevel@tonic-gate /*
48597c478bd9Sstevel@tonic-gate  * The input line is no longer displayed.
48607c478bd9Sstevel@tonic-gate  */
48617c478bd9Sstevel@tonic-gate   gl_line_erased(gl);
48627c478bd9Sstevel@tonic-gate /*
48637c478bd9Sstevel@tonic-gate  * Arrange for the input line to be redisplayed.
48647c478bd9Sstevel@tonic-gate  */
48657c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
48667c478bd9Sstevel@tonic-gate   return 0;
48677c478bd9Sstevel@tonic-gate }
48687c478bd9Sstevel@tonic-gate 
48697c478bd9Sstevel@tonic-gate /*.......................................................................
48707c478bd9Sstevel@tonic-gate  * This is an action function which swaps the character under the cursor
48717c478bd9Sstevel@tonic-gate  * with the character to the left of the cursor.
48727c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_transpose_chars)48737c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_transpose_chars)
48747c478bd9Sstevel@tonic-gate {
48757c478bd9Sstevel@tonic-gate   char from[3];     /* The original string of 2 characters */
48767c478bd9Sstevel@tonic-gate   char swap[3];     /* The swapped string of two characters */
48777c478bd9Sstevel@tonic-gate /*
48787c478bd9Sstevel@tonic-gate  * If we are at the beginning or end of the line, there aren't two
48797c478bd9Sstevel@tonic-gate  * characters to swap.
48807c478bd9Sstevel@tonic-gate  */
48817c478bd9Sstevel@tonic-gate   if(gl->buff_curpos < 1 || gl->buff_curpos >= gl->ntotal)
48827c478bd9Sstevel@tonic-gate     return 0;
48837c478bd9Sstevel@tonic-gate /*
48847c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
48857c478bd9Sstevel@tonic-gate  * use by vi-undo.
48867c478bd9Sstevel@tonic-gate  */
48877c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
48887c478bd9Sstevel@tonic-gate /*
48897c478bd9Sstevel@tonic-gate  * Get the original and swapped strings of the two characters.
48907c478bd9Sstevel@tonic-gate  */
48917c478bd9Sstevel@tonic-gate   from[0] = gl->line[gl->buff_curpos - 1];
48927c478bd9Sstevel@tonic-gate   from[1] = gl->line[gl->buff_curpos];
48937c478bd9Sstevel@tonic-gate   from[2] = '\0';
48947c478bd9Sstevel@tonic-gate   swap[0] = gl->line[gl->buff_curpos];
48957c478bd9Sstevel@tonic-gate   swap[1] = gl->line[gl->buff_curpos - 1];
48967c478bd9Sstevel@tonic-gate   swap[2] = '\0';
48977c478bd9Sstevel@tonic-gate /*
48987c478bd9Sstevel@tonic-gate  * Move the cursor to the start of the two characters.
48997c478bd9Sstevel@tonic-gate  */
49007c478bd9Sstevel@tonic-gate   if(gl_place_cursor(gl, gl->buff_curpos-1))
49017c478bd9Sstevel@tonic-gate     return 1;
49027c478bd9Sstevel@tonic-gate /*
49037c478bd9Sstevel@tonic-gate  * Swap the two characters in the buffer.
49047c478bd9Sstevel@tonic-gate  */
49057c478bd9Sstevel@tonic-gate   gl_buffer_char(gl, swap[0], gl->buff_curpos);
49067c478bd9Sstevel@tonic-gate   gl_buffer_char(gl, swap[1], gl->buff_curpos+1);
49077c478bd9Sstevel@tonic-gate /*
49087c478bd9Sstevel@tonic-gate  * If the sum of the displayed width of the two characters
49097c478bd9Sstevel@tonic-gate  * in their current and final positions is the same, swapping can
49107c478bd9Sstevel@tonic-gate  * be done by just overwriting with the two swapped characters.
49117c478bd9Sstevel@tonic-gate  */
49127c478bd9Sstevel@tonic-gate   if(gl_displayed_string_width(gl, from, -1, gl->term_curpos) ==
49137c478bd9Sstevel@tonic-gate      gl_displayed_string_width(gl, swap, -1, gl->term_curpos)) {
49147c478bd9Sstevel@tonic-gate     int insert = gl->insert;
49157c478bd9Sstevel@tonic-gate     gl->insert = 0;
49167c478bd9Sstevel@tonic-gate     if(gl_print_char(gl, swap[0], swap[1]) ||
49177c478bd9Sstevel@tonic-gate        gl_print_char(gl, swap[1], gl->line[gl->buff_curpos+2]))
49187c478bd9Sstevel@tonic-gate       return 1;
49197c478bd9Sstevel@tonic-gate     gl->insert = insert;
49207c478bd9Sstevel@tonic-gate /*
49217c478bd9Sstevel@tonic-gate  * If the swapped substring has a different displayed size, we need to
49227c478bd9Sstevel@tonic-gate  * redraw everything after the first of the characters.
49237c478bd9Sstevel@tonic-gate  */
49247c478bd9Sstevel@tonic-gate   } else {
49257c478bd9Sstevel@tonic-gate     if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0') ||
49267c478bd9Sstevel@tonic-gate        gl_truncate_display(gl))
49277c478bd9Sstevel@tonic-gate       return 1;
49287c478bd9Sstevel@tonic-gate   };
49297c478bd9Sstevel@tonic-gate /*
49307c478bd9Sstevel@tonic-gate  * Advance the cursor to the character after the swapped pair.
49317c478bd9Sstevel@tonic-gate  */
49327c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos + 2);
49337c478bd9Sstevel@tonic-gate }
49347c478bd9Sstevel@tonic-gate 
49357c478bd9Sstevel@tonic-gate /*.......................................................................
49367c478bd9Sstevel@tonic-gate  * This is an action function which sets a mark at the current cursor
49377c478bd9Sstevel@tonic-gate  * location.
49387c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_set_mark)49397c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_set_mark)
49407c478bd9Sstevel@tonic-gate {
49417c478bd9Sstevel@tonic-gate   gl->buff_mark = gl->buff_curpos;
49427c478bd9Sstevel@tonic-gate   return 0;
49437c478bd9Sstevel@tonic-gate }
49447c478bd9Sstevel@tonic-gate 
49457c478bd9Sstevel@tonic-gate /*.......................................................................
49467c478bd9Sstevel@tonic-gate  * This is an action function which swaps the mark location for the
49477c478bd9Sstevel@tonic-gate  * cursor location.
49487c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_exchange_point_and_mark)49497c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_exchange_point_and_mark)
49507c478bd9Sstevel@tonic-gate {
49517c478bd9Sstevel@tonic-gate /*
49527c478bd9Sstevel@tonic-gate  * Get the old mark position, and limit to the extent of the input
49537c478bd9Sstevel@tonic-gate  * line.
49547c478bd9Sstevel@tonic-gate  */
49557c478bd9Sstevel@tonic-gate   int old_mark = gl->buff_mark <= gl->ntotal ? gl->buff_mark : gl->ntotal;
49567c478bd9Sstevel@tonic-gate /*
49577c478bd9Sstevel@tonic-gate  * Make the current cursor position the new mark.
49587c478bd9Sstevel@tonic-gate  */
49597c478bd9Sstevel@tonic-gate   gl->buff_mark = gl->buff_curpos;
49607c478bd9Sstevel@tonic-gate /*
49617c478bd9Sstevel@tonic-gate  * Move the cursor to the old mark position.
49627c478bd9Sstevel@tonic-gate  */
49637c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, old_mark);
49647c478bd9Sstevel@tonic-gate }
49657c478bd9Sstevel@tonic-gate 
49667c478bd9Sstevel@tonic-gate /*.......................................................................
49677c478bd9Sstevel@tonic-gate  * This is an action function which deletes the characters between the
49687c478bd9Sstevel@tonic-gate  * mark and the cursor, recording them in gl->cutbuf for later pasting.
49697c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_kill_region)49707c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_kill_region)
49717c478bd9Sstevel@tonic-gate {
49727c478bd9Sstevel@tonic-gate /*
49737c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
49747c478bd9Sstevel@tonic-gate  * use by vi-undo.
49757c478bd9Sstevel@tonic-gate  */
49767c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
49777c478bd9Sstevel@tonic-gate /*
49787c478bd9Sstevel@tonic-gate  * Limit the mark to be within the line.
49797c478bd9Sstevel@tonic-gate  */
49807c478bd9Sstevel@tonic-gate   if(gl->buff_mark > gl->ntotal)
49817c478bd9Sstevel@tonic-gate     gl->buff_mark = gl->ntotal;
49827c478bd9Sstevel@tonic-gate /*
49837c478bd9Sstevel@tonic-gate  * If there are no characters between the cursor and the mark, simply clear
49847c478bd9Sstevel@tonic-gate  * the cut buffer.
49857c478bd9Sstevel@tonic-gate  */
49867c478bd9Sstevel@tonic-gate   if(gl->buff_mark == gl->buff_curpos) {
49877c478bd9Sstevel@tonic-gate     gl->cutbuf[0] = '\0';
49887c478bd9Sstevel@tonic-gate     return 0;
49897c478bd9Sstevel@tonic-gate   };
49907c478bd9Sstevel@tonic-gate /*
49917c478bd9Sstevel@tonic-gate  * If the mark is before the cursor, swap the cursor and the mark.
49927c478bd9Sstevel@tonic-gate  */
49937c478bd9Sstevel@tonic-gate   if(gl->buff_mark < gl->buff_curpos && gl_exchange_point_and_mark(gl,1,NULL))
49947c478bd9Sstevel@tonic-gate     return 1;
49957c478bd9Sstevel@tonic-gate /*
49967c478bd9Sstevel@tonic-gate  * Delete the characters.
49977c478bd9Sstevel@tonic-gate  */
49987c478bd9Sstevel@tonic-gate   if(gl_delete_chars(gl, gl->buff_mark - gl->buff_curpos, 1))
49997c478bd9Sstevel@tonic-gate     return 1;
50007c478bd9Sstevel@tonic-gate /*
50017c478bd9Sstevel@tonic-gate  * Make the mark the same as the cursor position.
50027c478bd9Sstevel@tonic-gate  */
50037c478bd9Sstevel@tonic-gate   gl->buff_mark = gl->buff_curpos;
50047c478bd9Sstevel@tonic-gate   return 0;
50057c478bd9Sstevel@tonic-gate }
50067c478bd9Sstevel@tonic-gate 
50077c478bd9Sstevel@tonic-gate /*.......................................................................
50087c478bd9Sstevel@tonic-gate  * This is an action function which records the characters between the
50097c478bd9Sstevel@tonic-gate  * mark and the cursor, in gl->cutbuf for later pasting.
50107c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_copy_region_as_kill)50117c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_region_as_kill)
50127c478bd9Sstevel@tonic-gate {
50137c478bd9Sstevel@tonic-gate   int ca, cb;  /* The indexes of the first and last characters in the region */
50147c478bd9Sstevel@tonic-gate   int mark;    /* The position of the mark */
50157c478bd9Sstevel@tonic-gate /*
50167c478bd9Sstevel@tonic-gate  * Get the position of the mark, limiting it to lie within the line.
50177c478bd9Sstevel@tonic-gate  */
50187c478bd9Sstevel@tonic-gate   mark = gl->buff_mark > gl->ntotal ? gl->ntotal : gl->buff_mark;
50197c478bd9Sstevel@tonic-gate /*
50207c478bd9Sstevel@tonic-gate  * If there are no characters between the cursor and the mark, clear
50217c478bd9Sstevel@tonic-gate  * the cut buffer.
50227c478bd9Sstevel@tonic-gate  */
50237c478bd9Sstevel@tonic-gate   if(mark == gl->buff_curpos) {
50247c478bd9Sstevel@tonic-gate     gl->cutbuf[0] = '\0';
50257c478bd9Sstevel@tonic-gate     return 0;
50267c478bd9Sstevel@tonic-gate   };
50277c478bd9Sstevel@tonic-gate /*
50287c478bd9Sstevel@tonic-gate  * Get the line indexes of the first and last characters in the region.
50297c478bd9Sstevel@tonic-gate  */
50307c478bd9Sstevel@tonic-gate   if(mark < gl->buff_curpos) {
50317c478bd9Sstevel@tonic-gate     ca = mark;
50327c478bd9Sstevel@tonic-gate     cb = gl->buff_curpos - 1;
50337c478bd9Sstevel@tonic-gate   } else {
50347c478bd9Sstevel@tonic-gate     ca = gl->buff_curpos;
50357c478bd9Sstevel@tonic-gate     cb = mark - 1;
50367c478bd9Sstevel@tonic-gate   };
50377c478bd9Sstevel@tonic-gate /*
50387c478bd9Sstevel@tonic-gate  * Copy the region to the cut buffer.
50397c478bd9Sstevel@tonic-gate  */
50407c478bd9Sstevel@tonic-gate   memcpy(gl->cutbuf, gl->line + ca, cb + 1 - ca);
50417c478bd9Sstevel@tonic-gate   gl->cutbuf[cb + 1 - ca] = '\0';
50427c478bd9Sstevel@tonic-gate   return 0;
50437c478bd9Sstevel@tonic-gate }
50447c478bd9Sstevel@tonic-gate 
50457c478bd9Sstevel@tonic-gate /*.......................................................................
50467c478bd9Sstevel@tonic-gate  * This is an action function which inserts the contents of the cut
50477c478bd9Sstevel@tonic-gate  * buffer at the current cursor location.
50487c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_yank)50497c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_yank)
50507c478bd9Sstevel@tonic-gate {
50517c478bd9Sstevel@tonic-gate   int i;
50527c478bd9Sstevel@tonic-gate /*
50537c478bd9Sstevel@tonic-gate  * Set the mark at the current location.
50547c478bd9Sstevel@tonic-gate  */
50557c478bd9Sstevel@tonic-gate   gl->buff_mark = gl->buff_curpos;
50567c478bd9Sstevel@tonic-gate /*
50577c478bd9Sstevel@tonic-gate  * Do nothing else if the cut buffer is empty.
50587c478bd9Sstevel@tonic-gate  */
50597c478bd9Sstevel@tonic-gate   if(gl->cutbuf[0] == '\0')
50607c478bd9Sstevel@tonic-gate     return gl_ring_bell(gl, 1, NULL);
50617c478bd9Sstevel@tonic-gate /*
50627c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
50637c478bd9Sstevel@tonic-gate  * use by vi-undo.
50647c478bd9Sstevel@tonic-gate  */
50657c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
50667c478bd9Sstevel@tonic-gate /*
50677c478bd9Sstevel@tonic-gate  * Insert the string count times.
50687c478bd9Sstevel@tonic-gate  */
50697c478bd9Sstevel@tonic-gate   for(i=0; i<count; i++) {
50707c478bd9Sstevel@tonic-gate     if(gl_add_string_to_line(gl, gl->cutbuf))
50717c478bd9Sstevel@tonic-gate       return 1;
50727c478bd9Sstevel@tonic-gate   };
50737c478bd9Sstevel@tonic-gate /*
50747c478bd9Sstevel@tonic-gate  * gl_add_string_to_line() leaves the cursor after the last character that
50757c478bd9Sstevel@tonic-gate  * was pasted, whereas vi leaves the cursor over the last character pasted.
50767c478bd9Sstevel@tonic-gate  */
50777c478bd9Sstevel@tonic-gate   if(gl->editor == GL_VI_MODE && gl_cursor_left(gl, 1, NULL))
50787c478bd9Sstevel@tonic-gate     return 1;
50797c478bd9Sstevel@tonic-gate   return 0;
50807c478bd9Sstevel@tonic-gate }
50817c478bd9Sstevel@tonic-gate 
50827c478bd9Sstevel@tonic-gate /*.......................................................................
50837c478bd9Sstevel@tonic-gate  * This is an action function which inserts the contents of the cut
50847c478bd9Sstevel@tonic-gate  * buffer one character beyond the current cursor location.
50857c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_append_yank)50867c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_append_yank)
50877c478bd9Sstevel@tonic-gate {
50887c478bd9Sstevel@tonic-gate   int was_command = gl->vi.command;
50897c478bd9Sstevel@tonic-gate   int i;
50907c478bd9Sstevel@tonic-gate /*
50917c478bd9Sstevel@tonic-gate  * If the cut buffer is empty, ring the terminal bell.
50927c478bd9Sstevel@tonic-gate  */
50937c478bd9Sstevel@tonic-gate   if(gl->cutbuf[0] == '\0')
50947c478bd9Sstevel@tonic-gate     return gl_ring_bell(gl, 1, NULL);
50957c478bd9Sstevel@tonic-gate /*
50967c478bd9Sstevel@tonic-gate  * Set the mark at the current location + 1.
50977c478bd9Sstevel@tonic-gate  */
50987c478bd9Sstevel@tonic-gate   gl->buff_mark = gl->buff_curpos + 1;
50997c478bd9Sstevel@tonic-gate /*
51007c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
51017c478bd9Sstevel@tonic-gate  * use by vi-undo.
51027c478bd9Sstevel@tonic-gate  */
51037c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
51047c478bd9Sstevel@tonic-gate /*
51057c478bd9Sstevel@tonic-gate  * Arrange to paste the text in insert mode after the current character.
51067c478bd9Sstevel@tonic-gate  */
51077c478bd9Sstevel@tonic-gate   if(gl_vi_append(gl, 0, NULL))
51087c478bd9Sstevel@tonic-gate     return 1;
51097c478bd9Sstevel@tonic-gate /*
51107c478bd9Sstevel@tonic-gate  * Insert the string count times.
51117c478bd9Sstevel@tonic-gate  */
51127c478bd9Sstevel@tonic-gate   for(i=0; i<count; i++) {
51137c478bd9Sstevel@tonic-gate     if(gl_add_string_to_line(gl, gl->cutbuf))
51147c478bd9Sstevel@tonic-gate       return 1;
51157c478bd9Sstevel@tonic-gate   };
51167c478bd9Sstevel@tonic-gate /*
51177c478bd9Sstevel@tonic-gate  * Switch back to command mode if necessary.
51187c478bd9Sstevel@tonic-gate  */
51197c478bd9Sstevel@tonic-gate   if(was_command)
51207c478bd9Sstevel@tonic-gate     gl_vi_command_mode(gl);
51217c478bd9Sstevel@tonic-gate   return 0;
51227c478bd9Sstevel@tonic-gate }
51237c478bd9Sstevel@tonic-gate 
51247c478bd9Sstevel@tonic-gate /*.......................................................................
51257c478bd9Sstevel@tonic-gate  * Attempt to ask the terminal for its current size. On systems that
51267c478bd9Sstevel@tonic-gate  * don't support the TIOCWINSZ ioctl() for querying the terminal size,
51277c478bd9Sstevel@tonic-gate  * the current values of gl->ncolumn and gl->nrow are returned.
51287c478bd9Sstevel@tonic-gate  *
51297c478bd9Sstevel@tonic-gate  * Input:
51307c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The resource object of gl_get_line().
51317c478bd9Sstevel@tonic-gate  * Input/Output:
51327c478bd9Sstevel@tonic-gate  *  ncolumn    int *  The number of columns will be assigned to *ncolumn.
51337c478bd9Sstevel@tonic-gate  *  nline      int *  The number of lines will be assigned to *nline.
51347c478bd9Sstevel@tonic-gate  */
gl_query_size(GetLine * gl,int * ncolumn,int * nline)51357c478bd9Sstevel@tonic-gate static void gl_query_size(GetLine *gl, int *ncolumn, int *nline)
51367c478bd9Sstevel@tonic-gate {
51377c478bd9Sstevel@tonic-gate #ifdef TIOCGWINSZ
51387c478bd9Sstevel@tonic-gate /*
51397c478bd9Sstevel@tonic-gate  * Query the new terminal window size. Ignore invalid responses.
51407c478bd9Sstevel@tonic-gate  */
51417c478bd9Sstevel@tonic-gate   struct winsize size;
51427c478bd9Sstevel@tonic-gate   if(ioctl(gl->output_fd, TIOCGWINSZ, &size) == 0 &&
51437c478bd9Sstevel@tonic-gate      size.ws_row > 0 && size.ws_col > 0) {
51447c478bd9Sstevel@tonic-gate     *ncolumn = size.ws_col;
51457c478bd9Sstevel@tonic-gate     *nline = size.ws_row;
51467c478bd9Sstevel@tonic-gate     return;
51477c478bd9Sstevel@tonic-gate   };
51487c478bd9Sstevel@tonic-gate #endif
51497c478bd9Sstevel@tonic-gate /*
51507c478bd9Sstevel@tonic-gate  * Return the existing values.
51517c478bd9Sstevel@tonic-gate  */
51527c478bd9Sstevel@tonic-gate   *ncolumn = gl->ncolumn;
51537c478bd9Sstevel@tonic-gate   *nline = gl->nline;
51547c478bd9Sstevel@tonic-gate   return;
51557c478bd9Sstevel@tonic-gate }
51567c478bd9Sstevel@tonic-gate 
51577c478bd9Sstevel@tonic-gate /*.......................................................................
51587c478bd9Sstevel@tonic-gate  * Query the size of the terminal, and if it has changed, redraw the
51597c478bd9Sstevel@tonic-gate  * current input line accordingly.
51607c478bd9Sstevel@tonic-gate  *
51617c478bd9Sstevel@tonic-gate  * Input:
51627c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The resource object of gl_get_line().
51637c478bd9Sstevel@tonic-gate  * Output:
51647c478bd9Sstevel@tonic-gate  *  return     int    0 - OK.
51657c478bd9Sstevel@tonic-gate  *                    1 - Error.
51667c478bd9Sstevel@tonic-gate  */
_gl_update_size(GetLine * gl)51677c478bd9Sstevel@tonic-gate static int _gl_update_size(GetLine *gl)
51687c478bd9Sstevel@tonic-gate {
51697c478bd9Sstevel@tonic-gate   int ncolumn, nline;    /* The new size of the terminal */
51707c478bd9Sstevel@tonic-gate /*
51717c478bd9Sstevel@tonic-gate  * Query the new terminal window size.
51727c478bd9Sstevel@tonic-gate  */
51737c478bd9Sstevel@tonic-gate   gl_query_size(gl, &ncolumn, &nline);
51747c478bd9Sstevel@tonic-gate /*
51757c478bd9Sstevel@tonic-gate  * Update gl and the displayed line to fit the new dimensions.
51767c478bd9Sstevel@tonic-gate  */
51777c478bd9Sstevel@tonic-gate   return gl_handle_tty_resize(gl, ncolumn, nline);
51787c478bd9Sstevel@tonic-gate }
51797c478bd9Sstevel@tonic-gate 
51807c478bd9Sstevel@tonic-gate /*.......................................................................
51817c478bd9Sstevel@tonic-gate  * Redraw the current input line to account for a change in the terminal
51827c478bd9Sstevel@tonic-gate  * size. Also install the new size in gl.
51837c478bd9Sstevel@tonic-gate  *
51847c478bd9Sstevel@tonic-gate  * Input:
51857c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The resource object of gl_get_line().
51867c478bd9Sstevel@tonic-gate  *  ncolumn    int    The new number of columns.
51877c478bd9Sstevel@tonic-gate  *  nline      int    The new number of lines.
51887c478bd9Sstevel@tonic-gate  * Output:
51897c478bd9Sstevel@tonic-gate  *  return     int    0 - OK.
51907c478bd9Sstevel@tonic-gate  *                    1 - Error.
51917c478bd9Sstevel@tonic-gate  */
gl_handle_tty_resize(GetLine * gl,int ncolumn,int nline)51927c478bd9Sstevel@tonic-gate static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline)
51937c478bd9Sstevel@tonic-gate {
51947c478bd9Sstevel@tonic-gate /*
51957c478bd9Sstevel@tonic-gate  * If the input device isn't a terminal, just record the new size.
51967c478bd9Sstevel@tonic-gate  */
51977c478bd9Sstevel@tonic-gate   if(!gl->is_term) {
51987c478bd9Sstevel@tonic-gate     gl->nline = nline;
51997c478bd9Sstevel@tonic-gate     gl->ncolumn = ncolumn;
52007c478bd9Sstevel@tonic-gate /*
52017c478bd9Sstevel@tonic-gate  * Has the size actually changed?
52027c478bd9Sstevel@tonic-gate  */
52037c478bd9Sstevel@tonic-gate   } else if(ncolumn != gl->ncolumn || nline != gl->nline) {
52047c478bd9Sstevel@tonic-gate /*
52057c478bd9Sstevel@tonic-gate  * If we are currently editing a line, erase it.
52067c478bd9Sstevel@tonic-gate  */
52077c478bd9Sstevel@tonic-gate     if(gl_erase_line(gl))
52087c478bd9Sstevel@tonic-gate       return 1;
52097c478bd9Sstevel@tonic-gate /*
52107c478bd9Sstevel@tonic-gate  * Update the recorded window size.
52117c478bd9Sstevel@tonic-gate  */
52127c478bd9Sstevel@tonic-gate     gl->nline = nline;
52137c478bd9Sstevel@tonic-gate     gl->ncolumn = ncolumn;
52147c478bd9Sstevel@tonic-gate /*
52157c478bd9Sstevel@tonic-gate  * Arrange for the input line to be redrawn before the next character
52167c478bd9Sstevel@tonic-gate  * is read from the terminal.
52177c478bd9Sstevel@tonic-gate  */
52187c478bd9Sstevel@tonic-gate     gl_queue_redisplay(gl);
52197c478bd9Sstevel@tonic-gate   };
52207c478bd9Sstevel@tonic-gate   return 0;
52217c478bd9Sstevel@tonic-gate }
52227c478bd9Sstevel@tonic-gate 
52237c478bd9Sstevel@tonic-gate /*.......................................................................
52247c478bd9Sstevel@tonic-gate  * This is the action function that recalls the previous line in the
52257c478bd9Sstevel@tonic-gate  * history buffer.
52267c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_up_history)52277c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_up_history)
52287c478bd9Sstevel@tonic-gate {
52297c478bd9Sstevel@tonic-gate /*
52307c478bd9Sstevel@tonic-gate  * In vi mode, switch to command mode, since the user is very
52317c478bd9Sstevel@tonic-gate  * likely to want to move around newly recalled lines.
52327c478bd9Sstevel@tonic-gate  */
52337c478bd9Sstevel@tonic-gate   gl_vi_command_mode(gl);
52347c478bd9Sstevel@tonic-gate /*
52357c478bd9Sstevel@tonic-gate  * Forget any previous recall session.
52367c478bd9Sstevel@tonic-gate  */
52377c478bd9Sstevel@tonic-gate   gl->preload_id = 0;
52387c478bd9Sstevel@tonic-gate /*
52397c478bd9Sstevel@tonic-gate  * Record the key sequence number of this search action.
52407c478bd9Sstevel@tonic-gate  */
52417c478bd9Sstevel@tonic-gate   gl->last_search = gl->keyseq_count;
52427c478bd9Sstevel@tonic-gate /*
52437c478bd9Sstevel@tonic-gate  * We don't want a search prefix for this function.
52447c478bd9Sstevel@tonic-gate  */
52457c478bd9Sstevel@tonic-gate   if(_glh_search_prefix(gl->glh, gl->line, 0)) {
52467c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
52477c478bd9Sstevel@tonic-gate     return 1;
52487c478bd9Sstevel@tonic-gate   };
52497c478bd9Sstevel@tonic-gate /*
52507c478bd9Sstevel@tonic-gate  * Recall the count'th next older line in the history list. If the first one
52517c478bd9Sstevel@tonic-gate  * fails we can return since nothing has changed, otherwise we must continue
52527c478bd9Sstevel@tonic-gate  * and update the line state.
52537c478bd9Sstevel@tonic-gate  */
52547c478bd9Sstevel@tonic-gate   if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
52557c478bd9Sstevel@tonic-gate     return 0;
52567c478bd9Sstevel@tonic-gate   while(--count && _glh_find_backwards(gl->glh, gl->line, gl->linelen+1))
52577c478bd9Sstevel@tonic-gate     ;
52587c478bd9Sstevel@tonic-gate /*
52597c478bd9Sstevel@tonic-gate  * Accomodate the new contents of gl->line[].
52607c478bd9Sstevel@tonic-gate  */
52617c478bd9Sstevel@tonic-gate   gl_update_buffer(gl);
52627c478bd9Sstevel@tonic-gate /*
52637c478bd9Sstevel@tonic-gate  * Arrange to have the cursor placed at the end of the new line.
52647c478bd9Sstevel@tonic-gate  */
52657c478bd9Sstevel@tonic-gate   gl->buff_curpos = gl->ntotal;
52667c478bd9Sstevel@tonic-gate /*
52677c478bd9Sstevel@tonic-gate  * Erase and display the new line.
52687c478bd9Sstevel@tonic-gate  */
52697c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
52707c478bd9Sstevel@tonic-gate   return 0;
52717c478bd9Sstevel@tonic-gate }
52727c478bd9Sstevel@tonic-gate 
52737c478bd9Sstevel@tonic-gate /*.......................................................................
52747c478bd9Sstevel@tonic-gate  * This is the action function that recalls the next line in the
52757c478bd9Sstevel@tonic-gate  * history buffer.
52767c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_down_history)52777c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_down_history)
52787c478bd9Sstevel@tonic-gate {
52797c478bd9Sstevel@tonic-gate /*
52807c478bd9Sstevel@tonic-gate  * In vi mode, switch to command mode, since the user is very
52817c478bd9Sstevel@tonic-gate  * likely to want to move around newly recalled lines.
52827c478bd9Sstevel@tonic-gate  */
52837c478bd9Sstevel@tonic-gate   gl_vi_command_mode(gl);
52847c478bd9Sstevel@tonic-gate /*
52857c478bd9Sstevel@tonic-gate  * Record the key sequence number of this search action.
52867c478bd9Sstevel@tonic-gate  */
52877c478bd9Sstevel@tonic-gate   gl->last_search = gl->keyseq_count;
52887c478bd9Sstevel@tonic-gate /*
52897c478bd9Sstevel@tonic-gate  * If no search is currently in progress continue a previous recall
52907c478bd9Sstevel@tonic-gate  * session from a previous entered line if possible.
52917c478bd9Sstevel@tonic-gate  */
52927c478bd9Sstevel@tonic-gate   if(_glh_line_id(gl->glh, 0) == 0 && gl->preload_id) {
52937c478bd9Sstevel@tonic-gate     _glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1);
52947c478bd9Sstevel@tonic-gate     gl->preload_id = 0;
52957c478bd9Sstevel@tonic-gate   } else {
52967c478bd9Sstevel@tonic-gate /*
52977c478bd9Sstevel@tonic-gate  * We don't want a search prefix for this function.
52987c478bd9Sstevel@tonic-gate  */
52997c478bd9Sstevel@tonic-gate     if(_glh_search_prefix(gl->glh, gl->line, 0)) {
53007c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
53017c478bd9Sstevel@tonic-gate       return 1;
53027c478bd9Sstevel@tonic-gate     };
53037c478bd9Sstevel@tonic-gate /*
53047c478bd9Sstevel@tonic-gate  * Recall the count'th next newer line in the history list. If the first one
53057c478bd9Sstevel@tonic-gate  * fails we can return since nothing has changed otherwise we must continue
53067c478bd9Sstevel@tonic-gate  * and update the line state.
53077c478bd9Sstevel@tonic-gate  */
53087c478bd9Sstevel@tonic-gate     if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
53097c478bd9Sstevel@tonic-gate       return 0;
53107c478bd9Sstevel@tonic-gate     while(--count && _glh_find_forwards(gl->glh, gl->line, gl->linelen+1))
53117c478bd9Sstevel@tonic-gate       ;
53127c478bd9Sstevel@tonic-gate   };
53137c478bd9Sstevel@tonic-gate /*
53147c478bd9Sstevel@tonic-gate  * Accomodate the new contents of gl->line[].
53157c478bd9Sstevel@tonic-gate  */
53167c478bd9Sstevel@tonic-gate   gl_update_buffer(gl);
53177c478bd9Sstevel@tonic-gate /*
53187c478bd9Sstevel@tonic-gate  * Arrange to have the cursor placed at the end of the new line.
53197c478bd9Sstevel@tonic-gate  */
53207c478bd9Sstevel@tonic-gate   gl->buff_curpos = gl->ntotal;
53217c478bd9Sstevel@tonic-gate /*
53227c478bd9Sstevel@tonic-gate  * Erase and display the new line.
53237c478bd9Sstevel@tonic-gate  */
53247c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
53257c478bd9Sstevel@tonic-gate   return 0;
53267c478bd9Sstevel@tonic-gate }
53277c478bd9Sstevel@tonic-gate 
53287c478bd9Sstevel@tonic-gate /*.......................................................................
53297c478bd9Sstevel@tonic-gate  * This is the action function that recalls the previous line in the
53307c478bd9Sstevel@tonic-gate  * history buffer whos prefix matches the characters that currently
53317c478bd9Sstevel@tonic-gate  * precede the cursor. By setting count=-1, this can be used internally
53327c478bd9Sstevel@tonic-gate  * to force searching for the prefix used in the last search.
53337c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_history_search_backward)53347c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_search_backward)
53357c478bd9Sstevel@tonic-gate {
53367c478bd9Sstevel@tonic-gate /*
53377c478bd9Sstevel@tonic-gate  * In vi mode, switch to command mode, since the user is very
53387c478bd9Sstevel@tonic-gate  * likely to want to move around newly recalled lines.
53397c478bd9Sstevel@tonic-gate  */
53407c478bd9Sstevel@tonic-gate   gl_vi_command_mode(gl);
53417c478bd9Sstevel@tonic-gate /*
53427c478bd9Sstevel@tonic-gate  * Forget any previous recall session.
53437c478bd9Sstevel@tonic-gate  */
53447c478bd9Sstevel@tonic-gate   gl->preload_id = 0;
53457c478bd9Sstevel@tonic-gate /*
53467c478bd9Sstevel@tonic-gate  * Record the key sequence number of this search action.
53477c478bd9Sstevel@tonic-gate  */
53487c478bd9Sstevel@tonic-gate   gl->last_search = gl->keyseq_count;
53497c478bd9Sstevel@tonic-gate /*
53507c478bd9Sstevel@tonic-gate  * If a prefix search isn't already in progress, replace the search
53517c478bd9Sstevel@tonic-gate  * prefix to the string that precedes the cursor. In vi command mode
53527c478bd9Sstevel@tonic-gate  * include the character that is under the cursor in the string.  If
53537c478bd9Sstevel@tonic-gate  * count<0 keep the previous search prefix regardless, so as to force
53547c478bd9Sstevel@tonic-gate  * a repeat search even if the last command wasn't a history command.
53557c478bd9Sstevel@tonic-gate  */
53567c478bd9Sstevel@tonic-gate   if(count >= 0 && !_glh_search_active(gl->glh) &&
53577c478bd9Sstevel@tonic-gate      _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
53587c478bd9Sstevel@tonic-gate 			(gl->editor==GL_VI_MODE && gl->ntotal>0))) {
53597c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
53607c478bd9Sstevel@tonic-gate     return 1;
53617c478bd9Sstevel@tonic-gate   };
53627c478bd9Sstevel@tonic-gate /*
53637c478bd9Sstevel@tonic-gate  * Search backwards for a match to the part of the line which precedes the
53647c478bd9Sstevel@tonic-gate  * cursor.
53657c478bd9Sstevel@tonic-gate  */
53667c478bd9Sstevel@tonic-gate   if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL)
53677c478bd9Sstevel@tonic-gate     return 0;
53687c478bd9Sstevel@tonic-gate /*
53697c478bd9Sstevel@tonic-gate  * Accomodate the new contents of gl->line[].
53707c478bd9Sstevel@tonic-gate  */
53717c478bd9Sstevel@tonic-gate   gl_update_buffer(gl);
53727c478bd9Sstevel@tonic-gate /*
53737c478bd9Sstevel@tonic-gate  * Arrange to have the cursor placed at the end of the new line.
53747c478bd9Sstevel@tonic-gate  */
53757c478bd9Sstevel@tonic-gate   gl->buff_curpos = gl->ntotal;
53767c478bd9Sstevel@tonic-gate /*
53777c478bd9Sstevel@tonic-gate  * Erase and display the new line.
53787c478bd9Sstevel@tonic-gate  */
53797c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
53807c478bd9Sstevel@tonic-gate   return 0;
53817c478bd9Sstevel@tonic-gate }
53827c478bd9Sstevel@tonic-gate 
53837c478bd9Sstevel@tonic-gate /*.......................................................................
53847c478bd9Sstevel@tonic-gate  * This is the action function that recalls the previous line in the
53857c478bd9Sstevel@tonic-gate  * history buffer who's prefix matches that specified in an earlier call
53867c478bd9Sstevel@tonic-gate  * to gl_history_search_backward() or gl_history_search_forward().
53877c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_history_re_search_backward)53887c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_re_search_backward)
53897c478bd9Sstevel@tonic-gate {
53907c478bd9Sstevel@tonic-gate   return gl_history_search_backward(gl, -1, NULL);
53917c478bd9Sstevel@tonic-gate }
53927c478bd9Sstevel@tonic-gate 
53937c478bd9Sstevel@tonic-gate /*.......................................................................
53947c478bd9Sstevel@tonic-gate  * This is the action function that recalls the next line in the
53957c478bd9Sstevel@tonic-gate  * history buffer who's prefix matches that specified in the earlier call
53967c478bd9Sstevel@tonic-gate  * to gl_history_search_backward) which started the history search.
53977c478bd9Sstevel@tonic-gate  * By setting count=-1, this can be used internally to force searching
53987c478bd9Sstevel@tonic-gate  * for the prefix used in the last search.
53997c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_history_search_forward)54007c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_search_forward)
54017c478bd9Sstevel@tonic-gate {
54027c478bd9Sstevel@tonic-gate /*
54037c478bd9Sstevel@tonic-gate  * In vi mode, switch to command mode, since the user is very
54047c478bd9Sstevel@tonic-gate  * likely to want to move around newly recalled lines.
54057c478bd9Sstevel@tonic-gate  */
54067c478bd9Sstevel@tonic-gate   gl_vi_command_mode(gl);
54077c478bd9Sstevel@tonic-gate /*
54087c478bd9Sstevel@tonic-gate  * Record the key sequence number of this search action.
54097c478bd9Sstevel@tonic-gate  */
54107c478bd9Sstevel@tonic-gate   gl->last_search = gl->keyseq_count;
54117c478bd9Sstevel@tonic-gate /*
54127c478bd9Sstevel@tonic-gate  * If a prefix search isn't already in progress, replace the search
54137c478bd9Sstevel@tonic-gate  * prefix to the string that precedes the cursor. In vi command mode
54147c478bd9Sstevel@tonic-gate  * include the character that is under the cursor in the string.  If
54157c478bd9Sstevel@tonic-gate  * count<0 keep the previous search prefix regardless, so as to force
54167c478bd9Sstevel@tonic-gate  * a repeat search even if the last command wasn't a history command.
54177c478bd9Sstevel@tonic-gate  */
54187c478bd9Sstevel@tonic-gate   if(count >= 0 && !_glh_search_active(gl->glh) &&
54197c478bd9Sstevel@tonic-gate      _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos +
54207c478bd9Sstevel@tonic-gate 			(gl->editor==GL_VI_MODE && gl->ntotal>0))) {
54217c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
54227c478bd9Sstevel@tonic-gate     return 1;
54237c478bd9Sstevel@tonic-gate   };
54247c478bd9Sstevel@tonic-gate /*
54257c478bd9Sstevel@tonic-gate  * Search forwards for the next matching line.
54267c478bd9Sstevel@tonic-gate  */
54277c478bd9Sstevel@tonic-gate   if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL)
54287c478bd9Sstevel@tonic-gate     return 0;
54297c478bd9Sstevel@tonic-gate /*
54307c478bd9Sstevel@tonic-gate  * Accomodate the new contents of gl->line[].
54317c478bd9Sstevel@tonic-gate  */
54327c478bd9Sstevel@tonic-gate   gl_update_buffer(gl);
54337c478bd9Sstevel@tonic-gate /*
54347c478bd9Sstevel@tonic-gate  * Arrange for the cursor to be placed at the end of the new line.
54357c478bd9Sstevel@tonic-gate  */
54367c478bd9Sstevel@tonic-gate   gl->buff_curpos = gl->ntotal;
54377c478bd9Sstevel@tonic-gate /*
54387c478bd9Sstevel@tonic-gate  * Erase and display the new line.
54397c478bd9Sstevel@tonic-gate  */
54407c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
54417c478bd9Sstevel@tonic-gate   return 0;
54427c478bd9Sstevel@tonic-gate }
54437c478bd9Sstevel@tonic-gate 
54447c478bd9Sstevel@tonic-gate /*.......................................................................
54457c478bd9Sstevel@tonic-gate  * This is the action function that recalls the next line in the
54467c478bd9Sstevel@tonic-gate  * history buffer who's prefix matches that specified in an earlier call
54477c478bd9Sstevel@tonic-gate  * to gl_history_search_backward() or gl_history_search_forward().
54487c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_history_re_search_forward)54497c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_re_search_forward)
54507c478bd9Sstevel@tonic-gate {
54517c478bd9Sstevel@tonic-gate   return gl_history_search_forward(gl, -1, NULL);
54527c478bd9Sstevel@tonic-gate }
54537c478bd9Sstevel@tonic-gate 
54547c478bd9Sstevel@tonic-gate #ifdef HIDE_FILE_SYSTEM
54557c478bd9Sstevel@tonic-gate /*.......................................................................
54567c478bd9Sstevel@tonic-gate  * The following function is used as the default completion handler when
54577c478bd9Sstevel@tonic-gate  * the filesystem is to be hidden. It simply reports no completions.
54587c478bd9Sstevel@tonic-gate  */
CPL_MATCH_FN(gl_no_completions)54597c478bd9Sstevel@tonic-gate static CPL_MATCH_FN(gl_no_completions)
54607c478bd9Sstevel@tonic-gate {
54617c478bd9Sstevel@tonic-gate   return 0;
54627c478bd9Sstevel@tonic-gate }
54637c478bd9Sstevel@tonic-gate #endif
54647c478bd9Sstevel@tonic-gate 
54657c478bd9Sstevel@tonic-gate /*.......................................................................
54667c478bd9Sstevel@tonic-gate  * This is the tab completion function that completes the filename that
54677c478bd9Sstevel@tonic-gate  * precedes the cursor position. Its callback data argument must be a
54687c478bd9Sstevel@tonic-gate  * pointer to a GlCplCallback containing the completion callback function
54697c478bd9Sstevel@tonic-gate  * and its callback data, or NULL to use the builtin filename completer.
54707c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_complete_word)54717c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_complete_word)
54727c478bd9Sstevel@tonic-gate {
54737c478bd9Sstevel@tonic-gate   CplMatches *matches;    /* The possible completions */
54747c478bd9Sstevel@tonic-gate   int suffix_len;         /* The length of the completion extension */
54757c478bd9Sstevel@tonic-gate   int cont_len;           /* The length of any continuation suffix */
54767c478bd9Sstevel@tonic-gate   int nextra;             /* The number of characters being added to the */
54777c478bd9Sstevel@tonic-gate                           /*  total length of the line. */
54787c478bd9Sstevel@tonic-gate   int buff_pos;           /* The buffer index at which the completion is */
54797c478bd9Sstevel@tonic-gate                           /*  to be inserted. */
54807c478bd9Sstevel@tonic-gate   int waserr = 0;         /* True after errors */
54817c478bd9Sstevel@tonic-gate /*
54827c478bd9Sstevel@tonic-gate  * Get the container of the completion callback and its callback data.
54837c478bd9Sstevel@tonic-gate  */
54847c478bd9Sstevel@tonic-gate   GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
54857c478bd9Sstevel@tonic-gate /*
54867c478bd9Sstevel@tonic-gate  * In vi command mode, switch to append mode so that the character under
54877c478bd9Sstevel@tonic-gate  * the cursor is included in the completion (otherwise people can't
54887c478bd9Sstevel@tonic-gate  * complete at the end of the line).
54897c478bd9Sstevel@tonic-gate  */
54907c478bd9Sstevel@tonic-gate   if(gl->vi.command && gl_vi_append(gl, 0, NULL))
54917c478bd9Sstevel@tonic-gate     return 1;
54927c478bd9Sstevel@tonic-gate /*
54937c478bd9Sstevel@tonic-gate  * Get the cursor position at which the completion is to be inserted.
54947c478bd9Sstevel@tonic-gate  */
54957c478bd9Sstevel@tonic-gate   buff_pos = gl->buff_curpos;
54967c478bd9Sstevel@tonic-gate /*
54977c478bd9Sstevel@tonic-gate  * Perform the completion.
54987c478bd9Sstevel@tonic-gate  */
54997c478bd9Sstevel@tonic-gate   matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos, cb->data,
55007c478bd9Sstevel@tonic-gate 			      cb->fn);
55017c478bd9Sstevel@tonic-gate /*
55027c478bd9Sstevel@tonic-gate  * No matching completions?
55037c478bd9Sstevel@tonic-gate  */
55047c478bd9Sstevel@tonic-gate   if(!matches) {
55057c478bd9Sstevel@tonic-gate     waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
55067c478bd9Sstevel@tonic-gate /*
55077c478bd9Sstevel@tonic-gate  * Are there any completions?
55087c478bd9Sstevel@tonic-gate  */
55097c478bd9Sstevel@tonic-gate   } else if(matches->nmatch >= 1) {
55107c478bd9Sstevel@tonic-gate /*
55117c478bd9Sstevel@tonic-gate  * If there any ambiguous matches, report them, starting on a new line.
55127c478bd9Sstevel@tonic-gate  */
55137c478bd9Sstevel@tonic-gate     if(matches->nmatch > 1 && gl->echo) {
55147c478bd9Sstevel@tonic-gate       if(_gl_normal_io(gl) ||
55157c478bd9Sstevel@tonic-gate 	 _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
55167c478bd9Sstevel@tonic-gate 	waserr = 1;
55177c478bd9Sstevel@tonic-gate     };
55187c478bd9Sstevel@tonic-gate /*
55197c478bd9Sstevel@tonic-gate  * Get the length of the suffix and any continuation suffix to add to it.
55207c478bd9Sstevel@tonic-gate  */
55217c478bd9Sstevel@tonic-gate     suffix_len = strlen(matches->suffix);
55227c478bd9Sstevel@tonic-gate     cont_len = strlen(matches->cont_suffix);
55237c478bd9Sstevel@tonic-gate /*
55247c478bd9Sstevel@tonic-gate  * If there is an unambiguous match, and the continuation suffix ends in
55257c478bd9Sstevel@tonic-gate  * a newline, strip that newline and arrange to have getline return
55267c478bd9Sstevel@tonic-gate  * after this action function returns.
55277c478bd9Sstevel@tonic-gate  */
55287c478bd9Sstevel@tonic-gate     if(matches->nmatch==1 && cont_len > 0 &&
55297c478bd9Sstevel@tonic-gate        matches->cont_suffix[cont_len - 1] == '\n') {
55307c478bd9Sstevel@tonic-gate       cont_len--;
55317c478bd9Sstevel@tonic-gate       if(gl_newline(gl, 1, NULL))
55327c478bd9Sstevel@tonic-gate 	waserr = 1;
55337c478bd9Sstevel@tonic-gate     };
55347c478bd9Sstevel@tonic-gate /*
55357c478bd9Sstevel@tonic-gate  * Work out the number of characters that are to be added.
55367c478bd9Sstevel@tonic-gate  */
55377c478bd9Sstevel@tonic-gate     nextra = suffix_len + cont_len;
55387c478bd9Sstevel@tonic-gate /*
55397c478bd9Sstevel@tonic-gate  * Is there anything to be added?
55407c478bd9Sstevel@tonic-gate  */
55417c478bd9Sstevel@tonic-gate     if(!waserr && nextra) {
55427c478bd9Sstevel@tonic-gate /*
55437c478bd9Sstevel@tonic-gate  * Will there be space for the expansion in the line buffer?
55447c478bd9Sstevel@tonic-gate  */
55457c478bd9Sstevel@tonic-gate       if(gl->ntotal + nextra < gl->linelen) {
55467c478bd9Sstevel@tonic-gate /*
55477c478bd9Sstevel@tonic-gate  * Make room to insert the filename extension.
55487c478bd9Sstevel@tonic-gate  */
55497c478bd9Sstevel@tonic-gate 	gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
55507c478bd9Sstevel@tonic-gate /*
55517c478bd9Sstevel@tonic-gate  * Insert the filename extension.
55527c478bd9Sstevel@tonic-gate  */
55537c478bd9Sstevel@tonic-gate 	gl_buffer_string(gl, matches->suffix, suffix_len, gl->buff_curpos);
55547c478bd9Sstevel@tonic-gate /*
55557c478bd9Sstevel@tonic-gate  * Add the terminating characters.
55567c478bd9Sstevel@tonic-gate  */
55577c478bd9Sstevel@tonic-gate 	gl_buffer_string(gl, matches->cont_suffix, cont_len,
55587c478bd9Sstevel@tonic-gate 			 gl->buff_curpos + suffix_len);
55597c478bd9Sstevel@tonic-gate /*
55607c478bd9Sstevel@tonic-gate  * Place the cursor position at the end of the completion.
55617c478bd9Sstevel@tonic-gate  */
55627c478bd9Sstevel@tonic-gate 	gl->buff_curpos += nextra;
55637c478bd9Sstevel@tonic-gate /*
55647c478bd9Sstevel@tonic-gate  * If we don't have to redisplay the whole line, redisplay the part
55657c478bd9Sstevel@tonic-gate  * of the line which follows the original cursor position, and place
55667c478bd9Sstevel@tonic-gate  * the cursor at the end of the completion.
55677c478bd9Sstevel@tonic-gate  */
55687c478bd9Sstevel@tonic-gate 	if(gl->displayed) {
55697c478bd9Sstevel@tonic-gate 	  if(gl_truncate_display(gl) ||
55707c478bd9Sstevel@tonic-gate 	     gl_print_string(gl, gl->line + buff_pos, '\0') ||
55717c478bd9Sstevel@tonic-gate 	     gl_place_cursor(gl, gl->buff_curpos))
55727c478bd9Sstevel@tonic-gate 	    waserr = 1;
55737c478bd9Sstevel@tonic-gate 	};
55747c478bd9Sstevel@tonic-gate       } else {
55757c478bd9Sstevel@tonic-gate 	(void) gl_print_info(gl,
55767c478bd9Sstevel@tonic-gate 			     "Insufficient room in line for file completion.",
55777c478bd9Sstevel@tonic-gate 			     GL_END_INFO);
55787c478bd9Sstevel@tonic-gate 	waserr = 1;
55797c478bd9Sstevel@tonic-gate       };
55807c478bd9Sstevel@tonic-gate     };
55817c478bd9Sstevel@tonic-gate   };
55827c478bd9Sstevel@tonic-gate /*
55837c478bd9Sstevel@tonic-gate  * If any output had to be written to the terminal, then editing will
55847c478bd9Sstevel@tonic-gate  * have been suspended, make sure that we are back in raw line editing
55857c478bd9Sstevel@tonic-gate  * mode before returning.
55867c478bd9Sstevel@tonic-gate  */
55877c478bd9Sstevel@tonic-gate   if(_gl_raw_io(gl, 1))
55887c478bd9Sstevel@tonic-gate     waserr = 1;
55897c478bd9Sstevel@tonic-gate   return 0;
55907c478bd9Sstevel@tonic-gate }
55917c478bd9Sstevel@tonic-gate 
55927c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
55937c478bd9Sstevel@tonic-gate /*.......................................................................
55947c478bd9Sstevel@tonic-gate  * This is the function that expands the filename that precedes the
55957c478bd9Sstevel@tonic-gate  * cursor position. It expands ~user/ expressions, $envvar expressions,
55967c478bd9Sstevel@tonic-gate  * and wildcards.
55977c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_expand_filename)55987c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_expand_filename)
55997c478bd9Sstevel@tonic-gate {
56007c478bd9Sstevel@tonic-gate   char *start_path;      /* The pointer to the start of the pathname in */
56017c478bd9Sstevel@tonic-gate                          /*  gl->line[]. */
56027c478bd9Sstevel@tonic-gate   FileExpansion *result; /* The results of the filename expansion */
56037c478bd9Sstevel@tonic-gate   int pathlen;           /* The length of the pathname being expanded */
56047c478bd9Sstevel@tonic-gate   int length;            /* The number of characters needed to display the */
56057c478bd9Sstevel@tonic-gate                          /*  expanded files. */
56067c478bd9Sstevel@tonic-gate   int nextra;            /* The number of characters to be added */
56077c478bd9Sstevel@tonic-gate   int i,j;
56087c478bd9Sstevel@tonic-gate /*
56097c478bd9Sstevel@tonic-gate  * In vi command mode, switch to append mode so that the character under
56107c478bd9Sstevel@tonic-gate  * the cursor is included in the completion (otherwise people can't
56117c478bd9Sstevel@tonic-gate  * complete at the end of the line).
56127c478bd9Sstevel@tonic-gate  */
56137c478bd9Sstevel@tonic-gate   if(gl->vi.command && gl_vi_append(gl, 0, NULL))
56147c478bd9Sstevel@tonic-gate     return 1;
56157c478bd9Sstevel@tonic-gate /*
56167c478bd9Sstevel@tonic-gate  * Locate the start of the filename that precedes the cursor position.
56177c478bd9Sstevel@tonic-gate  */
56187c478bd9Sstevel@tonic-gate   start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
56197c478bd9Sstevel@tonic-gate   if(!start_path)
56207c478bd9Sstevel@tonic-gate     return 1;
56217c478bd9Sstevel@tonic-gate /*
56227c478bd9Sstevel@tonic-gate  * Get the length of the string that is to be expanded.
56237c478bd9Sstevel@tonic-gate  */
56247c478bd9Sstevel@tonic-gate   pathlen = gl->buff_curpos - (start_path - gl->line);
56257c478bd9Sstevel@tonic-gate /*
56267c478bd9Sstevel@tonic-gate  * Attempt to expand it.
56277c478bd9Sstevel@tonic-gate  */
56287c478bd9Sstevel@tonic-gate   result = ef_expand_file(gl->ef, start_path, pathlen);
56297c478bd9Sstevel@tonic-gate /*
56307c478bd9Sstevel@tonic-gate  * If there was an error, report the error on a new line.
56317c478bd9Sstevel@tonic-gate  */
56327c478bd9Sstevel@tonic-gate   if(!result)
56337c478bd9Sstevel@tonic-gate     return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
56347c478bd9Sstevel@tonic-gate /*
56357c478bd9Sstevel@tonic-gate  * If no files matched, report this as well.
56367c478bd9Sstevel@tonic-gate  */
56377c478bd9Sstevel@tonic-gate   if(result->nfile == 0 || !result->exists)
56387c478bd9Sstevel@tonic-gate     return gl_print_info(gl, "No files match.", GL_END_INFO);
56397c478bd9Sstevel@tonic-gate /*
56407c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential use by
56417c478bd9Sstevel@tonic-gate  * vi-undo.
56427c478bd9Sstevel@tonic-gate  */
56437c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
56447c478bd9Sstevel@tonic-gate /*
56457c478bd9Sstevel@tonic-gate  * Work out how much space we will need to display all of the matching
56467c478bd9Sstevel@tonic-gate  * filenames, taking account of the space that we need to place between
56477c478bd9Sstevel@tonic-gate  * them, and the number of additional '\' characters needed to escape
56487c478bd9Sstevel@tonic-gate  * spaces, tabs and backslash characters in the individual filenames.
56497c478bd9Sstevel@tonic-gate  */
56507c478bd9Sstevel@tonic-gate   length = 0;
56517c478bd9Sstevel@tonic-gate   for(i=0; i<result->nfile; i++) {
56527c478bd9Sstevel@tonic-gate     char *file = result->files[i];
56537c478bd9Sstevel@tonic-gate     while(*file) {
56547c478bd9Sstevel@tonic-gate       int c = *file++;
56557c478bd9Sstevel@tonic-gate       switch(c) {
56567c478bd9Sstevel@tonic-gate       case ' ': case '\t': case '\\': case '*': case '?': case '[':
56577c478bd9Sstevel@tonic-gate 	length++;  /* Count extra backslash characters */
56587c478bd9Sstevel@tonic-gate       };
56597c478bd9Sstevel@tonic-gate       length++;    /* Count the character itself */
56607c478bd9Sstevel@tonic-gate     };
56617c478bd9Sstevel@tonic-gate     length++;      /* Count the space that follows each filename */
56627c478bd9Sstevel@tonic-gate   };
56637c478bd9Sstevel@tonic-gate /*
56647c478bd9Sstevel@tonic-gate  * Work out the number of characters that are to be added.
56657c478bd9Sstevel@tonic-gate  */
56667c478bd9Sstevel@tonic-gate   nextra = length - pathlen;
56677c478bd9Sstevel@tonic-gate /*
56687c478bd9Sstevel@tonic-gate  * Will there be space for the expansion in the line buffer?
56697c478bd9Sstevel@tonic-gate  */
56707c478bd9Sstevel@tonic-gate   if(gl->ntotal + nextra >= gl->linelen) {
56717c478bd9Sstevel@tonic-gate     return gl_print_info(gl, "Insufficient room in line for file expansion.",
56727c478bd9Sstevel@tonic-gate 			 GL_END_INFO);
56737c478bd9Sstevel@tonic-gate   } else {
56747c478bd9Sstevel@tonic-gate /*
56757c478bd9Sstevel@tonic-gate  * Do we need to move the part of the line that followed the unexpanded
56767c478bd9Sstevel@tonic-gate  * filename?
56777c478bd9Sstevel@tonic-gate  */
56787c478bd9Sstevel@tonic-gate     if(nextra > 0) {
56797c478bd9Sstevel@tonic-gate       gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra);
56807c478bd9Sstevel@tonic-gate     } else if(nextra < 0) {
56817c478bd9Sstevel@tonic-gate       gl->buff_curpos += nextra;
56827c478bd9Sstevel@tonic-gate       gl_remove_from_buffer(gl, gl->buff_curpos, -nextra);
56837c478bd9Sstevel@tonic-gate     };
56847c478bd9Sstevel@tonic-gate /*
56857c478bd9Sstevel@tonic-gate  * Insert the filenames, separated by spaces, and with internal spaces,
56867c478bd9Sstevel@tonic-gate  * tabs and backslashes escaped with backslashes.
56877c478bd9Sstevel@tonic-gate  */
56887c478bd9Sstevel@tonic-gate     for(i=0,j=start_path - gl->line; i<result->nfile; i++) {
56897c478bd9Sstevel@tonic-gate       char *file = result->files[i];
56907c478bd9Sstevel@tonic-gate       while(*file) {
56917c478bd9Sstevel@tonic-gate 	int c = *file++;
56927c478bd9Sstevel@tonic-gate 	switch(c) {
56937c478bd9Sstevel@tonic-gate 	case ' ': case '\t': case '\\': case '*': case '?': case '[':
56947c478bd9Sstevel@tonic-gate 	  gl_buffer_char(gl, '\\', j++);
56957c478bd9Sstevel@tonic-gate 	};
56967c478bd9Sstevel@tonic-gate 	gl_buffer_char(gl, c, j++);
56977c478bd9Sstevel@tonic-gate       };
56987c478bd9Sstevel@tonic-gate       gl_buffer_char(gl, ' ', j++);
56997c478bd9Sstevel@tonic-gate     };
57007c478bd9Sstevel@tonic-gate   };
57017c478bd9Sstevel@tonic-gate /*
57027c478bd9Sstevel@tonic-gate  * Redisplay the part of the line which follows the start of
57037c478bd9Sstevel@tonic-gate  * the original filename.
57047c478bd9Sstevel@tonic-gate  */
57057c478bd9Sstevel@tonic-gate   if(gl_place_cursor(gl, start_path - gl->line) ||
57067c478bd9Sstevel@tonic-gate      gl_truncate_display(gl) ||
57077c478bd9Sstevel@tonic-gate      gl_print_string(gl, start_path, start_path[length]))
57087c478bd9Sstevel@tonic-gate     return 1;
57097c478bd9Sstevel@tonic-gate /*
57107c478bd9Sstevel@tonic-gate  * Move the cursor to the end of the expansion.
57117c478bd9Sstevel@tonic-gate  */
57127c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, (start_path - gl->line) + length);
57137c478bd9Sstevel@tonic-gate }
57147c478bd9Sstevel@tonic-gate #endif
57157c478bd9Sstevel@tonic-gate 
57167c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
57177c478bd9Sstevel@tonic-gate /*.......................................................................
57187c478bd9Sstevel@tonic-gate  * This is the action function that lists glob expansions of the
57197c478bd9Sstevel@tonic-gate  * filename that precedes the cursor position. It expands ~user/
57207c478bd9Sstevel@tonic-gate  * expressions, $envvar expressions, and wildcards.
57217c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_list_glob)57227c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_glob)
57237c478bd9Sstevel@tonic-gate {
57247c478bd9Sstevel@tonic-gate   char *start_path;      /* The pointer to the start of the pathname in */
57257c478bd9Sstevel@tonic-gate                          /*  gl->line[]. */
57267c478bd9Sstevel@tonic-gate   FileExpansion *result; /* The results of the filename expansion */
57277c478bd9Sstevel@tonic-gate   int pathlen;           /* The length of the pathname being expanded */
57287c478bd9Sstevel@tonic-gate /*
57297c478bd9Sstevel@tonic-gate  * Locate the start of the filename that precedes the cursor position.
57307c478bd9Sstevel@tonic-gate  */
57317c478bd9Sstevel@tonic-gate   start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
57327c478bd9Sstevel@tonic-gate   if(!start_path)
57337c478bd9Sstevel@tonic-gate     return 1;
57347c478bd9Sstevel@tonic-gate /*
57357c478bd9Sstevel@tonic-gate  * Get the length of the string that is to be expanded.
57367c478bd9Sstevel@tonic-gate  */
57377c478bd9Sstevel@tonic-gate   pathlen = gl->buff_curpos - (start_path - gl->line);
57387c478bd9Sstevel@tonic-gate /*
57397c478bd9Sstevel@tonic-gate  * Attempt to expand it.
57407c478bd9Sstevel@tonic-gate  */
57417c478bd9Sstevel@tonic-gate   result = ef_expand_file(gl->ef, start_path, pathlen);
57427c478bd9Sstevel@tonic-gate /*
57437c478bd9Sstevel@tonic-gate  * If there was an error, report it.
57447c478bd9Sstevel@tonic-gate  */
57457c478bd9Sstevel@tonic-gate   if(!result) {
57467c478bd9Sstevel@tonic-gate     return gl_print_info(gl,  ef_last_error(gl->ef), GL_END_INFO);
57477c478bd9Sstevel@tonic-gate /*
57487c478bd9Sstevel@tonic-gate  * If no files matched, report this as well.
57497c478bd9Sstevel@tonic-gate  */
57507c478bd9Sstevel@tonic-gate   } else if(result->nfile == 0 || !result->exists) {
57517c478bd9Sstevel@tonic-gate     return gl_print_info(gl, "No files match.", GL_END_INFO);
57527c478bd9Sstevel@tonic-gate /*
57537c478bd9Sstevel@tonic-gate  * List the matching expansions.
57547c478bd9Sstevel@tonic-gate  */
57557c478bd9Sstevel@tonic-gate   } else if(gl->echo) {
57567c478bd9Sstevel@tonic-gate     if(gl_start_newline(gl, 1) ||
57577c478bd9Sstevel@tonic-gate        _ef_output_expansions(result, gl_write_fn, gl, gl->ncolumn))
57587c478bd9Sstevel@tonic-gate       return 1;
57597c478bd9Sstevel@tonic-gate     gl_queue_redisplay(gl);
57607c478bd9Sstevel@tonic-gate   };
57617c478bd9Sstevel@tonic-gate   return 0;
57627c478bd9Sstevel@tonic-gate }
57637c478bd9Sstevel@tonic-gate #endif
57647c478bd9Sstevel@tonic-gate 
57657c478bd9Sstevel@tonic-gate /*.......................................................................
57667c478bd9Sstevel@tonic-gate  * Return non-zero if a character should be considered a part of a word.
57677c478bd9Sstevel@tonic-gate  *
57687c478bd9Sstevel@tonic-gate  * Input:
57697c478bd9Sstevel@tonic-gate  *  c       int  The character to be tested.
57707c478bd9Sstevel@tonic-gate  * Output:
57717c478bd9Sstevel@tonic-gate  *  return  int  True if the character should be considered part of a word.
57727c478bd9Sstevel@tonic-gate  */
gl_is_word_char(int c)57737c478bd9Sstevel@tonic-gate static int gl_is_word_char(int c)
57747c478bd9Sstevel@tonic-gate {
57757c478bd9Sstevel@tonic-gate   return isalnum((int)(unsigned char)c) || strchr(GL_WORD_CHARS, c) != NULL;
57767c478bd9Sstevel@tonic-gate }
57777c478bd9Sstevel@tonic-gate 
57787c478bd9Sstevel@tonic-gate /*.......................................................................
57797c478bd9Sstevel@tonic-gate  * Override the builtin file-completion callback that is bound to the
57807c478bd9Sstevel@tonic-gate  * "complete_word" action function.
57817c478bd9Sstevel@tonic-gate  *
57827c478bd9Sstevel@tonic-gate  * Input:
57837c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of the command-line input
57847c478bd9Sstevel@tonic-gate  *                           module.
57857c478bd9Sstevel@tonic-gate  *  data             void *  This is passed to match_fn() whenever it is
57867c478bd9Sstevel@tonic-gate  *                           called. It could, for example, point to a
57877c478bd9Sstevel@tonic-gate  *                           symbol table where match_fn() could look
57887c478bd9Sstevel@tonic-gate  *                           for possible completions.
57897c478bd9Sstevel@tonic-gate  *  match_fn   CplMatchFn *  The function that will identify the prefix
57907c478bd9Sstevel@tonic-gate  *                           to be completed from the input line, and
57917c478bd9Sstevel@tonic-gate  *                           report matching symbols.
57927c478bd9Sstevel@tonic-gate  * Output:
57937c478bd9Sstevel@tonic-gate  *  return            int    0 - OK.
57947c478bd9Sstevel@tonic-gate  *                           1 - Error.
57957c478bd9Sstevel@tonic-gate  */
gl_customize_completion(GetLine * gl,void * data,CplMatchFn * match_fn)57967c478bd9Sstevel@tonic-gate int gl_customize_completion(GetLine *gl, void *data, CplMatchFn *match_fn)
57977c478bd9Sstevel@tonic-gate {
57987c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
57997c478bd9Sstevel@tonic-gate /*
58007c478bd9Sstevel@tonic-gate  * Check the arguments.
58017c478bd9Sstevel@tonic-gate  */
58027c478bd9Sstevel@tonic-gate   if(!gl || !match_fn) {
58037c478bd9Sstevel@tonic-gate     if(gl)
58047c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "NULL argument", END_ERR_MSG);
58057c478bd9Sstevel@tonic-gate     errno = EINVAL;
58067c478bd9Sstevel@tonic-gate     return 1;
58077c478bd9Sstevel@tonic-gate   };
58087c478bd9Sstevel@tonic-gate /*
58097c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
58107c478bd9Sstevel@tonic-gate  */
58117c478bd9Sstevel@tonic-gate   gl_mask_signals(gl, &oldset);
58127c478bd9Sstevel@tonic-gate /*
58137c478bd9Sstevel@tonic-gate  * Record the new completion function and its callback data.
58147c478bd9Sstevel@tonic-gate  */
58157c478bd9Sstevel@tonic-gate   gl->cplfn.fn = match_fn;
58167c478bd9Sstevel@tonic-gate   gl->cplfn.data = data;
58177c478bd9Sstevel@tonic-gate /*
58187c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
58197c478bd9Sstevel@tonic-gate  */
58207c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
58217c478bd9Sstevel@tonic-gate   return 0;
58227c478bd9Sstevel@tonic-gate }
58237c478bd9Sstevel@tonic-gate 
58247c478bd9Sstevel@tonic-gate /*.......................................................................
58257c478bd9Sstevel@tonic-gate  * Change the terminal (or stream) that getline interacts with.
58267c478bd9Sstevel@tonic-gate  *
58277c478bd9Sstevel@tonic-gate  * Input:
58287c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of the command-line input
58297c478bd9Sstevel@tonic-gate  *                           module.
58307c478bd9Sstevel@tonic-gate  *  input_fp         FILE *  The stdio stream to read from.
58317c478bd9Sstevel@tonic-gate  *  output_fp        FILE *  The stdio stream to write to.
58327c478bd9Sstevel@tonic-gate  *  term             char *  The terminal type. This can be NULL if
58337c478bd9Sstevel@tonic-gate  *                           either or both of input_fp and output_fp don't
58347c478bd9Sstevel@tonic-gate  *                           refer to a terminal. Otherwise it should refer
58357c478bd9Sstevel@tonic-gate  *                           to an entry in the terminal information database.
58367c478bd9Sstevel@tonic-gate  * Output:
58377c478bd9Sstevel@tonic-gate  *  return            int    0 - OK.
58387c478bd9Sstevel@tonic-gate  *                           1 - Error.
58397c478bd9Sstevel@tonic-gate  */
gl_change_terminal(GetLine * gl,FILE * input_fp,FILE * output_fp,const char * term)58407c478bd9Sstevel@tonic-gate int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
58417c478bd9Sstevel@tonic-gate 		       const char *term)
58427c478bd9Sstevel@tonic-gate {
58437c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
58447c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_change_terminal() */
58457c478bd9Sstevel@tonic-gate /*
58467c478bd9Sstevel@tonic-gate  * Check the arguments.
58477c478bd9Sstevel@tonic-gate  */
58487c478bd9Sstevel@tonic-gate   if(!gl) {
58497c478bd9Sstevel@tonic-gate     errno = EINVAL;
58507c478bd9Sstevel@tonic-gate     return 1;
58517c478bd9Sstevel@tonic-gate   };
58527c478bd9Sstevel@tonic-gate /*
58537c478bd9Sstevel@tonic-gate  * Block all signals.
58547c478bd9Sstevel@tonic-gate  */
58557c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
58567c478bd9Sstevel@tonic-gate     return 1;
58577c478bd9Sstevel@tonic-gate /*
58587c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
58597c478bd9Sstevel@tonic-gate  */
58607c478bd9Sstevel@tonic-gate   status = _gl_change_terminal(gl, input_fp, output_fp, term);
58617c478bd9Sstevel@tonic-gate /*
58627c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
58637c478bd9Sstevel@tonic-gate  */
58647c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
58657c478bd9Sstevel@tonic-gate   return status;
58667c478bd9Sstevel@tonic-gate }
58677c478bd9Sstevel@tonic-gate 
58687c478bd9Sstevel@tonic-gate /*.......................................................................
58697c478bd9Sstevel@tonic-gate  * This is the private body of the gl_change_terminal() function. It
58707c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
58717c478bd9Sstevel@tonic-gate  * delivery of signals.
58727c478bd9Sstevel@tonic-gate  */
_gl_change_terminal(GetLine * gl,FILE * input_fp,FILE * output_fp,const char * term)58737c478bd9Sstevel@tonic-gate static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp,
58747c478bd9Sstevel@tonic-gate 			       const char *term)
58757c478bd9Sstevel@tonic-gate {
58767c478bd9Sstevel@tonic-gate   int is_term = 0;   /* True if both input_fd and output_fd are associated */
58777c478bd9Sstevel@tonic-gate                      /*  with a terminal. */
58787c478bd9Sstevel@tonic-gate /*
58797c478bd9Sstevel@tonic-gate  * Require that input_fp and output_fp both be valid.
58807c478bd9Sstevel@tonic-gate  */
58817c478bd9Sstevel@tonic-gate   if(!input_fp || !output_fp) {
58827c478bd9Sstevel@tonic-gate     gl_print_info(gl, "Can't change terminal. Bad input/output stream(s).",
58837c478bd9Sstevel@tonic-gate 		  GL_END_INFO);
58847c478bd9Sstevel@tonic-gate     return 1;
58857c478bd9Sstevel@tonic-gate   };
58867c478bd9Sstevel@tonic-gate /*
58877c478bd9Sstevel@tonic-gate  * Are we displacing an existing terminal (as opposed to setting the
58887c478bd9Sstevel@tonic-gate  * initial terminal)?
58897c478bd9Sstevel@tonic-gate  */
58907c478bd9Sstevel@tonic-gate   if(gl->input_fd >= 0) {
58917c478bd9Sstevel@tonic-gate /*
58927c478bd9Sstevel@tonic-gate  * Make sure to leave the previous terminal in a usable state.
58937c478bd9Sstevel@tonic-gate  */
58947c478bd9Sstevel@tonic-gate     if(_gl_normal_io(gl))
58957c478bd9Sstevel@tonic-gate       return 1;
58967c478bd9Sstevel@tonic-gate /*
58977c478bd9Sstevel@tonic-gate  * Remove the displaced terminal from the list of fds to watch.
58987c478bd9Sstevel@tonic-gate  */
58997c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
59007c478bd9Sstevel@tonic-gate     FD_CLR(gl->input_fd, &gl->rfds);
59017c478bd9Sstevel@tonic-gate #endif
59027c478bd9Sstevel@tonic-gate   };
59037c478bd9Sstevel@tonic-gate /*
59047c478bd9Sstevel@tonic-gate  * Record the file descriptors and streams.
59057c478bd9Sstevel@tonic-gate  */
59067c478bd9Sstevel@tonic-gate   gl->input_fp = input_fp;
59077c478bd9Sstevel@tonic-gate   gl->input_fd = fileno(input_fp);
59087c478bd9Sstevel@tonic-gate   gl->output_fp = output_fp;
59097c478bd9Sstevel@tonic-gate   gl->output_fd = fileno(output_fp);
59107c478bd9Sstevel@tonic-gate /*
59117c478bd9Sstevel@tonic-gate  * If needed, expand the record of the maximum file-descriptor that might
59127c478bd9Sstevel@tonic-gate  * need to be monitored with select().
59137c478bd9Sstevel@tonic-gate  */
59147c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
59157c478bd9Sstevel@tonic-gate   if(gl->input_fd > gl->max_fd)
59167c478bd9Sstevel@tonic-gate     gl->max_fd = gl->input_fd;
59177c478bd9Sstevel@tonic-gate #endif
59187c478bd9Sstevel@tonic-gate /*
59197c478bd9Sstevel@tonic-gate  * Disable terminal interaction until we have enough info to interact
59207c478bd9Sstevel@tonic-gate  * with the terminal.
59217c478bd9Sstevel@tonic-gate  */
59227c478bd9Sstevel@tonic-gate   gl->is_term = 0;
59237c478bd9Sstevel@tonic-gate /*
59247c478bd9Sstevel@tonic-gate  * For terminal editing, we need both output_fd and input_fd to refer to
59257c478bd9Sstevel@tonic-gate  * a terminal. While we can't verify that they both point to the same
59267c478bd9Sstevel@tonic-gate  * terminal, we can verify that they point to terminals.
59277c478bd9Sstevel@tonic-gate  */
59287c478bd9Sstevel@tonic-gate   is_term = isatty(gl->input_fd) && isatty(gl->output_fd);
59297c478bd9Sstevel@tonic-gate /*
59307c478bd9Sstevel@tonic-gate  * If we are interacting with a terminal and no terminal type has been
59317c478bd9Sstevel@tonic-gate  * specified, treat it as a generic ANSI terminal.
59327c478bd9Sstevel@tonic-gate  */
59337c478bd9Sstevel@tonic-gate   if(is_term && !term)
59347c478bd9Sstevel@tonic-gate     term = "ansi";
59357c478bd9Sstevel@tonic-gate /*
59367c478bd9Sstevel@tonic-gate  * Make a copy of the terminal type string.
59377c478bd9Sstevel@tonic-gate  */
59387c478bd9Sstevel@tonic-gate   if(term != gl->term) {
59397c478bd9Sstevel@tonic-gate /*
59407c478bd9Sstevel@tonic-gate  * Delete any old terminal type string.
59417c478bd9Sstevel@tonic-gate  */
59427c478bd9Sstevel@tonic-gate     if(gl->term) {
59437c478bd9Sstevel@tonic-gate       free(gl->term);
59447c478bd9Sstevel@tonic-gate       gl->term = NULL;
59457c478bd9Sstevel@tonic-gate     };
59467c478bd9Sstevel@tonic-gate /*
59477c478bd9Sstevel@tonic-gate  * Make a copy of the new terminal-type string, if any.
59487c478bd9Sstevel@tonic-gate  */
59497c478bd9Sstevel@tonic-gate     if(term) {
59507c478bd9Sstevel@tonic-gate       size_t termsz = strlen(term)+1;
59517c478bd9Sstevel@tonic-gate 
59527c478bd9Sstevel@tonic-gate       gl->term = (char *) malloc(termsz);
59537c478bd9Sstevel@tonic-gate       if(gl->term)
59547c478bd9Sstevel@tonic-gate 	strlcpy(gl->term, term, termsz);
59557c478bd9Sstevel@tonic-gate     };
59567c478bd9Sstevel@tonic-gate   };
59577c478bd9Sstevel@tonic-gate /*
59587c478bd9Sstevel@tonic-gate  * Clear any terminal-specific key bindings that were taken from the
59597c478bd9Sstevel@tonic-gate  * settings of the last terminal.
59607c478bd9Sstevel@tonic-gate  */
59617c478bd9Sstevel@tonic-gate   _kt_clear_bindings(gl->bindings, KTB_TERM);
59627c478bd9Sstevel@tonic-gate /*
59637c478bd9Sstevel@tonic-gate  * If we have a terminal install new bindings for it.
59647c478bd9Sstevel@tonic-gate  */
59657c478bd9Sstevel@tonic-gate   if(is_term) {
59667c478bd9Sstevel@tonic-gate /*
59677c478bd9Sstevel@tonic-gate  * Get the current settings of the terminal.
59687c478bd9Sstevel@tonic-gate  */
59697c478bd9Sstevel@tonic-gate     if(tcgetattr(gl->input_fd, &gl->oldattr)) {
59707c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
59717c478bd9Sstevel@tonic-gate       return 1;
59727c478bd9Sstevel@tonic-gate     };
59737c478bd9Sstevel@tonic-gate /*
59747c478bd9Sstevel@tonic-gate  * If we don't set this now, gl_control_strings() won't know
59757c478bd9Sstevel@tonic-gate  * that it is talking to a terminal.
59767c478bd9Sstevel@tonic-gate  */
59777c478bd9Sstevel@tonic-gate     gl->is_term = 1;
59787c478bd9Sstevel@tonic-gate /*
59797c478bd9Sstevel@tonic-gate  * Lookup the terminal control string and size information.
59807c478bd9Sstevel@tonic-gate  */
59817c478bd9Sstevel@tonic-gate     if(gl_control_strings(gl, term)) {
59827c478bd9Sstevel@tonic-gate       gl->is_term = 0;
59837c478bd9Sstevel@tonic-gate       return 1;
59847c478bd9Sstevel@tonic-gate     };
59857c478bd9Sstevel@tonic-gate /*
59867c478bd9Sstevel@tonic-gate  * Bind terminal-specific keys.
59877c478bd9Sstevel@tonic-gate  */
59887c478bd9Sstevel@tonic-gate     if(gl_bind_terminal_keys(gl))
59897c478bd9Sstevel@tonic-gate       return 1;
59907c478bd9Sstevel@tonic-gate   };
59917c478bd9Sstevel@tonic-gate /*
59927c478bd9Sstevel@tonic-gate  * Assume that the caller has given us a terminal in a sane state.
59937c478bd9Sstevel@tonic-gate  */
59947c478bd9Sstevel@tonic-gate   gl->io_mode = GL_NORMAL_MODE;
59957c478bd9Sstevel@tonic-gate /*
59967c478bd9Sstevel@tonic-gate  * Switch into the currently configured I/O mode.
59977c478bd9Sstevel@tonic-gate  */
59987c478bd9Sstevel@tonic-gate   if(_gl_io_mode(gl, gl->io_mode))
59997c478bd9Sstevel@tonic-gate     return 1;
60007c478bd9Sstevel@tonic-gate   return 0;
60017c478bd9Sstevel@tonic-gate }
60027c478bd9Sstevel@tonic-gate 
60037c478bd9Sstevel@tonic-gate /*.......................................................................
60047c478bd9Sstevel@tonic-gate  * Set up terminal-specific key bindings.
60057c478bd9Sstevel@tonic-gate  *
60067c478bd9Sstevel@tonic-gate  * Input:
60077c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of the command-line input
60087c478bd9Sstevel@tonic-gate  *                           module.
60097c478bd9Sstevel@tonic-gate  * Output:
60107c478bd9Sstevel@tonic-gate  *  return            int    0 - OK.
60117c478bd9Sstevel@tonic-gate  *                           1 - Error.
60127c478bd9Sstevel@tonic-gate  */
gl_bind_terminal_keys(GetLine * gl)60137c478bd9Sstevel@tonic-gate static int gl_bind_terminal_keys(GetLine *gl)
60147c478bd9Sstevel@tonic-gate {
60157c478bd9Sstevel@tonic-gate /*
60167c478bd9Sstevel@tonic-gate  * Install key-bindings for the special terminal characters.
60177c478bd9Sstevel@tonic-gate  */
60187c478bd9Sstevel@tonic-gate   if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VINTR],
60197c478bd9Sstevel@tonic-gate 			  "user-interrupt") ||
60207c478bd9Sstevel@tonic-gate      gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VQUIT], "abort") ||
60217c478bd9Sstevel@tonic-gate      gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VSUSP], "suspend"))
60227c478bd9Sstevel@tonic-gate     return 1;
60237c478bd9Sstevel@tonic-gate /*
60247c478bd9Sstevel@tonic-gate  * In vi-mode, arrange for the above characters to be seen in command
60257c478bd9Sstevel@tonic-gate  * mode.
60267c478bd9Sstevel@tonic-gate  */
60277c478bd9Sstevel@tonic-gate   if(gl->editor == GL_VI_MODE) {
60287c478bd9Sstevel@tonic-gate     if(gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VINTR]),
60297c478bd9Sstevel@tonic-gate 			    "user-interrupt") ||
60307c478bd9Sstevel@tonic-gate        gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VQUIT]),
60317c478bd9Sstevel@tonic-gate 			    "abort") ||
60327c478bd9Sstevel@tonic-gate        gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VSUSP]),
60337c478bd9Sstevel@tonic-gate 			    "suspend"))
60347c478bd9Sstevel@tonic-gate       return 1;
60357c478bd9Sstevel@tonic-gate   };
60367c478bd9Sstevel@tonic-gate /*
60377c478bd9Sstevel@tonic-gate  * Non-universal special keys.
60387c478bd9Sstevel@tonic-gate  */
60397c478bd9Sstevel@tonic-gate #ifdef VLNEXT
60407c478bd9Sstevel@tonic-gate   if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VLNEXT],
60417c478bd9Sstevel@tonic-gate 			  "literal-next"))
60427c478bd9Sstevel@tonic-gate     return 1;
60437c478bd9Sstevel@tonic-gate #else
60447c478bd9Sstevel@tonic-gate   if(_kt_set_keybinding(gl->bindings, KTB_TERM, "^V", "literal-next")) {
60457c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
60467c478bd9Sstevel@tonic-gate     return 1;
60477c478bd9Sstevel@tonic-gate   };
60487c478bd9Sstevel@tonic-gate #endif
60497c478bd9Sstevel@tonic-gate /*
60507c478bd9Sstevel@tonic-gate  * Bind action functions to the terminal-specific arrow keys
60517c478bd9Sstevel@tonic-gate  * looked up by gl_control_strings().
60527c478bd9Sstevel@tonic-gate  */
60537c478bd9Sstevel@tonic-gate   if(_gl_bind_arrow_keys(gl))
60547c478bd9Sstevel@tonic-gate     return 1;
60557c478bd9Sstevel@tonic-gate   return 0;
60567c478bd9Sstevel@tonic-gate }
60577c478bd9Sstevel@tonic-gate 
60587c478bd9Sstevel@tonic-gate /*.......................................................................
60597c478bd9Sstevel@tonic-gate  * This function is normally bound to control-D. When it is invoked within
60607c478bd9Sstevel@tonic-gate  * a line it deletes the character which follows the cursor. When invoked
60617c478bd9Sstevel@tonic-gate  * at the end of the line it lists possible file completions, and when
60627c478bd9Sstevel@tonic-gate  * invoked on an empty line it causes gl_get_line() to return EOF. This
60637c478bd9Sstevel@tonic-gate  * function emulates the one that is normally bound to control-D by tcsh.
60647c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_del_char_or_list_or_eof)60657c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_del_char_or_list_or_eof)
60667c478bd9Sstevel@tonic-gate {
60677c478bd9Sstevel@tonic-gate /*
60687c478bd9Sstevel@tonic-gate  * If we have an empty line arrange to return EOF.
60697c478bd9Sstevel@tonic-gate  */
60707c478bd9Sstevel@tonic-gate   if(gl->ntotal < 1) {
60717c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_EOF, 0);
60727c478bd9Sstevel@tonic-gate     return 1;
60737c478bd9Sstevel@tonic-gate /*
60747c478bd9Sstevel@tonic-gate  * If we are at the end of the line list possible completions.
60757c478bd9Sstevel@tonic-gate  */
60767c478bd9Sstevel@tonic-gate   } else if(gl->buff_curpos >= gl->ntotal) {
60777c478bd9Sstevel@tonic-gate     return gl_list_completions(gl, 1, NULL);
60787c478bd9Sstevel@tonic-gate /*
60797c478bd9Sstevel@tonic-gate  * Within the line delete the character that follows the cursor.
60807c478bd9Sstevel@tonic-gate  */
60817c478bd9Sstevel@tonic-gate   } else {
60827c478bd9Sstevel@tonic-gate /*
60837c478bd9Sstevel@tonic-gate  * If in vi command mode, first preserve the current line for potential use
60847c478bd9Sstevel@tonic-gate  * by vi-undo.
60857c478bd9Sstevel@tonic-gate  */
60867c478bd9Sstevel@tonic-gate     gl_save_for_undo(gl);
60877c478bd9Sstevel@tonic-gate /*
60887c478bd9Sstevel@tonic-gate  * Delete 'count' characters.
60897c478bd9Sstevel@tonic-gate  */
60907c478bd9Sstevel@tonic-gate     return gl_forward_delete_char(gl, count, NULL);
60917c478bd9Sstevel@tonic-gate   };
60927c478bd9Sstevel@tonic-gate }
60937c478bd9Sstevel@tonic-gate 
60947c478bd9Sstevel@tonic-gate /*.......................................................................
60957c478bd9Sstevel@tonic-gate  * This function is normally bound to control-D in vi mode. When it is
60967c478bd9Sstevel@tonic-gate  * invoked within a line it lists possible file completions, and when
60977c478bd9Sstevel@tonic-gate  * invoked on an empty line it causes gl_get_line() to return EOF. This
60987c478bd9Sstevel@tonic-gate  * function emulates the one that is normally bound to control-D by tcsh.
60997c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_list_or_eof)61007c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_or_eof)
61017c478bd9Sstevel@tonic-gate {
61027c478bd9Sstevel@tonic-gate /*
61037c478bd9Sstevel@tonic-gate  * If we have an empty line arrange to return EOF.
61047c478bd9Sstevel@tonic-gate  */
61057c478bd9Sstevel@tonic-gate   if(gl->ntotal < 1) {
61067c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_EOF, 0);
61077c478bd9Sstevel@tonic-gate     return 1;
61087c478bd9Sstevel@tonic-gate /*
61097c478bd9Sstevel@tonic-gate  * Otherwise list possible completions.
61107c478bd9Sstevel@tonic-gate  */
61117c478bd9Sstevel@tonic-gate   } else {
61127c478bd9Sstevel@tonic-gate     return gl_list_completions(gl, 1, NULL);
61137c478bd9Sstevel@tonic-gate   };
61147c478bd9Sstevel@tonic-gate }
61157c478bd9Sstevel@tonic-gate 
61167c478bd9Sstevel@tonic-gate /*.......................................................................
61177c478bd9Sstevel@tonic-gate  * List possible completions of the word that precedes the cursor. The
61187c478bd9Sstevel@tonic-gate  * callback data argument must either be NULL to select the default
61197c478bd9Sstevel@tonic-gate  * file completion callback, or be a GlCplCallback object containing the
61207c478bd9Sstevel@tonic-gate  * completion callback function to call.
61217c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_list_completions)61227c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_completions)
61237c478bd9Sstevel@tonic-gate {
61247c478bd9Sstevel@tonic-gate   int waserr = 0;   /* True after errors */
61257c478bd9Sstevel@tonic-gate /*
61267c478bd9Sstevel@tonic-gate  * Get the container of the completion callback and its callback data.
61277c478bd9Sstevel@tonic-gate  */
61287c478bd9Sstevel@tonic-gate   GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn;
61297c478bd9Sstevel@tonic-gate /*
61307c478bd9Sstevel@tonic-gate  * Get the list of possible completions.
61317c478bd9Sstevel@tonic-gate  */
61327c478bd9Sstevel@tonic-gate   CplMatches *matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos,
61337c478bd9Sstevel@tonic-gate 					  cb->data, cb->fn);
61347c478bd9Sstevel@tonic-gate /*
61357c478bd9Sstevel@tonic-gate  * No matching completions?
61367c478bd9Sstevel@tonic-gate  */
61377c478bd9Sstevel@tonic-gate   if(!matches) {
61387c478bd9Sstevel@tonic-gate     waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO);
61397c478bd9Sstevel@tonic-gate /*
61407c478bd9Sstevel@tonic-gate  * List the matches.
61417c478bd9Sstevel@tonic-gate  */
61427c478bd9Sstevel@tonic-gate   } else if(matches->nmatch > 0 && gl->echo) {
61437c478bd9Sstevel@tonic-gate     if(_gl_normal_io(gl) ||
61447c478bd9Sstevel@tonic-gate        _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn))
61457c478bd9Sstevel@tonic-gate       waserr = 1;
61467c478bd9Sstevel@tonic-gate   };
61477c478bd9Sstevel@tonic-gate /*
61487c478bd9Sstevel@tonic-gate  * If any output had to be written to the terminal, then editing will
61497c478bd9Sstevel@tonic-gate  * have been suspended, make sure that we are back in raw line editing
61507c478bd9Sstevel@tonic-gate  * mode before returning.
61517c478bd9Sstevel@tonic-gate  */
61527c478bd9Sstevel@tonic-gate   if(_gl_raw_io(gl, 1))
61537c478bd9Sstevel@tonic-gate     waserr = 1;
61547c478bd9Sstevel@tonic-gate   return waserr;
61557c478bd9Sstevel@tonic-gate }
61567c478bd9Sstevel@tonic-gate 
61577c478bd9Sstevel@tonic-gate /*.......................................................................
61587c478bd9Sstevel@tonic-gate  * Where the user has used the symbolic arrow-key names to specify
61597c478bd9Sstevel@tonic-gate  * arrow key bindings, bind the specified action functions to the default
61607c478bd9Sstevel@tonic-gate  * and terminal specific arrow key sequences.
61617c478bd9Sstevel@tonic-gate  *
61627c478bd9Sstevel@tonic-gate  * Input:
61637c478bd9Sstevel@tonic-gate  *  gl     GetLine *   The getline resource object.
61647c478bd9Sstevel@tonic-gate  * Output:
61657c478bd9Sstevel@tonic-gate  *  return     int     0 - OK.
61667c478bd9Sstevel@tonic-gate  *                     1 - Error.
61677c478bd9Sstevel@tonic-gate  */
_gl_bind_arrow_keys(GetLine * gl)61687c478bd9Sstevel@tonic-gate static int _gl_bind_arrow_keys(GetLine *gl)
61697c478bd9Sstevel@tonic-gate {
61707c478bd9Sstevel@tonic-gate /*
61717c478bd9Sstevel@tonic-gate  * Process each of the arrow keys.
61727c478bd9Sstevel@tonic-gate  */
61737c478bd9Sstevel@tonic-gate   if(_gl_rebind_arrow_key(gl, "up", gl->u_arrow, "^[[A", "^[OA") ||
61747c478bd9Sstevel@tonic-gate      _gl_rebind_arrow_key(gl, "down", gl->d_arrow, "^[[B", "^[OB") ||
61757c478bd9Sstevel@tonic-gate      _gl_rebind_arrow_key(gl, "left", gl->l_arrow, "^[[D", "^[OD") ||
61767c478bd9Sstevel@tonic-gate      _gl_rebind_arrow_key(gl, "right", gl->r_arrow, "^[[C", "^[OC"))
61777c478bd9Sstevel@tonic-gate     return 1;
61787c478bd9Sstevel@tonic-gate   return 0;
61797c478bd9Sstevel@tonic-gate }
61807c478bd9Sstevel@tonic-gate 
61817c478bd9Sstevel@tonic-gate /*.......................................................................
61827c478bd9Sstevel@tonic-gate  * Lookup the action function of a symbolic arrow-key binding, and bind
61837c478bd9Sstevel@tonic-gate  * it to the terminal-specific and default arrow-key sequences. Note that
61847c478bd9Sstevel@tonic-gate  * we don't trust the terminal-specified key sequences to be correct.
61857c478bd9Sstevel@tonic-gate  * The main reason for this is that on some machines the xterm terminfo
61867c478bd9Sstevel@tonic-gate  * entry is for hardware X-terminals, rather than xterm terminal emulators
61877c478bd9Sstevel@tonic-gate  * and the two terminal types emit different character sequences when the
61887c478bd9Sstevel@tonic-gate  * their cursor keys are pressed. As a result we also supply a couple
61897c478bd9Sstevel@tonic-gate  * of default key sequences.
61907c478bd9Sstevel@tonic-gate  *
61917c478bd9Sstevel@tonic-gate  * Input:
61927c478bd9Sstevel@tonic-gate  *  gl          GetLine *   The resource object of gl_get_line().
61937c478bd9Sstevel@tonic-gate  *  name           char *   The symbolic name of the arrow key.
61947c478bd9Sstevel@tonic-gate  *  term_seq       char *   The terminal-specific arrow-key sequence.
61957c478bd9Sstevel@tonic-gate  *  def_seq1       char *   The first default arrow-key sequence.
61967c478bd9Sstevel@tonic-gate  *  def_seq2       char *   The second arrow-key sequence.
61977c478bd9Sstevel@tonic-gate  * Output:
61987c478bd9Sstevel@tonic-gate  *  return          int     0 - OK.
61997c478bd9Sstevel@tonic-gate  *                          1 - Error.
62007c478bd9Sstevel@tonic-gate  */
_gl_rebind_arrow_key(GetLine * gl,const char * name,const char * term_seq,const char * def_seq1,const char * def_seq2)62017c478bd9Sstevel@tonic-gate static int _gl_rebind_arrow_key(GetLine *gl, const char *name,
62027c478bd9Sstevel@tonic-gate 				const char *term_seq, const char *def_seq1,
62037c478bd9Sstevel@tonic-gate 				const char *def_seq2)
62047c478bd9Sstevel@tonic-gate {
62057c478bd9Sstevel@tonic-gate   KeySym *keysym;  /* The binding-table entry matching the arrow-key name */
62067c478bd9Sstevel@tonic-gate   int nsym;        /* The number of ambiguous matches */
62077c478bd9Sstevel@tonic-gate /*
62087c478bd9Sstevel@tonic-gate  * Lookup the key binding for the symbolic name of the arrow key. This
62097c478bd9Sstevel@tonic-gate  * will either be the default action, or a user provided one.
62107c478bd9Sstevel@tonic-gate  */
62117c478bd9Sstevel@tonic-gate   if(_kt_lookup_keybinding(gl->bindings, name, strlen(name), &keysym, &nsym)
62127c478bd9Sstevel@tonic-gate      == KT_EXACT_MATCH) {
62137c478bd9Sstevel@tonic-gate /*
62147c478bd9Sstevel@tonic-gate  * Get the action function.
62157c478bd9Sstevel@tonic-gate  */
62167c478bd9Sstevel@tonic-gate     KtAction *action = keysym->actions + keysym->binder;
62177c478bd9Sstevel@tonic-gate     KtKeyFn *fn = action->fn;
62187c478bd9Sstevel@tonic-gate     void *data = action->data;
62197c478bd9Sstevel@tonic-gate /*
62207c478bd9Sstevel@tonic-gate  * Bind this to each of the specified key sequences.
62217c478bd9Sstevel@tonic-gate  */
62227c478bd9Sstevel@tonic-gate     if((term_seq &&
62237c478bd9Sstevel@tonic-gate 	_kt_set_keyfn(gl->bindings, KTB_TERM, term_seq, fn, data)) ||
62247c478bd9Sstevel@tonic-gate        (def_seq1 &&
62257c478bd9Sstevel@tonic-gate 	_kt_set_keyfn(gl->bindings, KTB_NORM, def_seq1, fn, data)) ||
62267c478bd9Sstevel@tonic-gate        (def_seq2 &&
62277c478bd9Sstevel@tonic-gate 	_kt_set_keyfn(gl->bindings, KTB_NORM, def_seq2, fn, data))) {
62287c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
62297c478bd9Sstevel@tonic-gate       return 1;
62307c478bd9Sstevel@tonic-gate     };
62317c478bd9Sstevel@tonic-gate   };
62327c478bd9Sstevel@tonic-gate   return 0;
62337c478bd9Sstevel@tonic-gate }
62347c478bd9Sstevel@tonic-gate 
62357c478bd9Sstevel@tonic-gate /*.......................................................................
62367c478bd9Sstevel@tonic-gate  * Read getline configuration information from a given file.
62377c478bd9Sstevel@tonic-gate  *
62387c478bd9Sstevel@tonic-gate  * Input:
62397c478bd9Sstevel@tonic-gate  *  gl           GetLine *  The getline resource object.
62407c478bd9Sstevel@tonic-gate  *  filename  const char *  The name of the file to read configuration
62417c478bd9Sstevel@tonic-gate  *                          information from. The contents of this file
62427c478bd9Sstevel@tonic-gate  *                          are as described in the gl_get_line(3) man
62437c478bd9Sstevel@tonic-gate  *                          page for the default ~/.teclarc configuration
62447c478bd9Sstevel@tonic-gate  *                          file.
62457c478bd9Sstevel@tonic-gate  *  who         KtBinder    Who bindings are to be installed for.
62467c478bd9Sstevel@tonic-gate  * Output:
62477c478bd9Sstevel@tonic-gate  *  return           int    0 - OK.
62487c478bd9Sstevel@tonic-gate  *                          1 - Irrecoverable error.
62497c478bd9Sstevel@tonic-gate  */
_gl_read_config_file(GetLine * gl,const char * filename,KtBinder who)62507c478bd9Sstevel@tonic-gate static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who)
62517c478bd9Sstevel@tonic-gate {
62527c478bd9Sstevel@tonic-gate /*
62537c478bd9Sstevel@tonic-gate  * If filesystem access is to be excluded, configuration files can't
62547c478bd9Sstevel@tonic-gate  * be read.
62557c478bd9Sstevel@tonic-gate  */
62567c478bd9Sstevel@tonic-gate #ifdef WITHOUT_FILE_SYSTEM
62577c478bd9Sstevel@tonic-gate   _err_record_msg(gl->err,
62587c478bd9Sstevel@tonic-gate 		  "Can't read configuration files without filesystem access",
62597c478bd9Sstevel@tonic-gate 		  END_ERR_MSG);
62607c478bd9Sstevel@tonic-gate   errno = EINVAL;
62617c478bd9Sstevel@tonic-gate   return 1;
62627c478bd9Sstevel@tonic-gate #else
62637c478bd9Sstevel@tonic-gate   FileExpansion *expansion; /* The expansion of the filename */
62647c478bd9Sstevel@tonic-gate   FILE *fp;                 /* The opened file */
62657c478bd9Sstevel@tonic-gate   int waserr = 0;           /* True if an error occurred while reading */
62667c478bd9Sstevel@tonic-gate   int lineno = 1;           /* The line number being processed */
62677c478bd9Sstevel@tonic-gate /*
62687c478bd9Sstevel@tonic-gate  * Check the arguments.
62697c478bd9Sstevel@tonic-gate  */
62707c478bd9Sstevel@tonic-gate   if(!gl || !filename) {
62717c478bd9Sstevel@tonic-gate     if(gl)
62727c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
62737c478bd9Sstevel@tonic-gate     errno = EINVAL;
62747c478bd9Sstevel@tonic-gate     return 1;
62757c478bd9Sstevel@tonic-gate   };
62767c478bd9Sstevel@tonic-gate /*
62777c478bd9Sstevel@tonic-gate  * Expand the filename.
62787c478bd9Sstevel@tonic-gate  */
62797c478bd9Sstevel@tonic-gate   expansion = ef_expand_file(gl->ef, filename, -1);
62807c478bd9Sstevel@tonic-gate   if(!expansion) {
62817c478bd9Sstevel@tonic-gate     gl_print_info(gl, "Unable to expand ", filename, " (",
62827c478bd9Sstevel@tonic-gate 		  ef_last_error(gl->ef), ").", GL_END_INFO);
62837c478bd9Sstevel@tonic-gate     return 1;
62847c478bd9Sstevel@tonic-gate   };
62857c478bd9Sstevel@tonic-gate /*
62867c478bd9Sstevel@tonic-gate  * Attempt to open the file.
62877c478bd9Sstevel@tonic-gate  */
62887c478bd9Sstevel@tonic-gate   fp = fopen(expansion->files[0], "r");
62897c478bd9Sstevel@tonic-gate /*
62907c478bd9Sstevel@tonic-gate  * It isn't an error for there to be no configuration file.
62917c478bd9Sstevel@tonic-gate  */
62927c478bd9Sstevel@tonic-gate   if(!fp)
62937c478bd9Sstevel@tonic-gate     return 0;
62947c478bd9Sstevel@tonic-gate /*
62957c478bd9Sstevel@tonic-gate  * Parse the contents of the file.
62967c478bd9Sstevel@tonic-gate  */
62977c478bd9Sstevel@tonic-gate   while(!waserr && !feof(fp))
62987c478bd9Sstevel@tonic-gate     waserr = _gl_parse_config_line(gl, fp, glc_file_getc, filename, who,
62997c478bd9Sstevel@tonic-gate 				   &lineno);
63007c478bd9Sstevel@tonic-gate /*
63017c478bd9Sstevel@tonic-gate  * Bind action functions to the terminal-specific arrow keys.
63027c478bd9Sstevel@tonic-gate  */
63037c478bd9Sstevel@tonic-gate   if(_gl_bind_arrow_keys(gl))
63047c478bd9Sstevel@tonic-gate     return 1;
63057c478bd9Sstevel@tonic-gate /*
63067c478bd9Sstevel@tonic-gate  * Clean up.
63077c478bd9Sstevel@tonic-gate  */
63087c478bd9Sstevel@tonic-gate   (void) fclose(fp);
63097c478bd9Sstevel@tonic-gate   return waserr;
63107c478bd9Sstevel@tonic-gate #endif
63117c478bd9Sstevel@tonic-gate }
63127c478bd9Sstevel@tonic-gate 
63137c478bd9Sstevel@tonic-gate /*.......................................................................
63147c478bd9Sstevel@tonic-gate  * Read GetLine configuration information from a string. The contents of
63157c478bd9Sstevel@tonic-gate  * the string are the same as those described in the gl_get_line(3)
63167c478bd9Sstevel@tonic-gate  * man page for the contents of the ~/.teclarc configuration file.
63177c478bd9Sstevel@tonic-gate  */
_gl_read_config_string(GetLine * gl,const char * buffer,KtBinder who)63187c478bd9Sstevel@tonic-gate static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who)
63197c478bd9Sstevel@tonic-gate {
63207c478bd9Sstevel@tonic-gate   const char *bptr;         /* A pointer into buffer[] */
63217c478bd9Sstevel@tonic-gate   int waserr = 0;           /* True if an error occurred while reading */
63227c478bd9Sstevel@tonic-gate   int lineno = 1;           /* The line number being processed */
63237c478bd9Sstevel@tonic-gate /*
63247c478bd9Sstevel@tonic-gate  * Check the arguments.
63257c478bd9Sstevel@tonic-gate  */
63267c478bd9Sstevel@tonic-gate   if(!gl || !buffer) {
63277c478bd9Sstevel@tonic-gate     if(gl)
63287c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
63297c478bd9Sstevel@tonic-gate     errno = EINVAL;
63307c478bd9Sstevel@tonic-gate     return 1;
63317c478bd9Sstevel@tonic-gate   };
63327c478bd9Sstevel@tonic-gate /*
63337c478bd9Sstevel@tonic-gate  * Get a pointer to the start of the buffer.
63347c478bd9Sstevel@tonic-gate  */
63357c478bd9Sstevel@tonic-gate   bptr = buffer;
63367c478bd9Sstevel@tonic-gate /*
63377c478bd9Sstevel@tonic-gate  * Parse the contents of the buffer.
63387c478bd9Sstevel@tonic-gate  */
63397c478bd9Sstevel@tonic-gate   while(!waserr && *bptr)
63407c478bd9Sstevel@tonic-gate     waserr = _gl_parse_config_line(gl, &bptr, glc_buff_getc, "", who, &lineno);
63417c478bd9Sstevel@tonic-gate /*
63427c478bd9Sstevel@tonic-gate  * Bind action functions to the terminal-specific arrow keys.
63437c478bd9Sstevel@tonic-gate  */
63447c478bd9Sstevel@tonic-gate   if(_gl_bind_arrow_keys(gl))
63457c478bd9Sstevel@tonic-gate     return 1;
63467c478bd9Sstevel@tonic-gate   return waserr;
63477c478bd9Sstevel@tonic-gate }
63487c478bd9Sstevel@tonic-gate 
63497c478bd9Sstevel@tonic-gate /*.......................................................................
63507c478bd9Sstevel@tonic-gate  * Parse the next line of a getline configuration file.
63517c478bd9Sstevel@tonic-gate  *
63527c478bd9Sstevel@tonic-gate  * Input:
63537c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The getline resource object.
63547c478bd9Sstevel@tonic-gate  *  stream        void *  The pointer representing the stream to be read
63557c478bd9Sstevel@tonic-gate  *                        by getc_fn().
63567c478bd9Sstevel@tonic-gate  *  getc_fn  GlcGetcFn *  A callback function which when called with
63577c478bd9Sstevel@tonic-gate  *                       'stream' as its argument, returns the next
63587c478bd9Sstevel@tonic-gate  *                        unread character from the stream.
63597c478bd9Sstevel@tonic-gate  *  origin  const char *  The name of the entity being read (eg. a
63607c478bd9Sstevel@tonic-gate  *                        file name).
63617c478bd9Sstevel@tonic-gate  *  who       KtBinder    Who bindings are to be installed for.
63627c478bd9Sstevel@tonic-gate  * Input/Output:
63637c478bd9Sstevel@tonic-gate  *  lineno         int *  The line number being processed is to be
63647c478bd9Sstevel@tonic-gate  *                        maintained in *lineno.
63657c478bd9Sstevel@tonic-gate  * Output:
63667c478bd9Sstevel@tonic-gate  *  return         int    0 - OK.
63677c478bd9Sstevel@tonic-gate  *                        1 - Irrecoverable error.
63687c478bd9Sstevel@tonic-gate  */
_gl_parse_config_line(GetLine * gl,void * stream,GlcGetcFn * getc_fn,const char * origin,KtBinder who,int * lineno)63697c478bd9Sstevel@tonic-gate static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn,
63707c478bd9Sstevel@tonic-gate 				 const char *origin, KtBinder who, int *lineno)
63717c478bd9Sstevel@tonic-gate {
63727c478bd9Sstevel@tonic-gate   char buffer[GL_CONF_BUFLEN+1];  /* The input line buffer */
63737c478bd9Sstevel@tonic-gate   char *argv[GL_CONF_MAXARG];     /* The argument list */
63747c478bd9Sstevel@tonic-gate   int argc = 0;                   /* The number of arguments in argv[] */
63757c478bd9Sstevel@tonic-gate   int c;                          /* A character from the file */
63767c478bd9Sstevel@tonic-gate   int escaped = 0;                /* True if the next character is escaped */
63777c478bd9Sstevel@tonic-gate   int i;
63787c478bd9Sstevel@tonic-gate /*
63797c478bd9Sstevel@tonic-gate  * Skip spaces and tabs.
63807c478bd9Sstevel@tonic-gate  */
63817c478bd9Sstevel@tonic-gate   do c = getc_fn(stream); while(c==' ' || c=='\t');
63827c478bd9Sstevel@tonic-gate /*
63837c478bd9Sstevel@tonic-gate  * Comments extend to the end of the line.
63847c478bd9Sstevel@tonic-gate  */
63857c478bd9Sstevel@tonic-gate   if(c=='#')
63867c478bd9Sstevel@tonic-gate     do c = getc_fn(stream); while(c != '\n' && c != EOF);
63877c478bd9Sstevel@tonic-gate /*
63887c478bd9Sstevel@tonic-gate  * Ignore empty lines.
63897c478bd9Sstevel@tonic-gate  */
63907c478bd9Sstevel@tonic-gate   if(c=='\n' || c==EOF) {
63917c478bd9Sstevel@tonic-gate     (*lineno)++;
63927c478bd9Sstevel@tonic-gate     return 0;
63937c478bd9Sstevel@tonic-gate   };
63947c478bd9Sstevel@tonic-gate /*
63957c478bd9Sstevel@tonic-gate  * Record the buffer location of the start of the first argument.
63967c478bd9Sstevel@tonic-gate  */
63977c478bd9Sstevel@tonic-gate   argv[argc] = buffer;
63987c478bd9Sstevel@tonic-gate /*
63997c478bd9Sstevel@tonic-gate  * Read the rest of the line, stopping early if a comment is seen, or
64007c478bd9Sstevel@tonic-gate  * the buffer overflows, and replacing sequences of spaces with a
64017c478bd9Sstevel@tonic-gate  * '\0', and recording the thus terminated string as an argument.
64027c478bd9Sstevel@tonic-gate  */
64037c478bd9Sstevel@tonic-gate   i = 0;
64047c478bd9Sstevel@tonic-gate   while(i<GL_CONF_BUFLEN) {
64057c478bd9Sstevel@tonic-gate /*
64067c478bd9Sstevel@tonic-gate  * Did we hit the end of the latest argument?
64077c478bd9Sstevel@tonic-gate  */
64087c478bd9Sstevel@tonic-gate     if(c==EOF || (!escaped && (c==' ' || c=='\n' || c=='\t' || c=='#'))) {
64097c478bd9Sstevel@tonic-gate /*
64107c478bd9Sstevel@tonic-gate  * Terminate the argument.
64117c478bd9Sstevel@tonic-gate  */
64127c478bd9Sstevel@tonic-gate       buffer[i++] = '\0';
64137c478bd9Sstevel@tonic-gate       argc++;
64147c478bd9Sstevel@tonic-gate /*
64157c478bd9Sstevel@tonic-gate  * Skip spaces and tabs.
64167c478bd9Sstevel@tonic-gate  */
64177c478bd9Sstevel@tonic-gate       while(c==' ' || c=='\t')
64187c478bd9Sstevel@tonic-gate 	c = getc_fn(stream);
64197c478bd9Sstevel@tonic-gate /*
64207c478bd9Sstevel@tonic-gate  * If we hit the end of the line, or the start of a comment, exit the loop.
64217c478bd9Sstevel@tonic-gate  */
64227c478bd9Sstevel@tonic-gate       if(c==EOF || c=='\n' || c=='#')
64237c478bd9Sstevel@tonic-gate 	break;
64247c478bd9Sstevel@tonic-gate /*
64257c478bd9Sstevel@tonic-gate  * Start recording the next argument.
64267c478bd9Sstevel@tonic-gate  */
64277c478bd9Sstevel@tonic-gate       if(argc >= GL_CONF_MAXARG) {
64287c478bd9Sstevel@tonic-gate 	gl_report_config_error(gl, origin, *lineno, "Too many arguments.");
64297c478bd9Sstevel@tonic-gate 	do c = getc_fn(stream); while(c!='\n' && c!=EOF);  /* Skip past eol */
64307c478bd9Sstevel@tonic-gate 	return 0;
64317c478bd9Sstevel@tonic-gate       };
64327c478bd9Sstevel@tonic-gate       argv[argc] = buffer + i;
64337c478bd9Sstevel@tonic-gate /*
64347c478bd9Sstevel@tonic-gate  * The next character was preceded by spaces, so it isn't escaped.
64357c478bd9Sstevel@tonic-gate  */
64367c478bd9Sstevel@tonic-gate       escaped = 0;
64377c478bd9Sstevel@tonic-gate     } else {
64387c478bd9Sstevel@tonic-gate /*
64397c478bd9Sstevel@tonic-gate  * If we hit an unescaped backslash, this means that we should arrange
64407c478bd9Sstevel@tonic-gate  * to treat the next character like a simple alphabetical character.
64417c478bd9Sstevel@tonic-gate  */
64427c478bd9Sstevel@tonic-gate       if(c=='\\' && !escaped) {
64437c478bd9Sstevel@tonic-gate 	escaped = 1;
64447c478bd9Sstevel@tonic-gate /*
64457c478bd9Sstevel@tonic-gate  * Splice lines where the newline is escaped.
64467c478bd9Sstevel@tonic-gate  */
64477c478bd9Sstevel@tonic-gate       } else if(c=='\n' && escaped) {
64487c478bd9Sstevel@tonic-gate 	(*lineno)++;
64497c478bd9Sstevel@tonic-gate /*
64507c478bd9Sstevel@tonic-gate  * Record a normal character, preserving any preceding backslash.
64517c478bd9Sstevel@tonic-gate  */
64527c478bd9Sstevel@tonic-gate       } else {
64537c478bd9Sstevel@tonic-gate 	if(escaped)
64547c478bd9Sstevel@tonic-gate 	  buffer[i++] = '\\';
64557c478bd9Sstevel@tonic-gate 	if(i>=GL_CONF_BUFLEN)
64567c478bd9Sstevel@tonic-gate 	  break;
64577c478bd9Sstevel@tonic-gate 	escaped = 0;
64587c478bd9Sstevel@tonic-gate 	buffer[i++] = c;
64597c478bd9Sstevel@tonic-gate       };
64607c478bd9Sstevel@tonic-gate /*
64617c478bd9Sstevel@tonic-gate  * Get the next character.
64627c478bd9Sstevel@tonic-gate  */
64637c478bd9Sstevel@tonic-gate       c = getc_fn(stream);
64647c478bd9Sstevel@tonic-gate     };
64657c478bd9Sstevel@tonic-gate   };
64667c478bd9Sstevel@tonic-gate /*
64677c478bd9Sstevel@tonic-gate  * Did the buffer overflow?
64687c478bd9Sstevel@tonic-gate  */
64697c478bd9Sstevel@tonic-gate   if(i>=GL_CONF_BUFLEN) {
64707c478bd9Sstevel@tonic-gate     gl_report_config_error(gl, origin, *lineno, "Line too long.");
64717c478bd9Sstevel@tonic-gate     return 0;
64727c478bd9Sstevel@tonic-gate   };
64737c478bd9Sstevel@tonic-gate /*
64747c478bd9Sstevel@tonic-gate  * The first argument should be a command name.
64757c478bd9Sstevel@tonic-gate  */
64767c478bd9Sstevel@tonic-gate   if(strcmp(argv[0], "bind") == 0) {
64777c478bd9Sstevel@tonic-gate     const char *action = NULL; /* A NULL action removes a keybinding */
64787c478bd9Sstevel@tonic-gate     const char *keyseq = NULL;
64797c478bd9Sstevel@tonic-gate     switch(argc) {
64807c478bd9Sstevel@tonic-gate     case 3:
64817c478bd9Sstevel@tonic-gate       action = argv[2];
6482cf421650SToomas Soome       /* FALLTHROUGH */
64837c478bd9Sstevel@tonic-gate     case 2:              /* Note the intentional fallthrough */
64847c478bd9Sstevel@tonic-gate       keyseq = argv[1];
64857c478bd9Sstevel@tonic-gate /*
64867c478bd9Sstevel@tonic-gate  * Attempt to record the new keybinding.
64877c478bd9Sstevel@tonic-gate  */
64887c478bd9Sstevel@tonic-gate       if(_kt_set_keybinding(gl->bindings, who, keyseq, action)) {
64897c478bd9Sstevel@tonic-gate 	gl_report_config_error(gl, origin, *lineno,
64907c478bd9Sstevel@tonic-gate 			       _kt_last_error(gl->bindings));
64917c478bd9Sstevel@tonic-gate       };
64927c478bd9Sstevel@tonic-gate       break;
64937c478bd9Sstevel@tonic-gate     default:
64947c478bd9Sstevel@tonic-gate       gl_report_config_error(gl, origin, *lineno, "Wrong number of arguments.");
64957c478bd9Sstevel@tonic-gate     };
64967c478bd9Sstevel@tonic-gate   } else if(strcmp(argv[0], "edit-mode") == 0) {
64977c478bd9Sstevel@tonic-gate     if(argc == 2 && strcmp(argv[1], "emacs") == 0) {
64987c478bd9Sstevel@tonic-gate       gl_change_editor(gl, GL_EMACS_MODE);
64997c478bd9Sstevel@tonic-gate     } else if(argc == 2 && strcmp(argv[1], "vi") == 0) {
65007c478bd9Sstevel@tonic-gate       gl_change_editor(gl, GL_VI_MODE);
65017c478bd9Sstevel@tonic-gate     } else if(argc == 2 && strcmp(argv[1], "none") == 0) {
65027c478bd9Sstevel@tonic-gate       gl_change_editor(gl, GL_NO_EDITOR);
65037c478bd9Sstevel@tonic-gate     } else {
65047c478bd9Sstevel@tonic-gate       gl_report_config_error(gl, origin, *lineno,
65057c478bd9Sstevel@tonic-gate 			     "The argument of editor should be vi or emacs.");
65067c478bd9Sstevel@tonic-gate     };
65077c478bd9Sstevel@tonic-gate   } else if(strcmp(argv[0], "nobeep") == 0) {
65087c478bd9Sstevel@tonic-gate     gl->silence_bell = 1;
65097c478bd9Sstevel@tonic-gate   } else {
65107c478bd9Sstevel@tonic-gate     gl_report_config_error(gl, origin, *lineno, "Unknown command name.");
65117c478bd9Sstevel@tonic-gate   };
65127c478bd9Sstevel@tonic-gate /*
65137c478bd9Sstevel@tonic-gate  * Skip any trailing comment.
65147c478bd9Sstevel@tonic-gate  */
65157c478bd9Sstevel@tonic-gate   while(c != '\n' && c != EOF)
65167c478bd9Sstevel@tonic-gate     c = getc_fn(stream);
65177c478bd9Sstevel@tonic-gate   (*lineno)++;
65187c478bd9Sstevel@tonic-gate   return 0;
65197c478bd9Sstevel@tonic-gate }
65207c478bd9Sstevel@tonic-gate 
65217c478bd9Sstevel@tonic-gate /*.......................................................................
65227c478bd9Sstevel@tonic-gate  * This is a private function of _gl_parse_config_line() which prints
65237c478bd9Sstevel@tonic-gate  * out an error message about the contents of the line, prefixed by the
65247c478bd9Sstevel@tonic-gate  * name of the origin of the line and its line number.
65257c478bd9Sstevel@tonic-gate  *
65267c478bd9Sstevel@tonic-gate  * Input:
65277c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
65287c478bd9Sstevel@tonic-gate  *  origin  const char *  The name of the entity being read (eg. a
65297c478bd9Sstevel@tonic-gate  *                        file name).
65307c478bd9Sstevel@tonic-gate  *  lineno         int    The line number at which the error occurred.
65317c478bd9Sstevel@tonic-gate  *  errmsg  const char *  The error message.
65327c478bd9Sstevel@tonic-gate  * Output:
65337c478bd9Sstevel@tonic-gate  *  return         int    0 - OK.
65347c478bd9Sstevel@tonic-gate  *                        1 - Error.
65357c478bd9Sstevel@tonic-gate  */
gl_report_config_error(GetLine * gl,const char * origin,int lineno,const char * errmsg)65367c478bd9Sstevel@tonic-gate static int gl_report_config_error(GetLine *gl, const char *origin, int lineno,
65377c478bd9Sstevel@tonic-gate 				  const char *errmsg)
65387c478bd9Sstevel@tonic-gate {
65397c478bd9Sstevel@tonic-gate   char lnum[20];   /* A buffer in which to render a single integer */
65407c478bd9Sstevel@tonic-gate /*
65417c478bd9Sstevel@tonic-gate  * Convert the line number into a string.
65427c478bd9Sstevel@tonic-gate  */
65437c478bd9Sstevel@tonic-gate   snprintf(lnum, sizeof(lnum), "%d", lineno);
65447c478bd9Sstevel@tonic-gate /*
65457c478bd9Sstevel@tonic-gate  * Have the string printed on the terminal.
65467c478bd9Sstevel@tonic-gate  */
65477c478bd9Sstevel@tonic-gate   return gl_print_info(gl, origin, ":", lnum, ": ", errmsg, GL_END_INFO);
65487c478bd9Sstevel@tonic-gate }
65497c478bd9Sstevel@tonic-gate 
65507c478bd9Sstevel@tonic-gate /*.......................................................................
65517c478bd9Sstevel@tonic-gate  * This is the _gl_parse_config_line() callback function which reads the
65527c478bd9Sstevel@tonic-gate  * next character from a configuration file.
65537c478bd9Sstevel@tonic-gate  */
GLC_GETC_FN(glc_file_getc)65547c478bd9Sstevel@tonic-gate static GLC_GETC_FN(glc_file_getc)
65557c478bd9Sstevel@tonic-gate {
65567c478bd9Sstevel@tonic-gate   return fgetc((FILE *) stream);
65577c478bd9Sstevel@tonic-gate }
65587c478bd9Sstevel@tonic-gate 
65597c478bd9Sstevel@tonic-gate /*.......................................................................
65607c478bd9Sstevel@tonic-gate  * This is the _gl_parse_config_line() callback function which reads the
65617c478bd9Sstevel@tonic-gate  * next character from a buffer. Its stream argument is a pointer to a
65627c478bd9Sstevel@tonic-gate  * variable which is, in turn, a pointer into the buffer being read from.
65637c478bd9Sstevel@tonic-gate  */
GLC_GETC_FN(glc_buff_getc)65647c478bd9Sstevel@tonic-gate static GLC_GETC_FN(glc_buff_getc)
65657c478bd9Sstevel@tonic-gate {
65667c478bd9Sstevel@tonic-gate   const char **lptr = (char const **) stream;
65677c478bd9Sstevel@tonic-gate   return **lptr ? *(*lptr)++ : EOF;
65687c478bd9Sstevel@tonic-gate }
65697c478bd9Sstevel@tonic-gate 
65707c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
65717c478bd9Sstevel@tonic-gate /*.......................................................................
65727c478bd9Sstevel@tonic-gate  * When this action is triggered, it arranges to temporarily read command
65737c478bd9Sstevel@tonic-gate  * lines from the regular file whos name precedes the cursor.
65747c478bd9Sstevel@tonic-gate  * The current line is first discarded.
65757c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_read_from_file)65767c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_read_from_file)
65777c478bd9Sstevel@tonic-gate {
65787c478bd9Sstevel@tonic-gate   char *start_path;       /* The pointer to the start of the pathname in */
65797c478bd9Sstevel@tonic-gate                           /*  gl->line[]. */
65807c478bd9Sstevel@tonic-gate   FileExpansion *result;  /* The results of the filename expansion */
65817c478bd9Sstevel@tonic-gate   int pathlen;            /* The length of the pathname being expanded */
65827c478bd9Sstevel@tonic-gate /*
65837c478bd9Sstevel@tonic-gate  * Locate the start of the filename that precedes the cursor position.
65847c478bd9Sstevel@tonic-gate  */
65857c478bd9Sstevel@tonic-gate   start_path = _pu_start_of_path(gl->line, gl->buff_curpos);
65867c478bd9Sstevel@tonic-gate   if(!start_path)
65877c478bd9Sstevel@tonic-gate     return 1;
65887c478bd9Sstevel@tonic-gate /*
65897c478bd9Sstevel@tonic-gate  * Get the length of the pathname string.
65907c478bd9Sstevel@tonic-gate  */
65917c478bd9Sstevel@tonic-gate   pathlen = gl->buff_curpos - (start_path - gl->line);
65927c478bd9Sstevel@tonic-gate /*
65937c478bd9Sstevel@tonic-gate  * Attempt to expand the pathname.
65947c478bd9Sstevel@tonic-gate  */
65957c478bd9Sstevel@tonic-gate   result = ef_expand_file(gl->ef, start_path, pathlen);
65967c478bd9Sstevel@tonic-gate /*
65977c478bd9Sstevel@tonic-gate  * If there was an error, report the error on a new line.
65987c478bd9Sstevel@tonic-gate  */
65997c478bd9Sstevel@tonic-gate   if(!result) {
66007c478bd9Sstevel@tonic-gate     return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO);
66017c478bd9Sstevel@tonic-gate /*
66027c478bd9Sstevel@tonic-gate  * If no files matched, report this as well.
66037c478bd9Sstevel@tonic-gate  */
66047c478bd9Sstevel@tonic-gate   } else if(result->nfile == 0 || !result->exists) {
66057c478bd9Sstevel@tonic-gate     return gl_print_info(gl, "No files match.", GL_END_INFO);
66067c478bd9Sstevel@tonic-gate /*
66077c478bd9Sstevel@tonic-gate  * Complain if more than one file matches.
66087c478bd9Sstevel@tonic-gate  */
66097c478bd9Sstevel@tonic-gate   } else if(result->nfile > 1) {
66107c478bd9Sstevel@tonic-gate     return gl_print_info(gl, "More than one file matches.", GL_END_INFO);
66117c478bd9Sstevel@tonic-gate /*
66127c478bd9Sstevel@tonic-gate  * Disallow input from anything but normal files. In principle we could
66137c478bd9Sstevel@tonic-gate  * also support input from named pipes. Terminal files would be a problem
66147c478bd9Sstevel@tonic-gate  * since we wouldn't know the terminal type, and other types of files
66157c478bd9Sstevel@tonic-gate  * might cause the library to lock up.
66167c478bd9Sstevel@tonic-gate  */
66177c478bd9Sstevel@tonic-gate   } else if(!_pu_path_is_file(result->files[0])) {
66187c478bd9Sstevel@tonic-gate     return gl_print_info(gl, "Not a normal file.", GL_END_INFO);
66197c478bd9Sstevel@tonic-gate   } else {
66207c478bd9Sstevel@tonic-gate /*
66217c478bd9Sstevel@tonic-gate  * Attempt to open and install the specified file for reading.
66227c478bd9Sstevel@tonic-gate  */
66237c478bd9Sstevel@tonic-gate     gl->file_fp = fopen(result->files[0], "r");
66247c478bd9Sstevel@tonic-gate     if(!gl->file_fp) {
66257c478bd9Sstevel@tonic-gate       return gl_print_info(gl, "Unable to open: ", result->files[0],
66267c478bd9Sstevel@tonic-gate 			   GL_END_INFO);
66277c478bd9Sstevel@tonic-gate     };
66287c478bd9Sstevel@tonic-gate /*
66297c478bd9Sstevel@tonic-gate  * If needed, expand the record of the maximum file-descriptor that might
66307c478bd9Sstevel@tonic-gate  * need to be monitored with select().
66317c478bd9Sstevel@tonic-gate  */
66327c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT
66337c478bd9Sstevel@tonic-gate     if(fileno(gl->file_fp) > gl->max_fd)
66347c478bd9Sstevel@tonic-gate       gl->max_fd = fileno(gl->file_fp);
66357c478bd9Sstevel@tonic-gate #endif
66367c478bd9Sstevel@tonic-gate /*
66377c478bd9Sstevel@tonic-gate  * Is non-blocking I/O needed?
66387c478bd9Sstevel@tonic-gate  */
66397c478bd9Sstevel@tonic-gate     if(gl->raw_mode && gl->io_mode==GL_SERVER_MODE &&
66407c478bd9Sstevel@tonic-gate        gl_nonblocking_io(gl, fileno(gl->file_fp))) {
66417c478bd9Sstevel@tonic-gate       gl_revert_input(gl);
66427c478bd9Sstevel@tonic-gate       return gl_print_info(gl, "Can't read file %s with non-blocking I/O",
66437c478bd9Sstevel@tonic-gate 			   result->files[0]);
66447c478bd9Sstevel@tonic-gate     };
66457c478bd9Sstevel@tonic-gate /*
66467c478bd9Sstevel@tonic-gate  * Inform the user what is happening.
66477c478bd9Sstevel@tonic-gate  */
66487c478bd9Sstevel@tonic-gate     if(gl_print_info(gl, "<Taking input from ", result->files[0], ">",
66497c478bd9Sstevel@tonic-gate 		     GL_END_INFO))
66507c478bd9Sstevel@tonic-gate       return 1;
66517c478bd9Sstevel@tonic-gate   };
66527c478bd9Sstevel@tonic-gate   return 0;
66537c478bd9Sstevel@tonic-gate }
66547c478bd9Sstevel@tonic-gate #endif
66557c478bd9Sstevel@tonic-gate 
66567c478bd9Sstevel@tonic-gate /*.......................................................................
66577c478bd9Sstevel@tonic-gate  * Close any temporary file that is being used for input.
66587c478bd9Sstevel@tonic-gate  *
66597c478bd9Sstevel@tonic-gate  * Input:
66607c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The getline resource object.
66617c478bd9Sstevel@tonic-gate  */
gl_revert_input(GetLine * gl)66627c478bd9Sstevel@tonic-gate static void gl_revert_input(GetLine *gl)
66637c478bd9Sstevel@tonic-gate {
66647c478bd9Sstevel@tonic-gate   if(gl->file_fp)
66657c478bd9Sstevel@tonic-gate     fclose(gl->file_fp);
66667c478bd9Sstevel@tonic-gate   gl->file_fp = NULL;
66677c478bd9Sstevel@tonic-gate   gl->endline = 1;
66687c478bd9Sstevel@tonic-gate }
66697c478bd9Sstevel@tonic-gate 
66707c478bd9Sstevel@tonic-gate /*.......................................................................
66717c478bd9Sstevel@tonic-gate  * This is the action function that recalls the oldest line in the
66727c478bd9Sstevel@tonic-gate  * history buffer.
66737c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_beginning_of_history)66747c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_beginning_of_history)
66757c478bd9Sstevel@tonic-gate {
66767c478bd9Sstevel@tonic-gate /*
66777c478bd9Sstevel@tonic-gate  * In vi mode, switch to command mode, since the user is very
66787c478bd9Sstevel@tonic-gate  * likely to want to move around newly recalled lines.
66797c478bd9Sstevel@tonic-gate  */
66807c478bd9Sstevel@tonic-gate   gl_vi_command_mode(gl);
66817c478bd9Sstevel@tonic-gate /*
66827c478bd9Sstevel@tonic-gate  * Forget any previous recall session.
66837c478bd9Sstevel@tonic-gate  */
66847c478bd9Sstevel@tonic-gate   gl->preload_id = 0;
66857c478bd9Sstevel@tonic-gate /*
66867c478bd9Sstevel@tonic-gate  * Record the key sequence number of this search action.
66877c478bd9Sstevel@tonic-gate  */
66887c478bd9Sstevel@tonic-gate   gl->last_search = gl->keyseq_count;
66897c478bd9Sstevel@tonic-gate /*
66907c478bd9Sstevel@tonic-gate  * Recall the next oldest line in the history list.
66917c478bd9Sstevel@tonic-gate  */
66927c478bd9Sstevel@tonic-gate   if(_glh_oldest_line(gl->glh, gl->line, gl->linelen+1) == NULL)
66937c478bd9Sstevel@tonic-gate     return 0;
66947c478bd9Sstevel@tonic-gate /*
66957c478bd9Sstevel@tonic-gate  * Accomodate the new contents of gl->line[].
66967c478bd9Sstevel@tonic-gate  */
66977c478bd9Sstevel@tonic-gate   gl_update_buffer(gl);
66987c478bd9Sstevel@tonic-gate /*
66997c478bd9Sstevel@tonic-gate  * Arrange to have the cursor placed at the end of the new line.
67007c478bd9Sstevel@tonic-gate  */
67017c478bd9Sstevel@tonic-gate   gl->buff_curpos = gl->ntotal;
67027c478bd9Sstevel@tonic-gate /*
67037c478bd9Sstevel@tonic-gate  * Erase and display the new line.
67047c478bd9Sstevel@tonic-gate  */
67057c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
67067c478bd9Sstevel@tonic-gate   return 0;
67077c478bd9Sstevel@tonic-gate }
67087c478bd9Sstevel@tonic-gate 
67097c478bd9Sstevel@tonic-gate /*.......................................................................
67107c478bd9Sstevel@tonic-gate  * If a history session is currently in progress, this action function
67117c478bd9Sstevel@tonic-gate  * recalls the line that was being edited when the session started. If
67127c478bd9Sstevel@tonic-gate  * no history session is in progress, it does nothing.
67137c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_end_of_history)67147c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_end_of_history)
67157c478bd9Sstevel@tonic-gate {
67167c478bd9Sstevel@tonic-gate /*
67177c478bd9Sstevel@tonic-gate  * In vi mode, switch to command mode, since the user is very
67187c478bd9Sstevel@tonic-gate  * likely to want to move around newly recalled lines.
67197c478bd9Sstevel@tonic-gate  */
67207c478bd9Sstevel@tonic-gate   gl_vi_command_mode(gl);
67217c478bd9Sstevel@tonic-gate /*
67227c478bd9Sstevel@tonic-gate  * Forget any previous recall session.
67237c478bd9Sstevel@tonic-gate  */
67247c478bd9Sstevel@tonic-gate   gl->preload_id = 0;
67257c478bd9Sstevel@tonic-gate /*
67267c478bd9Sstevel@tonic-gate  * Record the key sequence number of this search action.
67277c478bd9Sstevel@tonic-gate  */
67287c478bd9Sstevel@tonic-gate   gl->last_search = gl->keyseq_count;
67297c478bd9Sstevel@tonic-gate /*
67307c478bd9Sstevel@tonic-gate  * Recall the next oldest line in the history list.
67317c478bd9Sstevel@tonic-gate  */
67327c478bd9Sstevel@tonic-gate   if(_glh_current_line(gl->glh, gl->line, gl->linelen+1) == NULL)
67337c478bd9Sstevel@tonic-gate     return 0;
67347c478bd9Sstevel@tonic-gate /*
67357c478bd9Sstevel@tonic-gate  * Accomodate the new contents of gl->line[].
67367c478bd9Sstevel@tonic-gate  */
67377c478bd9Sstevel@tonic-gate   gl_update_buffer(gl);
67387c478bd9Sstevel@tonic-gate /*
67397c478bd9Sstevel@tonic-gate  * Arrange to have the cursor placed at the end of the new line.
67407c478bd9Sstevel@tonic-gate  */
67417c478bd9Sstevel@tonic-gate   gl->buff_curpos = gl->ntotal;
67427c478bd9Sstevel@tonic-gate /*
67437c478bd9Sstevel@tonic-gate  * Erase and display the new line.
67447c478bd9Sstevel@tonic-gate  */
67457c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
67467c478bd9Sstevel@tonic-gate   return 0;
67477c478bd9Sstevel@tonic-gate }
67487c478bd9Sstevel@tonic-gate 
67497c478bd9Sstevel@tonic-gate /*.......................................................................
67507c478bd9Sstevel@tonic-gate  * This action function is treated specially, in that its count argument
67517c478bd9Sstevel@tonic-gate  * is set to the end keystroke of the keysequence that activated it.
67527c478bd9Sstevel@tonic-gate  * It accumulates a numeric argument, adding one digit on each call in
67537c478bd9Sstevel@tonic-gate  * which the last keystroke was a numeric digit.
67547c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_digit_argument)67557c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_digit_argument)
67567c478bd9Sstevel@tonic-gate {
67577c478bd9Sstevel@tonic-gate /*
67587c478bd9Sstevel@tonic-gate  * Was the last keystroke a digit?
67597c478bd9Sstevel@tonic-gate  */
67607c478bd9Sstevel@tonic-gate   int is_digit = isdigit((int)(unsigned char) count);
67617c478bd9Sstevel@tonic-gate /*
67627c478bd9Sstevel@tonic-gate  * In vi command mode, a lone '0' means goto-start-of-line.
67637c478bd9Sstevel@tonic-gate  */
67647c478bd9Sstevel@tonic-gate   if(gl->vi.command && gl->number < 0 && count == '0')
67657c478bd9Sstevel@tonic-gate     return gl_beginning_of_line(gl, count, NULL);
67667c478bd9Sstevel@tonic-gate /*
67677c478bd9Sstevel@tonic-gate  * Are we starting to accumulate a new number?
67687c478bd9Sstevel@tonic-gate  */
67697c478bd9Sstevel@tonic-gate   if(gl->number < 0 || !is_digit)
67707c478bd9Sstevel@tonic-gate     gl->number = 0;
67717c478bd9Sstevel@tonic-gate /*
67727c478bd9Sstevel@tonic-gate  * Was the last keystroke a digit?
67737c478bd9Sstevel@tonic-gate  */
67747c478bd9Sstevel@tonic-gate   if(is_digit) {
67757c478bd9Sstevel@tonic-gate /*
67767c478bd9Sstevel@tonic-gate  * Read the numeric value of the digit, without assuming ASCII.
67777c478bd9Sstevel@tonic-gate  */
67787c478bd9Sstevel@tonic-gate     int n;
67797c478bd9Sstevel@tonic-gate     char s[2]; s[0] = count; s[1] = '\0';
67807c478bd9Sstevel@tonic-gate     n = atoi(s);
67817c478bd9Sstevel@tonic-gate /*
67827c478bd9Sstevel@tonic-gate  * Append the new digit.
67837c478bd9Sstevel@tonic-gate  */
67847c478bd9Sstevel@tonic-gate     gl->number = gl->number * 10 + n;
67857c478bd9Sstevel@tonic-gate   };
67867c478bd9Sstevel@tonic-gate   return 0;
67877c478bd9Sstevel@tonic-gate }
67887c478bd9Sstevel@tonic-gate 
67897c478bd9Sstevel@tonic-gate /*.......................................................................
67907c478bd9Sstevel@tonic-gate  * The newline action function sets gl->endline to tell
67917c478bd9Sstevel@tonic-gate  * gl_get_input_line() that the line is now complete.
67927c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_newline)67937c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_newline)
67947c478bd9Sstevel@tonic-gate {
67957c478bd9Sstevel@tonic-gate   GlhLineID id;    /* The last history line recalled while entering this line */
67967c478bd9Sstevel@tonic-gate /*
67977c478bd9Sstevel@tonic-gate  * Flag the line as ended.
67987c478bd9Sstevel@tonic-gate  */
67997c478bd9Sstevel@tonic-gate   gl->endline = 1;
68007c478bd9Sstevel@tonic-gate /*
68017c478bd9Sstevel@tonic-gate  * Record the next position in the history buffer, for potential
68027c478bd9Sstevel@tonic-gate  * recall by an action function on the next call to gl_get_line().
68037c478bd9Sstevel@tonic-gate  */
68047c478bd9Sstevel@tonic-gate   id = _glh_line_id(gl->glh, 1);
68057c478bd9Sstevel@tonic-gate   if(id)
68067c478bd9Sstevel@tonic-gate     gl->preload_id = id;
68077c478bd9Sstevel@tonic-gate   return 0;
68087c478bd9Sstevel@tonic-gate }
68097c478bd9Sstevel@tonic-gate 
68107c478bd9Sstevel@tonic-gate /*.......................................................................
68117c478bd9Sstevel@tonic-gate  * The 'repeat' action function sets gl->endline to tell
68127c478bd9Sstevel@tonic-gate  * gl_get_input_line() that the line is now complete, and records the
68137c478bd9Sstevel@tonic-gate  * ID of the next history line in gl->preload_id so that the next call
68147c478bd9Sstevel@tonic-gate  * to gl_get_input_line() will preload the line with that history line.
68157c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_repeat_history)68167c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_repeat_history)
68177c478bd9Sstevel@tonic-gate {
68187c478bd9Sstevel@tonic-gate   gl->endline = 1;
68197c478bd9Sstevel@tonic-gate   gl->preload_id = _glh_line_id(gl->glh, 1);
68207c478bd9Sstevel@tonic-gate   gl->preload_history = 1;
68217c478bd9Sstevel@tonic-gate   return 0;
68227c478bd9Sstevel@tonic-gate }
68237c478bd9Sstevel@tonic-gate 
68247c478bd9Sstevel@tonic-gate /*.......................................................................
68257c478bd9Sstevel@tonic-gate  * Flush unwritten characters to the terminal.
68267c478bd9Sstevel@tonic-gate  *
68277c478bd9Sstevel@tonic-gate  * Input:
68287c478bd9Sstevel@tonic-gate  *  gl     GetLine *  The getline resource object.
68297c478bd9Sstevel@tonic-gate  * Output:
68307c478bd9Sstevel@tonic-gate  *  return     int    0 - OK.
68317c478bd9Sstevel@tonic-gate  *                    1 - Either an error occured, or the output
68327c478bd9Sstevel@tonic-gate  *                        blocked and non-blocking I/O is being used.
68337c478bd9Sstevel@tonic-gate  *                        See gl->rtn_status for details.
68347c478bd9Sstevel@tonic-gate  */
gl_flush_output(GetLine * gl)68357c478bd9Sstevel@tonic-gate static int gl_flush_output(GetLine *gl)
68367c478bd9Sstevel@tonic-gate {
68377c478bd9Sstevel@tonic-gate /*
68387c478bd9Sstevel@tonic-gate  * Record the fact that we are about to write to the terminal.
68397c478bd9Sstevel@tonic-gate  */
68407c478bd9Sstevel@tonic-gate   gl->pending_io = GLP_WRITE;
68417c478bd9Sstevel@tonic-gate /*
68427c478bd9Sstevel@tonic-gate  * Attempt to flush the output to the terminal.
68437c478bd9Sstevel@tonic-gate  */
68447c478bd9Sstevel@tonic-gate   errno = 0;
68457c478bd9Sstevel@tonic-gate   switch(_glq_flush_queue(gl->cq, gl->flush_fn, gl)) {
68467c478bd9Sstevel@tonic-gate   case GLQ_FLUSH_DONE:
68477c478bd9Sstevel@tonic-gate     return gl->redisplay && !gl->postpone && gl_redisplay(gl, 1, NULL);
68487c478bd9Sstevel@tonic-gate     break;
68497c478bd9Sstevel@tonic-gate   case GLQ_FLUSH_AGAIN:      /* Output blocked */
68507c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
68517c478bd9Sstevel@tonic-gate     return 1;
68527c478bd9Sstevel@tonic-gate     break;
68537c478bd9Sstevel@tonic-gate   default:                   /* Abort the line if an error occurs */
68547c478bd9Sstevel@tonic-gate     gl_record_status(gl, errno==EINTR ? GLR_SIGNAL : GLR_ERROR, errno);
68557c478bd9Sstevel@tonic-gate     return 1;
68567c478bd9Sstevel@tonic-gate     break;
68577c478bd9Sstevel@tonic-gate   };
68587c478bd9Sstevel@tonic-gate }
68597c478bd9Sstevel@tonic-gate 
68607c478bd9Sstevel@tonic-gate /*.......................................................................
68617c478bd9Sstevel@tonic-gate  * This is the callback which _glq_flush_queue() uses to write buffered
68627c478bd9Sstevel@tonic-gate  * characters to the terminal.
68637c478bd9Sstevel@tonic-gate  */
GL_WRITE_FN(gl_flush_terminal)68647c478bd9Sstevel@tonic-gate static GL_WRITE_FN(gl_flush_terminal)
68657c478bd9Sstevel@tonic-gate {
68667c478bd9Sstevel@tonic-gate   int ndone = 0;    /* The number of characters written so far */
68677c478bd9Sstevel@tonic-gate /*
68687c478bd9Sstevel@tonic-gate  * Get the line-editor resource object.
68697c478bd9Sstevel@tonic-gate  */
68707c478bd9Sstevel@tonic-gate   GetLine *gl = (GetLine *) data;
68717c478bd9Sstevel@tonic-gate /*
68727c478bd9Sstevel@tonic-gate  * Transfer the latest array of characters to stdio.
68737c478bd9Sstevel@tonic-gate  */
68747c478bd9Sstevel@tonic-gate   while(ndone < n) {
68757c478bd9Sstevel@tonic-gate     int nnew = write(gl->output_fd, s, n-ndone);
68767c478bd9Sstevel@tonic-gate /*
68777c478bd9Sstevel@tonic-gate  * If the write was successful, add to the recorded number of bytes
68787c478bd9Sstevel@tonic-gate  * that have now been written.
68797c478bd9Sstevel@tonic-gate  */
68807c478bd9Sstevel@tonic-gate     if(nnew > 0) {
68817c478bd9Sstevel@tonic-gate       ndone += nnew;
68827c478bd9Sstevel@tonic-gate /*
68837c478bd9Sstevel@tonic-gate  * If a signal interrupted the call, restart the write(), since all of
68847c478bd9Sstevel@tonic-gate  * the signals that gl_get_line() has been told to watch for are
68857c478bd9Sstevel@tonic-gate  * currently blocked.
68867c478bd9Sstevel@tonic-gate  */
68877c478bd9Sstevel@tonic-gate     } else if(errno == EINTR) {
68887c478bd9Sstevel@tonic-gate       continue;
68897c478bd9Sstevel@tonic-gate /*
68907c478bd9Sstevel@tonic-gate  * If we managed to write something before an I/O error occurred, or
68917c478bd9Sstevel@tonic-gate  * output blocked before anything was written, report the number of
68927c478bd9Sstevel@tonic-gate  * bytes that were successfully written before this happened.
68937c478bd9Sstevel@tonic-gate  */
68947c478bd9Sstevel@tonic-gate     } else if(ndone > 0
68957c478bd9Sstevel@tonic-gate #if defined(EAGAIN)
68967c478bd9Sstevel@tonic-gate 	      || errno==EAGAIN
68977c478bd9Sstevel@tonic-gate #endif
68987c478bd9Sstevel@tonic-gate #if defined(EWOULDBLOCK)
68997c478bd9Sstevel@tonic-gate 	      || errno==EWOULDBLOCK
69007c478bd9Sstevel@tonic-gate #endif
69017c478bd9Sstevel@tonic-gate 	      ) {
69027c478bd9Sstevel@tonic-gate       return ndone;
69037c478bd9Sstevel@tonic-gate 
69047c478bd9Sstevel@tonic-gate /*
69057c478bd9Sstevel@tonic-gate  * To get here, an error must have occurred before anything new could
69067c478bd9Sstevel@tonic-gate  * be written.
69077c478bd9Sstevel@tonic-gate  */
69087c478bd9Sstevel@tonic-gate     } else {
69097c478bd9Sstevel@tonic-gate       return -1;
69107c478bd9Sstevel@tonic-gate     };
69117c478bd9Sstevel@tonic-gate   };
69127c478bd9Sstevel@tonic-gate /*
69137c478bd9Sstevel@tonic-gate  * To get here, we must have successfully written the number of
69147c478bd9Sstevel@tonic-gate  * bytes that was specified.
69157c478bd9Sstevel@tonic-gate  */
69167c478bd9Sstevel@tonic-gate   return n;
69177c478bd9Sstevel@tonic-gate }
69187c478bd9Sstevel@tonic-gate 
69197c478bd9Sstevel@tonic-gate /*.......................................................................
69207c478bd9Sstevel@tonic-gate  * Change the style of editing to emulate a given editor.
69217c478bd9Sstevel@tonic-gate  *
69227c478bd9Sstevel@tonic-gate  * Input:
69237c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
69247c478bd9Sstevel@tonic-gate  *  editor  GlEditor    The type of editor to emulate.
69257c478bd9Sstevel@tonic-gate  * Output:
69267c478bd9Sstevel@tonic-gate  *  return       int    0 - OK.
69277c478bd9Sstevel@tonic-gate  *                      1 - Error.
69287c478bd9Sstevel@tonic-gate  */
gl_change_editor(GetLine * gl,GlEditor editor)69297c478bd9Sstevel@tonic-gate static int gl_change_editor(GetLine *gl, GlEditor editor)
69307c478bd9Sstevel@tonic-gate {
69317c478bd9Sstevel@tonic-gate /*
69327c478bd9Sstevel@tonic-gate  * Install the default key-bindings of the requested editor.
69337c478bd9Sstevel@tonic-gate  */
69347c478bd9Sstevel@tonic-gate   switch(editor) {
69357c478bd9Sstevel@tonic-gate   case GL_EMACS_MODE:
69367c478bd9Sstevel@tonic-gate     _kt_clear_bindings(gl->bindings, KTB_NORM);
69377c478bd9Sstevel@tonic-gate     _kt_clear_bindings(gl->bindings, KTB_TERM);
69387c478bd9Sstevel@tonic-gate     (void) _kt_add_bindings(gl->bindings, KTB_NORM, gl_emacs_bindings,
69397c478bd9Sstevel@tonic-gate 		   sizeof(gl_emacs_bindings)/sizeof(gl_emacs_bindings[0]));
69407c478bd9Sstevel@tonic-gate     break;
69417c478bd9Sstevel@tonic-gate   case GL_VI_MODE:
69427c478bd9Sstevel@tonic-gate     _kt_clear_bindings(gl->bindings, KTB_NORM);
69437c478bd9Sstevel@tonic-gate     _kt_clear_bindings(gl->bindings, KTB_TERM);
69447c478bd9Sstevel@tonic-gate     (void) _kt_add_bindings(gl->bindings, KTB_NORM, gl_vi_bindings,
69457c478bd9Sstevel@tonic-gate 			    sizeof(gl_vi_bindings)/sizeof(gl_vi_bindings[0]));
69467c478bd9Sstevel@tonic-gate     break;
69477c478bd9Sstevel@tonic-gate   case GL_NO_EDITOR:
69487c478bd9Sstevel@tonic-gate     break;
69497c478bd9Sstevel@tonic-gate   default:
69507c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "Unknown editor", END_ERR_MSG);
69517c478bd9Sstevel@tonic-gate     errno = EINVAL;
69527c478bd9Sstevel@tonic-gate     return 1;
69537c478bd9Sstevel@tonic-gate   };
69547c478bd9Sstevel@tonic-gate /*
69557c478bd9Sstevel@tonic-gate  * Record the new editing mode.
69567c478bd9Sstevel@tonic-gate  */
69577c478bd9Sstevel@tonic-gate   gl->editor = editor;
69587c478bd9Sstevel@tonic-gate   gl->vi.command = 0;     /* Start in input mode */
69597c478bd9Sstevel@tonic-gate   gl->insert_curpos = 0;
69607c478bd9Sstevel@tonic-gate /*
69617c478bd9Sstevel@tonic-gate  * Reinstate terminal-specific bindings.
69627c478bd9Sstevel@tonic-gate  */
69637c478bd9Sstevel@tonic-gate   if(gl->editor != GL_NO_EDITOR && gl->input_fp)
69647c478bd9Sstevel@tonic-gate     (void) gl_bind_terminal_keys(gl);
69657c478bd9Sstevel@tonic-gate   return 0;
69667c478bd9Sstevel@tonic-gate }
69677c478bd9Sstevel@tonic-gate 
69687c478bd9Sstevel@tonic-gate /*.......................................................................
69697c478bd9Sstevel@tonic-gate  * This is an action function that switches to editing using emacs bindings
69707c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_emacs_editing_mode)69717c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_emacs_editing_mode)
69727c478bd9Sstevel@tonic-gate {
69737c478bd9Sstevel@tonic-gate   return gl_change_editor(gl, GL_EMACS_MODE);
69747c478bd9Sstevel@tonic-gate }
69757c478bd9Sstevel@tonic-gate 
69767c478bd9Sstevel@tonic-gate /*.......................................................................
69777c478bd9Sstevel@tonic-gate  * This is an action function that switches to editing using vi bindings
69787c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_editing_mode)69797c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_editing_mode)
69807c478bd9Sstevel@tonic-gate {
69817c478bd9Sstevel@tonic-gate   return gl_change_editor(gl, GL_VI_MODE);
69827c478bd9Sstevel@tonic-gate }
69837c478bd9Sstevel@tonic-gate 
69847c478bd9Sstevel@tonic-gate /*.......................................................................
69857c478bd9Sstevel@tonic-gate  * This is the action function that switches to insert mode.
69867c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_insert)69877c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_insert)
69887c478bd9Sstevel@tonic-gate {
69897c478bd9Sstevel@tonic-gate /*
69907c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
69917c478bd9Sstevel@tonic-gate  * use by vi-undo.
69927c478bd9Sstevel@tonic-gate  */
69937c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
69947c478bd9Sstevel@tonic-gate /*
69957c478bd9Sstevel@tonic-gate  * Switch to vi insert mode.
69967c478bd9Sstevel@tonic-gate  */
69977c478bd9Sstevel@tonic-gate   gl->insert = 1;
69987c478bd9Sstevel@tonic-gate   gl->vi.command = 0;
69997c478bd9Sstevel@tonic-gate   gl->insert_curpos = gl->buff_curpos;
70007c478bd9Sstevel@tonic-gate   return 0;
70017c478bd9Sstevel@tonic-gate }
70027c478bd9Sstevel@tonic-gate 
70037c478bd9Sstevel@tonic-gate /*.......................................................................
70047c478bd9Sstevel@tonic-gate  * This is an action function that switches to overwrite mode.
70057c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_overwrite)70067c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_overwrite)
70077c478bd9Sstevel@tonic-gate {
70087c478bd9Sstevel@tonic-gate /*
70097c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
70107c478bd9Sstevel@tonic-gate  * use by vi-undo.
70117c478bd9Sstevel@tonic-gate  */
70127c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
70137c478bd9Sstevel@tonic-gate /*
70147c478bd9Sstevel@tonic-gate  * Switch to vi overwrite mode.
70157c478bd9Sstevel@tonic-gate  */
70167c478bd9Sstevel@tonic-gate   gl->insert = 0;
70177c478bd9Sstevel@tonic-gate   gl->vi.command = 0;
70187c478bd9Sstevel@tonic-gate   gl->insert_curpos = gl->buff_curpos;
70197c478bd9Sstevel@tonic-gate   return 0;
70207c478bd9Sstevel@tonic-gate }
70217c478bd9Sstevel@tonic-gate 
70227c478bd9Sstevel@tonic-gate /*.......................................................................
70237c478bd9Sstevel@tonic-gate  * This action function toggles the case of the character under the
70247c478bd9Sstevel@tonic-gate  * cursor.
70257c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_change_case)70267c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_change_case)
70277c478bd9Sstevel@tonic-gate {
70287c478bd9Sstevel@tonic-gate   int i;
70297c478bd9Sstevel@tonic-gate /*
70307c478bd9Sstevel@tonic-gate  * Keep a record of the current insert mode and the cursor position.
70317c478bd9Sstevel@tonic-gate  */
70327c478bd9Sstevel@tonic-gate   int insert = gl->insert;
70337c478bd9Sstevel@tonic-gate /*
70347c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
70357c478bd9Sstevel@tonic-gate  * use by vi-undo.
70367c478bd9Sstevel@tonic-gate  */
70377c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
70387c478bd9Sstevel@tonic-gate /*
70397c478bd9Sstevel@tonic-gate  * We want to overwrite the modified word.
70407c478bd9Sstevel@tonic-gate  */
70417c478bd9Sstevel@tonic-gate   gl->insert = 0;
70427c478bd9Sstevel@tonic-gate /*
70437c478bd9Sstevel@tonic-gate  * Toggle the case of 'count' characters.
70447c478bd9Sstevel@tonic-gate  */
70457c478bd9Sstevel@tonic-gate   for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) {
70467c478bd9Sstevel@tonic-gate     char *cptr = gl->line + gl->buff_curpos++;
70477c478bd9Sstevel@tonic-gate /*
70487c478bd9Sstevel@tonic-gate  * Convert the character to upper case?
70497c478bd9Sstevel@tonic-gate  */
70507c478bd9Sstevel@tonic-gate     if(islower((int)(unsigned char) *cptr))
70517c478bd9Sstevel@tonic-gate       gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line);
70527c478bd9Sstevel@tonic-gate     else if(isupper((int)(unsigned char) *cptr))
70537c478bd9Sstevel@tonic-gate       gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line);
70547c478bd9Sstevel@tonic-gate /*
70557c478bd9Sstevel@tonic-gate  * Write the possibly modified character back. Note that for non-modified
70567c478bd9Sstevel@tonic-gate  * characters we want to do this as well, so as to advance the cursor.
70577c478bd9Sstevel@tonic-gate  */
70587c478bd9Sstevel@tonic-gate       if(gl_print_char(gl, *cptr, cptr[1]))
70597c478bd9Sstevel@tonic-gate 	return 1;
70607c478bd9Sstevel@tonic-gate   };
70617c478bd9Sstevel@tonic-gate /*
70627c478bd9Sstevel@tonic-gate  * Restore the insertion mode.
70637c478bd9Sstevel@tonic-gate  */
70647c478bd9Sstevel@tonic-gate   gl->insert = insert;
70657c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos);	/* bounds check */
70667c478bd9Sstevel@tonic-gate }
70677c478bd9Sstevel@tonic-gate 
70687c478bd9Sstevel@tonic-gate /*.......................................................................
70697c478bd9Sstevel@tonic-gate  * This is the action function which implements the vi-style action which
70707c478bd9Sstevel@tonic-gate  * moves the cursor to the start of the line, then switches to insert mode.
70717c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_insert_at_bol)70727c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_insert_at_bol)
70737c478bd9Sstevel@tonic-gate {
70747c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
70757c478bd9Sstevel@tonic-gate   return gl_beginning_of_line(gl, 0, NULL) ||
70767c478bd9Sstevel@tonic-gate          gl_vi_insert(gl, 0, NULL);
70777c478bd9Sstevel@tonic-gate 
70787c478bd9Sstevel@tonic-gate }
70797c478bd9Sstevel@tonic-gate 
70807c478bd9Sstevel@tonic-gate /*.......................................................................
70817c478bd9Sstevel@tonic-gate  * This is the action function which implements the vi-style action which
70827c478bd9Sstevel@tonic-gate  * moves the cursor to the end of the line, then switches to insert mode
70837c478bd9Sstevel@tonic-gate  * to allow text to be appended to the line.
70847c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_append_at_eol)70857c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_append_at_eol)
70867c478bd9Sstevel@tonic-gate {
70877c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
70887c478bd9Sstevel@tonic-gate   gl->vi.command = 0;	/* Allow cursor at EOL */
70897c478bd9Sstevel@tonic-gate   return gl_end_of_line(gl, 0, NULL) ||
70907c478bd9Sstevel@tonic-gate          gl_vi_insert(gl, 0, NULL);
70917c478bd9Sstevel@tonic-gate }
70927c478bd9Sstevel@tonic-gate 
70937c478bd9Sstevel@tonic-gate /*.......................................................................
70947c478bd9Sstevel@tonic-gate  * This is the action function which implements the vi-style action which
70957c478bd9Sstevel@tonic-gate  * moves the cursor to right one then switches to insert mode, thus
70967c478bd9Sstevel@tonic-gate  * allowing text to be appended after the next character.
70977c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_append)70987c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_append)
70997c478bd9Sstevel@tonic-gate {
71007c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
71017c478bd9Sstevel@tonic-gate   gl->vi.command = 0;	/* Allow cursor at EOL */
71027c478bd9Sstevel@tonic-gate   return gl_cursor_right(gl, 1, NULL) ||
71037c478bd9Sstevel@tonic-gate          gl_vi_insert(gl, 0, NULL);
71047c478bd9Sstevel@tonic-gate }
71057c478bd9Sstevel@tonic-gate 
71067c478bd9Sstevel@tonic-gate /*.......................................................................
71077c478bd9Sstevel@tonic-gate  * This action function moves the cursor to the column specified by the
71087c478bd9Sstevel@tonic-gate  * numeric argument. Column indexes start at 1.
71097c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_goto_column)71107c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_goto_column)
71117c478bd9Sstevel@tonic-gate {
71127c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, count - 1);
71137c478bd9Sstevel@tonic-gate }
71147c478bd9Sstevel@tonic-gate 
71157c478bd9Sstevel@tonic-gate /*.......................................................................
71167c478bd9Sstevel@tonic-gate  * Starting with the character under the cursor, replace 'count'
71177c478bd9Sstevel@tonic-gate  * characters with the next character that the user types.
71187c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_replace_char)71197c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_replace_char)
71207c478bd9Sstevel@tonic-gate {
71217c478bd9Sstevel@tonic-gate   char c;  /* The replacement character */
71227c478bd9Sstevel@tonic-gate   int i;
71237c478bd9Sstevel@tonic-gate /*
71247c478bd9Sstevel@tonic-gate  * Keep a record of the current insert mode.
71257c478bd9Sstevel@tonic-gate  */
71267c478bd9Sstevel@tonic-gate   int insert = gl->insert;
71277c478bd9Sstevel@tonic-gate /*
71287c478bd9Sstevel@tonic-gate  * Get the replacement character.
71297c478bd9Sstevel@tonic-gate  */
71307c478bd9Sstevel@tonic-gate   if(gl->vi.repeat.active) {
71317c478bd9Sstevel@tonic-gate     c = gl->vi.repeat.input_char;
71327c478bd9Sstevel@tonic-gate   } else {
71337c478bd9Sstevel@tonic-gate     if(gl_read_terminal(gl, 1, &c))
71347c478bd9Sstevel@tonic-gate       return 1;
71357c478bd9Sstevel@tonic-gate     gl->vi.repeat.input_char = c;
71367c478bd9Sstevel@tonic-gate   };
71377c478bd9Sstevel@tonic-gate /*
71387c478bd9Sstevel@tonic-gate  * Are there 'count' characters to be replaced?
71397c478bd9Sstevel@tonic-gate  */
71407c478bd9Sstevel@tonic-gate   if(gl->ntotal - gl->buff_curpos >= count) {
71417c478bd9Sstevel@tonic-gate /*
71427c478bd9Sstevel@tonic-gate  * If in vi command mode, preserve the current line for potential
71437c478bd9Sstevel@tonic-gate  * use by vi-undo.
71447c478bd9Sstevel@tonic-gate  */
71457c478bd9Sstevel@tonic-gate     gl_save_for_undo(gl);
71467c478bd9Sstevel@tonic-gate /*
71477c478bd9Sstevel@tonic-gate  * Temporarily switch to overwrite mode.
71487c478bd9Sstevel@tonic-gate  */
71497c478bd9Sstevel@tonic-gate     gl->insert = 0;
71507c478bd9Sstevel@tonic-gate /*
71517c478bd9Sstevel@tonic-gate  * Overwrite the current character plus count-1 subsequent characters
71527c478bd9Sstevel@tonic-gate  * with the replacement character.
71537c478bd9Sstevel@tonic-gate  */
71547c478bd9Sstevel@tonic-gate     for(i=0; i<count; i++)
71557c478bd9Sstevel@tonic-gate       gl_add_char_to_line(gl, c);
71567c478bd9Sstevel@tonic-gate /*
71577c478bd9Sstevel@tonic-gate  * Restore the original insert/overwrite mode.
71587c478bd9Sstevel@tonic-gate  */
71597c478bd9Sstevel@tonic-gate     gl->insert = insert;
71607c478bd9Sstevel@tonic-gate   };
71617c478bd9Sstevel@tonic-gate   return gl_place_cursor(gl, gl->buff_curpos);	/* bounds check */
71627c478bd9Sstevel@tonic-gate }
71637c478bd9Sstevel@tonic-gate 
71647c478bd9Sstevel@tonic-gate /*.......................................................................
71657c478bd9Sstevel@tonic-gate  * This is an action function which changes all characters between the
71667c478bd9Sstevel@tonic-gate  * current cursor position and the end of the line.
71677c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_change_rest_of_line)71687c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_rest_of_line)
71697c478bd9Sstevel@tonic-gate {
71707c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
71717c478bd9Sstevel@tonic-gate   gl->vi.command = 0;	/* Allow cursor at EOL */
71727c478bd9Sstevel@tonic-gate   return gl_kill_line(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
71737c478bd9Sstevel@tonic-gate }
71747c478bd9Sstevel@tonic-gate 
71757c478bd9Sstevel@tonic-gate /*.......................................................................
71767c478bd9Sstevel@tonic-gate  * This is an action function which changes all characters between the
71777c478bd9Sstevel@tonic-gate  * start of the line and the current cursor position.
71787c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_change_to_bol)71797c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_bol)
71807c478bd9Sstevel@tonic-gate {
71817c478bd9Sstevel@tonic-gate   return gl_backward_kill_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL);
71827c478bd9Sstevel@tonic-gate }
71837c478bd9Sstevel@tonic-gate 
71847c478bd9Sstevel@tonic-gate /*.......................................................................
71857c478bd9Sstevel@tonic-gate  * This is an action function which deletes the entire contents of the
71867c478bd9Sstevel@tonic-gate  * current line and switches to insert mode.
71877c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_change_line)71887c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_line)
71897c478bd9Sstevel@tonic-gate {
71907c478bd9Sstevel@tonic-gate   return gl_delete_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL);
71917c478bd9Sstevel@tonic-gate }
71927c478bd9Sstevel@tonic-gate 
71937c478bd9Sstevel@tonic-gate /*.......................................................................
71947c478bd9Sstevel@tonic-gate  * Starting from the cursor position and looking towards the end of the
71957c478bd9Sstevel@tonic-gate  * line, copy 'count' characters to the cut buffer.
71967c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_copy_char)71977c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_char)
71987c478bd9Sstevel@tonic-gate {
71997c478bd9Sstevel@tonic-gate /*
72007c478bd9Sstevel@tonic-gate  * Limit the count to the number of characters available.
72017c478bd9Sstevel@tonic-gate  */
72027c478bd9Sstevel@tonic-gate   if(gl->buff_curpos + count >= gl->ntotal)
72037c478bd9Sstevel@tonic-gate     count = gl->ntotal - gl->buff_curpos;
72047c478bd9Sstevel@tonic-gate   if(count < 0)
72057c478bd9Sstevel@tonic-gate     count = 0;
72067c478bd9Sstevel@tonic-gate /*
72077c478bd9Sstevel@tonic-gate  * Copy the characters to the cut buffer.
72087c478bd9Sstevel@tonic-gate  */
72097c478bd9Sstevel@tonic-gate   memcpy(gl->cutbuf, gl->line + gl->buff_curpos, count);
72107c478bd9Sstevel@tonic-gate   gl->cutbuf[count] = '\0';
72117c478bd9Sstevel@tonic-gate   return 0;
72127c478bd9Sstevel@tonic-gate }
72137c478bd9Sstevel@tonic-gate 
72147c478bd9Sstevel@tonic-gate /*.......................................................................
72157c478bd9Sstevel@tonic-gate  * Starting from the character before the cursor position and looking
72167c478bd9Sstevel@tonic-gate  * backwards towards the start of the line, copy 'count' characters to
72177c478bd9Sstevel@tonic-gate  * the cut buffer.
72187c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_copy_char)72197c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_char)
72207c478bd9Sstevel@tonic-gate {
72217c478bd9Sstevel@tonic-gate /*
72227c478bd9Sstevel@tonic-gate  * Limit the count to the number of characters available.
72237c478bd9Sstevel@tonic-gate  */
72247c478bd9Sstevel@tonic-gate   if(count > gl->buff_curpos)
72257c478bd9Sstevel@tonic-gate     count = gl->buff_curpos;
72267c478bd9Sstevel@tonic-gate   if(count < 0)
72277c478bd9Sstevel@tonic-gate     count = 0;
72287c478bd9Sstevel@tonic-gate   gl_place_cursor(gl, gl->buff_curpos - count);
72297c478bd9Sstevel@tonic-gate /*
72307c478bd9Sstevel@tonic-gate  * Copy the characters to the cut buffer.
72317c478bd9Sstevel@tonic-gate  */
72327c478bd9Sstevel@tonic-gate   memcpy(gl->cutbuf, gl->line + gl->buff_curpos, count);
72337c478bd9Sstevel@tonic-gate   gl->cutbuf[count] = '\0';
72347c478bd9Sstevel@tonic-gate   return 0;
72357c478bd9Sstevel@tonic-gate }
72367c478bd9Sstevel@tonic-gate 
72377c478bd9Sstevel@tonic-gate /*.......................................................................
72387c478bd9Sstevel@tonic-gate  * Starting from the cursor position copy to the specified column into the
72397c478bd9Sstevel@tonic-gate  * cut buffer.
72407c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_copy_to_column)72417c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_column)
72427c478bd9Sstevel@tonic-gate {
72437c478bd9Sstevel@tonic-gate   if (--count >= gl->buff_curpos)
72447c478bd9Sstevel@tonic-gate     return gl_forward_copy_char(gl, count - gl->buff_curpos, NULL);
72457c478bd9Sstevel@tonic-gate   else
72467c478bd9Sstevel@tonic-gate     return gl_backward_copy_char(gl, gl->buff_curpos - count, NULL);
72477c478bd9Sstevel@tonic-gate }
72487c478bd9Sstevel@tonic-gate 
72497c478bd9Sstevel@tonic-gate /*.......................................................................
72507c478bd9Sstevel@tonic-gate  * Starting from the cursor position copy characters up to a matching
72517c478bd9Sstevel@tonic-gate  * parenthesis into the cut buffer.
72527c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_copy_to_parenthesis)72537c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_parenthesis)
72547c478bd9Sstevel@tonic-gate {
72557c478bd9Sstevel@tonic-gate   int curpos = gl_index_of_matching_paren(gl);
72567c478bd9Sstevel@tonic-gate   if(curpos >= 0) {
72577c478bd9Sstevel@tonic-gate     gl_save_for_undo(gl);
72587c478bd9Sstevel@tonic-gate     if(curpos >= gl->buff_curpos)
72597c478bd9Sstevel@tonic-gate       return gl_forward_copy_char(gl, curpos - gl->buff_curpos + 1, NULL);
72607c478bd9Sstevel@tonic-gate     else
72617c478bd9Sstevel@tonic-gate       return gl_backward_copy_char(gl, ++gl->buff_curpos - curpos + 1, NULL);
72627c478bd9Sstevel@tonic-gate   };
72637c478bd9Sstevel@tonic-gate   return 0;
72647c478bd9Sstevel@tonic-gate }
72657c478bd9Sstevel@tonic-gate 
72667c478bd9Sstevel@tonic-gate /*.......................................................................
72677c478bd9Sstevel@tonic-gate  * Starting from the cursor position copy the rest of the line into the
72687c478bd9Sstevel@tonic-gate  * cut buffer.
72697c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_copy_rest_of_line)72707c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_rest_of_line)
72717c478bd9Sstevel@tonic-gate {
72727c478bd9Sstevel@tonic-gate /*
72737c478bd9Sstevel@tonic-gate  * Copy the characters to the cut buffer.
72747c478bd9Sstevel@tonic-gate  */
72757c478bd9Sstevel@tonic-gate   memcpy(gl->cutbuf, gl->line + gl->buff_curpos, gl->ntotal - gl->buff_curpos);
72767c478bd9Sstevel@tonic-gate   gl->cutbuf[gl->ntotal - gl->buff_curpos] = '\0';
72777c478bd9Sstevel@tonic-gate   return 0;
72787c478bd9Sstevel@tonic-gate }
72797c478bd9Sstevel@tonic-gate 
72807c478bd9Sstevel@tonic-gate /*.......................................................................
72817c478bd9Sstevel@tonic-gate  * Copy from the beginning of the line to the cursor position into the
72827c478bd9Sstevel@tonic-gate  * cut buffer.
72837c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_copy_to_bol)72847c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_bol)
72857c478bd9Sstevel@tonic-gate {
72867c478bd9Sstevel@tonic-gate /*
72877c478bd9Sstevel@tonic-gate  * Copy the characters to the cut buffer.
72887c478bd9Sstevel@tonic-gate  */
72897c478bd9Sstevel@tonic-gate   memcpy(gl->cutbuf, gl->line, gl->buff_curpos);
72907c478bd9Sstevel@tonic-gate   gl->cutbuf[gl->buff_curpos] = '\0';
72917c478bd9Sstevel@tonic-gate   gl_place_cursor(gl, 0);
72927c478bd9Sstevel@tonic-gate   return 0;
72937c478bd9Sstevel@tonic-gate }
72947c478bd9Sstevel@tonic-gate 
72957c478bd9Sstevel@tonic-gate /*.......................................................................
72967c478bd9Sstevel@tonic-gate  * Copy the entire line into the cut buffer.
72977c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_copy_line)72987c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_line)
72997c478bd9Sstevel@tonic-gate {
73007c478bd9Sstevel@tonic-gate /*
73017c478bd9Sstevel@tonic-gate  * Copy the characters to the cut buffer.
73027c478bd9Sstevel@tonic-gate  */
73037c478bd9Sstevel@tonic-gate   memcpy(gl->cutbuf, gl->line, gl->ntotal);
73047c478bd9Sstevel@tonic-gate   gl->cutbuf[gl->ntotal] = '\0';
73057c478bd9Sstevel@tonic-gate   return 0;
73067c478bd9Sstevel@tonic-gate }
73077c478bd9Sstevel@tonic-gate 
73087c478bd9Sstevel@tonic-gate /*.......................................................................
73097c478bd9Sstevel@tonic-gate  * Search forwards for the next character that the user enters.
73107c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_find_char)73117c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_find_char)
73127c478bd9Sstevel@tonic-gate {
73137c478bd9Sstevel@tonic-gate   int pos = gl_find_char(gl, count, 1, 1, '\0');
73147c478bd9Sstevel@tonic-gate   return pos >= 0 && gl_place_cursor(gl, pos);
73157c478bd9Sstevel@tonic-gate }
73167c478bd9Sstevel@tonic-gate 
73177c478bd9Sstevel@tonic-gate /*.......................................................................
73187c478bd9Sstevel@tonic-gate  * Search backwards for the next character that the user enters.
73197c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_find_char)73207c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_find_char)
73217c478bd9Sstevel@tonic-gate {
73227c478bd9Sstevel@tonic-gate   int pos = gl_find_char(gl, count, 0, 1, '\0');
73237c478bd9Sstevel@tonic-gate   return pos >= 0 && gl_place_cursor(gl, pos);
73247c478bd9Sstevel@tonic-gate }
73257c478bd9Sstevel@tonic-gate 
73267c478bd9Sstevel@tonic-gate /*.......................................................................
73277c478bd9Sstevel@tonic-gate  * Search forwards for the next character that the user enters. Move up to,
73287c478bd9Sstevel@tonic-gate  * but not onto, the found character.
73297c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_to_char)73307c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_to_char)
73317c478bd9Sstevel@tonic-gate {
73327c478bd9Sstevel@tonic-gate   int pos = gl_find_char(gl, count, 1, 0, '\0');
73337c478bd9Sstevel@tonic-gate   return pos >= 0 && gl_place_cursor(gl, pos);
73347c478bd9Sstevel@tonic-gate }
73357c478bd9Sstevel@tonic-gate 
73367c478bd9Sstevel@tonic-gate /*.......................................................................
73377c478bd9Sstevel@tonic-gate  * Search backwards for the next character that the user enters. Move back to,
73387c478bd9Sstevel@tonic-gate  * but not onto, the found character.
73397c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_to_char)73407c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_to_char)
73417c478bd9Sstevel@tonic-gate {
73427c478bd9Sstevel@tonic-gate   int pos = gl_find_char(gl, count, 0, 0, '\0');
73437c478bd9Sstevel@tonic-gate   return pos >= 0 && gl_place_cursor(gl, pos);
73447c478bd9Sstevel@tonic-gate }
73457c478bd9Sstevel@tonic-gate 
73467c478bd9Sstevel@tonic-gate /*.......................................................................
73477c478bd9Sstevel@tonic-gate  * Searching in a given direction, return the index of a given (or
73487c478bd9Sstevel@tonic-gate  * read) character in the input line, or the character that precedes
73497c478bd9Sstevel@tonic-gate  * it in the specified search direction. Return -1 if not found.
73507c478bd9Sstevel@tonic-gate  *
73517c478bd9Sstevel@tonic-gate  * Input:
73527c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
73537c478bd9Sstevel@tonic-gate  *  count        int    The number of times to search.
73547c478bd9Sstevel@tonic-gate  *  forward      int    True if searching forward.
73557c478bd9Sstevel@tonic-gate  *  onto         int    True if the search should end on top of the
73567c478bd9Sstevel@tonic-gate  *                      character, false if the search should stop
73577c478bd9Sstevel@tonic-gate  *                      one character before the character in the
73587c478bd9Sstevel@tonic-gate  *                      specified search direction.
73597c478bd9Sstevel@tonic-gate  *  c           char    The character to be sought, or '\0' if the
73607c478bd9Sstevel@tonic-gate  *                      character should be read from the user.
73617c478bd9Sstevel@tonic-gate  * Output:
73627c478bd9Sstevel@tonic-gate  *  return       int    The index of the character in gl->line[], or
73637c478bd9Sstevel@tonic-gate  *                      -1 if not found.
73647c478bd9Sstevel@tonic-gate  */
gl_find_char(GetLine * gl,int count,int forward,int onto,char c)73657c478bd9Sstevel@tonic-gate static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c)
73667c478bd9Sstevel@tonic-gate {
73677c478bd9Sstevel@tonic-gate   int pos;     /* The index reached in searching the input line */
73687c478bd9Sstevel@tonic-gate   int i;
73697c478bd9Sstevel@tonic-gate /*
73707c478bd9Sstevel@tonic-gate  * Get a character from the user?
73717c478bd9Sstevel@tonic-gate  */
73727c478bd9Sstevel@tonic-gate   if(!c) {
73737c478bd9Sstevel@tonic-gate /*
73747c478bd9Sstevel@tonic-gate  * If we are in the process of repeating a previous change command, substitute
73757c478bd9Sstevel@tonic-gate  * the last find character.
73767c478bd9Sstevel@tonic-gate  */
73777c478bd9Sstevel@tonic-gate     if(gl->vi.repeat.active) {
73787c478bd9Sstevel@tonic-gate       c = gl->vi.find_char;
73797c478bd9Sstevel@tonic-gate     } else {
73807c478bd9Sstevel@tonic-gate       if(gl_read_terminal(gl, 1, &c))
73817c478bd9Sstevel@tonic-gate 	return -1;
73827c478bd9Sstevel@tonic-gate /*
73837c478bd9Sstevel@tonic-gate  * Record the details of the new search, for use by repeat finds.
73847c478bd9Sstevel@tonic-gate  */
73857c478bd9Sstevel@tonic-gate       gl->vi.find_forward = forward;
73867c478bd9Sstevel@tonic-gate       gl->vi.find_onto = onto;
73877c478bd9Sstevel@tonic-gate       gl->vi.find_char = c;
73887c478bd9Sstevel@tonic-gate     };
73897c478bd9Sstevel@tonic-gate   };
73907c478bd9Sstevel@tonic-gate /*
73917c478bd9Sstevel@tonic-gate  * Which direction should we search?
73927c478bd9Sstevel@tonic-gate  */
73937c478bd9Sstevel@tonic-gate   if(forward) {
73947c478bd9Sstevel@tonic-gate /*
73957c478bd9Sstevel@tonic-gate  * Search forwards 'count' times for the character, starting with the
73967c478bd9Sstevel@tonic-gate  * character that follows the cursor.
73977c478bd9Sstevel@tonic-gate  */
73987c478bd9Sstevel@tonic-gate     for(i=0, pos=gl->buff_curpos; i<count && pos < gl->ntotal; i++) {
73997c478bd9Sstevel@tonic-gate /*
74007c478bd9Sstevel@tonic-gate  * Advance past the last match (or past the current cursor position
74017c478bd9Sstevel@tonic-gate  * on the first search).
74027c478bd9Sstevel@tonic-gate  */
74037c478bd9Sstevel@tonic-gate       pos++;
74047c478bd9Sstevel@tonic-gate /*
74057c478bd9Sstevel@tonic-gate  * Search for the next instance of c.
74067c478bd9Sstevel@tonic-gate  */
74077c478bd9Sstevel@tonic-gate       for( ; pos<gl->ntotal && c!=gl->line[pos]; pos++)
74087c478bd9Sstevel@tonic-gate 	;
74097c478bd9Sstevel@tonic-gate     };
74107c478bd9Sstevel@tonic-gate /*
74117c478bd9Sstevel@tonic-gate  * If the character was found and we have been requested to return the
74127c478bd9Sstevel@tonic-gate  * position of the character that precedes the desired character, then
74137c478bd9Sstevel@tonic-gate  * we have gone one character too far.
74147c478bd9Sstevel@tonic-gate  */
74157c478bd9Sstevel@tonic-gate     if(!onto && pos<gl->ntotal)
74167c478bd9Sstevel@tonic-gate       pos--;
74177c478bd9Sstevel@tonic-gate   } else {
74187c478bd9Sstevel@tonic-gate /*
74197c478bd9Sstevel@tonic-gate  * Search backwards 'count' times for the character, starting with the
74207c478bd9Sstevel@tonic-gate  * character that precedes the cursor.
74217c478bd9Sstevel@tonic-gate  */
74227c478bd9Sstevel@tonic-gate     for(i=0, pos=gl->buff_curpos; i<count && pos >= gl->insert_curpos; i++) {
74237c478bd9Sstevel@tonic-gate /*
74247c478bd9Sstevel@tonic-gate  * Step back one from the last match (or from the current cursor
74257c478bd9Sstevel@tonic-gate  * position on the first search).
74267c478bd9Sstevel@tonic-gate  */
74277c478bd9Sstevel@tonic-gate       pos--;
74287c478bd9Sstevel@tonic-gate /*
74297c478bd9Sstevel@tonic-gate  * Search for the next instance of c.
74307c478bd9Sstevel@tonic-gate  */
74317c478bd9Sstevel@tonic-gate       for( ; pos>=gl->insert_curpos && c!=gl->line[pos]; pos--)
74327c478bd9Sstevel@tonic-gate 	;
74337c478bd9Sstevel@tonic-gate     };
74347c478bd9Sstevel@tonic-gate /*
74357c478bd9Sstevel@tonic-gate  * If the character was found and we have been requested to return the
74367c478bd9Sstevel@tonic-gate  * position of the character that precedes the desired character, then
74377c478bd9Sstevel@tonic-gate  * we have gone one character too far.
74387c478bd9Sstevel@tonic-gate  */
74397c478bd9Sstevel@tonic-gate     if(!onto && pos>=gl->insert_curpos)
74407c478bd9Sstevel@tonic-gate       pos++;
74417c478bd9Sstevel@tonic-gate   };
74427c478bd9Sstevel@tonic-gate /*
74437c478bd9Sstevel@tonic-gate  * If found, return the cursor position of the count'th match.
74447c478bd9Sstevel@tonic-gate  * Otherwise ring the terminal bell.
74457c478bd9Sstevel@tonic-gate  */
74467c478bd9Sstevel@tonic-gate   if(pos >= gl->insert_curpos && pos < gl->ntotal) {
74477c478bd9Sstevel@tonic-gate     return pos;
74487c478bd9Sstevel@tonic-gate   } else {
74497c478bd9Sstevel@tonic-gate     (void) gl_ring_bell(gl, 1, NULL);
74507c478bd9Sstevel@tonic-gate     return -1;
74517c478bd9Sstevel@tonic-gate   }
74527c478bd9Sstevel@tonic-gate }
74537c478bd9Sstevel@tonic-gate 
74547c478bd9Sstevel@tonic-gate /*.......................................................................
74557c478bd9Sstevel@tonic-gate  * Repeat the last character search in the same direction as the last
74567c478bd9Sstevel@tonic-gate  * search.
74577c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_repeat_find_char)74587c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_repeat_find_char)
74597c478bd9Sstevel@tonic-gate {
74607c478bd9Sstevel@tonic-gate   int pos = gl->vi.find_char ?
74617c478bd9Sstevel@tonic-gate     gl_find_char(gl, count, gl->vi.find_forward, gl->vi.find_onto,
74627c478bd9Sstevel@tonic-gate 		 gl->vi.find_char) : -1;
74637c478bd9Sstevel@tonic-gate   return pos >= 0 && gl_place_cursor(gl, pos);
74647c478bd9Sstevel@tonic-gate }
74657c478bd9Sstevel@tonic-gate 
74667c478bd9Sstevel@tonic-gate /*.......................................................................
74677c478bd9Sstevel@tonic-gate  * Repeat the last character search in the opposite direction as the last
74687c478bd9Sstevel@tonic-gate  * search.
74697c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_invert_refind_char)74707c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_invert_refind_char)
74717c478bd9Sstevel@tonic-gate {
74727c478bd9Sstevel@tonic-gate   int pos = gl->vi.find_char ?
74737c478bd9Sstevel@tonic-gate     gl_find_char(gl, count, !gl->vi.find_forward, gl->vi.find_onto,
74747c478bd9Sstevel@tonic-gate 		 gl->vi.find_char) : -1;
74757c478bd9Sstevel@tonic-gate   return pos >= 0 && gl_place_cursor(gl, pos);
74767c478bd9Sstevel@tonic-gate }
74777c478bd9Sstevel@tonic-gate 
74787c478bd9Sstevel@tonic-gate /*.......................................................................
74797c478bd9Sstevel@tonic-gate  * Search forward from the current position of the cursor for 'count'
74807c478bd9Sstevel@tonic-gate  * word endings, returning the index of the last one found, or the end of
74817c478bd9Sstevel@tonic-gate  * the line if there were less than 'count' words.
74827c478bd9Sstevel@tonic-gate  *
74837c478bd9Sstevel@tonic-gate  * Input:
74847c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
74857c478bd9Sstevel@tonic-gate  *  n            int    The number of word boundaries to search for.
74867c478bd9Sstevel@tonic-gate  * Output:
74877c478bd9Sstevel@tonic-gate  *  return       int    The buffer index of the located position.
74887c478bd9Sstevel@tonic-gate  */
gl_nth_word_end_forward(GetLine * gl,int n)74897c478bd9Sstevel@tonic-gate static int gl_nth_word_end_forward(GetLine *gl, int n)
74907c478bd9Sstevel@tonic-gate {
74917c478bd9Sstevel@tonic-gate   int bufpos;   /* The buffer index being checked. */
74927c478bd9Sstevel@tonic-gate   int i;
74937c478bd9Sstevel@tonic-gate /*
74947c478bd9Sstevel@tonic-gate  * In order to guarantee forward motion to the next word ending,
74957c478bd9Sstevel@tonic-gate  * we need to start from one position to the right of the cursor
74967c478bd9Sstevel@tonic-gate  * position, since this may already be at the end of a word.
74977c478bd9Sstevel@tonic-gate  */
74987c478bd9Sstevel@tonic-gate   bufpos = gl->buff_curpos + 1;
74997c478bd9Sstevel@tonic-gate /*
75007c478bd9Sstevel@tonic-gate  * If we are at the end of the line, return the index of the last
75017c478bd9Sstevel@tonic-gate  * real character on the line. Note that this will be -1 if the line
75027c478bd9Sstevel@tonic-gate  * is empty.
75037c478bd9Sstevel@tonic-gate  */
75047c478bd9Sstevel@tonic-gate   if(bufpos >= gl->ntotal)
75057c478bd9Sstevel@tonic-gate     return gl->ntotal - 1;
75067c478bd9Sstevel@tonic-gate /*
75077c478bd9Sstevel@tonic-gate  * Search 'n' times, unless the end of the input line is reached first.
75087c478bd9Sstevel@tonic-gate  */
75097c478bd9Sstevel@tonic-gate   for(i=0; i<n && bufpos<gl->ntotal; i++) {
75107c478bd9Sstevel@tonic-gate /*
75117c478bd9Sstevel@tonic-gate  * If we are not already within a word, skip to the start of the next word.
75127c478bd9Sstevel@tonic-gate  */
75137c478bd9Sstevel@tonic-gate     for( ; bufpos<gl->ntotal && !gl_is_word_char((int)gl->line[bufpos]);
75147c478bd9Sstevel@tonic-gate 	bufpos++)
75157c478bd9Sstevel@tonic-gate       ;
75167c478bd9Sstevel@tonic-gate /*
75177c478bd9Sstevel@tonic-gate  * Find the end of the next word.
75187c478bd9Sstevel@tonic-gate  */
75197c478bd9Sstevel@tonic-gate     for( ; bufpos<gl->ntotal && gl_is_word_char((int)gl->line[bufpos]);
75207c478bd9Sstevel@tonic-gate 	bufpos++)
75217c478bd9Sstevel@tonic-gate       ;
75227c478bd9Sstevel@tonic-gate   };
75237c478bd9Sstevel@tonic-gate /*
75247c478bd9Sstevel@tonic-gate  * We will have overshot.
75257c478bd9Sstevel@tonic-gate  */
75267c478bd9Sstevel@tonic-gate   return bufpos > 0 ? bufpos-1 : bufpos;
75277c478bd9Sstevel@tonic-gate }
75287c478bd9Sstevel@tonic-gate 
75297c478bd9Sstevel@tonic-gate /*.......................................................................
75307c478bd9Sstevel@tonic-gate  * Search forward from the current position of the cursor for 'count'
75317c478bd9Sstevel@tonic-gate  * word starts, returning the index of the last one found, or the end of
75327c478bd9Sstevel@tonic-gate  * the line if there were less than 'count' words.
75337c478bd9Sstevel@tonic-gate  *
75347c478bd9Sstevel@tonic-gate  * Input:
75357c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
75367c478bd9Sstevel@tonic-gate  *  n            int    The number of word boundaries to search for.
75377c478bd9Sstevel@tonic-gate  * Output:
75387c478bd9Sstevel@tonic-gate  *  return       int    The buffer index of the located position.
75397c478bd9Sstevel@tonic-gate  */
gl_nth_word_start_forward(GetLine * gl,int n)75407c478bd9Sstevel@tonic-gate static int gl_nth_word_start_forward(GetLine *gl, int n)
75417c478bd9Sstevel@tonic-gate {
75427c478bd9Sstevel@tonic-gate   int bufpos;   /* The buffer index being checked. */
75437c478bd9Sstevel@tonic-gate   int i;
75447c478bd9Sstevel@tonic-gate /*
75457c478bd9Sstevel@tonic-gate  * Get the current cursor position.
75467c478bd9Sstevel@tonic-gate  */
75477c478bd9Sstevel@tonic-gate   bufpos = gl->buff_curpos;
75487c478bd9Sstevel@tonic-gate /*
75497c478bd9Sstevel@tonic-gate  * Search 'n' times, unless the end of the input line is reached first.
75507c478bd9Sstevel@tonic-gate  */
75517c478bd9Sstevel@tonic-gate   for(i=0; i<n && bufpos<gl->ntotal; i++) {
75527c478bd9Sstevel@tonic-gate /*
75537c478bd9Sstevel@tonic-gate  * Find the end of the current word.
75547c478bd9Sstevel@tonic-gate  */
75557c478bd9Sstevel@tonic-gate     for( ; bufpos<gl->ntotal && gl_is_word_char((int)gl->line[bufpos]);
75567c478bd9Sstevel@tonic-gate 	bufpos++)
75577c478bd9Sstevel@tonic-gate       ;
75587c478bd9Sstevel@tonic-gate /*
75597c478bd9Sstevel@tonic-gate  * Skip to the start of the next word.
75607c478bd9Sstevel@tonic-gate  */
75617c478bd9Sstevel@tonic-gate     for( ; bufpos<gl->ntotal && !gl_is_word_char((int)gl->line[bufpos]);
75627c478bd9Sstevel@tonic-gate 	bufpos++)
75637c478bd9Sstevel@tonic-gate       ;
75647c478bd9Sstevel@tonic-gate   };
75657c478bd9Sstevel@tonic-gate   return bufpos;
75667c478bd9Sstevel@tonic-gate }
75677c478bd9Sstevel@tonic-gate 
75687c478bd9Sstevel@tonic-gate /*.......................................................................
75697c478bd9Sstevel@tonic-gate  * Search backward from the current position of the cursor for 'count'
75707c478bd9Sstevel@tonic-gate  * word starts, returning the index of the last one found, or the start
75717c478bd9Sstevel@tonic-gate  * of the line if there were less than 'count' words.
75727c478bd9Sstevel@tonic-gate  *
75737c478bd9Sstevel@tonic-gate  * Input:
75747c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
75757c478bd9Sstevel@tonic-gate  *  n            int    The number of word boundaries to search for.
75767c478bd9Sstevel@tonic-gate  * Output:
75777c478bd9Sstevel@tonic-gate  *  return       int    The buffer index of the located position.
75787c478bd9Sstevel@tonic-gate  */
gl_nth_word_start_backward(GetLine * gl,int n)75797c478bd9Sstevel@tonic-gate static int gl_nth_word_start_backward(GetLine *gl, int n)
75807c478bd9Sstevel@tonic-gate {
75817c478bd9Sstevel@tonic-gate   int bufpos;   /* The buffer index being checked. */
75827c478bd9Sstevel@tonic-gate   int i;
75837c478bd9Sstevel@tonic-gate /*
75847c478bd9Sstevel@tonic-gate  * Get the current cursor position.
75857c478bd9Sstevel@tonic-gate  */
75867c478bd9Sstevel@tonic-gate   bufpos = gl->buff_curpos;
75877c478bd9Sstevel@tonic-gate /*
75887c478bd9Sstevel@tonic-gate  * Search 'n' times, unless the beginning of the input line (or vi insertion
75897c478bd9Sstevel@tonic-gate  * point) is reached first.
75907c478bd9Sstevel@tonic-gate  */
75917c478bd9Sstevel@tonic-gate   for(i=0; i<n && bufpos > gl->insert_curpos; i++) {
75927c478bd9Sstevel@tonic-gate /*
75937c478bd9Sstevel@tonic-gate  * Starting one character back from the last search, so as not to keep
75947c478bd9Sstevel@tonic-gate  * settling on the same word-start, search backwards until finding a
75957c478bd9Sstevel@tonic-gate  * word character.
75967c478bd9Sstevel@tonic-gate  */
75977c478bd9Sstevel@tonic-gate     while(--bufpos >= gl->insert_curpos &&
75987c478bd9Sstevel@tonic-gate           !gl_is_word_char((int)gl->line[bufpos]))
75997c478bd9Sstevel@tonic-gate       ;
76007c478bd9Sstevel@tonic-gate /*
76017c478bd9Sstevel@tonic-gate  * Find the start of the word.
76027c478bd9Sstevel@tonic-gate  */
76037c478bd9Sstevel@tonic-gate     while(--bufpos >= gl->insert_curpos &&
76047c478bd9Sstevel@tonic-gate           gl_is_word_char((int)gl->line[bufpos]))
76057c478bd9Sstevel@tonic-gate       ;
76067c478bd9Sstevel@tonic-gate /*
76077c478bd9Sstevel@tonic-gate  * We will have gone one character too far.
76087c478bd9Sstevel@tonic-gate  */
76097c478bd9Sstevel@tonic-gate     bufpos++;
76107c478bd9Sstevel@tonic-gate   };
76117c478bd9Sstevel@tonic-gate   return bufpos >= gl->insert_curpos ? bufpos : gl->insert_curpos;
76127c478bd9Sstevel@tonic-gate }
76137c478bd9Sstevel@tonic-gate 
76147c478bd9Sstevel@tonic-gate /*.......................................................................
76157c478bd9Sstevel@tonic-gate  * Copy one or more words into the cut buffer without moving the cursor
76167c478bd9Sstevel@tonic-gate  * or deleting text.
76177c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_copy_word)76187c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_word)
76197c478bd9Sstevel@tonic-gate {
76207c478bd9Sstevel@tonic-gate /*
76217c478bd9Sstevel@tonic-gate  * Find the location of the count'th start or end of a word
76227c478bd9Sstevel@tonic-gate  * after the cursor, depending on whether in emacs or vi mode.
76237c478bd9Sstevel@tonic-gate  */
76247c478bd9Sstevel@tonic-gate   int next = gl->editor == GL_EMACS_MODE ?
76257c478bd9Sstevel@tonic-gate     gl_nth_word_end_forward(gl, count) :
76267c478bd9Sstevel@tonic-gate     gl_nth_word_start_forward(gl, count);
76277c478bd9Sstevel@tonic-gate /*
76287c478bd9Sstevel@tonic-gate  * How many characters are to be copied into the cut buffer?
76297c478bd9Sstevel@tonic-gate  */
76307c478bd9Sstevel@tonic-gate   int n = next - gl->buff_curpos;
76317c478bd9Sstevel@tonic-gate /*
76327c478bd9Sstevel@tonic-gate  * Copy the specified segment and terminate the string.
76337c478bd9Sstevel@tonic-gate  */
76347c478bd9Sstevel@tonic-gate   memcpy(gl->cutbuf, gl->line + gl->buff_curpos, n);
76357c478bd9Sstevel@tonic-gate   gl->cutbuf[n] = '\0';
76367c478bd9Sstevel@tonic-gate   return 0;
76377c478bd9Sstevel@tonic-gate }
76387c478bd9Sstevel@tonic-gate 
76397c478bd9Sstevel@tonic-gate /*.......................................................................
76407c478bd9Sstevel@tonic-gate  * Copy one or more words preceding the cursor into the cut buffer,
76417c478bd9Sstevel@tonic-gate  * without moving the cursor or deleting text.
76427c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_copy_word)76437c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_word)
76447c478bd9Sstevel@tonic-gate {
76457c478bd9Sstevel@tonic-gate /*
76467c478bd9Sstevel@tonic-gate  * Find the location of the count'th start of word before the cursor.
76477c478bd9Sstevel@tonic-gate  */
76487c478bd9Sstevel@tonic-gate   int next = gl_nth_word_start_backward(gl, count);
76497c478bd9Sstevel@tonic-gate /*
76507c478bd9Sstevel@tonic-gate  * How many characters are to be copied into the cut buffer?
76517c478bd9Sstevel@tonic-gate  */
76527c478bd9Sstevel@tonic-gate   int n = gl->buff_curpos - next;
76537c478bd9Sstevel@tonic-gate   gl_place_cursor(gl, next);
76547c478bd9Sstevel@tonic-gate /*
76557c478bd9Sstevel@tonic-gate  * Copy the specified segment and terminate the string.
76567c478bd9Sstevel@tonic-gate  */
76577c478bd9Sstevel@tonic-gate   memcpy(gl->cutbuf, gl->line + next, n);
76587c478bd9Sstevel@tonic-gate   gl->cutbuf[n] = '\0';
76597c478bd9Sstevel@tonic-gate   return 0;
76607c478bd9Sstevel@tonic-gate }
76617c478bd9Sstevel@tonic-gate 
76627c478bd9Sstevel@tonic-gate /*.......................................................................
76637c478bd9Sstevel@tonic-gate  * Copy the characters between the cursor and the count'th instance of
76647c478bd9Sstevel@tonic-gate  * a specified character in the input line, into the cut buffer.
76657c478bd9Sstevel@tonic-gate  *
76667c478bd9Sstevel@tonic-gate  * Input:
76677c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
76687c478bd9Sstevel@tonic-gate  *  count        int    The number of times to search.
76697c478bd9Sstevel@tonic-gate  *  c           char    The character to be searched for, or '\0' if
76707c478bd9Sstevel@tonic-gate  *                      the character should be read from the user.
76717c478bd9Sstevel@tonic-gate  *  forward      int    True if searching forward.
76727c478bd9Sstevel@tonic-gate  *  onto         int    True if the search should end on top of the
76737c478bd9Sstevel@tonic-gate  *                      character, false if the search should stop
76747c478bd9Sstevel@tonic-gate  *                      one character before the character in the
76757c478bd9Sstevel@tonic-gate  *                      specified search direction.
76767c478bd9Sstevel@tonic-gate  * Output:
76777c478bd9Sstevel@tonic-gate  *  return       int    0 - OK.
76787c478bd9Sstevel@tonic-gate  *                      1 - Error.
76797c478bd9Sstevel@tonic-gate  *
76807c478bd9Sstevel@tonic-gate  */
gl_copy_find(GetLine * gl,int count,char c,int forward,int onto)76817c478bd9Sstevel@tonic-gate static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto)
76827c478bd9Sstevel@tonic-gate {
76837c478bd9Sstevel@tonic-gate   int n;  /* The number of characters in the cut buffer */
76847c478bd9Sstevel@tonic-gate /*
76857c478bd9Sstevel@tonic-gate  * Search for the character, and abort the operation if not found.
76867c478bd9Sstevel@tonic-gate  */
76877c478bd9Sstevel@tonic-gate   int pos = gl_find_char(gl, count, forward, onto, c);
76887c478bd9Sstevel@tonic-gate   if(pos < 0)
76897c478bd9Sstevel@tonic-gate     return 0;
76907c478bd9Sstevel@tonic-gate /*
76917c478bd9Sstevel@tonic-gate  * Copy the specified segment.
76927c478bd9Sstevel@tonic-gate  */
76937c478bd9Sstevel@tonic-gate   if(forward) {
76947c478bd9Sstevel@tonic-gate     n = pos + 1 - gl->buff_curpos;
76957c478bd9Sstevel@tonic-gate     memcpy(gl->cutbuf, gl->line + gl->buff_curpos, n);
76967c478bd9Sstevel@tonic-gate   } else {
76977c478bd9Sstevel@tonic-gate     n = gl->buff_curpos - pos;
76987c478bd9Sstevel@tonic-gate     memcpy(gl->cutbuf, gl->line + pos, n);
76997c478bd9Sstevel@tonic-gate     if(gl->editor == GL_VI_MODE)
77007c478bd9Sstevel@tonic-gate       gl_place_cursor(gl, pos);
77017c478bd9Sstevel@tonic-gate   }
77027c478bd9Sstevel@tonic-gate /*
77037c478bd9Sstevel@tonic-gate  * Terminate the copy.
77047c478bd9Sstevel@tonic-gate  */
77057c478bd9Sstevel@tonic-gate   gl->cutbuf[n] = '\0';
77067c478bd9Sstevel@tonic-gate   return 0;
77077c478bd9Sstevel@tonic-gate }
77087c478bd9Sstevel@tonic-gate 
77097c478bd9Sstevel@tonic-gate /*.......................................................................
77107c478bd9Sstevel@tonic-gate  * Copy a section up to and including a specified character into the cut
77117c478bd9Sstevel@tonic-gate  * buffer without moving the cursor or deleting text.
77127c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_copy_find)77137c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_find)
77147c478bd9Sstevel@tonic-gate {
77157c478bd9Sstevel@tonic-gate   return gl_copy_find(gl, count, '\0', 1, 1);
77167c478bd9Sstevel@tonic-gate }
77177c478bd9Sstevel@tonic-gate 
77187c478bd9Sstevel@tonic-gate /*.......................................................................
77197c478bd9Sstevel@tonic-gate  * Copy a section back to and including a specified character into the cut
77207c478bd9Sstevel@tonic-gate  * buffer without moving the cursor or deleting text.
77217c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_copy_find)77227c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_find)
77237c478bd9Sstevel@tonic-gate {
77247c478bd9Sstevel@tonic-gate   return gl_copy_find(gl, count, '\0', 0, 1);
77257c478bd9Sstevel@tonic-gate }
77267c478bd9Sstevel@tonic-gate 
77277c478bd9Sstevel@tonic-gate /*.......................................................................
77287c478bd9Sstevel@tonic-gate  * Copy a section up to and not including a specified character into the cut
77297c478bd9Sstevel@tonic-gate  * buffer without moving the cursor or deleting text.
77307c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_forward_copy_to)77317c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_to)
77327c478bd9Sstevel@tonic-gate {
77337c478bd9Sstevel@tonic-gate   return gl_copy_find(gl, count, '\0', 1, 0);
77347c478bd9Sstevel@tonic-gate }
77357c478bd9Sstevel@tonic-gate 
77367c478bd9Sstevel@tonic-gate /*.......................................................................
77377c478bd9Sstevel@tonic-gate  * Copy a section back to and not including a specified character into the cut
77387c478bd9Sstevel@tonic-gate  * buffer without moving the cursor or deleting text.
77397c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_backward_copy_to)77407c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_to)
77417c478bd9Sstevel@tonic-gate {
77427c478bd9Sstevel@tonic-gate   return gl_copy_find(gl, count, '\0', 0, 0);
77437c478bd9Sstevel@tonic-gate }
77447c478bd9Sstevel@tonic-gate 
77457c478bd9Sstevel@tonic-gate /*.......................................................................
77467c478bd9Sstevel@tonic-gate  * Copy to a character specified in a previous search into the cut
77477c478bd9Sstevel@tonic-gate  * buffer without moving the cursor or deleting text.
77487c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_copy_refind)77497c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_refind)
77507c478bd9Sstevel@tonic-gate {
77517c478bd9Sstevel@tonic-gate   return gl_copy_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
77527c478bd9Sstevel@tonic-gate 		      gl->vi.find_onto);
77537c478bd9Sstevel@tonic-gate }
77547c478bd9Sstevel@tonic-gate 
77557c478bd9Sstevel@tonic-gate /*.......................................................................
77567c478bd9Sstevel@tonic-gate  * Copy to a character specified in a previous search, but in the opposite
77577c478bd9Sstevel@tonic-gate  * direction, into the cut buffer without moving the cursor or deleting text.
77587c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_copy_invert_refind)77597c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_invert_refind)
77607c478bd9Sstevel@tonic-gate {
77617c478bd9Sstevel@tonic-gate   return gl_copy_find(gl, count, gl->vi.find_char, !gl->vi.find_forward,
77627c478bd9Sstevel@tonic-gate 		      gl->vi.find_onto);
77637c478bd9Sstevel@tonic-gate }
77647c478bd9Sstevel@tonic-gate 
77657c478bd9Sstevel@tonic-gate /*.......................................................................
77667c478bd9Sstevel@tonic-gate  * Set the position of the cursor in the line input buffer and the
77677c478bd9Sstevel@tonic-gate  * terminal.
77687c478bd9Sstevel@tonic-gate  *
77697c478bd9Sstevel@tonic-gate  * Input:
77707c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
77717c478bd9Sstevel@tonic-gate  *  buff_curpos  int    The new buffer cursor position.
77727c478bd9Sstevel@tonic-gate  * Output:
77737c478bd9Sstevel@tonic-gate  *  return       int    0 - OK.
77747c478bd9Sstevel@tonic-gate  *                      1 - Error.
77757c478bd9Sstevel@tonic-gate  */
gl_place_cursor(GetLine * gl,int buff_curpos)77767c478bd9Sstevel@tonic-gate static int gl_place_cursor(GetLine *gl, int buff_curpos)
77777c478bd9Sstevel@tonic-gate {
77787c478bd9Sstevel@tonic-gate /*
77797c478bd9Sstevel@tonic-gate  * Don't allow the cursor position to go out of the bounds of the input
77807c478bd9Sstevel@tonic-gate  * line.
77817c478bd9Sstevel@tonic-gate  */
77827c478bd9Sstevel@tonic-gate   if(buff_curpos >= gl->ntotal)
77837c478bd9Sstevel@tonic-gate     buff_curpos = gl->vi.command ? gl->ntotal-1 : gl->ntotal;
77847c478bd9Sstevel@tonic-gate   if(buff_curpos < 0)
77857c478bd9Sstevel@tonic-gate     buff_curpos = 0;
77867c478bd9Sstevel@tonic-gate /*
77877c478bd9Sstevel@tonic-gate  * Record the new buffer position.
77887c478bd9Sstevel@tonic-gate  */
77897c478bd9Sstevel@tonic-gate   gl->buff_curpos = buff_curpos;
77907c478bd9Sstevel@tonic-gate /*
77917c478bd9Sstevel@tonic-gate  * Move the terminal cursor to the corresponding character.
77927c478bd9Sstevel@tonic-gate  */
77937c478bd9Sstevel@tonic-gate   return gl_set_term_curpos(gl, gl->prompt_len +
77947c478bd9Sstevel@tonic-gate     gl_displayed_string_width(gl, gl->line, buff_curpos, gl->prompt_len));
77957c478bd9Sstevel@tonic-gate }
77967c478bd9Sstevel@tonic-gate 
77977c478bd9Sstevel@tonic-gate /*.......................................................................
77987c478bd9Sstevel@tonic-gate  * In vi command mode, this function saves the current line to the
77997c478bd9Sstevel@tonic-gate  * historical buffer needed by the undo command. In emacs mode it does
78007c478bd9Sstevel@tonic-gate  * nothing. In order to allow action functions to call other action
78017c478bd9Sstevel@tonic-gate  * functions, gl_interpret_char() sets gl->vi.undo.saved to 0 before
78027c478bd9Sstevel@tonic-gate  * invoking an action, and thereafter once any call to this function
78037c478bd9Sstevel@tonic-gate  * has set it to 1, further calls are ignored.
78047c478bd9Sstevel@tonic-gate  *
78057c478bd9Sstevel@tonic-gate  * Input:
78067c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
78077c478bd9Sstevel@tonic-gate  */
gl_save_for_undo(GetLine * gl)78087c478bd9Sstevel@tonic-gate static void gl_save_for_undo(GetLine *gl)
78097c478bd9Sstevel@tonic-gate {
78107c478bd9Sstevel@tonic-gate   if(gl->vi.command && !gl->vi.undo.saved) {
78117c478bd9Sstevel@tonic-gate     strlcpy(gl->vi.undo.line, gl->line, gl->linelen);
78127c478bd9Sstevel@tonic-gate     gl->vi.undo.buff_curpos = gl->buff_curpos;
78137c478bd9Sstevel@tonic-gate     gl->vi.undo.ntotal = gl->ntotal;
78147c478bd9Sstevel@tonic-gate     gl->vi.undo.saved = 1;
78157c478bd9Sstevel@tonic-gate   };
78167c478bd9Sstevel@tonic-gate   if(gl->vi.command && !gl->vi.repeat.saved &&
78177c478bd9Sstevel@tonic-gate      gl->current_action.fn != gl_vi_repeat_change) {
78187c478bd9Sstevel@tonic-gate     gl->vi.repeat.action = gl->current_action;
78197c478bd9Sstevel@tonic-gate     gl->vi.repeat.count = gl->current_count;
78207c478bd9Sstevel@tonic-gate     gl->vi.repeat.saved = 1;
78217c478bd9Sstevel@tonic-gate   };
78227c478bd9Sstevel@tonic-gate   return;
78237c478bd9Sstevel@tonic-gate }
78247c478bd9Sstevel@tonic-gate 
78257c478bd9Sstevel@tonic-gate /*.......................................................................
78267c478bd9Sstevel@tonic-gate  * In vi mode, restore the line to the way it was before the last command
78277c478bd9Sstevel@tonic-gate  * mode operation, storing the current line in the buffer so that the
78287c478bd9Sstevel@tonic-gate  * undo operation itself can subsequently be undone.
78297c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_undo)78307c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_undo)
78317c478bd9Sstevel@tonic-gate {
78327c478bd9Sstevel@tonic-gate /*
78337c478bd9Sstevel@tonic-gate  * Get pointers into the two lines.
78347c478bd9Sstevel@tonic-gate  */
78357c478bd9Sstevel@tonic-gate   char *undo_ptr = gl->vi.undo.line;
78367c478bd9Sstevel@tonic-gate   char *line_ptr = gl->line;
78377c478bd9Sstevel@tonic-gate /*
78387c478bd9Sstevel@tonic-gate  * Swap the characters of the two buffers up to the length of the shortest
78397c478bd9Sstevel@tonic-gate  * line.
78407c478bd9Sstevel@tonic-gate  */
78417c478bd9Sstevel@tonic-gate   while(*undo_ptr && *line_ptr) {
78427c478bd9Sstevel@tonic-gate     char c = *undo_ptr;
78437c478bd9Sstevel@tonic-gate     *undo_ptr++ = *line_ptr;
78447c478bd9Sstevel@tonic-gate     *line_ptr++ = c;
78457c478bd9Sstevel@tonic-gate   };
78467c478bd9Sstevel@tonic-gate /*
78477c478bd9Sstevel@tonic-gate  * Copy the rest directly.
78487c478bd9Sstevel@tonic-gate  */
78497c478bd9Sstevel@tonic-gate   if(gl->ntotal > gl->vi.undo.ntotal) {
78507c478bd9Sstevel@tonic-gate     strlcpy(undo_ptr, line_ptr, gl->linelen);
78517c478bd9Sstevel@tonic-gate     *line_ptr = '\0';
78527c478bd9Sstevel@tonic-gate   } else {
78537c478bd9Sstevel@tonic-gate     strlcpy(line_ptr, undo_ptr, gl->linelen);
78547c478bd9Sstevel@tonic-gate     *undo_ptr = '\0';
78557c478bd9Sstevel@tonic-gate   };
78567c478bd9Sstevel@tonic-gate /*
78577c478bd9Sstevel@tonic-gate  * Record the length of the stored string.
78587c478bd9Sstevel@tonic-gate  */
78597c478bd9Sstevel@tonic-gate   gl->vi.undo.ntotal = gl->ntotal;
78607c478bd9Sstevel@tonic-gate /*
78617c478bd9Sstevel@tonic-gate  * Accomodate the new contents of gl->line[].
78627c478bd9Sstevel@tonic-gate  */
78637c478bd9Sstevel@tonic-gate   gl_update_buffer(gl);
78647c478bd9Sstevel@tonic-gate /*
78657c478bd9Sstevel@tonic-gate  * Set both cursor positions to the leftmost of the saved and current
78667c478bd9Sstevel@tonic-gate  * cursor positions to emulate what vi does.
78677c478bd9Sstevel@tonic-gate  */
78687c478bd9Sstevel@tonic-gate   if(gl->buff_curpos < gl->vi.undo.buff_curpos)
78697c478bd9Sstevel@tonic-gate     gl->vi.undo.buff_curpos = gl->buff_curpos;
78707c478bd9Sstevel@tonic-gate   else
78717c478bd9Sstevel@tonic-gate     gl->buff_curpos = gl->vi.undo.buff_curpos;
78727c478bd9Sstevel@tonic-gate /*
78737c478bd9Sstevel@tonic-gate  * Since we have bipassed calling gl_save_for_undo(), record repeat
78747c478bd9Sstevel@tonic-gate  * information inline.
78757c478bd9Sstevel@tonic-gate  */
78767c478bd9Sstevel@tonic-gate   gl->vi.repeat.action.fn = gl_vi_undo;
78777c478bd9Sstevel@tonic-gate   gl->vi.repeat.action.data = NULL;
78787c478bd9Sstevel@tonic-gate   gl->vi.repeat.count = 1;
78797c478bd9Sstevel@tonic-gate /*
78807c478bd9Sstevel@tonic-gate  * Display the restored line.
78817c478bd9Sstevel@tonic-gate  */
78827c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
78837c478bd9Sstevel@tonic-gate   return 0;
78847c478bd9Sstevel@tonic-gate }
78857c478bd9Sstevel@tonic-gate 
78867c478bd9Sstevel@tonic-gate /*.......................................................................
78877c478bd9Sstevel@tonic-gate  * Delete the following word and leave the user in vi insert mode.
78887c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_forward_change_word)78897c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_word)
78907c478bd9Sstevel@tonic-gate {
78917c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
78927c478bd9Sstevel@tonic-gate   gl->vi.command = 0;	/* Allow cursor at EOL */
78937c478bd9Sstevel@tonic-gate   return gl_forward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
78947c478bd9Sstevel@tonic-gate }
78957c478bd9Sstevel@tonic-gate 
78967c478bd9Sstevel@tonic-gate /*.......................................................................
78977c478bd9Sstevel@tonic-gate  * Delete the preceding word and leave the user in vi insert mode.
78987c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_backward_change_word)78997c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_word)
79007c478bd9Sstevel@tonic-gate {
79017c478bd9Sstevel@tonic-gate   return gl_backward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
79027c478bd9Sstevel@tonic-gate }
79037c478bd9Sstevel@tonic-gate 
79047c478bd9Sstevel@tonic-gate /*.......................................................................
79057c478bd9Sstevel@tonic-gate  * Delete the following section and leave the user in vi insert mode.
79067c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_forward_change_find)79077c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_find)
79087c478bd9Sstevel@tonic-gate {
79097c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, '\0', 1, 1, 1);
79107c478bd9Sstevel@tonic-gate }
79117c478bd9Sstevel@tonic-gate 
79127c478bd9Sstevel@tonic-gate /*.......................................................................
79137c478bd9Sstevel@tonic-gate  * Delete the preceding section and leave the user in vi insert mode.
79147c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_backward_change_find)79157c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_find)
79167c478bd9Sstevel@tonic-gate {
79177c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, '\0', 0, 1, 1);
79187c478bd9Sstevel@tonic-gate }
79197c478bd9Sstevel@tonic-gate 
79207c478bd9Sstevel@tonic-gate /*.......................................................................
79217c478bd9Sstevel@tonic-gate  * Delete the following section and leave the user in vi insert mode.
79227c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_forward_change_to)79237c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_to)
79247c478bd9Sstevel@tonic-gate {
79257c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, '\0', 1, 0, 1);
79267c478bd9Sstevel@tonic-gate }
79277c478bd9Sstevel@tonic-gate 
79287c478bd9Sstevel@tonic-gate /*.......................................................................
79297c478bd9Sstevel@tonic-gate  * Delete the preceding section and leave the user in vi insert mode.
79307c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_backward_change_to)79317c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_to)
79327c478bd9Sstevel@tonic-gate {
79337c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, '\0', 0, 0, 1);
79347c478bd9Sstevel@tonic-gate }
79357c478bd9Sstevel@tonic-gate 
79367c478bd9Sstevel@tonic-gate /*.......................................................................
79377c478bd9Sstevel@tonic-gate  * Delete to a character specified by a previous search and leave the user
79387c478bd9Sstevel@tonic-gate  * in vi insert mode.
79397c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_change_refind)79407c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_refind)
79417c478bd9Sstevel@tonic-gate {
79427c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward,
79437c478bd9Sstevel@tonic-gate 			gl->vi.find_onto, 1);
79447c478bd9Sstevel@tonic-gate }
79457c478bd9Sstevel@tonic-gate 
79467c478bd9Sstevel@tonic-gate /*.......................................................................
79477c478bd9Sstevel@tonic-gate  * Delete to a character specified by a previous search, but in the opposite
79487c478bd9Sstevel@tonic-gate  * direction, and leave the user in vi insert mode.
79497c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_change_invert_refind)79507c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_invert_refind)
79517c478bd9Sstevel@tonic-gate {
79527c478bd9Sstevel@tonic-gate   return gl_delete_find(gl, count, gl->vi.find_char, !gl->vi.find_forward,
79537c478bd9Sstevel@tonic-gate 			gl->vi.find_onto, 1);
79547c478bd9Sstevel@tonic-gate }
79557c478bd9Sstevel@tonic-gate 
79567c478bd9Sstevel@tonic-gate /*.......................................................................
79577c478bd9Sstevel@tonic-gate  * Delete the following character and leave the user in vi insert mode.
79587c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_forward_change_char)79597c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_char)
79607c478bd9Sstevel@tonic-gate {
79617c478bd9Sstevel@tonic-gate   gl_save_for_undo(gl);
79627c478bd9Sstevel@tonic-gate   gl->vi.command = 0;	/* Allow cursor at EOL */
79637c478bd9Sstevel@tonic-gate   return gl_delete_chars(gl, count, 1) || gl_vi_insert(gl, 0, NULL);
79647c478bd9Sstevel@tonic-gate }
79657c478bd9Sstevel@tonic-gate 
79667c478bd9Sstevel@tonic-gate /*.......................................................................
79677c478bd9Sstevel@tonic-gate  * Delete the preceding character and leave the user in vi insert mode.
79687c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_backward_change_char)79697c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_char)
79707c478bd9Sstevel@tonic-gate {
79717c478bd9Sstevel@tonic-gate   return gl_backward_delete_char(gl, count, NULL) || gl_vi_insert(gl, 0, NULL);
79727c478bd9Sstevel@tonic-gate }
79737c478bd9Sstevel@tonic-gate 
79747c478bd9Sstevel@tonic-gate /*.......................................................................
79757c478bd9Sstevel@tonic-gate  * Starting from the cursor position change characters to the specified column.
79767c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_change_to_column)79777c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_column)
79787c478bd9Sstevel@tonic-gate {
79797c478bd9Sstevel@tonic-gate   if (--count >= gl->buff_curpos)
79807c478bd9Sstevel@tonic-gate     return gl_vi_forward_change_char(gl, count - gl->buff_curpos, NULL);
79817c478bd9Sstevel@tonic-gate   else
79827c478bd9Sstevel@tonic-gate     return gl_vi_backward_change_char(gl, gl->buff_curpos - count, NULL);
79837c478bd9Sstevel@tonic-gate }
79847c478bd9Sstevel@tonic-gate 
79857c478bd9Sstevel@tonic-gate /*.......................................................................
79867c478bd9Sstevel@tonic-gate  * Starting from the cursor position change characters to a matching
79877c478bd9Sstevel@tonic-gate  * parenthesis.
79887c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_change_to_parenthesis)79897c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_parenthesis)
79907c478bd9Sstevel@tonic-gate {
79917c478bd9Sstevel@tonic-gate   int curpos = gl_index_of_matching_paren(gl);
79927c478bd9Sstevel@tonic-gate   if(curpos >= 0) {
79937c478bd9Sstevel@tonic-gate     gl_save_for_undo(gl);
79947c478bd9Sstevel@tonic-gate     if(curpos >= gl->buff_curpos)
79957c478bd9Sstevel@tonic-gate       return gl_vi_forward_change_char(gl, curpos - gl->buff_curpos + 1, NULL);
79967c478bd9Sstevel@tonic-gate     else
79977c478bd9Sstevel@tonic-gate       return gl_vi_backward_change_char(gl, ++gl->buff_curpos - curpos + 1,
79987c478bd9Sstevel@tonic-gate 					NULL);
79997c478bd9Sstevel@tonic-gate   };
80007c478bd9Sstevel@tonic-gate   return 0;
80017c478bd9Sstevel@tonic-gate }
80027c478bd9Sstevel@tonic-gate 
80037c478bd9Sstevel@tonic-gate /*.......................................................................
80047c478bd9Sstevel@tonic-gate  * If in vi mode, switch to vi command mode.
80057c478bd9Sstevel@tonic-gate  *
80067c478bd9Sstevel@tonic-gate  * Input:
80077c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
80087c478bd9Sstevel@tonic-gate  */
gl_vi_command_mode(GetLine * gl)80097c478bd9Sstevel@tonic-gate static void gl_vi_command_mode(GetLine *gl)
80107c478bd9Sstevel@tonic-gate {
80117c478bd9Sstevel@tonic-gate   if(gl->editor == GL_VI_MODE && !gl->vi.command) {
80127c478bd9Sstevel@tonic-gate     gl->insert = 1;
80137c478bd9Sstevel@tonic-gate     gl->vi.command = 1;
80147c478bd9Sstevel@tonic-gate     gl->vi.repeat.input_curpos = gl->insert_curpos;
80157c478bd9Sstevel@tonic-gate     gl->vi.repeat.command_curpos = gl->buff_curpos;
80167c478bd9Sstevel@tonic-gate     gl->insert_curpos = 0;	 /* unrestrict left motion boundary */
80177c478bd9Sstevel@tonic-gate     gl_cursor_left(gl, 1, NULL); /* Vi moves 1 left on entering command mode */
80187c478bd9Sstevel@tonic-gate   };
80197c478bd9Sstevel@tonic-gate }
80207c478bd9Sstevel@tonic-gate 
80217c478bd9Sstevel@tonic-gate /*.......................................................................
80227c478bd9Sstevel@tonic-gate  * This is an action function which rings the terminal bell.
80237c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_ring_bell)80247c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_ring_bell)
80257c478bd9Sstevel@tonic-gate {
80267c478bd9Sstevel@tonic-gate   return gl->silence_bell ? 0 :
80277c478bd9Sstevel@tonic-gate     gl_print_control_sequence(gl, 1, gl->sound_bell);
80287c478bd9Sstevel@tonic-gate }
80297c478bd9Sstevel@tonic-gate 
80307c478bd9Sstevel@tonic-gate /*.......................................................................
80317c478bd9Sstevel@tonic-gate  * This is the action function which implements the vi-repeat-change
80327c478bd9Sstevel@tonic-gate  * action.
80337c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_vi_repeat_change)80347c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_repeat_change)
80357c478bd9Sstevel@tonic-gate {
80367c478bd9Sstevel@tonic-gate   int status;   /* The return status of the repeated action function */
80377c478bd9Sstevel@tonic-gate   int i;
80387c478bd9Sstevel@tonic-gate /*
80397c478bd9Sstevel@tonic-gate  * Nothing to repeat?
80407c478bd9Sstevel@tonic-gate  */
80417c478bd9Sstevel@tonic-gate   if(!gl->vi.repeat.action.fn)
80427c478bd9Sstevel@tonic-gate     return gl_ring_bell(gl, 1, NULL);
80437c478bd9Sstevel@tonic-gate /*
80447c478bd9Sstevel@tonic-gate  * Provide a way for action functions to know whether they are being
80457c478bd9Sstevel@tonic-gate  * called by us.
80467c478bd9Sstevel@tonic-gate  */
80477c478bd9Sstevel@tonic-gate   gl->vi.repeat.active = 1;
80487c478bd9Sstevel@tonic-gate /*
80497c478bd9Sstevel@tonic-gate  * Re-run the recorded function.
80507c478bd9Sstevel@tonic-gate  */
80517c478bd9Sstevel@tonic-gate   status = gl->vi.repeat.action.fn(gl, gl->vi.repeat.count,
80527c478bd9Sstevel@tonic-gate 				   gl->vi.repeat.action.data);
80537c478bd9Sstevel@tonic-gate /*
80547c478bd9Sstevel@tonic-gate  * Mark the repeat as completed.
80557c478bd9Sstevel@tonic-gate  */
80567c478bd9Sstevel@tonic-gate   gl->vi.repeat.active = 0;
80577c478bd9Sstevel@tonic-gate /*
80587c478bd9Sstevel@tonic-gate  * Is we are repeating a function that has just switched to input
80597c478bd9Sstevel@tonic-gate  * mode to allow the user to type, re-enter the text that the user
80607c478bd9Sstevel@tonic-gate  * previously entered.
80617c478bd9Sstevel@tonic-gate  */
80627c478bd9Sstevel@tonic-gate   if(status==0 && !gl->vi.command) {
80637c478bd9Sstevel@tonic-gate /*
80647c478bd9Sstevel@tonic-gate  * Make sure that the current line has been saved.
80657c478bd9Sstevel@tonic-gate  */
80667c478bd9Sstevel@tonic-gate     gl_save_for_undo(gl);
80677c478bd9Sstevel@tonic-gate /*
80687c478bd9Sstevel@tonic-gate  * Repeat a previous insertion or overwrite?
80697c478bd9Sstevel@tonic-gate  */
80707c478bd9Sstevel@tonic-gate     if(gl->vi.repeat.input_curpos >= 0 &&
80717c478bd9Sstevel@tonic-gate        gl->vi.repeat.input_curpos <= gl->vi.repeat.command_curpos &&
80727c478bd9Sstevel@tonic-gate        gl->vi.repeat.command_curpos <= gl->vi.undo.ntotal) {
80737c478bd9Sstevel@tonic-gate /*
80747c478bd9Sstevel@tonic-gate  * Using the current line which is saved in the undo buffer, plus
80757c478bd9Sstevel@tonic-gate  * the range of characters therein, as recorded by gl_vi_command_mode(),
80767c478bd9Sstevel@tonic-gate  * add the characters that the user previously entered, to the input
80777c478bd9Sstevel@tonic-gate  * line.
80787c478bd9Sstevel@tonic-gate  */
80797c478bd9Sstevel@tonic-gate       for(i=gl->vi.repeat.input_curpos; i<gl->vi.repeat.command_curpos; i++) {
80807c478bd9Sstevel@tonic-gate 	if(gl_add_char_to_line(gl, gl->vi.undo.line[i]))
80817c478bd9Sstevel@tonic-gate 	  return 1;
80827c478bd9Sstevel@tonic-gate       };
80837c478bd9Sstevel@tonic-gate     };
80847c478bd9Sstevel@tonic-gate /*
80857c478bd9Sstevel@tonic-gate  * Switch back to command mode, now that the insertion has been repeated.
80867c478bd9Sstevel@tonic-gate  */
80877c478bd9Sstevel@tonic-gate     gl_vi_command_mode(gl);
80887c478bd9Sstevel@tonic-gate   };
80897c478bd9Sstevel@tonic-gate   return status;
80907c478bd9Sstevel@tonic-gate }
80917c478bd9Sstevel@tonic-gate 
80927c478bd9Sstevel@tonic-gate /*.......................................................................
80937c478bd9Sstevel@tonic-gate  * If the cursor is currently over a parenthesis character, return the
80947c478bd9Sstevel@tonic-gate  * index of its matching parenthesis. If not currently over a parenthesis
80957c478bd9Sstevel@tonic-gate  * character, return the next close parenthesis character to the right of
80967c478bd9Sstevel@tonic-gate  * the cursor. If the respective parenthesis character isn't found,
80977c478bd9Sstevel@tonic-gate  * ring the terminal bell and return -1.
80987c478bd9Sstevel@tonic-gate  *
80997c478bd9Sstevel@tonic-gate  * Input:
81007c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The getline resource object.
81017c478bd9Sstevel@tonic-gate  * Output:
81027c478bd9Sstevel@tonic-gate  *  return       int    Either the index of the matching parenthesis,
81037c478bd9Sstevel@tonic-gate  *                      or -1 if not found.
81047c478bd9Sstevel@tonic-gate  */
gl_index_of_matching_paren(GetLine * gl)81057c478bd9Sstevel@tonic-gate static int gl_index_of_matching_paren(GetLine *gl)
81067c478bd9Sstevel@tonic-gate {
81077c478bd9Sstevel@tonic-gate   int i;
81087c478bd9Sstevel@tonic-gate /*
81097c478bd9Sstevel@tonic-gate  * List the recognized parentheses, and their matches.
81107c478bd9Sstevel@tonic-gate  */
81117c478bd9Sstevel@tonic-gate   const char *o_paren = "([{";
81127c478bd9Sstevel@tonic-gate   const char *c_paren = ")]}";
81137c478bd9Sstevel@tonic-gate   const char *cptr;
81147c478bd9Sstevel@tonic-gate /*
81157c478bd9Sstevel@tonic-gate  * Get the character that is currently under the cursor.
81167c478bd9Sstevel@tonic-gate  */
81177c478bd9Sstevel@tonic-gate   char c = gl->line[gl->buff_curpos];
81187c478bd9Sstevel@tonic-gate /*
81197c478bd9Sstevel@tonic-gate  * If the character under the cursor is an open parenthesis, look forward
81207c478bd9Sstevel@tonic-gate  * for the matching close parenthesis.
81217c478bd9Sstevel@tonic-gate  */
81227c478bd9Sstevel@tonic-gate   if((cptr=strchr(o_paren, c))) {
81237c478bd9Sstevel@tonic-gate     char match = c_paren[cptr - o_paren];
81247c478bd9Sstevel@tonic-gate     int matches_needed = 1;
81257c478bd9Sstevel@tonic-gate     for(i=gl->buff_curpos+1; i<gl->ntotal; i++) {
81267c478bd9Sstevel@tonic-gate       if(gl->line[i] == c)
81277c478bd9Sstevel@tonic-gate 	matches_needed++;
81287c478bd9Sstevel@tonic-gate       else if(gl->line[i] == match && --matches_needed==0)
81297c478bd9Sstevel@tonic-gate 	return i;
81307c478bd9Sstevel@tonic-gate     };
81317c478bd9Sstevel@tonic-gate /*
81327c478bd9Sstevel@tonic-gate  * If the character under the cursor is an close parenthesis, look forward
81337c478bd9Sstevel@tonic-gate  * for the matching open parenthesis.
81347c478bd9Sstevel@tonic-gate  */
81357c478bd9Sstevel@tonic-gate   } else if((cptr=strchr(c_paren, c))) {
81367c478bd9Sstevel@tonic-gate     char match = o_paren[cptr - c_paren];
81377c478bd9Sstevel@tonic-gate     int matches_needed = 1;
81387c478bd9Sstevel@tonic-gate     for(i=gl->buff_curpos-1; i>=0; i--) {
81397c478bd9Sstevel@tonic-gate       if(gl->line[i] == c)
81407c478bd9Sstevel@tonic-gate 	matches_needed++;
81417c478bd9Sstevel@tonic-gate       else if(gl->line[i] == match && --matches_needed==0)
81427c478bd9Sstevel@tonic-gate 	return i;
81437c478bd9Sstevel@tonic-gate     };
81447c478bd9Sstevel@tonic-gate /*
81457c478bd9Sstevel@tonic-gate  * If not currently over a parenthesis character, search forwards for
81467c478bd9Sstevel@tonic-gate  * the first close parenthesis (this is what the vi % binding does).
81477c478bd9Sstevel@tonic-gate  */
81487c478bd9Sstevel@tonic-gate   } else {
81497c478bd9Sstevel@tonic-gate     for(i=gl->buff_curpos+1; i<gl->ntotal; i++)
81507c478bd9Sstevel@tonic-gate       if(strchr(c_paren, gl->line[i]) != NULL)
81517c478bd9Sstevel@tonic-gate 	return i;
81527c478bd9Sstevel@tonic-gate   };
81537c478bd9Sstevel@tonic-gate /*
81547c478bd9Sstevel@tonic-gate  * Not found.
81557c478bd9Sstevel@tonic-gate  */
81567c478bd9Sstevel@tonic-gate   (void) gl_ring_bell(gl, 1, NULL);
81577c478bd9Sstevel@tonic-gate   return -1;
81587c478bd9Sstevel@tonic-gate }
81597c478bd9Sstevel@tonic-gate 
81607c478bd9Sstevel@tonic-gate /*.......................................................................
81617c478bd9Sstevel@tonic-gate  * If the cursor is currently over a parenthesis character, this action
81627c478bd9Sstevel@tonic-gate  * function moves the cursor to its matching parenthesis.
81637c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_find_parenthesis)81647c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_find_parenthesis)
81657c478bd9Sstevel@tonic-gate {
81667c478bd9Sstevel@tonic-gate   int curpos = gl_index_of_matching_paren(gl);
81677c478bd9Sstevel@tonic-gate   if(curpos >= 0)
81687c478bd9Sstevel@tonic-gate     return gl_place_cursor(gl, curpos);
81697c478bd9Sstevel@tonic-gate   return 0;
81707c478bd9Sstevel@tonic-gate }
81717c478bd9Sstevel@tonic-gate 
81727c478bd9Sstevel@tonic-gate /*.......................................................................
81737c478bd9Sstevel@tonic-gate  * Handle the receipt of the potential start of a new key-sequence from
81747c478bd9Sstevel@tonic-gate  * the user.
81757c478bd9Sstevel@tonic-gate  *
81767c478bd9Sstevel@tonic-gate  * Input:
81777c478bd9Sstevel@tonic-gate  *  gl      GetLine *   The resource object of this library.
81787c478bd9Sstevel@tonic-gate  *  first_char char     The first character of the sequence.
81797c478bd9Sstevel@tonic-gate  * Output:
81807c478bd9Sstevel@tonic-gate  *  return      int     0 - OK.
81817c478bd9Sstevel@tonic-gate  *                      1 - Error.
81827c478bd9Sstevel@tonic-gate  */
gl_interpret_char(GetLine * gl,char first_char)81837c478bd9Sstevel@tonic-gate static int gl_interpret_char(GetLine *gl, char first_char)
81847c478bd9Sstevel@tonic-gate {
81857c478bd9Sstevel@tonic-gate   char keyseq[GL_KEY_MAX+1]; /* A special key sequence being read */
81867c478bd9Sstevel@tonic-gate   int nkey=0;                /* The number of characters in the key sequence */
81877c478bd9Sstevel@tonic-gate   int count;                 /* The repeat count of an action function */
81887c478bd9Sstevel@tonic-gate   int ret;                   /* The return value of an action function */
81897c478bd9Sstevel@tonic-gate   int i;
81907c478bd9Sstevel@tonic-gate /*
81917c478bd9Sstevel@tonic-gate  * Get the first character.
81927c478bd9Sstevel@tonic-gate  */
81937c478bd9Sstevel@tonic-gate   char c = first_char;
81947c478bd9Sstevel@tonic-gate /*
81957c478bd9Sstevel@tonic-gate  * If editing is disabled, just add newly entered characters to the
81967c478bd9Sstevel@tonic-gate  * input line buffer, and watch for the end of the line.
81977c478bd9Sstevel@tonic-gate  */
81987c478bd9Sstevel@tonic-gate   if(gl->editor == GL_NO_EDITOR) {
81997c478bd9Sstevel@tonic-gate     gl_discard_chars(gl, 1);
82007c478bd9Sstevel@tonic-gate     if(gl->ntotal >= gl->linelen)
82017c478bd9Sstevel@tonic-gate       return 0;
82027c478bd9Sstevel@tonic-gate     if(c == '\n' || c == '\r')
82037c478bd9Sstevel@tonic-gate       return gl_newline(gl, 1, NULL);
82047c478bd9Sstevel@tonic-gate     gl_buffer_char(gl, c, gl->ntotal);
82057c478bd9Sstevel@tonic-gate     return 0;
82067c478bd9Sstevel@tonic-gate   };
82077c478bd9Sstevel@tonic-gate /*
82087c478bd9Sstevel@tonic-gate  * If the user is in the process of specifying a repeat count and the
82097c478bd9Sstevel@tonic-gate  * new character is a digit, increment the repeat count accordingly.
82107c478bd9Sstevel@tonic-gate  */
82117c478bd9Sstevel@tonic-gate   if(gl->number >= 0 && isdigit((int)(unsigned char) c)) {
82127c478bd9Sstevel@tonic-gate     gl_discard_chars(gl, 1);
82137c478bd9Sstevel@tonic-gate     return gl_digit_argument(gl, c, NULL);
82147c478bd9Sstevel@tonic-gate /*
82157c478bd9Sstevel@tonic-gate  * In vi command mode, all key-sequences entered need to be
82167c478bd9Sstevel@tonic-gate  * either implicitly or explicitly prefixed with an escape character.
82177c478bd9Sstevel@tonic-gate  */
82187c478bd9Sstevel@tonic-gate   } else if(gl->vi.command && c != GL_ESC_CHAR) {
82197c478bd9Sstevel@tonic-gate     keyseq[nkey++] = GL_ESC_CHAR;
82207c478bd9Sstevel@tonic-gate /*
82217c478bd9Sstevel@tonic-gate  * If the first character of the sequence is a printable character,
82227c478bd9Sstevel@tonic-gate  * then to avoid confusion with the special "up", "down", "left"
82237c478bd9Sstevel@tonic-gate  * or "right" cursor key bindings, we need to prefix the
82247c478bd9Sstevel@tonic-gate  * printable character with a backslash escape before looking it up.
82257c478bd9Sstevel@tonic-gate  */
82267c478bd9Sstevel@tonic-gate   } else if(!IS_META_CHAR(c) && !IS_CTRL_CHAR(c)) {
82277c478bd9Sstevel@tonic-gate     keyseq[nkey++] = '\\';
82287c478bd9Sstevel@tonic-gate   };
82297c478bd9Sstevel@tonic-gate /*
82307c478bd9Sstevel@tonic-gate  * Compose a potentially multiple key-sequence in gl->keyseq.
82317c478bd9Sstevel@tonic-gate  */
82327c478bd9Sstevel@tonic-gate   while(nkey < GL_KEY_MAX) {
82337c478bd9Sstevel@tonic-gate     KtAction *action; /* An action function */
82347c478bd9Sstevel@tonic-gate     KeySym *keysym;   /* The symbol-table entry of a key-sequence */
82357c478bd9Sstevel@tonic-gate     int nsym;         /* The number of ambiguously matching key-sequences */
82367c478bd9Sstevel@tonic-gate /*
82377c478bd9Sstevel@tonic-gate  * If the character is an unprintable meta character, split it
82387c478bd9Sstevel@tonic-gate  * into two characters, an escape character and the character
82397c478bd9Sstevel@tonic-gate  * that was modified by the meta key.
82407c478bd9Sstevel@tonic-gate  */
82417c478bd9Sstevel@tonic-gate     if(IS_META_CHAR(c)) {
82427c478bd9Sstevel@tonic-gate       keyseq[nkey++] = GL_ESC_CHAR;
82437c478bd9Sstevel@tonic-gate       c = META_TO_CHAR(c);
82447c478bd9Sstevel@tonic-gate       continue;
82457c478bd9Sstevel@tonic-gate     };
82467c478bd9Sstevel@tonic-gate /*
82477c478bd9Sstevel@tonic-gate  * Append the latest character to the key sequence.
82487c478bd9Sstevel@tonic-gate  */
82497c478bd9Sstevel@tonic-gate     keyseq[nkey++] = c;
82507c478bd9Sstevel@tonic-gate /*
82517c478bd9Sstevel@tonic-gate  * When doing vi-style editing, an escape at the beginning of any binding
82527c478bd9Sstevel@tonic-gate  * switches to command mode.
82537c478bd9Sstevel@tonic-gate  */
82547c478bd9Sstevel@tonic-gate     if(keyseq[0] == GL_ESC_CHAR && !gl->vi.command)
82557c478bd9Sstevel@tonic-gate       gl_vi_command_mode(gl);
82567c478bd9Sstevel@tonic-gate /*
82577c478bd9Sstevel@tonic-gate  * Lookup the key sequence.
82587c478bd9Sstevel@tonic-gate  */
82597c478bd9Sstevel@tonic-gate     switch(_kt_lookup_keybinding(gl->bindings, keyseq, nkey, &keysym, &nsym)) {
82607c478bd9Sstevel@tonic-gate     case KT_EXACT_MATCH:
82617c478bd9Sstevel@tonic-gate /*
82627c478bd9Sstevel@tonic-gate  * Get the matching action function.
82637c478bd9Sstevel@tonic-gate  */
82647c478bd9Sstevel@tonic-gate       action = keysym->actions + keysym->binder;
82657c478bd9Sstevel@tonic-gate /*
82667c478bd9Sstevel@tonic-gate  * Get the repeat count, passing the last keystroke if executing the
82677c478bd9Sstevel@tonic-gate  * digit-argument action.
82687c478bd9Sstevel@tonic-gate  */
82697c478bd9Sstevel@tonic-gate       if(action->fn == gl_digit_argument) {
82707c478bd9Sstevel@tonic-gate 	count = c;
82717c478bd9Sstevel@tonic-gate       } else {
82727c478bd9Sstevel@tonic-gate 	count = gl->number >= 0 ? gl->number : 1;
82737c478bd9Sstevel@tonic-gate       };
82747c478bd9Sstevel@tonic-gate /*
82757c478bd9Sstevel@tonic-gate  * Record the function that is being invoked.
82767c478bd9Sstevel@tonic-gate  */
82777c478bd9Sstevel@tonic-gate       gl->current_action = *action;
82787c478bd9Sstevel@tonic-gate       gl->current_count = count;
82797c478bd9Sstevel@tonic-gate /*
82807c478bd9Sstevel@tonic-gate  * Mark the current line as not yet preserved for use by the vi undo command.
82817c478bd9Sstevel@tonic-gate  */
82827c478bd9Sstevel@tonic-gate       gl->vi.undo.saved = 0;
82837c478bd9Sstevel@tonic-gate       gl->vi.repeat.saved = 0;
82847c478bd9Sstevel@tonic-gate /*
82857c478bd9Sstevel@tonic-gate  * Execute the action function. Note the action function can tell
82867c478bd9Sstevel@tonic-gate  * whether the provided repeat count was defaulted or specified
82877c478bd9Sstevel@tonic-gate  * explicitly by looking at whether gl->number is -1 or not. If
82887c478bd9Sstevel@tonic-gate  * it is negative, then no repeat count was specified by the user.
82897c478bd9Sstevel@tonic-gate  */
82907c478bd9Sstevel@tonic-gate       ret = action->fn(gl, count, action->data);
82917c478bd9Sstevel@tonic-gate /*
82927c478bd9Sstevel@tonic-gate  * In server mode, the action will return immediately if it tries to
82937c478bd9Sstevel@tonic-gate  * read input from the terminal, and no input is currently available.
82947c478bd9Sstevel@tonic-gate  * If this happens, abort. Note that gl_get_input_line() will rewind
82957c478bd9Sstevel@tonic-gate  * the read-ahead buffer to allow the next call to redo the function
82967c478bd9Sstevel@tonic-gate  * from scratch.
82977c478bd9Sstevel@tonic-gate  */
82987c478bd9Sstevel@tonic-gate       if(gl->rtn_status == GLR_BLOCKED && gl->pending_io==GLP_READ)
82997c478bd9Sstevel@tonic-gate 	return 1;
83007c478bd9Sstevel@tonic-gate /*
83017c478bd9Sstevel@tonic-gate  * Discard the now processed characters from the key sequence buffer.
83027c478bd9Sstevel@tonic-gate  */
83037c478bd9Sstevel@tonic-gate       gl_discard_chars(gl, gl->nread);
83047c478bd9Sstevel@tonic-gate /*
83057c478bd9Sstevel@tonic-gate  * If the latest action function wasn't a history action, cancel any
83067c478bd9Sstevel@tonic-gate  * current history search.
83077c478bd9Sstevel@tonic-gate  */
83087c478bd9Sstevel@tonic-gate       if(gl->last_search != gl->keyseq_count)
83097c478bd9Sstevel@tonic-gate 	_glh_cancel_search(gl->glh);
83107c478bd9Sstevel@tonic-gate /*
83117c478bd9Sstevel@tonic-gate  * Reset the repeat count after running action functions.
83127c478bd9Sstevel@tonic-gate  */
83137c478bd9Sstevel@tonic-gate       if(action->fn != gl_digit_argument)
83147c478bd9Sstevel@tonic-gate 	gl->number = -1;
83157c478bd9Sstevel@tonic-gate       return ret ? 1 : 0;
83167c478bd9Sstevel@tonic-gate       break;
83177c478bd9Sstevel@tonic-gate     case KT_AMBIG_MATCH:    /* Ambiguous match - so read the next character */
83187c478bd9Sstevel@tonic-gate       if(gl_read_terminal(gl, 1, &c))
83197c478bd9Sstevel@tonic-gate 	return 1;
83207c478bd9Sstevel@tonic-gate       break;
83217c478bd9Sstevel@tonic-gate     case KT_NO_MATCH:
83227c478bd9Sstevel@tonic-gate /*
83237c478bd9Sstevel@tonic-gate  * If the first character looked like it might be a prefix of a key-sequence
83247c478bd9Sstevel@tonic-gate  * but it turned out not to be, ring the bell to tell the user that it
83257c478bd9Sstevel@tonic-gate  * wasn't recognised.
83267c478bd9Sstevel@tonic-gate  */
83277c478bd9Sstevel@tonic-gate       if(keyseq[0] != '\\' && keyseq[0] != '\t') {
83287c478bd9Sstevel@tonic-gate 	gl_ring_bell(gl, 1, NULL);
83297c478bd9Sstevel@tonic-gate       } else {
83307c478bd9Sstevel@tonic-gate /*
83317c478bd9Sstevel@tonic-gate  * The user typed a single printable character that doesn't match
83327c478bd9Sstevel@tonic-gate  * the start of any keysequence, so add it to the line in accordance
83337c478bd9Sstevel@tonic-gate  * with the current repeat count.
83347c478bd9Sstevel@tonic-gate  */
83357c478bd9Sstevel@tonic-gate 	count = gl->number >= 0 ? gl->number : 1;
83367c478bd9Sstevel@tonic-gate 	for(i=0; i<count; i++)
83377c478bd9Sstevel@tonic-gate 	  gl_add_char_to_line(gl, first_char);
83387c478bd9Sstevel@tonic-gate 	gl->number = -1;
83397c478bd9Sstevel@tonic-gate       };
83407c478bd9Sstevel@tonic-gate       gl_discard_chars(gl, 1);
83417c478bd9Sstevel@tonic-gate       _glh_cancel_search(gl->glh);
83427c478bd9Sstevel@tonic-gate       return 0;
83437c478bd9Sstevel@tonic-gate       break;
83447c478bd9Sstevel@tonic-gate     case KT_BAD_MATCH:
83457c478bd9Sstevel@tonic-gate       gl_ring_bell(gl, 1, NULL);
83467c478bd9Sstevel@tonic-gate       gl_discard_chars(gl, gl->nread);
83477c478bd9Sstevel@tonic-gate       _glh_cancel_search(gl->glh);
83487c478bd9Sstevel@tonic-gate       return 1;
83497c478bd9Sstevel@tonic-gate       break;
83507c478bd9Sstevel@tonic-gate     };
83517c478bd9Sstevel@tonic-gate   };
83527c478bd9Sstevel@tonic-gate /*
83537c478bd9Sstevel@tonic-gate  * If the key sequence was too long to match, ring the bell, then
83547c478bd9Sstevel@tonic-gate  * discard the first character, so that the next attempt to match a
83557c478bd9Sstevel@tonic-gate  * key-sequence continues with the next key press. In practice this
83567c478bd9Sstevel@tonic-gate  * shouldn't happen, since one isn't allowed to bind action functions
83577c478bd9Sstevel@tonic-gate  * to keysequences that are longer than GL_KEY_MAX.
83587c478bd9Sstevel@tonic-gate  */
83597c478bd9Sstevel@tonic-gate   gl_ring_bell(gl, 1, NULL);
83607c478bd9Sstevel@tonic-gate   gl_discard_chars(gl, 1);
83617c478bd9Sstevel@tonic-gate   return 0;
83627c478bd9Sstevel@tonic-gate }
83637c478bd9Sstevel@tonic-gate 
83647c478bd9Sstevel@tonic-gate /*.......................................................................
83657c478bd9Sstevel@tonic-gate  * Configure the application and/or user-specific behavior of
83667c478bd9Sstevel@tonic-gate  * gl_get_line().
83677c478bd9Sstevel@tonic-gate  *
83687c478bd9Sstevel@tonic-gate  * Note that calling this function between calling new_GetLine() and
83697c478bd9Sstevel@tonic-gate  * the first call to gl_get_line(), disables the otherwise automatic
83707c478bd9Sstevel@tonic-gate  * reading of ~/.teclarc on the first call to gl_get_line().
83717c478bd9Sstevel@tonic-gate  *
83727c478bd9Sstevel@tonic-gate  * Input:
83737c478bd9Sstevel@tonic-gate  *  gl             GetLine *  The resource object of this library.
83747c478bd9Sstevel@tonic-gate  *  app_string  const char *  Either NULL, or a string containing one
83757c478bd9Sstevel@tonic-gate  *                            or more .teclarc command lines, separated
83767c478bd9Sstevel@tonic-gate  *                            by newline characters. This can be used to
83777c478bd9Sstevel@tonic-gate  *                            establish an application-specific
83787c478bd9Sstevel@tonic-gate  *                            configuration, without the need for an external
83797c478bd9Sstevel@tonic-gate  *                            file. This is particularly useful in embedded
83807c478bd9Sstevel@tonic-gate  *                            environments where there is no filesystem.
83817c478bd9Sstevel@tonic-gate  *  app_file    const char *  Either NULL, or the pathname of an
83827c478bd9Sstevel@tonic-gate  *                            application-specific .teclarc file. The
83837c478bd9Sstevel@tonic-gate  *                            contents of this file, if provided, are
83847c478bd9Sstevel@tonic-gate  *                            read after the contents of app_string[].
83857c478bd9Sstevel@tonic-gate  *  user_file   const char *  Either NULL, or the pathname of a
83867c478bd9Sstevel@tonic-gate  *                            user-specific .teclarc file. Except in
83877c478bd9Sstevel@tonic-gate  *                            embedded applications, this should
83887c478bd9Sstevel@tonic-gate  *                            usually be "~/.teclarc".
83897c478bd9Sstevel@tonic-gate  * Output:
83907c478bd9Sstevel@tonic-gate  *  return             int    0 - OK.
83917c478bd9Sstevel@tonic-gate  *                            1 - Bad argument(s).
83927c478bd9Sstevel@tonic-gate  */
gl_configure_getline(GetLine * gl,const char * app_string,const char * app_file,const char * user_file)83937c478bd9Sstevel@tonic-gate int gl_configure_getline(GetLine *gl, const char *app_string,
83947c478bd9Sstevel@tonic-gate 			 const char *app_file, const char *user_file)
83957c478bd9Sstevel@tonic-gate {
83967c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
83977c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_configure_getline() */
83987c478bd9Sstevel@tonic-gate /*
83997c478bd9Sstevel@tonic-gate  * Check the arguments.
84007c478bd9Sstevel@tonic-gate  */
84017c478bd9Sstevel@tonic-gate   if(!gl) {
84027c478bd9Sstevel@tonic-gate     errno = EINVAL;
84037c478bd9Sstevel@tonic-gate     return 1;
84047c478bd9Sstevel@tonic-gate   };
84057c478bd9Sstevel@tonic-gate /*
84067c478bd9Sstevel@tonic-gate  * Block all signals.
84077c478bd9Sstevel@tonic-gate  */
84087c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
84097c478bd9Sstevel@tonic-gate     return 1;
84107c478bd9Sstevel@tonic-gate /*
84117c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
84127c478bd9Sstevel@tonic-gate  */
84137c478bd9Sstevel@tonic-gate   status = _gl_configure_getline(gl, app_string, app_file, user_file);
84147c478bd9Sstevel@tonic-gate /*
84157c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
84167c478bd9Sstevel@tonic-gate  */
84177c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
84187c478bd9Sstevel@tonic-gate   return status;
84197c478bd9Sstevel@tonic-gate }
84207c478bd9Sstevel@tonic-gate 
84217c478bd9Sstevel@tonic-gate /*.......................................................................
84227c478bd9Sstevel@tonic-gate  * This is the private body of the gl_configure_getline() function. It
84237c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
84247c478bd9Sstevel@tonic-gate  * delivery of signals.
84257c478bd9Sstevel@tonic-gate  */
_gl_configure_getline(GetLine * gl,const char * app_string,const char * app_file,const char * user_file)84267c478bd9Sstevel@tonic-gate static int _gl_configure_getline(GetLine *gl, const char *app_string,
84277c478bd9Sstevel@tonic-gate 				 const char *app_file, const char *user_file)
84287c478bd9Sstevel@tonic-gate {
84297c478bd9Sstevel@tonic-gate /*
84307c478bd9Sstevel@tonic-gate  * Mark getline as having been explicitly configured.
84317c478bd9Sstevel@tonic-gate  */
84327c478bd9Sstevel@tonic-gate   gl->configured = 1;
84337c478bd9Sstevel@tonic-gate /*
84347c478bd9Sstevel@tonic-gate  * Start by parsing the configuration string, if provided.
84357c478bd9Sstevel@tonic-gate  */
84367c478bd9Sstevel@tonic-gate   if(app_string)
84377c478bd9Sstevel@tonic-gate     (void) _gl_read_config_string(gl, app_string, KTB_NORM);
84387c478bd9Sstevel@tonic-gate /*
84397c478bd9Sstevel@tonic-gate  * Now parse the application-specific configuration file, if provided.
84407c478bd9Sstevel@tonic-gate  */
84417c478bd9Sstevel@tonic-gate   if(app_file)
84427c478bd9Sstevel@tonic-gate     (void) _gl_read_config_file(gl, app_file, KTB_NORM);
84437c478bd9Sstevel@tonic-gate /*
84447c478bd9Sstevel@tonic-gate  * Finally, parse the user-specific configuration file, if provided.
84457c478bd9Sstevel@tonic-gate  */
84467c478bd9Sstevel@tonic-gate   if(user_file)
84477c478bd9Sstevel@tonic-gate     (void) _gl_read_config_file(gl, user_file, KTB_USER);
84487c478bd9Sstevel@tonic-gate /*
84497c478bd9Sstevel@tonic-gate  * Record the names of the configuration files to allow them to
84507c478bd9Sstevel@tonic-gate  * be re-read if requested at a later time.
84517c478bd9Sstevel@tonic-gate  */
84527c478bd9Sstevel@tonic-gate   if(gl_record_string(&gl->app_file, app_file) ||
84537c478bd9Sstevel@tonic-gate      gl_record_string(&gl->user_file, user_file)) {
84547c478bd9Sstevel@tonic-gate     errno = ENOMEM;
84557c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err,
84567c478bd9Sstevel@tonic-gate 	   "Insufficient memory to record tecla configuration file names",
84577c478bd9Sstevel@tonic-gate 	   END_ERR_MSG);
84587c478bd9Sstevel@tonic-gate     return 1;
84597c478bd9Sstevel@tonic-gate   };
84607c478bd9Sstevel@tonic-gate   return 0;
84617c478bd9Sstevel@tonic-gate }
84627c478bd9Sstevel@tonic-gate 
84637c478bd9Sstevel@tonic-gate /*.......................................................................
84647c478bd9Sstevel@tonic-gate  * Replace a malloc'd string (or NULL), with another malloc'd copy of
84657c478bd9Sstevel@tonic-gate  * a string (or NULL).
84667c478bd9Sstevel@tonic-gate  *
84677c478bd9Sstevel@tonic-gate  * Input:
84687c478bd9Sstevel@tonic-gate  *  sptr          char **  On input if *sptr!=NULL, *sptr will be
84697c478bd9Sstevel@tonic-gate  *                         free'd and *sptr will be set to NULL. Then,
84707c478bd9Sstevel@tonic-gate  *                         on output, if string!=NULL a malloc'd copy
84717c478bd9Sstevel@tonic-gate  *                         of this string will be assigned to *sptr.
84727c478bd9Sstevel@tonic-gate  *  string  const char *   The string to be copied, or NULL to simply
84737c478bd9Sstevel@tonic-gate  *                         discard any existing string.
84747c478bd9Sstevel@tonic-gate  * Output:
84757c478bd9Sstevel@tonic-gate  *  return         int     0 - OK.
84767c478bd9Sstevel@tonic-gate  *                         1 - Malloc failure (no error message is generated).
84777c478bd9Sstevel@tonic-gate  */
gl_record_string(char ** sptr,const char * string)84787c478bd9Sstevel@tonic-gate static int gl_record_string(char **sptr, const char *string)
84797c478bd9Sstevel@tonic-gate {
84807c478bd9Sstevel@tonic-gate /*
84817c478bd9Sstevel@tonic-gate  * If the original string is the same string, don't do anything.
84827c478bd9Sstevel@tonic-gate  */
84837c478bd9Sstevel@tonic-gate   if(*sptr == string || (*sptr && string && strcmp(*sptr, string)==0))
84847c478bd9Sstevel@tonic-gate     return 0;
84857c478bd9Sstevel@tonic-gate /*
84867c478bd9Sstevel@tonic-gate  * Discard any existing cached string.
84877c478bd9Sstevel@tonic-gate  */
84887c478bd9Sstevel@tonic-gate   if(*sptr) {
84897c478bd9Sstevel@tonic-gate     free(*sptr);
84907c478bd9Sstevel@tonic-gate     *sptr = NULL;
84917c478bd9Sstevel@tonic-gate   };
84927c478bd9Sstevel@tonic-gate /*
84937c478bd9Sstevel@tonic-gate  * Allocate memory for a copy of the specified string.
84947c478bd9Sstevel@tonic-gate  */
84957c478bd9Sstevel@tonic-gate   if(string) {
84967c478bd9Sstevel@tonic-gate     size_t ssz = strlen(string) + 1;
84977c478bd9Sstevel@tonic-gate     *sptr = (char *) malloc(ssz);
84987c478bd9Sstevel@tonic-gate     if(!*sptr)
84997c478bd9Sstevel@tonic-gate       return 1;
85007c478bd9Sstevel@tonic-gate /*
85017c478bd9Sstevel@tonic-gate  * Copy the string.
85027c478bd9Sstevel@tonic-gate  */
85037c478bd9Sstevel@tonic-gate     strlcpy(*sptr, string, ssz);
85047c478bd9Sstevel@tonic-gate   };
85057c478bd9Sstevel@tonic-gate   return 0;
85067c478bd9Sstevel@tonic-gate }
85077c478bd9Sstevel@tonic-gate 
85087c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM
85097c478bd9Sstevel@tonic-gate /*.......................................................................
85107c478bd9Sstevel@tonic-gate  * Re-read any application-specific and user-specific files previously
85117c478bd9Sstevel@tonic-gate  * specified via the gl_configure_getline() function.
85127c478bd9Sstevel@tonic-gate  */
KT_KEY_FN(gl_read_init_files)85137c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_read_init_files)
85147c478bd9Sstevel@tonic-gate {
85157c478bd9Sstevel@tonic-gate   return _gl_configure_getline(gl, NULL, gl->app_file, gl->user_file);
85167c478bd9Sstevel@tonic-gate }
85177c478bd9Sstevel@tonic-gate #endif
85187c478bd9Sstevel@tonic-gate 
85197c478bd9Sstevel@tonic-gate /*.......................................................................
85207c478bd9Sstevel@tonic-gate  * Save the contents of the history buffer to a given new file.
85217c478bd9Sstevel@tonic-gate  *
85227c478bd9Sstevel@tonic-gate  * Input:
85237c478bd9Sstevel@tonic-gate  *  gl             GetLine *  The resource object of this library.
85247c478bd9Sstevel@tonic-gate  *  filename    const char *  The name of the new file to write to.
85257c478bd9Sstevel@tonic-gate  *  comment     const char *  Extra information such as timestamps will
85267c478bd9Sstevel@tonic-gate  *                            be recorded on a line started with this
85277c478bd9Sstevel@tonic-gate  *                            string, the idea being that the file can
85287c478bd9Sstevel@tonic-gate  *                            double as a command file. Specify "" if
85297c478bd9Sstevel@tonic-gate  *                            you don't care.
85307c478bd9Sstevel@tonic-gate  *  max_lines          int    The maximum number of lines to save, or -1
85317c478bd9Sstevel@tonic-gate  *                            to save all of the lines in the history
85327c478bd9Sstevel@tonic-gate  *                            list.
85337c478bd9Sstevel@tonic-gate  * Output:
85347c478bd9Sstevel@tonic-gate  *  return             int     0 - OK.
85357c478bd9Sstevel@tonic-gate  *                             1 - Error.
85367c478bd9Sstevel@tonic-gate  */
gl_save_history(GetLine * gl,const char * filename,const char * comment,int max_lines)85377c478bd9Sstevel@tonic-gate int gl_save_history(GetLine *gl, const char *filename, const char *comment,
85387c478bd9Sstevel@tonic-gate 		    int max_lines)
85397c478bd9Sstevel@tonic-gate {
85407c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
85417c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_save_history() */
85427c478bd9Sstevel@tonic-gate /*
85437c478bd9Sstevel@tonic-gate  * Check the arguments.
85447c478bd9Sstevel@tonic-gate  */
85457c478bd9Sstevel@tonic-gate   if(!gl || !filename || !comment) {
85467c478bd9Sstevel@tonic-gate     if(gl)
85477c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
85487c478bd9Sstevel@tonic-gate     errno = EINVAL;
85497c478bd9Sstevel@tonic-gate     return 1;
85507c478bd9Sstevel@tonic-gate   };
85517c478bd9Sstevel@tonic-gate /*
85527c478bd9Sstevel@tonic-gate  * Block all signals.
85537c478bd9Sstevel@tonic-gate  */
85547c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
85557c478bd9Sstevel@tonic-gate     return 1;
85567c478bd9Sstevel@tonic-gate /*
85577c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
85587c478bd9Sstevel@tonic-gate  */
85597c478bd9Sstevel@tonic-gate   status = _gl_save_history(gl, filename, comment, max_lines);
85607c478bd9Sstevel@tonic-gate /*
85617c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
85627c478bd9Sstevel@tonic-gate  */
85637c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
85647c478bd9Sstevel@tonic-gate   return status;
85657c478bd9Sstevel@tonic-gate }
85667c478bd9Sstevel@tonic-gate 
85677c478bd9Sstevel@tonic-gate /*.......................................................................
85687c478bd9Sstevel@tonic-gate  * This is the private body of the gl_save_history() function. It
85697c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
85707c478bd9Sstevel@tonic-gate  * delivery of signals.
85717c478bd9Sstevel@tonic-gate  */
_gl_save_history(GetLine * gl,const char * filename,const char * comment,int max_lines)85727c478bd9Sstevel@tonic-gate static int _gl_save_history(GetLine *gl, const char *filename,
85737c478bd9Sstevel@tonic-gate 			    const char *comment, int max_lines)
85747c478bd9Sstevel@tonic-gate {
85757c478bd9Sstevel@tonic-gate /*
85767c478bd9Sstevel@tonic-gate  * If filesystem access is to be excluded, then history files can't
85777c478bd9Sstevel@tonic-gate  * be written.
85787c478bd9Sstevel@tonic-gate  */
85797c478bd9Sstevel@tonic-gate #ifdef WITHOUT_FILE_SYSTEM
85807c478bd9Sstevel@tonic-gate   _err_record_msg(gl->err, "Can't save history without filesystem access",
85817c478bd9Sstevel@tonic-gate 		  END_ERR_MSG);
85827c478bd9Sstevel@tonic-gate   errno = EINVAL;
85837c478bd9Sstevel@tonic-gate   return 1;
85847c478bd9Sstevel@tonic-gate #else
85857c478bd9Sstevel@tonic-gate   FileExpansion *expansion; /* The expansion of the filename */
85867c478bd9Sstevel@tonic-gate /*
85877c478bd9Sstevel@tonic-gate  * Expand the filename.
85887c478bd9Sstevel@tonic-gate  */
85897c478bd9Sstevel@tonic-gate   expansion = ef_expand_file(gl->ef, filename, -1);
85907c478bd9Sstevel@tonic-gate   if(!expansion) {
85917c478bd9Sstevel@tonic-gate     gl_print_info(gl, "Unable to expand ", filename, " (",
85927c478bd9Sstevel@tonic-gate 		  ef_last_error(gl->ef), ").", GL_END_INFO);
85937c478bd9Sstevel@tonic-gate     return 1;
85947c478bd9Sstevel@tonic-gate   };
85957c478bd9Sstevel@tonic-gate /*
85967c478bd9Sstevel@tonic-gate  * Attempt to save to the specified file.
85977c478bd9Sstevel@tonic-gate  */
85987c478bd9Sstevel@tonic-gate   if(_glh_save_history(gl->glh, expansion->files[0], comment, max_lines)) {
85997c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
86007c478bd9Sstevel@tonic-gate     return 1;
86017c478bd9Sstevel@tonic-gate   };
86027c478bd9Sstevel@tonic-gate   return 0;
86037c478bd9Sstevel@tonic-gate #endif
86047c478bd9Sstevel@tonic-gate }
86057c478bd9Sstevel@tonic-gate 
86067c478bd9Sstevel@tonic-gate /*.......................................................................
86077c478bd9Sstevel@tonic-gate  * Restore the contents of the history buffer from a given new file.
86087c478bd9Sstevel@tonic-gate  *
86097c478bd9Sstevel@tonic-gate  * Input:
86107c478bd9Sstevel@tonic-gate  *  gl             GetLine *  The resource object of this library.
86117c478bd9Sstevel@tonic-gate  *  filename    const char *  The name of the new file to write to.
86127c478bd9Sstevel@tonic-gate  *  comment     const char *  This must be the same string that was
86137c478bd9Sstevel@tonic-gate  *                            passed to gl_save_history() when the file
86147c478bd9Sstevel@tonic-gate  *                            was written.
86157c478bd9Sstevel@tonic-gate  * Output:
86167c478bd9Sstevel@tonic-gate  *  return             int     0 - OK.
86177c478bd9Sstevel@tonic-gate  *                             1 - Error.
86187c478bd9Sstevel@tonic-gate  */
gl_load_history(GetLine * gl,const char * filename,const char * comment)86197c478bd9Sstevel@tonic-gate int gl_load_history(GetLine *gl, const char *filename, const char *comment)
86207c478bd9Sstevel@tonic-gate {
86217c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
86227c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_load_history() */
86237c478bd9Sstevel@tonic-gate /*
86247c478bd9Sstevel@tonic-gate  * Check the arguments.
86257c478bd9Sstevel@tonic-gate  */
86267c478bd9Sstevel@tonic-gate   if(!gl || !filename || !comment) {
86277c478bd9Sstevel@tonic-gate     if(gl)
86287c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
86297c478bd9Sstevel@tonic-gate     errno = EINVAL;
86307c478bd9Sstevel@tonic-gate     return 1;
86317c478bd9Sstevel@tonic-gate   };
86327c478bd9Sstevel@tonic-gate /*
86337c478bd9Sstevel@tonic-gate  * Block all signals.
86347c478bd9Sstevel@tonic-gate  */
86357c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
86367c478bd9Sstevel@tonic-gate     return 1;
86377c478bd9Sstevel@tonic-gate /*
86387c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
86397c478bd9Sstevel@tonic-gate  */
86407c478bd9Sstevel@tonic-gate   status = _gl_load_history(gl, filename, comment);
86417c478bd9Sstevel@tonic-gate /*
86427c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
86437c478bd9Sstevel@tonic-gate  */
86447c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
86457c478bd9Sstevel@tonic-gate   return status;
86467c478bd9Sstevel@tonic-gate }
86477c478bd9Sstevel@tonic-gate 
86487c478bd9Sstevel@tonic-gate /*.......................................................................
86497c478bd9Sstevel@tonic-gate  * This is the private body of the gl_load_history() function. It
86507c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
86517c478bd9Sstevel@tonic-gate  * delivery of signals.
86527c478bd9Sstevel@tonic-gate  */
_gl_load_history(GetLine * gl,const char * filename,const char * comment)86537c478bd9Sstevel@tonic-gate static int _gl_load_history(GetLine *gl, const char *filename,
86547c478bd9Sstevel@tonic-gate 			    const char *comment)
86557c478bd9Sstevel@tonic-gate {
86567c478bd9Sstevel@tonic-gate /*
86577c478bd9Sstevel@tonic-gate  * If filesystem access is to be excluded, then history files can't
86587c478bd9Sstevel@tonic-gate  * be read.
86597c478bd9Sstevel@tonic-gate  */
86607c478bd9Sstevel@tonic-gate #ifdef WITHOUT_FILE_SYSTEM
86617c478bd9Sstevel@tonic-gate   _err_record_msg(gl->err, "Can't load history without filesystem access",
86627c478bd9Sstevel@tonic-gate 		  END_ERR_MSG);
86637c478bd9Sstevel@tonic-gate   errno = EINVAL;
86647c478bd9Sstevel@tonic-gate   return 1;
86657c478bd9Sstevel@tonic-gate #else
86667c478bd9Sstevel@tonic-gate   FileExpansion *expansion; /* The expansion of the filename */
86677c478bd9Sstevel@tonic-gate /*
86687c478bd9Sstevel@tonic-gate  * Expand the filename.
86697c478bd9Sstevel@tonic-gate  */
86707c478bd9Sstevel@tonic-gate   expansion = ef_expand_file(gl->ef, filename, -1);
86717c478bd9Sstevel@tonic-gate   if(!expansion) {
86727c478bd9Sstevel@tonic-gate     gl_print_info(gl, "Unable to expand ", filename, " (",
86737c478bd9Sstevel@tonic-gate 		  ef_last_error(gl->ef), ").", GL_END_INFO);
86747c478bd9Sstevel@tonic-gate     return 1;
86757c478bd9Sstevel@tonic-gate   };
86767c478bd9Sstevel@tonic-gate /*
86777c478bd9Sstevel@tonic-gate  * Attempt to load from the specified file.
86787c478bd9Sstevel@tonic-gate  */
86797c478bd9Sstevel@tonic-gate   if(_glh_load_history(gl->glh, expansion->files[0], comment,
86807c478bd9Sstevel@tonic-gate 		       gl->cutbuf, gl->linelen+1)) {
86817c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
86827c478bd9Sstevel@tonic-gate     gl->cutbuf[0] = '\0';
86837c478bd9Sstevel@tonic-gate     return 1;
86847c478bd9Sstevel@tonic-gate   };
86857c478bd9Sstevel@tonic-gate   gl->cutbuf[0] = '\0';
86867c478bd9Sstevel@tonic-gate   return 0;
86877c478bd9Sstevel@tonic-gate #endif
86887c478bd9Sstevel@tonic-gate }
86897c478bd9Sstevel@tonic-gate 
86907c478bd9Sstevel@tonic-gate /*.......................................................................
86917c478bd9Sstevel@tonic-gate  * Where possible, register a function and associated data to be called
86927c478bd9Sstevel@tonic-gate  * whenever a specified event is seen on a file descriptor.
86937c478bd9Sstevel@tonic-gate  *
86947c478bd9Sstevel@tonic-gate  * Input:
86957c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of the command-line input
86967c478bd9Sstevel@tonic-gate  *                           module.
86977c478bd9Sstevel@tonic-gate  *  fd                int    The file descriptor to watch.
86987c478bd9Sstevel@tonic-gate  *  event       GlFdEvent    The type of activity to watch for.
86997c478bd9Sstevel@tonic-gate  *  callback  GlFdEventFn *  The function to call when the specified
87007c478bd9Sstevel@tonic-gate  *                           event occurs. Setting this to 0 removes
87017c478bd9Sstevel@tonic-gate  *                           any existing callback.
87027c478bd9Sstevel@tonic-gate  *  data             void *  A pointer to arbitrary data to pass to the
87037c478bd9Sstevel@tonic-gate  *                           callback function.
87047c478bd9Sstevel@tonic-gate  * Output:
87057c478bd9Sstevel@tonic-gate  *  return            int    0 - OK.
87067c478bd9Sstevel@tonic-gate  *                           1 - Either gl==NULL, or this facility isn't
87077c478bd9Sstevel@tonic-gate  *                               available on the the host system
87087c478bd9Sstevel@tonic-gate  *                               (ie. select() isn't available). No
87097c478bd9Sstevel@tonic-gate  *                               error message is generated in the latter
87107c478bd9Sstevel@tonic-gate  *                               case.
87117c478bd9Sstevel@tonic-gate  */
gl_watch_fd(GetLine * gl,int fd,GlFdEvent event,GlFdEventFn * callback,void * data)87127c478bd9Sstevel@tonic-gate int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
87137c478bd9Sstevel@tonic-gate 		GlFdEventFn *callback, void *data)
87147c478bd9Sstevel@tonic-gate {
87157c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
87167c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_watch_fd() */
87177c478bd9Sstevel@tonic-gate /*
87187c478bd9Sstevel@tonic-gate  * Check the arguments.
87197c478bd9Sstevel@tonic-gate  */
87207c478bd9Sstevel@tonic-gate   if(!gl) {
87217c478bd9Sstevel@tonic-gate     errno = EINVAL;
87227c478bd9Sstevel@tonic-gate     return 1;
87237c478bd9Sstevel@tonic-gate   };
87247c478bd9Sstevel@tonic-gate   if(fd < 0) {
87257c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "Error: fd < 0", END_ERR_MSG);
87267c478bd9Sstevel@tonic-gate     errno = EINVAL;
87277c478bd9Sstevel@tonic-gate     return 1;
87287c478bd9Sstevel@tonic-gate   };
87297c478bd9Sstevel@tonic-gate /*
87307c478bd9Sstevel@tonic-gate  * Block all signals.
87317c478bd9Sstevel@tonic-gate  */
87327c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
87337c478bd9Sstevel@tonic-gate     return 1;
87347c478bd9Sstevel@tonic-gate /*
87357c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
87367c478bd9Sstevel@tonic-gate  */
87377c478bd9Sstevel@tonic-gate   status = _gl_watch_fd(gl, fd, event, callback, data);
87387c478bd9Sstevel@tonic-gate /*
87397c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
87407c478bd9Sstevel@tonic-gate  */
87417c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
87427c478bd9Sstevel@tonic-gate   return status;
87437c478bd9Sstevel@tonic-gate }
87447c478bd9Sstevel@tonic-gate 
87457c478bd9Sstevel@tonic-gate /*.......................................................................
87467c478bd9Sstevel@tonic-gate  * This is the private body of the gl_watch_fd() function. It
87477c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
87487c478bd9Sstevel@tonic-gate  * delivery of signals.
87497c478bd9Sstevel@tonic-gate  */
_gl_watch_fd(GetLine * gl,int fd,GlFdEvent event,GlFdEventFn * callback,void * data)87507c478bd9Sstevel@tonic-gate static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
87517c478bd9Sstevel@tonic-gate 			GlFdEventFn *callback, void *data)
87527c478bd9Sstevel@tonic-gate #if !defined(HAVE_SELECT)
87537c478bd9Sstevel@tonic-gate {return 1;}               /* The facility isn't supported on this system */
87547c478bd9Sstevel@tonic-gate #else
87557c478bd9Sstevel@tonic-gate {
87567c478bd9Sstevel@tonic-gate   GlFdNode *prev;  /* The node that precedes 'node' in gl->fd_nodes */
87577c478bd9Sstevel@tonic-gate   GlFdNode *node;  /* The file-descriptor node being checked */
87587c478bd9Sstevel@tonic-gate /*
87597c478bd9Sstevel@tonic-gate  * Search the list of already registered fd activity nodes for the specified
87607c478bd9Sstevel@tonic-gate  * file descriptor.
87617c478bd9Sstevel@tonic-gate  */
87627c478bd9Sstevel@tonic-gate   for(prev=NULL,node=gl->fd_nodes; node && node->fd != fd;
87637c478bd9Sstevel@tonic-gate       prev=node, node=node->next)
87647c478bd9Sstevel@tonic-gate     ;
87657c478bd9Sstevel@tonic-gate /*
87667c478bd9Sstevel@tonic-gate  * Hasn't a node been allocated for this fd yet?
87677c478bd9Sstevel@tonic-gate  */
87687c478bd9Sstevel@tonic-gate   if(!node) {
87697c478bd9Sstevel@tonic-gate /*
87707c478bd9Sstevel@tonic-gate  * If there is no callback to record, just ignore the call.
87717c478bd9Sstevel@tonic-gate  */
87727c478bd9Sstevel@tonic-gate     if(!callback)
87737c478bd9Sstevel@tonic-gate       return 0;
87747c478bd9Sstevel@tonic-gate /*
87757c478bd9Sstevel@tonic-gate  * Allocate the new node.
87767c478bd9Sstevel@tonic-gate  */
87777c478bd9Sstevel@tonic-gate     node = (GlFdNode *) _new_FreeListNode(gl->fd_node_mem);
87787c478bd9Sstevel@tonic-gate     if(!node) {
87797c478bd9Sstevel@tonic-gate       errno = ENOMEM;
87807c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "Insufficient memory", END_ERR_MSG);
87817c478bd9Sstevel@tonic-gate       return 1;
87827c478bd9Sstevel@tonic-gate     };
87837c478bd9Sstevel@tonic-gate /*
87847c478bd9Sstevel@tonic-gate  * Prepend the node to the list.
87857c478bd9Sstevel@tonic-gate  */
87867c478bd9Sstevel@tonic-gate     node->next = gl->fd_nodes;
87877c478bd9Sstevel@tonic-gate     gl->fd_nodes = node;
87887c478bd9Sstevel@tonic-gate /*
87897c478bd9Sstevel@tonic-gate  * Initialize the node.
87907c478bd9Sstevel@tonic-gate  */
87917c478bd9Sstevel@tonic-gate     node->fd = fd;
87927c478bd9Sstevel@tonic-gate     node->rd.fn = 0;
87937c478bd9Sstevel@tonic-gate     node->rd.data = NULL;
87947c478bd9Sstevel@tonic-gate     node->ur = node->wr = node->rd;
87957c478bd9Sstevel@tonic-gate   };
87967c478bd9Sstevel@tonic-gate /*
87977c478bd9Sstevel@tonic-gate  * Record the new callback.
87987c478bd9Sstevel@tonic-gate  */
87997c478bd9Sstevel@tonic-gate   switch(event) {
88007c478bd9Sstevel@tonic-gate   case GLFD_READ:
88017c478bd9Sstevel@tonic-gate     node->rd.fn = callback;
88027c478bd9Sstevel@tonic-gate     node->rd.data = data;
88037c478bd9Sstevel@tonic-gate     if(callback)
88047c478bd9Sstevel@tonic-gate       FD_SET(fd, &gl->rfds);
88057c478bd9Sstevel@tonic-gate     else
88067c478bd9Sstevel@tonic-gate       FD_CLR(fd, &gl->rfds);
88077c478bd9Sstevel@tonic-gate     break;
88087c478bd9Sstevel@tonic-gate   case GLFD_WRITE:
88097c478bd9Sstevel@tonic-gate     node->wr.fn = callback;
88107c478bd9Sstevel@tonic-gate     node->wr.data = data;
88117c478bd9Sstevel@tonic-gate     if(callback)
88127c478bd9Sstevel@tonic-gate       FD_SET(fd, &gl->wfds);
88137c478bd9Sstevel@tonic-gate     else
88147c478bd9Sstevel@tonic-gate       FD_CLR(fd, &gl->wfds);
88157c478bd9Sstevel@tonic-gate     break;
88167c478bd9Sstevel@tonic-gate   case GLFD_URGENT:
88177c478bd9Sstevel@tonic-gate     node->ur.fn = callback;
88187c478bd9Sstevel@tonic-gate     node->ur.data = data;
88197c478bd9Sstevel@tonic-gate     if(callback)
88207c478bd9Sstevel@tonic-gate       FD_SET(fd, &gl->ufds);
88217c478bd9Sstevel@tonic-gate     else
88227c478bd9Sstevel@tonic-gate       FD_CLR(fd, &gl->ufds);
88237c478bd9Sstevel@tonic-gate     break;
88247c478bd9Sstevel@tonic-gate   };
88257c478bd9Sstevel@tonic-gate /*
88267c478bd9Sstevel@tonic-gate  * Keep a record of the largest file descriptor being watched.
88277c478bd9Sstevel@tonic-gate  */
88287c478bd9Sstevel@tonic-gate   if(fd > gl->max_fd)
88297c478bd9Sstevel@tonic-gate     gl->max_fd = fd;
88307c478bd9Sstevel@tonic-gate /*
88317c478bd9Sstevel@tonic-gate  * If we are deleting an existing callback, also delete the parent
88327c478bd9Sstevel@tonic-gate  * activity node if no callbacks are registered to the fd anymore.
88337c478bd9Sstevel@tonic-gate  */
88347c478bd9Sstevel@tonic-gate   if(!callback) {
88357c478bd9Sstevel@tonic-gate     if(!node->rd.fn && !node->wr.fn && !node->ur.fn) {
88367c478bd9Sstevel@tonic-gate       if(prev)
88377c478bd9Sstevel@tonic-gate 	prev->next = node->next;
88387c478bd9Sstevel@tonic-gate       else
88397c478bd9Sstevel@tonic-gate 	gl->fd_nodes = node->next;
88407c478bd9Sstevel@tonic-gate       node = (GlFdNode *) _del_FreeListNode(gl->fd_node_mem, node);
88417c478bd9Sstevel@tonic-gate     };
88427c478bd9Sstevel@tonic-gate   };
88437c478bd9Sstevel@tonic-gate   return 0;
88447c478bd9Sstevel@tonic-gate }
88457c478bd9Sstevel@tonic-gate #endif
88467c478bd9Sstevel@tonic-gate 
88477c478bd9Sstevel@tonic-gate /*.......................................................................
88487c478bd9Sstevel@tonic-gate  * On systems with the select() system call, the gl_inactivity_timeout()
88497c478bd9Sstevel@tonic-gate  * function provides the option of setting (or cancelling) an
88507c478bd9Sstevel@tonic-gate  * inactivity timeout. Inactivity, in this case, refers both to
88517c478bd9Sstevel@tonic-gate  * terminal input received from the user, and to I/O on any file
88527c478bd9Sstevel@tonic-gate  * descriptors registered by calls to gl_watch_fd(). If at any time,
88537c478bd9Sstevel@tonic-gate  * no activity is seen for the requested time period, the specified
88547c478bd9Sstevel@tonic-gate  * timeout callback function is called. On returning, this callback
88557c478bd9Sstevel@tonic-gate  * returns a code which tells gl_get_line() what to do next. Note that
88567c478bd9Sstevel@tonic-gate  * each call to gl_inactivity_timeout() replaces any previously installed
88577c478bd9Sstevel@tonic-gate  * timeout callback, and that specifying a callback of 0, turns off
88587c478bd9Sstevel@tonic-gate  * inactivity timing.
88597c478bd9Sstevel@tonic-gate  *
88607c478bd9Sstevel@tonic-gate  * Beware that although the timeout argument includes a nano-second
88617c478bd9Sstevel@tonic-gate  * component, few computer clocks presently have resolutions finer
88627c478bd9Sstevel@tonic-gate  * than a few milliseconds, so asking for less than a few milliseconds
88637c478bd9Sstevel@tonic-gate  * is equivalent to zero on a lot of systems.
88647c478bd9Sstevel@tonic-gate  *
88657c478bd9Sstevel@tonic-gate  * Input:
88667c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of the command-line input
88677c478bd9Sstevel@tonic-gate  *                           module.
88687c478bd9Sstevel@tonic-gate  *  callback  GlTimeoutFn *  The function to call when the inactivity
88697c478bd9Sstevel@tonic-gate  *                           timeout is exceeded. To turn off
88707c478bd9Sstevel@tonic-gate  *                           inactivity timeouts altogether, send 0.
88717c478bd9Sstevel@tonic-gate  *  data             void *  A pointer to arbitrary data to pass to the
88727c478bd9Sstevel@tonic-gate  *                           callback function.
88737c478bd9Sstevel@tonic-gate  *  sec     unsigned long    The number of whole seconds in the timeout.
88747c478bd9Sstevel@tonic-gate  *  nsec    unsigned long    The fractional number of seconds in the
88757c478bd9Sstevel@tonic-gate  *                           timeout, expressed in nano-seconds (see
88767c478bd9Sstevel@tonic-gate  *                           the caveat above).
88777c478bd9Sstevel@tonic-gate  * Output:
88787c478bd9Sstevel@tonic-gate  *  return            int    0 - OK.
88797c478bd9Sstevel@tonic-gate  *                           1 - Either gl==NULL, or this facility isn't
88807c478bd9Sstevel@tonic-gate  *                               available on the the host system
88817c478bd9Sstevel@tonic-gate  *                               (ie. select() isn't available). No
88827c478bd9Sstevel@tonic-gate  *                               error message is generated in the latter
88837c478bd9Sstevel@tonic-gate  *                               case.
88847c478bd9Sstevel@tonic-gate  */
gl_inactivity_timeout(GetLine * gl,GlTimeoutFn * timeout_fn,void * data,unsigned long sec,unsigned long nsec)88857c478bd9Sstevel@tonic-gate int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *timeout_fn, void *data,
88867c478bd9Sstevel@tonic-gate 		   unsigned long sec, unsigned long nsec)
88877c478bd9Sstevel@tonic-gate #if !defined(HAVE_SELECT)
88887c478bd9Sstevel@tonic-gate {return 1;}               /* The facility isn't supported on this system */
88897c478bd9Sstevel@tonic-gate #else
88907c478bd9Sstevel@tonic-gate {
88917c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
88927c478bd9Sstevel@tonic-gate /*
88937c478bd9Sstevel@tonic-gate  * Check the arguments.
88947c478bd9Sstevel@tonic-gate  */
88957c478bd9Sstevel@tonic-gate   if(!gl) {
88967c478bd9Sstevel@tonic-gate     errno = EINVAL;
88977c478bd9Sstevel@tonic-gate     return 1;
88987c478bd9Sstevel@tonic-gate   };
88997c478bd9Sstevel@tonic-gate /*
89007c478bd9Sstevel@tonic-gate  * Block all signals.
89017c478bd9Sstevel@tonic-gate  */
89027c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
89037c478bd9Sstevel@tonic-gate     return 1;
89047c478bd9Sstevel@tonic-gate /*
89057c478bd9Sstevel@tonic-gate  * Install a new timeout?
89067c478bd9Sstevel@tonic-gate  */
89077c478bd9Sstevel@tonic-gate   if(timeout_fn) {
89087c478bd9Sstevel@tonic-gate     gl->timer.dt.tv_sec = sec;
89097c478bd9Sstevel@tonic-gate     gl->timer.dt.tv_usec = nsec / 1000;
89107c478bd9Sstevel@tonic-gate     gl->timer.fn = timeout_fn;
89117c478bd9Sstevel@tonic-gate     gl->timer.data = data;
89127c478bd9Sstevel@tonic-gate   } else {
89137c478bd9Sstevel@tonic-gate     gl->timer.fn = 0;
89147c478bd9Sstevel@tonic-gate     gl->timer.data = NULL;
89157c478bd9Sstevel@tonic-gate   };
89167c478bd9Sstevel@tonic-gate /*
89177c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
89187c478bd9Sstevel@tonic-gate  */
89197c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
89207c478bd9Sstevel@tonic-gate   return 0;
89217c478bd9Sstevel@tonic-gate }
89227c478bd9Sstevel@tonic-gate #endif
89237c478bd9Sstevel@tonic-gate 
89247c478bd9Sstevel@tonic-gate /*.......................................................................
89257c478bd9Sstevel@tonic-gate  * When select() is available, this is a private function of
89267c478bd9Sstevel@tonic-gate  * gl_read_input() which responds to file-descriptor events registered by
89277c478bd9Sstevel@tonic-gate  * the caller. Note that it assumes that it is being called from within
89287c478bd9Sstevel@tonic-gate  * gl_read_input()'s sigsetjump() clause.
89297c478bd9Sstevel@tonic-gate  *
89307c478bd9Sstevel@tonic-gate  * Input:
89317c478bd9Sstevel@tonic-gate  *  gl    GetLine *  The resource object of this module.
89327c478bd9Sstevel@tonic-gate  *  fd        int    The file descriptor to be watched for user input.
89337c478bd9Sstevel@tonic-gate  * Output:
89347c478bd9Sstevel@tonic-gate  *  return    int    0 - OK.
89357c478bd9Sstevel@tonic-gate  *                   1 - An error occurred.
89367c478bd9Sstevel@tonic-gate  */
gl_event_handler(GetLine * gl,int fd)89377c478bd9Sstevel@tonic-gate static int gl_event_handler(GetLine *gl, int fd)
89387c478bd9Sstevel@tonic-gate {
89397c478bd9Sstevel@tonic-gate #if !defined(HAVE_SELECT)
89407c478bd9Sstevel@tonic-gate   return 0;
89417c478bd9Sstevel@tonic-gate #else
89427c478bd9Sstevel@tonic-gate /*
89437c478bd9Sstevel@tonic-gate  * Set up a zero-second timeout.
89447c478bd9Sstevel@tonic-gate  */
89457c478bd9Sstevel@tonic-gate   struct timeval zero;
89467c478bd9Sstevel@tonic-gate   zero.tv_sec = zero.tv_usec = 0;
89477c478bd9Sstevel@tonic-gate /*
89487c478bd9Sstevel@tonic-gate  * If at any time no external callbacks remain, quit the loop return,
89497c478bd9Sstevel@tonic-gate  * so that we can simply wait in read(). This is designed as an
89507c478bd9Sstevel@tonic-gate  * optimization for when no callbacks have been registered on entry to
89517c478bd9Sstevel@tonic-gate  * this function, but since callbacks can delete themselves, it can
89527c478bd9Sstevel@tonic-gate  * also help later.
89537c478bd9Sstevel@tonic-gate  */
89547c478bd9Sstevel@tonic-gate   while(gl->fd_nodes || gl->timer.fn) {
89557c478bd9Sstevel@tonic-gate     int nready;   /* The number of file descriptors that are ready for I/O */
89567c478bd9Sstevel@tonic-gate /*
89577c478bd9Sstevel@tonic-gate  * Get the set of descriptors to be watched.
89587c478bd9Sstevel@tonic-gate  */
89597c478bd9Sstevel@tonic-gate     fd_set rfds = gl->rfds;
89607c478bd9Sstevel@tonic-gate     fd_set wfds = gl->wfds;
89617c478bd9Sstevel@tonic-gate     fd_set ufds = gl->ufds;
89627c478bd9Sstevel@tonic-gate /*
89637c478bd9Sstevel@tonic-gate  * Get the appropriate timeout.
89647c478bd9Sstevel@tonic-gate  */
89657c478bd9Sstevel@tonic-gate     struct timeval dt = gl->timer.fn ? gl->timer.dt : zero;
89667c478bd9Sstevel@tonic-gate /*
89677c478bd9Sstevel@tonic-gate  * Add the specified user-input file descriptor to the set that is to
89687c478bd9Sstevel@tonic-gate  * be watched.
89697c478bd9Sstevel@tonic-gate  */
89707c478bd9Sstevel@tonic-gate     FD_SET(fd, &rfds);
89717c478bd9Sstevel@tonic-gate /*
89727c478bd9Sstevel@tonic-gate  * Unblock the signals that we are watching, while select is blocked
89737c478bd9Sstevel@tonic-gate  * waiting for I/O.
89747c478bd9Sstevel@tonic-gate  */
89757c478bd9Sstevel@tonic-gate     gl_catch_signals(gl);
89767c478bd9Sstevel@tonic-gate /*
89777c478bd9Sstevel@tonic-gate  * Wait for activity on any of the file descriptors.
89787c478bd9Sstevel@tonic-gate  */
89797c478bd9Sstevel@tonic-gate     nready = select(gl->max_fd+1, &rfds, &wfds, &ufds,
89807c478bd9Sstevel@tonic-gate 	    (gl->timer.fn || gl->io_mode==GL_SERVER_MODE) ? &dt : NULL);
89817c478bd9Sstevel@tonic-gate /*
89827c478bd9Sstevel@tonic-gate  * We don't want to do a longjmp in the middle of a callback that
89837c478bd9Sstevel@tonic-gate  * might be modifying global or heap data, so block all the signals
89847c478bd9Sstevel@tonic-gate  * that we are trapping before executing callback functions. Note that
89857c478bd9Sstevel@tonic-gate  * the caller will unblock them again when it needs to, so there is
89867c478bd9Sstevel@tonic-gate  * no need to undo this before returning.
89877c478bd9Sstevel@tonic-gate  */
89887c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, NULL);
89897c478bd9Sstevel@tonic-gate /*
89907c478bd9Sstevel@tonic-gate  * If select() returns but none of the file descriptors are reported
89917c478bd9Sstevel@tonic-gate  * to have activity, then select() timed out.
89927c478bd9Sstevel@tonic-gate  */
89937c478bd9Sstevel@tonic-gate     if(nready == 0) {
89947c478bd9Sstevel@tonic-gate /*
89957c478bd9Sstevel@tonic-gate  * Note that in non-blocking server mode, the inactivity timer is used
89967c478bd9Sstevel@tonic-gate  * to allow I/O to block for a specified amount of time, so in this
89977c478bd9Sstevel@tonic-gate  * mode we return the postponed blocked status when an abort is
89987c478bd9Sstevel@tonic-gate  * requested.
89997c478bd9Sstevel@tonic-gate  */
90007c478bd9Sstevel@tonic-gate       if(gl_call_timeout_handler(gl)) {
90017c478bd9Sstevel@tonic-gate 	return 1;
90027c478bd9Sstevel@tonic-gate       } else if(gl->io_mode == GL_SERVER_MODE) {
90037c478bd9Sstevel@tonic-gate 	gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
90047c478bd9Sstevel@tonic-gate 	return 1;
90057c478bd9Sstevel@tonic-gate       };
90067c478bd9Sstevel@tonic-gate /*
90077c478bd9Sstevel@tonic-gate  * If nready < 0, this means an error occurred.
90087c478bd9Sstevel@tonic-gate  */
90097c478bd9Sstevel@tonic-gate     } else if(nready < 0) {
90107c478bd9Sstevel@tonic-gate       if(errno != EINTR) {
90117c478bd9Sstevel@tonic-gate 	gl_record_status(gl, GLR_ERROR, errno);
90127c478bd9Sstevel@tonic-gate 	return 1;
90137c478bd9Sstevel@tonic-gate       };
90147c478bd9Sstevel@tonic-gate /*
90157c478bd9Sstevel@tonic-gate  * If the user-input file descriptor has data available, return.
90167c478bd9Sstevel@tonic-gate  */
90177c478bd9Sstevel@tonic-gate     } else if(FD_ISSET(fd, &rfds)) {
90187c478bd9Sstevel@tonic-gate       return 0;
90197c478bd9Sstevel@tonic-gate /*
90207c478bd9Sstevel@tonic-gate  * Check for activity on any of the file descriptors registered by the
90217c478bd9Sstevel@tonic-gate  * calling application, and call the associated callback functions.
90227c478bd9Sstevel@tonic-gate  */
90237c478bd9Sstevel@tonic-gate     } else {
90247c478bd9Sstevel@tonic-gate       GlFdNode *node;   /* The fd event node being checked */
90257c478bd9Sstevel@tonic-gate /*
90267c478bd9Sstevel@tonic-gate  * Search the list for the file descriptor that caused select() to return.
90277c478bd9Sstevel@tonic-gate  */
90287c478bd9Sstevel@tonic-gate       for(node=gl->fd_nodes; node; node=node->next) {
90297c478bd9Sstevel@tonic-gate /*
90307c478bd9Sstevel@tonic-gate  * Is there urgent out of band data waiting to be read on fd?
90317c478bd9Sstevel@tonic-gate  */
90327c478bd9Sstevel@tonic-gate 	if(node->ur.fn && FD_ISSET(node->fd, &ufds)) {
90337c478bd9Sstevel@tonic-gate 	  if(gl_call_fd_handler(gl, &node->ur, node->fd, GLFD_URGENT))
90347c478bd9Sstevel@tonic-gate 	    return 1;
90357c478bd9Sstevel@tonic-gate 	  break;  /* The callback may have changed the list of nodes */
90367c478bd9Sstevel@tonic-gate /*
90377c478bd9Sstevel@tonic-gate  * Is the fd readable?
90387c478bd9Sstevel@tonic-gate  */
90397c478bd9Sstevel@tonic-gate 	} else if(node->rd.fn && FD_ISSET(node->fd, &rfds)) {
90407c478bd9Sstevel@tonic-gate 	  if(gl_call_fd_handler(gl, &node->rd, node->fd, GLFD_READ))
90417c478bd9Sstevel@tonic-gate 	    return 1;
90427c478bd9Sstevel@tonic-gate 	  break;  /* The callback may have changed the list of nodes */
90437c478bd9Sstevel@tonic-gate /*
90447c478bd9Sstevel@tonic-gate  * Is the fd writable?
90457c478bd9Sstevel@tonic-gate  */
90467c478bd9Sstevel@tonic-gate 	} else if(node->wr.fn && FD_ISSET(node->fd, &wfds)) {
90477c478bd9Sstevel@tonic-gate 	  if(gl_call_fd_handler(gl, &node->wr, node->fd, GLFD_WRITE))
90487c478bd9Sstevel@tonic-gate 	    return 1;
90497c478bd9Sstevel@tonic-gate 	  break;  /* The callback may have changed the list of nodes */
90507c478bd9Sstevel@tonic-gate 	};
90517c478bd9Sstevel@tonic-gate       };
90527c478bd9Sstevel@tonic-gate     };
90537c478bd9Sstevel@tonic-gate /*
90547c478bd9Sstevel@tonic-gate  * Just in case the above event handlers asked for the input line to
90557c478bd9Sstevel@tonic-gate  * be redrawn, flush any pending output.
90567c478bd9Sstevel@tonic-gate  */
90577c478bd9Sstevel@tonic-gate     if(gl_flush_output(gl))
90587c478bd9Sstevel@tonic-gate       return 1;
90597c478bd9Sstevel@tonic-gate   };
90607c478bd9Sstevel@tonic-gate   return 0;
90617c478bd9Sstevel@tonic-gate }
90627c478bd9Sstevel@tonic-gate #endif
90637c478bd9Sstevel@tonic-gate 
90647c478bd9Sstevel@tonic-gate #if defined(HAVE_SELECT)
90657c478bd9Sstevel@tonic-gate /*.......................................................................
90667c478bd9Sstevel@tonic-gate  * This is a private function of gl_event_handler(), used to call a
90677c478bd9Sstevel@tonic-gate  * file-descriptor callback.
90687c478bd9Sstevel@tonic-gate  *
90697c478bd9Sstevel@tonic-gate  * Input:
90707c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The resource object of gl_get_line().
90717c478bd9Sstevel@tonic-gate  *  gfh  GlFdHandler *  The I/O handler.
90727c478bd9Sstevel@tonic-gate  *  fd           int    The file-descriptor being reported.
90737c478bd9Sstevel@tonic-gate  *  event  GlFdEvent    The I/O event being reported.
90747c478bd9Sstevel@tonic-gate  * Output:
90757c478bd9Sstevel@tonic-gate  *  return       int    0 - OK.
90767c478bd9Sstevel@tonic-gate  *                      1 - Error.
90777c478bd9Sstevel@tonic-gate  */
90787c478bd9Sstevel@tonic-gate static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
90797c478bd9Sstevel@tonic-gate 			      GlFdEvent event)
90807c478bd9Sstevel@tonic-gate {
90817c478bd9Sstevel@tonic-gate   Termios attr;       /* The terminal attributes */
90827c478bd9Sstevel@tonic-gate   int waserr = 0;     /* True after any error */
90837c478bd9Sstevel@tonic-gate /*
90847c478bd9Sstevel@tonic-gate  * Re-enable conversion of newline characters to carriage-return/linefeed,
90857c478bd9Sstevel@tonic-gate  * so that the callback can write to the terminal without having to do
90867c478bd9Sstevel@tonic-gate  * anything special.
90877c478bd9Sstevel@tonic-gate  */
90887c478bd9Sstevel@tonic-gate   if(tcgetattr(gl->input_fd, &attr)) {
90897c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
90907c478bd9Sstevel@tonic-gate     return 1;
90917c478bd9Sstevel@tonic-gate   };
90927c478bd9Sstevel@tonic-gate   attr.c_oflag |= OPOST;
90937c478bd9Sstevel@tonic-gate   while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
90947c478bd9Sstevel@tonic-gate     if(errno != EINTR) {
90957c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
90967c478bd9Sstevel@tonic-gate       return 1;
90977c478bd9Sstevel@tonic-gate     };
90987c478bd9Sstevel@tonic-gate   };
90997c478bd9Sstevel@tonic-gate /*
91007c478bd9Sstevel@tonic-gate  * Invoke the application's callback function.
91017c478bd9Sstevel@tonic-gate  */
91027c478bd9Sstevel@tonic-gate   switch(gfh->fn(gl, gfh->data, fd, event)) {
91037c478bd9Sstevel@tonic-gate   default:
91047c478bd9Sstevel@tonic-gate   case GLFD_ABORT:
91057c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_FDABORT, 0);
91067c478bd9Sstevel@tonic-gate     waserr = 1;
91077c478bd9Sstevel@tonic-gate     break;
91087c478bd9Sstevel@tonic-gate   case GLFD_REFRESH:
91097c478bd9Sstevel@tonic-gate     gl_queue_redisplay(gl);
91107c478bd9Sstevel@tonic-gate     break;
91117c478bd9Sstevel@tonic-gate   case GLFD_CONTINUE:
91127c478bd9Sstevel@tonic-gate     break;
91137c478bd9Sstevel@tonic-gate   };
91147c478bd9Sstevel@tonic-gate /*
91157c478bd9Sstevel@tonic-gate  * Disable conversion of newline characters to carriage-return/linefeed.
91167c478bd9Sstevel@tonic-gate  */
91177c478bd9Sstevel@tonic-gate   attr.c_oflag &= ~(OPOST);
91187c478bd9Sstevel@tonic-gate   while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
91197c478bd9Sstevel@tonic-gate     if(errno != EINTR) {
91207c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
91217c478bd9Sstevel@tonic-gate       return 1;
91227c478bd9Sstevel@tonic-gate     };
91237c478bd9Sstevel@tonic-gate   };
91247c478bd9Sstevel@tonic-gate   return waserr;
91257c478bd9Sstevel@tonic-gate }
91267c478bd9Sstevel@tonic-gate 
91277c478bd9Sstevel@tonic-gate /*.......................................................................
91287c478bd9Sstevel@tonic-gate  * This is a private function of gl_event_handler(), used to call a
91297c478bd9Sstevel@tonic-gate  * inactivity timer callbacks.
91307c478bd9Sstevel@tonic-gate  *
91317c478bd9Sstevel@tonic-gate  * Input:
91327c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The resource object of gl_get_line().
91337c478bd9Sstevel@tonic-gate  * Output:
91347c478bd9Sstevel@tonic-gate  *  return       int    0 - OK.
91357c478bd9Sstevel@tonic-gate  *                      1 - Error.
91367c478bd9Sstevel@tonic-gate  */
91377c478bd9Sstevel@tonic-gate static int gl_call_timeout_handler(GetLine *gl)
91387c478bd9Sstevel@tonic-gate {
91397c478bd9Sstevel@tonic-gate   Termios attr;       /* The terminal attributes */
91407c478bd9Sstevel@tonic-gate   int waserr = 0;     /* True after any error */
91417c478bd9Sstevel@tonic-gate /*
91427c478bd9Sstevel@tonic-gate  * Make sure that there is an inactivity timeout callback.
91437c478bd9Sstevel@tonic-gate  */
91447c478bd9Sstevel@tonic-gate   if(!gl->timer.fn)
91457c478bd9Sstevel@tonic-gate     return 0;
91467c478bd9Sstevel@tonic-gate /*
91477c478bd9Sstevel@tonic-gate  * Re-enable conversion of newline characters to carriage-return/linefeed,
91487c478bd9Sstevel@tonic-gate  * so that the callback can write to the terminal without having to do
91497c478bd9Sstevel@tonic-gate  * anything special.
91507c478bd9Sstevel@tonic-gate  */
91517c478bd9Sstevel@tonic-gate   if(tcgetattr(gl->input_fd, &attr)) {
91527c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG);
91537c478bd9Sstevel@tonic-gate     return 1;
91547c478bd9Sstevel@tonic-gate   };
91557c478bd9Sstevel@tonic-gate   attr.c_oflag |= OPOST;
91567c478bd9Sstevel@tonic-gate   while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
91577c478bd9Sstevel@tonic-gate     if(errno != EINTR) {
91587c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
91597c478bd9Sstevel@tonic-gate       return 1;
91607c478bd9Sstevel@tonic-gate     };
91617c478bd9Sstevel@tonic-gate   };
91627c478bd9Sstevel@tonic-gate /*
91637c478bd9Sstevel@tonic-gate  * Invoke the application's callback function.
91647c478bd9Sstevel@tonic-gate  */
91657c478bd9Sstevel@tonic-gate   switch(gl->timer.fn(gl, gl->timer.data)) {
91667c478bd9Sstevel@tonic-gate   default:
91677c478bd9Sstevel@tonic-gate   case GLTO_ABORT:
91687c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_TIMEOUT, 0);
91697c478bd9Sstevel@tonic-gate     waserr = 1;
91707c478bd9Sstevel@tonic-gate     break;
91717c478bd9Sstevel@tonic-gate   case GLTO_REFRESH:
91727c478bd9Sstevel@tonic-gate     gl_queue_redisplay(gl);
91737c478bd9Sstevel@tonic-gate     break;
91747c478bd9Sstevel@tonic-gate   case GLTO_CONTINUE:
91757c478bd9Sstevel@tonic-gate     break;
91767c478bd9Sstevel@tonic-gate   };
91777c478bd9Sstevel@tonic-gate /*
91787c478bd9Sstevel@tonic-gate  * Disable conversion of newline characters to carriage-return/linefeed.
91797c478bd9Sstevel@tonic-gate  */
91807c478bd9Sstevel@tonic-gate   attr.c_oflag &= ~(OPOST);
91817c478bd9Sstevel@tonic-gate   while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) {
91827c478bd9Sstevel@tonic-gate     if(errno != EINTR) {
91837c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG);
91847c478bd9Sstevel@tonic-gate       return 1;
91857c478bd9Sstevel@tonic-gate     };
91867c478bd9Sstevel@tonic-gate   };
91877c478bd9Sstevel@tonic-gate   return waserr;
91887c478bd9Sstevel@tonic-gate }
91897c478bd9Sstevel@tonic-gate #endif  /* HAVE_SELECT */
91907c478bd9Sstevel@tonic-gate 
91917c478bd9Sstevel@tonic-gate /*.......................................................................
91927c478bd9Sstevel@tonic-gate  * Switch history groups. History groups represent separate history
91937c478bd9Sstevel@tonic-gate  * lists recorded within a single history buffer. Different groups
91947c478bd9Sstevel@tonic-gate  * are distinguished by integer identifiers chosen by the calling
91957c478bd9Sstevel@tonic-gate  * appplicaton. Initially new_GetLine() sets the group identifier to
91967c478bd9Sstevel@tonic-gate  * 0. Whenever a new line is appended to the history list, the current
91977c478bd9Sstevel@tonic-gate  * group identifier is recorded with it, and history lookups only
91987c478bd9Sstevel@tonic-gate  * consider lines marked with the current group identifier.
91997c478bd9Sstevel@tonic-gate  *
92007c478bd9Sstevel@tonic-gate  * Input:
92017c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The resource object of gl_get_line().
92027c478bd9Sstevel@tonic-gate  *  id     unsigned    The new history group identifier.
92037c478bd9Sstevel@tonic-gate  * Output:
92047c478bd9Sstevel@tonic-gate  *  return      int    0 - OK.
92057c478bd9Sstevel@tonic-gate  *                     1 - Error.
92067c478bd9Sstevel@tonic-gate  */
92077c478bd9Sstevel@tonic-gate int gl_group_history(GetLine *gl, unsigned id)
92087c478bd9Sstevel@tonic-gate {
92097c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
92107c478bd9Sstevel@tonic-gate   int status;      /* The return status of this function */
92117c478bd9Sstevel@tonic-gate /*
92127c478bd9Sstevel@tonic-gate  * Check the arguments.
92137c478bd9Sstevel@tonic-gate  */
92147c478bd9Sstevel@tonic-gate   if(!gl) {
92157c478bd9Sstevel@tonic-gate     errno = EINVAL;
92167c478bd9Sstevel@tonic-gate     return 1;
92177c478bd9Sstevel@tonic-gate   };
92187c478bd9Sstevel@tonic-gate /*
92197c478bd9Sstevel@tonic-gate  * Block all signals while we install the new configuration.
92207c478bd9Sstevel@tonic-gate  */
92217c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
92227c478bd9Sstevel@tonic-gate     return 1;
92237c478bd9Sstevel@tonic-gate /*
92247c478bd9Sstevel@tonic-gate  * If the group isn't being changed, do nothing.
92257c478bd9Sstevel@tonic-gate  */
92267c478bd9Sstevel@tonic-gate   if(_glh_get_group(gl->glh) == id) {
92277c478bd9Sstevel@tonic-gate     status = 0;
92287c478bd9Sstevel@tonic-gate /*
92297c478bd9Sstevel@tonic-gate  * Establish the new group.
92307c478bd9Sstevel@tonic-gate  */
92317c478bd9Sstevel@tonic-gate   } else if(_glh_set_group(gl->glh, id)) {
92327c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
92337c478bd9Sstevel@tonic-gate     status = 1;
92347c478bd9Sstevel@tonic-gate /*
92357c478bd9Sstevel@tonic-gate  * Prevent history information from the previous group being
92367c478bd9Sstevel@tonic-gate  * inappropriately used by the next call to gl_get_line().
92377c478bd9Sstevel@tonic-gate  */
92387c478bd9Sstevel@tonic-gate   } else {
92397c478bd9Sstevel@tonic-gate     gl->preload_history = 0;
92407c478bd9Sstevel@tonic-gate     gl->last_search = -1;
92417c478bd9Sstevel@tonic-gate     status = 0;
92427c478bd9Sstevel@tonic-gate   };
92437c478bd9Sstevel@tonic-gate /*
92447c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
92457c478bd9Sstevel@tonic-gate  */
92467c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
92477c478bd9Sstevel@tonic-gate   return status;
92487c478bd9Sstevel@tonic-gate }
92497c478bd9Sstevel@tonic-gate 
92507c478bd9Sstevel@tonic-gate /*.......................................................................
92517c478bd9Sstevel@tonic-gate  * Display the contents of the history list.
92527c478bd9Sstevel@tonic-gate  *
92537c478bd9Sstevel@tonic-gate  * Input:
92547c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The resource object of gl_get_line().
92557c478bd9Sstevel@tonic-gate  *  fp         FILE *  The stdio output stream to write to.
92567c478bd9Sstevel@tonic-gate  *  fmt  const char *  A format string. This containing characters to be
92577c478bd9Sstevel@tonic-gate  *                     written verbatim, plus any of the following
92587c478bd9Sstevel@tonic-gate  *                     format directives:
92597c478bd9Sstevel@tonic-gate  *                       %D  -  The date, formatted like 2001-11-20
92607c478bd9Sstevel@tonic-gate  *                       %T  -  The time of day, formatted like 23:59:59
92617c478bd9Sstevel@tonic-gate  *                       %N  -  The sequential entry number of the
92627c478bd9Sstevel@tonic-gate  *                              line in the history buffer.
92637c478bd9Sstevel@tonic-gate  *                       %G  -  The number of the history group that
92647c478bd9Sstevel@tonic-gate  *                              the line belongs to.
92657c478bd9Sstevel@tonic-gate  *                       %%  -  A literal % character.
92667c478bd9Sstevel@tonic-gate  *                       %H  -  The history line itself.
92677c478bd9Sstevel@tonic-gate  *                     Note that a '\n' newline character is not
92687c478bd9Sstevel@tonic-gate  *                     appended by default.
92697c478bd9Sstevel@tonic-gate  *  all_groups  int    If true, display history lines from all
92707c478bd9Sstevel@tonic-gate  *                     history groups. Otherwise only display
92717c478bd9Sstevel@tonic-gate  *                     those of the current history group.
92727c478bd9Sstevel@tonic-gate  *  max_lines   int    If max_lines is < 0, all available lines
92737c478bd9Sstevel@tonic-gate  *                     are displayed. Otherwise only the most
92747c478bd9Sstevel@tonic-gate  *                     recent max_lines lines will be displayed.
92757c478bd9Sstevel@tonic-gate  * Output:
92767c478bd9Sstevel@tonic-gate  *  return      int    0 - OK.
92777c478bd9Sstevel@tonic-gate  *                     1 - Error.
92787c478bd9Sstevel@tonic-gate  */
92797c478bd9Sstevel@tonic-gate int gl_show_history(GetLine *gl, FILE *fp, const char *fmt, int all_groups,
92807c478bd9Sstevel@tonic-gate 		    int max_lines)
92817c478bd9Sstevel@tonic-gate {
92827c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
92837c478bd9Sstevel@tonic-gate   int status;      /* The return status of this function */
92847c478bd9Sstevel@tonic-gate /*
92857c478bd9Sstevel@tonic-gate  * Check the arguments.
92867c478bd9Sstevel@tonic-gate  */
92877c478bd9Sstevel@tonic-gate   if(!gl || !fp || !fmt) {
92887c478bd9Sstevel@tonic-gate     if(gl)
92897c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
92907c478bd9Sstevel@tonic-gate     errno = EINVAL;
92917c478bd9Sstevel@tonic-gate     return 1;
92927c478bd9Sstevel@tonic-gate   };
92937c478bd9Sstevel@tonic-gate /*
92947c478bd9Sstevel@tonic-gate  * Block all signals.
92957c478bd9Sstevel@tonic-gate  */
92967c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
92977c478bd9Sstevel@tonic-gate     return 1;
92987c478bd9Sstevel@tonic-gate /*
92997c478bd9Sstevel@tonic-gate  * Display the specified history group(s) while signals are blocked.
93007c478bd9Sstevel@tonic-gate  */
93017c478bd9Sstevel@tonic-gate   status = _glh_show_history(gl->glh, _io_write_stdio, fp, fmt, all_groups,
93027c478bd9Sstevel@tonic-gate 			     max_lines) || fflush(fp)==EOF;
93037c478bd9Sstevel@tonic-gate   if(!status)
93047c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
93057c478bd9Sstevel@tonic-gate /*
93067c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
93077c478bd9Sstevel@tonic-gate  */
93087c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
93097c478bd9Sstevel@tonic-gate   return status;
93107c478bd9Sstevel@tonic-gate }
93117c478bd9Sstevel@tonic-gate 
93127c478bd9Sstevel@tonic-gate /*.......................................................................
93137c478bd9Sstevel@tonic-gate  * Update if necessary, and return the current size of the terminal.
93147c478bd9Sstevel@tonic-gate  *
93157c478bd9Sstevel@tonic-gate  * Input:
93167c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of gl_get_line().
93177c478bd9Sstevel@tonic-gate  *  def_ncolumn       int    If the number of columns in the terminal
93187c478bd9Sstevel@tonic-gate  *                           can't be determined, substitute this number.
93197c478bd9Sstevel@tonic-gate  *  def_nline         int    If the number of lines in the terminal can't
93207c478bd9Sstevel@tonic-gate  *                           be determined, substitute this number.
93217c478bd9Sstevel@tonic-gate  * Output:
93227c478bd9Sstevel@tonic-gate  *  return GlTerminalSize    The current terminal size.
93237c478bd9Sstevel@tonic-gate  */
93247c478bd9Sstevel@tonic-gate GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline)
93257c478bd9Sstevel@tonic-gate {
93267c478bd9Sstevel@tonic-gate   GlTerminalSize size;  /* The object to be returned */
93277c478bd9Sstevel@tonic-gate   sigset_t oldset;      /* The signals that were blocked on entry */
93287c478bd9Sstevel@tonic-gate                         /*  to this function */
93297c478bd9Sstevel@tonic-gate /*
93307c478bd9Sstevel@tonic-gate  * Block all signals while accessing gl.
93317c478bd9Sstevel@tonic-gate  */
93327c478bd9Sstevel@tonic-gate   gl_mask_signals(gl, &oldset);
93337c478bd9Sstevel@tonic-gate /*
93347c478bd9Sstevel@tonic-gate  * Lookup/configure the terminal size.
93357c478bd9Sstevel@tonic-gate  */
93367c478bd9Sstevel@tonic-gate   _gl_terminal_size(gl, def_ncolumn, def_nline, &size);
93377c478bd9Sstevel@tonic-gate /*
93387c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
93397c478bd9Sstevel@tonic-gate  */
93407c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
93417c478bd9Sstevel@tonic-gate   return size;
93427c478bd9Sstevel@tonic-gate }
93437c478bd9Sstevel@tonic-gate 
93447c478bd9Sstevel@tonic-gate /*.......................................................................
93457c478bd9Sstevel@tonic-gate  * This is the private body of the gl_terminal_size() function. It
93467c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
93477c478bd9Sstevel@tonic-gate  * delivery of signals.
93487c478bd9Sstevel@tonic-gate  */
93497c478bd9Sstevel@tonic-gate static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline,
93507c478bd9Sstevel@tonic-gate 			      GlTerminalSize *size)
93517c478bd9Sstevel@tonic-gate {
93527c478bd9Sstevel@tonic-gate   const char *env;      /* The value of an environment variable */
93537c478bd9Sstevel@tonic-gate   int n;                /* A number read from env[] */
93547c478bd9Sstevel@tonic-gate /*
93557c478bd9Sstevel@tonic-gate  * Set the number of lines and columns to non-sensical values so that
93567c478bd9Sstevel@tonic-gate  * we know later if they have been set.
93577c478bd9Sstevel@tonic-gate  */
93587c478bd9Sstevel@tonic-gate   gl->nline = 0;
93597c478bd9Sstevel@tonic-gate   gl->ncolumn = 0;
93607c478bd9Sstevel@tonic-gate /*
93617c478bd9Sstevel@tonic-gate  * Are we reading from a terminal?
93627c478bd9Sstevel@tonic-gate  */
93637c478bd9Sstevel@tonic-gate   if(gl->is_term) {
93647c478bd9Sstevel@tonic-gate /*
93657c478bd9Sstevel@tonic-gate  * Ask the terminal directly if possible.
93667c478bd9Sstevel@tonic-gate  */
93677c478bd9Sstevel@tonic-gate     (void) _gl_update_size(gl);
93687c478bd9Sstevel@tonic-gate /*
93697c478bd9Sstevel@tonic-gate  * If gl_update_size() couldn't ask the terminal, it will have
93707c478bd9Sstevel@tonic-gate  * left gl->nrow and gl->ncolumn unchanged. If these values haven't
93717c478bd9Sstevel@tonic-gate  * been changed from their initial values of zero, we need to find
93727c478bd9Sstevel@tonic-gate  * a different method to get the terminal size.
93737c478bd9Sstevel@tonic-gate  *
93747c478bd9Sstevel@tonic-gate  * If the number of lines isn't known yet, first see if the
93757c478bd9Sstevel@tonic-gate  * LINES environment ariable exists and specifies a believable number.
93767c478bd9Sstevel@tonic-gate  * If this doesn't work, look up the default size in the terminal
93777c478bd9Sstevel@tonic-gate  * information database.
93787c478bd9Sstevel@tonic-gate  */
93797c478bd9Sstevel@tonic-gate     if(gl->nline < 1) {
93807c478bd9Sstevel@tonic-gate       if((env = getenv("LINES")) && (n=atoi(env)) > 0)
93817c478bd9Sstevel@tonic-gate 	gl->nline = n;
93827c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
93837c478bd9Sstevel@tonic-gate       else
93847c478bd9Sstevel@tonic-gate 	gl->nline = tigetnum((char *)"lines");
93857c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP)
93867c478bd9Sstevel@tonic-gate       else
93877c478bd9Sstevel@tonic-gate         gl->nline = tgetnum("li");
93887c478bd9Sstevel@tonic-gate #endif
93897c478bd9Sstevel@tonic-gate     };
93907c478bd9Sstevel@tonic-gate /*
93917c478bd9Sstevel@tonic-gate  * If the number of lines isn't known yet, first see if the COLUMNS
93927c478bd9Sstevel@tonic-gate  * environment ariable exists and specifies a believable number.  If
93937c478bd9Sstevel@tonic-gate  * this doesn't work, look up the default size in the terminal
93947c478bd9Sstevel@tonic-gate  * information database.
93957c478bd9Sstevel@tonic-gate  */
93967c478bd9Sstevel@tonic-gate     if(gl->ncolumn < 1) {
93977c478bd9Sstevel@tonic-gate       if((env = getenv("COLUMNS")) && (n=atoi(env)) > 0)
93987c478bd9Sstevel@tonic-gate 	gl->ncolumn = n;
93997c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO
94007c478bd9Sstevel@tonic-gate       else
94017c478bd9Sstevel@tonic-gate 	gl->ncolumn = tigetnum((char *)"cols");
94027c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP)
94037c478bd9Sstevel@tonic-gate       else
94047c478bd9Sstevel@tonic-gate 	gl->ncolumn = tgetnum("co");
94057c478bd9Sstevel@tonic-gate #endif
94067c478bd9Sstevel@tonic-gate     };
94077c478bd9Sstevel@tonic-gate   };
94087c478bd9Sstevel@tonic-gate /*
94097c478bd9Sstevel@tonic-gate  * If we still haven't been able to acquire reasonable values, substitute
94107c478bd9Sstevel@tonic-gate  * the default values specified by the caller.
94117c478bd9Sstevel@tonic-gate  */
94127c478bd9Sstevel@tonic-gate   if(gl->nline <= 0)
94137c478bd9Sstevel@tonic-gate     gl->nline = def_nline;
94147c478bd9Sstevel@tonic-gate   if(gl->ncolumn <= 0)
94157c478bd9Sstevel@tonic-gate     gl->ncolumn = def_ncolumn;
94167c478bd9Sstevel@tonic-gate /*
94177c478bd9Sstevel@tonic-gate  * Copy the new size into the return value.
94187c478bd9Sstevel@tonic-gate  */
94197c478bd9Sstevel@tonic-gate   if(size) {
94207c478bd9Sstevel@tonic-gate     size->nline = gl->nline;
94217c478bd9Sstevel@tonic-gate     size->ncolumn = gl->ncolumn;
94227c478bd9Sstevel@tonic-gate   };
94237c478bd9Sstevel@tonic-gate   return;
94247c478bd9Sstevel@tonic-gate }
94257c478bd9Sstevel@tonic-gate 
94267c478bd9Sstevel@tonic-gate /*.......................................................................
94277c478bd9Sstevel@tonic-gate  * Resize or delete the history buffer.
94287c478bd9Sstevel@tonic-gate  *
94297c478bd9Sstevel@tonic-gate  * Input:
94307c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The resource object of gl_get_line().
94317c478bd9Sstevel@tonic-gate  *  bufsize  size_t    The number of bytes in the history buffer, or 0
94327c478bd9Sstevel@tonic-gate  *                     to delete the buffer completely.
94337c478bd9Sstevel@tonic-gate  * Output:
94347c478bd9Sstevel@tonic-gate  *  return      int    0 - OK.
94357c478bd9Sstevel@tonic-gate  *                     1 - Insufficient memory (the previous buffer
94367c478bd9Sstevel@tonic-gate  *                         will have been retained). No error message
94377c478bd9Sstevel@tonic-gate  *                         will be displayed.
94387c478bd9Sstevel@tonic-gate  */
94397c478bd9Sstevel@tonic-gate int gl_resize_history(GetLine *gl, size_t bufsize)
94407c478bd9Sstevel@tonic-gate {
94417c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
94427c478bd9Sstevel@tonic-gate   int status;      /* The return status of this function */
94437c478bd9Sstevel@tonic-gate /*
94447c478bd9Sstevel@tonic-gate  * Check the arguments.
94457c478bd9Sstevel@tonic-gate  */
94467c478bd9Sstevel@tonic-gate   if(!gl)
94477c478bd9Sstevel@tonic-gate     return 1;
94487c478bd9Sstevel@tonic-gate /*
94497c478bd9Sstevel@tonic-gate  * Block all signals while modifying the contents of gl.
94507c478bd9Sstevel@tonic-gate  */
94517c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
94527c478bd9Sstevel@tonic-gate     return 1;
94537c478bd9Sstevel@tonic-gate /*
94547c478bd9Sstevel@tonic-gate  * Perform the resize while signals are blocked.
94557c478bd9Sstevel@tonic-gate  */
94567c478bd9Sstevel@tonic-gate   status = _glh_resize_history(gl->glh, bufsize);
94577c478bd9Sstevel@tonic-gate   if(status)
94587c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
94597c478bd9Sstevel@tonic-gate /*
94607c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
94617c478bd9Sstevel@tonic-gate  */
94627c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
94637c478bd9Sstevel@tonic-gate   return status;
94647c478bd9Sstevel@tonic-gate }
94657c478bd9Sstevel@tonic-gate 
94667c478bd9Sstevel@tonic-gate /*.......................................................................
94677c478bd9Sstevel@tonic-gate  * Set an upper limit to the number of lines that can be recorded in the
94687c478bd9Sstevel@tonic-gate  * history list, or remove a previously specified limit.
94697c478bd9Sstevel@tonic-gate  *
94707c478bd9Sstevel@tonic-gate  * Input:
94717c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The resource object of gl_get_line().
94727c478bd9Sstevel@tonic-gate  *  max_lines   int    The maximum number of lines to allow, or -1 to
94737c478bd9Sstevel@tonic-gate  *                     cancel a previous limit and allow as many lines
94747c478bd9Sstevel@tonic-gate  *                     as will fit in the current history buffer size.
94757c478bd9Sstevel@tonic-gate  */
94767c478bd9Sstevel@tonic-gate void gl_limit_history(GetLine *gl, int max_lines)
94777c478bd9Sstevel@tonic-gate {
94787c478bd9Sstevel@tonic-gate   if(gl) {
94797c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
94807c478bd9Sstevel@tonic-gate /*
94817c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
94827c478bd9Sstevel@tonic-gate  */
94837c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
94847c478bd9Sstevel@tonic-gate /*
94857c478bd9Sstevel@tonic-gate  * Apply the limit while signals are blocked.
94867c478bd9Sstevel@tonic-gate  */
94877c478bd9Sstevel@tonic-gate     _glh_limit_history(gl->glh, max_lines);
94887c478bd9Sstevel@tonic-gate /*
94897c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
94907c478bd9Sstevel@tonic-gate  */
94917c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
94927c478bd9Sstevel@tonic-gate   };
94937c478bd9Sstevel@tonic-gate }
94947c478bd9Sstevel@tonic-gate 
94957c478bd9Sstevel@tonic-gate /*.......................................................................
94967c478bd9Sstevel@tonic-gate  * Discard either all historical lines, or just those associated with the
94977c478bd9Sstevel@tonic-gate  * current history group.
94987c478bd9Sstevel@tonic-gate  *
94997c478bd9Sstevel@tonic-gate  * Input:
95007c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The resource object of gl_get_line().
95017c478bd9Sstevel@tonic-gate  *  all_groups  int    If true, clear all of the history. If false,
95027c478bd9Sstevel@tonic-gate  *                     clear only the stored lines associated with the
95037c478bd9Sstevel@tonic-gate  *                     currently selected history group.
95047c478bd9Sstevel@tonic-gate  */
95057c478bd9Sstevel@tonic-gate void gl_clear_history(GetLine *gl, int all_groups)
95067c478bd9Sstevel@tonic-gate {
95077c478bd9Sstevel@tonic-gate   if(gl) {
95087c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
95097c478bd9Sstevel@tonic-gate /*
95107c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
95117c478bd9Sstevel@tonic-gate  */
95127c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
95137c478bd9Sstevel@tonic-gate /*
95147c478bd9Sstevel@tonic-gate  * Clear the history buffer while signals are blocked.
95157c478bd9Sstevel@tonic-gate  */
95167c478bd9Sstevel@tonic-gate     _glh_clear_history(gl->glh, all_groups);
95177c478bd9Sstevel@tonic-gate /*
95187c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
95197c478bd9Sstevel@tonic-gate  */
95207c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
95217c478bd9Sstevel@tonic-gate   };
95227c478bd9Sstevel@tonic-gate }
95237c478bd9Sstevel@tonic-gate 
95247c478bd9Sstevel@tonic-gate /*.......................................................................
95257c478bd9Sstevel@tonic-gate  * Temporarily enable or disable the gl_get_line() history mechanism.
95267c478bd9Sstevel@tonic-gate  *
95277c478bd9Sstevel@tonic-gate  * Input:
95287c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The resource object of gl_get_line().
95297c478bd9Sstevel@tonic-gate  *  enable      int    If true, turn on the history mechanism. If
95307c478bd9Sstevel@tonic-gate  *                     false, disable it.
95317c478bd9Sstevel@tonic-gate  */
95327c478bd9Sstevel@tonic-gate void gl_toggle_history(GetLine *gl, int enable)
95337c478bd9Sstevel@tonic-gate {
95347c478bd9Sstevel@tonic-gate   if(gl) {
95357c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
95367c478bd9Sstevel@tonic-gate /*
95377c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
95387c478bd9Sstevel@tonic-gate  */
95397c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
95407c478bd9Sstevel@tonic-gate /*
95417c478bd9Sstevel@tonic-gate  * Change the history recording mode while signals are blocked.
95427c478bd9Sstevel@tonic-gate  */
95437c478bd9Sstevel@tonic-gate     _glh_toggle_history(gl->glh, enable);
95447c478bd9Sstevel@tonic-gate /*
95457c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
95467c478bd9Sstevel@tonic-gate  */
95477c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
95487c478bd9Sstevel@tonic-gate   };
95497c478bd9Sstevel@tonic-gate }
95507c478bd9Sstevel@tonic-gate 
95517c478bd9Sstevel@tonic-gate /*.......................................................................
95527c478bd9Sstevel@tonic-gate  * Lookup a history line by its sequential number of entry in the
95537c478bd9Sstevel@tonic-gate  * history buffer.
95547c478bd9Sstevel@tonic-gate  *
95557c478bd9Sstevel@tonic-gate  * Input:
95567c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of gl_get_line().
95577c478bd9Sstevel@tonic-gate  *  id      unsigned long    The identification number of the line to
95587c478bd9Sstevel@tonic-gate  *                           be returned, where 0 denotes the first line
95597c478bd9Sstevel@tonic-gate  *                           that was entered in the history list, and
95607c478bd9Sstevel@tonic-gate  *                           each subsequently added line has a number
95617c478bd9Sstevel@tonic-gate  *                           one greater than the previous one. For
95627c478bd9Sstevel@tonic-gate  *                           the range of lines currently in the list,
95637c478bd9Sstevel@tonic-gate  *                           see the gl_range_of_history() function.
95647c478bd9Sstevel@tonic-gate  * Input/Output:
95657c478bd9Sstevel@tonic-gate  *  line    GlHistoryLine *  A pointer to the variable in which to
95667c478bd9Sstevel@tonic-gate  *                           return the details of the line.
95677c478bd9Sstevel@tonic-gate  * Output:
95687c478bd9Sstevel@tonic-gate  *  return            int    0 - The line is no longer in the history
95697c478bd9Sstevel@tonic-gate  *                               list, and *line has not been changed.
95707c478bd9Sstevel@tonic-gate  *                           1 - The requested line can be found in
95717c478bd9Sstevel@tonic-gate  *                               *line. Note that line->line is part
95727c478bd9Sstevel@tonic-gate  *                               of the history buffer, so a
95737c478bd9Sstevel@tonic-gate  *                               private copy should be made if you
95747c478bd9Sstevel@tonic-gate  *                               wish to use it after subsequent calls
95757c478bd9Sstevel@tonic-gate  *                               to any functions that take *gl as an
95767c478bd9Sstevel@tonic-gate  *                               argument.
95777c478bd9Sstevel@tonic-gate  */
95787c478bd9Sstevel@tonic-gate int gl_lookup_history(GetLine *gl, unsigned long id, GlHistoryLine *line)
95797c478bd9Sstevel@tonic-gate {
95807c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
95817c478bd9Sstevel@tonic-gate   int status;      /* The return status of this function */
95827c478bd9Sstevel@tonic-gate /*
95837c478bd9Sstevel@tonic-gate  * Check the arguments.
95847c478bd9Sstevel@tonic-gate  */
95857c478bd9Sstevel@tonic-gate   if(!gl)
95867c478bd9Sstevel@tonic-gate     return 0;
95877c478bd9Sstevel@tonic-gate /*
95887c478bd9Sstevel@tonic-gate  * Block all signals while modifying the contents of gl.
95897c478bd9Sstevel@tonic-gate  */
95907c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
95917c478bd9Sstevel@tonic-gate     return 1;
95927c478bd9Sstevel@tonic-gate /*
95937c478bd9Sstevel@tonic-gate  * Perform the lookup while signals are blocked.
95947c478bd9Sstevel@tonic-gate  */
95957c478bd9Sstevel@tonic-gate   status = _glh_lookup_history(gl->glh, (GlhLineID) id, &line->line,
95967c478bd9Sstevel@tonic-gate 			       &line->group, &line->timestamp);
95977c478bd9Sstevel@tonic-gate   if(status)
95987c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
95997c478bd9Sstevel@tonic-gate /*
96007c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
96017c478bd9Sstevel@tonic-gate  */
96027c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
96037c478bd9Sstevel@tonic-gate   return status;
96047c478bd9Sstevel@tonic-gate }
96057c478bd9Sstevel@tonic-gate 
96067c478bd9Sstevel@tonic-gate /*.......................................................................
96077c478bd9Sstevel@tonic-gate  * Query the state of the history list. Note that any of the input/output
96087c478bd9Sstevel@tonic-gate  * pointers can be specified as NULL.
96097c478bd9Sstevel@tonic-gate  *
96107c478bd9Sstevel@tonic-gate  * Input:
96117c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of gl_get_line().
96127c478bd9Sstevel@tonic-gate  * Input/Output:
96137c478bd9Sstevel@tonic-gate  *  state  GlHistoryState *  A pointer to the variable in which to record
96147c478bd9Sstevel@tonic-gate  *                           the return values.
96157c478bd9Sstevel@tonic-gate  */
96167c478bd9Sstevel@tonic-gate void gl_state_of_history(GetLine *gl, GlHistoryState *state)
96177c478bd9Sstevel@tonic-gate {
96187c478bd9Sstevel@tonic-gate   if(gl && state) {
96197c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
96207c478bd9Sstevel@tonic-gate /*
96217c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
96227c478bd9Sstevel@tonic-gate  */
96237c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
96247c478bd9Sstevel@tonic-gate /*
96257c478bd9Sstevel@tonic-gate  * Lookup the status while signals are blocked.
96267c478bd9Sstevel@tonic-gate  */
96277c478bd9Sstevel@tonic-gate     _glh_state_of_history(gl->glh, &state->enabled, &state->group,
96287c478bd9Sstevel@tonic-gate 			  &state->max_lines);
96297c478bd9Sstevel@tonic-gate /*
96307c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
96317c478bd9Sstevel@tonic-gate  */
96327c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
96337c478bd9Sstevel@tonic-gate   };
96347c478bd9Sstevel@tonic-gate }
96357c478bd9Sstevel@tonic-gate 
96367c478bd9Sstevel@tonic-gate /*.......................................................................
96377c478bd9Sstevel@tonic-gate  * Query the number and range of lines in the history buffer.
96387c478bd9Sstevel@tonic-gate  *
96397c478bd9Sstevel@tonic-gate  * Input:
96407c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of gl_get_line().
96417c478bd9Sstevel@tonic-gate  *  range  GlHistoryRange *  A pointer to the variable in which to record
96427c478bd9Sstevel@tonic-gate  *                           the return values. If range->nline=0, the
96437c478bd9Sstevel@tonic-gate  *                           range of lines will be given as 0-0.
96447c478bd9Sstevel@tonic-gate  */
96457c478bd9Sstevel@tonic-gate void gl_range_of_history(GetLine *gl, GlHistoryRange *range)
96467c478bd9Sstevel@tonic-gate {
96477c478bd9Sstevel@tonic-gate   if(gl && range) {
96487c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
96497c478bd9Sstevel@tonic-gate /*
96507c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
96517c478bd9Sstevel@tonic-gate  */
96527c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
96537c478bd9Sstevel@tonic-gate /*
96547c478bd9Sstevel@tonic-gate  * Lookup the information while signals are blocked.
96557c478bd9Sstevel@tonic-gate  */
96567c478bd9Sstevel@tonic-gate     _glh_range_of_history(gl->glh, &range->oldest, &range->newest,
96577c478bd9Sstevel@tonic-gate 			  &range->nlines);
96587c478bd9Sstevel@tonic-gate /*
96597c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
96607c478bd9Sstevel@tonic-gate  */
96617c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
96627c478bd9Sstevel@tonic-gate   };
96637c478bd9Sstevel@tonic-gate }
96647c478bd9Sstevel@tonic-gate 
96657c478bd9Sstevel@tonic-gate /*.......................................................................
96667c478bd9Sstevel@tonic-gate  * Return the size of the history buffer and the amount of the
96677c478bd9Sstevel@tonic-gate  * buffer that is currently in use.
96687c478bd9Sstevel@tonic-gate  *
96697c478bd9Sstevel@tonic-gate  * Input:
96707c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The gl_get_line() resource object.
96717c478bd9Sstevel@tonic-gate  * Input/Output:
96727c478bd9Sstevel@tonic-gate  *  GlHistorySize size *  A pointer to the variable in which to return
96737c478bd9Sstevel@tonic-gate  *                        the results.
96747c478bd9Sstevel@tonic-gate  */
96757c478bd9Sstevel@tonic-gate void gl_size_of_history(GetLine *gl, GlHistorySize *size)
96767c478bd9Sstevel@tonic-gate {
96777c478bd9Sstevel@tonic-gate   if(gl && size) {
96787c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
96797c478bd9Sstevel@tonic-gate /*
96807c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
96817c478bd9Sstevel@tonic-gate  */
96827c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
96837c478bd9Sstevel@tonic-gate /*
96847c478bd9Sstevel@tonic-gate  * Lookup the information while signals are blocked.
96857c478bd9Sstevel@tonic-gate  */
96867c478bd9Sstevel@tonic-gate     _glh_size_of_history(gl->glh, &size->size, &size->used);
96877c478bd9Sstevel@tonic-gate /*
96887c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
96897c478bd9Sstevel@tonic-gate  */
96907c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
96917c478bd9Sstevel@tonic-gate   };
96927c478bd9Sstevel@tonic-gate }
96937c478bd9Sstevel@tonic-gate 
96947c478bd9Sstevel@tonic-gate /*.......................................................................
96957c478bd9Sstevel@tonic-gate  * This is the action function that lists the contents of the history
96967c478bd9Sstevel@tonic-gate  * list.
96977c478bd9Sstevel@tonic-gate  */
96987c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_history)
96997c478bd9Sstevel@tonic-gate {
97007c478bd9Sstevel@tonic-gate /*
97017c478bd9Sstevel@tonic-gate  * Start a new line.
97027c478bd9Sstevel@tonic-gate  */
97037c478bd9Sstevel@tonic-gate   if(gl_start_newline(gl, 1))
97047c478bd9Sstevel@tonic-gate     return 1;
97057c478bd9Sstevel@tonic-gate /*
97067c478bd9Sstevel@tonic-gate  * List history lines that belong to the current group.
97077c478bd9Sstevel@tonic-gate  */
97087c478bd9Sstevel@tonic-gate   _glh_show_history(gl->glh, gl_write_fn, gl, "%N  %T   %H\r\n", 0,
97097c478bd9Sstevel@tonic-gate 		    count<=1 ? -1 : count);
97107c478bd9Sstevel@tonic-gate /*
97117c478bd9Sstevel@tonic-gate  * Arrange for the input line to be redisplayed.
97127c478bd9Sstevel@tonic-gate  */
97137c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
97147c478bd9Sstevel@tonic-gate   return 0;
97157c478bd9Sstevel@tonic-gate }
97167c478bd9Sstevel@tonic-gate 
97177c478bd9Sstevel@tonic-gate /*.......................................................................
97187c478bd9Sstevel@tonic-gate  * Specify whether text that users type should be displayed or hidden.
97197c478bd9Sstevel@tonic-gate  * In the latter case, only the prompt is displayed, and the final
97207c478bd9Sstevel@tonic-gate  * input line is not archived in the history list.
97217c478bd9Sstevel@tonic-gate  *
97227c478bd9Sstevel@tonic-gate  * Input:
97237c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The gl_get_line() resource object.
97247c478bd9Sstevel@tonic-gate  *  enable         int     0 - Disable echoing.
97257c478bd9Sstevel@tonic-gate  *                         1 - Enable echoing.
97267c478bd9Sstevel@tonic-gate  *                        -1 - Just query the mode without changing it.
97277c478bd9Sstevel@tonic-gate  * Output:
97287c478bd9Sstevel@tonic-gate  *  return         int    The echoing disposition that was in effect
97297c478bd9Sstevel@tonic-gate  *                        before this function was called:
97307c478bd9Sstevel@tonic-gate  *                         0 - Echoing was disabled.
97317c478bd9Sstevel@tonic-gate  *                         1 - Echoing was enabled.
97327c478bd9Sstevel@tonic-gate  */
97337c478bd9Sstevel@tonic-gate int gl_echo_mode(GetLine *gl, int enable)
97347c478bd9Sstevel@tonic-gate {
97357c478bd9Sstevel@tonic-gate   if(gl) {
97367c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
97377c478bd9Sstevel@tonic-gate     int was_echoing; /* The echoing disposition on entry to this function */
97387c478bd9Sstevel@tonic-gate /*
97397c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
97407c478bd9Sstevel@tonic-gate  */
97417c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
97427c478bd9Sstevel@tonic-gate /*
97437c478bd9Sstevel@tonic-gate  * Install the new disposition while signals are blocked.
97447c478bd9Sstevel@tonic-gate  */
97457c478bd9Sstevel@tonic-gate     was_echoing = gl->echo;
97467c478bd9Sstevel@tonic-gate     if(enable >= 0)
97477c478bd9Sstevel@tonic-gate       gl->echo = enable;
97487c478bd9Sstevel@tonic-gate /*
97497c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
97507c478bd9Sstevel@tonic-gate  */
97517c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
97527c478bd9Sstevel@tonic-gate /*
97537c478bd9Sstevel@tonic-gate  * Return the original echoing disposition.
97547c478bd9Sstevel@tonic-gate  */
97557c478bd9Sstevel@tonic-gate     return was_echoing;
97567c478bd9Sstevel@tonic-gate   };
97577c478bd9Sstevel@tonic-gate   return 1;
97587c478bd9Sstevel@tonic-gate }
97597c478bd9Sstevel@tonic-gate 
97607c478bd9Sstevel@tonic-gate /*.......................................................................
97617c478bd9Sstevel@tonic-gate  * Display the prompt.
97627c478bd9Sstevel@tonic-gate  *
97637c478bd9Sstevel@tonic-gate  * Input:
97647c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
97657c478bd9Sstevel@tonic-gate  * Output:
97667c478bd9Sstevel@tonic-gate  *  return         int    0 - OK.
97677c478bd9Sstevel@tonic-gate  *                        1 - Error.
97687c478bd9Sstevel@tonic-gate  */
97697c478bd9Sstevel@tonic-gate static int gl_display_prompt(GetLine *gl)
97707c478bd9Sstevel@tonic-gate {
97717c478bd9Sstevel@tonic-gate   const char *pptr;       /* A pointer into gl->prompt[] */
97727c478bd9Sstevel@tonic-gate   unsigned old_attr=0;    /* The current text display attributes */
97737c478bd9Sstevel@tonic-gate   unsigned new_attr=0;    /* The requested text display attributes */
97747c478bd9Sstevel@tonic-gate /*
97757c478bd9Sstevel@tonic-gate  * Temporarily switch to echoing output characters.
97767c478bd9Sstevel@tonic-gate  */
97777c478bd9Sstevel@tonic-gate   int kept_echo = gl->echo;
97787c478bd9Sstevel@tonic-gate   gl->echo = 1;
97797c478bd9Sstevel@tonic-gate /*
97807c478bd9Sstevel@tonic-gate  * In case the screen got messed up, send a carriage return to
97817c478bd9Sstevel@tonic-gate  * put the cursor at the beginning of the current terminal line.
97827c478bd9Sstevel@tonic-gate  */
97837c478bd9Sstevel@tonic-gate   if(gl_print_control_sequence(gl, 1, gl->bol))
97847c478bd9Sstevel@tonic-gate     return 1;
97857c478bd9Sstevel@tonic-gate /*
97867c478bd9Sstevel@tonic-gate  * Mark the line as partially displayed.
97877c478bd9Sstevel@tonic-gate  */
97887c478bd9Sstevel@tonic-gate   gl->displayed = 1;
97897c478bd9Sstevel@tonic-gate /*
97907c478bd9Sstevel@tonic-gate  * Write the prompt, using the currently selected prompt style.
97917c478bd9Sstevel@tonic-gate  */
97927c478bd9Sstevel@tonic-gate   switch(gl->prompt_style) {
97937c478bd9Sstevel@tonic-gate   case GL_LITERAL_PROMPT:
97947c478bd9Sstevel@tonic-gate     if(gl_print_string(gl, gl->prompt, '\0'))
97957c478bd9Sstevel@tonic-gate       return 1;
97967c478bd9Sstevel@tonic-gate     break;
97977c478bd9Sstevel@tonic-gate   case GL_FORMAT_PROMPT:
97987c478bd9Sstevel@tonic-gate     for(pptr=gl->prompt; *pptr; pptr++) {
97997c478bd9Sstevel@tonic-gate /*
98007c478bd9Sstevel@tonic-gate  * Does the latest character appear to be the start of a directive?
98017c478bd9Sstevel@tonic-gate  */
98027c478bd9Sstevel@tonic-gate       if(*pptr == '%') {
98037c478bd9Sstevel@tonic-gate /*
98047c478bd9Sstevel@tonic-gate  * Check for and act on attribute changing directives.
98057c478bd9Sstevel@tonic-gate  */
98067c478bd9Sstevel@tonic-gate 	switch(pptr[1]) {
98077c478bd9Sstevel@tonic-gate /*
98087c478bd9Sstevel@tonic-gate  * Add or remove a text attribute from the new set of attributes.
98097c478bd9Sstevel@tonic-gate  */
98107c478bd9Sstevel@tonic-gate 	case 'B': case 'U': case 'S': case 'P': case 'F': case 'V':
98117c478bd9Sstevel@tonic-gate 	case 'b': case 'u': case 's': case 'p': case 'f': case 'v':
98127c478bd9Sstevel@tonic-gate 	  switch(*++pptr) {
98137c478bd9Sstevel@tonic-gate 	  case 'B':           /* Switch to a bold font */
98147c478bd9Sstevel@tonic-gate 	    new_attr |= GL_TXT_BOLD;
98157c478bd9Sstevel@tonic-gate 	    break;
98167c478bd9Sstevel@tonic-gate 	  case 'b':           /* Switch to a non-bold font */
98177c478bd9Sstevel@tonic-gate 	    new_attr &= ~GL_TXT_BOLD;
98187c478bd9Sstevel@tonic-gate 	    break;
98197c478bd9Sstevel@tonic-gate 	  case 'U':           /* Start underlining */
98207c478bd9Sstevel@tonic-gate 	    new_attr |= GL_TXT_UNDERLINE;
98217c478bd9Sstevel@tonic-gate 	    break;
98227c478bd9Sstevel@tonic-gate 	  case 'u':           /* Stop underlining */
98237c478bd9Sstevel@tonic-gate 	    new_attr &= ~GL_TXT_UNDERLINE;
98247c478bd9Sstevel@tonic-gate 	    break;
98257c478bd9Sstevel@tonic-gate 	  case 'S':           /* Start highlighting */
98267c478bd9Sstevel@tonic-gate 	    new_attr |= GL_TXT_STANDOUT;
98277c478bd9Sstevel@tonic-gate 	    break;
98287c478bd9Sstevel@tonic-gate 	  case 's':           /* Stop highlighting */
98297c478bd9Sstevel@tonic-gate 	    new_attr &= ~GL_TXT_STANDOUT;
98307c478bd9Sstevel@tonic-gate 	    break;
98317c478bd9Sstevel@tonic-gate 	  case 'P':           /* Switch to a pale font */
98327c478bd9Sstevel@tonic-gate 	    new_attr |= GL_TXT_DIM;
98337c478bd9Sstevel@tonic-gate 	    break;
98347c478bd9Sstevel@tonic-gate 	  case 'p':           /* Switch to a non-pale font */
98357c478bd9Sstevel@tonic-gate 	    new_attr &= ~GL_TXT_DIM;
98367c478bd9Sstevel@tonic-gate 	    break;
98377c478bd9Sstevel@tonic-gate 	  case 'F':           /* Switch to a flashing font */
98387c478bd9Sstevel@tonic-gate 	    new_attr |= GL_TXT_BLINK;
98397c478bd9Sstevel@tonic-gate 	    break;
98407c478bd9Sstevel@tonic-gate 	  case 'f':           /* Switch to a steady font */
98417c478bd9Sstevel@tonic-gate 	    new_attr &= ~GL_TXT_BLINK;
98427c478bd9Sstevel@tonic-gate 	    break;
98437c478bd9Sstevel@tonic-gate 	  case 'V':           /* Switch to reverse video */
98447c478bd9Sstevel@tonic-gate 	    new_attr |= GL_TXT_REVERSE;
98457c478bd9Sstevel@tonic-gate 	    break;
98467c478bd9Sstevel@tonic-gate 	  case 'v':           /* Switch out of reverse video */
98477c478bd9Sstevel@tonic-gate 	    new_attr &= ~GL_TXT_REVERSE;
98487c478bd9Sstevel@tonic-gate 	    break;
98497c478bd9Sstevel@tonic-gate 	  };
98507c478bd9Sstevel@tonic-gate 	  continue;
98517c478bd9Sstevel@tonic-gate /*
98527c478bd9Sstevel@tonic-gate  * A literal % is represented by %%. Skip the leading %.
98537c478bd9Sstevel@tonic-gate  */
98547c478bd9Sstevel@tonic-gate 	case '%':
98557c478bd9Sstevel@tonic-gate 	  pptr++;
98567c478bd9Sstevel@tonic-gate 	  break;
98577c478bd9Sstevel@tonic-gate 	};
98587c478bd9Sstevel@tonic-gate       };
98597c478bd9Sstevel@tonic-gate /*
98607c478bd9Sstevel@tonic-gate  * Many terminals, when asked to turn off a single text attribute, turn
98617c478bd9Sstevel@tonic-gate  * them all off, so the portable way to turn one off individually is to
98627c478bd9Sstevel@tonic-gate  * explicitly turn them all off, then specify those that we want from
98637c478bd9Sstevel@tonic-gate  * scratch.
98647c478bd9Sstevel@tonic-gate  */
98657c478bd9Sstevel@tonic-gate       if(old_attr & ~new_attr) {
98667c478bd9Sstevel@tonic-gate 	if(gl_print_control_sequence(gl, 1, gl->text_attr_off))
98677c478bd9Sstevel@tonic-gate 	  return 1;
98687c478bd9Sstevel@tonic-gate 	old_attr = 0;
98697c478bd9Sstevel@tonic-gate       };
98707c478bd9Sstevel@tonic-gate /*
98717c478bd9Sstevel@tonic-gate  * Install new text attributes?
98727c478bd9Sstevel@tonic-gate  */
98737c478bd9Sstevel@tonic-gate       if(new_attr != old_attr) {
98747c478bd9Sstevel@tonic-gate 	if(new_attr & GL_TXT_BOLD && !(old_attr & GL_TXT_BOLD) &&
98757c478bd9Sstevel@tonic-gate 	   gl_print_control_sequence(gl, 1, gl->bold))
98767c478bd9Sstevel@tonic-gate 	  return 1;
98777c478bd9Sstevel@tonic-gate 	if(new_attr & GL_TXT_UNDERLINE && !(old_attr & GL_TXT_UNDERLINE) &&
98787c478bd9Sstevel@tonic-gate 	   gl_print_control_sequence(gl, 1, gl->underline))
98797c478bd9Sstevel@tonic-gate 	  return 1;
98807c478bd9Sstevel@tonic-gate 	if(new_attr & GL_TXT_STANDOUT && !(old_attr & GL_TXT_STANDOUT) &&
98817c478bd9Sstevel@tonic-gate 	   gl_print_control_sequence(gl, 1, gl->standout))
98827c478bd9Sstevel@tonic-gate 	  return 1;
98837c478bd9Sstevel@tonic-gate 	if(new_attr & GL_TXT_DIM && !(old_attr & GL_TXT_DIM) &&
98847c478bd9Sstevel@tonic-gate 	   gl_print_control_sequence(gl, 1, gl->dim))
98857c478bd9Sstevel@tonic-gate 	  return 1;
98867c478bd9Sstevel@tonic-gate 	if(new_attr & GL_TXT_REVERSE && !(old_attr & GL_TXT_REVERSE) &&
98877c478bd9Sstevel@tonic-gate 	   gl_print_control_sequence(gl, 1, gl->reverse))
98887c478bd9Sstevel@tonic-gate 	  return 1;
98897c478bd9Sstevel@tonic-gate 	if(new_attr & GL_TXT_BLINK && !(old_attr & GL_TXT_BLINK) &&
98907c478bd9Sstevel@tonic-gate 	   gl_print_control_sequence(gl, 1, gl->blink))
98917c478bd9Sstevel@tonic-gate 	  return 1;
98927c478bd9Sstevel@tonic-gate 	old_attr = new_attr;
98937c478bd9Sstevel@tonic-gate       };
98947c478bd9Sstevel@tonic-gate /*
98957c478bd9Sstevel@tonic-gate  * Display the latest character.
98967c478bd9Sstevel@tonic-gate  */
98977c478bd9Sstevel@tonic-gate       if(gl_print_char(gl, *pptr, pptr[1]))
98987c478bd9Sstevel@tonic-gate 	return 1;
98997c478bd9Sstevel@tonic-gate     };
99007c478bd9Sstevel@tonic-gate /*
99017c478bd9Sstevel@tonic-gate  * Turn off all text attributes now that we have finished drawing
99027c478bd9Sstevel@tonic-gate  * the prompt.
99037c478bd9Sstevel@tonic-gate  */
99047c478bd9Sstevel@tonic-gate     if(gl_print_control_sequence(gl, 1, gl->text_attr_off))
99057c478bd9Sstevel@tonic-gate       return 1;
99067c478bd9Sstevel@tonic-gate     break;
99077c478bd9Sstevel@tonic-gate   };
99087c478bd9Sstevel@tonic-gate /*
99097c478bd9Sstevel@tonic-gate  * Restore the original echo mode.
99107c478bd9Sstevel@tonic-gate  */
99117c478bd9Sstevel@tonic-gate   gl->echo = kept_echo;
99127c478bd9Sstevel@tonic-gate /*
99137c478bd9Sstevel@tonic-gate  * The prompt has now been displayed at least once.
99147c478bd9Sstevel@tonic-gate  */
99157c478bd9Sstevel@tonic-gate   gl->prompt_changed = 0;
99167c478bd9Sstevel@tonic-gate   return 0;
99177c478bd9Sstevel@tonic-gate }
99187c478bd9Sstevel@tonic-gate 
99197c478bd9Sstevel@tonic-gate /*.......................................................................
99207c478bd9Sstevel@tonic-gate  * This function can be called from gl_get_line() callbacks to have
99217c478bd9Sstevel@tonic-gate  * the prompt changed when they return. It has no effect if gl_get_line()
99227c478bd9Sstevel@tonic-gate  * is not currently being invoked.
99237c478bd9Sstevel@tonic-gate  *
99247c478bd9Sstevel@tonic-gate  * Input:
99257c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
99267c478bd9Sstevel@tonic-gate  *  prompt  const char *  The new prompt.
99277c478bd9Sstevel@tonic-gate  */
99287c478bd9Sstevel@tonic-gate void gl_replace_prompt(GetLine *gl, const char *prompt)
99297c478bd9Sstevel@tonic-gate {
99307c478bd9Sstevel@tonic-gate   if(gl) {
99317c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
99327c478bd9Sstevel@tonic-gate /*
99337c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
99347c478bd9Sstevel@tonic-gate  */
99357c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
99367c478bd9Sstevel@tonic-gate /*
99377c478bd9Sstevel@tonic-gate  * Replace the prompt.
99387c478bd9Sstevel@tonic-gate  */
99397c478bd9Sstevel@tonic-gate     _gl_replace_prompt(gl, prompt);
99407c478bd9Sstevel@tonic-gate /*
99417c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
99427c478bd9Sstevel@tonic-gate  */
99437c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
99447c478bd9Sstevel@tonic-gate   };
99457c478bd9Sstevel@tonic-gate }
99467c478bd9Sstevel@tonic-gate 
99477c478bd9Sstevel@tonic-gate /*.......................................................................
99487c478bd9Sstevel@tonic-gate  * This is the private body of the gl_replace_prompt() function. It
99497c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
99507c478bd9Sstevel@tonic-gate  * delivery of signals.
99517c478bd9Sstevel@tonic-gate  */
99527c478bd9Sstevel@tonic-gate static void _gl_replace_prompt(GetLine *gl, const char *prompt)
99537c478bd9Sstevel@tonic-gate {
99547c478bd9Sstevel@tonic-gate   size_t size;
99557c478bd9Sstevel@tonic-gate 
99567c478bd9Sstevel@tonic-gate /*
99577c478bd9Sstevel@tonic-gate  * Substitute an empty prompt?
99587c478bd9Sstevel@tonic-gate  */
99597c478bd9Sstevel@tonic-gate   if(!prompt)
99607c478bd9Sstevel@tonic-gate     prompt = "";
99617c478bd9Sstevel@tonic-gate /*
99627c478bd9Sstevel@tonic-gate  * Gaurd against aliasing between prompt and gl->prompt.
99637c478bd9Sstevel@tonic-gate  */
99647c478bd9Sstevel@tonic-gate   if(gl->prompt != prompt) {
99657c478bd9Sstevel@tonic-gate /*
99667c478bd9Sstevel@tonic-gate  * Get the length of the new prompt string.
99677c478bd9Sstevel@tonic-gate  */
99687c478bd9Sstevel@tonic-gate     size_t slen = strlen(prompt);
99697c478bd9Sstevel@tonic-gate /*
99707c478bd9Sstevel@tonic-gate  * If needed, allocate a new buffer for the prompt string.
99717c478bd9Sstevel@tonic-gate  */
99727c478bd9Sstevel@tonic-gate     size = sizeof(char) * (slen + 1);
99737c478bd9Sstevel@tonic-gate     if(!gl->prompt || slen > strlen(gl->prompt)) {
99747c478bd9Sstevel@tonic-gate       char *new_prompt = gl->prompt ? realloc(gl->prompt, size) : malloc(size);
99757c478bd9Sstevel@tonic-gate       if(!new_prompt)
99767c478bd9Sstevel@tonic-gate 	return;
99777c478bd9Sstevel@tonic-gate       gl->prompt = new_prompt;
99787c478bd9Sstevel@tonic-gate     };
99797c478bd9Sstevel@tonic-gate /*
99807c478bd9Sstevel@tonic-gate  * Make a copy of the new prompt.
99817c478bd9Sstevel@tonic-gate  */
99827c478bd9Sstevel@tonic-gate     strlcpy(gl->prompt, prompt, size);
99837c478bd9Sstevel@tonic-gate   };
99847c478bd9Sstevel@tonic-gate /*
99857c478bd9Sstevel@tonic-gate  * Record the statistics of the new prompt.
99867c478bd9Sstevel@tonic-gate  */
99877c478bd9Sstevel@tonic-gate   gl->prompt_len = gl_displayed_prompt_width(gl);
99887c478bd9Sstevel@tonic-gate   gl->prompt_changed = 1;
99897c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
99907c478bd9Sstevel@tonic-gate   return;
99917c478bd9Sstevel@tonic-gate }
99927c478bd9Sstevel@tonic-gate 
99937c478bd9Sstevel@tonic-gate /*.......................................................................
99947c478bd9Sstevel@tonic-gate  * Work out the length of the current prompt on the terminal, according
99957c478bd9Sstevel@tonic-gate  * to the current prompt formatting style.
99967c478bd9Sstevel@tonic-gate  *
99977c478bd9Sstevel@tonic-gate  * Input:
99987c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The resource object of this library.
99997c478bd9Sstevel@tonic-gate  * Output:
100007c478bd9Sstevel@tonic-gate  *  return       int    The number of displayed characters.
100017c478bd9Sstevel@tonic-gate  */
100027c478bd9Sstevel@tonic-gate static int gl_displayed_prompt_width(GetLine *gl)
100037c478bd9Sstevel@tonic-gate {
100047c478bd9Sstevel@tonic-gate   int slen=0;         /* The displayed number of characters */
100057c478bd9Sstevel@tonic-gate   const char *pptr;   /* A pointer into prompt[] */
100067c478bd9Sstevel@tonic-gate /*
100077c478bd9Sstevel@tonic-gate  * The length differs according to the prompt display style.
100087c478bd9Sstevel@tonic-gate  */
100097c478bd9Sstevel@tonic-gate   switch(gl->prompt_style) {
100107c478bd9Sstevel@tonic-gate   case GL_LITERAL_PROMPT:
100117c478bd9Sstevel@tonic-gate     return gl_displayed_string_width(gl, gl->prompt, -1, 0);
100127c478bd9Sstevel@tonic-gate     break;
100137c478bd9Sstevel@tonic-gate   case GL_FORMAT_PROMPT:
100147c478bd9Sstevel@tonic-gate /*
100157c478bd9Sstevel@tonic-gate  * Add up the length of the displayed string, while filtering out
100167c478bd9Sstevel@tonic-gate  * attribute directives.
100177c478bd9Sstevel@tonic-gate  */
100187c478bd9Sstevel@tonic-gate     for(pptr=gl->prompt; *pptr; pptr++) {
100197c478bd9Sstevel@tonic-gate /*
100207c478bd9Sstevel@tonic-gate  * Does the latest character appear to be the start of a directive?
100217c478bd9Sstevel@tonic-gate  */
100227c478bd9Sstevel@tonic-gate       if(*pptr == '%') {
100237c478bd9Sstevel@tonic-gate /*
100247c478bd9Sstevel@tonic-gate  * Check for and skip attribute changing directives.
100257c478bd9Sstevel@tonic-gate  */
100267c478bd9Sstevel@tonic-gate 	switch(pptr[1]) {
100277c478bd9Sstevel@tonic-gate 	case 'B': case 'b': case 'U': case 'u': case 'S': case 's':
100287c478bd9Sstevel@tonic-gate 	  pptr++;
100297c478bd9Sstevel@tonic-gate 	  continue;
100307c478bd9Sstevel@tonic-gate /*
100317c478bd9Sstevel@tonic-gate  * A literal % is represented by %%. Skip the leading %.
100327c478bd9Sstevel@tonic-gate  */
100337c478bd9Sstevel@tonic-gate 	case '%':
100347c478bd9Sstevel@tonic-gate 	  pptr++;
100357c478bd9Sstevel@tonic-gate 	  break;
100367c478bd9Sstevel@tonic-gate 	};
100377c478bd9Sstevel@tonic-gate       };
100387c478bd9Sstevel@tonic-gate       slen += gl_displayed_char_width(gl, *pptr, slen);
100397c478bd9Sstevel@tonic-gate     };
100407c478bd9Sstevel@tonic-gate     break;
100417c478bd9Sstevel@tonic-gate   };
100427c478bd9Sstevel@tonic-gate   return slen;
100437c478bd9Sstevel@tonic-gate }
100447c478bd9Sstevel@tonic-gate 
100457c478bd9Sstevel@tonic-gate /*.......................................................................
100467c478bd9Sstevel@tonic-gate  * Specify whether to heed text attribute directives within prompt
100477c478bd9Sstevel@tonic-gate  * strings.
100487c478bd9Sstevel@tonic-gate  *
100497c478bd9Sstevel@tonic-gate  * Input:
100507c478bd9Sstevel@tonic-gate  *  gl           GetLine *  The resource object of gl_get_line().
100517c478bd9Sstevel@tonic-gate  *  style  GlPromptStyle    The style of prompt (see the definition of
100527c478bd9Sstevel@tonic-gate  *                          GlPromptStyle in libtecla.h for details).
100537c478bd9Sstevel@tonic-gate  */
100547c478bd9Sstevel@tonic-gate void gl_prompt_style(GetLine *gl, GlPromptStyle style)
100557c478bd9Sstevel@tonic-gate {
100567c478bd9Sstevel@tonic-gate   if(gl) {
100577c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
100587c478bd9Sstevel@tonic-gate /*
100597c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
100607c478bd9Sstevel@tonic-gate  */
100617c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
100627c478bd9Sstevel@tonic-gate /*
100637c478bd9Sstevel@tonic-gate  * Install the new style in gl while signals are blocked.
100647c478bd9Sstevel@tonic-gate  */
100657c478bd9Sstevel@tonic-gate     if(style != gl->prompt_style) {
100667c478bd9Sstevel@tonic-gate       gl->prompt_style = style;
100677c478bd9Sstevel@tonic-gate       gl->prompt_len = gl_displayed_prompt_width(gl);
100687c478bd9Sstevel@tonic-gate       gl->prompt_changed = 1;
100697c478bd9Sstevel@tonic-gate       gl_queue_redisplay(gl);
100707c478bd9Sstevel@tonic-gate     };
100717c478bd9Sstevel@tonic-gate /*
100727c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
100737c478bd9Sstevel@tonic-gate  */
100747c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
100757c478bd9Sstevel@tonic-gate   };
100767c478bd9Sstevel@tonic-gate }
100777c478bd9Sstevel@tonic-gate 
100787c478bd9Sstevel@tonic-gate /*.......................................................................
100797c478bd9Sstevel@tonic-gate  * Tell gl_get_line() how to respond to a given signal. This can be used
100807c478bd9Sstevel@tonic-gate  * both to override the default responses to signals that gl_get_line()
100817c478bd9Sstevel@tonic-gate  * normally catches and to add new signals to the list that are to be
100827c478bd9Sstevel@tonic-gate  * caught.
100837c478bd9Sstevel@tonic-gate  *
100847c478bd9Sstevel@tonic-gate  * Input:
100857c478bd9Sstevel@tonic-gate  *  gl           GetLine *  The resource object of gl_get_line().
100867c478bd9Sstevel@tonic-gate  *  signo            int    The number of the signal to be caught.
100877c478bd9Sstevel@tonic-gate  *  flags       unsigned    A bitwise union of GlSignalFlags enumerators.
100887c478bd9Sstevel@tonic-gate  *  after  GlAfterSignal    What to do after the application's signal
100897c478bd9Sstevel@tonic-gate  *                          handler has been called.
100907c478bd9Sstevel@tonic-gate  *  errno_value      int    The value to set errno to.
100917c478bd9Sstevel@tonic-gate  * Output:
100927c478bd9Sstevel@tonic-gate  *  return           int    0 - OK.
100937c478bd9Sstevel@tonic-gate  *                          1 - Error.
100947c478bd9Sstevel@tonic-gate  */
100957c478bd9Sstevel@tonic-gate int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
100967c478bd9Sstevel@tonic-gate 		   GlAfterSignal after, int errno_value)
100977c478bd9Sstevel@tonic-gate {
100987c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
100997c478bd9Sstevel@tonic-gate   int status;      /* The return status of this function */
101007c478bd9Sstevel@tonic-gate /*
101017c478bd9Sstevel@tonic-gate  * Check the arguments.
101027c478bd9Sstevel@tonic-gate  */
101037c478bd9Sstevel@tonic-gate   if(!gl) {
101047c478bd9Sstevel@tonic-gate     errno = EINVAL;
101057c478bd9Sstevel@tonic-gate     return 1;
101067c478bd9Sstevel@tonic-gate   };
101077c478bd9Sstevel@tonic-gate /*
101087c478bd9Sstevel@tonic-gate  * Block all signals while modifying the contents of gl.
101097c478bd9Sstevel@tonic-gate  */
101107c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
101117c478bd9Sstevel@tonic-gate     return 1;
101127c478bd9Sstevel@tonic-gate /*
101137c478bd9Sstevel@tonic-gate  * Perform the modification while signals are blocked.
101147c478bd9Sstevel@tonic-gate  */
101157c478bd9Sstevel@tonic-gate   status = _gl_trap_signal(gl, signo, flags, after, errno_value);
101167c478bd9Sstevel@tonic-gate /*
101177c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
101187c478bd9Sstevel@tonic-gate  */
101197c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
101207c478bd9Sstevel@tonic-gate   return status;
101217c478bd9Sstevel@tonic-gate }
101227c478bd9Sstevel@tonic-gate 
101237c478bd9Sstevel@tonic-gate /*.......................................................................
101247c478bd9Sstevel@tonic-gate  * This is the private body of the gl_trap_signal() function. It
101257c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
101267c478bd9Sstevel@tonic-gate  * delivery of signals.
101277c478bd9Sstevel@tonic-gate  */
101287c478bd9Sstevel@tonic-gate static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags,
101297c478bd9Sstevel@tonic-gate 			   GlAfterSignal after, int errno_value)
101307c478bd9Sstevel@tonic-gate {
101317c478bd9Sstevel@tonic-gate   GlSignalNode *sig;
101327c478bd9Sstevel@tonic-gate /*
101337c478bd9Sstevel@tonic-gate  * Complain if an attempt is made to trap untrappable signals.
101347c478bd9Sstevel@tonic-gate  * These would otherwise cause errors later in gl_mask_signals().
101357c478bd9Sstevel@tonic-gate  */
101367c478bd9Sstevel@tonic-gate   if(0
101377c478bd9Sstevel@tonic-gate #ifdef SIGKILL
101387c478bd9Sstevel@tonic-gate      || signo==SIGKILL
101397c478bd9Sstevel@tonic-gate #endif
101407c478bd9Sstevel@tonic-gate #ifdef SIGBLOCK
101417c478bd9Sstevel@tonic-gate      || signo==SIGBLOCK
101427c478bd9Sstevel@tonic-gate #endif
101437c478bd9Sstevel@tonic-gate      ) {
101447c478bd9Sstevel@tonic-gate     return 1;
101457c478bd9Sstevel@tonic-gate   };
101467c478bd9Sstevel@tonic-gate /*
101477c478bd9Sstevel@tonic-gate  * See if the signal has already been registered.
101487c478bd9Sstevel@tonic-gate  */
101497c478bd9Sstevel@tonic-gate   for(sig=gl->sigs; sig && sig->signo != signo; sig = sig->next)
101507c478bd9Sstevel@tonic-gate     ;
101517c478bd9Sstevel@tonic-gate /*
101527c478bd9Sstevel@tonic-gate  * If the signal hasn't already been registered, allocate a node for
101537c478bd9Sstevel@tonic-gate  * it.
101547c478bd9Sstevel@tonic-gate  */
101557c478bd9Sstevel@tonic-gate   if(!sig) {
101567c478bd9Sstevel@tonic-gate     sig = (GlSignalNode *) _new_FreeListNode(gl->sig_mem);
101577c478bd9Sstevel@tonic-gate     if(!sig)
101587c478bd9Sstevel@tonic-gate       return 1;
101597c478bd9Sstevel@tonic-gate /*
101607c478bd9Sstevel@tonic-gate  * Add the new node to the head of the list.
101617c478bd9Sstevel@tonic-gate  */
101627c478bd9Sstevel@tonic-gate     sig->next = gl->sigs;
101637c478bd9Sstevel@tonic-gate     gl->sigs = sig;
101647c478bd9Sstevel@tonic-gate /*
101657c478bd9Sstevel@tonic-gate  * Record the signal number.
101667c478bd9Sstevel@tonic-gate  */
101677c478bd9Sstevel@tonic-gate     sig->signo = signo;
101687c478bd9Sstevel@tonic-gate /*
101697c478bd9Sstevel@tonic-gate  * Create a signal set that includes just this signal.
101707c478bd9Sstevel@tonic-gate  */
101717c478bd9Sstevel@tonic-gate     sigemptyset(&sig->proc_mask);
101727c478bd9Sstevel@tonic-gate     if(sigaddset(&sig->proc_mask, signo) == -1) {
101737c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG);
101747c478bd9Sstevel@tonic-gate       sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig);
101757c478bd9Sstevel@tonic-gate       return 1;
101767c478bd9Sstevel@tonic-gate     };
101777c478bd9Sstevel@tonic-gate /*
101787c478bd9Sstevel@tonic-gate  * Add the signal to the bit-mask of signals being trapped.
101797c478bd9Sstevel@tonic-gate  */
101807c478bd9Sstevel@tonic-gate     sigaddset(&gl->all_signal_set, signo);
101817c478bd9Sstevel@tonic-gate   };
101827c478bd9Sstevel@tonic-gate /*
101837c478bd9Sstevel@tonic-gate  * Record the new signal attributes.
101847c478bd9Sstevel@tonic-gate  */
101857c478bd9Sstevel@tonic-gate   sig->flags = flags;
101867c478bd9Sstevel@tonic-gate   sig->after = after;
101877c478bd9Sstevel@tonic-gate   sig->errno_value = errno_value;
101887c478bd9Sstevel@tonic-gate   return 0;
101897c478bd9Sstevel@tonic-gate }
101907c478bd9Sstevel@tonic-gate 
101917c478bd9Sstevel@tonic-gate /*.......................................................................
101927c478bd9Sstevel@tonic-gate  * Remove a signal from the list of signals that gl_get_line() traps.
101937c478bd9Sstevel@tonic-gate  *
101947c478bd9Sstevel@tonic-gate  * Input:
101957c478bd9Sstevel@tonic-gate  *  gl           GetLine *  The resource object of gl_get_line().
101967c478bd9Sstevel@tonic-gate  *  signo            int    The number of the signal to be ignored.
101977c478bd9Sstevel@tonic-gate  * Output:
101987c478bd9Sstevel@tonic-gate  *  return           int    0 - OK.
101997c478bd9Sstevel@tonic-gate  *                          1 - Error.
102007c478bd9Sstevel@tonic-gate  */
102017c478bd9Sstevel@tonic-gate int gl_ignore_signal(GetLine *gl, int signo)
102027c478bd9Sstevel@tonic-gate {
102037c478bd9Sstevel@tonic-gate   GlSignalNode *sig;  /* The gl->sigs list node of the specified signal */
102047c478bd9Sstevel@tonic-gate   GlSignalNode *prev; /* The node that precedes sig in the list */
102057c478bd9Sstevel@tonic-gate   sigset_t oldset;    /* The signals that were blocked on entry to this */
102067c478bd9Sstevel@tonic-gate                       /*  function. */
102077c478bd9Sstevel@tonic-gate /*
102087c478bd9Sstevel@tonic-gate  * Check the arguments.
102097c478bd9Sstevel@tonic-gate  */
102107c478bd9Sstevel@tonic-gate   if(!gl) {
102117c478bd9Sstevel@tonic-gate     errno = EINVAL;
102127c478bd9Sstevel@tonic-gate     return 1;
102137c478bd9Sstevel@tonic-gate   };
102147c478bd9Sstevel@tonic-gate /*
102157c478bd9Sstevel@tonic-gate  * Block all signals while modifying the contents of gl.
102167c478bd9Sstevel@tonic-gate  */
102177c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
102187c478bd9Sstevel@tonic-gate     return 1;
102197c478bd9Sstevel@tonic-gate /*
102207c478bd9Sstevel@tonic-gate  * Find the node of the gl->sigs list which records the disposition
102217c478bd9Sstevel@tonic-gate  * of the specified signal.
102227c478bd9Sstevel@tonic-gate  */
102237c478bd9Sstevel@tonic-gate   for(prev=NULL,sig=gl->sigs; sig && sig->signo != signo;
102247c478bd9Sstevel@tonic-gate       prev=sig,sig=sig->next)
102257c478bd9Sstevel@tonic-gate     ;
102267c478bd9Sstevel@tonic-gate   if(sig) {
102277c478bd9Sstevel@tonic-gate /*
102287c478bd9Sstevel@tonic-gate  * Remove the node from the list.
102297c478bd9Sstevel@tonic-gate  */
102307c478bd9Sstevel@tonic-gate     if(prev)
102317c478bd9Sstevel@tonic-gate       prev->next = sig->next;
102327c478bd9Sstevel@tonic-gate     else
102337c478bd9Sstevel@tonic-gate       gl->sigs = sig->next;
102347c478bd9Sstevel@tonic-gate /*
102357c478bd9Sstevel@tonic-gate  * Return the node to the freelist.
102367c478bd9Sstevel@tonic-gate  */
102377c478bd9Sstevel@tonic-gate     sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig);
102387c478bd9Sstevel@tonic-gate /*
102397c478bd9Sstevel@tonic-gate  * Remove the signal from the bit-mask union of signals being trapped.
102407c478bd9Sstevel@tonic-gate  */
102417c478bd9Sstevel@tonic-gate     sigdelset(&gl->all_signal_set, signo);
102427c478bd9Sstevel@tonic-gate   };
102437c478bd9Sstevel@tonic-gate /*
102447c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
102457c478bd9Sstevel@tonic-gate  */
102467c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
102477c478bd9Sstevel@tonic-gate   return 0;
102487c478bd9Sstevel@tonic-gate }
102497c478bd9Sstevel@tonic-gate 
102507c478bd9Sstevel@tonic-gate /*.......................................................................
102517c478bd9Sstevel@tonic-gate  * This function is called when an input line has been completed. It
102527c478bd9Sstevel@tonic-gate  * appends the specified newline character, terminates the line,
102537c478bd9Sstevel@tonic-gate  * records the line in the history buffer if appropriate, and positions
102547c478bd9Sstevel@tonic-gate  * the terminal cursor at the start of the next line.
102557c478bd9Sstevel@tonic-gate  *
102567c478bd9Sstevel@tonic-gate  * Input:
102577c478bd9Sstevel@tonic-gate  *  gl           GetLine *  The resource object of gl_get_line().
102587c478bd9Sstevel@tonic-gate  *  newline_char     int    The newline character to add to the end
102597c478bd9Sstevel@tonic-gate  *                          of the line.
102607c478bd9Sstevel@tonic-gate  * Output:
102617c478bd9Sstevel@tonic-gate  *  return           int    0 - OK.
102627c478bd9Sstevel@tonic-gate  *                          1 - Error.
102637c478bd9Sstevel@tonic-gate  */
102647c478bd9Sstevel@tonic-gate static int gl_line_ended(GetLine *gl, int newline_char)
102657c478bd9Sstevel@tonic-gate {
102667c478bd9Sstevel@tonic-gate /*
102677c478bd9Sstevel@tonic-gate  * If the newline character is printable, display it at the end of
102687c478bd9Sstevel@tonic-gate  * the line, and add it to the input line buffer.
102697c478bd9Sstevel@tonic-gate  */
102707c478bd9Sstevel@tonic-gate   if(isprint((int)(unsigned char) newline_char)) {
102717c478bd9Sstevel@tonic-gate     if(gl_end_of_line(gl, 1, NULL) || gl_add_char_to_line(gl, newline_char))
102727c478bd9Sstevel@tonic-gate       return 1;
102737c478bd9Sstevel@tonic-gate   } else {
102747c478bd9Sstevel@tonic-gate /*
102757c478bd9Sstevel@tonic-gate  * Otherwise just append a newline character to the input line buffer.
102767c478bd9Sstevel@tonic-gate  */
102777c478bd9Sstevel@tonic-gate     newline_char = '\n';
102787c478bd9Sstevel@tonic-gate     gl_buffer_char(gl, newline_char, gl->ntotal);
102797c478bd9Sstevel@tonic-gate   };
102807c478bd9Sstevel@tonic-gate /*
102817c478bd9Sstevel@tonic-gate  * Add the line to the history buffer if it was entered with a
102827c478bd9Sstevel@tonic-gate  * newline character.
102837c478bd9Sstevel@tonic-gate  */
102847c478bd9Sstevel@tonic-gate   if(gl->echo && gl->automatic_history && newline_char=='\n')
102857c478bd9Sstevel@tonic-gate     (void) _gl_append_history(gl, gl->line);
102867c478bd9Sstevel@tonic-gate /*
102877c478bd9Sstevel@tonic-gate  * Except when depending on the system-provided line editing, start a new
102887c478bd9Sstevel@tonic-gate  * line after the end of the line that has just been entered.
102897c478bd9Sstevel@tonic-gate  */
102907c478bd9Sstevel@tonic-gate   if(gl->editor != GL_NO_EDITOR && gl_start_newline(gl, 1))
102917c478bd9Sstevel@tonic-gate     return 1;
102927c478bd9Sstevel@tonic-gate /*
102937c478bd9Sstevel@tonic-gate  * Record the successful return status.
102947c478bd9Sstevel@tonic-gate  */
102957c478bd9Sstevel@tonic-gate   gl_record_status(gl, GLR_NEWLINE, 0);
102967c478bd9Sstevel@tonic-gate /*
102977c478bd9Sstevel@tonic-gate  * Attempt to flush any pending output.
102987c478bd9Sstevel@tonic-gate  */
102997c478bd9Sstevel@tonic-gate   (void) gl_flush_output(gl);
103007c478bd9Sstevel@tonic-gate /*
103017c478bd9Sstevel@tonic-gate  * The next call to gl_get_line() will write the prompt for a new line
103027c478bd9Sstevel@tonic-gate  * (or continue the above flush if incomplete), so if we manage to
103037c478bd9Sstevel@tonic-gate  * flush the terminal now, report that we are waiting to write to the
103047c478bd9Sstevel@tonic-gate  * terminal.
103057c478bd9Sstevel@tonic-gate  */
103067c478bd9Sstevel@tonic-gate   gl->pending_io = GLP_WRITE;
103077c478bd9Sstevel@tonic-gate   return 0;
103087c478bd9Sstevel@tonic-gate }
103097c478bd9Sstevel@tonic-gate 
103107c478bd9Sstevel@tonic-gate /*.......................................................................
103117c478bd9Sstevel@tonic-gate  * Return the last signal that was caught by the most recent call to
103127c478bd9Sstevel@tonic-gate  * gl_get_line(), or -1 if no signals were caught. This is useful if
103137c478bd9Sstevel@tonic-gate  * gl_get_line() returns errno=EINTR and you need to find out what signal
103147c478bd9Sstevel@tonic-gate  * caused it to abort.
103157c478bd9Sstevel@tonic-gate  *
103167c478bd9Sstevel@tonic-gate  * Input:
103177c478bd9Sstevel@tonic-gate  *  gl           GetLine *  The resource object of gl_get_line().
103187c478bd9Sstevel@tonic-gate  * Output:
103197c478bd9Sstevel@tonic-gate  *  return           int    The last signal caught by the most recent
103207c478bd9Sstevel@tonic-gate  *                          call to gl_get_line(), or -1 if no signals
103217c478bd9Sstevel@tonic-gate  *                          were caught.
103227c478bd9Sstevel@tonic-gate  */
103237c478bd9Sstevel@tonic-gate int gl_last_signal(GetLine *gl)
103247c478bd9Sstevel@tonic-gate {
103257c478bd9Sstevel@tonic-gate   int signo = -1;   /* The requested signal number */
103267c478bd9Sstevel@tonic-gate   if(gl) {
103277c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
103287c478bd9Sstevel@tonic-gate /*
103297c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
103307c478bd9Sstevel@tonic-gate  */
103317c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
103327c478bd9Sstevel@tonic-gate /*
103337c478bd9Sstevel@tonic-gate  * Access gl now that signals are blocked.
103347c478bd9Sstevel@tonic-gate  */
103357c478bd9Sstevel@tonic-gate     signo = gl->last_signal;
103367c478bd9Sstevel@tonic-gate /*
103377c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
103387c478bd9Sstevel@tonic-gate  */
103397c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
103407c478bd9Sstevel@tonic-gate   };
103417c478bd9Sstevel@tonic-gate   return signo;
103427c478bd9Sstevel@tonic-gate }
103437c478bd9Sstevel@tonic-gate 
103447c478bd9Sstevel@tonic-gate /*.......................................................................
103457c478bd9Sstevel@tonic-gate  * Prepare to edit a new line.
103467c478bd9Sstevel@tonic-gate  *
103477c478bd9Sstevel@tonic-gate  * Input:
103487c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of this library.
103497c478bd9Sstevel@tonic-gate  *  prompt        char *  The prompt to prefix the line with, or NULL to
103507c478bd9Sstevel@tonic-gate  *                        use the same prompt that was used by the previous
103517c478bd9Sstevel@tonic-gate  *                        line.
103527c478bd9Sstevel@tonic-gate  *  start_line    char *  The initial contents of the input line, or NULL
103537c478bd9Sstevel@tonic-gate  *                        if it should start out empty.
103547c478bd9Sstevel@tonic-gate  *  start_pos      int    If start_line isn't NULL, this specifies the
103557c478bd9Sstevel@tonic-gate  *                        index of the character over which the cursor
103567c478bd9Sstevel@tonic-gate  *                        should initially be positioned within the line.
103577c478bd9Sstevel@tonic-gate  *                        If you just want it to follow the last character
103587c478bd9Sstevel@tonic-gate  *                        of the line, send -1.
103597c478bd9Sstevel@tonic-gate  * Output:
103607c478bd9Sstevel@tonic-gate  *  return    int    0 - OK.
103617c478bd9Sstevel@tonic-gate  *                   1 - Error.
103627c478bd9Sstevel@tonic-gate  */
103637c478bd9Sstevel@tonic-gate static int gl_present_line(GetLine *gl, const char *prompt,
103647c478bd9Sstevel@tonic-gate 			   const char *start_line, int start_pos)
103657c478bd9Sstevel@tonic-gate {
103667c478bd9Sstevel@tonic-gate /*
103677c478bd9Sstevel@tonic-gate  * Reset the properties of the line.
103687c478bd9Sstevel@tonic-gate  */
103697c478bd9Sstevel@tonic-gate   gl_reset_input_line(gl);
103707c478bd9Sstevel@tonic-gate /*
103717c478bd9Sstevel@tonic-gate  * Record the new prompt and its displayed width.
103727c478bd9Sstevel@tonic-gate  */
103737c478bd9Sstevel@tonic-gate   if(prompt)
103747c478bd9Sstevel@tonic-gate     _gl_replace_prompt(gl, prompt);
103757c478bd9Sstevel@tonic-gate /*
103767c478bd9Sstevel@tonic-gate  * Reset the history search pointers.
103777c478bd9Sstevel@tonic-gate  */
103787c478bd9Sstevel@tonic-gate   if(_glh_cancel_search(gl->glh)) {
103797c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
103807c478bd9Sstevel@tonic-gate     return 1;
103817c478bd9Sstevel@tonic-gate   };
103827c478bd9Sstevel@tonic-gate /*
103837c478bd9Sstevel@tonic-gate  * If the previous line was entered via the repeat-history action,
103847c478bd9Sstevel@tonic-gate  * preload the specified history line.
103857c478bd9Sstevel@tonic-gate  */
103867c478bd9Sstevel@tonic-gate   if(gl->preload_history) {
103877c478bd9Sstevel@tonic-gate     gl->preload_history = 0;
103887c478bd9Sstevel@tonic-gate     if(gl->preload_id) {
103897c478bd9Sstevel@tonic-gate       if(_glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1)) {
103907c478bd9Sstevel@tonic-gate 	gl_update_buffer(gl);          /* Compute gl->ntotal etc.. */
103917c478bd9Sstevel@tonic-gate 	gl->buff_curpos = gl->ntotal;
103927c478bd9Sstevel@tonic-gate       } else {
103937c478bd9Sstevel@tonic-gate 	gl_truncate_buffer(gl, 0);
103947c478bd9Sstevel@tonic-gate       };
103957c478bd9Sstevel@tonic-gate       gl->preload_id = 0;
103967c478bd9Sstevel@tonic-gate     };
103977c478bd9Sstevel@tonic-gate /*
103987c478bd9Sstevel@tonic-gate  * Present a specified initial line?
103997c478bd9Sstevel@tonic-gate  */
104007c478bd9Sstevel@tonic-gate   } else if(start_line) {
104017c478bd9Sstevel@tonic-gate     char *cptr;      /* A pointer into gl->line[] */
104027c478bd9Sstevel@tonic-gate /*
104037c478bd9Sstevel@tonic-gate  * Measure the length of the starting line.
104047c478bd9Sstevel@tonic-gate  */
104057c478bd9Sstevel@tonic-gate     int start_len = strlen(start_line);
104067c478bd9Sstevel@tonic-gate /*
104077c478bd9Sstevel@tonic-gate  * If the length of the line is greater than the available space,
104087c478bd9Sstevel@tonic-gate  * truncate it.
104097c478bd9Sstevel@tonic-gate  */
104107c478bd9Sstevel@tonic-gate     if(start_len > gl->linelen)
104117c478bd9Sstevel@tonic-gate       start_len = gl->linelen;
104127c478bd9Sstevel@tonic-gate /*
104137c478bd9Sstevel@tonic-gate  * Load the line into the buffer.
104147c478bd9Sstevel@tonic-gate  */
104157c478bd9Sstevel@tonic-gate     if(start_line != gl->line)
104167c478bd9Sstevel@tonic-gate       gl_buffer_string(gl, start_line, start_len, 0);
104177c478bd9Sstevel@tonic-gate /*
104187c478bd9Sstevel@tonic-gate  * Strip off any trailing newline and carriage return characters.
104197c478bd9Sstevel@tonic-gate  */
104207c478bd9Sstevel@tonic-gate     for(cptr=gl->line + gl->ntotal - 1; cptr >= gl->line &&
104217c478bd9Sstevel@tonic-gate 	(*cptr=='\n' || *cptr=='\r'); cptr--,gl->ntotal--)
104227c478bd9Sstevel@tonic-gate       ;
104237c478bd9Sstevel@tonic-gate     gl_truncate_buffer(gl, gl->ntotal < 0 ? 0 : gl->ntotal);
104247c478bd9Sstevel@tonic-gate /*
104257c478bd9Sstevel@tonic-gate  * Where should the cursor be placed within the line?
104267c478bd9Sstevel@tonic-gate  */
104277c478bd9Sstevel@tonic-gate     if(start_pos < 0 || start_pos > gl->ntotal) {
104287c478bd9Sstevel@tonic-gate       if(gl_place_cursor(gl, gl->ntotal))
104297c478bd9Sstevel@tonic-gate 	return 1;
104307c478bd9Sstevel@tonic-gate     } else {
104317c478bd9Sstevel@tonic-gate       if(gl_place_cursor(gl, start_pos))
104327c478bd9Sstevel@tonic-gate 	return 1;
104337c478bd9Sstevel@tonic-gate     };
104347c478bd9Sstevel@tonic-gate /*
104357c478bd9Sstevel@tonic-gate  * Clear the input line?
104367c478bd9Sstevel@tonic-gate  */
104377c478bd9Sstevel@tonic-gate   } else {
104387c478bd9Sstevel@tonic-gate     gl_truncate_buffer(gl, 0);
104397c478bd9Sstevel@tonic-gate   };
104407c478bd9Sstevel@tonic-gate /*
104417c478bd9Sstevel@tonic-gate  * Arrange for the line to be displayed by gl_flush_output().
104427c478bd9Sstevel@tonic-gate  */
104437c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
104447c478bd9Sstevel@tonic-gate /*
104457c478bd9Sstevel@tonic-gate  * Update the display.
104467c478bd9Sstevel@tonic-gate  */
104477c478bd9Sstevel@tonic-gate   return gl_flush_output(gl);
104487c478bd9Sstevel@tonic-gate }
104497c478bd9Sstevel@tonic-gate 
104507c478bd9Sstevel@tonic-gate /*.......................................................................
104517c478bd9Sstevel@tonic-gate  * Reset all line input parameters for a new input line.
104527c478bd9Sstevel@tonic-gate  *
104537c478bd9Sstevel@tonic-gate  * Input:
104547c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The line editor resource object.
104557c478bd9Sstevel@tonic-gate  */
104567c478bd9Sstevel@tonic-gate static void gl_reset_input_line(GetLine *gl)
104577c478bd9Sstevel@tonic-gate {
104587c478bd9Sstevel@tonic-gate   gl->ntotal = 0;
104597c478bd9Sstevel@tonic-gate   gl->line[0] = '\0';
104607c478bd9Sstevel@tonic-gate   gl->buff_curpos = 0;
104617c478bd9Sstevel@tonic-gate   gl->term_curpos = 0;
104627c478bd9Sstevel@tonic-gate   gl->term_len = 0;
104637c478bd9Sstevel@tonic-gate   gl->insert_curpos = 0;
104647c478bd9Sstevel@tonic-gate   gl->number = -1;
104657c478bd9Sstevel@tonic-gate   gl->displayed = 0;
104667c478bd9Sstevel@tonic-gate   gl->endline = 0;
104677c478bd9Sstevel@tonic-gate   gl->redisplay = 0;
104687c478bd9Sstevel@tonic-gate   gl->postpone = 0;
104697c478bd9Sstevel@tonic-gate   gl->nbuf = 0;
104707c478bd9Sstevel@tonic-gate   gl->nread = 0;
104717c478bd9Sstevel@tonic-gate   gl->vi.command = 0;
104727c478bd9Sstevel@tonic-gate   gl->vi.undo.line[0] = '\0';
104737c478bd9Sstevel@tonic-gate   gl->vi.undo.ntotal = 0;
104747c478bd9Sstevel@tonic-gate   gl->vi.undo.buff_curpos = 0;
104757c478bd9Sstevel@tonic-gate   gl->vi.repeat.action.fn = 0;
104767c478bd9Sstevel@tonic-gate   gl->vi.repeat.action.data = 0;
104777c478bd9Sstevel@tonic-gate   gl->last_signal = -1;
104787c478bd9Sstevel@tonic-gate }
104797c478bd9Sstevel@tonic-gate 
104807c478bd9Sstevel@tonic-gate /*.......................................................................
104817c478bd9Sstevel@tonic-gate  * Print an informational message to the terminal, after starting a new
104827c478bd9Sstevel@tonic-gate  * line.
104837c478bd9Sstevel@tonic-gate  *
104847c478bd9Sstevel@tonic-gate  * Input:
104857c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The line editor resource object.
104867c478bd9Sstevel@tonic-gate  *  ...  const char *  Zero or more strings to be printed.
104877c478bd9Sstevel@tonic-gate  *  ...        void *  The last argument must always be GL_END_INFO.
104887c478bd9Sstevel@tonic-gate  * Output:
104897c478bd9Sstevel@tonic-gate  *  return      int    0 - OK.
104907c478bd9Sstevel@tonic-gate  *                     1 - Error.
104917c478bd9Sstevel@tonic-gate  */
104927c478bd9Sstevel@tonic-gate static int gl_print_info(GetLine *gl, ...)
104937c478bd9Sstevel@tonic-gate {
104947c478bd9Sstevel@tonic-gate   va_list ap;     /* The variable argument list */
104957c478bd9Sstevel@tonic-gate   const char *s;  /* The string being printed */
104967c478bd9Sstevel@tonic-gate   int waserr = 0; /* True after an error */
104977c478bd9Sstevel@tonic-gate /*
104987c478bd9Sstevel@tonic-gate  * Only display output when echoing is on.
104997c478bd9Sstevel@tonic-gate  */
105007c478bd9Sstevel@tonic-gate   if(gl->echo) {
105017c478bd9Sstevel@tonic-gate /*
105027c478bd9Sstevel@tonic-gate  * Skip to the start of the next empty line before displaying the message.
105037c478bd9Sstevel@tonic-gate  */
105047c478bd9Sstevel@tonic-gate     if(gl_start_newline(gl, 1))
105057c478bd9Sstevel@tonic-gate       return 1;
105067c478bd9Sstevel@tonic-gate /*
105077c478bd9Sstevel@tonic-gate  * Display the list of provided messages.
105087c478bd9Sstevel@tonic-gate  */
105097c478bd9Sstevel@tonic-gate     va_start(ap, gl);
105107c478bd9Sstevel@tonic-gate     while(!waserr && (s = va_arg(ap, const char *)) != GL_END_INFO)
105117c478bd9Sstevel@tonic-gate       waserr = gl_print_raw_string(gl, 1, s, -1);
105127c478bd9Sstevel@tonic-gate     va_end(ap);
105137c478bd9Sstevel@tonic-gate /*
105147c478bd9Sstevel@tonic-gate  * Start a newline.
105157c478bd9Sstevel@tonic-gate  */
105167c478bd9Sstevel@tonic-gate     waserr = waserr || gl_print_raw_string(gl, 1, "\n\r", -1);
105177c478bd9Sstevel@tonic-gate /*
105187c478bd9Sstevel@tonic-gate  * Arrange for the input line to be redrawn.
105197c478bd9Sstevel@tonic-gate  */
105207c478bd9Sstevel@tonic-gate     gl_queue_redisplay(gl);
105217c478bd9Sstevel@tonic-gate   };
105227c478bd9Sstevel@tonic-gate   return waserr;
105237c478bd9Sstevel@tonic-gate }
105247c478bd9Sstevel@tonic-gate 
105257c478bd9Sstevel@tonic-gate /*.......................................................................
105267c478bd9Sstevel@tonic-gate  * Go to the start of the next empty line, ready to output miscellaneous
105277c478bd9Sstevel@tonic-gate  * text to the screen.
105287c478bd9Sstevel@tonic-gate  *
105297c478bd9Sstevel@tonic-gate  * Note that when async-signal safety is required, the 'buffered'
105307c478bd9Sstevel@tonic-gate  * argument must be 0.
105317c478bd9Sstevel@tonic-gate  *
105327c478bd9Sstevel@tonic-gate  * Input:
105337c478bd9Sstevel@tonic-gate  *  gl          GetLine *  The line editor resource object.
105347c478bd9Sstevel@tonic-gate  *  buffered        int    If true, used buffered I/O when writing to
105357c478bd9Sstevel@tonic-gate  *                         the terminal. Otherwise use async-signal-safe
105367c478bd9Sstevel@tonic-gate  *                         unbuffered I/O.
105377c478bd9Sstevel@tonic-gate  * Output:
105387c478bd9Sstevel@tonic-gate  *  return          int    0 - OK.
105397c478bd9Sstevel@tonic-gate  *                         1 - Error.
105407c478bd9Sstevel@tonic-gate  */
105417c478bd9Sstevel@tonic-gate static int gl_start_newline(GetLine *gl, int buffered)
105427c478bd9Sstevel@tonic-gate {
105437c478bd9Sstevel@tonic-gate   int waserr = 0;  /* True after any I/O error */
105447c478bd9Sstevel@tonic-gate /*
105457c478bd9Sstevel@tonic-gate  * Move the cursor to the start of the terminal line that follows the
105467c478bd9Sstevel@tonic-gate  * last line of the partially enterred line. In order that this
105477c478bd9Sstevel@tonic-gate  * function remain async-signal safe when write_fn is signal safe, we
105487c478bd9Sstevel@tonic-gate  * can't call our normal output functions, since they call tputs(),
105497c478bd9Sstevel@tonic-gate  * who's signal saftey isn't defined. Fortunately, we can simply use
105507c478bd9Sstevel@tonic-gate  * \r and \n to move the cursor to the right place.
105517c478bd9Sstevel@tonic-gate  */
105527c478bd9Sstevel@tonic-gate   if(gl->displayed) {   /* Is an input line currently displayed? */
105537c478bd9Sstevel@tonic-gate /*
105547c478bd9Sstevel@tonic-gate  * On which terminal lines are the cursor and the last character of the
105557c478bd9Sstevel@tonic-gate  * input line?
105567c478bd9Sstevel@tonic-gate  */
105577c478bd9Sstevel@tonic-gate     int curs_line = gl->term_curpos / gl->ncolumn;
105587c478bd9Sstevel@tonic-gate     int last_line = gl->term_len / gl->ncolumn;
105597c478bd9Sstevel@tonic-gate /*
105607c478bd9Sstevel@tonic-gate  * Move the cursor to the start of the line that follows the last
105617c478bd9Sstevel@tonic-gate  * terminal line that is occupied by the input line.
105627c478bd9Sstevel@tonic-gate  */
105637c478bd9Sstevel@tonic-gate     for( ; curs_line < last_line + 1; curs_line++)
105647c478bd9Sstevel@tonic-gate       waserr = waserr || gl_print_raw_string(gl, buffered, "\n", 1);
105657c478bd9Sstevel@tonic-gate     waserr = waserr || gl_print_raw_string(gl, buffered, "\r", 1);
105667c478bd9Sstevel@tonic-gate /*
105677c478bd9Sstevel@tonic-gate  * Mark the line as no longer displayed.
105687c478bd9Sstevel@tonic-gate  */
105697c478bd9Sstevel@tonic-gate     gl_line_erased(gl);
105707c478bd9Sstevel@tonic-gate   };
105717c478bd9Sstevel@tonic-gate   return waserr;
105727c478bd9Sstevel@tonic-gate }
105737c478bd9Sstevel@tonic-gate 
105747c478bd9Sstevel@tonic-gate /*.......................................................................
105757c478bd9Sstevel@tonic-gate  * The callback through which all terminal output is routed.
105767c478bd9Sstevel@tonic-gate  * This simply appends characters to a queue buffer, which is
105777c478bd9Sstevel@tonic-gate  * subsequently flushed to the output channel by gl_flush_output().
105787c478bd9Sstevel@tonic-gate  *
105797c478bd9Sstevel@tonic-gate  * Input:
105807c478bd9Sstevel@tonic-gate  *  data     void *  The pointer to a GetLine line editor resource object
105817c478bd9Sstevel@tonic-gate  *                   cast to (void *).
105827c478bd9Sstevel@tonic-gate  *  s  const char *  The string to be written.
105837c478bd9Sstevel@tonic-gate  *  n         int    The number of characters to write from s[].
105847c478bd9Sstevel@tonic-gate  * Output:
105857c478bd9Sstevel@tonic-gate  *  return    int    The number of characters written. This will always
105867c478bd9Sstevel@tonic-gate  *                   be equal to 'n' unless an error occurs.
105877c478bd9Sstevel@tonic-gate  */
105887c478bd9Sstevel@tonic-gate static GL_WRITE_FN(gl_write_fn)
105897c478bd9Sstevel@tonic-gate {
105907c478bd9Sstevel@tonic-gate   GetLine *gl = (GetLine *) data;
105917c478bd9Sstevel@tonic-gate   int ndone = _glq_append_chars(gl->cq, s, n, gl->flush_fn, gl);
105927c478bd9Sstevel@tonic-gate   if(ndone != n)
105937c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glq_last_error(gl->cq), END_ERR_MSG);
105947c478bd9Sstevel@tonic-gate   return ndone;
105957c478bd9Sstevel@tonic-gate }
105967c478bd9Sstevel@tonic-gate 
105977c478bd9Sstevel@tonic-gate /*.......................................................................
105987c478bd9Sstevel@tonic-gate  * Ask gl_get_line() what caused it to return.
105997c478bd9Sstevel@tonic-gate  *
106007c478bd9Sstevel@tonic-gate  * Input:
106017c478bd9Sstevel@tonic-gate  *  gl             GetLine *  The line editor resource object.
106027c478bd9Sstevel@tonic-gate  * Output:
106037c478bd9Sstevel@tonic-gate  *  return  GlReturnStatus    The return status of the last call to
106047c478bd9Sstevel@tonic-gate  *                            gl_get_line().
106057c478bd9Sstevel@tonic-gate  */
106067c478bd9Sstevel@tonic-gate GlReturnStatus gl_return_status(GetLine *gl)
106077c478bd9Sstevel@tonic-gate {
106087c478bd9Sstevel@tonic-gate   GlReturnStatus rtn_status = GLR_ERROR;   /* The requested status */
106097c478bd9Sstevel@tonic-gate   if(gl) {
106107c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
106117c478bd9Sstevel@tonic-gate /*
106127c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
106137c478bd9Sstevel@tonic-gate  */
106147c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
106157c478bd9Sstevel@tonic-gate /*
106167c478bd9Sstevel@tonic-gate  * Access gl while signals are blocked.
106177c478bd9Sstevel@tonic-gate  */
106187c478bd9Sstevel@tonic-gate     rtn_status = gl->rtn_status;
106197c478bd9Sstevel@tonic-gate /*
106207c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
106217c478bd9Sstevel@tonic-gate  */
106227c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
106237c478bd9Sstevel@tonic-gate   };
106247c478bd9Sstevel@tonic-gate   return rtn_status;
106257c478bd9Sstevel@tonic-gate }
106267c478bd9Sstevel@tonic-gate 
106277c478bd9Sstevel@tonic-gate /*.......................................................................
106287c478bd9Sstevel@tonic-gate  * In non-blocking server-I/O mode, this function should be called
106297c478bd9Sstevel@tonic-gate  * from the application's external event loop to see what type of
106307c478bd9Sstevel@tonic-gate  * terminal I/O is being waited for by gl_get_line(), and thus what
106317c478bd9Sstevel@tonic-gate  * direction of I/O to wait for with select() or poll().
106327c478bd9Sstevel@tonic-gate  *
106337c478bd9Sstevel@tonic-gate  * Input:
106347c478bd9Sstevel@tonic-gate  *  gl          GetLine *  The resource object of gl_get_line().
106357c478bd9Sstevel@tonic-gate  * Output:
106367c478bd9Sstevel@tonic-gate  *  return  GlPendingIO    The type of pending I/O being waited for.
106377c478bd9Sstevel@tonic-gate  */
106387c478bd9Sstevel@tonic-gate GlPendingIO gl_pending_io(GetLine *gl)
106397c478bd9Sstevel@tonic-gate {
106407c478bd9Sstevel@tonic-gate   GlPendingIO pending_io = GLP_WRITE;   /* The requested information */
106417c478bd9Sstevel@tonic-gate   if(gl) {
106427c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
106437c478bd9Sstevel@tonic-gate /*
106447c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
106457c478bd9Sstevel@tonic-gate  */
106467c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
106477c478bd9Sstevel@tonic-gate /*
106487c478bd9Sstevel@tonic-gate  * Access gl while signals are blocked.
106497c478bd9Sstevel@tonic-gate  */
106507c478bd9Sstevel@tonic-gate     pending_io = gl->pending_io;
106517c478bd9Sstevel@tonic-gate /*
106527c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
106537c478bd9Sstevel@tonic-gate  */
106547c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
106557c478bd9Sstevel@tonic-gate   };
106567c478bd9Sstevel@tonic-gate   return pending_io;
106577c478bd9Sstevel@tonic-gate }
106587c478bd9Sstevel@tonic-gate 
106597c478bd9Sstevel@tonic-gate /*.......................................................................
106607c478bd9Sstevel@tonic-gate  * In server mode, this function configures the terminal for non-blocking
106617c478bd9Sstevel@tonic-gate  * raw terminal I/O. In normal I/O mode it does nothing.
106627c478bd9Sstevel@tonic-gate  *
106637c478bd9Sstevel@tonic-gate  * Callers of this function must be careful to trap all signals that
106647c478bd9Sstevel@tonic-gate  * terminate or suspend the program, and call gl_normal_io()
106657c478bd9Sstevel@tonic-gate  * from the corresponding signal handlers in order to restore the
106667c478bd9Sstevel@tonic-gate  * terminal to its original settings before the program is terminated
106677c478bd9Sstevel@tonic-gate  * or suspended. They should also trap the SIGCONT signal to detect
106687c478bd9Sstevel@tonic-gate  * when the program resumes, and ensure that its signal handler
106697c478bd9Sstevel@tonic-gate  * call gl_raw_io() to redisplay the line and resume editing.
106707c478bd9Sstevel@tonic-gate  *
106717c478bd9Sstevel@tonic-gate  * This function is async signal safe.
106727c478bd9Sstevel@tonic-gate  *
106737c478bd9Sstevel@tonic-gate  * Input:
106747c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The line editor resource object.
106757c478bd9Sstevel@tonic-gate  * Output:
106767c478bd9Sstevel@tonic-gate  *  return      int    0 - OK.
106777c478bd9Sstevel@tonic-gate  *                     1 - Error.
106787c478bd9Sstevel@tonic-gate  */
106797c478bd9Sstevel@tonic-gate int gl_raw_io(GetLine *gl)
106807c478bd9Sstevel@tonic-gate {
106817c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
106827c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_raw_io() */
106837c478bd9Sstevel@tonic-gate /*
106847c478bd9Sstevel@tonic-gate  * Check the arguments.
106857c478bd9Sstevel@tonic-gate  */
106867c478bd9Sstevel@tonic-gate   if(!gl) {
106877c478bd9Sstevel@tonic-gate     errno = EINVAL;
106887c478bd9Sstevel@tonic-gate     return 1;
106897c478bd9Sstevel@tonic-gate   };
106907c478bd9Sstevel@tonic-gate /*
106917c478bd9Sstevel@tonic-gate  * Block all signals.
106927c478bd9Sstevel@tonic-gate  */
106937c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
106947c478bd9Sstevel@tonic-gate     return 1;
106957c478bd9Sstevel@tonic-gate /*
106967c478bd9Sstevel@tonic-gate  * Don't allow applications to switch into raw mode unless in server mode.
106977c478bd9Sstevel@tonic-gate  */
106987c478bd9Sstevel@tonic-gate   if(gl->io_mode != GL_SERVER_MODE) {
106997c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "Can't switch to raw I/O unless in server mode",
107007c478bd9Sstevel@tonic-gate 		    END_ERR_MSG);
107017c478bd9Sstevel@tonic-gate     errno = EPERM;
107027c478bd9Sstevel@tonic-gate     status = 1;
107037c478bd9Sstevel@tonic-gate   } else {
107047c478bd9Sstevel@tonic-gate /*
107057c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
107067c478bd9Sstevel@tonic-gate  */
107077c478bd9Sstevel@tonic-gate     status = _gl_raw_io(gl, 1);
107087c478bd9Sstevel@tonic-gate   };
107097c478bd9Sstevel@tonic-gate /*
107107c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
107117c478bd9Sstevel@tonic-gate  */
107127c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
107137c478bd9Sstevel@tonic-gate   return status;
107147c478bd9Sstevel@tonic-gate }
107157c478bd9Sstevel@tonic-gate 
107167c478bd9Sstevel@tonic-gate /*.......................................................................
107177c478bd9Sstevel@tonic-gate  * This is the private body of the public function, gl_raw_io().
107187c478bd9Sstevel@tonic-gate  * It assumes that the caller has checked its arguments and blocked the
107197c478bd9Sstevel@tonic-gate  * delivery of signals.
107207c478bd9Sstevel@tonic-gate  *
107217c478bd9Sstevel@tonic-gate  * This function is async signal safe.
107227c478bd9Sstevel@tonic-gate  */
107237c478bd9Sstevel@tonic-gate static int _gl_raw_io(GetLine *gl, int redisplay)
107247c478bd9Sstevel@tonic-gate {
107257c478bd9Sstevel@tonic-gate /*
107267c478bd9Sstevel@tonic-gate  * If we are already in the correct mode, do nothing.
107277c478bd9Sstevel@tonic-gate  */
107287c478bd9Sstevel@tonic-gate   if(gl->raw_mode)
107297c478bd9Sstevel@tonic-gate     return 0;
107307c478bd9Sstevel@tonic-gate /*
107317c478bd9Sstevel@tonic-gate  * Switch the terminal to raw mode.
107327c478bd9Sstevel@tonic-gate  */
107337c478bd9Sstevel@tonic-gate   if(gl->is_term && gl_raw_terminal_mode(gl))
107347c478bd9Sstevel@tonic-gate     return 1;
107357c478bd9Sstevel@tonic-gate /*
107367c478bd9Sstevel@tonic-gate  * Switch to non-blocking I/O mode?
107377c478bd9Sstevel@tonic-gate  */
107387c478bd9Sstevel@tonic-gate   if(gl->io_mode==GL_SERVER_MODE &&
107397c478bd9Sstevel@tonic-gate      (gl_nonblocking_io(gl, gl->input_fd) ||
107407c478bd9Sstevel@tonic-gate       gl_nonblocking_io(gl, gl->output_fd) ||
107417c478bd9Sstevel@tonic-gate       (gl->file_fp && gl_nonblocking_io(gl, fileno(gl->file_fp))))) {
107427c478bd9Sstevel@tonic-gate     if(gl->is_term)
107437c478bd9Sstevel@tonic-gate       gl_restore_terminal_attributes(gl);
107447c478bd9Sstevel@tonic-gate     return 1;
107457c478bd9Sstevel@tonic-gate   };
107467c478bd9Sstevel@tonic-gate /*
107477c478bd9Sstevel@tonic-gate  * If an input line is being entered, arrange for it to be
107487c478bd9Sstevel@tonic-gate  * displayed.
107497c478bd9Sstevel@tonic-gate  */
107507c478bd9Sstevel@tonic-gate   if(redisplay) {
107517c478bd9Sstevel@tonic-gate     gl->postpone = 0;
107527c478bd9Sstevel@tonic-gate     gl_queue_redisplay(gl);
107537c478bd9Sstevel@tonic-gate   };
107547c478bd9Sstevel@tonic-gate   return 0;
107557c478bd9Sstevel@tonic-gate }
107567c478bd9Sstevel@tonic-gate 
107577c478bd9Sstevel@tonic-gate /*.......................................................................
107587c478bd9Sstevel@tonic-gate  * Restore the terminal to the state that it had when
107597c478bd9Sstevel@tonic-gate  * gl_raw_io() was last called. After calling
107607c478bd9Sstevel@tonic-gate  * gl_raw_io(), this function must be called before
107617c478bd9Sstevel@tonic-gate  * terminating or suspending the program, and before attempting other
107627c478bd9Sstevel@tonic-gate  * uses of the terminal from within the program. See gl_raw_io()
107637c478bd9Sstevel@tonic-gate  * for more details.
107647c478bd9Sstevel@tonic-gate  *
107657c478bd9Sstevel@tonic-gate  * Input:
107667c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The line editor resource object.
107677c478bd9Sstevel@tonic-gate  * Output:
107687c478bd9Sstevel@tonic-gate  *  return      int    0 - OK.
107697c478bd9Sstevel@tonic-gate  *                     1 - Error.
107707c478bd9Sstevel@tonic-gate  */
107717c478bd9Sstevel@tonic-gate int gl_normal_io(GetLine *gl)
107727c478bd9Sstevel@tonic-gate {
107737c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
107747c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_normal_io() */
107757c478bd9Sstevel@tonic-gate /*
107767c478bd9Sstevel@tonic-gate  * Check the arguments.
107777c478bd9Sstevel@tonic-gate  */
107787c478bd9Sstevel@tonic-gate   if(!gl) {
107797c478bd9Sstevel@tonic-gate     errno = EINVAL;
107807c478bd9Sstevel@tonic-gate     return 1;
107817c478bd9Sstevel@tonic-gate   };
107827c478bd9Sstevel@tonic-gate /*
107837c478bd9Sstevel@tonic-gate  * Block all signals.
107847c478bd9Sstevel@tonic-gate  */
107857c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
107867c478bd9Sstevel@tonic-gate     return 1;
107877c478bd9Sstevel@tonic-gate /*
107887c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
107897c478bd9Sstevel@tonic-gate  */
107907c478bd9Sstevel@tonic-gate   status = _gl_normal_io(gl);
107917c478bd9Sstevel@tonic-gate /*
107927c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
107937c478bd9Sstevel@tonic-gate  */
107947c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
107957c478bd9Sstevel@tonic-gate   return status;
107967c478bd9Sstevel@tonic-gate }
107977c478bd9Sstevel@tonic-gate 
107987c478bd9Sstevel@tonic-gate /*.......................................................................
107997c478bd9Sstevel@tonic-gate  * This is the private body of the public function, gl_normal_io().
108007c478bd9Sstevel@tonic-gate  * It assumes that the caller has checked its arguments and blocked the
108017c478bd9Sstevel@tonic-gate  * delivery of signals.
108027c478bd9Sstevel@tonic-gate  */
108037c478bd9Sstevel@tonic-gate static int _gl_normal_io(GetLine *gl)
108047c478bd9Sstevel@tonic-gate {
108057c478bd9Sstevel@tonic-gate /*
108067c478bd9Sstevel@tonic-gate  * If we are already in normal mode, do nothing.
108077c478bd9Sstevel@tonic-gate  */
108087c478bd9Sstevel@tonic-gate   if(!gl->raw_mode)
108097c478bd9Sstevel@tonic-gate     return 0;
108107c478bd9Sstevel@tonic-gate /*
108117c478bd9Sstevel@tonic-gate  * Postpone subsequent redisplays until after _gl_raw_io(gl, 1)
108127c478bd9Sstevel@tonic-gate  * is next called.
108137c478bd9Sstevel@tonic-gate  */
108147c478bd9Sstevel@tonic-gate   gl->postpone = 1;
108157c478bd9Sstevel@tonic-gate /*
108167c478bd9Sstevel@tonic-gate  * Switch back to blocking I/O. Note that this is essential to do
108177c478bd9Sstevel@tonic-gate  * here, because when using non-blocking I/O, the terminal output
108187c478bd9Sstevel@tonic-gate  * buffering code can't always make room for new output without calling
108197c478bd9Sstevel@tonic-gate  * malloc(), and a call to malloc() would mean that this function
108207c478bd9Sstevel@tonic-gate  * couldn't safely be called from signal handlers.
108217c478bd9Sstevel@tonic-gate  */
108227c478bd9Sstevel@tonic-gate   if(gl->io_mode==GL_SERVER_MODE &&
108237c478bd9Sstevel@tonic-gate      (gl_blocking_io(gl, gl->input_fd) ||
108247c478bd9Sstevel@tonic-gate       gl_blocking_io(gl, gl->output_fd) ||
108257c478bd9Sstevel@tonic-gate       (gl->file_fp && gl_blocking_io(gl, fileno(gl->file_fp)))))
108267c478bd9Sstevel@tonic-gate     return 1;
108277c478bd9Sstevel@tonic-gate /*
108287c478bd9Sstevel@tonic-gate  * Move the cursor to the next empty terminal line. Note that
108297c478bd9Sstevel@tonic-gate  * unbuffered I/O is requested, to ensure that gl_start_newline() be
108307c478bd9Sstevel@tonic-gate  * async-signal-safe.
108317c478bd9Sstevel@tonic-gate  */
108327c478bd9Sstevel@tonic-gate   if(gl->is_term && gl_start_newline(gl, 0))
108337c478bd9Sstevel@tonic-gate     return 1;
108347c478bd9Sstevel@tonic-gate /*
108357c478bd9Sstevel@tonic-gate  * Switch the terminal to normal mode.
108367c478bd9Sstevel@tonic-gate  */
108377c478bd9Sstevel@tonic-gate   if(gl->is_term && gl_restore_terminal_attributes(gl)) {
108387c478bd9Sstevel@tonic-gate /*
108397c478bd9Sstevel@tonic-gate  * On error, revert to non-blocking I/O if needed, so that on failure
108407c478bd9Sstevel@tonic-gate  * we remain in raw mode.
108417c478bd9Sstevel@tonic-gate  */
108427c478bd9Sstevel@tonic-gate     if(gl->io_mode==GL_SERVER_MODE) {
108437c478bd9Sstevel@tonic-gate       gl_nonblocking_io(gl, gl->input_fd);
108447c478bd9Sstevel@tonic-gate       gl_nonblocking_io(gl, gl->output_fd);
108457c478bd9Sstevel@tonic-gate       if(gl->file_fp)
108467c478bd9Sstevel@tonic-gate 	gl_nonblocking_io(gl, fileno(gl->file_fp));
108477c478bd9Sstevel@tonic-gate     };
108487c478bd9Sstevel@tonic-gate     return 1;
108497c478bd9Sstevel@tonic-gate   };
108507c478bd9Sstevel@tonic-gate   return 0;
108517c478bd9Sstevel@tonic-gate }
108527c478bd9Sstevel@tonic-gate 
108537c478bd9Sstevel@tonic-gate /*.......................................................................
108547c478bd9Sstevel@tonic-gate  * This function allows you to install an additional completion
108557c478bd9Sstevel@tonic-gate  * action, or to change the completion function of an existing
108567c478bd9Sstevel@tonic-gate  * one. This should be called before the first call to gl_get_line()
108577c478bd9Sstevel@tonic-gate  * so that the name of the action be defined before the user's
108587c478bd9Sstevel@tonic-gate  * configuration file is read.
108597c478bd9Sstevel@tonic-gate  *
108607c478bd9Sstevel@tonic-gate  * Input:
108617c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of the command-line input
108627c478bd9Sstevel@tonic-gate  *                           module.
108637c478bd9Sstevel@tonic-gate  *  data             void *  This is passed to match_fn() whenever it is
108647c478bd9Sstevel@tonic-gate  *                           called. It could, for example, point to a
108657c478bd9Sstevel@tonic-gate  *                           symbol table that match_fn() would look up
108667c478bd9Sstevel@tonic-gate  *                           matches in.
108677c478bd9Sstevel@tonic-gate  *  match_fn   CplMatchFn *  The function that will identify the prefix
108687c478bd9Sstevel@tonic-gate  *                           to be completed from the input line, and
108697c478bd9Sstevel@tonic-gate  *                           report matching symbols.
108707c478bd9Sstevel@tonic-gate  *  list_only         int    If non-zero, install an action that only lists
108717c478bd9Sstevel@tonic-gate  *                           possible completions, rather than attempting
108727c478bd9Sstevel@tonic-gate  *                           to perform the completion.
108737c478bd9Sstevel@tonic-gate  *  name       const char *  The name with which users can refer to the
108747c478bd9Sstevel@tonic-gate  *                           binding in tecla configuration files.
108757c478bd9Sstevel@tonic-gate  *  keyseq     const char *  Either NULL, or a key sequence with which
108767c478bd9Sstevel@tonic-gate  *                           to invoke the binding. This should be
108777c478bd9Sstevel@tonic-gate  *                           specified in the same manner as key-sequences
108787c478bd9Sstevel@tonic-gate  *                           in tecla configuration files (eg. "M-^I").
108797c478bd9Sstevel@tonic-gate  * Output:
108807c478bd9Sstevel@tonic-gate  *  return            int    0 - OK.
108817c478bd9Sstevel@tonic-gate  *                           1 - Error.
108827c478bd9Sstevel@tonic-gate  */
108837c478bd9Sstevel@tonic-gate int gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
108847c478bd9Sstevel@tonic-gate 			 int list_only, const char *name, const char *keyseq)
108857c478bd9Sstevel@tonic-gate {
108867c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
108877c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_completion_action() */
108887c478bd9Sstevel@tonic-gate /*
108897c478bd9Sstevel@tonic-gate  * Check the arguments.
108907c478bd9Sstevel@tonic-gate  */
108917c478bd9Sstevel@tonic-gate   if(!gl || !name || !match_fn) {
108927c478bd9Sstevel@tonic-gate     errno = EINVAL;
108937c478bd9Sstevel@tonic-gate     return 1;
108947c478bd9Sstevel@tonic-gate   };
108957c478bd9Sstevel@tonic-gate /*
108967c478bd9Sstevel@tonic-gate  * Block all signals.
108977c478bd9Sstevel@tonic-gate  */
108987c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
108997c478bd9Sstevel@tonic-gate     return 1;
109007c478bd9Sstevel@tonic-gate /*
109017c478bd9Sstevel@tonic-gate  * Install the new action while signals are blocked.
109027c478bd9Sstevel@tonic-gate  */
109037c478bd9Sstevel@tonic-gate   status = _gl_completion_action(gl, data, match_fn, list_only, name, keyseq);
109047c478bd9Sstevel@tonic-gate /*
109057c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
109067c478bd9Sstevel@tonic-gate  */
109077c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
109087c478bd9Sstevel@tonic-gate   return status;
109097c478bd9Sstevel@tonic-gate }
109107c478bd9Sstevel@tonic-gate 
109117c478bd9Sstevel@tonic-gate /*.......................................................................
109127c478bd9Sstevel@tonic-gate  * This is the private body of the public function, gl_completion_action().
109137c478bd9Sstevel@tonic-gate  * It assumes that the caller has checked its arguments and blocked the
109147c478bd9Sstevel@tonic-gate  * delivery of signals.
109157c478bd9Sstevel@tonic-gate  */
109167c478bd9Sstevel@tonic-gate static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn,
109177c478bd9Sstevel@tonic-gate 				 int list_only, const char *name,
109187c478bd9Sstevel@tonic-gate 				 const char *keyseq)
109197c478bd9Sstevel@tonic-gate {
109207c478bd9Sstevel@tonic-gate   KtKeyFn *current_fn;      /* An existing action function */
109217c478bd9Sstevel@tonic-gate   void *current_data;       /* The action-function callback data */
109227c478bd9Sstevel@tonic-gate /*
109237c478bd9Sstevel@tonic-gate  * Which action function is desired?
109247c478bd9Sstevel@tonic-gate  */
109257c478bd9Sstevel@tonic-gate   KtKeyFn *action_fn = list_only ? gl_list_completions : gl_complete_word;
109267c478bd9Sstevel@tonic-gate /*
109277c478bd9Sstevel@tonic-gate  * Is there already an action of the specified name?
109287c478bd9Sstevel@tonic-gate  */
109297c478bd9Sstevel@tonic-gate   if(_kt_lookup_action(gl->bindings, name, &current_fn, &current_data) == 0) {
109307c478bd9Sstevel@tonic-gate /*
109317c478bd9Sstevel@tonic-gate  * If the action has the same type as the one being requested,
109327c478bd9Sstevel@tonic-gate  * simply change the contents of its GlCplCallback callback data.
109337c478bd9Sstevel@tonic-gate  */
109347c478bd9Sstevel@tonic-gate     if(current_fn == action_fn) {
109357c478bd9Sstevel@tonic-gate       GlCplCallback *cb = (GlCplCallback *) current_data;
109367c478bd9Sstevel@tonic-gate       cb->fn = match_fn;
109377c478bd9Sstevel@tonic-gate       cb->data = data;
109387c478bd9Sstevel@tonic-gate     } else {
109397c478bd9Sstevel@tonic-gate       errno = EINVAL;
109407c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err,
109417c478bd9Sstevel@tonic-gate         "Illegal attempt to change the type of an existing completion action",
109427c478bd9Sstevel@tonic-gate         END_ERR_MSG);
109437c478bd9Sstevel@tonic-gate       return 1;
109447c478bd9Sstevel@tonic-gate     };
109457c478bd9Sstevel@tonic-gate /*
109467c478bd9Sstevel@tonic-gate  * No existing action has the specified name.
109477c478bd9Sstevel@tonic-gate  */
109487c478bd9Sstevel@tonic-gate   } else {
109497c478bd9Sstevel@tonic-gate /*
109507c478bd9Sstevel@tonic-gate  * Allocate a new GlCplCallback callback object.
109517c478bd9Sstevel@tonic-gate  */
109527c478bd9Sstevel@tonic-gate     GlCplCallback *cb = (GlCplCallback *) _new_FreeListNode(gl->cpl_mem);
109537c478bd9Sstevel@tonic-gate     if(!cb) {
109547c478bd9Sstevel@tonic-gate       errno = ENOMEM;
109557c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "Insufficient memory to add completion action",
109567c478bd9Sstevel@tonic-gate 		      END_ERR_MSG);
109577c478bd9Sstevel@tonic-gate       return 1;
109587c478bd9Sstevel@tonic-gate     };
109597c478bd9Sstevel@tonic-gate /*
109607c478bd9Sstevel@tonic-gate  * Record the completion callback data.
109617c478bd9Sstevel@tonic-gate  */
109627c478bd9Sstevel@tonic-gate     cb->fn = match_fn;
109637c478bd9Sstevel@tonic-gate     cb->data = data;
109647c478bd9Sstevel@tonic-gate /*
109657c478bd9Sstevel@tonic-gate  * Attempt to register the new action.
109667c478bd9Sstevel@tonic-gate  */
109677c478bd9Sstevel@tonic-gate     if(_kt_set_action(gl->bindings, name, action_fn, cb)) {
109687c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
109697c478bd9Sstevel@tonic-gate       _del_FreeListNode(gl->cpl_mem, (void *) cb);
109707c478bd9Sstevel@tonic-gate       return 1;
109717c478bd9Sstevel@tonic-gate     };
109727c478bd9Sstevel@tonic-gate   };
109737c478bd9Sstevel@tonic-gate /*
109747c478bd9Sstevel@tonic-gate  * Bind the action to a given key-sequence?
109757c478bd9Sstevel@tonic-gate  */
109767c478bd9Sstevel@tonic-gate   if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) {
109777c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
109787c478bd9Sstevel@tonic-gate     return 1;
109797c478bd9Sstevel@tonic-gate   };
109807c478bd9Sstevel@tonic-gate   return 0;
109817c478bd9Sstevel@tonic-gate }
109827c478bd9Sstevel@tonic-gate 
109837c478bd9Sstevel@tonic-gate /*.......................................................................
109847c478bd9Sstevel@tonic-gate  * Register an application-provided function as an action function.
109857c478bd9Sstevel@tonic-gate  * This should preferably be called before the first call to gl_get_line()
109867c478bd9Sstevel@tonic-gate  * so that the name of the action becomes defined before the user's
109877c478bd9Sstevel@tonic-gate  * configuration file is read.
109887c478bd9Sstevel@tonic-gate  *
109897c478bd9Sstevel@tonic-gate  * Input:
109907c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of the command-line input
109917c478bd9Sstevel@tonic-gate  *                           module.
109927c478bd9Sstevel@tonic-gate  *  data             void *  Arbitrary application-specific callback
109937c478bd9Sstevel@tonic-gate  *                           data to be passed to the callback
109947c478bd9Sstevel@tonic-gate  *                           function, fn().
109957c478bd9Sstevel@tonic-gate  *  fn         GlActionFn *  The application-specific function that
109967c478bd9Sstevel@tonic-gate  *                           implements the action. This will be invoked
109977c478bd9Sstevel@tonic-gate  *                           whenever the user presses any
109987c478bd9Sstevel@tonic-gate  *                           key-sequence which is bound to this action.
109997c478bd9Sstevel@tonic-gate  *  name       const char *  The name with which users can refer to the
110007c478bd9Sstevel@tonic-gate  *                           binding in tecla configuration files.
110017c478bd9Sstevel@tonic-gate  *  keyseq     const char *  The key sequence with which to invoke
110027c478bd9Sstevel@tonic-gate  *                           the binding. This should be specified in the
110037c478bd9Sstevel@tonic-gate  *                           same manner as key-sequences in tecla
110047c478bd9Sstevel@tonic-gate  *                           configuration files (eg. "M-^I").
110057c478bd9Sstevel@tonic-gate  * Output:
110067c478bd9Sstevel@tonic-gate  *  return            int    0 - OK.
110077c478bd9Sstevel@tonic-gate  *                           1 - Error.
110087c478bd9Sstevel@tonic-gate  */
110097c478bd9Sstevel@tonic-gate int gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
110107c478bd9Sstevel@tonic-gate                        const char *name, const char *keyseq)
110117c478bd9Sstevel@tonic-gate {
110127c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
110137c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_register_action() */
110147c478bd9Sstevel@tonic-gate /*
110157c478bd9Sstevel@tonic-gate  * Check the arguments.
110167c478bd9Sstevel@tonic-gate  */
110177c478bd9Sstevel@tonic-gate   if(!gl || !name || !fn) {
110187c478bd9Sstevel@tonic-gate     errno = EINVAL;
110197c478bd9Sstevel@tonic-gate     return 1;
110207c478bd9Sstevel@tonic-gate   };
110217c478bd9Sstevel@tonic-gate /*
110227c478bd9Sstevel@tonic-gate  * Block all signals.
110237c478bd9Sstevel@tonic-gate  */
110247c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
110257c478bd9Sstevel@tonic-gate     return 1;
110267c478bd9Sstevel@tonic-gate /*
110277c478bd9Sstevel@tonic-gate  * Install the new action while signals are blocked.
110287c478bd9Sstevel@tonic-gate  */
110297c478bd9Sstevel@tonic-gate   status = _gl_register_action(gl, data, fn, name, keyseq);
110307c478bd9Sstevel@tonic-gate /*
110317c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
110327c478bd9Sstevel@tonic-gate  */
110337c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
110347c478bd9Sstevel@tonic-gate   return status;
110357c478bd9Sstevel@tonic-gate }
110367c478bd9Sstevel@tonic-gate 
110377c478bd9Sstevel@tonic-gate /*.......................................................................
110387c478bd9Sstevel@tonic-gate  * This is the private body of the public function, gl_register_action().
110397c478bd9Sstevel@tonic-gate  * It assumes that the caller has checked its arguments and blocked the
110407c478bd9Sstevel@tonic-gate  * delivery of signals.
110417c478bd9Sstevel@tonic-gate  */
110427c478bd9Sstevel@tonic-gate static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn,
110437c478bd9Sstevel@tonic-gate 			       const char *name, const char *keyseq)
110447c478bd9Sstevel@tonic-gate {
110457c478bd9Sstevel@tonic-gate   KtKeyFn *current_fn;      /* An existing action function */
110467c478bd9Sstevel@tonic-gate   void *current_data;       /* The action-function callback data */
110477c478bd9Sstevel@tonic-gate /*
110487c478bd9Sstevel@tonic-gate  * Get the action function which actually runs the application-provided
110497c478bd9Sstevel@tonic-gate  * function.
110507c478bd9Sstevel@tonic-gate  */
110517c478bd9Sstevel@tonic-gate   KtKeyFn *action_fn = gl_run_external_action;
110527c478bd9Sstevel@tonic-gate /*
110537c478bd9Sstevel@tonic-gate  * Is there already an action of the specified name?
110547c478bd9Sstevel@tonic-gate  */
110557c478bd9Sstevel@tonic-gate   if(_kt_lookup_action(gl->bindings, name, &current_fn, &current_data) == 0) {
110567c478bd9Sstevel@tonic-gate /*
110577c478bd9Sstevel@tonic-gate  * If the action has the same type as the one being requested,
110587c478bd9Sstevel@tonic-gate  * simply change the contents of its GlCplCallback callback data.
110597c478bd9Sstevel@tonic-gate  */
110607c478bd9Sstevel@tonic-gate     if(current_fn == action_fn) {
110617c478bd9Sstevel@tonic-gate       GlExternalAction *a = (GlExternalAction *) current_data;
110627c478bd9Sstevel@tonic-gate       a->fn = fn;
110637c478bd9Sstevel@tonic-gate       a->data = data;
110647c478bd9Sstevel@tonic-gate     } else {
110657c478bd9Sstevel@tonic-gate       errno = EINVAL;
110667c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err,
110677c478bd9Sstevel@tonic-gate         "Illegal attempt to change the type of an existing action",
110687c478bd9Sstevel@tonic-gate 		      END_ERR_MSG);
110697c478bd9Sstevel@tonic-gate       return 1;
110707c478bd9Sstevel@tonic-gate     };
110717c478bd9Sstevel@tonic-gate /*
110727c478bd9Sstevel@tonic-gate  * No existing action has the specified name.
110737c478bd9Sstevel@tonic-gate  */
110747c478bd9Sstevel@tonic-gate   } else {
110757c478bd9Sstevel@tonic-gate /*
110767c478bd9Sstevel@tonic-gate  * Allocate a new GlCplCallback callback object.
110777c478bd9Sstevel@tonic-gate  */
110787c478bd9Sstevel@tonic-gate     GlExternalAction *a =
110797c478bd9Sstevel@tonic-gate       (GlExternalAction *) _new_FreeListNode(gl->ext_act_mem);
110807c478bd9Sstevel@tonic-gate     if(!a) {
110817c478bd9Sstevel@tonic-gate       errno = ENOMEM;
110827c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "Insufficient memory to add completion action",
110837c478bd9Sstevel@tonic-gate 		      END_ERR_MSG);
110847c478bd9Sstevel@tonic-gate       return 1;
110857c478bd9Sstevel@tonic-gate     };
110867c478bd9Sstevel@tonic-gate /*
110877c478bd9Sstevel@tonic-gate  * Record the completion callback data.
110887c478bd9Sstevel@tonic-gate  */
110897c478bd9Sstevel@tonic-gate     a->fn = fn;
110907c478bd9Sstevel@tonic-gate     a->data = data;
110917c478bd9Sstevel@tonic-gate /*
110927c478bd9Sstevel@tonic-gate  * Attempt to register the new action.
110937c478bd9Sstevel@tonic-gate  */
110947c478bd9Sstevel@tonic-gate     if(_kt_set_action(gl->bindings, name, action_fn, a)) {
110957c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
110967c478bd9Sstevel@tonic-gate       _del_FreeListNode(gl->cpl_mem, (void *) a);
110977c478bd9Sstevel@tonic-gate       return 1;
110987c478bd9Sstevel@tonic-gate     };
110997c478bd9Sstevel@tonic-gate   };
111007c478bd9Sstevel@tonic-gate /*
111017c478bd9Sstevel@tonic-gate  * Bind the action to a given key-sequence?
111027c478bd9Sstevel@tonic-gate  */
111037c478bd9Sstevel@tonic-gate   if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) {
111047c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
111057c478bd9Sstevel@tonic-gate     return 1;
111067c478bd9Sstevel@tonic-gate   };
111077c478bd9Sstevel@tonic-gate   return 0;
111087c478bd9Sstevel@tonic-gate }
111097c478bd9Sstevel@tonic-gate 
111107c478bd9Sstevel@tonic-gate /*.......................................................................
111117c478bd9Sstevel@tonic-gate  * Invoke an action function previously registered by a call to
111127c478bd9Sstevel@tonic-gate  * gl_register_action().
111137c478bd9Sstevel@tonic-gate  */
111147c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_run_external_action)
111157c478bd9Sstevel@tonic-gate {
111167c478bd9Sstevel@tonic-gate   GlAfterAction status;  /* The return value of the action function */
111177c478bd9Sstevel@tonic-gate /*
111187c478bd9Sstevel@tonic-gate  * Get the container of the action function and associated callback data.
111197c478bd9Sstevel@tonic-gate  */
111207c478bd9Sstevel@tonic-gate   GlExternalAction *a = (GlExternalAction *) data;
111217c478bd9Sstevel@tonic-gate /*
111227c478bd9Sstevel@tonic-gate  * Invoke the action function.
111237c478bd9Sstevel@tonic-gate  */
111247c478bd9Sstevel@tonic-gate   status = a->fn(gl, a->data, count, gl->buff_curpos, gl->line);
111257c478bd9Sstevel@tonic-gate /*
111267c478bd9Sstevel@tonic-gate  * If the callback took us out of raw (possibly non-blocking) input
111277c478bd9Sstevel@tonic-gate  * mode, restore this mode, and queue a redisplay of the input line.
111287c478bd9Sstevel@tonic-gate  */
111297c478bd9Sstevel@tonic-gate   if(_gl_raw_io(gl, 1))
111307c478bd9Sstevel@tonic-gate     return 1;
111317c478bd9Sstevel@tonic-gate /*
111327c478bd9Sstevel@tonic-gate  * Finally, check to see what the action function wants us to do next.
111337c478bd9Sstevel@tonic-gate  */
111347c478bd9Sstevel@tonic-gate   switch(status) {
111357c478bd9Sstevel@tonic-gate   default:
111367c478bd9Sstevel@tonic-gate   case GLA_ABORT:
111377c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_ERROR, errno);
111387c478bd9Sstevel@tonic-gate     return 1;
111397c478bd9Sstevel@tonic-gate     break;
111407c478bd9Sstevel@tonic-gate   case GLA_RETURN:
111417c478bd9Sstevel@tonic-gate     return gl_newline(gl, 1, NULL);
111427c478bd9Sstevel@tonic-gate     break;
111437c478bd9Sstevel@tonic-gate   case GLA_CONTINUE:
111447c478bd9Sstevel@tonic-gate     break;
111457c478bd9Sstevel@tonic-gate   };
111467c478bd9Sstevel@tonic-gate   return 0;
111477c478bd9Sstevel@tonic-gate }
111487c478bd9Sstevel@tonic-gate 
111497c478bd9Sstevel@tonic-gate /*.......................................................................
111507c478bd9Sstevel@tonic-gate  * In server-I/O mode the terminal is left in raw mode between calls
111517c478bd9Sstevel@tonic-gate  * to gl_get_line(), so it is necessary for the application to install
111527c478bd9Sstevel@tonic-gate  * terminal restoring signal handlers for signals that could terminate
111537c478bd9Sstevel@tonic-gate  * or suspend the process, plus a terminal reconfiguration handler to
111547c478bd9Sstevel@tonic-gate  * be called when a process resumption signal is received, and finally
111557c478bd9Sstevel@tonic-gate  * a handler to be called when a terminal-resize signal is received.
111567c478bd9Sstevel@tonic-gate  *
111577c478bd9Sstevel@tonic-gate  * Since there are many signals that by default terminate or suspend
111587c478bd9Sstevel@tonic-gate  * processes, and different systems support different sub-sets of
111597c478bd9Sstevel@tonic-gate  * these signals, this function provides a convenient wrapper around
111607c478bd9Sstevel@tonic-gate  * sigaction() for assigning the specified handlers to all appropriate
111617c478bd9Sstevel@tonic-gate  * signals. It also arranges that when any one of these signals is
111627c478bd9Sstevel@tonic-gate  * being handled, all other catchable signals are blocked. This is
111637c478bd9Sstevel@tonic-gate  * necessary so that the specified signal handlers can safely call
111647c478bd9Sstevel@tonic-gate  * gl_raw_io(), gl_normal_io() and gl_update_size() without
111657c478bd9Sstevel@tonic-gate  * reentrancy issues.
111667c478bd9Sstevel@tonic-gate  *
111677c478bd9Sstevel@tonic-gate  * Input:
111687c478bd9Sstevel@tonic-gate  *  term_handler  void (*)(int)  The signal handler to invoke when
111697c478bd9Sstevel@tonic-gate  *                               a process terminating signal is
111707c478bd9Sstevel@tonic-gate  *                               received.
111717c478bd9Sstevel@tonic-gate  *  susp_handler  void (*)(int)  The signal handler to invoke when
111727c478bd9Sstevel@tonic-gate  *                               a process suspending signal is
111737c478bd9Sstevel@tonic-gate  *                               received.
111747c478bd9Sstevel@tonic-gate  *  cont_handler  void (*)(int)  The signal handler to invoke when
111757c478bd9Sstevel@tonic-gate  *                               a process resumption signal is
111767c478bd9Sstevel@tonic-gate  *                               received (ie. SIGCONT).
111777c478bd9Sstevel@tonic-gate  *  size_handler  void (*)(int)  The signal handler to invoke when
111787c478bd9Sstevel@tonic-gate  *                               a terminal-resize signal (ie. SIGWINCH)
111797c478bd9Sstevel@tonic-gate  *                               is received.
111807c478bd9Sstevel@tonic-gate  * Output:
111817c478bd9Sstevel@tonic-gate  *  return                  int  0 - OK.
111827c478bd9Sstevel@tonic-gate  *                               1 - Error.
111837c478bd9Sstevel@tonic-gate  */
111847c478bd9Sstevel@tonic-gate int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int),
111857c478bd9Sstevel@tonic-gate 		   void (*cont_handler)(int), void (*size_handler)(int))
111867c478bd9Sstevel@tonic-gate {
111877c478bd9Sstevel@tonic-gate   int i;
111887c478bd9Sstevel@tonic-gate /*
111897c478bd9Sstevel@tonic-gate  * Search for signals of the specified classes, and assign the
111907c478bd9Sstevel@tonic-gate  * associated signal handler to them.
111917c478bd9Sstevel@tonic-gate  */
111927c478bd9Sstevel@tonic-gate   for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
111937c478bd9Sstevel@tonic-gate     const struct GlDefSignal *sig = gl_signal_list + i;
111947c478bd9Sstevel@tonic-gate     if(sig->attr & GLSA_SUSP) {
111957c478bd9Sstevel@tonic-gate       if(gl_set_tty_signal(sig->signo, term_handler))
111967c478bd9Sstevel@tonic-gate 	return 1;
111977c478bd9Sstevel@tonic-gate     } else if(sig->attr & GLSA_TERM) {
111987c478bd9Sstevel@tonic-gate       if(gl_set_tty_signal(sig->signo, susp_handler))
111997c478bd9Sstevel@tonic-gate 	return 1;
112007c478bd9Sstevel@tonic-gate     } else if(sig->attr & GLSA_CONT) {
112017c478bd9Sstevel@tonic-gate       if(gl_set_tty_signal(sig->signo, cont_handler))
112027c478bd9Sstevel@tonic-gate 	return 1;
112037c478bd9Sstevel@tonic-gate     } else if(sig->attr & GLSA_SIZE) {
112047c478bd9Sstevel@tonic-gate       if(gl_set_tty_signal(sig->signo, size_handler))
112057c478bd9Sstevel@tonic-gate 	return 1;
112067c478bd9Sstevel@tonic-gate     };
112077c478bd9Sstevel@tonic-gate   };
112087c478bd9Sstevel@tonic-gate   return 0;
112097c478bd9Sstevel@tonic-gate }
112107c478bd9Sstevel@tonic-gate 
112117c478bd9Sstevel@tonic-gate /*.......................................................................
112127c478bd9Sstevel@tonic-gate  * This is a private function of gl_tty_signals(). It installs a given
112137c478bd9Sstevel@tonic-gate  * signal handler, and arranges that when that signal handler is being
112147c478bd9Sstevel@tonic-gate  * invoked other signals are blocked. The latter is important to allow
112157c478bd9Sstevel@tonic-gate  * functions like gl_normal_io(), gl_raw_io() and gl_update_size()
112167c478bd9Sstevel@tonic-gate  * to be called from signal handlers.
112177c478bd9Sstevel@tonic-gate  *
112187c478bd9Sstevel@tonic-gate  * Input:
112197c478bd9Sstevel@tonic-gate  *  signo     int           The signal to be trapped.
112207c478bd9Sstevel@tonic-gate  *  handler  void (*)(int)  The signal handler to assign to the signal.
112217c478bd9Sstevel@tonic-gate  */
112227c478bd9Sstevel@tonic-gate static int gl_set_tty_signal(int signo, void (*handler)(int))
112237c478bd9Sstevel@tonic-gate {
112247c478bd9Sstevel@tonic-gate   SigAction act;   /* The signal handler configuation */
112257c478bd9Sstevel@tonic-gate /*
112267c478bd9Sstevel@tonic-gate  * Arrange to block all trappable signals except the one that is being
112277c478bd9Sstevel@tonic-gate  * assigned (the trapped signal will be blocked automatically by the
112287c478bd9Sstevel@tonic-gate  * system).
112297c478bd9Sstevel@tonic-gate  */
112307c478bd9Sstevel@tonic-gate   gl_list_trappable_signals(&act.sa_mask);
112317c478bd9Sstevel@tonic-gate   sigdelset(&act.sa_mask, signo);
112327c478bd9Sstevel@tonic-gate /*
112337c478bd9Sstevel@tonic-gate  * Assign the signal handler.
112347c478bd9Sstevel@tonic-gate  */
112357c478bd9Sstevel@tonic-gate   act.sa_handler = handler;
112367c478bd9Sstevel@tonic-gate /*
112377c478bd9Sstevel@tonic-gate  * There is only one portable signal handling flag, and it isn't
112387c478bd9Sstevel@tonic-gate  * relevant to us, so don't specify any flags.
112397c478bd9Sstevel@tonic-gate  */
112407c478bd9Sstevel@tonic-gate   act.sa_flags = 0;
112417c478bd9Sstevel@tonic-gate /*
112427c478bd9Sstevel@tonic-gate  * Register the signal handler.
112437c478bd9Sstevel@tonic-gate  */
112447c478bd9Sstevel@tonic-gate   if(sigaction(signo, &act, NULL))
112457c478bd9Sstevel@tonic-gate     return 1;
112467c478bd9Sstevel@tonic-gate   return 0;
112477c478bd9Sstevel@tonic-gate }
112487c478bd9Sstevel@tonic-gate 
112497c478bd9Sstevel@tonic-gate /*.......................................................................
112507c478bd9Sstevel@tonic-gate  * Display a left-justified string over multiple terminal lines,
112517c478bd9Sstevel@tonic-gate  * taking account of the current width of the terminal. Optional
112527c478bd9Sstevel@tonic-gate  * indentation and an optional prefix string can be specified to be
112537c478bd9Sstevel@tonic-gate  * displayed at the start of each new terminal line used. Similarly,
112547c478bd9Sstevel@tonic-gate  * an optional suffix can be specified to be displayed at the end of
112557c478bd9Sstevel@tonic-gate  * each terminal line.  If needed, a single paragraph can be broken
112567c478bd9Sstevel@tonic-gate  * across multiple calls.  Note that literal newlines in the input
112577c478bd9Sstevel@tonic-gate  * string can be used to force a newline at any point and that you
112587c478bd9Sstevel@tonic-gate  * should use this feature to explicitly end all paragraphs, including
112597c478bd9Sstevel@tonic-gate  * at the end of the last string that you write. Note that when a new
112607c478bd9Sstevel@tonic-gate  * line is started between two words that are separated by spaces,
112617c478bd9Sstevel@tonic-gate  * those spaces are not output, whereas when a new line is started
112627c478bd9Sstevel@tonic-gate  * because a newline character was found in the string, only the
112637c478bd9Sstevel@tonic-gate  * spaces before the newline character are discarded.
112647c478bd9Sstevel@tonic-gate  *
112657c478bd9Sstevel@tonic-gate  * Input:
112667c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
112677c478bd9Sstevel@tonic-gate  *  indentation    int    The number of spaces of indentation to write
112687c478bd9Sstevel@tonic-gate  *                        at the beginning of each new terminal line.
112697c478bd9Sstevel@tonic-gate  *  prefix  const char *  An optional prefix string to write after the
112707c478bd9Sstevel@tonic-gate  *                        indentation margin at the start of each new
112717c478bd9Sstevel@tonic-gate  *                        terminal line. You can specify NULL if no
112727c478bd9Sstevel@tonic-gate  *                        prefix is required.
112737c478bd9Sstevel@tonic-gate  *  suffix  const char *  An optional suffix string to draw at the end
112747c478bd9Sstevel@tonic-gate  *                        of the terminal line. Spaces will be added
112757c478bd9Sstevel@tonic-gate  *                        where necessary to ensure that the suffix ends
112767c478bd9Sstevel@tonic-gate  *                        in the last column of the terminal line. If
112777c478bd9Sstevel@tonic-gate  *                        no suffix is desired, specify NULL.
112787c478bd9Sstevel@tonic-gate  *  fill_char      int    The padding character to use when indenting
112797c478bd9Sstevel@tonic-gate  *                        the line or padding up to the suffix.
112807c478bd9Sstevel@tonic-gate  *  def_width      int    If the terminal width isn't known, such as when
112817c478bd9Sstevel@tonic-gate  *                        writing to a pipe or redirecting to a file,
112827c478bd9Sstevel@tonic-gate  *                        this number specifies what width to assume.
112837c478bd9Sstevel@tonic-gate  *  start          int    The number of characters already written to
112847c478bd9Sstevel@tonic-gate  *                        the start of the current terminal line. This
112857c478bd9Sstevel@tonic-gate  *                        is primarily used to allow individual
112867c478bd9Sstevel@tonic-gate  *                        paragraphs to be written over multiple calls
112877c478bd9Sstevel@tonic-gate  *                        to this function, but can also be used to
112887c478bd9Sstevel@tonic-gate  *                        allow you to start the first line of a
112897c478bd9Sstevel@tonic-gate  *                        paragraph with a different prefix or
112907c478bd9Sstevel@tonic-gate  *                        indentation than those specified above.
112917c478bd9Sstevel@tonic-gate  *  string  const char *  The string to be written.
112927c478bd9Sstevel@tonic-gate  * Output:
112937c478bd9Sstevel@tonic-gate  *  return         int    On error -1 is returned. Otherwise the
112947c478bd9Sstevel@tonic-gate  *                        return value is the terminal column index at
112957c478bd9Sstevel@tonic-gate  *                        which the cursor was left after writing the
112967c478bd9Sstevel@tonic-gate  *                        final word in the string. Successful return
112977c478bd9Sstevel@tonic-gate  *                        values can thus be passed verbatim to the
112987c478bd9Sstevel@tonic-gate  *                        'start' arguments of subsequent calls to
112997c478bd9Sstevel@tonic-gate  *                        gl_display_text() to allow the printing of a
113007c478bd9Sstevel@tonic-gate  *                        paragraph to be broken across multiple calls
113017c478bd9Sstevel@tonic-gate  *                        to gl_display_text().
113027c478bd9Sstevel@tonic-gate  */
113037c478bd9Sstevel@tonic-gate int gl_display_text(GetLine *gl, int indentation, const char *prefix,
113047c478bd9Sstevel@tonic-gate 		    const char *suffix, int fill_char,
113057c478bd9Sstevel@tonic-gate 		    int def_width, int start, const char *string)
113067c478bd9Sstevel@tonic-gate {
113077c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
113087c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_completion_action() */
113097c478bd9Sstevel@tonic-gate /*
113107c478bd9Sstevel@tonic-gate  * Check the arguments?
113117c478bd9Sstevel@tonic-gate  */
113127c478bd9Sstevel@tonic-gate   if(!gl || !string) {
113137c478bd9Sstevel@tonic-gate     errno = EINVAL;
113147c478bd9Sstevel@tonic-gate     return -1;
113157c478bd9Sstevel@tonic-gate   };
113167c478bd9Sstevel@tonic-gate /*
113177c478bd9Sstevel@tonic-gate  * Block all signals.
113187c478bd9Sstevel@tonic-gate  */
113197c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
113207c478bd9Sstevel@tonic-gate     return -1;
113217c478bd9Sstevel@tonic-gate /*
113227c478bd9Sstevel@tonic-gate  * Display the text while signals are blocked.
113237c478bd9Sstevel@tonic-gate  */
113247c478bd9Sstevel@tonic-gate   status = _io_display_text(_io_write_stdio, gl->output_fp, indentation,
113257c478bd9Sstevel@tonic-gate 			    prefix, suffix, fill_char,
113267c478bd9Sstevel@tonic-gate 			    gl->ncolumn > 0 ? gl->ncolumn : def_width,
113277c478bd9Sstevel@tonic-gate 			    start, string);
113287c478bd9Sstevel@tonic-gate /*
113297c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
113307c478bd9Sstevel@tonic-gate  */
113317c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
113327c478bd9Sstevel@tonic-gate   return status;
113337c478bd9Sstevel@tonic-gate }
113347c478bd9Sstevel@tonic-gate 
113357c478bd9Sstevel@tonic-gate /*.......................................................................
113367c478bd9Sstevel@tonic-gate  * Block all of the signals that we are currently trapping.
113377c478bd9Sstevel@tonic-gate  *
113387c478bd9Sstevel@tonic-gate  * Input:
113397c478bd9Sstevel@tonic-gate  *  gl       GetLine *   The resource object of gl_get_line().
113407c478bd9Sstevel@tonic-gate  * Input/Output:
113417c478bd9Sstevel@tonic-gate  *  oldset   sigset_t *   The superseded process signal mask
113427c478bd9Sstevel@tonic-gate  *                        will be return in *oldset unless oldset is
113437c478bd9Sstevel@tonic-gate  *                        NULL.
113447c478bd9Sstevel@tonic-gate  * Output:
113457c478bd9Sstevel@tonic-gate  *  return        int     0 - OK.
113467c478bd9Sstevel@tonic-gate  *                        1 - Error.
113477c478bd9Sstevel@tonic-gate  */
113487c478bd9Sstevel@tonic-gate static int gl_mask_signals(GetLine *gl, sigset_t *oldset)
113497c478bd9Sstevel@tonic-gate {
113507c478bd9Sstevel@tonic-gate /*
113517c478bd9Sstevel@tonic-gate  * Block all signals in all_signal_set, along with any others that are
113527c478bd9Sstevel@tonic-gate  * already blocked by the application.
113537c478bd9Sstevel@tonic-gate  */
113547c478bd9Sstevel@tonic-gate   if(sigprocmask(SIG_BLOCK, &gl->all_signal_set, oldset) >= 0) {
113557c478bd9Sstevel@tonic-gate     gl->signals_masked = 1;
113567c478bd9Sstevel@tonic-gate     return 0;
113577c478bd9Sstevel@tonic-gate   };
113587c478bd9Sstevel@tonic-gate /*
113597c478bd9Sstevel@tonic-gate  * On error attempt to query the current process signal mask, so
113607c478bd9Sstevel@tonic-gate  * that oldset be the correct process signal mask to restore later
113617c478bd9Sstevel@tonic-gate  * if the caller of this function ignores the error return value.
113627c478bd9Sstevel@tonic-gate  */
113637c478bd9Sstevel@tonic-gate   if(oldset)
113647c478bd9Sstevel@tonic-gate     (void) sigprocmask(SIG_SETMASK, NULL, oldset);
113657c478bd9Sstevel@tonic-gate   gl->signals_masked = 0;
113667c478bd9Sstevel@tonic-gate   return 1;
113677c478bd9Sstevel@tonic-gate }
113687c478bd9Sstevel@tonic-gate 
113697c478bd9Sstevel@tonic-gate /*.......................................................................
113707c478bd9Sstevel@tonic-gate  * Restore a process signal mask that was previously returned via the
113717c478bd9Sstevel@tonic-gate  * oldset argument of gl_mask_signals().
113727c478bd9Sstevel@tonic-gate  *
113737c478bd9Sstevel@tonic-gate  * Input:
113747c478bd9Sstevel@tonic-gate  *  gl        GetLine *   The resource object of gl_get_line().
113757c478bd9Sstevel@tonic-gate  * Input/Output:
113767c478bd9Sstevel@tonic-gate  *  oldset   sigset_t *   The process signal mask to be restored.
113777c478bd9Sstevel@tonic-gate  * Output:
113787c478bd9Sstevel@tonic-gate  *  return        int     0 - OK.
113797c478bd9Sstevel@tonic-gate  *                        1 - Error.
113807c478bd9Sstevel@tonic-gate  */
113817c478bd9Sstevel@tonic-gate static int gl_unmask_signals(GetLine *gl, sigset_t *oldset)
113827c478bd9Sstevel@tonic-gate {
113837c478bd9Sstevel@tonic-gate   gl->signals_masked = 0;
113847c478bd9Sstevel@tonic-gate   return sigprocmask(SIG_SETMASK, oldset, NULL) < 0;
113857c478bd9Sstevel@tonic-gate }
113867c478bd9Sstevel@tonic-gate 
113877c478bd9Sstevel@tonic-gate /*.......................................................................
113887c478bd9Sstevel@tonic-gate  * Arrange to temporarily catch the signals marked in gl->use_signal_set.
113897c478bd9Sstevel@tonic-gate  *
113907c478bd9Sstevel@tonic-gate  * Input:
113917c478bd9Sstevel@tonic-gate  *  gl        GetLine *   The resource object of gl_get_line().
113927c478bd9Sstevel@tonic-gate  * Output:
113937c478bd9Sstevel@tonic-gate  *  return        int     0 - OK.
113947c478bd9Sstevel@tonic-gate  *                        1 - Error.
113957c478bd9Sstevel@tonic-gate  */
113967c478bd9Sstevel@tonic-gate static int gl_catch_signals(GetLine *gl)
113977c478bd9Sstevel@tonic-gate {
113987c478bd9Sstevel@tonic-gate   return sigprocmask(SIG_UNBLOCK, &gl->use_signal_set, NULL) < 0;
113997c478bd9Sstevel@tonic-gate }
114007c478bd9Sstevel@tonic-gate 
114017c478bd9Sstevel@tonic-gate /*.......................................................................
114027c478bd9Sstevel@tonic-gate  * Select the I/O mode to be used by gl_get_line().
114037c478bd9Sstevel@tonic-gate  *
114047c478bd9Sstevel@tonic-gate  * Input:
114057c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
114067c478bd9Sstevel@tonic-gate  *  mode      GlIOMode    The I/O mode to establish.
114077c478bd9Sstevel@tonic-gate  * Output:
114087c478bd9Sstevel@tonic-gate  *  return         int    0 - OK.
114097c478bd9Sstevel@tonic-gate  *                        1 - Error.
114107c478bd9Sstevel@tonic-gate  */
114117c478bd9Sstevel@tonic-gate int gl_io_mode(GetLine *gl, GlIOMode mode)
114127c478bd9Sstevel@tonic-gate {
114137c478bd9Sstevel@tonic-gate   sigset_t oldset; /* The signals that were blocked on entry to this function */
114147c478bd9Sstevel@tonic-gate   int status;      /* The return status of _gl_io_mode() */
114157c478bd9Sstevel@tonic-gate /*
114167c478bd9Sstevel@tonic-gate  * Check the arguments.
114177c478bd9Sstevel@tonic-gate  */
114187c478bd9Sstevel@tonic-gate   if(!gl) {
114197c478bd9Sstevel@tonic-gate     errno = EINVAL;
114207c478bd9Sstevel@tonic-gate     return 1;
114217c478bd9Sstevel@tonic-gate   };
114227c478bd9Sstevel@tonic-gate /*
114237c478bd9Sstevel@tonic-gate  * Check that the requested mode is known.
114247c478bd9Sstevel@tonic-gate  */
114257c478bd9Sstevel@tonic-gate   switch(mode) {
114267c478bd9Sstevel@tonic-gate   case GL_NORMAL_MODE:
114277c478bd9Sstevel@tonic-gate   case GL_SERVER_MODE:
114287c478bd9Sstevel@tonic-gate     break;
114297c478bd9Sstevel@tonic-gate   default:
114307c478bd9Sstevel@tonic-gate     errno = EINVAL;
114317c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "Unknown gl_get_line() I/O mode requested.",
114327c478bd9Sstevel@tonic-gate 		    END_ERR_MSG);
114337c478bd9Sstevel@tonic-gate     return 1;
114347c478bd9Sstevel@tonic-gate   };
114357c478bd9Sstevel@tonic-gate /*
114367c478bd9Sstevel@tonic-gate  * Block all signals.
114377c478bd9Sstevel@tonic-gate  */
114387c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
114397c478bd9Sstevel@tonic-gate     return 1;
114407c478bd9Sstevel@tonic-gate /*
114417c478bd9Sstevel@tonic-gate  * Invoke the private body of this function.
114427c478bd9Sstevel@tonic-gate  */
114437c478bd9Sstevel@tonic-gate   status = _gl_io_mode(gl, mode);
114447c478bd9Sstevel@tonic-gate /*
114457c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
114467c478bd9Sstevel@tonic-gate  */
114477c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
114487c478bd9Sstevel@tonic-gate   return status;
114497c478bd9Sstevel@tonic-gate }
114507c478bd9Sstevel@tonic-gate 
114517c478bd9Sstevel@tonic-gate /*.......................................................................
114527c478bd9Sstevel@tonic-gate  * This is the private body of the public function, gl_io_mode().
114537c478bd9Sstevel@tonic-gate  * It assumes that the caller has checked its arguments and blocked the
114547c478bd9Sstevel@tonic-gate  * delivery of signals.
114557c478bd9Sstevel@tonic-gate  */
114567c478bd9Sstevel@tonic-gate static int _gl_io_mode(GetLine *gl, GlIOMode mode)
114577c478bd9Sstevel@tonic-gate {
114587c478bd9Sstevel@tonic-gate /*
114597c478bd9Sstevel@tonic-gate  * Are we already in the specified mode?
114607c478bd9Sstevel@tonic-gate  */
114617c478bd9Sstevel@tonic-gate   if(mode == gl->io_mode)
114627c478bd9Sstevel@tonic-gate     return 0;
114637c478bd9Sstevel@tonic-gate /*
114647c478bd9Sstevel@tonic-gate  * First revert to normal I/O in the current I/O mode.
114657c478bd9Sstevel@tonic-gate  */
114667c478bd9Sstevel@tonic-gate   _gl_normal_io(gl);
114677c478bd9Sstevel@tonic-gate /*
114687c478bd9Sstevel@tonic-gate  * Record the new mode.
114697c478bd9Sstevel@tonic-gate  */
114707c478bd9Sstevel@tonic-gate   gl->io_mode = mode;
114717c478bd9Sstevel@tonic-gate /*
114727c478bd9Sstevel@tonic-gate  * Perform any actions needed by the new mode.
114737c478bd9Sstevel@tonic-gate  */
114747c478bd9Sstevel@tonic-gate   if(mode==GL_SERVER_MODE) {
114757c478bd9Sstevel@tonic-gate     if(_gl_raw_io(gl, 1))
114767c478bd9Sstevel@tonic-gate       return 1;
114777c478bd9Sstevel@tonic-gate   };
114787c478bd9Sstevel@tonic-gate   return 0;
114797c478bd9Sstevel@tonic-gate }
114807c478bd9Sstevel@tonic-gate 
114817c478bd9Sstevel@tonic-gate /*.......................................................................
114827c478bd9Sstevel@tonic-gate  * Return extra information (ie. in addition to that provided by errno)
114837c478bd9Sstevel@tonic-gate  * about the last error to occur in either gl_get_line() or its
114847c478bd9Sstevel@tonic-gate  * associated public functions.
114857c478bd9Sstevel@tonic-gate  *
114867c478bd9Sstevel@tonic-gate  * Input:
114877c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
114887c478bd9Sstevel@tonic-gate  * Input/Output:
114897c478bd9Sstevel@tonic-gate  *  buff          char *  An optional output buffer. Note that if the
114907c478bd9Sstevel@tonic-gate  *                        calling application calls any gl_*()
114917c478bd9Sstevel@tonic-gate  *                        functions from signal handlers, it should
114927c478bd9Sstevel@tonic-gate  *                        provide a buffer here, so that a copy of
114937c478bd9Sstevel@tonic-gate  *                        the latest error message can safely be made
114947c478bd9Sstevel@tonic-gate  *                        while signals are blocked.
114957c478bd9Sstevel@tonic-gate  *  n           size_t    The allocated size of buff[].
114967c478bd9Sstevel@tonic-gate  * Output:
114977c478bd9Sstevel@tonic-gate  *  return  const char *  A pointer to the error message. This will
114987c478bd9Sstevel@tonic-gate  *                        be the buff argument, unless buff==NULL, in
114997c478bd9Sstevel@tonic-gate  *                        which case it will be a pointer to an
115007c478bd9Sstevel@tonic-gate  *                        internal error buffer. In the latter case,
115017c478bd9Sstevel@tonic-gate  *                        note that the contents of the returned buffer
115027c478bd9Sstevel@tonic-gate  *                        will change on subsequent calls to any gl_*()
115037c478bd9Sstevel@tonic-gate  *                        functions.
115047c478bd9Sstevel@tonic-gate  */
115057c478bd9Sstevel@tonic-gate const char *gl_error_message(GetLine *gl, char *buff, size_t n)
115067c478bd9Sstevel@tonic-gate {
115077c478bd9Sstevel@tonic-gate   if(!gl) {
115087c478bd9Sstevel@tonic-gate     static const char *msg = "NULL GetLine argument";
115097c478bd9Sstevel@tonic-gate     if(buff) {
115107c478bd9Sstevel@tonic-gate       strncpy(buff, msg, n);
115117c478bd9Sstevel@tonic-gate       buff[n-1] = '\0';
115127c478bd9Sstevel@tonic-gate     } else {
115137c478bd9Sstevel@tonic-gate       return msg;
115147c478bd9Sstevel@tonic-gate     };
115157c478bd9Sstevel@tonic-gate   } else if(buff) {
115167c478bd9Sstevel@tonic-gate     sigset_t oldset; /* The signals that were blocked on entry to this block */
115177c478bd9Sstevel@tonic-gate /*
115187c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
115197c478bd9Sstevel@tonic-gate  */
115207c478bd9Sstevel@tonic-gate     gl_mask_signals(gl, &oldset);
115217c478bd9Sstevel@tonic-gate /*
115227c478bd9Sstevel@tonic-gate  * Copy the error message into the specified buffer.
115237c478bd9Sstevel@tonic-gate  */
115247c478bd9Sstevel@tonic-gate     if(buff && n > 0) {
115257c478bd9Sstevel@tonic-gate       strncpy(buff, _err_get_msg(gl->err), n);
115267c478bd9Sstevel@tonic-gate       buff[n-1] = '\0';
115277c478bd9Sstevel@tonic-gate     };
115287c478bd9Sstevel@tonic-gate /*
115297c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
115307c478bd9Sstevel@tonic-gate  */
115317c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &oldset);
115327c478bd9Sstevel@tonic-gate   } else {
115337c478bd9Sstevel@tonic-gate     return _err_get_msg(gl->err);
115347c478bd9Sstevel@tonic-gate   };
115357c478bd9Sstevel@tonic-gate   return buff;
115367c478bd9Sstevel@tonic-gate }
115377c478bd9Sstevel@tonic-gate 
115387c478bd9Sstevel@tonic-gate /*.......................................................................
115397c478bd9Sstevel@tonic-gate  * Return the signal mask used by gl_get_line(). This is the set of
115407c478bd9Sstevel@tonic-gate  * signals that gl_get_line() is currently configured to trap.
115417c478bd9Sstevel@tonic-gate  *
115427c478bd9Sstevel@tonic-gate  * Input:
115437c478bd9Sstevel@tonic-gate  *  gl         GetLine *  The resource object of gl_get_line().
115447c478bd9Sstevel@tonic-gate  * Input/Output:
115457c478bd9Sstevel@tonic-gate  *  set       sigset_t *  The set of signals will be returned in *set,
115467c478bd9Sstevel@tonic-gate  *                        in the form of a signal process mask, as
115477c478bd9Sstevel@tonic-gate  *                        used by sigaction(), sigprocmask(),
115487c478bd9Sstevel@tonic-gate  *                        sigpending(), sigsuspend(), sigsetjmp() and
115497c478bd9Sstevel@tonic-gate  *                        other standard POSIX signal-aware
115507c478bd9Sstevel@tonic-gate  *                        functions.
115517c478bd9Sstevel@tonic-gate  * Output:
115527c478bd9Sstevel@tonic-gate  *  return         int    0 - OK.
115537c478bd9Sstevel@tonic-gate  *                        1 - Error (examine errno for reason).
115547c478bd9Sstevel@tonic-gate  */
115557c478bd9Sstevel@tonic-gate int gl_list_signals(GetLine *gl, sigset_t *set)
115567c478bd9Sstevel@tonic-gate {
115577c478bd9Sstevel@tonic-gate /*
115587c478bd9Sstevel@tonic-gate  * Check the arguments.
115597c478bd9Sstevel@tonic-gate  */
115607c478bd9Sstevel@tonic-gate   if(!gl || !set) {
115617c478bd9Sstevel@tonic-gate     if(gl)
115627c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
115637c478bd9Sstevel@tonic-gate     errno = EINVAL;
115647c478bd9Sstevel@tonic-gate     return 1;
115657c478bd9Sstevel@tonic-gate   };
115667c478bd9Sstevel@tonic-gate /*
115677c478bd9Sstevel@tonic-gate  * Copy the signal mask into *set.
115687c478bd9Sstevel@tonic-gate  */
115697c478bd9Sstevel@tonic-gate   memcpy(set, &gl->all_signal_set, sizeof(*set));
115707c478bd9Sstevel@tonic-gate   return 0;
115717c478bd9Sstevel@tonic-gate }
115727c478bd9Sstevel@tonic-gate 
115737c478bd9Sstevel@tonic-gate /*.......................................................................
115747c478bd9Sstevel@tonic-gate  * By default, gl_get_line() doesn't trap signals that are blocked
115757c478bd9Sstevel@tonic-gate  * when it is called. This default can be changed either on a
115767c478bd9Sstevel@tonic-gate  * per-signal basis by calling gl_trap_signal(), or on a global basis
115777c478bd9Sstevel@tonic-gate  * by calling this function. What this function does is add the
115787c478bd9Sstevel@tonic-gate  * GLS_UNBLOCK_SIG flag to all signals that are currently configured
115797c478bd9Sstevel@tonic-gate  * to be trapped by gl_get_line(), such that when subsequent calls to
115807c478bd9Sstevel@tonic-gate  * gl_get_line() wait for I/O, these signals are temporarily
115817c478bd9Sstevel@tonic-gate  * unblocked. This behavior is useful in non-blocking server-I/O mode,
115827c478bd9Sstevel@tonic-gate  * where it is used to avoid race conditions related to handling these
115837c478bd9Sstevel@tonic-gate  * signals externally to gl_get_line(). See the demonstration code in
115847c478bd9Sstevel@tonic-gate  * demo3.c, or the gl_handle_signal() man page for further
115857c478bd9Sstevel@tonic-gate  * information.
115867c478bd9Sstevel@tonic-gate  *
115877c478bd9Sstevel@tonic-gate  * Input:
115887c478bd9Sstevel@tonic-gate  *  gl         GetLine *   The resource object of gl_get_line().
115897c478bd9Sstevel@tonic-gate  */
115907c478bd9Sstevel@tonic-gate void gl_catch_blocked(GetLine *gl)
115917c478bd9Sstevel@tonic-gate {
115927c478bd9Sstevel@tonic-gate   sigset_t oldset;    /* The process signal mask to restore */
115937c478bd9Sstevel@tonic-gate   GlSignalNode *sig;  /* A signal node in gl->sigs */
115947c478bd9Sstevel@tonic-gate /*
115957c478bd9Sstevel@tonic-gate  * Check the arguments.
115967c478bd9Sstevel@tonic-gate  */
115977c478bd9Sstevel@tonic-gate   if(!gl) {
115987c478bd9Sstevel@tonic-gate     errno = EINVAL;
115997c478bd9Sstevel@tonic-gate     return;
116007c478bd9Sstevel@tonic-gate   };
116017c478bd9Sstevel@tonic-gate /*
116027c478bd9Sstevel@tonic-gate  * Temporarily block all signals while we modify the contents of gl.
116037c478bd9Sstevel@tonic-gate  */
116047c478bd9Sstevel@tonic-gate   gl_mask_signals(gl, &oldset);
116057c478bd9Sstevel@tonic-gate /*
116067c478bd9Sstevel@tonic-gate  * Add the GLS_UNBLOCK_SIG flag to all configured signals.
116077c478bd9Sstevel@tonic-gate  */
116087c478bd9Sstevel@tonic-gate   for(sig=gl->sigs; sig; sig=sig->next)
116097c478bd9Sstevel@tonic-gate     sig->flags |= GLS_UNBLOCK_SIG;
116107c478bd9Sstevel@tonic-gate /*
116117c478bd9Sstevel@tonic-gate  * Restore the process signal mask that was superseded by the call
116127c478bd9Sstevel@tonic-gate  * to gl_mask_signals().
116137c478bd9Sstevel@tonic-gate  */
116147c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
116157c478bd9Sstevel@tonic-gate   return;
116167c478bd9Sstevel@tonic-gate }
116177c478bd9Sstevel@tonic-gate 
116187c478bd9Sstevel@tonic-gate /*.......................................................................
116197c478bd9Sstevel@tonic-gate  * Respond to signals who's default effects have important
116207c478bd9Sstevel@tonic-gate  * consequences to gl_get_line(). This is intended for use in
116217c478bd9Sstevel@tonic-gate  * non-blocking server mode, where the external event loop is
116227c478bd9Sstevel@tonic-gate  * responsible for catching signals. Signals that are handled include
116237c478bd9Sstevel@tonic-gate  * those that by default terminate or suspend the process, and the
116247c478bd9Sstevel@tonic-gate  * signal that indicates that the terminal size has changed. Note that
116257c478bd9Sstevel@tonic-gate  * this function is not signal safe and should thus not be called from
116267c478bd9Sstevel@tonic-gate  * a signal handler itself. See the gl_io_mode() man page for how it
116277c478bd9Sstevel@tonic-gate  * should be used.
116287c478bd9Sstevel@tonic-gate  *
116297c478bd9Sstevel@tonic-gate  * In the case of signals that by default terminate or suspend
116307c478bd9Sstevel@tonic-gate  * processes, command-line editing will be suspended, the terminal
116317c478bd9Sstevel@tonic-gate  * returned to a usable state, then the default disposition of the
116327c478bd9Sstevel@tonic-gate  * signal restored and the signal resent, in order to suspend or
116337c478bd9Sstevel@tonic-gate  * terminate the process.  If the process subsequently resumes,
116347c478bd9Sstevel@tonic-gate  * command-line editing is resumed.
116357c478bd9Sstevel@tonic-gate  *
116367c478bd9Sstevel@tonic-gate  * In the case of signals that indicate that the terminal has been
116377c478bd9Sstevel@tonic-gate  * resized, the new size will be queried, and any input line that is
116387c478bd9Sstevel@tonic-gate  * being edited will be redrawn to fit the new dimensions of the
116397c478bd9Sstevel@tonic-gate  * terminal.
116407c478bd9Sstevel@tonic-gate  *
116417c478bd9Sstevel@tonic-gate  * Input:
116427c478bd9Sstevel@tonic-gate  *  signo    int    The number of the signal to respond to.
116437c478bd9Sstevel@tonic-gate  *  gl   GetLine *  The first element of an array of 'ngl' GetLine
116447c478bd9Sstevel@tonic-gate  *                  objects.
116457c478bd9Sstevel@tonic-gate  *  ngl      int    The number of elements in the gl[] array. Normally
116467c478bd9Sstevel@tonic-gate  *                  this will be one.
116477c478bd9Sstevel@tonic-gate  */
116487c478bd9Sstevel@tonic-gate void gl_handle_signal(int signo, GetLine *gl, int ngl)
116497c478bd9Sstevel@tonic-gate {
116507c478bd9Sstevel@tonic-gate   int attr;             /* The attributes of the specified signal */
116517c478bd9Sstevel@tonic-gate   sigset_t all_signals; /* The set of trappable signals */
116527c478bd9Sstevel@tonic-gate   sigset_t oldset;      /* The process signal mask to restore */
116537c478bd9Sstevel@tonic-gate   int i;
116547c478bd9Sstevel@tonic-gate /*
116557c478bd9Sstevel@tonic-gate  * NULL operation?
116567c478bd9Sstevel@tonic-gate  */
116577c478bd9Sstevel@tonic-gate   if(ngl < 1 || !gl)
116587c478bd9Sstevel@tonic-gate     return;
116597c478bd9Sstevel@tonic-gate /*
116607c478bd9Sstevel@tonic-gate  * Look up the default attributes of the specified signal.
116617c478bd9Sstevel@tonic-gate  */
116627c478bd9Sstevel@tonic-gate   attr = gl_classify_signal(signo);
116637c478bd9Sstevel@tonic-gate /*
116647c478bd9Sstevel@tonic-gate  * If the signal isn't known, we are done.
116657c478bd9Sstevel@tonic-gate  */
116667c478bd9Sstevel@tonic-gate   if(!attr)
116677c478bd9Sstevel@tonic-gate     return;
116687c478bd9Sstevel@tonic-gate /*
116697c478bd9Sstevel@tonic-gate  * Temporarily block all signals while we modify the gl objects.
116707c478bd9Sstevel@tonic-gate  */
116717c478bd9Sstevel@tonic-gate   gl_list_trappable_signals(&all_signals);
116727c478bd9Sstevel@tonic-gate   sigprocmask(SIG_BLOCK, &all_signals, &oldset);
116737c478bd9Sstevel@tonic-gate /*
116747c478bd9Sstevel@tonic-gate  * Suspend or terminate the process?
116757c478bd9Sstevel@tonic-gate  */
116767c478bd9Sstevel@tonic-gate   if(attr & (GLSA_SUSP | GLSA_TERM)) {
116777c478bd9Sstevel@tonic-gate     gl_suspend_process(signo, gl, ngl);
116787c478bd9Sstevel@tonic-gate /*
116797c478bd9Sstevel@tonic-gate  * Resize the terminal? Note that ioctl() isn't defined as being
116807c478bd9Sstevel@tonic-gate  * signal safe, so we can't call gl_update_size() here. However,
116817c478bd9Sstevel@tonic-gate  * gl_get_line() checks for resizes on each call, so simply arrange
116827c478bd9Sstevel@tonic-gate  * for the application's event loop to call gl_get_line() as soon as
116837c478bd9Sstevel@tonic-gate  * it becomes possible to write to the terminal. Note that if the
116847c478bd9Sstevel@tonic-gate  * caller is calling select() or poll when this happens, these functions
116857c478bd9Sstevel@tonic-gate  * get interrupted, since a signal has been caught.
116867c478bd9Sstevel@tonic-gate  */
116877c478bd9Sstevel@tonic-gate   } else if(attr & GLSA_SIZE) {
116887c478bd9Sstevel@tonic-gate     for(i=0; i<ngl; i++)
116897c478bd9Sstevel@tonic-gate       gl[i].pending_io = GLP_WRITE;
116907c478bd9Sstevel@tonic-gate   };
116917c478bd9Sstevel@tonic-gate /*
116927c478bd9Sstevel@tonic-gate  * Restore the process signal mask that was superseded by the call
116937c478bd9Sstevel@tonic-gate  * to gl_mask_signals().
116947c478bd9Sstevel@tonic-gate  */
116957c478bd9Sstevel@tonic-gate   sigprocmask(SIG_SETMASK, &oldset, NULL);
116967c478bd9Sstevel@tonic-gate   return;
116977c478bd9Sstevel@tonic-gate }
116987c478bd9Sstevel@tonic-gate 
116997c478bd9Sstevel@tonic-gate /*.......................................................................
117007c478bd9Sstevel@tonic-gate  * Respond to an externally caught process suspension or
117017c478bd9Sstevel@tonic-gate  * termination signal.
117027c478bd9Sstevel@tonic-gate  *
117037c478bd9Sstevel@tonic-gate  * After restoring the terminal to a usable state, suspend or
117047c478bd9Sstevel@tonic-gate  * terminate the calling process, using the original signal with its
117057c478bd9Sstevel@tonic-gate  * default disposition restored to do so. If the process subsequently
117067c478bd9Sstevel@tonic-gate  * resumes, resume editing any input lines that were being entered.
117077c478bd9Sstevel@tonic-gate  *
117087c478bd9Sstevel@tonic-gate  * Input:
117097c478bd9Sstevel@tonic-gate  *  signo    int    The signal number to suspend the process with. Note
117107c478bd9Sstevel@tonic-gate  *                  that the default disposition of this signal will be
117117c478bd9Sstevel@tonic-gate  *                  restored before the signal is sent, so provided
117127c478bd9Sstevel@tonic-gate  *                  that the default disposition of this signal is to
117137c478bd9Sstevel@tonic-gate  *                  either suspend or terminate the application,
117147c478bd9Sstevel@tonic-gate  *                  that is what wil happen, regardless of what signal
117157c478bd9Sstevel@tonic-gate  *                  handler is currently assigned to this signal.
117167c478bd9Sstevel@tonic-gate  *  gl   GetLine *  The first element of an array of 'ngl' GetLine objects
117177c478bd9Sstevel@tonic-gate  *                  whose terminals should be restored to a sane state
117187c478bd9Sstevel@tonic-gate  *                  while the application is suspended.
117197c478bd9Sstevel@tonic-gate  *  ngl      int    The number of elements in the gl[] array.
117207c478bd9Sstevel@tonic-gate  */
117217c478bd9Sstevel@tonic-gate static void gl_suspend_process(int signo, GetLine *gl, int ngl)
117227c478bd9Sstevel@tonic-gate {
117237c478bd9Sstevel@tonic-gate   sigset_t only_signo;          /* A signal set containing just signo */
117247c478bd9Sstevel@tonic-gate   sigset_t oldset;              /* The signal mask on entry to this function */
117257c478bd9Sstevel@tonic-gate   sigset_t all_signals;         /* A signal set containing all signals */
117267c478bd9Sstevel@tonic-gate   struct sigaction old_action;  /* The current signal handler */
117277c478bd9Sstevel@tonic-gate   struct sigaction def_action;  /* The default signal handler */
117287c478bd9Sstevel@tonic-gate   int i;
117297c478bd9Sstevel@tonic-gate /*
117307c478bd9Sstevel@tonic-gate  * Create a signal mask containing the signal that was trapped.
117317c478bd9Sstevel@tonic-gate  */
117327c478bd9Sstevel@tonic-gate   sigemptyset(&only_signo);
117337c478bd9Sstevel@tonic-gate   sigaddset(&only_signo, signo);
117347c478bd9Sstevel@tonic-gate /*
117357c478bd9Sstevel@tonic-gate  * Temporarily block all signals.
117367c478bd9Sstevel@tonic-gate  */
117377c478bd9Sstevel@tonic-gate   gl_list_trappable_signals(&all_signals);
117387c478bd9Sstevel@tonic-gate   sigprocmask(SIG_BLOCK, &all_signals, &oldset);
117397c478bd9Sstevel@tonic-gate /*
117407c478bd9Sstevel@tonic-gate  * Restore the terminal to a usable state.
117417c478bd9Sstevel@tonic-gate  */
117427c478bd9Sstevel@tonic-gate   for(i=0; i<ngl; i++) {
117437c478bd9Sstevel@tonic-gate     GetLine *obj = gl + i;
117447c478bd9Sstevel@tonic-gate     if(obj->raw_mode) {
117457c478bd9Sstevel@tonic-gate       _gl_normal_io(obj);
117467c478bd9Sstevel@tonic-gate       if(!obj->raw_mode)        /* Check that gl_normal_io() succeded */
117477c478bd9Sstevel@tonic-gate 	obj->raw_mode = -1;     /* Flag raw mode as needing to be restored */
117487c478bd9Sstevel@tonic-gate     };
117497c478bd9Sstevel@tonic-gate   };
117507c478bd9Sstevel@tonic-gate /*
117517c478bd9Sstevel@tonic-gate  * Restore the system default disposition of the signal that we
117527c478bd9Sstevel@tonic-gate  * caught.  Note that this signal is currently blocked. Note that we
117537c478bd9Sstevel@tonic-gate  * don't use memcpy() to copy signal sets here, because the signal safety
117547c478bd9Sstevel@tonic-gate  * of memcpy() is undefined.
117557c478bd9Sstevel@tonic-gate  */
117567c478bd9Sstevel@tonic-gate   def_action.sa_handler = SIG_DFL;
117577c478bd9Sstevel@tonic-gate   {
117587c478bd9Sstevel@tonic-gate     char *orig = (char *) &all_signals;
117597c478bd9Sstevel@tonic-gate     char *dest = (char *) &def_action.sa_mask;
117607c478bd9Sstevel@tonic-gate     for(i=0; i<sizeof(sigset_t); i++)
117617c478bd9Sstevel@tonic-gate       *dest++ = *orig++;
117627c478bd9Sstevel@tonic-gate   };
117637c478bd9Sstevel@tonic-gate   sigaction(signo, &def_action, &old_action);
117647c478bd9Sstevel@tonic-gate /*
117657c478bd9Sstevel@tonic-gate  * Resend the signal, and unblock it so that it gets delivered to
117667c478bd9Sstevel@tonic-gate  * the application. This will invoke the default action of this signal.
117677c478bd9Sstevel@tonic-gate  */
117687c478bd9Sstevel@tonic-gate   raise(signo);
117697c478bd9Sstevel@tonic-gate   sigprocmask(SIG_UNBLOCK, &only_signo, NULL);
117707c478bd9Sstevel@tonic-gate /*
117717c478bd9Sstevel@tonic-gate  * If the process resumes again, it will resume here.
117727c478bd9Sstevel@tonic-gate  * Block the signal again, then restore our signal handler.
117737c478bd9Sstevel@tonic-gate  */
117747c478bd9Sstevel@tonic-gate   sigprocmask(SIG_BLOCK, &only_signo, NULL);
117757c478bd9Sstevel@tonic-gate   sigaction(signo, &old_action, NULL);
117767c478bd9Sstevel@tonic-gate /*
117777c478bd9Sstevel@tonic-gate  * Resume command-line editing.
117787c478bd9Sstevel@tonic-gate  */
117797c478bd9Sstevel@tonic-gate   for(i=0; i<ngl; i++) {
117807c478bd9Sstevel@tonic-gate     GetLine *obj = gl + i;
117817c478bd9Sstevel@tonic-gate     if(obj->raw_mode == -1) { /* Did we flag the need to restore raw mode? */
117827c478bd9Sstevel@tonic-gate       obj->raw_mode = 0;      /* gl_raw_io() does nothing unless raw_mode==0 */
117837c478bd9Sstevel@tonic-gate       _gl_raw_io(obj, 1);
117847c478bd9Sstevel@tonic-gate     };
117857c478bd9Sstevel@tonic-gate   };
117867c478bd9Sstevel@tonic-gate /*
117877c478bd9Sstevel@tonic-gate  * Restore the process signal mask to the way it was when this function
117887c478bd9Sstevel@tonic-gate  * was called.
117897c478bd9Sstevel@tonic-gate  */
117907c478bd9Sstevel@tonic-gate   sigprocmask(SIG_SETMASK, &oldset, NULL);
117917c478bd9Sstevel@tonic-gate   return;
117927c478bd9Sstevel@tonic-gate }
117937c478bd9Sstevel@tonic-gate 
117947c478bd9Sstevel@tonic-gate /*.......................................................................
117957c478bd9Sstevel@tonic-gate  * Return the information about the default attributes of a given signal.
117967c478bd9Sstevel@tonic-gate  * The attributes that are returned are as defined by the standards that
117977c478bd9Sstevel@tonic-gate  * created them, including POSIX, SVR4 and 4.3+BSD, and are taken from a
117987c478bd9Sstevel@tonic-gate  * table in Richard Steven's book, "Advanced programming in the UNIX
117997c478bd9Sstevel@tonic-gate  * environment".
118007c478bd9Sstevel@tonic-gate  *
118017c478bd9Sstevel@tonic-gate  * Input:
118027c478bd9Sstevel@tonic-gate  *  signo        int   The signal to be characterized.
118037c478bd9Sstevel@tonic-gate  * Output:
118047c478bd9Sstevel@tonic-gate  *  return       int   A bitwise union of GlSigAttr enumerators, or 0
118057c478bd9Sstevel@tonic-gate  *                     if the signal isn't known.
118067c478bd9Sstevel@tonic-gate  */
118077c478bd9Sstevel@tonic-gate static int gl_classify_signal(int signo)
118087c478bd9Sstevel@tonic-gate {
118097c478bd9Sstevel@tonic-gate   int i;
118107c478bd9Sstevel@tonic-gate /*
118117c478bd9Sstevel@tonic-gate  * Search for the specified signal in the gl_signal_list[] table.
118127c478bd9Sstevel@tonic-gate  */
118137c478bd9Sstevel@tonic-gate   for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) {
118147c478bd9Sstevel@tonic-gate     const struct GlDefSignal *sig = gl_signal_list + i;
118157c478bd9Sstevel@tonic-gate     if(sig->signo == signo)
118167c478bd9Sstevel@tonic-gate       return sig->attr;
118177c478bd9Sstevel@tonic-gate   };
118187c478bd9Sstevel@tonic-gate /*
118197c478bd9Sstevel@tonic-gate  * Signal not known.
118207c478bd9Sstevel@tonic-gate  */
118217c478bd9Sstevel@tonic-gate   return 0;
118227c478bd9Sstevel@tonic-gate }
118237c478bd9Sstevel@tonic-gate 
118247c478bd9Sstevel@tonic-gate /*.......................................................................
118257c478bd9Sstevel@tonic-gate  * When in non-blocking server mode, this function can be used to abandon
118267c478bd9Sstevel@tonic-gate  * the current incompletely entered input line, and prepare to start
118277c478bd9Sstevel@tonic-gate  * editing a new line on the next call to gl_get_line().
118287c478bd9Sstevel@tonic-gate  *
118297c478bd9Sstevel@tonic-gate  * Input:
118307c478bd9Sstevel@tonic-gate  *  gl      GetLine *  The line editor resource object.
118317c478bd9Sstevel@tonic-gate  */
118327c478bd9Sstevel@tonic-gate void gl_abandon_line(GetLine *gl)
118337c478bd9Sstevel@tonic-gate {
118347c478bd9Sstevel@tonic-gate   sigset_t oldset;    /* The process signal mask to restore */
118357c478bd9Sstevel@tonic-gate /*
118367c478bd9Sstevel@tonic-gate  * Check the arguments.
118377c478bd9Sstevel@tonic-gate  */
118387c478bd9Sstevel@tonic-gate   if(!gl) {
118397c478bd9Sstevel@tonic-gate     errno = EINVAL;
118407c478bd9Sstevel@tonic-gate     return;
118417c478bd9Sstevel@tonic-gate   };
118427c478bd9Sstevel@tonic-gate /*
118437c478bd9Sstevel@tonic-gate  * Temporarily block all signals while we modify the contents of gl.
118447c478bd9Sstevel@tonic-gate  */
118457c478bd9Sstevel@tonic-gate   gl_mask_signals(gl, &oldset);
118467c478bd9Sstevel@tonic-gate /*
118477c478bd9Sstevel@tonic-gate  * Mark the input line as discarded.
118487c478bd9Sstevel@tonic-gate  */
118497c478bd9Sstevel@tonic-gate   _gl_abandon_line(gl);
118507c478bd9Sstevel@tonic-gate /*
118517c478bd9Sstevel@tonic-gate  * Restore the process signal mask that was superseded by the call
118527c478bd9Sstevel@tonic-gate  * to gl_mask_signals().
118537c478bd9Sstevel@tonic-gate  */
118547c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
118557c478bd9Sstevel@tonic-gate   return;
118567c478bd9Sstevel@tonic-gate }
118577c478bd9Sstevel@tonic-gate 
118587c478bd9Sstevel@tonic-gate /*.......................................................................
118597c478bd9Sstevel@tonic-gate  * This is the private body of the gl_abandon_line() function. It
118607c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
118617c478bd9Sstevel@tonic-gate  * delivery of signals.
118627c478bd9Sstevel@tonic-gate  */
118637c478bd9Sstevel@tonic-gate void _gl_abandon_line(GetLine *gl)
118647c478bd9Sstevel@tonic-gate {
118657c478bd9Sstevel@tonic-gate   gl->endline = 1;
118667c478bd9Sstevel@tonic-gate   gl->pending_io = GLP_WRITE;
118677c478bd9Sstevel@tonic-gate }
118687c478bd9Sstevel@tonic-gate 
118697c478bd9Sstevel@tonic-gate /*.......................................................................
118707c478bd9Sstevel@tonic-gate  * How many characters are needed to write a number as an octal string?
118717c478bd9Sstevel@tonic-gate  *
118727c478bd9Sstevel@tonic-gate  * Input:
118737c478bd9Sstevel@tonic-gate  *  num   unsigned   The to be measured.
118747c478bd9Sstevel@tonic-gate  * Output:
118757c478bd9Sstevel@tonic-gate  *  return     int   The number of characters needed.
118767c478bd9Sstevel@tonic-gate  */
118777c478bd9Sstevel@tonic-gate static int gl_octal_width(unsigned num)
118787c478bd9Sstevel@tonic-gate {
118797c478bd9Sstevel@tonic-gate   int n;    /* The number of characters needed to render the number */
118807c478bd9Sstevel@tonic-gate   for(n=1; num /= 8; n++)
118817c478bd9Sstevel@tonic-gate     ;
118827c478bd9Sstevel@tonic-gate   return n;
118837c478bd9Sstevel@tonic-gate }
118847c478bd9Sstevel@tonic-gate 
118857c478bd9Sstevel@tonic-gate /*.......................................................................
118867c478bd9Sstevel@tonic-gate  * Tell gl_get_line() the current terminal size. Note that this is only
118877c478bd9Sstevel@tonic-gate  * necessary on systems where changes in terminal size aren't reported
118887c478bd9Sstevel@tonic-gate  * via SIGWINCH.
118897c478bd9Sstevel@tonic-gate  *
118907c478bd9Sstevel@tonic-gate  * Input:
118917c478bd9Sstevel@tonic-gate  *  gl            GetLine *  The resource object of gl_get_line().
118927c478bd9Sstevel@tonic-gate  *  ncolumn           int    The number of columns in the terminal.
118937c478bd9Sstevel@tonic-gate  *  nline             int    The number of lines in the terminal.
118947c478bd9Sstevel@tonic-gate  * Output:
118957c478bd9Sstevel@tonic-gate  *  return            int    0 - OK.
118967c478bd9Sstevel@tonic-gate  *                           1 - Error.
118977c478bd9Sstevel@tonic-gate  */
118987c478bd9Sstevel@tonic-gate int gl_set_term_size(GetLine *gl, int ncolumn, int nline)
118997c478bd9Sstevel@tonic-gate {
119007c478bd9Sstevel@tonic-gate   sigset_t oldset;      /* The signals that were blocked on entry */
119017c478bd9Sstevel@tonic-gate                         /*  to this function */
119027c478bd9Sstevel@tonic-gate   int status;           /* The return status */
119037c478bd9Sstevel@tonic-gate /*
119047c478bd9Sstevel@tonic-gate  * Block all signals while accessing gl.
119057c478bd9Sstevel@tonic-gate  */
119067c478bd9Sstevel@tonic-gate   gl_mask_signals(gl, &oldset);
119077c478bd9Sstevel@tonic-gate /*
119087c478bd9Sstevel@tonic-gate  * Install the new terminal size.
119097c478bd9Sstevel@tonic-gate  */
119107c478bd9Sstevel@tonic-gate   status = _gl_set_term_size(gl, ncolumn, nline);
119117c478bd9Sstevel@tonic-gate /*
119127c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
119137c478bd9Sstevel@tonic-gate  */
119147c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
119157c478bd9Sstevel@tonic-gate   return status;
119167c478bd9Sstevel@tonic-gate }
119177c478bd9Sstevel@tonic-gate 
119187c478bd9Sstevel@tonic-gate /*.......................................................................
119197c478bd9Sstevel@tonic-gate  * This is the private body of the gl_set_term_size() function. It
119207c478bd9Sstevel@tonic-gate  * assumes that the caller has checked its arguments and blocked the
119217c478bd9Sstevel@tonic-gate  * delivery of signals.
119227c478bd9Sstevel@tonic-gate  */
119237c478bd9Sstevel@tonic-gate static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline)
119247c478bd9Sstevel@tonic-gate {
119257c478bd9Sstevel@tonic-gate /*
119267c478bd9Sstevel@tonic-gate  * Check the arguments.
119277c478bd9Sstevel@tonic-gate  */
119287c478bd9Sstevel@tonic-gate   if(!gl) {
119297c478bd9Sstevel@tonic-gate     errno = EINVAL;
119307c478bd9Sstevel@tonic-gate     return 1;
119317c478bd9Sstevel@tonic-gate   };
119327c478bd9Sstevel@tonic-gate /*
119337c478bd9Sstevel@tonic-gate  * Reject non-sensical dimensions.
119347c478bd9Sstevel@tonic-gate  */
119357c478bd9Sstevel@tonic-gate   if(ncolumn <= 0 || nline <= 0) {
119367c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, "Invalid terminal size", END_ERR_MSG);
119377c478bd9Sstevel@tonic-gate     errno = EINVAL;
119387c478bd9Sstevel@tonic-gate     return 1;
119397c478bd9Sstevel@tonic-gate   };
119407c478bd9Sstevel@tonic-gate /*
119417c478bd9Sstevel@tonic-gate  * Install the new dimensions in the terminal driver if possible, so
119427c478bd9Sstevel@tonic-gate  * that future calls to gl_query_size() get the new value.
119437c478bd9Sstevel@tonic-gate  */
119447c478bd9Sstevel@tonic-gate #ifdef TIOCSWINSZ
119457c478bd9Sstevel@tonic-gate   if(gl->is_term) {
119467c478bd9Sstevel@tonic-gate     struct winsize size;
119477c478bd9Sstevel@tonic-gate     size.ws_row = nline;
119487c478bd9Sstevel@tonic-gate     size.ws_col = ncolumn;
119497c478bd9Sstevel@tonic-gate     size.ws_xpixel = 0;
119507c478bd9Sstevel@tonic-gate     size.ws_ypixel = 0;
119517c478bd9Sstevel@tonic-gate     if(ioctl(gl->output_fd, TIOCSWINSZ, &size) == -1) {
119527c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "Can't change terminal size", END_ERR_MSG);
119537c478bd9Sstevel@tonic-gate       return 1;
119547c478bd9Sstevel@tonic-gate     };
119557c478bd9Sstevel@tonic-gate   };
119567c478bd9Sstevel@tonic-gate #endif
119577c478bd9Sstevel@tonic-gate /*
119587c478bd9Sstevel@tonic-gate  * If an input line is in the process of being edited, redisplay it to
119597c478bd9Sstevel@tonic-gate  * accomodate the new dimensions, and record the new dimensions in
119607c478bd9Sstevel@tonic-gate  * gl->nline and gl->ncolumn.
119617c478bd9Sstevel@tonic-gate  */
119627c478bd9Sstevel@tonic-gate   return gl_handle_tty_resize(gl, ncolumn, nline);
119637c478bd9Sstevel@tonic-gate }
119647c478bd9Sstevel@tonic-gate 
119657c478bd9Sstevel@tonic-gate /*.......................................................................
119667c478bd9Sstevel@tonic-gate  * Record a character in the input line buffer at a given position.
119677c478bd9Sstevel@tonic-gate  *
119687c478bd9Sstevel@tonic-gate  * Input:
119697c478bd9Sstevel@tonic-gate  *  gl    GetLine *   The resource object of gl_get_line().
119707c478bd9Sstevel@tonic-gate  *  c        char     The character to be recorded.
119717c478bd9Sstevel@tonic-gate  *  bufpos    int     The index in the buffer at which to record the
119727c478bd9Sstevel@tonic-gate  *                    character.
119737c478bd9Sstevel@tonic-gate  * Output:
119747c478bd9Sstevel@tonic-gate  *  return    int     0 - OK.
119757c478bd9Sstevel@tonic-gate  *                    1 - Insufficient room.
119767c478bd9Sstevel@tonic-gate  */
119777c478bd9Sstevel@tonic-gate static int gl_buffer_char(GetLine *gl, char c, int bufpos)
119787c478bd9Sstevel@tonic-gate {
119797c478bd9Sstevel@tonic-gate /*
119807c478bd9Sstevel@tonic-gate  * Guard against buffer overruns.
119817c478bd9Sstevel@tonic-gate  */
119827c478bd9Sstevel@tonic-gate   if(bufpos >= gl->linelen)
119837c478bd9Sstevel@tonic-gate     return 1;
119847c478bd9Sstevel@tonic-gate /*
119857c478bd9Sstevel@tonic-gate  * Record the new character.
119867c478bd9Sstevel@tonic-gate  */
119877c478bd9Sstevel@tonic-gate   gl->line[bufpos] = c;
119887c478bd9Sstevel@tonic-gate /*
119897c478bd9Sstevel@tonic-gate  * If the new character was placed beyond the end of the current input
119907c478bd9Sstevel@tonic-gate  * line, update gl->ntotal to reflect the increased number of characters
119917c478bd9Sstevel@tonic-gate  * that are in gl->line, and terminate the string.
119927c478bd9Sstevel@tonic-gate  */
119937c478bd9Sstevel@tonic-gate   if(bufpos >= gl->ntotal) {
119947c478bd9Sstevel@tonic-gate     gl->ntotal = bufpos+1;
119957c478bd9Sstevel@tonic-gate     gl->line[gl->ntotal] = '\0';
119967c478bd9Sstevel@tonic-gate   };
119977c478bd9Sstevel@tonic-gate   return 0;
119987c478bd9Sstevel@tonic-gate }
119997c478bd9Sstevel@tonic-gate 
120007c478bd9Sstevel@tonic-gate /*.......................................................................
120017c478bd9Sstevel@tonic-gate  * Copy a given string into the input buffer, overwriting the current
120027c478bd9Sstevel@tonic-gate  * contents.
120037c478bd9Sstevel@tonic-gate  *
120047c478bd9Sstevel@tonic-gate  * Input:
120057c478bd9Sstevel@tonic-gate  *  gl    GetLine *   The resource object of gl_get_line().
120067c478bd9Sstevel@tonic-gate  *  s  const char *   The string to be recorded.
120077c478bd9Sstevel@tonic-gate  *  n         int     The number of characters to be copied from the
120087c478bd9Sstevel@tonic-gate  *                    string.
120097c478bd9Sstevel@tonic-gate  *  bufpos    int     The index in the buffer at which to place the
120107c478bd9Sstevel@tonic-gate  *                    the first character of the string.
120117c478bd9Sstevel@tonic-gate  * Output:
120127c478bd9Sstevel@tonic-gate  *  return    int     0 - OK.
120137c478bd9Sstevel@tonic-gate  *                    1 - String truncated to fit.
120147c478bd9Sstevel@tonic-gate  */
120157c478bd9Sstevel@tonic-gate static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos)
120167c478bd9Sstevel@tonic-gate {
120177c478bd9Sstevel@tonic-gate   int nnew;  /* The number of characters actually recorded */
120187c478bd9Sstevel@tonic-gate   int i;
120197c478bd9Sstevel@tonic-gate /*
120207c478bd9Sstevel@tonic-gate  * How many of the characters will fit within the buffer?
120217c478bd9Sstevel@tonic-gate  */
120227c478bd9Sstevel@tonic-gate   nnew = bufpos + n <= gl->linelen ? n : (gl->linelen - bufpos);
120237c478bd9Sstevel@tonic-gate /*
120247c478bd9Sstevel@tonic-gate  * Record the first nnew characters of s[] in the buffer.
120257c478bd9Sstevel@tonic-gate  */
120267c478bd9Sstevel@tonic-gate   for(i=0; i<nnew; i++)
120277c478bd9Sstevel@tonic-gate     gl_buffer_char(gl, s[i], bufpos + i);
120287c478bd9Sstevel@tonic-gate /*
120297c478bd9Sstevel@tonic-gate  * Was the string truncated?
120307c478bd9Sstevel@tonic-gate  */
120317c478bd9Sstevel@tonic-gate   return nnew < n;
120327c478bd9Sstevel@tonic-gate }
120337c478bd9Sstevel@tonic-gate 
120347c478bd9Sstevel@tonic-gate /*.......................................................................
120357c478bd9Sstevel@tonic-gate  * Make room in the input buffer for a string to be inserted. This
120367c478bd9Sstevel@tonic-gate  * involves moving the characters that follow a specified point, towards
120377c478bd9Sstevel@tonic-gate  * the end of the buffer.
120387c478bd9Sstevel@tonic-gate  *
120397c478bd9Sstevel@tonic-gate  * Input:
120407c478bd9Sstevel@tonic-gate  *  gl    GetLine *   The resource object of gl_get_line().
120417c478bd9Sstevel@tonic-gate  *  start     int     The index of the first character to be moved.
120427c478bd9Sstevel@tonic-gate  *  n         int     The width of the gap.
120437c478bd9Sstevel@tonic-gate  * Output:
120447c478bd9Sstevel@tonic-gate  *  return    int     0 - OK.
120457c478bd9Sstevel@tonic-gate  *                    1 - Insufficient room.
120467c478bd9Sstevel@tonic-gate  */
120477c478bd9Sstevel@tonic-gate static int gl_make_gap_in_buffer(GetLine *gl, int start, int n)
120487c478bd9Sstevel@tonic-gate {
120497c478bd9Sstevel@tonic-gate /*
120507c478bd9Sstevel@tonic-gate  * Ensure that the buffer has sufficient space.
120517c478bd9Sstevel@tonic-gate  */
120527c478bd9Sstevel@tonic-gate   if(gl->ntotal + n > gl->linelen)
120537c478bd9Sstevel@tonic-gate     return 1;
120547c478bd9Sstevel@tonic-gate /*
120557c478bd9Sstevel@tonic-gate  * Move everything including and beyond the character at 'start'
120567c478bd9Sstevel@tonic-gate  * towards the end of the string.
120577c478bd9Sstevel@tonic-gate  */
120587c478bd9Sstevel@tonic-gate   memmove(gl->line + start + n, gl->line + start, gl->ntotal - start + 1);
120597c478bd9Sstevel@tonic-gate /*
120607c478bd9Sstevel@tonic-gate  * Update the recorded size of the line.
120617c478bd9Sstevel@tonic-gate  */
120627c478bd9Sstevel@tonic-gate   gl->ntotal += n;
120637c478bd9Sstevel@tonic-gate   return 1;
120647c478bd9Sstevel@tonic-gate }
120657c478bd9Sstevel@tonic-gate 
120667c478bd9Sstevel@tonic-gate /*.......................................................................
120677c478bd9Sstevel@tonic-gate  * Remove a given number of characters from the input buffer. This
120687c478bd9Sstevel@tonic-gate  * involves moving the characters that follow the removed characters to
120697c478bd9Sstevel@tonic-gate  * where the removed sub-string started in the input buffer.
120707c478bd9Sstevel@tonic-gate  *
120717c478bd9Sstevel@tonic-gate  * Input:
120727c478bd9Sstevel@tonic-gate  *  gl    GetLine *   The resource object of gl_get_line().
120737c478bd9Sstevel@tonic-gate  *  start     int     The first character to be removed.
120747c478bd9Sstevel@tonic-gate  *  n         int     The number of characters to remove.
120757c478bd9Sstevel@tonic-gate  */
120767c478bd9Sstevel@tonic-gate static void gl_remove_from_buffer(GetLine *gl, int start, int n)
120777c478bd9Sstevel@tonic-gate {
120787c478bd9Sstevel@tonic-gate   memmove(gl->line + start, gl->line + start + n, gl->ntotal - start - n + 1);
120797c478bd9Sstevel@tonic-gate /*
120807c478bd9Sstevel@tonic-gate  * Update the recorded size of the line.
120817c478bd9Sstevel@tonic-gate  */
120827c478bd9Sstevel@tonic-gate   gl->ntotal -= n;
120837c478bd9Sstevel@tonic-gate }
120847c478bd9Sstevel@tonic-gate 
120857c478bd9Sstevel@tonic-gate /*.......................................................................
120867c478bd9Sstevel@tonic-gate  * Truncate the string in the input line buffer after a given number of
120877c478bd9Sstevel@tonic-gate  * characters.
120887c478bd9Sstevel@tonic-gate  *
120897c478bd9Sstevel@tonic-gate  * Input:
120907c478bd9Sstevel@tonic-gate  *  gl       GetLine *   The resource object of gl_get_line().
120917c478bd9Sstevel@tonic-gate  *  n            int     The new length of the line.
120927c478bd9Sstevel@tonic-gate  * Output:
120937c478bd9Sstevel@tonic-gate  *  return       int     0 - OK.
120947c478bd9Sstevel@tonic-gate  *                       1 - n > gl->linelen.
120957c478bd9Sstevel@tonic-gate  */
120967c478bd9Sstevel@tonic-gate static int gl_truncate_buffer(GetLine *gl, int n)
120977c478bd9Sstevel@tonic-gate {
120987c478bd9Sstevel@tonic-gate   if(n > gl->linelen)
120997c478bd9Sstevel@tonic-gate     return 1;
121007c478bd9Sstevel@tonic-gate   gl->line[n] = '\0';
121017c478bd9Sstevel@tonic-gate   gl->ntotal = n;
121027c478bd9Sstevel@tonic-gate   return 0;
121037c478bd9Sstevel@tonic-gate }
121047c478bd9Sstevel@tonic-gate 
121057c478bd9Sstevel@tonic-gate /*.......................................................................
121067c478bd9Sstevel@tonic-gate  * When the contents of gl->line[] are changed without calling any of the
121077c478bd9Sstevel@tonic-gate  * gl_ buffer manipulation functions, this function must be called to
121087c478bd9Sstevel@tonic-gate  * compute the length of this string, and ancillary information.
121097c478bd9Sstevel@tonic-gate  *
121107c478bd9Sstevel@tonic-gate  * Input:
121117c478bd9Sstevel@tonic-gate  *  gl      GetLine *   The resource object of gl_get_line().
121127c478bd9Sstevel@tonic-gate  */
121137c478bd9Sstevel@tonic-gate static void gl_update_buffer(GetLine *gl)
121147c478bd9Sstevel@tonic-gate {
121157c478bd9Sstevel@tonic-gate   int len;  /* The length of the line */
121167c478bd9Sstevel@tonic-gate /*
121177c478bd9Sstevel@tonic-gate  * Measure the length of the input line.
121187c478bd9Sstevel@tonic-gate  */
121197c478bd9Sstevel@tonic-gate   for(len=0; len <= gl->linelen && gl->line[len]; len++)
121207c478bd9Sstevel@tonic-gate     ;
121217c478bd9Sstevel@tonic-gate /*
121227c478bd9Sstevel@tonic-gate  * Just in case the string wasn't correctly terminated, do so here.
121237c478bd9Sstevel@tonic-gate  */
121247c478bd9Sstevel@tonic-gate   gl->line[len] = '\0';
121257c478bd9Sstevel@tonic-gate /*
121267c478bd9Sstevel@tonic-gate  * Record the number of characters that are now in gl->line[].
121277c478bd9Sstevel@tonic-gate  */
121287c478bd9Sstevel@tonic-gate   gl->ntotal = len;
121297c478bd9Sstevel@tonic-gate /*
121307c478bd9Sstevel@tonic-gate  * Ensure that the cursor stays within the bounds of the modified
121317c478bd9Sstevel@tonic-gate  * input line.
121327c478bd9Sstevel@tonic-gate  */
121337c478bd9Sstevel@tonic-gate   if(gl->buff_curpos > gl->ntotal)
121347c478bd9Sstevel@tonic-gate     gl->buff_curpos = gl->ntotal;
121357c478bd9Sstevel@tonic-gate /*
121367c478bd9Sstevel@tonic-gate  * Arrange for the input line to be redrawn.
121377c478bd9Sstevel@tonic-gate  */
121387c478bd9Sstevel@tonic-gate   gl_queue_redisplay(gl);
121397c478bd9Sstevel@tonic-gate   return;
121407c478bd9Sstevel@tonic-gate }
121417c478bd9Sstevel@tonic-gate 
121427c478bd9Sstevel@tonic-gate /*.......................................................................
121437c478bd9Sstevel@tonic-gate  * Erase the displayed input line, including its prompt, and leave the
121447c478bd9Sstevel@tonic-gate  * cursor where the erased line started. Note that to allow this
121457c478bd9Sstevel@tonic-gate  * function to be used when responding to a terminal resize, this
121467c478bd9Sstevel@tonic-gate  * function is designed to work even if the horizontal cursor position
121477c478bd9Sstevel@tonic-gate  * doesn't match the internally recorded position.
121487c478bd9Sstevel@tonic-gate  *
121497c478bd9Sstevel@tonic-gate  * Input:
121507c478bd9Sstevel@tonic-gate  *  gl      GetLine *   The resource object of gl_get_line().
121517c478bd9Sstevel@tonic-gate  * Output:
121527c478bd9Sstevel@tonic-gate  *  return      int     0 - OK.
121537c478bd9Sstevel@tonic-gate  *                      1 - Error.
121547c478bd9Sstevel@tonic-gate  */
121557c478bd9Sstevel@tonic-gate static int gl_erase_line(GetLine *gl)
121567c478bd9Sstevel@tonic-gate {
121577c478bd9Sstevel@tonic-gate /*
121587c478bd9Sstevel@tonic-gate  * Is a line currently displayed?
121597c478bd9Sstevel@tonic-gate  */
121607c478bd9Sstevel@tonic-gate   if(gl->displayed) {
121617c478bd9Sstevel@tonic-gate /*
121627c478bd9Sstevel@tonic-gate  * Relative the the start of the input line, which terminal line of
121637c478bd9Sstevel@tonic-gate  * the current input line is the cursor currently on?
121647c478bd9Sstevel@tonic-gate  */
121657c478bd9Sstevel@tonic-gate     int cursor_line = gl->term_curpos / gl->ncolumn;
121667c478bd9Sstevel@tonic-gate /*
121677c478bd9Sstevel@tonic-gate  * Move the cursor to the start of the line.
121687c478bd9Sstevel@tonic-gate  */
121697c478bd9Sstevel@tonic-gate     for( ; cursor_line > 0; cursor_line--) {
121707c478bd9Sstevel@tonic-gate       if(gl_print_control_sequence(gl, 1, gl->up))
121717c478bd9Sstevel@tonic-gate 	return 1;
121727c478bd9Sstevel@tonic-gate     };
121737c478bd9Sstevel@tonic-gate     if(gl_print_control_sequence(gl, 1, gl->bol))
121747c478bd9Sstevel@tonic-gate       return 1;
121757c478bd9Sstevel@tonic-gate /*
121767c478bd9Sstevel@tonic-gate  * Clear from the start of the line to the end of the terminal.
121777c478bd9Sstevel@tonic-gate  */
121787c478bd9Sstevel@tonic-gate     if(gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
121797c478bd9Sstevel@tonic-gate       return 1;
121807c478bd9Sstevel@tonic-gate /*
121817c478bd9Sstevel@tonic-gate  * Mark the line as no longer displayed.
121827c478bd9Sstevel@tonic-gate  */
121837c478bd9Sstevel@tonic-gate     gl_line_erased(gl);
121847c478bd9Sstevel@tonic-gate   };
121857c478bd9Sstevel@tonic-gate   return 0;
121867c478bd9Sstevel@tonic-gate }
121877c478bd9Sstevel@tonic-gate 
121887c478bd9Sstevel@tonic-gate /*.......................................................................
121897c478bd9Sstevel@tonic-gate  * Arrange for the input line to be redisplayed by gl_flush_output(),
121907c478bd9Sstevel@tonic-gate  * as soon as the output queue becomes empty.
121917c478bd9Sstevel@tonic-gate  *
121927c478bd9Sstevel@tonic-gate  * Input:
121937c478bd9Sstevel@tonic-gate  *  gl          GetLine *   The resource object of gl_get_line().
121947c478bd9Sstevel@tonic-gate  */
121957c478bd9Sstevel@tonic-gate static void gl_queue_redisplay(GetLine *gl)
121967c478bd9Sstevel@tonic-gate {
121977c478bd9Sstevel@tonic-gate   gl->redisplay = 1;
121987c478bd9Sstevel@tonic-gate   gl->pending_io = GLP_WRITE;
121997c478bd9Sstevel@tonic-gate }
122007c478bd9Sstevel@tonic-gate 
122017c478bd9Sstevel@tonic-gate /*.......................................................................
122027c478bd9Sstevel@tonic-gate  * Truncate the displayed input line starting from the current
122037c478bd9Sstevel@tonic-gate  * terminal cursor position, and leave the cursor at the end of the
122047c478bd9Sstevel@tonic-gate  * truncated line. The input-line buffer is not affected.
122057c478bd9Sstevel@tonic-gate  *
122067c478bd9Sstevel@tonic-gate  * Input:
122077c478bd9Sstevel@tonic-gate  *  gl     GetLine *   The resource object of gl_get_line().
122087c478bd9Sstevel@tonic-gate  * Output:
122097c478bd9Sstevel@tonic-gate  *  return     int     0 - OK.
122107c478bd9Sstevel@tonic-gate  *                     1 - Error.
122117c478bd9Sstevel@tonic-gate  */
122127c478bd9Sstevel@tonic-gate static int gl_truncate_display(GetLine *gl)
122137c478bd9Sstevel@tonic-gate {
122147c478bd9Sstevel@tonic-gate /*
122157c478bd9Sstevel@tonic-gate  * Keep a record of the current terminal cursor position.
122167c478bd9Sstevel@tonic-gate  */
122177c478bd9Sstevel@tonic-gate   int term_curpos = gl->term_curpos;
122187c478bd9Sstevel@tonic-gate /*
122197c478bd9Sstevel@tonic-gate  * First clear from the cursor to the end of the current input line.
122207c478bd9Sstevel@tonic-gate  */
122217c478bd9Sstevel@tonic-gate   if(gl_print_control_sequence(gl, 1, gl->clear_eol))
122227c478bd9Sstevel@tonic-gate     return 1;
122237c478bd9Sstevel@tonic-gate /*
122247c478bd9Sstevel@tonic-gate  * If there is more than one line displayed, go to the start of the
122257c478bd9Sstevel@tonic-gate  * next line and clear from there to the end of the display. Note that
122267c478bd9Sstevel@tonic-gate  * we can't use clear_eod to do the whole job of clearing from the
122277c478bd9Sstevel@tonic-gate  * current cursor position to the end of the terminal because
122287c478bd9Sstevel@tonic-gate  * clear_eod is only defined when used at the start of a terminal line
122297c478bd9Sstevel@tonic-gate  * (eg. with gnome terminals, clear_eod clears from the start of the
122307c478bd9Sstevel@tonic-gate  * current terminal line, rather than from the current cursor
122317c478bd9Sstevel@tonic-gate  * position).
122327c478bd9Sstevel@tonic-gate  */
122337c478bd9Sstevel@tonic-gate   if(gl->term_len / gl->ncolumn > gl->term_curpos / gl->ncolumn) {
122347c478bd9Sstevel@tonic-gate     if(gl_print_control_sequence(gl, 1, gl->down) ||
122357c478bd9Sstevel@tonic-gate        gl_print_control_sequence(gl, 1, gl->bol) ||
122367c478bd9Sstevel@tonic-gate        gl_print_control_sequence(gl, gl->nline, gl->clear_eod))
122377c478bd9Sstevel@tonic-gate       return 1;
122387c478bd9Sstevel@tonic-gate /*
122397c478bd9Sstevel@tonic-gate  * Where is the cursor now?
122407c478bd9Sstevel@tonic-gate  */
122417c478bd9Sstevel@tonic-gate     gl->term_curpos = gl->ncolumn * (term_curpos / gl->ncolumn + 1);
122427c478bd9Sstevel@tonic-gate /*
122437c478bd9Sstevel@tonic-gate  * Restore the cursor position.
122447c478bd9Sstevel@tonic-gate  */
122457c478bd9Sstevel@tonic-gate     gl_set_term_curpos(gl, term_curpos);
122467c478bd9Sstevel@tonic-gate   };
122477c478bd9Sstevel@tonic-gate /*
122487c478bd9Sstevel@tonic-gate  * Update the recorded position of the final character.
122497c478bd9Sstevel@tonic-gate  */
122507c478bd9Sstevel@tonic-gate   gl->term_len = gl->term_curpos;
122517c478bd9Sstevel@tonic-gate   return 0;
122527c478bd9Sstevel@tonic-gate }
122537c478bd9Sstevel@tonic-gate 
122547c478bd9Sstevel@tonic-gate /*.......................................................................
122557c478bd9Sstevel@tonic-gate  * Return the set of all trappable signals.
122567c478bd9Sstevel@tonic-gate  *
122577c478bd9Sstevel@tonic-gate  * Input:
122587c478bd9Sstevel@tonic-gate  *  signals   sigset_t *  The set of signals will be recorded in
122597c478bd9Sstevel@tonic-gate  *                        *signals.
122607c478bd9Sstevel@tonic-gate  */
122617c478bd9Sstevel@tonic-gate static void gl_list_trappable_signals(sigset_t *signals)
122627c478bd9Sstevel@tonic-gate {
122637c478bd9Sstevel@tonic-gate /*
122647c478bd9Sstevel@tonic-gate  * Start with the set of all signals.
122657c478bd9Sstevel@tonic-gate  */
122667c478bd9Sstevel@tonic-gate   sigfillset(signals);
122677c478bd9Sstevel@tonic-gate /*
122687c478bd9Sstevel@tonic-gate  * Remove un-trappable signals from this set.
122697c478bd9Sstevel@tonic-gate  */
122707c478bd9Sstevel@tonic-gate #ifdef SIGKILL
122717c478bd9Sstevel@tonic-gate   sigdelset(signals, SIGKILL);
122727c478bd9Sstevel@tonic-gate #endif
122737c478bd9Sstevel@tonic-gate #ifdef SIGSTOP
122747c478bd9Sstevel@tonic-gate   sigdelset(signals, SIGSTOP);
122757c478bd9Sstevel@tonic-gate #endif
122767c478bd9Sstevel@tonic-gate }
122777c478bd9Sstevel@tonic-gate 
122787c478bd9Sstevel@tonic-gate /*.......................................................................
122797c478bd9Sstevel@tonic-gate  * Read an input line from a non-interactive input stream.
122807c478bd9Sstevel@tonic-gate  *
122817c478bd9Sstevel@tonic-gate  * Input:
122827c478bd9Sstevel@tonic-gate  *  gl     GetLine *   The resource object of gl_get_line().
122837c478bd9Sstevel@tonic-gate  * Output:
122847c478bd9Sstevel@tonic-gate  *  return     int     0 - OK
122857c478bd9Sstevel@tonic-gate  *                     1 - Error.
122867c478bd9Sstevel@tonic-gate  */
122877c478bd9Sstevel@tonic-gate static int gl_read_stream_line(GetLine *gl)
122887c478bd9Sstevel@tonic-gate {
122897c478bd9Sstevel@tonic-gate   char c = '\0'; /* The latest character read from fp */
122907c478bd9Sstevel@tonic-gate /*
122917c478bd9Sstevel@tonic-gate  * Record the fact that we are about to read input.
122927c478bd9Sstevel@tonic-gate  */
122937c478bd9Sstevel@tonic-gate   gl->pending_io = GLP_READ;
122947c478bd9Sstevel@tonic-gate /*
122957c478bd9Sstevel@tonic-gate  * If we are starting a new line, reset the line-input parameters.
122967c478bd9Sstevel@tonic-gate  */
122977c478bd9Sstevel@tonic-gate   if(gl->endline)
122987c478bd9Sstevel@tonic-gate     gl_reset_input_line(gl);
122997c478bd9Sstevel@tonic-gate /*
123007c478bd9Sstevel@tonic-gate  * Read one character at a time.
123017c478bd9Sstevel@tonic-gate  */
123027c478bd9Sstevel@tonic-gate   while(gl->ntotal < gl->linelen && c != '\n') {
123037c478bd9Sstevel@tonic-gate /*
123047c478bd9Sstevel@tonic-gate  * Attempt to read one more character.
123057c478bd9Sstevel@tonic-gate  */
123067c478bd9Sstevel@tonic-gate     switch(gl_read_input(gl, &c)) {
123077c478bd9Sstevel@tonic-gate     case GL_READ_OK:
123087c478bd9Sstevel@tonic-gate       break;
123097c478bd9Sstevel@tonic-gate     case GL_READ_EOF:        /* Reached end-of-file? */
123107c478bd9Sstevel@tonic-gate /*
123117c478bd9Sstevel@tonic-gate  * If any characters were read before the end-of-file condition,
123127c478bd9Sstevel@tonic-gate  * interpolate a newline character, so that the caller sees a
123137c478bd9Sstevel@tonic-gate  * properly terminated line. Otherwise return an end-of-file
123147c478bd9Sstevel@tonic-gate  * condition.
123157c478bd9Sstevel@tonic-gate  */
123167c478bd9Sstevel@tonic-gate       if(gl->ntotal > 0) {
123177c478bd9Sstevel@tonic-gate 	c = '\n';
123187c478bd9Sstevel@tonic-gate       } else {
123197c478bd9Sstevel@tonic-gate 	gl_record_status(gl, GLR_EOF, 0);
123207c478bd9Sstevel@tonic-gate 	return 1;
123217c478bd9Sstevel@tonic-gate       };
123227c478bd9Sstevel@tonic-gate       break;
123237c478bd9Sstevel@tonic-gate     case GL_READ_BLOCKED:    /* Input blocked? */
123247c478bd9Sstevel@tonic-gate       gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
123257c478bd9Sstevel@tonic-gate       return 1;
123267c478bd9Sstevel@tonic-gate       break;
123277c478bd9Sstevel@tonic-gate     case GL_READ_ERROR:     /* I/O error? */
123287c478bd9Sstevel@tonic-gate       return 1;
123297c478bd9Sstevel@tonic-gate       break;
123307c478bd9Sstevel@tonic-gate     };
123317c478bd9Sstevel@tonic-gate /*
123327c478bd9Sstevel@tonic-gate  * Append the character to the line buffer.
123337c478bd9Sstevel@tonic-gate  */
123347c478bd9Sstevel@tonic-gate     if(gl_buffer_char(gl, c, gl->ntotal))
123357c478bd9Sstevel@tonic-gate       return 1;
123367c478bd9Sstevel@tonic-gate   };
123377c478bd9Sstevel@tonic-gate /*
123387c478bd9Sstevel@tonic-gate  * Was the end of the input line reached before running out of buffer space?
123397c478bd9Sstevel@tonic-gate  */
123407c478bd9Sstevel@tonic-gate   gl->endline = (c == '\n');
123417c478bd9Sstevel@tonic-gate   return 0;
123427c478bd9Sstevel@tonic-gate }
123437c478bd9Sstevel@tonic-gate 
123447c478bd9Sstevel@tonic-gate /*.......................................................................
123457c478bd9Sstevel@tonic-gate  * Read a single character from a non-interactive input stream.
123467c478bd9Sstevel@tonic-gate  *
123477c478bd9Sstevel@tonic-gate  * Input:
123487c478bd9Sstevel@tonic-gate  *  gl     GetLine *   The resource object of gl_get_line().
123497c478bd9Sstevel@tonic-gate  * Output:
123507c478bd9Sstevel@tonic-gate  *  return     int     The character, or EOF on error.
123517c478bd9Sstevel@tonic-gate  */
123527c478bd9Sstevel@tonic-gate static int gl_read_stream_char(GetLine *gl)
123537c478bd9Sstevel@tonic-gate {
123547c478bd9Sstevel@tonic-gate   char c = '\0';    /* The latest character read from fp */
123557c478bd9Sstevel@tonic-gate   int retval = EOF; /* The return value of this function */
123567c478bd9Sstevel@tonic-gate /*
123577c478bd9Sstevel@tonic-gate  * Arrange to discard any incomplete input line.
123587c478bd9Sstevel@tonic-gate  */
123597c478bd9Sstevel@tonic-gate   _gl_abandon_line(gl);
123607c478bd9Sstevel@tonic-gate /*
123617c478bd9Sstevel@tonic-gate  * Record the fact that we are about to read input.
123627c478bd9Sstevel@tonic-gate  */
123637c478bd9Sstevel@tonic-gate   gl->pending_io = GLP_READ;
123647c478bd9Sstevel@tonic-gate /*
123657c478bd9Sstevel@tonic-gate  * Attempt to read one more character.
123667c478bd9Sstevel@tonic-gate  */
123677c478bd9Sstevel@tonic-gate   switch(gl_read_input(gl, &c)) {
123687c478bd9Sstevel@tonic-gate   case GL_READ_OK:      /* Success */
123697c478bd9Sstevel@tonic-gate     retval = c;
123707c478bd9Sstevel@tonic-gate     break;
123717c478bd9Sstevel@tonic-gate   case GL_READ_BLOCKED: /* The read blocked */
123727c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO);
123737c478bd9Sstevel@tonic-gate     retval = EOF;  /* Failure */
123747c478bd9Sstevel@tonic-gate     break;
123757c478bd9Sstevel@tonic-gate   case GL_READ_EOF:     /* End of file reached */
123767c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_EOF, 0);
123777c478bd9Sstevel@tonic-gate     retval = EOF;  /* Failure */
123787c478bd9Sstevel@tonic-gate     break;
123797c478bd9Sstevel@tonic-gate   case GL_READ_ERROR:
123807c478bd9Sstevel@tonic-gate     retval = EOF;  /* Failure */
123817c478bd9Sstevel@tonic-gate     break;
123827c478bd9Sstevel@tonic-gate   };
123837c478bd9Sstevel@tonic-gate   return retval;
123847c478bd9Sstevel@tonic-gate }
123857c478bd9Sstevel@tonic-gate 
123867c478bd9Sstevel@tonic-gate /*.......................................................................
123877c478bd9Sstevel@tonic-gate  * Bind a key sequence to a given action.
123887c478bd9Sstevel@tonic-gate  *
123897c478bd9Sstevel@tonic-gate  * Input:
123907c478bd9Sstevel@tonic-gate  *  gl          GetLine *   The resource object of gl_get_line().
123917c478bd9Sstevel@tonic-gate  *  origin  GlKeyOrigin     The originator of the key binding.
123927c478bd9Sstevel@tonic-gate  *  key      const char *   The key-sequence to be bound (or unbound).
123937c478bd9Sstevel@tonic-gate  *  action   const char *   The name of the action to bind the key to,
123947c478bd9Sstevel@tonic-gate  *                          or either NULL or "" to unbind the
123957c478bd9Sstevel@tonic-gate  *                          key-sequence.
123967c478bd9Sstevel@tonic-gate  * Output:
123977c478bd9Sstevel@tonic-gate  *  return          int     0 - OK
123987c478bd9Sstevel@tonic-gate  *                          1 - Error.
123997c478bd9Sstevel@tonic-gate  */
124007c478bd9Sstevel@tonic-gate int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin, const char *keyseq,
124017c478bd9Sstevel@tonic-gate 		   const char *action)
124027c478bd9Sstevel@tonic-gate {
124037c478bd9Sstevel@tonic-gate   KtBinder binder;  /* The private internal equivalent of 'origin' */
124047c478bd9Sstevel@tonic-gate /*
124057c478bd9Sstevel@tonic-gate  * Check the arguments.
124067c478bd9Sstevel@tonic-gate  */
124077c478bd9Sstevel@tonic-gate   if(!gl || !keyseq) {
124087c478bd9Sstevel@tonic-gate     errno = EINVAL;
124097c478bd9Sstevel@tonic-gate     if(gl)
124107c478bd9Sstevel@tonic-gate       _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG);
124117c478bd9Sstevel@tonic-gate     return 1;
124127c478bd9Sstevel@tonic-gate   };
124137c478bd9Sstevel@tonic-gate /*
124147c478bd9Sstevel@tonic-gate  * An empty action string requests that the key-sequence be unbound.
124157c478bd9Sstevel@tonic-gate  * This is indicated to _kt_set_keybinding() by passing a NULL action
124167c478bd9Sstevel@tonic-gate  * string, so convert an empty string to a NULL action pointer.
124177c478bd9Sstevel@tonic-gate  */
124187c478bd9Sstevel@tonic-gate   if(action && *action=='\0')
124197c478bd9Sstevel@tonic-gate     action = NULL;
124207c478bd9Sstevel@tonic-gate /*
124217c478bd9Sstevel@tonic-gate  * Translate the public originator enumeration to the private equivalent.
124227c478bd9Sstevel@tonic-gate  */
124237c478bd9Sstevel@tonic-gate   binder = origin==GL_USER_KEY ? KTB_USER : KTB_NORM;
124247c478bd9Sstevel@tonic-gate /*
124257c478bd9Sstevel@tonic-gate  * Bind the action to a given key-sequence?
124267c478bd9Sstevel@tonic-gate  */
124277c478bd9Sstevel@tonic-gate   if(keyseq && _kt_set_keybinding(gl->bindings, binder, keyseq, action)) {
124287c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG);
124297c478bd9Sstevel@tonic-gate     return 1;
124307c478bd9Sstevel@tonic-gate   };
124317c478bd9Sstevel@tonic-gate   return 0;
124327c478bd9Sstevel@tonic-gate }
124337c478bd9Sstevel@tonic-gate 
124347c478bd9Sstevel@tonic-gate /*.......................................................................
124357c478bd9Sstevel@tonic-gate  * This is the public wrapper around the gl_clear_termina() function.
124367c478bd9Sstevel@tonic-gate  * It clears the terminal and leaves the cursor at the home position.
124377c478bd9Sstevel@tonic-gate  * In server I/O mode, the next call to gl_get_line() will also
124387c478bd9Sstevel@tonic-gate  * redisplay the current input line.
124397c478bd9Sstevel@tonic-gate  *
124407c478bd9Sstevel@tonic-gate  * Input:
124417c478bd9Sstevel@tonic-gate  *  gl          GetLine *   The resource object of gl_get_line().
124427c478bd9Sstevel@tonic-gate  * Output:
124437c478bd9Sstevel@tonic-gate  *  return          int     0 - OK.
124447c478bd9Sstevel@tonic-gate  *                          1 - Error.
124457c478bd9Sstevel@tonic-gate  */
124467c478bd9Sstevel@tonic-gate int gl_erase_terminal(GetLine *gl)
124477c478bd9Sstevel@tonic-gate {
124487c478bd9Sstevel@tonic-gate   sigset_t oldset;      /* The signals that were blocked on entry */
124497c478bd9Sstevel@tonic-gate                         /*  to this function */
124507c478bd9Sstevel@tonic-gate   int status;           /* The return status */
124517c478bd9Sstevel@tonic-gate /*
124527c478bd9Sstevel@tonic-gate  * Block all signals while accessing gl.
124537c478bd9Sstevel@tonic-gate  */
124547c478bd9Sstevel@tonic-gate   gl_mask_signals(gl, &oldset);
124557c478bd9Sstevel@tonic-gate /*
124567c478bd9Sstevel@tonic-gate  * Clear the terminal.
124577c478bd9Sstevel@tonic-gate  */
124587c478bd9Sstevel@tonic-gate   status = gl_clear_screen(gl, 1, NULL);
124597c478bd9Sstevel@tonic-gate /*
124607c478bd9Sstevel@tonic-gate  * Attempt to flush the clear-screen control codes to the terminal.
124617c478bd9Sstevel@tonic-gate  * If this doesn't complete the job, the next call to gl_get_line()
124627c478bd9Sstevel@tonic-gate  * will.
124637c478bd9Sstevel@tonic-gate  */
124647c478bd9Sstevel@tonic-gate   (void) gl_flush_output(gl);
124657c478bd9Sstevel@tonic-gate /*
124667c478bd9Sstevel@tonic-gate  * Restore the process signal mask before returning.
124677c478bd9Sstevel@tonic-gate  */
124687c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
124697c478bd9Sstevel@tonic-gate   return status;
124707c478bd9Sstevel@tonic-gate }
124717c478bd9Sstevel@tonic-gate 
124727c478bd9Sstevel@tonic-gate /*.......................................................................
124737c478bd9Sstevel@tonic-gate  * This function must be called by any function that erases the input
124747c478bd9Sstevel@tonic-gate  * line.
124757c478bd9Sstevel@tonic-gate  *
124767c478bd9Sstevel@tonic-gate  * Input:
124777c478bd9Sstevel@tonic-gate  *  gl          GetLine *   The resource object of gl_get_line().
124787c478bd9Sstevel@tonic-gate  */
124797c478bd9Sstevel@tonic-gate static void gl_line_erased(GetLine *gl)
124807c478bd9Sstevel@tonic-gate {
124817c478bd9Sstevel@tonic-gate   gl->displayed = 0;
124827c478bd9Sstevel@tonic-gate   gl->term_curpos = 0;
124837c478bd9Sstevel@tonic-gate   gl->term_len = 0;
124847c478bd9Sstevel@tonic-gate }
124857c478bd9Sstevel@tonic-gate 
124867c478bd9Sstevel@tonic-gate /*.......................................................................
124877c478bd9Sstevel@tonic-gate  * Append a specified line to the history list.
124887c478bd9Sstevel@tonic-gate  *
124897c478bd9Sstevel@tonic-gate  * Input:
124907c478bd9Sstevel@tonic-gate  *  gl          GetLine *   The resource object of gl_get_line().
124917c478bd9Sstevel@tonic-gate  *  line     const char *   The line to be added.
124927c478bd9Sstevel@tonic-gate  * Output:
124937c478bd9Sstevel@tonic-gate  *  return          int     0 - OK.
124947c478bd9Sstevel@tonic-gate  *                          1 - Error.
124957c478bd9Sstevel@tonic-gate  */
124967c478bd9Sstevel@tonic-gate int gl_append_history(GetLine *gl, const char *line)
124977c478bd9Sstevel@tonic-gate {
124987c478bd9Sstevel@tonic-gate   sigset_t oldset;      /* The signals that were blocked on entry */
124997c478bd9Sstevel@tonic-gate                         /*  to this function */
125007c478bd9Sstevel@tonic-gate   int status;           /* The return status */
125017c478bd9Sstevel@tonic-gate /*
125027c478bd9Sstevel@tonic-gate  * Check the arguments.
125037c478bd9Sstevel@tonic-gate  */
125047c478bd9Sstevel@tonic-gate   if(!gl || !line) {
125057c478bd9Sstevel@tonic-gate     errno = EINVAL;
125067c478bd9Sstevel@tonic-gate     return 1;
125077c478bd9Sstevel@tonic-gate   };
125087c478bd9Sstevel@tonic-gate /*
125097c478bd9Sstevel@tonic-gate  * Block all signals.
125107c478bd9Sstevel@tonic-gate  */
125117c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
125127c478bd9Sstevel@tonic-gate     return 1;
125137c478bd9Sstevel@tonic-gate /*
125147c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
125157c478bd9Sstevel@tonic-gate  */
125167c478bd9Sstevel@tonic-gate   status = _gl_append_history(gl, line);
125177c478bd9Sstevel@tonic-gate /*
125187c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
125197c478bd9Sstevel@tonic-gate  */
125207c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
125217c478bd9Sstevel@tonic-gate   return status;
125227c478bd9Sstevel@tonic-gate }
125237c478bd9Sstevel@tonic-gate 
125247c478bd9Sstevel@tonic-gate /*.......................................................................
125257c478bd9Sstevel@tonic-gate  * This is the private body of the public function, gl_append_history().
125267c478bd9Sstevel@tonic-gate  * It assumes that the caller has checked its arguments and blocked the
125277c478bd9Sstevel@tonic-gate  * delivery of signals.
125287c478bd9Sstevel@tonic-gate  */
125297c478bd9Sstevel@tonic-gate static int _gl_append_history(GetLine *gl, const char *line)
125307c478bd9Sstevel@tonic-gate {
125317c478bd9Sstevel@tonic-gate   int status =_glh_add_history(gl->glh, line, 0);
125327c478bd9Sstevel@tonic-gate   if(status)
125337c478bd9Sstevel@tonic-gate     _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG);
125347c478bd9Sstevel@tonic-gate   return status;
125357c478bd9Sstevel@tonic-gate }
125367c478bd9Sstevel@tonic-gate 
125377c478bd9Sstevel@tonic-gate /*.......................................................................
125387c478bd9Sstevel@tonic-gate  * Enable or disable the automatic addition of newly entered lines to the
125397c478bd9Sstevel@tonic-gate  * history list.
125407c478bd9Sstevel@tonic-gate  *
125417c478bd9Sstevel@tonic-gate  * Input:
125427c478bd9Sstevel@tonic-gate  *  gl          GetLine *   The resource object of gl_get_line().
125437c478bd9Sstevel@tonic-gate  *  enable          int     If true, subsequently entered lines will
125447c478bd9Sstevel@tonic-gate  *                          automatically be added to the history list
125457c478bd9Sstevel@tonic-gate  *                          before they are returned to the caller of
125467c478bd9Sstevel@tonic-gate  *                          gl_get_line(). If 0, the choice of how and
125477c478bd9Sstevel@tonic-gate  *                          when to archive lines in the history list,
125487c478bd9Sstevel@tonic-gate  *                          is left up to the calling application, which
125497c478bd9Sstevel@tonic-gate  *                          can do so via calls to gl_append_history().
125507c478bd9Sstevel@tonic-gate  * Output:
125517c478bd9Sstevel@tonic-gate  *  return          int     0 - OK.
125527c478bd9Sstevel@tonic-gate  *                          1 - Error.
125537c478bd9Sstevel@tonic-gate  */
125547c478bd9Sstevel@tonic-gate int gl_automatic_history(GetLine *gl, int enable)
125557c478bd9Sstevel@tonic-gate {
125567c478bd9Sstevel@tonic-gate   sigset_t oldset;      /* The signals that were blocked on entry */
125577c478bd9Sstevel@tonic-gate                         /*  to this function */
125587c478bd9Sstevel@tonic-gate /*
125597c478bd9Sstevel@tonic-gate  * Check the arguments.
125607c478bd9Sstevel@tonic-gate  */
125617c478bd9Sstevel@tonic-gate   if(!gl) {
125627c478bd9Sstevel@tonic-gate     errno = EINVAL;
125637c478bd9Sstevel@tonic-gate     return 1;
125647c478bd9Sstevel@tonic-gate   };
125657c478bd9Sstevel@tonic-gate /*
125667c478bd9Sstevel@tonic-gate  * Block all signals.
125677c478bd9Sstevel@tonic-gate  */
125687c478bd9Sstevel@tonic-gate   if(gl_mask_signals(gl, &oldset))
125697c478bd9Sstevel@tonic-gate     return 1;
125707c478bd9Sstevel@tonic-gate /*
125717c478bd9Sstevel@tonic-gate  * Execute the private body of the function while signals are blocked.
125727c478bd9Sstevel@tonic-gate  */
125737c478bd9Sstevel@tonic-gate   gl->automatic_history = enable;
125747c478bd9Sstevel@tonic-gate /*
125757c478bd9Sstevel@tonic-gate  * Restore the process signal mask.
125767c478bd9Sstevel@tonic-gate  */
125777c478bd9Sstevel@tonic-gate   gl_unmask_signals(gl, &oldset);
125787c478bd9Sstevel@tonic-gate   return 0;
125797c478bd9Sstevel@tonic-gate }
125807c478bd9Sstevel@tonic-gate 
125817c478bd9Sstevel@tonic-gate /*.......................................................................
125827c478bd9Sstevel@tonic-gate  * This is a public function that reads a single uninterpretted
125837c478bd9Sstevel@tonic-gate  * character from the user, without displaying anything.
125847c478bd9Sstevel@tonic-gate  *
125857c478bd9Sstevel@tonic-gate  * Input:
125867c478bd9Sstevel@tonic-gate  *  gl     GetLine *  A resource object previously returned by
125877c478bd9Sstevel@tonic-gate  *                    new_GetLine().
125887c478bd9Sstevel@tonic-gate  * Output:
125897c478bd9Sstevel@tonic-gate  *  return     int    The character that was read, or EOF if the read
125907c478bd9Sstevel@tonic-gate  *                    had to be aborted (in which case you can call
125917c478bd9Sstevel@tonic-gate  *                    gl_return_status() to find out why).
125927c478bd9Sstevel@tonic-gate  */
125937c478bd9Sstevel@tonic-gate int gl_read_char(GetLine *gl)
125947c478bd9Sstevel@tonic-gate {
125957c478bd9Sstevel@tonic-gate   int retval;   /* The return value of _gl_read_char() */
125967c478bd9Sstevel@tonic-gate /*
125977c478bd9Sstevel@tonic-gate  * This function can be called from application callback functions,
125987c478bd9Sstevel@tonic-gate  * so check whether signals have already been masked, so that we don't
125997c478bd9Sstevel@tonic-gate  * do it again, and overwrite gl->old_signal_set.
126007c478bd9Sstevel@tonic-gate  */
126017c478bd9Sstevel@tonic-gate   int was_masked = gl->signals_masked;
126027c478bd9Sstevel@tonic-gate /*
126037c478bd9Sstevel@tonic-gate  * Check the arguments.
126047c478bd9Sstevel@tonic-gate  */
126057c478bd9Sstevel@tonic-gate   if(!gl) {
126067c478bd9Sstevel@tonic-gate     errno = EINVAL;
126077c478bd9Sstevel@tonic-gate     return EOF;
126087c478bd9Sstevel@tonic-gate   };
126097c478bd9Sstevel@tonic-gate /*
126107c478bd9Sstevel@tonic-gate  * Temporarily block all of the signals that we have been asked to trap.
126117c478bd9Sstevel@tonic-gate  */
126127c478bd9Sstevel@tonic-gate   if(!was_masked && gl_mask_signals(gl, &gl->old_signal_set))
126137c478bd9Sstevel@tonic-gate     return EOF;
126147c478bd9Sstevel@tonic-gate /*
126157c478bd9Sstevel@tonic-gate  * Perform the character reading task.
126167c478bd9Sstevel@tonic-gate  */
126177c478bd9Sstevel@tonic-gate   retval = _gl_read_char(gl);
126187c478bd9Sstevel@tonic-gate /*
126197c478bd9Sstevel@tonic-gate  * Restore the process signal mask to how it was when this function was
126207c478bd9Sstevel@tonic-gate  * first called.
126217c478bd9Sstevel@tonic-gate  */
126227c478bd9Sstevel@tonic-gate   if(!was_masked)
126237c478bd9Sstevel@tonic-gate     gl_unmask_signals(gl, &gl->old_signal_set);
126247c478bd9Sstevel@tonic-gate   return retval;
126257c478bd9Sstevel@tonic-gate }
126267c478bd9Sstevel@tonic-gate 
126277c478bd9Sstevel@tonic-gate /*.......................................................................
126287c478bd9Sstevel@tonic-gate  * This is the main body of the public function gl_read_char().
126297c478bd9Sstevel@tonic-gate  */
126307c478bd9Sstevel@tonic-gate static int _gl_read_char(GetLine *gl)
126317c478bd9Sstevel@tonic-gate {
126327c478bd9Sstevel@tonic-gate   int retval = EOF;  /* The return value */
126337c478bd9Sstevel@tonic-gate   int waserr = 0;    /* True if an error occurs */
126347c478bd9Sstevel@tonic-gate   char c;            /* The character read */
126357c478bd9Sstevel@tonic-gate /*
126367c478bd9Sstevel@tonic-gate  * This function can be called from application callback functions,
126377c478bd9Sstevel@tonic-gate  * so check whether signals have already been overriden, so that we don't
126387c478bd9Sstevel@tonic-gate  * overwrite the preserved signal handlers with gl_get_line()s. Also
126397c478bd9Sstevel@tonic-gate  * record whether we are currently in raw I/O mode or not, so that this
126407c478bd9Sstevel@tonic-gate  * can be left in the same state on leaving this function.
126417c478bd9Sstevel@tonic-gate  */
126427c478bd9Sstevel@tonic-gate   int was_overriden = gl->signals_overriden;
126437c478bd9Sstevel@tonic-gate   int was_raw = gl->raw_mode;
126447c478bd9Sstevel@tonic-gate /*
126457c478bd9Sstevel@tonic-gate  * Also keep a record of the direction of any I/O that gl_get_line()
126467c478bd9Sstevel@tonic-gate  * is awaiting, so that we can restore this status on return.
126477c478bd9Sstevel@tonic-gate  */
126487c478bd9Sstevel@tonic-gate   GlPendingIO old_pending_io = gl->pending_io;
126497c478bd9Sstevel@tonic-gate /*
126507c478bd9Sstevel@tonic-gate  * Assume that this call will successfully complete the input operation
126517c478bd9Sstevel@tonic-gate  * until proven otherwise.
126527c478bd9Sstevel@tonic-gate  */
126537c478bd9Sstevel@tonic-gate   gl_clear_status(gl);
126547c478bd9Sstevel@tonic-gate /*
126557c478bd9Sstevel@tonic-gate  * If this is the first call to this function or gl_get_line(),
126567c478bd9Sstevel@tonic-gate  * since new_GetLine(), complete any postponed configuration.
126577c478bd9Sstevel@tonic-gate  */
126587c478bd9Sstevel@tonic-gate   if(!gl->configured) {
126597c478bd9Sstevel@tonic-gate     (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE);
126607c478bd9Sstevel@tonic-gate     gl->configured = 1;
126617c478bd9Sstevel@tonic-gate   };
126627c478bd9Sstevel@tonic-gate /*
126637c478bd9Sstevel@tonic-gate  * Before installing our signal handler functions, record the fact
126647c478bd9Sstevel@tonic-gate  * that there are no pending signals.
126657c478bd9Sstevel@tonic-gate  */
126667c478bd9Sstevel@tonic-gate   gl_pending_signal = -1;
126677c478bd9Sstevel@tonic-gate /*
126687c478bd9Sstevel@tonic-gate  * Temporarily override the signal handlers of the calling program,
126697c478bd9Sstevel@tonic-gate  * so that we can intercept signals that would leave the terminal
126707c478bd9Sstevel@tonic-gate  * in a bad state.
126717c478bd9Sstevel@tonic-gate  */
126727c478bd9Sstevel@tonic-gate   if(!was_overriden)
126737c478bd9Sstevel@tonic-gate     waserr = gl_override_signal_handlers(gl);
126747c478bd9Sstevel@tonic-gate /*
126757c478bd9Sstevel@tonic-gate  * After recording the current terminal settings, switch the terminal
126767c478bd9Sstevel@tonic-gate  * into raw input mode, without redisplaying any partially entered input
126777c478bd9Sstevel@tonic-gate  * line.
126787c478bd9Sstevel@tonic-gate  */
126797c478bd9Sstevel@tonic-gate   if(!was_raw)
126807c478bd9Sstevel@tonic-gate     waserr = waserr || _gl_raw_io(gl, 0);
126817c478bd9Sstevel@tonic-gate /*
126827c478bd9Sstevel@tonic-gate  * Attempt to read the line. This will require more than one attempt if
126837c478bd9Sstevel@tonic-gate  * either a current temporary input file is opened by gl_get_input_line()
126847c478bd9Sstevel@tonic-gate  * or the end of a temporary input file is reached by gl_read_stream_line().
126857c478bd9Sstevel@tonic-gate  */
126867c478bd9Sstevel@tonic-gate   while(!waserr) {
126877c478bd9Sstevel@tonic-gate /*
126887c478bd9Sstevel@tonic-gate  * Read a line from a non-interactive stream?
126897c478bd9Sstevel@tonic-gate  */
126907c478bd9Sstevel@tonic-gate     if(gl->file_fp || !gl->is_term) {
126917c478bd9Sstevel@tonic-gate       retval = gl_read_stream_char(gl);
126927c478bd9Sstevel@tonic-gate       if(retval != EOF) {            /* Success? */
126937c478bd9Sstevel@tonic-gate 	break;
126947c478bd9Sstevel@tonic-gate       } else if(gl->file_fp) {  /* End of temporary input file? */
126957c478bd9Sstevel@tonic-gate 	gl_revert_input(gl);
126967c478bd9Sstevel@tonic-gate 	gl_record_status(gl, GLR_NEWLINE, 0);
126977c478bd9Sstevel@tonic-gate       } else {                  /* An error? */
126987c478bd9Sstevel@tonic-gate 	waserr = 1;
126997c478bd9Sstevel@tonic-gate 	break;
127007c478bd9Sstevel@tonic-gate       };
127017c478bd9Sstevel@tonic-gate     };
127027c478bd9Sstevel@tonic-gate /*
127037c478bd9Sstevel@tonic-gate  * Read from the terminal? Note that the above if() block may have
127047c478bd9Sstevel@tonic-gate  * changed gl->file_fp, so it is necessary to retest it here, rather
127057c478bd9Sstevel@tonic-gate  * than using an else statement.
127067c478bd9Sstevel@tonic-gate  */
127077c478bd9Sstevel@tonic-gate     if(!gl->file_fp && gl->is_term) {
127087c478bd9Sstevel@tonic-gate /*
127097c478bd9Sstevel@tonic-gate  * Flush any pending output to the terminal before waiting
127107c478bd9Sstevel@tonic-gate  * for the user to type a character.
127117c478bd9Sstevel@tonic-gate  */
127127c478bd9Sstevel@tonic-gate       if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl)) {
127137c478bd9Sstevel@tonic-gate 	retval = EOF;
127147c478bd9Sstevel@tonic-gate /*
127157c478bd9Sstevel@tonic-gate  * Read one character. Don't append it to the key buffer, since
127167c478bd9Sstevel@tonic-gate  * this would subseuqnely appear as bogus input to the line editor.
127177c478bd9Sstevel@tonic-gate  */
127187c478bd9Sstevel@tonic-gate       } else if(gl_read_terminal(gl, 0, &c) == 0) {
127197c478bd9Sstevel@tonic-gate /*
127207c478bd9Sstevel@tonic-gate  * Record the character for return.
127217c478bd9Sstevel@tonic-gate  */
127227c478bd9Sstevel@tonic-gate 	retval = c;
127237c478bd9Sstevel@tonic-gate /*
127247c478bd9Sstevel@tonic-gate  * In this mode, count each character as being a new key-sequence.
127257c478bd9Sstevel@tonic-gate  */
127267c478bd9Sstevel@tonic-gate 	gl->keyseq_count++;
127277c478bd9Sstevel@tonic-gate /*
127287c478bd9Sstevel@tonic-gate  * Delete the character that was read, from the key-press buffer.
127297c478bd9Sstevel@tonic-gate  */
127307c478bd9Sstevel@tonic-gate 	gl_discard_chars(gl, 1);
127317c478bd9Sstevel@tonic-gate       };
127327c478bd9Sstevel@tonic-gate       if(retval==EOF)
127337c478bd9Sstevel@tonic-gate 	waserr = 1;
127347c478bd9Sstevel@tonic-gate       else
127357c478bd9Sstevel@tonic-gate 	break;
127367c478bd9Sstevel@tonic-gate     };
127377c478bd9Sstevel@tonic-gate   };
127387c478bd9Sstevel@tonic-gate /*
127397c478bd9Sstevel@tonic-gate  * If an error occurred, but gl->rtn_status is still set to
127407c478bd9Sstevel@tonic-gate  * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise
127417c478bd9Sstevel@tonic-gate  * leave it at whatever specific value was assigned by the function
127427c478bd9Sstevel@tonic-gate  * that aborted input. This means that only functions that trap
127437c478bd9Sstevel@tonic-gate  * non-generic errors have to remember to update gl->rtn_status
127447c478bd9Sstevel@tonic-gate  * themselves.
127457c478bd9Sstevel@tonic-gate  */
127467c478bd9Sstevel@tonic-gate   if(waserr && gl->rtn_status == GLR_NEWLINE)
127477c478bd9Sstevel@tonic-gate     gl_record_status(gl, GLR_ERROR, errno);
127487c478bd9Sstevel@tonic-gate /*
127497c478bd9Sstevel@tonic-gate  * Restore terminal settings, if they were changed by this function.
127507c478bd9Sstevel@tonic-gate  */
127517c478bd9Sstevel@tonic-gate   if(!was_raw && gl->io_mode != GL_SERVER_MODE)
127527c478bd9Sstevel@tonic-gate     _gl_normal_io(gl);
127537c478bd9Sstevel@tonic-gate /*
127547c478bd9Sstevel@tonic-gate  * Restore the signal handlers, if they were overriden by this function.
127557c478bd9Sstevel@tonic-gate  */
127567c478bd9Sstevel@tonic-gate   if(!was_overriden)
127577c478bd9Sstevel@tonic-gate     gl_restore_signal_handlers(gl);
127587c478bd9Sstevel@tonic-gate /*
127597c478bd9Sstevel@tonic-gate  * If this function gets aborted early, the errno value associated
127607c478bd9Sstevel@tonic-gate  * with the event that caused this to happen is recorded in
127617c478bd9Sstevel@tonic-gate  * gl->rtn_errno. Since errno may have been overwritten by cleanup
127627c478bd9Sstevel@tonic-gate  * functions after this, restore its value to the value that it had
127637c478bd9Sstevel@tonic-gate  * when the error condition occured, so that the caller can examine it
127647c478bd9Sstevel@tonic-gate  * to find out what happened.
127657c478bd9Sstevel@tonic-gate  */
127667c478bd9Sstevel@tonic-gate   errno = gl->rtn_errno;
127677c478bd9Sstevel@tonic-gate /*
127687c478bd9Sstevel@tonic-gate  * Error conditions are signalled to the caller, by setting the returned
127697c478bd9Sstevel@tonic-gate  * character to EOF.
127707c478bd9Sstevel@tonic-gate  */
127717c478bd9Sstevel@tonic-gate   if(gl->rtn_status != GLR_NEWLINE)
127727c478bd9Sstevel@tonic-gate     retval = EOF;
127737c478bd9Sstevel@tonic-gate /*
127747c478bd9Sstevel@tonic-gate  * Restore the indication of what direction of I/O gl_get_line()
127757c478bd9Sstevel@tonic-gate  * was awaiting before this call.
127767c478bd9Sstevel@tonic-gate  */
127777c478bd9Sstevel@tonic-gate   gl->pending_io = old_pending_io;
127787c478bd9Sstevel@tonic-gate /*
127797c478bd9Sstevel@tonic-gate  * Return the acquired character.
127807c478bd9Sstevel@tonic-gate  */
127817c478bd9Sstevel@tonic-gate   return retval;
127827c478bd9Sstevel@tonic-gate }
127837c478bd9Sstevel@tonic-gate 
127847c478bd9Sstevel@tonic-gate /*.......................................................................
127857c478bd9Sstevel@tonic-gate  * Reset the GetLine completion status. This function should be called
127867c478bd9Sstevel@tonic-gate  * at the start of gl_get_line(), gl_read_char() and gl_query_char()
127877c478bd9Sstevel@tonic-gate  * to discard the completion status and non-zero errno value of any
127887c478bd9Sstevel@tonic-gate  * preceding calls to these functions.
127897c478bd9Sstevel@tonic-gate  *
127907c478bd9Sstevel@tonic-gate  * Input:
127917c478bd9Sstevel@tonic-gate  *  gl       GetLine *  The resource object of this module.
127927c478bd9Sstevel@tonic-gate  */
127937c478bd9Sstevel@tonic-gate static void gl_clear_status(GetLine *gl)
127947c478bd9Sstevel@tonic-gate {
127957c478bd9Sstevel@tonic-gate   gl_record_status(gl, GLR_NEWLINE, 0);
127967c478bd9Sstevel@tonic-gate }
127977c478bd9Sstevel@tonic-gate 
127987c478bd9Sstevel@tonic-gate /*.......................................................................
127997c478bd9Sstevel@tonic-gate  * When an error or other event causes gl_get_line() to return, this
128007c478bd9Sstevel@tonic-gate  * function should be called to record information about what
128017c478bd9Sstevel@tonic-gate  * happened, including the value of errno and the value that
128027c478bd9Sstevel@tonic-gate  * gl_return_status() should return.
128037c478bd9Sstevel@tonic-gate  *
128047c478bd9Sstevel@tonic-gate  * Input:
128057c478bd9Sstevel@tonic-gate  *  gl                GetLine *  The resource object of this module.
128067c478bd9Sstevel@tonic-gate  *  rtn_status GlReturnStatus    The completion status. To clear a
128077c478bd9Sstevel@tonic-gate  *                               previous abnormal completion status,
128087c478bd9Sstevel@tonic-gate  *                               specify GLR_NEWLINE (this is what
128097c478bd9Sstevel@tonic-gate  *                               gl_clear_status() does).
128107c478bd9Sstevel@tonic-gate  *  rtn_errno             int    The associated value of errno.
128117c478bd9Sstevel@tonic-gate  */
128127c478bd9Sstevel@tonic-gate static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status,
128137c478bd9Sstevel@tonic-gate 			     int rtn_errno)
128147c478bd9Sstevel@tonic-gate {
128157c478bd9Sstevel@tonic-gate /*
128167c478bd9Sstevel@tonic-gate  * If rtn_status==GLR_NEWLINE, then this resets the completion status, so we
128177c478bd9Sstevel@tonic-gate  * should always heed this. Otherwise, only record the first abnormal
128187c478bd9Sstevel@tonic-gate  * condition that occurs after such a reset.
128197c478bd9Sstevel@tonic-gate  */
128207c478bd9Sstevel@tonic-gate   if(rtn_status == GLR_NEWLINE || gl->rtn_status == GLR_NEWLINE) {
128217c478bd9Sstevel@tonic-gate     gl->rtn_status = rtn_status;
128227c478bd9Sstevel@tonic-gate     gl->rtn_errno = rtn_errno;
128237c478bd9Sstevel@tonic-gate   };
128247c478bd9Sstevel@tonic-gate }
128257c478bd9Sstevel@tonic-gate 
12826