17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
348bbca81SDaniel Hoffman  *
47c478bd9Sstevel@tonic-gate  * All rights reserved.
548bbca81SDaniel Hoffman  *
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.
1548bbca81SDaniel Hoffman  *
247c478bd9Sstevel@tonic-gate  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2548bbca81SDaniel Hoffman  *
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  */
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  */
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>
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
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
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
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);
1227c478bd9Sstevel@tonic-gate #endif  /* defined(USE_TERMINFO) || defined(USE_TERMCAP) */
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
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>
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;
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
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
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"
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;
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
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;
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 */
22748bbca81SDaniel Hoffman                              /*  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;
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;
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;
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 };
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
2917c478bd9Sstevel@tonic-gate static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd,
2927c478bd9Sstevel@tonic-gate 			      GlFdEvent event);
2947c478bd9Sstevel@tonic-gate static int gl_call_timeout_handler(GetLine *gl);
2967c478bd9Sstevel@tonic-gate #endif
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 };
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
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 };
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
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
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 };
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
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 */
42348bbca81SDaniel Hoffman   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 };
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
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
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
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;
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 };
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;
6467c478bd9Sstevel@tonic-gate static void gl_signal_handler(int signo);
6487c478bd9Sstevel@tonic-gate static int gl_check_caught_signal(GetLine *gl);
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);
6567c478bd9Sstevel@tonic-gate /* Return the default attributes of a given signal */
6587c478bd9Sstevel@tonic-gate static int gl_classify_signal(int signo);
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;
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
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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
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);
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)
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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 */
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);
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);
9767c478bd9Sstevel@tonic-gate /*
9777c478bd9Sstevel@tonic-gate  * Copy the binding of the specified symbolic arrow-key binding to
97848bbca81SDaniel Hoffman  * 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);
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);
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);
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);
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);
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;
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);
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));
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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;
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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
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
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);