1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd. 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * All rights reserved. 5*7c478bd9Sstevel@tonic-gate * 6*7c478bd9Sstevel@tonic-gate * Permission is hereby granted, free of charge, to any person obtaining a 7*7c478bd9Sstevel@tonic-gate * copy of this software and associated documentation files (the 8*7c478bd9Sstevel@tonic-gate * "Software"), to deal in the Software without restriction, including 9*7c478bd9Sstevel@tonic-gate * without limitation the rights to use, copy, modify, merge, publish, 10*7c478bd9Sstevel@tonic-gate * distribute, and/or sell copies of the Software, and to permit persons 11*7c478bd9Sstevel@tonic-gate * to whom the Software is furnished to do so, provided that the above 12*7c478bd9Sstevel@tonic-gate * copyright notice(s) and this permission notice appear in all copies of 13*7c478bd9Sstevel@tonic-gate * the Software and that both the above copyright notice(s) and this 14*7c478bd9Sstevel@tonic-gate * permission notice appear in supporting documentation. 15*7c478bd9Sstevel@tonic-gate * 16*7c478bd9Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17*7c478bd9Sstevel@tonic-gate * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18*7c478bd9Sstevel@tonic-gate * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 19*7c478bd9Sstevel@tonic-gate * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 20*7c478bd9Sstevel@tonic-gate * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 21*7c478bd9Sstevel@tonic-gate * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 22*7c478bd9Sstevel@tonic-gate * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 23*7c478bd9Sstevel@tonic-gate * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 24*7c478bd9Sstevel@tonic-gate * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * Except as contained in this notice, the name of a copyright holder 27*7c478bd9Sstevel@tonic-gate * shall not be used in advertising or otherwise to promote the sale, use 28*7c478bd9Sstevel@tonic-gate * or other dealings in this Software without prior written authorization 29*7c478bd9Sstevel@tonic-gate * of the copyright holder. 30*7c478bd9Sstevel@tonic-gate */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate /* 33*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 34*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate /* 40*7c478bd9Sstevel@tonic-gate * Standard headers. 41*7c478bd9Sstevel@tonic-gate */ 42*7c478bd9Sstevel@tonic-gate #include <stdio.h> 43*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 44*7c478bd9Sstevel@tonic-gate #include <signal.h> 45*7c478bd9Sstevel@tonic-gate #include <string.h> 46*7c478bd9Sstevel@tonic-gate #include <errno.h> 47*7c478bd9Sstevel@tonic-gate #include <ctype.h> 48*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 49*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* 52*7c478bd9Sstevel@tonic-gate * UNIX headers. 53*7c478bd9Sstevel@tonic-gate */ 54*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 55*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 56*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SYS_SELECT_H 57*7c478bd9Sstevel@tonic-gate #include <sys/select.h> 58*7c478bd9Sstevel@tonic-gate #endif 59*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 61*7c478bd9Sstevel@tonic-gate #endif 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* 64*7c478bd9Sstevel@tonic-gate * Handle the different sources of terminal control string and size 65*7c478bd9Sstevel@tonic-gate * information. Note that if no terminal information database is available, 66*7c478bd9Sstevel@tonic-gate * ANSI VT100 control sequences are used. 67*7c478bd9Sstevel@tonic-gate */ 68*7c478bd9Sstevel@tonic-gate #if defined(USE_TERMINFO) || defined(USE_TERMCAP) 69*7c478bd9Sstevel@tonic-gate /* 70*7c478bd9Sstevel@tonic-gate * Include curses.h or ncurses/curses.h depending on which is available. 71*7c478bd9Sstevel@tonic-gate */ 72*7c478bd9Sstevel@tonic-gate #ifdef HAVE_CURSES_H 73*7c478bd9Sstevel@tonic-gate #include <curses.h> 74*7c478bd9Sstevel@tonic-gate #elif defined(HAVE_NCURSES_CURSES_H) 75*7c478bd9Sstevel@tonic-gate #include <ncurses/curses.h> 76*7c478bd9Sstevel@tonic-gate #endif 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * Include term.h where available. 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate #if defined(HAVE_TERM_H) 81*7c478bd9Sstevel@tonic-gate #include <term.h> 82*7c478bd9Sstevel@tonic-gate #elif defined(HAVE_NCURSES_TERM_H) 83*7c478bd9Sstevel@tonic-gate #include <ncurses/term.h> 84*7c478bd9Sstevel@tonic-gate #endif 85*7c478bd9Sstevel@tonic-gate /* 86*7c478bd9Sstevel@tonic-gate * When using termcap, include termcap.h on systems that have it. 87*7c478bd9Sstevel@tonic-gate * Otherwise assume that all prototypes are provided by curses.h. 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate #if defined(USE_TERMCAP) && defined(HAVE_TERMCAP_H) 90*7c478bd9Sstevel@tonic-gate #include <termcap.h> 91*7c478bd9Sstevel@tonic-gate #endif 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate /* 94*7c478bd9Sstevel@tonic-gate * Under Solaris default Curses the output function that tputs takes is 95*7c478bd9Sstevel@tonic-gate * declared to have a char argument. On all other systems and on Solaris 96*7c478bd9Sstevel@tonic-gate * X/Open Curses (Issue 4, Version 2) it expects an int argument (using 97*7c478bd9Sstevel@tonic-gate * c89 or options -I /usr/xpg4/include -L /usr/xpg4/lib -R /usr/xpg4/lib 98*7c478bd9Sstevel@tonic-gate * selects XPG4v2 Curses on Solaris 2.6 and later). 99*7c478bd9Sstevel@tonic-gate * 100*7c478bd9Sstevel@tonic-gate * Similarly, under Mac OS X, the return value of the tputs output 101*7c478bd9Sstevel@tonic-gate * function is declared as void, whereas it is declared as int on 102*7c478bd9Sstevel@tonic-gate * other systems. 103*7c478bd9Sstevel@tonic-gate */ 104*7c478bd9Sstevel@tonic-gate #if defined __sun && defined __SVR4 && !defined _XOPEN_CURSES 105*7c478bd9Sstevel@tonic-gate typedef int TputsRetType; 106*7c478bd9Sstevel@tonic-gate typedef char TputsArgType; /* int tputs(char c, FILE *fp) */ 107*7c478bd9Sstevel@tonic-gate #define TPUTS_RETURNS_VALUE 1 108*7c478bd9Sstevel@tonic-gate #elif defined(__APPLE__) && defined(__MACH__) 109*7c478bd9Sstevel@tonic-gate typedef void TputsRetType; 110*7c478bd9Sstevel@tonic-gate typedef int TputsArgType; /* void tputs(int c, FILE *fp) */ 111*7c478bd9Sstevel@tonic-gate #define TPUTS_RETURNS_VALUE 0 112*7c478bd9Sstevel@tonic-gate #else 113*7c478bd9Sstevel@tonic-gate typedef int TputsRetType; 114*7c478bd9Sstevel@tonic-gate typedef int TputsArgType; /* int tputs(int c, FILE *fp) */ 115*7c478bd9Sstevel@tonic-gate #define TPUTS_RETURNS_VALUE 1 116*7c478bd9Sstevel@tonic-gate #endif 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* 119*7c478bd9Sstevel@tonic-gate * Use the above specifications to prototype our tputs callback function. 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate static TputsRetType gl_tputs_putchar(TputsArgType c); 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate #endif /* defined(USE_TERMINFO) || defined(USE_TERMCAP) */ 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* 126*7c478bd9Sstevel@tonic-gate * If the library is being compiled without filesystem access facilities, 127*7c478bd9Sstevel@tonic-gate * ensure that none of the action functions that normally do access the 128*7c478bd9Sstevel@tonic-gate * filesystem are bound by default, and that it they do get bound, that 129*7c478bd9Sstevel@tonic-gate * they don't do anything. 130*7c478bd9Sstevel@tonic-gate */ 131*7c478bd9Sstevel@tonic-gate #if WITHOUT_FILE_SYSTEM 132*7c478bd9Sstevel@tonic-gate #define HIDE_FILE_SYSTEM 133*7c478bd9Sstevel@tonic-gate #endif 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /* 136*7c478bd9Sstevel@tonic-gate * POSIX headers. 137*7c478bd9Sstevel@tonic-gate */ 138*7c478bd9Sstevel@tonic-gate #include <unistd.h> 139*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 140*7c478bd9Sstevel@tonic-gate #include <termios.h> 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate * Provide typedefs for standard POSIX structures. 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate typedef struct sigaction SigAction; 146*7c478bd9Sstevel@tonic-gate typedef struct termios Termios; 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * Which flag is used to select non-blocking I/O with fcntl()? 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate #undef NON_BLOCKING_FLAG 152*7c478bd9Sstevel@tonic-gate #if defined(O_NONBLOCK) 153*7c478bd9Sstevel@tonic-gate #define NON_BLOCKING_FLAG (O_NONBLOCK) 154*7c478bd9Sstevel@tonic-gate #elif defined(O_NDELAY) 155*7c478bd9Sstevel@tonic-gate #define NON_BLOCKING_FLAG (O_NDELAY) 156*7c478bd9Sstevel@tonic-gate #endif 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* 159*7c478bd9Sstevel@tonic-gate * What value should we give errno if I/O blocks when it shouldn't. 160*7c478bd9Sstevel@tonic-gate */ 161*7c478bd9Sstevel@tonic-gate #undef BLOCKED_ERRNO 162*7c478bd9Sstevel@tonic-gate #if defined(EAGAIN) 163*7c478bd9Sstevel@tonic-gate #define BLOCKED_ERRNO (EAGAIN) 164*7c478bd9Sstevel@tonic-gate #elif defined(EWOULDBLOCK) 165*7c478bd9Sstevel@tonic-gate #define BLOCKED_ERRNO (EWOULDBLOCK) 166*7c478bd9Sstevel@tonic-gate #elif defined(EIO) 167*7c478bd9Sstevel@tonic-gate #define BLOCKED_ERRNO (EIO) 168*7c478bd9Sstevel@tonic-gate #else 169*7c478bd9Sstevel@tonic-gate #define BLOCKED_ERRNO 0 170*7c478bd9Sstevel@tonic-gate #endif 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * Local headers. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM 176*7c478bd9Sstevel@tonic-gate #include "pathutil.h" 177*7c478bd9Sstevel@tonic-gate #endif 178*7c478bd9Sstevel@tonic-gate #include "libtecla.h" 179*7c478bd9Sstevel@tonic-gate #include "keytab.h" 180*7c478bd9Sstevel@tonic-gate #include "getline.h" 181*7c478bd9Sstevel@tonic-gate #include "ioutil.h" 182*7c478bd9Sstevel@tonic-gate #include "history.h" 183*7c478bd9Sstevel@tonic-gate #include "freelist.h" 184*7c478bd9Sstevel@tonic-gate #include "stringrp.h" 185*7c478bd9Sstevel@tonic-gate #include "chrqueue.h" 186*7c478bd9Sstevel@tonic-gate #include "cplmatch.h" 187*7c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM 188*7c478bd9Sstevel@tonic-gate #include "expand.h" 189*7c478bd9Sstevel@tonic-gate #endif 190*7c478bd9Sstevel@tonic-gate #include "errmsg.h" 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate /* 193*7c478bd9Sstevel@tonic-gate * Enumerate the available editing styles. 194*7c478bd9Sstevel@tonic-gate */ 195*7c478bd9Sstevel@tonic-gate typedef enum { 196*7c478bd9Sstevel@tonic-gate GL_EMACS_MODE, /* Emacs style editing */ 197*7c478bd9Sstevel@tonic-gate GL_VI_MODE, /* Vi style editing */ 198*7c478bd9Sstevel@tonic-gate GL_NO_EDITOR /* Fall back to the basic OS-provided editing */ 199*7c478bd9Sstevel@tonic-gate } GlEditor; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* 202*7c478bd9Sstevel@tonic-gate * Set the largest key-sequence that can be handled. 203*7c478bd9Sstevel@tonic-gate */ 204*7c478bd9Sstevel@tonic-gate #define GL_KEY_MAX 64 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate /* 207*7c478bd9Sstevel@tonic-gate * In vi mode, the following datatype is used to implement the 208*7c478bd9Sstevel@tonic-gate * undo command. It records a copy of the input line from before 209*7c478bd9Sstevel@tonic-gate * the command-mode action which edited the input line. 210*7c478bd9Sstevel@tonic-gate */ 211*7c478bd9Sstevel@tonic-gate typedef struct { 212*7c478bd9Sstevel@tonic-gate char *line; /* A historical copy of the input line */ 213*7c478bd9Sstevel@tonic-gate int buff_curpos; /* The historical location of the cursor in */ 214*7c478bd9Sstevel@tonic-gate /* line[] when the line was modified. */ 215*7c478bd9Sstevel@tonic-gate int ntotal; /* The number of characters in line[] */ 216*7c478bd9Sstevel@tonic-gate int saved; /* True once a line has been saved after the */ 217*7c478bd9Sstevel@tonic-gate /* last call to gl_interpret_char(). */ 218*7c478bd9Sstevel@tonic-gate } ViUndo; 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate /* 221*7c478bd9Sstevel@tonic-gate * In vi mode, the following datatype is used to record information 222*7c478bd9Sstevel@tonic-gate * needed by the vi-repeat-change command. 223*7c478bd9Sstevel@tonic-gate */ 224*7c478bd9Sstevel@tonic-gate typedef struct { 225*7c478bd9Sstevel@tonic-gate KtAction action; /* The last action function that made a */ 226*7c478bd9Sstevel@tonic-gate /* change to the line. */ 227*7c478bd9Sstevel@tonic-gate int count; /* The repeat count that was passed to the */ 228*7c478bd9Sstevel@tonic-gate /* above command. */ 229*7c478bd9Sstevel@tonic-gate int input_curpos; /* Whenever vi command mode is entered, the */ 230*7c478bd9Sstevel@tonic-gate /* the position at which it was first left */ 231*7c478bd9Sstevel@tonic-gate /* is recorded here. */ 232*7c478bd9Sstevel@tonic-gate int command_curpos; /* Whenever vi command mode is entered, the */ 233*7c478bd9Sstevel@tonic-gate /* the location of the cursor is recorded */ 234*7c478bd9Sstevel@tonic-gate /* here. */ 235*7c478bd9Sstevel@tonic-gate char input_char; /* Commands that call gl_read_terminal() */ 236*7c478bd9Sstevel@tonic-gate /* record the character here, so that it can */ 237*7c478bd9Sstevel@tonic-gate /* used on repeating the function. */ 238*7c478bd9Sstevel@tonic-gate int saved; /* True if a function has been saved since the */ 239*7c478bd9Sstevel@tonic-gate /* last call to gl_interpret_char(). */ 240*7c478bd9Sstevel@tonic-gate int active; /* True while a function is being repeated. */ 241*7c478bd9Sstevel@tonic-gate } ViRepeat; 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate /* 244*7c478bd9Sstevel@tonic-gate * The following datatype is used to encapsulate information specific 245*7c478bd9Sstevel@tonic-gate * to vi mode. 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate typedef struct { 248*7c478bd9Sstevel@tonic-gate ViUndo undo; /* Information needed to implement the vi */ 249*7c478bd9Sstevel@tonic-gate /* undo command. */ 250*7c478bd9Sstevel@tonic-gate ViRepeat repeat; /* Information needed to implement the vi */ 251*7c478bd9Sstevel@tonic-gate /* repeat command. */ 252*7c478bd9Sstevel@tonic-gate int command; /* True in vi command-mode */ 253*7c478bd9Sstevel@tonic-gate int find_forward; /* True if the last character search was in the */ 254*7c478bd9Sstevel@tonic-gate /* forward direction. */ 255*7c478bd9Sstevel@tonic-gate int find_onto; /* True if the last character search left the */ 256*7c478bd9Sstevel@tonic-gate /* on top of the located character, as opposed */ 257*7c478bd9Sstevel@tonic-gate /* to just before or after it. */ 258*7c478bd9Sstevel@tonic-gate char find_char; /* The last character sought, or '\0' if no */ 259*7c478bd9Sstevel@tonic-gate /* searches have been performed yet. */ 260*7c478bd9Sstevel@tonic-gate } ViMode; 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 263*7c478bd9Sstevel@tonic-gate /* 264*7c478bd9Sstevel@tonic-gate * Define a type for recording a file-descriptor callback and its associated 265*7c478bd9Sstevel@tonic-gate * data. 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate typedef struct { 268*7c478bd9Sstevel@tonic-gate GlFdEventFn *fn; /* The callback function */ 269*7c478bd9Sstevel@tonic-gate void *data; /* Anonymous data to pass to the callback function */ 270*7c478bd9Sstevel@tonic-gate } GlFdHandler; 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* 273*7c478bd9Sstevel@tonic-gate * A list of nodes of the following type is used to record file-activity 274*7c478bd9Sstevel@tonic-gate * event handlers, but only on systems that have the select() system call. 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate typedef struct GlFdNode GlFdNode; 277*7c478bd9Sstevel@tonic-gate struct GlFdNode { 278*7c478bd9Sstevel@tonic-gate GlFdNode *next; /* The next in the list of nodes */ 279*7c478bd9Sstevel@tonic-gate int fd; /* The file descriptor being watched */ 280*7c478bd9Sstevel@tonic-gate GlFdHandler rd; /* The callback to call when fd is readable */ 281*7c478bd9Sstevel@tonic-gate GlFdHandler wr; /* The callback to call when fd is writable */ 282*7c478bd9Sstevel@tonic-gate GlFdHandler ur; /* The callback to call when fd has urgent data */ 283*7c478bd9Sstevel@tonic-gate }; 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate /* 286*7c478bd9Sstevel@tonic-gate * Set the number of the above structures to allocate every time that 287*7c478bd9Sstevel@tonic-gate * the freelist of GlFdNode's becomes exhausted. 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate #define GLFD_FREELIST_BLOCKING 10 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd, 293*7c478bd9Sstevel@tonic-gate GlFdEvent event); 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate static int gl_call_timeout_handler(GetLine *gl); 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate #endif 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate /* 300*7c478bd9Sstevel@tonic-gate * Each signal that gl_get_line() traps is described by a list node 301*7c478bd9Sstevel@tonic-gate * of the following type. 302*7c478bd9Sstevel@tonic-gate */ 303*7c478bd9Sstevel@tonic-gate typedef struct GlSignalNode GlSignalNode; 304*7c478bd9Sstevel@tonic-gate struct GlSignalNode { 305*7c478bd9Sstevel@tonic-gate GlSignalNode *next; /* The next signal in the list */ 306*7c478bd9Sstevel@tonic-gate int signo; /* The number of the signal */ 307*7c478bd9Sstevel@tonic-gate sigset_t proc_mask; /* A process mask which only includes signo */ 308*7c478bd9Sstevel@tonic-gate SigAction original; /* The signal disposition of the calling program */ 309*7c478bd9Sstevel@tonic-gate /* for this signal. */ 310*7c478bd9Sstevel@tonic-gate unsigned flags; /* A bitwise union of GlSignalFlags enumerators */ 311*7c478bd9Sstevel@tonic-gate GlAfterSignal after; /* What to do after the signal has been handled */ 312*7c478bd9Sstevel@tonic-gate int errno_value; /* What to set errno to */ 313*7c478bd9Sstevel@tonic-gate }; 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate /* 316*7c478bd9Sstevel@tonic-gate * Set the number of the above structures to allocate every time that 317*7c478bd9Sstevel@tonic-gate * the freelist of GlSignalNode's becomes exhausted. 318*7c478bd9Sstevel@tonic-gate */ 319*7c478bd9Sstevel@tonic-gate #define GLS_FREELIST_BLOCKING 30 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* 322*7c478bd9Sstevel@tonic-gate * Completion handlers and their callback data are recorded in 323*7c478bd9Sstevel@tonic-gate * nodes of the following type. 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate typedef struct GlCplCallback GlCplCallback; 326*7c478bd9Sstevel@tonic-gate struct GlCplCallback { 327*7c478bd9Sstevel@tonic-gate CplMatchFn *fn; /* The completion callback function */ 328*7c478bd9Sstevel@tonic-gate void *data; /* Arbitrary callback data */ 329*7c478bd9Sstevel@tonic-gate }; 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * The following function is used as the default completion handler when 333*7c478bd9Sstevel@tonic-gate * the filesystem is to be hidden. It simply reports no completions. 334*7c478bd9Sstevel@tonic-gate */ 335*7c478bd9Sstevel@tonic-gate #ifdef HIDE_FILE_SYSTEM 336*7c478bd9Sstevel@tonic-gate static CPL_MATCH_FN(gl_no_completions); 337*7c478bd9Sstevel@tonic-gate #endif 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* 340*7c478bd9Sstevel@tonic-gate * Specify how many GlCplCallback nodes are added to the GlCplCallback freelist 341*7c478bd9Sstevel@tonic-gate * whenever it becomes exhausted. 342*7c478bd9Sstevel@tonic-gate */ 343*7c478bd9Sstevel@tonic-gate #define GL_CPL_FREELIST_BLOCKING 10 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate /* 346*7c478bd9Sstevel@tonic-gate * External action functions and their callback data are recorded in 347*7c478bd9Sstevel@tonic-gate * nodes of the following type. 348*7c478bd9Sstevel@tonic-gate */ 349*7c478bd9Sstevel@tonic-gate typedef struct GlExternalAction GlExternalAction; 350*7c478bd9Sstevel@tonic-gate struct GlExternalAction { 351*7c478bd9Sstevel@tonic-gate GlActionFn *fn; /* The function which implements the action */ 352*7c478bd9Sstevel@tonic-gate void *data; /* Arbitrary callback data */ 353*7c478bd9Sstevel@tonic-gate }; 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate /* 356*7c478bd9Sstevel@tonic-gate * Specify how many GlExternalAction nodes are added to the 357*7c478bd9Sstevel@tonic-gate * GlExternalAction freelist whenever it becomes exhausted. 358*7c478bd9Sstevel@tonic-gate */ 359*7c478bd9Sstevel@tonic-gate #define GL_EXT_ACT_FREELIST_BLOCKING 10 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate /* 362*7c478bd9Sstevel@tonic-gate * Define the contents of the GetLine object. 363*7c478bd9Sstevel@tonic-gate * Note that the typedef for this object can be found in libtecla.h. 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate struct GetLine { 366*7c478bd9Sstevel@tonic-gate ErrMsg *err; /* The error-reporting buffer */ 367*7c478bd9Sstevel@tonic-gate GlHistory *glh; /* The line-history buffer */ 368*7c478bd9Sstevel@tonic-gate WordCompletion *cpl; /* String completion resource object */ 369*7c478bd9Sstevel@tonic-gate GlCplCallback cplfn; /* The completion callback */ 370*7c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM 371*7c478bd9Sstevel@tonic-gate ExpandFile *ef; /* ~user/, $envvar and wildcard expansion */ 372*7c478bd9Sstevel@tonic-gate /* resource object. */ 373*7c478bd9Sstevel@tonic-gate #endif 374*7c478bd9Sstevel@tonic-gate StringGroup *capmem; /* Memory for recording terminal capability */ 375*7c478bd9Sstevel@tonic-gate /* strings. */ 376*7c478bd9Sstevel@tonic-gate GlCharQueue *cq; /* The terminal output character queue */ 377*7c478bd9Sstevel@tonic-gate int input_fd; /* The file descriptor to read on */ 378*7c478bd9Sstevel@tonic-gate int output_fd; /* The file descriptor to write to */ 379*7c478bd9Sstevel@tonic-gate FILE *input_fp; /* A stream wrapper around input_fd */ 380*7c478bd9Sstevel@tonic-gate FILE *output_fp; /* A stream wrapper around output_fd */ 381*7c478bd9Sstevel@tonic-gate FILE *file_fp; /* When input is being temporarily taken from */ 382*7c478bd9Sstevel@tonic-gate /* a file, this is its file-pointer. Otherwise */ 383*7c478bd9Sstevel@tonic-gate /* it is NULL. */ 384*7c478bd9Sstevel@tonic-gate char *term; /* The terminal type specified on the last call */ 385*7c478bd9Sstevel@tonic-gate /* to gl_change_terminal(). */ 386*7c478bd9Sstevel@tonic-gate int is_term; /* True if stdin is a terminal */ 387*7c478bd9Sstevel@tonic-gate GlWriteFn *flush_fn; /* The function to call to write to the terminal */ 388*7c478bd9Sstevel@tonic-gate GlIOMode io_mode; /* The I/O mode established by gl_io_mode() */ 389*7c478bd9Sstevel@tonic-gate int raw_mode; /* True while the terminal is in raw mode */ 390*7c478bd9Sstevel@tonic-gate GlPendingIO pending_io; /* The type of I/O that is currently pending */ 391*7c478bd9Sstevel@tonic-gate GlReturnStatus rtn_status; /* The reason why gl_get_line() returned */ 392*7c478bd9Sstevel@tonic-gate int rtn_errno; /* THe value of errno associated with rtn_status */ 393*7c478bd9Sstevel@tonic-gate size_t linelen; /* The max number of characters per line */ 394*7c478bd9Sstevel@tonic-gate char *line; /* A line-input buffer of allocated size */ 395*7c478bd9Sstevel@tonic-gate /* linelen+2. The extra 2 characters are */ 396*7c478bd9Sstevel@tonic-gate /* reserved for "\n\0". */ 397*7c478bd9Sstevel@tonic-gate char *cutbuf; /* A cut-buffer of the same size as line[] */ 398*7c478bd9Sstevel@tonic-gate char *prompt; /* The current prompt string */ 399*7c478bd9Sstevel@tonic-gate int prompt_len; /* The length of the prompt string */ 400*7c478bd9Sstevel@tonic-gate int prompt_changed; /* True after a callback changes the prompt */ 401*7c478bd9Sstevel@tonic-gate int prompt_style; /* How the prompt string is displayed */ 402*7c478bd9Sstevel@tonic-gate FreeList *cpl_mem; /* Memory for GlCplCallback objects */ 403*7c478bd9Sstevel@tonic-gate FreeList *ext_act_mem; /* Memory for GlExternalAction objects */ 404*7c478bd9Sstevel@tonic-gate FreeList *sig_mem; /* Memory for nodes of the signal list */ 405*7c478bd9Sstevel@tonic-gate GlSignalNode *sigs; /* The head of the list of signals */ 406*7c478bd9Sstevel@tonic-gate int signals_masked; /* True between calls to gl_mask_signals() and */ 407*7c478bd9Sstevel@tonic-gate /* gl_unmask_signals() */ 408*7c478bd9Sstevel@tonic-gate int signals_overriden; /* True between calls to gl_override_signals() */ 409*7c478bd9Sstevel@tonic-gate /* and gl_restore_signals() */ 410*7c478bd9Sstevel@tonic-gate sigset_t all_signal_set; /* The set of all signals that we are trapping */ 411*7c478bd9Sstevel@tonic-gate sigset_t old_signal_set; /* The set of blocked signals on entry to */ 412*7c478bd9Sstevel@tonic-gate /* gl_get_line(). */ 413*7c478bd9Sstevel@tonic-gate sigset_t use_signal_set; /* The subset of all_signal_set to unblock */ 414*7c478bd9Sstevel@tonic-gate /* while waiting for key-strokes */ 415*7c478bd9Sstevel@tonic-gate Termios oldattr; /* Saved terminal attributes. */ 416*7c478bd9Sstevel@tonic-gate KeyTab *bindings; /* A table of key-bindings */ 417*7c478bd9Sstevel@tonic-gate int ntotal; /* The number of characters in gl->line[] */ 418*7c478bd9Sstevel@tonic-gate int buff_curpos; /* The cursor position within gl->line[] */ 419*7c478bd9Sstevel@tonic-gate int term_curpos; /* The cursor position on the terminal */ 420*7c478bd9Sstevel@tonic-gate int term_len; /* The number of terminal characters used to */ 421*7c478bd9Sstevel@tonic-gate /* display the current input line. */ 422*7c478bd9Sstevel@tonic-gate int buff_mark; /* A marker location in the buffer */ 423*7c478bd9Sstevel@tonic-gate int insert_curpos; /* The cursor position at start of insert */ 424*7c478bd9Sstevel@tonic-gate int insert; /* True in insert mode */ 425*7c478bd9Sstevel@tonic-gate int number; /* If >= 0, a numeric argument is being read */ 426*7c478bd9Sstevel@tonic-gate int endline; /* True to tell gl_get_input_line() to return */ 427*7c478bd9Sstevel@tonic-gate /* the current contents of gl->line[] */ 428*7c478bd9Sstevel@tonic-gate int displayed; /* True if an input line is currently displayed */ 429*7c478bd9Sstevel@tonic-gate int redisplay; /* If true, the input line will be redrawn */ 430*7c478bd9Sstevel@tonic-gate /* either after the current action function */ 431*7c478bd9Sstevel@tonic-gate /* returns, or when gl_get_input_line() */ 432*7c478bd9Sstevel@tonic-gate /* is next called. */ 433*7c478bd9Sstevel@tonic-gate int postpone; /* _gl_normal_io() sets this flag, to */ 434*7c478bd9Sstevel@tonic-gate /* postpone any redisplays until */ 435*7c478bd9Sstevel@tonic-gate /* is next called, to resume line editing. */ 436*7c478bd9Sstevel@tonic-gate char keybuf[GL_KEY_MAX+1]; /* A buffer of currently unprocessed key presses */ 437*7c478bd9Sstevel@tonic-gate int nbuf; /* The number of characters in keybuf[] */ 438*7c478bd9Sstevel@tonic-gate int nread; /* The number of characters read from keybuf[] */ 439*7c478bd9Sstevel@tonic-gate KtAction current_action; /* The action function that is being invoked */ 440*7c478bd9Sstevel@tonic-gate int current_count; /* The repeat count passed to */ 441*7c478bd9Sstevel@tonic-gate /* current_acction.fn() */ 442*7c478bd9Sstevel@tonic-gate GlhLineID preload_id; /* When not zero, this should be the ID of a */ 443*7c478bd9Sstevel@tonic-gate /* line in the history buffer for potential */ 444*7c478bd9Sstevel@tonic-gate /* recall. */ 445*7c478bd9Sstevel@tonic-gate int preload_history; /* If true, preload the above history line when */ 446*7c478bd9Sstevel@tonic-gate /* gl_get_input_line() is next called. */ 447*7c478bd9Sstevel@tonic-gate long keyseq_count; /* The number of key sequences entered by the */ 448*7c478bd9Sstevel@tonic-gate /* the user since new_GetLine() was called. */ 449*7c478bd9Sstevel@tonic-gate long last_search; /* The value of keyseq_count during the last */ 450*7c478bd9Sstevel@tonic-gate /* history search operation. */ 451*7c478bd9Sstevel@tonic-gate GlEditor editor; /* The style of editing, (eg. vi or emacs) */ 452*7c478bd9Sstevel@tonic-gate int silence_bell; /* True if gl_ring_bell() should do nothing. */ 453*7c478bd9Sstevel@tonic-gate int automatic_history; /* True to automatically archive entered lines */ 454*7c478bd9Sstevel@tonic-gate /* in the history list. */ 455*7c478bd9Sstevel@tonic-gate ViMode vi; /* Parameters used when editing in vi mode */ 456*7c478bd9Sstevel@tonic-gate const char *left; /* The string that moves the cursor 1 character */ 457*7c478bd9Sstevel@tonic-gate /* left. */ 458*7c478bd9Sstevel@tonic-gate const char *right; /* The string that moves the cursor 1 character */ 459*7c478bd9Sstevel@tonic-gate /* right. */ 460*7c478bd9Sstevel@tonic-gate const char *up; /* The string that moves the cursor 1 character */ 461*7c478bd9Sstevel@tonic-gate /* up. */ 462*7c478bd9Sstevel@tonic-gate const char *down; /* The string that moves the cursor 1 character */ 463*7c478bd9Sstevel@tonic-gate /* down. */ 464*7c478bd9Sstevel@tonic-gate const char *home; /* The string that moves the cursor home */ 465*7c478bd9Sstevel@tonic-gate const char *bol; /* Move cursor to beginning of line */ 466*7c478bd9Sstevel@tonic-gate const char *clear_eol; /* The string that clears from the cursor to */ 467*7c478bd9Sstevel@tonic-gate /* the end of the line. */ 468*7c478bd9Sstevel@tonic-gate const char *clear_eod; /* The string that clears from the cursor to */ 469*7c478bd9Sstevel@tonic-gate /* the end of the display. */ 470*7c478bd9Sstevel@tonic-gate const char *u_arrow; /* The string returned by the up-arrow key */ 471*7c478bd9Sstevel@tonic-gate const char *d_arrow; /* The string returned by the down-arrow key */ 472*7c478bd9Sstevel@tonic-gate const char *l_arrow; /* The string returned by the left-arrow key */ 473*7c478bd9Sstevel@tonic-gate const char *r_arrow; /* The string returned by the right-arrow key */ 474*7c478bd9Sstevel@tonic-gate const char *sound_bell; /* The string needed to ring the terminal bell */ 475*7c478bd9Sstevel@tonic-gate const char *bold; /* Switch to the bold font */ 476*7c478bd9Sstevel@tonic-gate const char *underline; /* Underline subsequent characters */ 477*7c478bd9Sstevel@tonic-gate const char *standout; /* Turn on standout mode */ 478*7c478bd9Sstevel@tonic-gate const char *dim; /* Switch to a dim font */ 479*7c478bd9Sstevel@tonic-gate const char *reverse; /* Turn on reverse video */ 480*7c478bd9Sstevel@tonic-gate const char *blink; /* Switch to a blinking font */ 481*7c478bd9Sstevel@tonic-gate const char *text_attr_off; /* Turn off all text attributes */ 482*7c478bd9Sstevel@tonic-gate int nline; /* The height of the terminal in lines */ 483*7c478bd9Sstevel@tonic-gate int ncolumn; /* The width of the terminal in columns */ 484*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMCAP 485*7c478bd9Sstevel@tonic-gate char *tgetent_buf; /* The buffer that is used by tgetent() to */ 486*7c478bd9Sstevel@tonic-gate /* store a terminal description. */ 487*7c478bd9Sstevel@tonic-gate char *tgetstr_buf; /* The buffer that is used by tgetstr() to */ 488*7c478bd9Sstevel@tonic-gate /* store terminal capabilities. */ 489*7c478bd9Sstevel@tonic-gate #endif 490*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 491*7c478bd9Sstevel@tonic-gate const char *left_n; /* The parameter string that moves the cursor */ 492*7c478bd9Sstevel@tonic-gate /* n characters left. */ 493*7c478bd9Sstevel@tonic-gate const char *right_n; /* The parameter string that moves the cursor */ 494*7c478bd9Sstevel@tonic-gate /* n characters right. */ 495*7c478bd9Sstevel@tonic-gate #endif 496*7c478bd9Sstevel@tonic-gate char *app_file; /* The pathname of the application-specific */ 497*7c478bd9Sstevel@tonic-gate /* .teclarc configuration file, or NULL. */ 498*7c478bd9Sstevel@tonic-gate char *user_file; /* The pathname of the user-specific */ 499*7c478bd9Sstevel@tonic-gate /* .teclarc configuration file, or NULL. */ 500*7c478bd9Sstevel@tonic-gate int configured; /* True as soon as any teclarc configuration */ 501*7c478bd9Sstevel@tonic-gate /* file has been read. */ 502*7c478bd9Sstevel@tonic-gate int echo; /* True to display the line as it is being */ 503*7c478bd9Sstevel@tonic-gate /* entered. If 0, only the prompt will be */ 504*7c478bd9Sstevel@tonic-gate /* displayed, and the line will not be */ 505*7c478bd9Sstevel@tonic-gate /* archived in the history list. */ 506*7c478bd9Sstevel@tonic-gate int last_signal; /* The last signal that was caught by */ 507*7c478bd9Sstevel@tonic-gate /* the last call to gl_get_line(), or -1 */ 508*7c478bd9Sstevel@tonic-gate /* if no signal has been caught yet. */ 509*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 510*7c478bd9Sstevel@tonic-gate FreeList *fd_node_mem; /* A freelist of GlFdNode structures */ 511*7c478bd9Sstevel@tonic-gate GlFdNode *fd_nodes; /* The list of fd event descriptions */ 512*7c478bd9Sstevel@tonic-gate fd_set rfds; /* The set of fds to watch for readability */ 513*7c478bd9Sstevel@tonic-gate fd_set wfds; /* The set of fds to watch for writability */ 514*7c478bd9Sstevel@tonic-gate fd_set ufds; /* The set of fds to watch for urgent data */ 515*7c478bd9Sstevel@tonic-gate int max_fd; /* The maximum file-descriptor being watched */ 516*7c478bd9Sstevel@tonic-gate struct { /* Inactivity timeout related data */ 517*7c478bd9Sstevel@tonic-gate struct timeval dt; /* The inactivity timeout when timer.fn() */ 518*7c478bd9Sstevel@tonic-gate /* isn't 0 */ 519*7c478bd9Sstevel@tonic-gate GlTimeoutFn *fn; /* The application callback to call when */ 520*7c478bd9Sstevel@tonic-gate /* the inactivity timer expires, or 0 if */ 521*7c478bd9Sstevel@tonic-gate /* timeouts are not required. */ 522*7c478bd9Sstevel@tonic-gate void *data; /* Application provided data to be passed to */ 523*7c478bd9Sstevel@tonic-gate /* timer.fn(). */ 524*7c478bd9Sstevel@tonic-gate } timer; 525*7c478bd9Sstevel@tonic-gate #endif 526*7c478bd9Sstevel@tonic-gate }; 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * Define the max amount of space needed to store a termcap terminal 530*7c478bd9Sstevel@tonic-gate * description. Unfortunately this has to be done by guesswork, so 531*7c478bd9Sstevel@tonic-gate * there is the potential for buffer overflows if we guess too small. 532*7c478bd9Sstevel@tonic-gate * Fortunately termcap has been replaced by terminfo on most 533*7c478bd9Sstevel@tonic-gate * platforms, and with terminfo this isn't an issue. The value that I 534*7c478bd9Sstevel@tonic-gate * am using here is the conventional value, as recommended by certain 535*7c478bd9Sstevel@tonic-gate * web references. 536*7c478bd9Sstevel@tonic-gate */ 537*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMCAP 538*7c478bd9Sstevel@tonic-gate #define TERMCAP_BUF_SIZE 2048 539*7c478bd9Sstevel@tonic-gate #endif 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate /* 542*7c478bd9Sstevel@tonic-gate * Set the size of the string segments used to store terminal capability 543*7c478bd9Sstevel@tonic-gate * strings. 544*7c478bd9Sstevel@tonic-gate */ 545*7c478bd9Sstevel@tonic-gate #define CAPMEM_SEGMENT_SIZE 512 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate /* 548*7c478bd9Sstevel@tonic-gate * If no terminal size information is available, substitute the 549*7c478bd9Sstevel@tonic-gate * following vt100 default sizes. 550*7c478bd9Sstevel@tonic-gate */ 551*7c478bd9Sstevel@tonic-gate #define GL_DEF_NLINE 24 552*7c478bd9Sstevel@tonic-gate #define GL_DEF_NCOLUMN 80 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate /* 555*7c478bd9Sstevel@tonic-gate * Enumerate the attributes needed to classify different types of 556*7c478bd9Sstevel@tonic-gate * signals. These attributes reflect the standard default 557*7c478bd9Sstevel@tonic-gate * characteristics of these signals (according to Richard Steven's 558*7c478bd9Sstevel@tonic-gate * Advanced Programming in the UNIX Environment). Note that these values 559*7c478bd9Sstevel@tonic-gate * are all powers of 2, so that they can be combined in a bitwise union. 560*7c478bd9Sstevel@tonic-gate */ 561*7c478bd9Sstevel@tonic-gate typedef enum { 562*7c478bd9Sstevel@tonic-gate GLSA_TERM=1, /* A signal that terminates processes */ 563*7c478bd9Sstevel@tonic-gate GLSA_SUSP=2, /* A signal that suspends processes */ 564*7c478bd9Sstevel@tonic-gate GLSA_CONT=4, /* A signal that is sent when suspended processes resume */ 565*7c478bd9Sstevel@tonic-gate GLSA_IGN=8, /* A signal that is ignored */ 566*7c478bd9Sstevel@tonic-gate GLSA_CORE=16, /* A signal that generates a core dump */ 567*7c478bd9Sstevel@tonic-gate GLSA_HARD=32, /* A signal generated by a hardware exception */ 568*7c478bd9Sstevel@tonic-gate GLSA_SIZE=64 /* A signal indicating terminal size changes */ 569*7c478bd9Sstevel@tonic-gate } GlSigAttr; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate /* 572*7c478bd9Sstevel@tonic-gate * List the signals that we need to catch. In general these are 573*7c478bd9Sstevel@tonic-gate * those that by default terminate or suspend the process, since 574*7c478bd9Sstevel@tonic-gate * in such cases we need to restore terminal settings. 575*7c478bd9Sstevel@tonic-gate */ 576*7c478bd9Sstevel@tonic-gate static const struct GlDefSignal { 577*7c478bd9Sstevel@tonic-gate int signo; /* The number of the signal */ 578*7c478bd9Sstevel@tonic-gate unsigned flags; /* A bitwise union of GlSignalFlags enumerators */ 579*7c478bd9Sstevel@tonic-gate GlAfterSignal after; /* What to do after the signal has been delivered */ 580*7c478bd9Sstevel@tonic-gate int attr; /* The default attributes of this signal, expressed */ 581*7c478bd9Sstevel@tonic-gate /* as a bitwise union of GlSigAttr enumerators */ 582*7c478bd9Sstevel@tonic-gate int errno_value; /* What to set errno to */ 583*7c478bd9Sstevel@tonic-gate } gl_signal_list[] = { 584*7c478bd9Sstevel@tonic-gate {SIGABRT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR}, 585*7c478bd9Sstevel@tonic-gate {SIGALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0}, 586*7c478bd9Sstevel@tonic-gate {SIGCONT, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_CONT|GLSA_IGN, 0}, 587*7c478bd9Sstevel@tonic-gate #if defined(SIGHUP) 588*7c478bd9Sstevel@tonic-gate #ifdef ENOTTY 589*7c478bd9Sstevel@tonic-gate {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, ENOTTY}, 590*7c478bd9Sstevel@tonic-gate #else 591*7c478bd9Sstevel@tonic-gate {SIGHUP, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR}, 592*7c478bd9Sstevel@tonic-gate #endif 593*7c478bd9Sstevel@tonic-gate #endif 594*7c478bd9Sstevel@tonic-gate {SIGINT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR}, 595*7c478bd9Sstevel@tonic-gate #if defined(SIGPIPE) 596*7c478bd9Sstevel@tonic-gate #ifdef EPIPE 597*7c478bd9Sstevel@tonic-gate {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EPIPE}, 598*7c478bd9Sstevel@tonic-gate #else 599*7c478bd9Sstevel@tonic-gate {SIGPIPE, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR}, 600*7c478bd9Sstevel@tonic-gate #endif 601*7c478bd9Sstevel@tonic-gate #endif 602*7c478bd9Sstevel@tonic-gate #ifdef SIGPOLL 603*7c478bd9Sstevel@tonic-gate {SIGPOLL, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR}, 604*7c478bd9Sstevel@tonic-gate #endif 605*7c478bd9Sstevel@tonic-gate #ifdef SIGPWR 606*7c478bd9Sstevel@tonic-gate {SIGPWR, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_IGN, 0}, 607*7c478bd9Sstevel@tonic-gate #endif 608*7c478bd9Sstevel@tonic-gate #ifdef SIGQUIT 609*7c478bd9Sstevel@tonic-gate {SIGQUIT, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM|GLSA_CORE, EINTR}, 610*7c478bd9Sstevel@tonic-gate #endif 611*7c478bd9Sstevel@tonic-gate {SIGTERM, GLS_SUSPEND_INPUT, GLS_ABORT, GLSA_TERM, EINTR}, 612*7c478bd9Sstevel@tonic-gate #ifdef SIGTSTP 613*7c478bd9Sstevel@tonic-gate {SIGTSTP, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0}, 614*7c478bd9Sstevel@tonic-gate #endif 615*7c478bd9Sstevel@tonic-gate #ifdef SIGTTIN 616*7c478bd9Sstevel@tonic-gate {SIGTTIN, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0}, 617*7c478bd9Sstevel@tonic-gate #endif 618*7c478bd9Sstevel@tonic-gate #ifdef SIGTTOU 619*7c478bd9Sstevel@tonic-gate {SIGTTOU, GLS_SUSPEND_INPUT, GLS_CONTINUE, GLSA_SUSP, 0}, 620*7c478bd9Sstevel@tonic-gate #endif 621*7c478bd9Sstevel@tonic-gate #ifdef SIGUSR1 622*7c478bd9Sstevel@tonic-gate {SIGUSR1, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0}, 623*7c478bd9Sstevel@tonic-gate #endif 624*7c478bd9Sstevel@tonic-gate #ifdef SIGUSR2 625*7c478bd9Sstevel@tonic-gate {SIGUSR2, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0}, 626*7c478bd9Sstevel@tonic-gate #endif 627*7c478bd9Sstevel@tonic-gate #ifdef SIGVTALRM 628*7c478bd9Sstevel@tonic-gate {SIGVTALRM, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM, 0}, 629*7c478bd9Sstevel@tonic-gate #endif 630*7c478bd9Sstevel@tonic-gate #ifdef SIGWINCH 631*7c478bd9Sstevel@tonic-gate {SIGWINCH, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_SIZE|GLSA_IGN, 0}, 632*7c478bd9Sstevel@tonic-gate #endif 633*7c478bd9Sstevel@tonic-gate #ifdef SIGXCPU 634*7c478bd9Sstevel@tonic-gate {SIGXCPU, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0}, 635*7c478bd9Sstevel@tonic-gate #endif 636*7c478bd9Sstevel@tonic-gate #ifdef SIGXFSZ 637*7c478bd9Sstevel@tonic-gate {SIGXFSZ, GLS_RESTORE_ENV, GLS_CONTINUE, GLSA_TERM|GLSA_CORE, 0}, 638*7c478bd9Sstevel@tonic-gate #endif 639*7c478bd9Sstevel@tonic-gate }; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate /* 642*7c478bd9Sstevel@tonic-gate * Define file-scope variables for use in signal handlers. 643*7c478bd9Sstevel@tonic-gate */ 644*7c478bd9Sstevel@tonic-gate static volatile sig_atomic_t gl_pending_signal = -1; 645*7c478bd9Sstevel@tonic-gate static sigjmp_buf gl_setjmp_buffer; 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate static void gl_signal_handler(int signo); 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate static int gl_check_caught_signal(GetLine *gl); 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /* 652*7c478bd9Sstevel@tonic-gate * Respond to an externally caught process suspension or 653*7c478bd9Sstevel@tonic-gate * termination signal. 654*7c478bd9Sstevel@tonic-gate */ 655*7c478bd9Sstevel@tonic-gate static void gl_suspend_process(int signo, GetLine *gl, int ngl); 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate /* Return the default attributes of a given signal */ 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate static int gl_classify_signal(int signo); 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate /* 662*7c478bd9Sstevel@tonic-gate * Unfortunately both terminfo and termcap require one to use the tputs() 663*7c478bd9Sstevel@tonic-gate * function to output terminal control characters, and this function 664*7c478bd9Sstevel@tonic-gate * doesn't allow one to specify a file stream. As a result, the following 665*7c478bd9Sstevel@tonic-gate * file-scope variable is used to pass the current output file stream. 666*7c478bd9Sstevel@tonic-gate * This is bad, but there doesn't seem to be any alternative. 667*7c478bd9Sstevel@tonic-gate */ 668*7c478bd9Sstevel@tonic-gate static GetLine *tputs_gl = NULL; 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* 671*7c478bd9Sstevel@tonic-gate * Define a tab to be a string of 8 spaces. 672*7c478bd9Sstevel@tonic-gate */ 673*7c478bd9Sstevel@tonic-gate #define TAB_WIDTH 8 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate /* 676*7c478bd9Sstevel@tonic-gate * Lookup the current size of the terminal. 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate static void gl_query_size(GetLine *gl, int *ncolumn, int *nline); 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate /* 681*7c478bd9Sstevel@tonic-gate * Getline calls this to temporarily override certain signal handlers 682*7c478bd9Sstevel@tonic-gate * of the calling program. 683*7c478bd9Sstevel@tonic-gate */ 684*7c478bd9Sstevel@tonic-gate static int gl_override_signal_handlers(GetLine *gl); 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate /* 687*7c478bd9Sstevel@tonic-gate * Getline calls this to restore the signal handlers of the calling 688*7c478bd9Sstevel@tonic-gate * program. 689*7c478bd9Sstevel@tonic-gate */ 690*7c478bd9Sstevel@tonic-gate static int gl_restore_signal_handlers(GetLine *gl); 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* 693*7c478bd9Sstevel@tonic-gate * Temporarily block the delivery of all signals that gl_get_line() 694*7c478bd9Sstevel@tonic-gate * is currently configured to trap. 695*7c478bd9Sstevel@tonic-gate */ 696*7c478bd9Sstevel@tonic-gate static int gl_mask_signals(GetLine *gl, sigset_t *oldset); 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate /* 699*7c478bd9Sstevel@tonic-gate * Restore the process signal mask that was overriden by a previous 700*7c478bd9Sstevel@tonic-gate * call to gl_mask_signals(). 701*7c478bd9Sstevel@tonic-gate */ 702*7c478bd9Sstevel@tonic-gate static int gl_unmask_signals(GetLine *gl, sigset_t *oldset); 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate /* 705*7c478bd9Sstevel@tonic-gate * Unblock the signals that gl_get_line() has been configured to catch. 706*7c478bd9Sstevel@tonic-gate */ 707*7c478bd9Sstevel@tonic-gate static int gl_catch_signals(GetLine *gl); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate /* 710*7c478bd9Sstevel@tonic-gate * Return the set of all trappable signals. 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate static void gl_list_trappable_signals(sigset_t *signals); 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate /* 715*7c478bd9Sstevel@tonic-gate * Put the terminal into raw input mode, after saving the original 716*7c478bd9Sstevel@tonic-gate * terminal attributes in gl->oldattr. 717*7c478bd9Sstevel@tonic-gate */ 718*7c478bd9Sstevel@tonic-gate static int gl_raw_terminal_mode(GetLine *gl); 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate /* 721*7c478bd9Sstevel@tonic-gate * Restore the terminal attributes from gl->oldattr. 722*7c478bd9Sstevel@tonic-gate */ 723*7c478bd9Sstevel@tonic-gate static int gl_restore_terminal_attributes(GetLine *gl); 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate /* 726*7c478bd9Sstevel@tonic-gate * Switch to non-blocking I/O if possible. 727*7c478bd9Sstevel@tonic-gate */ 728*7c478bd9Sstevel@tonic-gate static int gl_nonblocking_io(GetLine *gl, int fd); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate /* 731*7c478bd9Sstevel@tonic-gate * Switch to blocking I/O if possible. 732*7c478bd9Sstevel@tonic-gate */ 733*7c478bd9Sstevel@tonic-gate static int gl_blocking_io(GetLine *gl, int fd); 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate /* 736*7c478bd9Sstevel@tonic-gate * Read a line from the user in raw mode. 737*7c478bd9Sstevel@tonic-gate */ 738*7c478bd9Sstevel@tonic-gate static int gl_get_input_line(GetLine *gl, const char *prompt, 739*7c478bd9Sstevel@tonic-gate const char *start_line, int start_pos); 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate /* 742*7c478bd9Sstevel@tonic-gate * Query the user for a single character. 743*7c478bd9Sstevel@tonic-gate */ 744*7c478bd9Sstevel@tonic-gate static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar); 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate /* 747*7c478bd9Sstevel@tonic-gate * Read input from a non-interactive input stream. 748*7c478bd9Sstevel@tonic-gate */ 749*7c478bd9Sstevel@tonic-gate static int gl_read_stream_line(GetLine *gl); 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate /* 752*7c478bd9Sstevel@tonic-gate * Read a single character from a non-interactive input stream. 753*7c478bd9Sstevel@tonic-gate */ 754*7c478bd9Sstevel@tonic-gate static int gl_read_stream_char(GetLine *gl); 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate /* 757*7c478bd9Sstevel@tonic-gate * Prepare to edit a new line. 758*7c478bd9Sstevel@tonic-gate */ 759*7c478bd9Sstevel@tonic-gate static int gl_present_line(GetLine *gl, const char *prompt, 760*7c478bd9Sstevel@tonic-gate const char *start_line, int start_pos); 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate /* 763*7c478bd9Sstevel@tonic-gate * Reset all line input parameters for a new input line. 764*7c478bd9Sstevel@tonic-gate */ 765*7c478bd9Sstevel@tonic-gate static void gl_reset_input_line(GetLine *gl); 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate /* 768*7c478bd9Sstevel@tonic-gate * Handle the receipt of the potential start of a new key-sequence from 769*7c478bd9Sstevel@tonic-gate * the user. 770*7c478bd9Sstevel@tonic-gate */ 771*7c478bd9Sstevel@tonic-gate static int gl_interpret_char(GetLine *gl, char c); 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate /* 774*7c478bd9Sstevel@tonic-gate * Bind a single control or meta character to an action. 775*7c478bd9Sstevel@tonic-gate */ 776*7c478bd9Sstevel@tonic-gate static int gl_bind_control_char(GetLine *gl, KtBinder binder, 777*7c478bd9Sstevel@tonic-gate char c, const char *action); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate /* 780*7c478bd9Sstevel@tonic-gate * Set up terminal-specific key bindings. 781*7c478bd9Sstevel@tonic-gate */ 782*7c478bd9Sstevel@tonic-gate static int gl_bind_terminal_keys(GetLine *gl); 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate /* 785*7c478bd9Sstevel@tonic-gate * Lookup terminal control string and size information. 786*7c478bd9Sstevel@tonic-gate */ 787*7c478bd9Sstevel@tonic-gate static int gl_control_strings(GetLine *gl, const char *term); 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate /* 790*7c478bd9Sstevel@tonic-gate * Wrappers around the terminfo and termcap functions that lookup 791*7c478bd9Sstevel@tonic-gate * strings in the terminal information databases. 792*7c478bd9Sstevel@tonic-gate */ 793*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 794*7c478bd9Sstevel@tonic-gate static const char *gl_tigetstr(GetLine *gl, const char *name); 795*7c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP) 796*7c478bd9Sstevel@tonic-gate static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr); 797*7c478bd9Sstevel@tonic-gate #endif 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate /* 800*7c478bd9Sstevel@tonic-gate * Output a binary string directly to the terminal. 801*7c478bd9Sstevel@tonic-gate */ 802*7c478bd9Sstevel@tonic-gate static int gl_print_raw_string(GetLine *gl, int buffered, 803*7c478bd9Sstevel@tonic-gate const char *string, int n); 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate /* 806*7c478bd9Sstevel@tonic-gate * Print an informational message, starting and finishing on new lines. 807*7c478bd9Sstevel@tonic-gate * After the list of strings to be printed, the last argument MUST be 808*7c478bd9Sstevel@tonic-gate * GL_END_INFO. 809*7c478bd9Sstevel@tonic-gate */ 810*7c478bd9Sstevel@tonic-gate static int gl_print_info(GetLine *gl, ...); 811*7c478bd9Sstevel@tonic-gate #define GL_END_INFO ((const char *)0) 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate /* 814*7c478bd9Sstevel@tonic-gate * Start a newline and place the cursor at its start. 815*7c478bd9Sstevel@tonic-gate */ 816*7c478bd9Sstevel@tonic-gate static int gl_start_newline(GetLine *gl, int buffered); 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate /* 819*7c478bd9Sstevel@tonic-gate * Output a terminal control sequence. 820*7c478bd9Sstevel@tonic-gate */ 821*7c478bd9Sstevel@tonic-gate static int gl_print_control_sequence(GetLine *gl, int nline, 822*7c478bd9Sstevel@tonic-gate const char *string); 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate /* 825*7c478bd9Sstevel@tonic-gate * Output a character or string to the terminal after converting tabs 826*7c478bd9Sstevel@tonic-gate * to spaces and control characters to a caret followed by the modified 827*7c478bd9Sstevel@tonic-gate * character. 828*7c478bd9Sstevel@tonic-gate */ 829*7c478bd9Sstevel@tonic-gate static int gl_print_char(GetLine *gl, char c, char pad); 830*7c478bd9Sstevel@tonic-gate static int gl_print_string(GetLine *gl, const char *string, char pad); 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate /* 833*7c478bd9Sstevel@tonic-gate * Delete nc characters starting from the one under the cursor. 834*7c478bd9Sstevel@tonic-gate * Optionally copy the deleted characters to the cut buffer. 835*7c478bd9Sstevel@tonic-gate */ 836*7c478bd9Sstevel@tonic-gate static int gl_delete_chars(GetLine *gl, int nc, int cut); 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate /* 839*7c478bd9Sstevel@tonic-gate * Add a character to the line buffer at the current cursor position, 840*7c478bd9Sstevel@tonic-gate * inserting or overwriting according the current mode. 841*7c478bd9Sstevel@tonic-gate */ 842*7c478bd9Sstevel@tonic-gate static int gl_add_char_to_line(GetLine *gl, char c); 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate /* 845*7c478bd9Sstevel@tonic-gate * Insert/append a string to the line buffer and terminal at the current 846*7c478bd9Sstevel@tonic-gate * cursor position. 847*7c478bd9Sstevel@tonic-gate */ 848*7c478bd9Sstevel@tonic-gate static int gl_add_string_to_line(GetLine *gl, const char *s); 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate /* 851*7c478bd9Sstevel@tonic-gate * Record a new character in the input-line buffer. 852*7c478bd9Sstevel@tonic-gate */ 853*7c478bd9Sstevel@tonic-gate static int gl_buffer_char(GetLine *gl, char c, int bufpos); 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate /* 856*7c478bd9Sstevel@tonic-gate * Record a string in the input-line buffer. 857*7c478bd9Sstevel@tonic-gate */ 858*7c478bd9Sstevel@tonic-gate static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos); 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate /* 861*7c478bd9Sstevel@tonic-gate * Make way to insert a string in the input-line buffer. 862*7c478bd9Sstevel@tonic-gate */ 863*7c478bd9Sstevel@tonic-gate static int gl_make_gap_in_buffer(GetLine *gl, int start, int n); 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate /* 866*7c478bd9Sstevel@tonic-gate * Remove characters from the input-line buffer, and move any characters 867*7c478bd9Sstevel@tonic-gate * that followed them to the start of the vacated space. 868*7c478bd9Sstevel@tonic-gate */ 869*7c478bd9Sstevel@tonic-gate static void gl_remove_from_buffer(GetLine *gl, int start, int n); 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate /* 872*7c478bd9Sstevel@tonic-gate * Terminate the input-line buffer after a specified number of characters. 873*7c478bd9Sstevel@tonic-gate */ 874*7c478bd9Sstevel@tonic-gate static int gl_truncate_buffer(GetLine *gl, int n); 875*7c478bd9Sstevel@tonic-gate 876*7c478bd9Sstevel@tonic-gate /* 877*7c478bd9Sstevel@tonic-gate * Delete the displayed part of the input line that follows the current 878*7c478bd9Sstevel@tonic-gate * terminal cursor position. 879*7c478bd9Sstevel@tonic-gate */ 880*7c478bd9Sstevel@tonic-gate static int gl_truncate_display(GetLine *gl); 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate /* 883*7c478bd9Sstevel@tonic-gate * Accomodate changes to the contents of the input line buffer 884*7c478bd9Sstevel@tonic-gate * that weren't made by the above gl_*buffer functions. 885*7c478bd9Sstevel@tonic-gate */ 886*7c478bd9Sstevel@tonic-gate static void gl_update_buffer(GetLine *gl); 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate /* 889*7c478bd9Sstevel@tonic-gate * Read a single character from the terminal. 890*7c478bd9Sstevel@tonic-gate */ 891*7c478bd9Sstevel@tonic-gate static int gl_read_terminal(GetLine *gl, int keep, char *c); 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate /* 894*7c478bd9Sstevel@tonic-gate * Discard processed characters from the key-press lookahead buffer. 895*7c478bd9Sstevel@tonic-gate */ 896*7c478bd9Sstevel@tonic-gate static void gl_discard_chars(GetLine *gl, int nused); 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate /* 899*7c478bd9Sstevel@tonic-gate * Move the terminal cursor n positions to the left or right. 900*7c478bd9Sstevel@tonic-gate */ 901*7c478bd9Sstevel@tonic-gate static int gl_terminal_move_cursor(GetLine *gl, int n); 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate /* 904*7c478bd9Sstevel@tonic-gate * Move the terminal cursor to a given position. 905*7c478bd9Sstevel@tonic-gate */ 906*7c478bd9Sstevel@tonic-gate static int gl_set_term_curpos(GetLine *gl, int term_curpos); 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate /* 909*7c478bd9Sstevel@tonic-gate * Set the position of the cursor both in the line input buffer and on the 910*7c478bd9Sstevel@tonic-gate * terminal. 911*7c478bd9Sstevel@tonic-gate */ 912*7c478bd9Sstevel@tonic-gate static int gl_place_cursor(GetLine *gl, int buff_curpos); 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* 915*7c478bd9Sstevel@tonic-gate * How many characters are needed to write a number as an octal string? 916*7c478bd9Sstevel@tonic-gate */ 917*7c478bd9Sstevel@tonic-gate static int gl_octal_width(unsigned num); 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate /* 920*7c478bd9Sstevel@tonic-gate * Return the number of spaces needed to display a tab character at 921*7c478bd9Sstevel@tonic-gate * a given location of the terminal. 922*7c478bd9Sstevel@tonic-gate */ 923*7c478bd9Sstevel@tonic-gate static int gl_displayed_tab_width(GetLine *gl, int term_curpos); 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate /* 926*7c478bd9Sstevel@tonic-gate * Return the number of terminal characters needed to display a 927*7c478bd9Sstevel@tonic-gate * given raw character. 928*7c478bd9Sstevel@tonic-gate */ 929*7c478bd9Sstevel@tonic-gate static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos); 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate /* 932*7c478bd9Sstevel@tonic-gate * Return the number of terminal characters needed to display a 933*7c478bd9Sstevel@tonic-gate * given substring. 934*7c478bd9Sstevel@tonic-gate */ 935*7c478bd9Sstevel@tonic-gate static int gl_displayed_string_width(GetLine *gl, const char *string, int nc, 936*7c478bd9Sstevel@tonic-gate int term_curpos); 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate /* 939*7c478bd9Sstevel@tonic-gate * Return non-zero if 'c' is to be considered part of a word. 940*7c478bd9Sstevel@tonic-gate */ 941*7c478bd9Sstevel@tonic-gate static int gl_is_word_char(int c); 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate /* 944*7c478bd9Sstevel@tonic-gate * Read a tecla configuration file. 945*7c478bd9Sstevel@tonic-gate */ 946*7c478bd9Sstevel@tonic-gate static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who); 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate /* 949*7c478bd9Sstevel@tonic-gate * Read a tecla configuration string. 950*7c478bd9Sstevel@tonic-gate */ 951*7c478bd9Sstevel@tonic-gate static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who); 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate /* 954*7c478bd9Sstevel@tonic-gate * Define the callback function used by _gl_parse_config_line() to 955*7c478bd9Sstevel@tonic-gate * read the next character of a configuration stream. 956*7c478bd9Sstevel@tonic-gate */ 957*7c478bd9Sstevel@tonic-gate #define GLC_GETC_FN(fn) int (fn)(void *stream) 958*7c478bd9Sstevel@tonic-gate typedef GLC_GETC_FN(GlcGetcFn); 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate static GLC_GETC_FN(glc_file_getc); /* Read from a file */ 961*7c478bd9Sstevel@tonic-gate static GLC_GETC_FN(glc_buff_getc); /* Read from a string */ 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate /* 964*7c478bd9Sstevel@tonic-gate * Parse a single configuration command line. 965*7c478bd9Sstevel@tonic-gate */ 966*7c478bd9Sstevel@tonic-gate static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn, 967*7c478bd9Sstevel@tonic-gate const char *origin, KtBinder who, int *lineno); 968*7c478bd9Sstevel@tonic-gate static int gl_report_config_error(GetLine *gl, const char *origin, int lineno, 969*7c478bd9Sstevel@tonic-gate const char *errmsg); 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate /* 972*7c478bd9Sstevel@tonic-gate * Bind the actual arrow key bindings to match those of the symbolic 973*7c478bd9Sstevel@tonic-gate * arrow-key bindings. 974*7c478bd9Sstevel@tonic-gate */ 975*7c478bd9Sstevel@tonic-gate static int _gl_bind_arrow_keys(GetLine *gl); 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate /* 978*7c478bd9Sstevel@tonic-gate * Copy the binding of the specified symbolic arrow-key binding to 979*7c478bd9Sstevel@tonic-gate * the terminal specific, and default arrow-key key-sequences. 980*7c478bd9Sstevel@tonic-gate */ 981*7c478bd9Sstevel@tonic-gate static int _gl_rebind_arrow_key(GetLine *gl, const char *name, 982*7c478bd9Sstevel@tonic-gate const char *term_seq, 983*7c478bd9Sstevel@tonic-gate const char *def_seq1, 984*7c478bd9Sstevel@tonic-gate const char *def_seq2); 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate /* 987*7c478bd9Sstevel@tonic-gate * After the gl_read_from_file() action has been used to tell gl_get_line() 988*7c478bd9Sstevel@tonic-gate * to temporarily read input from a file, gl_revert_input() arranges 989*7c478bd9Sstevel@tonic-gate * for input to be reverted to the input stream last registered with 990*7c478bd9Sstevel@tonic-gate * gl_change_terminal(). 991*7c478bd9Sstevel@tonic-gate */ 992*7c478bd9Sstevel@tonic-gate static void gl_revert_input(GetLine *gl); 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate /* 995*7c478bd9Sstevel@tonic-gate * Flush unwritten characters to the terminal. 996*7c478bd9Sstevel@tonic-gate */ 997*7c478bd9Sstevel@tonic-gate static int gl_flush_output(GetLine *gl); 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate /* 1000*7c478bd9Sstevel@tonic-gate * The callback through which all terminal output is routed. 1001*7c478bd9Sstevel@tonic-gate * This simply appends characters to a queue buffer, which is 1002*7c478bd9Sstevel@tonic-gate * subsequently flushed to the output channel by gl_flush_output(). 1003*7c478bd9Sstevel@tonic-gate */ 1004*7c478bd9Sstevel@tonic-gate static GL_WRITE_FN(gl_write_fn); 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate /* 1007*7c478bd9Sstevel@tonic-gate * The callback function which the output character queue object 1008*7c478bd9Sstevel@tonic-gate * calls to transfer characters to the output channel. 1009*7c478bd9Sstevel@tonic-gate */ 1010*7c478bd9Sstevel@tonic-gate static GL_WRITE_FN(gl_flush_terminal); 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate /* 1013*7c478bd9Sstevel@tonic-gate * Enumerate the possible return statuses of gl_read_input(). 1014*7c478bd9Sstevel@tonic-gate */ 1015*7c478bd9Sstevel@tonic-gate typedef enum { 1016*7c478bd9Sstevel@tonic-gate GL_READ_OK, /* A character was read successfully */ 1017*7c478bd9Sstevel@tonic-gate GL_READ_ERROR, /* A read-error occurred */ 1018*7c478bd9Sstevel@tonic-gate GL_READ_BLOCKED, /* The read would have blocked the caller */ 1019*7c478bd9Sstevel@tonic-gate GL_READ_EOF /* The end of the current input file was reached */ 1020*7c478bd9Sstevel@tonic-gate } GlReadStatus; 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate static GlReadStatus gl_read_input(GetLine *gl, char *c); 1023*7c478bd9Sstevel@tonic-gate /* 1024*7c478bd9Sstevel@tonic-gate * Private functions of gl_read_input(). 1025*7c478bd9Sstevel@tonic-gate */ 1026*7c478bd9Sstevel@tonic-gate static int gl_event_handler(GetLine *gl, int fd); 1027*7c478bd9Sstevel@tonic-gate static int gl_read_unmasked(GetLine *gl, int fd, char *c); 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate /* 1031*7c478bd9Sstevel@tonic-gate * A private function of gl_tty_signals(). 1032*7c478bd9Sstevel@tonic-gate */ 1033*7c478bd9Sstevel@tonic-gate static int gl_set_tty_signal(int signo, void (*handler)(int)); 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate /* 1036*7c478bd9Sstevel@tonic-gate * Change the editor style being emulated. 1037*7c478bd9Sstevel@tonic-gate */ 1038*7c478bd9Sstevel@tonic-gate static int gl_change_editor(GetLine *gl, GlEditor editor); 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate /* 1041*7c478bd9Sstevel@tonic-gate * Searching in a given direction, return the index of a given (or 1042*7c478bd9Sstevel@tonic-gate * read) character in the input line, or the character that precedes 1043*7c478bd9Sstevel@tonic-gate * it in the specified search direction. Return -1 if not found. 1044*7c478bd9Sstevel@tonic-gate */ 1045*7c478bd9Sstevel@tonic-gate static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c); 1046*7c478bd9Sstevel@tonic-gate 1047*7c478bd9Sstevel@tonic-gate /* 1048*7c478bd9Sstevel@tonic-gate * Return the buffer index of the nth word ending after the cursor. 1049*7c478bd9Sstevel@tonic-gate */ 1050*7c478bd9Sstevel@tonic-gate static int gl_nth_word_end_forward(GetLine *gl, int n); 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate /* 1053*7c478bd9Sstevel@tonic-gate * Return the buffer index of the nth word start after the cursor. 1054*7c478bd9Sstevel@tonic-gate */ 1055*7c478bd9Sstevel@tonic-gate static int gl_nth_word_start_forward(GetLine *gl, int n); 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate /* 1058*7c478bd9Sstevel@tonic-gate * Return the buffer index of the nth word start before the cursor. 1059*7c478bd9Sstevel@tonic-gate */ 1060*7c478bd9Sstevel@tonic-gate static int gl_nth_word_start_backward(GetLine *gl, int n); 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate /* 1063*7c478bd9Sstevel@tonic-gate * When called when vi command mode is enabled, this function saves the 1064*7c478bd9Sstevel@tonic-gate * current line and cursor position for potential restoration later 1065*7c478bd9Sstevel@tonic-gate * by the vi undo command. 1066*7c478bd9Sstevel@tonic-gate */ 1067*7c478bd9Sstevel@tonic-gate static void gl_save_for_undo(GetLine *gl); 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate /* 1070*7c478bd9Sstevel@tonic-gate * If in vi mode, switch to vi command mode. 1071*7c478bd9Sstevel@tonic-gate */ 1072*7c478bd9Sstevel@tonic-gate static void gl_vi_command_mode(GetLine *gl); 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate /* 1075*7c478bd9Sstevel@tonic-gate * In vi mode this is used to delete up to or onto a given or read 1076*7c478bd9Sstevel@tonic-gate * character in the input line. Also switch to insert mode if requested 1077*7c478bd9Sstevel@tonic-gate * after the deletion. 1078*7c478bd9Sstevel@tonic-gate */ 1079*7c478bd9Sstevel@tonic-gate static int gl_delete_find(GetLine *gl, int count, char c, int forward, 1080*7c478bd9Sstevel@tonic-gate int onto, int change); 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate /* 1083*7c478bd9Sstevel@tonic-gate * Copy the characters between the cursor and the count'th instance of 1084*7c478bd9Sstevel@tonic-gate * a specified (or read) character in the input line, into the cut buffer. 1085*7c478bd9Sstevel@tonic-gate */ 1086*7c478bd9Sstevel@tonic-gate static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto); 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate /* 1089*7c478bd9Sstevel@tonic-gate * Return the line index of the parenthesis that either matches the one under 1090*7c478bd9Sstevel@tonic-gate * the cursor, or not over a parenthesis character, the index of the next 1091*7c478bd9Sstevel@tonic-gate * close parenthesis. Return -1 if not found. 1092*7c478bd9Sstevel@tonic-gate */ 1093*7c478bd9Sstevel@tonic-gate static int gl_index_of_matching_paren(GetLine *gl); 1094*7c478bd9Sstevel@tonic-gate 1095*7c478bd9Sstevel@tonic-gate /* 1096*7c478bd9Sstevel@tonic-gate * Replace a malloc'd string (or NULL), with another malloc'd copy of 1097*7c478bd9Sstevel@tonic-gate * a string (or NULL). 1098*7c478bd9Sstevel@tonic-gate */ 1099*7c478bd9Sstevel@tonic-gate static int gl_record_string(char **sptr, const char *string); 1100*7c478bd9Sstevel@tonic-gate 1101*7c478bd9Sstevel@tonic-gate /* 1102*7c478bd9Sstevel@tonic-gate * Enumerate text display attributes as powers of two, suitable for 1103*7c478bd9Sstevel@tonic-gate * use in a bit-mask. 1104*7c478bd9Sstevel@tonic-gate */ 1105*7c478bd9Sstevel@tonic-gate typedef enum { 1106*7c478bd9Sstevel@tonic-gate GL_TXT_STANDOUT=1, /* Display text highlighted */ 1107*7c478bd9Sstevel@tonic-gate GL_TXT_UNDERLINE=2, /* Display text underlined */ 1108*7c478bd9Sstevel@tonic-gate GL_TXT_REVERSE=4, /* Display text with reverse video */ 1109*7c478bd9Sstevel@tonic-gate GL_TXT_BLINK=8, /* Display blinking text */ 1110*7c478bd9Sstevel@tonic-gate GL_TXT_DIM=16, /* Display text in a dim font */ 1111*7c478bd9Sstevel@tonic-gate GL_TXT_BOLD=32 /* Display text using a bold font */ 1112*7c478bd9Sstevel@tonic-gate } GlTextAttr; 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate /* 1115*7c478bd9Sstevel@tonic-gate * Display the prompt regardless of the current visibility mode. 1116*7c478bd9Sstevel@tonic-gate */ 1117*7c478bd9Sstevel@tonic-gate static int gl_display_prompt(GetLine *gl); 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate /* 1120*7c478bd9Sstevel@tonic-gate * Return the number of characters used by the prompt on the terminal. 1121*7c478bd9Sstevel@tonic-gate */ 1122*7c478bd9Sstevel@tonic-gate static int gl_displayed_prompt_width(GetLine *gl); 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate /* 1125*7c478bd9Sstevel@tonic-gate * Prepare to return the current input line to the caller of gl_get_line(). 1126*7c478bd9Sstevel@tonic-gate */ 1127*7c478bd9Sstevel@tonic-gate static int gl_line_ended(GetLine *gl, int newline_char); 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate /* 1130*7c478bd9Sstevel@tonic-gate * Arrange for the input line to be redisplayed when the current contents 1131*7c478bd9Sstevel@tonic-gate * of the output queue have been flushed. 1132*7c478bd9Sstevel@tonic-gate */ 1133*7c478bd9Sstevel@tonic-gate static void gl_queue_redisplay(GetLine *gl); 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate /* 1136*7c478bd9Sstevel@tonic-gate * Erase the displayed representation of the input line, without 1137*7c478bd9Sstevel@tonic-gate * touching the buffered copy. 1138*7c478bd9Sstevel@tonic-gate */ 1139*7c478bd9Sstevel@tonic-gate static int gl_erase_line(GetLine *gl); 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate /* 1142*7c478bd9Sstevel@tonic-gate * This function is called whenever the input line has been erased. 1143*7c478bd9Sstevel@tonic-gate */ 1144*7c478bd9Sstevel@tonic-gate static void gl_line_erased(GetLine *gl); 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate /* 1147*7c478bd9Sstevel@tonic-gate * Arrange for the current input line to be discarded. 1148*7c478bd9Sstevel@tonic-gate */ 1149*7c478bd9Sstevel@tonic-gate void _gl_abandon_line(GetLine *gl); 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate /* 1152*7c478bd9Sstevel@tonic-gate * The following are private internally callable versions of pertinent 1153*7c478bd9Sstevel@tonic-gate * public functions. Unlike their public wrapper functions, they don't 1154*7c478bd9Sstevel@tonic-gate * block signals while running, and assume that their arguments are valid. 1155*7c478bd9Sstevel@tonic-gate * They are designed to be called from places where signals are already 1156*7c478bd9Sstevel@tonic-gate * blocked, and where simple sanity checks have already been applied to 1157*7c478bd9Sstevel@tonic-gate * their arguments. 1158*7c478bd9Sstevel@tonic-gate */ 1159*7c478bd9Sstevel@tonic-gate static char *_gl_get_line(GetLine *gl, const char *prompt, 1160*7c478bd9Sstevel@tonic-gate const char *start_line, int start_pos); 1161*7c478bd9Sstevel@tonic-gate static int _gl_query_char(GetLine *gl, const char *prompt, char defchar); 1162*7c478bd9Sstevel@tonic-gate static int _gl_read_char(GetLine *gl); 1163*7c478bd9Sstevel@tonic-gate static int _gl_update_size(GetLine *gl); 1164*7c478bd9Sstevel@tonic-gate /* 1165*7c478bd9Sstevel@tonic-gate * Redraw the current input line to account for a change in the terminal 1166*7c478bd9Sstevel@tonic-gate * size. Also install the new size in gl. 1167*7c478bd9Sstevel@tonic-gate */ 1168*7c478bd9Sstevel@tonic-gate static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline); 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp, 1171*7c478bd9Sstevel@tonic-gate const char *term); 1172*7c478bd9Sstevel@tonic-gate static int _gl_configure_getline(GetLine *gl, const char *app_string, 1173*7c478bd9Sstevel@tonic-gate const char *app_file, const char *user_file); 1174*7c478bd9Sstevel@tonic-gate static int _gl_save_history(GetLine *gl, const char *filename, 1175*7c478bd9Sstevel@tonic-gate const char *comment, int max_lines); 1176*7c478bd9Sstevel@tonic-gate static int _gl_load_history(GetLine *gl, const char *filename, 1177*7c478bd9Sstevel@tonic-gate const char *comment); 1178*7c478bd9Sstevel@tonic-gate static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event, 1179*7c478bd9Sstevel@tonic-gate GlFdEventFn *callback, void *data); 1180*7c478bd9Sstevel@tonic-gate static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline, 1181*7c478bd9Sstevel@tonic-gate GlTerminalSize *size); 1182*7c478bd9Sstevel@tonic-gate static void _gl_replace_prompt(GetLine *gl, const char *prompt); 1183*7c478bd9Sstevel@tonic-gate static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags, 1184*7c478bd9Sstevel@tonic-gate GlAfterSignal after, int errno_value); 1185*7c478bd9Sstevel@tonic-gate static int _gl_raw_io(GetLine *gl, int redisplay); 1186*7c478bd9Sstevel@tonic-gate static int _gl_normal_io(GetLine *gl); 1187*7c478bd9Sstevel@tonic-gate static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn, 1188*7c478bd9Sstevel@tonic-gate int list_only, const char *name, 1189*7c478bd9Sstevel@tonic-gate const char *keyseq); 1190*7c478bd9Sstevel@tonic-gate static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn, 1191*7c478bd9Sstevel@tonic-gate const char *name, const char *keyseq); 1192*7c478bd9Sstevel@tonic-gate static int _gl_io_mode(GetLine *gl, GlIOMode mode); 1193*7c478bd9Sstevel@tonic-gate static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline); 1194*7c478bd9Sstevel@tonic-gate static int _gl_append_history(GetLine *gl, const char *line); 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate /* 1197*7c478bd9Sstevel@tonic-gate * Reset the completion status and associated errno value in 1198*7c478bd9Sstevel@tonic-gate * gl->rtn_status and gl->rtn_errno. 1199*7c478bd9Sstevel@tonic-gate */ 1200*7c478bd9Sstevel@tonic-gate static void gl_clear_status(GetLine *gl); 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate /* 1203*7c478bd9Sstevel@tonic-gate * Record a completion status, unless a previous abnormal completion 1204*7c478bd9Sstevel@tonic-gate * status has already been recorded for the current call. 1205*7c478bd9Sstevel@tonic-gate */ 1206*7c478bd9Sstevel@tonic-gate static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status, 1207*7c478bd9Sstevel@tonic-gate int rtn_errno); 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate /* 1210*7c478bd9Sstevel@tonic-gate * Set the maximum length of a line in a user's tecla configuration 1211*7c478bd9Sstevel@tonic-gate * file (not counting comments). 1212*7c478bd9Sstevel@tonic-gate */ 1213*7c478bd9Sstevel@tonic-gate #define GL_CONF_BUFLEN 100 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate /* 1216*7c478bd9Sstevel@tonic-gate * Set the maximum number of arguments supported by individual commands 1217*7c478bd9Sstevel@tonic-gate * in tecla configuration files. 1218*7c478bd9Sstevel@tonic-gate */ 1219*7c478bd9Sstevel@tonic-gate #define GL_CONF_MAXARG 10 1220*7c478bd9Sstevel@tonic-gate 1221*7c478bd9Sstevel@tonic-gate /* 1222*7c478bd9Sstevel@tonic-gate * Prototype the available action functions. 1223*7c478bd9Sstevel@tonic-gate */ 1224*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_user_interrupt); 1225*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_abort); 1226*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_suspend); 1227*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_stop_output); 1228*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_start_output); 1229*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_literal_next); 1230*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_cursor_left); 1231*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_cursor_right); 1232*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_insert_mode); 1233*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_beginning_of_line); 1234*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_end_of_line); 1235*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_line); 1236*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_kill_line); 1237*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_word); 1238*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_word); 1239*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_char); 1240*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_char); 1241*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_word); 1242*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_word); 1243*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_refind); 1244*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_invert_refind); 1245*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_to_column); 1246*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_to_parenthesis); 1247*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_find); 1248*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_find); 1249*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_to); 1250*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_to); 1251*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_upcase_word); 1252*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_downcase_word); 1253*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_capitalize_word); 1254*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_redisplay); 1255*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_clear_screen); 1256*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_transpose_chars); 1257*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_set_mark); 1258*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_exchange_point_and_mark); 1259*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_kill_region); 1260*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_region_as_kill); 1261*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_yank); 1262*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_up_history); 1263*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_down_history); 1264*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_search_backward); 1265*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_re_search_backward); 1266*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_search_forward); 1267*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_re_search_forward); 1268*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_complete_word); 1269*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 1270*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_expand_filename); 1271*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_read_from_file); 1272*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_read_init_files); 1273*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_glob); 1274*7c478bd9Sstevel@tonic-gate #endif 1275*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_del_char_or_list_or_eof); 1276*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_or_eof); 1277*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_beginning_of_history); 1278*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_end_of_history); 1279*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_digit_argument); 1280*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_newline); 1281*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_repeat_history); 1282*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_insert); 1283*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_overwrite); 1284*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_change_case); 1285*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_insert_at_bol); 1286*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_append_at_eol); 1287*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_append); 1288*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_kill_line); 1289*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_goto_column); 1290*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_to_word); 1291*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_replace_char); 1292*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_rest_of_line); 1293*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_line); 1294*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_bol); 1295*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_refind); 1296*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_invert_refind); 1297*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_column); 1298*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_parenthesis); 1299*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_word); 1300*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_word); 1301*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_find); 1302*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_find); 1303*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_to); 1304*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_to); 1305*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_char); 1306*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_char); 1307*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_char); 1308*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_char); 1309*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_find_char); 1310*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_find_char); 1311*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_to_char); 1312*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_to_char); 1313*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_repeat_find_char); 1314*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_invert_refind_char); 1315*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_append_yank); 1316*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_word); 1317*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_word); 1318*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_bol); 1319*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_refind); 1320*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_invert_refind); 1321*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_column); 1322*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_parenthesis); 1323*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_rest_of_line); 1324*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_line); 1325*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_find); 1326*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_find); 1327*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_to); 1328*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_to); 1329*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_undo); 1330*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_emacs_editing_mode); 1331*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_editing_mode); 1332*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_ring_bell); 1333*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_repeat_change); 1334*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_find_parenthesis); 1335*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_history); 1336*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_completions); 1337*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_run_external_action); 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate /* 1340*7c478bd9Sstevel@tonic-gate * Name the available action functions. 1341*7c478bd9Sstevel@tonic-gate */ 1342*7c478bd9Sstevel@tonic-gate static const struct {const char *name; KT_KEY_FN(*fn);} gl_actions[] = { 1343*7c478bd9Sstevel@tonic-gate {"user-interrupt", gl_user_interrupt}, 1344*7c478bd9Sstevel@tonic-gate {"abort", gl_abort}, 1345*7c478bd9Sstevel@tonic-gate {"suspend", gl_suspend}, 1346*7c478bd9Sstevel@tonic-gate {"stop-output", gl_stop_output}, 1347*7c478bd9Sstevel@tonic-gate {"start-output", gl_start_output}, 1348*7c478bd9Sstevel@tonic-gate {"literal-next", gl_literal_next}, 1349*7c478bd9Sstevel@tonic-gate {"cursor-right", gl_cursor_right}, 1350*7c478bd9Sstevel@tonic-gate {"cursor-left", gl_cursor_left}, 1351*7c478bd9Sstevel@tonic-gate {"insert-mode", gl_insert_mode}, 1352*7c478bd9Sstevel@tonic-gate {"beginning-of-line", gl_beginning_of_line}, 1353*7c478bd9Sstevel@tonic-gate {"end-of-line", gl_end_of_line}, 1354*7c478bd9Sstevel@tonic-gate {"delete-line", gl_delete_line}, 1355*7c478bd9Sstevel@tonic-gate {"kill-line", gl_kill_line}, 1356*7c478bd9Sstevel@tonic-gate {"forward-word", gl_forward_word}, 1357*7c478bd9Sstevel@tonic-gate {"backward-word", gl_backward_word}, 1358*7c478bd9Sstevel@tonic-gate {"forward-delete-char", gl_forward_delete_char}, 1359*7c478bd9Sstevel@tonic-gate {"backward-delete-char", gl_backward_delete_char}, 1360*7c478bd9Sstevel@tonic-gate {"forward-delete-word", gl_forward_delete_word}, 1361*7c478bd9Sstevel@tonic-gate {"backward-delete-word", gl_backward_delete_word}, 1362*7c478bd9Sstevel@tonic-gate {"delete-refind", gl_delete_refind}, 1363*7c478bd9Sstevel@tonic-gate {"delete-invert-refind", gl_delete_invert_refind}, 1364*7c478bd9Sstevel@tonic-gate {"delete-to-column", gl_delete_to_column}, 1365*7c478bd9Sstevel@tonic-gate {"delete-to-parenthesis", gl_delete_to_parenthesis}, 1366*7c478bd9Sstevel@tonic-gate {"forward-delete-find", gl_forward_delete_find}, 1367*7c478bd9Sstevel@tonic-gate {"backward-delete-find", gl_backward_delete_find}, 1368*7c478bd9Sstevel@tonic-gate {"forward-delete-to", gl_forward_delete_to}, 1369*7c478bd9Sstevel@tonic-gate {"backward-delete-to", gl_backward_delete_to}, 1370*7c478bd9Sstevel@tonic-gate {"upcase-word", gl_upcase_word}, 1371*7c478bd9Sstevel@tonic-gate {"downcase-word", gl_downcase_word}, 1372*7c478bd9Sstevel@tonic-gate {"capitalize-word", gl_capitalize_word}, 1373*7c478bd9Sstevel@tonic-gate {"redisplay", gl_redisplay}, 1374*7c478bd9Sstevel@tonic-gate {"clear-screen", gl_clear_screen}, 1375*7c478bd9Sstevel@tonic-gate {"transpose-chars", gl_transpose_chars}, 1376*7c478bd9Sstevel@tonic-gate {"set-mark", gl_set_mark}, 1377*7c478bd9Sstevel@tonic-gate {"exchange-point-and-mark", gl_exchange_point_and_mark}, 1378*7c478bd9Sstevel@tonic-gate {"kill-region", gl_kill_region}, 1379*7c478bd9Sstevel@tonic-gate {"copy-region-as-kill", gl_copy_region_as_kill}, 1380*7c478bd9Sstevel@tonic-gate {"yank", gl_yank}, 1381*7c478bd9Sstevel@tonic-gate {"up-history", gl_up_history}, 1382*7c478bd9Sstevel@tonic-gate {"down-history", gl_down_history}, 1383*7c478bd9Sstevel@tonic-gate {"history-search-backward", gl_history_search_backward}, 1384*7c478bd9Sstevel@tonic-gate {"history-re-search-backward", gl_history_re_search_backward}, 1385*7c478bd9Sstevel@tonic-gate {"history-search-forward", gl_history_search_forward}, 1386*7c478bd9Sstevel@tonic-gate {"history-re-search-forward", gl_history_re_search_forward}, 1387*7c478bd9Sstevel@tonic-gate {"complete-word", gl_complete_word}, 1388*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 1389*7c478bd9Sstevel@tonic-gate {"expand-filename", gl_expand_filename}, 1390*7c478bd9Sstevel@tonic-gate {"read-from-file", gl_read_from_file}, 1391*7c478bd9Sstevel@tonic-gate {"read-init-files", gl_read_init_files}, 1392*7c478bd9Sstevel@tonic-gate {"list-glob", gl_list_glob}, 1393*7c478bd9Sstevel@tonic-gate #endif 1394*7c478bd9Sstevel@tonic-gate {"del-char-or-list-or-eof", gl_del_char_or_list_or_eof}, 1395*7c478bd9Sstevel@tonic-gate {"beginning-of-history", gl_beginning_of_history}, 1396*7c478bd9Sstevel@tonic-gate {"end-of-history", gl_end_of_history}, 1397*7c478bd9Sstevel@tonic-gate {"digit-argument", gl_digit_argument}, 1398*7c478bd9Sstevel@tonic-gate {"newline", gl_newline}, 1399*7c478bd9Sstevel@tonic-gate {"repeat-history", gl_repeat_history}, 1400*7c478bd9Sstevel@tonic-gate {"vi-insert", gl_vi_insert}, 1401*7c478bd9Sstevel@tonic-gate {"vi-overwrite", gl_vi_overwrite}, 1402*7c478bd9Sstevel@tonic-gate {"vi-insert-at-bol", gl_vi_insert_at_bol}, 1403*7c478bd9Sstevel@tonic-gate {"vi-append-at-eol", gl_vi_append_at_eol}, 1404*7c478bd9Sstevel@tonic-gate {"vi-append", gl_vi_append}, 1405*7c478bd9Sstevel@tonic-gate {"change-case", gl_change_case}, 1406*7c478bd9Sstevel@tonic-gate {"backward-kill-line", gl_backward_kill_line}, 1407*7c478bd9Sstevel@tonic-gate {"goto-column", gl_goto_column}, 1408*7c478bd9Sstevel@tonic-gate {"forward-to-word", gl_forward_to_word}, 1409*7c478bd9Sstevel@tonic-gate {"vi-replace-char", gl_vi_replace_char}, 1410*7c478bd9Sstevel@tonic-gate {"vi-change-rest-of-line", gl_vi_change_rest_of_line}, 1411*7c478bd9Sstevel@tonic-gate {"vi-change-line", gl_vi_change_line}, 1412*7c478bd9Sstevel@tonic-gate {"vi-change-to-bol", gl_vi_change_to_bol}, 1413*7c478bd9Sstevel@tonic-gate {"vi-change-refind", gl_vi_change_refind}, 1414*7c478bd9Sstevel@tonic-gate {"vi-change-invert-refind", gl_vi_change_invert_refind}, 1415*7c478bd9Sstevel@tonic-gate {"vi-change-to-column", gl_vi_change_to_column}, 1416*7c478bd9Sstevel@tonic-gate {"vi-change-to-parenthesis", gl_vi_change_to_parenthesis}, 1417*7c478bd9Sstevel@tonic-gate {"forward-copy-char", gl_forward_copy_char}, 1418*7c478bd9Sstevel@tonic-gate {"backward-copy-char", gl_backward_copy_char}, 1419*7c478bd9Sstevel@tonic-gate {"forward-find-char", gl_forward_find_char}, 1420*7c478bd9Sstevel@tonic-gate {"backward-find-char", gl_backward_find_char}, 1421*7c478bd9Sstevel@tonic-gate {"forward-to-char", gl_forward_to_char}, 1422*7c478bd9Sstevel@tonic-gate {"backward-to-char", gl_backward_to_char}, 1423*7c478bd9Sstevel@tonic-gate {"repeat-find-char", gl_repeat_find_char}, 1424*7c478bd9Sstevel@tonic-gate {"invert-refind-char", gl_invert_refind_char}, 1425*7c478bd9Sstevel@tonic-gate {"append-yank", gl_append_yank}, 1426*7c478bd9Sstevel@tonic-gate {"backward-copy-word", gl_backward_copy_word}, 1427*7c478bd9Sstevel@tonic-gate {"forward-copy-word", gl_forward_copy_word}, 1428*7c478bd9Sstevel@tonic-gate {"copy-to-bol", gl_copy_to_bol}, 1429*7c478bd9Sstevel@tonic-gate {"copy-refind", gl_copy_refind}, 1430*7c478bd9Sstevel@tonic-gate {"copy-invert-refind", gl_copy_invert_refind}, 1431*7c478bd9Sstevel@tonic-gate {"copy-to-column", gl_copy_to_column}, 1432*7c478bd9Sstevel@tonic-gate {"copy-to-parenthesis", gl_copy_to_parenthesis}, 1433*7c478bd9Sstevel@tonic-gate {"copy-rest-of-line", gl_copy_rest_of_line}, 1434*7c478bd9Sstevel@tonic-gate {"copy-line", gl_copy_line}, 1435*7c478bd9Sstevel@tonic-gate {"backward-copy-find", gl_backward_copy_find}, 1436*7c478bd9Sstevel@tonic-gate {"forward-copy-find", gl_forward_copy_find}, 1437*7c478bd9Sstevel@tonic-gate {"backward-copy-to", gl_backward_copy_to}, 1438*7c478bd9Sstevel@tonic-gate {"forward-copy-to", gl_forward_copy_to}, 1439*7c478bd9Sstevel@tonic-gate {"list-or-eof", gl_list_or_eof}, 1440*7c478bd9Sstevel@tonic-gate {"vi-undo", gl_vi_undo}, 1441*7c478bd9Sstevel@tonic-gate {"vi-backward-change-word", gl_vi_backward_change_word}, 1442*7c478bd9Sstevel@tonic-gate {"vi-forward-change-word", gl_vi_forward_change_word}, 1443*7c478bd9Sstevel@tonic-gate {"vi-backward-change-find", gl_vi_backward_change_find}, 1444*7c478bd9Sstevel@tonic-gate {"vi-forward-change-find", gl_vi_forward_change_find}, 1445*7c478bd9Sstevel@tonic-gate {"vi-backward-change-to", gl_vi_backward_change_to}, 1446*7c478bd9Sstevel@tonic-gate {"vi-forward-change-to", gl_vi_forward_change_to}, 1447*7c478bd9Sstevel@tonic-gate {"vi-backward-change-char", gl_vi_backward_change_char}, 1448*7c478bd9Sstevel@tonic-gate {"vi-forward-change-char", gl_vi_forward_change_char}, 1449*7c478bd9Sstevel@tonic-gate {"emacs-mode", gl_emacs_editing_mode}, 1450*7c478bd9Sstevel@tonic-gate {"vi-mode", gl_vi_editing_mode}, 1451*7c478bd9Sstevel@tonic-gate {"ring-bell", gl_ring_bell}, 1452*7c478bd9Sstevel@tonic-gate {"vi-repeat-change", gl_vi_repeat_change}, 1453*7c478bd9Sstevel@tonic-gate {"find-parenthesis", gl_find_parenthesis}, 1454*7c478bd9Sstevel@tonic-gate {"list-history", gl_list_history}, 1455*7c478bd9Sstevel@tonic-gate }; 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate /* 1458*7c478bd9Sstevel@tonic-gate * Define the default key-bindings in emacs mode. 1459*7c478bd9Sstevel@tonic-gate */ 1460*7c478bd9Sstevel@tonic-gate static const KtKeyBinding gl_emacs_bindings[] = { 1461*7c478bd9Sstevel@tonic-gate {"right", "cursor-right"}, 1462*7c478bd9Sstevel@tonic-gate {"^F", "cursor-right"}, 1463*7c478bd9Sstevel@tonic-gate {"left", "cursor-left"}, 1464*7c478bd9Sstevel@tonic-gate {"^B", "cursor-left"}, 1465*7c478bd9Sstevel@tonic-gate {"M-i", "insert-mode"}, 1466*7c478bd9Sstevel@tonic-gate {"M-I", "insert-mode"}, 1467*7c478bd9Sstevel@tonic-gate {"^A", "beginning-of-line"}, 1468*7c478bd9Sstevel@tonic-gate {"^E", "end-of-line"}, 1469*7c478bd9Sstevel@tonic-gate {"^U", "delete-line"}, 1470*7c478bd9Sstevel@tonic-gate {"^K", "kill-line"}, 1471*7c478bd9Sstevel@tonic-gate {"M-f", "forward-word"}, 1472*7c478bd9Sstevel@tonic-gate {"M-F", "forward-word"}, 1473*7c478bd9Sstevel@tonic-gate {"M-b", "backward-word"}, 1474*7c478bd9Sstevel@tonic-gate {"M-B", "backward-word"}, 1475*7c478bd9Sstevel@tonic-gate {"^D", "del-char-or-list-or-eof"}, 1476*7c478bd9Sstevel@tonic-gate {"^H", "backward-delete-char"}, 1477*7c478bd9Sstevel@tonic-gate {"^?", "backward-delete-char"}, 1478*7c478bd9Sstevel@tonic-gate {"M-d", "forward-delete-word"}, 1479*7c478bd9Sstevel@tonic-gate {"M-D", "forward-delete-word"}, 1480*7c478bd9Sstevel@tonic-gate {"M-^H", "backward-delete-word"}, 1481*7c478bd9Sstevel@tonic-gate {"M-^?", "backward-delete-word"}, 1482*7c478bd9Sstevel@tonic-gate {"M-u", "upcase-word"}, 1483*7c478bd9Sstevel@tonic-gate {"M-U", "upcase-word"}, 1484*7c478bd9Sstevel@tonic-gate {"M-l", "downcase-word"}, 1485*7c478bd9Sstevel@tonic-gate {"M-L", "downcase-word"}, 1486*7c478bd9Sstevel@tonic-gate {"M-c", "capitalize-word"}, 1487*7c478bd9Sstevel@tonic-gate {"M-C", "capitalize-word"}, 1488*7c478bd9Sstevel@tonic-gate {"^R", "redisplay"}, 1489*7c478bd9Sstevel@tonic-gate {"^L", "clear-screen"}, 1490*7c478bd9Sstevel@tonic-gate {"^T", "transpose-chars"}, 1491*7c478bd9Sstevel@tonic-gate {"^@", "set-mark"}, 1492*7c478bd9Sstevel@tonic-gate {"^X^X", "exchange-point-and-mark"}, 1493*7c478bd9Sstevel@tonic-gate {"^W", "kill-region"}, 1494*7c478bd9Sstevel@tonic-gate {"M-w", "copy-region-as-kill"}, 1495*7c478bd9Sstevel@tonic-gate {"M-W", "copy-region-as-kill"}, 1496*7c478bd9Sstevel@tonic-gate {"^Y", "yank"}, 1497*7c478bd9Sstevel@tonic-gate {"^P", "up-history"}, 1498*7c478bd9Sstevel@tonic-gate {"up", "up-history"}, 1499*7c478bd9Sstevel@tonic-gate {"^N", "down-history"}, 1500*7c478bd9Sstevel@tonic-gate {"down", "down-history"}, 1501*7c478bd9Sstevel@tonic-gate {"M-p", "history-search-backward"}, 1502*7c478bd9Sstevel@tonic-gate {"M-P", "history-search-backward"}, 1503*7c478bd9Sstevel@tonic-gate {"M-n", "history-search-forward"}, 1504*7c478bd9Sstevel@tonic-gate {"M-N", "history-search-forward"}, 1505*7c478bd9Sstevel@tonic-gate {"\t", "complete-word"}, 1506*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 1507*7c478bd9Sstevel@tonic-gate {"^X*", "expand-filename"}, 1508*7c478bd9Sstevel@tonic-gate {"^X^F", "read-from-file"}, 1509*7c478bd9Sstevel@tonic-gate {"^X^R", "read-init-files"}, 1510*7c478bd9Sstevel@tonic-gate {"^Xg", "list-glob"}, 1511*7c478bd9Sstevel@tonic-gate {"^XG", "list-glob"}, 1512*7c478bd9Sstevel@tonic-gate #endif 1513*7c478bd9Sstevel@tonic-gate {"^Xh", "list-history"}, 1514*7c478bd9Sstevel@tonic-gate {"^XH", "list-history"}, 1515*7c478bd9Sstevel@tonic-gate {"M-<", "beginning-of-history"}, 1516*7c478bd9Sstevel@tonic-gate {"M->", "end-of-history"}, 1517*7c478bd9Sstevel@tonic-gate {"M-0", "digit-argument"}, 1518*7c478bd9Sstevel@tonic-gate {"M-1", "digit-argument"}, 1519*7c478bd9Sstevel@tonic-gate {"M-2", "digit-argument"}, 1520*7c478bd9Sstevel@tonic-gate {"M-3", "digit-argument"}, 1521*7c478bd9Sstevel@tonic-gate {"M-4", "digit-argument"}, 1522*7c478bd9Sstevel@tonic-gate {"M-5", "digit-argument"}, 1523*7c478bd9Sstevel@tonic-gate {"M-6", "digit-argument"}, 1524*7c478bd9Sstevel@tonic-gate {"M-7", "digit-argument"}, 1525*7c478bd9Sstevel@tonic-gate {"M-8", "digit-argument"}, 1526*7c478bd9Sstevel@tonic-gate {"M-9", "digit-argument"}, 1527*7c478bd9Sstevel@tonic-gate {"\r", "newline"}, 1528*7c478bd9Sstevel@tonic-gate {"\n", "newline"}, 1529*7c478bd9Sstevel@tonic-gate {"M-o", "repeat-history"}, 1530*7c478bd9Sstevel@tonic-gate {"M-C-v", "vi-mode"}, 1531*7c478bd9Sstevel@tonic-gate }; 1532*7c478bd9Sstevel@tonic-gate 1533*7c478bd9Sstevel@tonic-gate /* 1534*7c478bd9Sstevel@tonic-gate * Define the default key-bindings in vi mode. Note that in vi-mode 1535*7c478bd9Sstevel@tonic-gate * meta-key bindings are command-mode bindings. For example M-i first 1536*7c478bd9Sstevel@tonic-gate * switches to command mode if not already in that mode, then moves 1537*7c478bd9Sstevel@tonic-gate * the cursor one position right, as in vi. 1538*7c478bd9Sstevel@tonic-gate */ 1539*7c478bd9Sstevel@tonic-gate static const KtKeyBinding gl_vi_bindings[] = { 1540*7c478bd9Sstevel@tonic-gate {"^D", "list-or-eof"}, 1541*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 1542*7c478bd9Sstevel@tonic-gate {"^G", "list-glob"}, 1543*7c478bd9Sstevel@tonic-gate #endif 1544*7c478bd9Sstevel@tonic-gate {"^H", "backward-delete-char"}, 1545*7c478bd9Sstevel@tonic-gate {"\t", "complete-word"}, 1546*7c478bd9Sstevel@tonic-gate {"\r", "newline"}, 1547*7c478bd9Sstevel@tonic-gate {"\n", "newline"}, 1548*7c478bd9Sstevel@tonic-gate {"^L", "clear-screen"}, 1549*7c478bd9Sstevel@tonic-gate {"^N", "down-history"}, 1550*7c478bd9Sstevel@tonic-gate {"^P", "up-history"}, 1551*7c478bd9Sstevel@tonic-gate {"^R", "redisplay"}, 1552*7c478bd9Sstevel@tonic-gate {"^U", "backward-kill-line"}, 1553*7c478bd9Sstevel@tonic-gate {"^W", "backward-delete-word"}, 1554*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 1555*7c478bd9Sstevel@tonic-gate {"^X^F", "read-from-file"}, 1556*7c478bd9Sstevel@tonic-gate {"^X^R", "read-init-files"}, 1557*7c478bd9Sstevel@tonic-gate {"^X*", "expand-filename"}, 1558*7c478bd9Sstevel@tonic-gate #endif 1559*7c478bd9Sstevel@tonic-gate {"^?", "backward-delete-char"}, 1560*7c478bd9Sstevel@tonic-gate {"M- ", "cursor-right"}, 1561*7c478bd9Sstevel@tonic-gate {"M-$", "end-of-line"}, 1562*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 1563*7c478bd9Sstevel@tonic-gate {"M-*", "expand-filename"}, 1564*7c478bd9Sstevel@tonic-gate #endif 1565*7c478bd9Sstevel@tonic-gate {"M-+", "down-history"}, 1566*7c478bd9Sstevel@tonic-gate {"M--", "up-history"}, 1567*7c478bd9Sstevel@tonic-gate {"M-<", "beginning-of-history"}, 1568*7c478bd9Sstevel@tonic-gate {"M->", "end-of-history"}, 1569*7c478bd9Sstevel@tonic-gate {"M-^", "beginning-of-line"}, 1570*7c478bd9Sstevel@tonic-gate {"M-;", "repeat-find-char"}, 1571*7c478bd9Sstevel@tonic-gate {"M-,", "invert-refind-char"}, 1572*7c478bd9Sstevel@tonic-gate {"M-|", "goto-column"}, 1573*7c478bd9Sstevel@tonic-gate {"M-~", "change-case"}, 1574*7c478bd9Sstevel@tonic-gate {"M-.", "vi-repeat-change"}, 1575*7c478bd9Sstevel@tonic-gate {"M-%", "find-parenthesis"}, 1576*7c478bd9Sstevel@tonic-gate {"M-0", "digit-argument"}, 1577*7c478bd9Sstevel@tonic-gate {"M-1", "digit-argument"}, 1578*7c478bd9Sstevel@tonic-gate {"M-2", "digit-argument"}, 1579*7c478bd9Sstevel@tonic-gate {"M-3", "digit-argument"}, 1580*7c478bd9Sstevel@tonic-gate {"M-4", "digit-argument"}, 1581*7c478bd9Sstevel@tonic-gate {"M-5", "digit-argument"}, 1582*7c478bd9Sstevel@tonic-gate {"M-6", "digit-argument"}, 1583*7c478bd9Sstevel@tonic-gate {"M-7", "digit-argument"}, 1584*7c478bd9Sstevel@tonic-gate {"M-8", "digit-argument"}, 1585*7c478bd9Sstevel@tonic-gate {"M-9", "digit-argument"}, 1586*7c478bd9Sstevel@tonic-gate {"M-a", "vi-append"}, 1587*7c478bd9Sstevel@tonic-gate {"M-A", "vi-append-at-eol"}, 1588*7c478bd9Sstevel@tonic-gate {"M-b", "backward-word"}, 1589*7c478bd9Sstevel@tonic-gate {"M-B", "backward-word"}, 1590*7c478bd9Sstevel@tonic-gate {"M-C", "vi-change-rest-of-line"}, 1591*7c478bd9Sstevel@tonic-gate {"M-cb", "vi-backward-change-word"}, 1592*7c478bd9Sstevel@tonic-gate {"M-cB", "vi-backward-change-word"}, 1593*7c478bd9Sstevel@tonic-gate {"M-cc", "vi-change-line"}, 1594*7c478bd9Sstevel@tonic-gate {"M-ce", "vi-forward-change-word"}, 1595*7c478bd9Sstevel@tonic-gate {"M-cE", "vi-forward-change-word"}, 1596*7c478bd9Sstevel@tonic-gate {"M-cw", "vi-forward-change-word"}, 1597*7c478bd9Sstevel@tonic-gate {"M-cW", "vi-forward-change-word"}, 1598*7c478bd9Sstevel@tonic-gate {"M-cF", "vi-backward-change-find"}, 1599*7c478bd9Sstevel@tonic-gate {"M-cf", "vi-forward-change-find"}, 1600*7c478bd9Sstevel@tonic-gate {"M-cT", "vi-backward-change-to"}, 1601*7c478bd9Sstevel@tonic-gate {"M-ct", "vi-forward-change-to"}, 1602*7c478bd9Sstevel@tonic-gate {"M-c;", "vi-change-refind"}, 1603*7c478bd9Sstevel@tonic-gate {"M-c,", "vi-change-invert-refind"}, 1604*7c478bd9Sstevel@tonic-gate {"M-ch", "vi-backward-change-char"}, 1605*7c478bd9Sstevel@tonic-gate {"M-c^H", "vi-backward-change-char"}, 1606*7c478bd9Sstevel@tonic-gate {"M-c^?", "vi-backward-change-char"}, 1607*7c478bd9Sstevel@tonic-gate {"M-cl", "vi-forward-change-char"}, 1608*7c478bd9Sstevel@tonic-gate {"M-c ", "vi-forward-change-char"}, 1609*7c478bd9Sstevel@tonic-gate {"M-c^", "vi-change-to-bol"}, 1610*7c478bd9Sstevel@tonic-gate {"M-c0", "vi-change-to-bol"}, 1611*7c478bd9Sstevel@tonic-gate {"M-c$", "vi-change-rest-of-line"}, 1612*7c478bd9Sstevel@tonic-gate {"M-c|", "vi-change-to-column"}, 1613*7c478bd9Sstevel@tonic-gate {"M-c%", "vi-change-to-parenthesis"}, 1614*7c478bd9Sstevel@tonic-gate {"M-dh", "backward-delete-char"}, 1615*7c478bd9Sstevel@tonic-gate {"M-d^H", "backward-delete-char"}, 1616*7c478bd9Sstevel@tonic-gate {"M-d^?", "backward-delete-char"}, 1617*7c478bd9Sstevel@tonic-gate {"M-dl", "forward-delete-char"}, 1618*7c478bd9Sstevel@tonic-gate {"M-d ", "forward-delete-char"}, 1619*7c478bd9Sstevel@tonic-gate {"M-dd", "delete-line"}, 1620*7c478bd9Sstevel@tonic-gate {"M-db", "backward-delete-word"}, 1621*7c478bd9Sstevel@tonic-gate {"M-dB", "backward-delete-word"}, 1622*7c478bd9Sstevel@tonic-gate {"M-de", "forward-delete-word"}, 1623*7c478bd9Sstevel@tonic-gate {"M-dE", "forward-delete-word"}, 1624*7c478bd9Sstevel@tonic-gate {"M-dw", "forward-delete-word"}, 1625*7c478bd9Sstevel@tonic-gate {"M-dW", "forward-delete-word"}, 1626*7c478bd9Sstevel@tonic-gate {"M-dF", "backward-delete-find"}, 1627*7c478bd9Sstevel@tonic-gate {"M-df", "forward-delete-find"}, 1628*7c478bd9Sstevel@tonic-gate {"M-dT", "backward-delete-to"}, 1629*7c478bd9Sstevel@tonic-gate {"M-dt", "forward-delete-to"}, 1630*7c478bd9Sstevel@tonic-gate {"M-d;", "delete-refind"}, 1631*7c478bd9Sstevel@tonic-gate {"M-d,", "delete-invert-refind"}, 1632*7c478bd9Sstevel@tonic-gate {"M-d^", "backward-kill-line"}, 1633*7c478bd9Sstevel@tonic-gate {"M-d0", "backward-kill-line"}, 1634*7c478bd9Sstevel@tonic-gate {"M-d$", "kill-line"}, 1635*7c478bd9Sstevel@tonic-gate {"M-D", "kill-line"}, 1636*7c478bd9Sstevel@tonic-gate {"M-d|", "delete-to-column"}, 1637*7c478bd9Sstevel@tonic-gate {"M-d%", "delete-to-parenthesis"}, 1638*7c478bd9Sstevel@tonic-gate {"M-e", "forward-word"}, 1639*7c478bd9Sstevel@tonic-gate {"M-E", "forward-word"}, 1640*7c478bd9Sstevel@tonic-gate {"M-f", "forward-find-char"}, 1641*7c478bd9Sstevel@tonic-gate {"M-F", "backward-find-char"}, 1642*7c478bd9Sstevel@tonic-gate {"M--", "up-history"}, 1643*7c478bd9Sstevel@tonic-gate {"M-h", "cursor-left"}, 1644*7c478bd9Sstevel@tonic-gate {"M-H", "beginning-of-history"}, 1645*7c478bd9Sstevel@tonic-gate {"M-i", "vi-insert"}, 1646*7c478bd9Sstevel@tonic-gate {"M-I", "vi-insert-at-bol"}, 1647*7c478bd9Sstevel@tonic-gate {"M-j", "down-history"}, 1648*7c478bd9Sstevel@tonic-gate {"M-J", "history-search-forward"}, 1649*7c478bd9Sstevel@tonic-gate {"M-k", "up-history"}, 1650*7c478bd9Sstevel@tonic-gate {"M-K", "history-search-backward"}, 1651*7c478bd9Sstevel@tonic-gate {"M-l", "cursor-right"}, 1652*7c478bd9Sstevel@tonic-gate {"M-L", "end-of-history"}, 1653*7c478bd9Sstevel@tonic-gate {"M-n", "history-re-search-forward"}, 1654*7c478bd9Sstevel@tonic-gate {"M-N", "history-re-search-backward"}, 1655*7c478bd9Sstevel@tonic-gate {"M-p", "append-yank"}, 1656*7c478bd9Sstevel@tonic-gate {"M-P", "yank"}, 1657*7c478bd9Sstevel@tonic-gate {"M-r", "vi-replace-char"}, 1658*7c478bd9Sstevel@tonic-gate {"M-R", "vi-overwrite"}, 1659*7c478bd9Sstevel@tonic-gate {"M-s", "vi-forward-change-char"}, 1660*7c478bd9Sstevel@tonic-gate {"M-S", "vi-change-line"}, 1661*7c478bd9Sstevel@tonic-gate {"M-t", "forward-to-char"}, 1662*7c478bd9Sstevel@tonic-gate {"M-T", "backward-to-char"}, 1663*7c478bd9Sstevel@tonic-gate {"M-u", "vi-undo"}, 1664*7c478bd9Sstevel@tonic-gate {"M-w", "forward-to-word"}, 1665*7c478bd9Sstevel@tonic-gate {"M-W", "forward-to-word"}, 1666*7c478bd9Sstevel@tonic-gate {"M-x", "forward-delete-char"}, 1667*7c478bd9Sstevel@tonic-gate {"M-X", "backward-delete-char"}, 1668*7c478bd9Sstevel@tonic-gate {"M-yh", "backward-copy-char"}, 1669*7c478bd9Sstevel@tonic-gate {"M-y^H", "backward-copy-char"}, 1670*7c478bd9Sstevel@tonic-gate {"M-y^?", "backward-copy-char"}, 1671*7c478bd9Sstevel@tonic-gate {"M-yl", "forward-copy-char"}, 1672*7c478bd9Sstevel@tonic-gate {"M-y ", "forward-copy-char"}, 1673*7c478bd9Sstevel@tonic-gate {"M-ye", "forward-copy-word"}, 1674*7c478bd9Sstevel@tonic-gate {"M-yE", "forward-copy-word"}, 1675*7c478bd9Sstevel@tonic-gate {"M-yw", "forward-copy-word"}, 1676*7c478bd9Sstevel@tonic-gate {"M-yW", "forward-copy-word"}, 1677*7c478bd9Sstevel@tonic-gate {"M-yb", "backward-copy-word"}, 1678*7c478bd9Sstevel@tonic-gate {"M-yB", "backward-copy-word"}, 1679*7c478bd9Sstevel@tonic-gate {"M-yf", "forward-copy-find"}, 1680*7c478bd9Sstevel@tonic-gate {"M-yF", "backward-copy-find"}, 1681*7c478bd9Sstevel@tonic-gate {"M-yt", "forward-copy-to"}, 1682*7c478bd9Sstevel@tonic-gate {"M-yT", "backward-copy-to"}, 1683*7c478bd9Sstevel@tonic-gate {"M-y;", "copy-refind"}, 1684*7c478bd9Sstevel@tonic-gate {"M-y,", "copy-invert-refind"}, 1685*7c478bd9Sstevel@tonic-gate {"M-y^", "copy-to-bol"}, 1686*7c478bd9Sstevel@tonic-gate {"M-y0", "copy-to-bol"}, 1687*7c478bd9Sstevel@tonic-gate {"M-y$", "copy-rest-of-line"}, 1688*7c478bd9Sstevel@tonic-gate {"M-yy", "copy-line"}, 1689*7c478bd9Sstevel@tonic-gate {"M-Y", "copy-line"}, 1690*7c478bd9Sstevel@tonic-gate {"M-y|", "copy-to-column"}, 1691*7c478bd9Sstevel@tonic-gate {"M-y%", "copy-to-parenthesis"}, 1692*7c478bd9Sstevel@tonic-gate {"M-^E", "emacs-mode"}, 1693*7c478bd9Sstevel@tonic-gate {"M-^H", "cursor-left"}, 1694*7c478bd9Sstevel@tonic-gate {"M-^?", "cursor-left"}, 1695*7c478bd9Sstevel@tonic-gate {"M-^L", "clear-screen"}, 1696*7c478bd9Sstevel@tonic-gate {"M-^N", "down-history"}, 1697*7c478bd9Sstevel@tonic-gate {"M-^P", "up-history"}, 1698*7c478bd9Sstevel@tonic-gate {"M-^R", "redisplay"}, 1699*7c478bd9Sstevel@tonic-gate {"M-^D", "list-or-eof"}, 1700*7c478bd9Sstevel@tonic-gate {"M-\r", "newline"}, 1701*7c478bd9Sstevel@tonic-gate {"M-\t", "complete-word"}, 1702*7c478bd9Sstevel@tonic-gate {"M-\n", "newline"}, 1703*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 1704*7c478bd9Sstevel@tonic-gate {"M-^X^R", "read-init-files"}, 1705*7c478bd9Sstevel@tonic-gate #endif 1706*7c478bd9Sstevel@tonic-gate {"M-^Xh", "list-history"}, 1707*7c478bd9Sstevel@tonic-gate {"M-^XH", "list-history"}, 1708*7c478bd9Sstevel@tonic-gate {"down", "down-history"}, 1709*7c478bd9Sstevel@tonic-gate {"up", "up-history"}, 1710*7c478bd9Sstevel@tonic-gate {"left", "cursor-left"}, 1711*7c478bd9Sstevel@tonic-gate {"right", "cursor-right"}, 1712*7c478bd9Sstevel@tonic-gate }; 1713*7c478bd9Sstevel@tonic-gate 1714*7c478bd9Sstevel@tonic-gate /*....................................................................... 1715*7c478bd9Sstevel@tonic-gate * Create a new GetLine object. 1716*7c478bd9Sstevel@tonic-gate * 1717*7c478bd9Sstevel@tonic-gate * Input: 1718*7c478bd9Sstevel@tonic-gate * linelen size_t The maximum line length to allow for. 1719*7c478bd9Sstevel@tonic-gate * histlen size_t The number of bytes to allocate for recording 1720*7c478bd9Sstevel@tonic-gate * a circular buffer of history lines. 1721*7c478bd9Sstevel@tonic-gate * Output: 1722*7c478bd9Sstevel@tonic-gate * return GetLine * The new object, or NULL on error. 1723*7c478bd9Sstevel@tonic-gate */ 1724*7c478bd9Sstevel@tonic-gate GetLine *new_GetLine(size_t linelen, size_t histlen) 1725*7c478bd9Sstevel@tonic-gate { 1726*7c478bd9Sstevel@tonic-gate GetLine *gl; /* The object to be returned */ 1727*7c478bd9Sstevel@tonic-gate int i; 1728*7c478bd9Sstevel@tonic-gate /* 1729*7c478bd9Sstevel@tonic-gate * Check the arguments. 1730*7c478bd9Sstevel@tonic-gate */ 1731*7c478bd9Sstevel@tonic-gate if(linelen < 10) { 1732*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1733*7c478bd9Sstevel@tonic-gate return NULL; 1734*7c478bd9Sstevel@tonic-gate }; 1735*7c478bd9Sstevel@tonic-gate /* 1736*7c478bd9Sstevel@tonic-gate * Allocate the container. 1737*7c478bd9Sstevel@tonic-gate */ 1738*7c478bd9Sstevel@tonic-gate gl = (GetLine *) malloc(sizeof(GetLine)); 1739*7c478bd9Sstevel@tonic-gate if(!gl) { 1740*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1741*7c478bd9Sstevel@tonic-gate return NULL; 1742*7c478bd9Sstevel@tonic-gate }; 1743*7c478bd9Sstevel@tonic-gate /* 1744*7c478bd9Sstevel@tonic-gate * Before attempting any operation that might fail, initialize the 1745*7c478bd9Sstevel@tonic-gate * container at least up to the point at which it can safely be passed 1746*7c478bd9Sstevel@tonic-gate * to del_GetLine(). 1747*7c478bd9Sstevel@tonic-gate */ 1748*7c478bd9Sstevel@tonic-gate gl->err = NULL; 1749*7c478bd9Sstevel@tonic-gate gl->glh = NULL; 1750*7c478bd9Sstevel@tonic-gate gl->cpl = NULL; 1751*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 1752*7c478bd9Sstevel@tonic-gate gl->cplfn.fn = cpl_file_completions; 1753*7c478bd9Sstevel@tonic-gate #else 1754*7c478bd9Sstevel@tonic-gate gl->cplfn.fn = gl_no_completions; 1755*7c478bd9Sstevel@tonic-gate #endif 1756*7c478bd9Sstevel@tonic-gate gl->cplfn.data = NULL; 1757*7c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM 1758*7c478bd9Sstevel@tonic-gate gl->ef = NULL; 1759*7c478bd9Sstevel@tonic-gate #endif 1760*7c478bd9Sstevel@tonic-gate gl->capmem = NULL; 1761*7c478bd9Sstevel@tonic-gate gl->cq = NULL; 1762*7c478bd9Sstevel@tonic-gate gl->input_fd = -1; 1763*7c478bd9Sstevel@tonic-gate gl->output_fd = -1; 1764*7c478bd9Sstevel@tonic-gate gl->input_fp = NULL; 1765*7c478bd9Sstevel@tonic-gate gl->output_fp = NULL; 1766*7c478bd9Sstevel@tonic-gate gl->file_fp = NULL; 1767*7c478bd9Sstevel@tonic-gate gl->term = NULL; 1768*7c478bd9Sstevel@tonic-gate gl->is_term = 0; 1769*7c478bd9Sstevel@tonic-gate gl->flush_fn = gl_flush_terminal; 1770*7c478bd9Sstevel@tonic-gate gl->io_mode = GL_NORMAL_MODE; 1771*7c478bd9Sstevel@tonic-gate gl->raw_mode = 0; 1772*7c478bd9Sstevel@tonic-gate gl->pending_io = GLP_WRITE; /* We will start by writing the prompt */ 1773*7c478bd9Sstevel@tonic-gate gl_clear_status(gl); 1774*7c478bd9Sstevel@tonic-gate gl->linelen = linelen; 1775*7c478bd9Sstevel@tonic-gate gl->line = NULL; 1776*7c478bd9Sstevel@tonic-gate gl->cutbuf = NULL; 1777*7c478bd9Sstevel@tonic-gate gl->prompt = NULL; 1778*7c478bd9Sstevel@tonic-gate gl->prompt_len = 0; 1779*7c478bd9Sstevel@tonic-gate gl->prompt_changed = 0; 1780*7c478bd9Sstevel@tonic-gate gl->prompt_style = GL_LITERAL_PROMPT; 1781*7c478bd9Sstevel@tonic-gate gl->cpl_mem = NULL; 1782*7c478bd9Sstevel@tonic-gate gl->ext_act_mem = NULL; 1783*7c478bd9Sstevel@tonic-gate gl->sig_mem = NULL; 1784*7c478bd9Sstevel@tonic-gate gl->sigs = NULL; 1785*7c478bd9Sstevel@tonic-gate gl->signals_masked = 0; 1786*7c478bd9Sstevel@tonic-gate gl->signals_overriden = 0; 1787*7c478bd9Sstevel@tonic-gate sigemptyset(&gl->all_signal_set); 1788*7c478bd9Sstevel@tonic-gate sigemptyset(&gl->old_signal_set); 1789*7c478bd9Sstevel@tonic-gate sigemptyset(&gl->use_signal_set); 1790*7c478bd9Sstevel@tonic-gate gl->bindings = NULL; 1791*7c478bd9Sstevel@tonic-gate gl->ntotal = 0; 1792*7c478bd9Sstevel@tonic-gate gl->buff_curpos = 0; 1793*7c478bd9Sstevel@tonic-gate gl->term_curpos = 0; 1794*7c478bd9Sstevel@tonic-gate gl->term_len = 0; 1795*7c478bd9Sstevel@tonic-gate gl->buff_mark = 0; 1796*7c478bd9Sstevel@tonic-gate gl->insert_curpos = 0; 1797*7c478bd9Sstevel@tonic-gate gl->insert = 1; 1798*7c478bd9Sstevel@tonic-gate gl->number = -1; 1799*7c478bd9Sstevel@tonic-gate gl->endline = 1; 1800*7c478bd9Sstevel@tonic-gate gl->displayed = 0; 1801*7c478bd9Sstevel@tonic-gate gl->redisplay = 0; 1802*7c478bd9Sstevel@tonic-gate gl->postpone = 0; 1803*7c478bd9Sstevel@tonic-gate gl->keybuf[0]='\0'; 1804*7c478bd9Sstevel@tonic-gate gl->nbuf = 0; 1805*7c478bd9Sstevel@tonic-gate gl->nread = 0; 1806*7c478bd9Sstevel@tonic-gate gl->current_action.fn = 0; 1807*7c478bd9Sstevel@tonic-gate gl->current_action.data = NULL; 1808*7c478bd9Sstevel@tonic-gate gl->current_count = 0; 1809*7c478bd9Sstevel@tonic-gate gl->preload_id = 0; 1810*7c478bd9Sstevel@tonic-gate gl->preload_history = 0; 1811*7c478bd9Sstevel@tonic-gate gl->keyseq_count = 0; 1812*7c478bd9Sstevel@tonic-gate gl->last_search = -1; 1813*7c478bd9Sstevel@tonic-gate gl->editor = GL_EMACS_MODE; 1814*7c478bd9Sstevel@tonic-gate gl->silence_bell = 0; 1815*7c478bd9Sstevel@tonic-gate gl->automatic_history = 1; 1816*7c478bd9Sstevel@tonic-gate gl->vi.undo.line = NULL; 1817*7c478bd9Sstevel@tonic-gate gl->vi.undo.buff_curpos = 0; 1818*7c478bd9Sstevel@tonic-gate gl->vi.undo.ntotal = 0; 1819*7c478bd9Sstevel@tonic-gate gl->vi.undo.saved = 0; 1820*7c478bd9Sstevel@tonic-gate gl->vi.repeat.action.fn = 0; 1821*7c478bd9Sstevel@tonic-gate gl->vi.repeat.action.data = 0; 1822*7c478bd9Sstevel@tonic-gate gl->vi.repeat.count = 0; 1823*7c478bd9Sstevel@tonic-gate gl->vi.repeat.input_curpos = 0; 1824*7c478bd9Sstevel@tonic-gate gl->vi.repeat.command_curpos = 0; 1825*7c478bd9Sstevel@tonic-gate gl->vi.repeat.input_char = '\0'; 1826*7c478bd9Sstevel@tonic-gate gl->vi.repeat.saved = 0; 1827*7c478bd9Sstevel@tonic-gate gl->vi.repeat.active = 0; 1828*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; 1829*7c478bd9Sstevel@tonic-gate gl->vi.find_forward = 0; 1830*7c478bd9Sstevel@tonic-gate gl->vi.find_onto = 0; 1831*7c478bd9Sstevel@tonic-gate gl->vi.find_char = '\0'; 1832*7c478bd9Sstevel@tonic-gate gl->left = NULL; 1833*7c478bd9Sstevel@tonic-gate gl->right = NULL; 1834*7c478bd9Sstevel@tonic-gate gl->up = NULL; 1835*7c478bd9Sstevel@tonic-gate gl->down = NULL; 1836*7c478bd9Sstevel@tonic-gate gl->home = NULL; 1837*7c478bd9Sstevel@tonic-gate gl->bol = 0; 1838*7c478bd9Sstevel@tonic-gate gl->clear_eol = NULL; 1839*7c478bd9Sstevel@tonic-gate gl->clear_eod = NULL; 1840*7c478bd9Sstevel@tonic-gate gl->u_arrow = NULL; 1841*7c478bd9Sstevel@tonic-gate gl->d_arrow = NULL; 1842*7c478bd9Sstevel@tonic-gate gl->l_arrow = NULL; 1843*7c478bd9Sstevel@tonic-gate gl->r_arrow = NULL; 1844*7c478bd9Sstevel@tonic-gate gl->sound_bell = NULL; 1845*7c478bd9Sstevel@tonic-gate gl->bold = NULL; 1846*7c478bd9Sstevel@tonic-gate gl->underline = NULL; 1847*7c478bd9Sstevel@tonic-gate gl->standout = NULL; 1848*7c478bd9Sstevel@tonic-gate gl->dim = NULL; 1849*7c478bd9Sstevel@tonic-gate gl->reverse = NULL; 1850*7c478bd9Sstevel@tonic-gate gl->blink = NULL; 1851*7c478bd9Sstevel@tonic-gate gl->text_attr_off = NULL; 1852*7c478bd9Sstevel@tonic-gate gl->nline = 0; 1853*7c478bd9Sstevel@tonic-gate gl->ncolumn = 0; 1854*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 1855*7c478bd9Sstevel@tonic-gate gl->left_n = NULL; 1856*7c478bd9Sstevel@tonic-gate gl->right_n = NULL; 1857*7c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP) 1858*7c478bd9Sstevel@tonic-gate gl->tgetent_buf = NULL; 1859*7c478bd9Sstevel@tonic-gate gl->tgetstr_buf = NULL; 1860*7c478bd9Sstevel@tonic-gate #endif 1861*7c478bd9Sstevel@tonic-gate gl->app_file = NULL; 1862*7c478bd9Sstevel@tonic-gate gl->user_file = NULL; 1863*7c478bd9Sstevel@tonic-gate gl->configured = 0; 1864*7c478bd9Sstevel@tonic-gate gl->echo = 1; 1865*7c478bd9Sstevel@tonic-gate gl->last_signal = -1; 1866*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 1867*7c478bd9Sstevel@tonic-gate gl->fd_node_mem = NULL; 1868*7c478bd9Sstevel@tonic-gate gl->fd_nodes = NULL; 1869*7c478bd9Sstevel@tonic-gate FD_ZERO(&gl->rfds); 1870*7c478bd9Sstevel@tonic-gate FD_ZERO(&gl->wfds); 1871*7c478bd9Sstevel@tonic-gate FD_ZERO(&gl->ufds); 1872*7c478bd9Sstevel@tonic-gate gl->max_fd = 0; 1873*7c478bd9Sstevel@tonic-gate gl->timer.dt.tv_sec = 0; 1874*7c478bd9Sstevel@tonic-gate gl->timer.dt.tv_usec = 0; 1875*7c478bd9Sstevel@tonic-gate gl->timer.fn = 0; 1876*7c478bd9Sstevel@tonic-gate gl->timer.data = NULL; 1877*7c478bd9Sstevel@tonic-gate #endif 1878*7c478bd9Sstevel@tonic-gate /* 1879*7c478bd9Sstevel@tonic-gate * Allocate an error reporting buffer. 1880*7c478bd9Sstevel@tonic-gate */ 1881*7c478bd9Sstevel@tonic-gate gl->err = _new_ErrMsg(); 1882*7c478bd9Sstevel@tonic-gate if(!gl->err) 1883*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1884*7c478bd9Sstevel@tonic-gate /* 1885*7c478bd9Sstevel@tonic-gate * Allocate the history buffer. 1886*7c478bd9Sstevel@tonic-gate */ 1887*7c478bd9Sstevel@tonic-gate gl->glh = _new_GlHistory(histlen); 1888*7c478bd9Sstevel@tonic-gate if(!gl->glh) 1889*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1890*7c478bd9Sstevel@tonic-gate /* 1891*7c478bd9Sstevel@tonic-gate * Allocate the resource object for file-completion. 1892*7c478bd9Sstevel@tonic-gate */ 1893*7c478bd9Sstevel@tonic-gate gl->cpl = new_WordCompletion(); 1894*7c478bd9Sstevel@tonic-gate if(!gl->cpl) 1895*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1896*7c478bd9Sstevel@tonic-gate /* 1897*7c478bd9Sstevel@tonic-gate * Allocate the resource object for file-completion. 1898*7c478bd9Sstevel@tonic-gate */ 1899*7c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM 1900*7c478bd9Sstevel@tonic-gate gl->ef = new_ExpandFile(); 1901*7c478bd9Sstevel@tonic-gate if(!gl->ef) 1902*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1903*7c478bd9Sstevel@tonic-gate #endif 1904*7c478bd9Sstevel@tonic-gate /* 1905*7c478bd9Sstevel@tonic-gate * Allocate a string-segment memory allocator for use in storing terminal 1906*7c478bd9Sstevel@tonic-gate * capablity strings. 1907*7c478bd9Sstevel@tonic-gate */ 1908*7c478bd9Sstevel@tonic-gate gl->capmem = _new_StringGroup(CAPMEM_SEGMENT_SIZE); 1909*7c478bd9Sstevel@tonic-gate if(!gl->capmem) 1910*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1911*7c478bd9Sstevel@tonic-gate /* 1912*7c478bd9Sstevel@tonic-gate * Allocate the character queue that is used to buffer terminal output. 1913*7c478bd9Sstevel@tonic-gate */ 1914*7c478bd9Sstevel@tonic-gate gl->cq = _new_GlCharQueue(); 1915*7c478bd9Sstevel@tonic-gate if(!gl->cq) 1916*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1917*7c478bd9Sstevel@tonic-gate /* 1918*7c478bd9Sstevel@tonic-gate * Allocate a line buffer, leaving 2 extra characters for the terminating 1919*7c478bd9Sstevel@tonic-gate * '\n' and '\0' characters 1920*7c478bd9Sstevel@tonic-gate */ 1921*7c478bd9Sstevel@tonic-gate gl->line = (char *) malloc(linelen + 2); 1922*7c478bd9Sstevel@tonic-gate if(!gl->line) { 1923*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1924*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1925*7c478bd9Sstevel@tonic-gate }; 1926*7c478bd9Sstevel@tonic-gate /* 1927*7c478bd9Sstevel@tonic-gate * Start with an empty input line. 1928*7c478bd9Sstevel@tonic-gate */ 1929*7c478bd9Sstevel@tonic-gate gl_truncate_buffer(gl, 0); 1930*7c478bd9Sstevel@tonic-gate /* 1931*7c478bd9Sstevel@tonic-gate * Allocate a cut buffer. 1932*7c478bd9Sstevel@tonic-gate */ 1933*7c478bd9Sstevel@tonic-gate gl->cutbuf = (char *) malloc(linelen + 2); 1934*7c478bd9Sstevel@tonic-gate if(!gl->cutbuf) { 1935*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1936*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1937*7c478bd9Sstevel@tonic-gate }; 1938*7c478bd9Sstevel@tonic-gate gl->cutbuf[0] = '\0'; 1939*7c478bd9Sstevel@tonic-gate /* 1940*7c478bd9Sstevel@tonic-gate * Allocate an initial empty prompt. 1941*7c478bd9Sstevel@tonic-gate */ 1942*7c478bd9Sstevel@tonic-gate _gl_replace_prompt(gl, NULL); 1943*7c478bd9Sstevel@tonic-gate if(!gl->prompt) { 1944*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1945*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1946*7c478bd9Sstevel@tonic-gate }; 1947*7c478bd9Sstevel@tonic-gate /* 1948*7c478bd9Sstevel@tonic-gate * Allocate a vi undo buffer. 1949*7c478bd9Sstevel@tonic-gate */ 1950*7c478bd9Sstevel@tonic-gate gl->vi.undo.line = (char *) malloc(linelen + 2); 1951*7c478bd9Sstevel@tonic-gate if(!gl->vi.undo.line) { 1952*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1953*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1954*7c478bd9Sstevel@tonic-gate }; 1955*7c478bd9Sstevel@tonic-gate gl->vi.undo.line[0] = '\0'; 1956*7c478bd9Sstevel@tonic-gate /* 1957*7c478bd9Sstevel@tonic-gate * Allocate a freelist from which to allocate nodes for the list 1958*7c478bd9Sstevel@tonic-gate * of completion functions. 1959*7c478bd9Sstevel@tonic-gate */ 1960*7c478bd9Sstevel@tonic-gate gl->cpl_mem = _new_FreeList(sizeof(GlCplCallback), GL_CPL_FREELIST_BLOCKING); 1961*7c478bd9Sstevel@tonic-gate if(!gl->cpl_mem) 1962*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1963*7c478bd9Sstevel@tonic-gate /* 1964*7c478bd9Sstevel@tonic-gate * Allocate a freelist from which to allocate nodes for the list 1965*7c478bd9Sstevel@tonic-gate * of external action functions. 1966*7c478bd9Sstevel@tonic-gate */ 1967*7c478bd9Sstevel@tonic-gate gl->ext_act_mem = _new_FreeList(sizeof(GlExternalAction), 1968*7c478bd9Sstevel@tonic-gate GL_EXT_ACT_FREELIST_BLOCKING); 1969*7c478bd9Sstevel@tonic-gate if(!gl->ext_act_mem) 1970*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1971*7c478bd9Sstevel@tonic-gate /* 1972*7c478bd9Sstevel@tonic-gate * Allocate a freelist from which to allocate nodes for the list 1973*7c478bd9Sstevel@tonic-gate * of signals. 1974*7c478bd9Sstevel@tonic-gate */ 1975*7c478bd9Sstevel@tonic-gate gl->sig_mem = _new_FreeList(sizeof(GlSignalNode), GLS_FREELIST_BLOCKING); 1976*7c478bd9Sstevel@tonic-gate if(!gl->sig_mem) 1977*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1978*7c478bd9Sstevel@tonic-gate /* 1979*7c478bd9Sstevel@tonic-gate * Install initial dispositions for the default list of signals that 1980*7c478bd9Sstevel@tonic-gate * gl_get_line() traps. 1981*7c478bd9Sstevel@tonic-gate */ 1982*7c478bd9Sstevel@tonic-gate for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) { 1983*7c478bd9Sstevel@tonic-gate const struct GlDefSignal *sig = gl_signal_list + i; 1984*7c478bd9Sstevel@tonic-gate if(_gl_trap_signal(gl, sig->signo, sig->flags, sig->after, 1985*7c478bd9Sstevel@tonic-gate sig->errno_value)) 1986*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1987*7c478bd9Sstevel@tonic-gate }; 1988*7c478bd9Sstevel@tonic-gate /* 1989*7c478bd9Sstevel@tonic-gate * Allocate an empty table of key bindings. 1990*7c478bd9Sstevel@tonic-gate */ 1991*7c478bd9Sstevel@tonic-gate gl->bindings = _new_KeyTab(); 1992*7c478bd9Sstevel@tonic-gate if(!gl->bindings) 1993*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 1994*7c478bd9Sstevel@tonic-gate /* 1995*7c478bd9Sstevel@tonic-gate * Define the available actions that can be bound to key sequences. 1996*7c478bd9Sstevel@tonic-gate */ 1997*7c478bd9Sstevel@tonic-gate for(i=0; i<sizeof(gl_actions)/sizeof(gl_actions[0]); i++) { 1998*7c478bd9Sstevel@tonic-gate if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn, NULL)) 1999*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 2000*7c478bd9Sstevel@tonic-gate }; 2001*7c478bd9Sstevel@tonic-gate /* 2002*7c478bd9Sstevel@tonic-gate * Set up the default bindings. 2003*7c478bd9Sstevel@tonic-gate */ 2004*7c478bd9Sstevel@tonic-gate if(gl_change_editor(gl, gl->editor)) 2005*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 2006*7c478bd9Sstevel@tonic-gate /* 2007*7c478bd9Sstevel@tonic-gate * Allocate termcap buffers. 2008*7c478bd9Sstevel@tonic-gate */ 2009*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMCAP 2010*7c478bd9Sstevel@tonic-gate gl->tgetent_buf = (char *) malloc(TERMCAP_BUF_SIZE); 2011*7c478bd9Sstevel@tonic-gate gl->tgetstr_buf = (char *) malloc(TERMCAP_BUF_SIZE); 2012*7c478bd9Sstevel@tonic-gate if(!gl->tgetent_buf || !gl->tgetstr_buf) { 2013*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 2014*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 2015*7c478bd9Sstevel@tonic-gate }; 2016*7c478bd9Sstevel@tonic-gate #endif 2017*7c478bd9Sstevel@tonic-gate /* 2018*7c478bd9Sstevel@tonic-gate * Set up for I/O assuming stdin and stdout. 2019*7c478bd9Sstevel@tonic-gate */ 2020*7c478bd9Sstevel@tonic-gate if(_gl_change_terminal(gl, stdin, stdout, getenv("TERM"))) 2021*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 2022*7c478bd9Sstevel@tonic-gate /* 2023*7c478bd9Sstevel@tonic-gate * Create a freelist for use in allocating GlFdNode list nodes. 2024*7c478bd9Sstevel@tonic-gate */ 2025*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 2026*7c478bd9Sstevel@tonic-gate gl->fd_node_mem = _new_FreeList(sizeof(GlFdNode), GLFD_FREELIST_BLOCKING); 2027*7c478bd9Sstevel@tonic-gate if(!gl->fd_node_mem) 2028*7c478bd9Sstevel@tonic-gate return del_GetLine(gl); 2029*7c478bd9Sstevel@tonic-gate #endif 2030*7c478bd9Sstevel@tonic-gate /* 2031*7c478bd9Sstevel@tonic-gate * We are done for now. 2032*7c478bd9Sstevel@tonic-gate */ 2033*7c478bd9Sstevel@tonic-gate return gl; 2034*7c478bd9Sstevel@tonic-gate } 2035*7c478bd9Sstevel@tonic-gate 2036*7c478bd9Sstevel@tonic-gate /*....................................................................... 2037*7c478bd9Sstevel@tonic-gate * Delete a GetLine object. 2038*7c478bd9Sstevel@tonic-gate * 2039*7c478bd9Sstevel@tonic-gate * Input: 2040*7c478bd9Sstevel@tonic-gate * gl GetLine * The object to be deleted. 2041*7c478bd9Sstevel@tonic-gate * Output: 2042*7c478bd9Sstevel@tonic-gate * return GetLine * The deleted object (always NULL). 2043*7c478bd9Sstevel@tonic-gate */ 2044*7c478bd9Sstevel@tonic-gate GetLine *del_GetLine(GetLine *gl) 2045*7c478bd9Sstevel@tonic-gate { 2046*7c478bd9Sstevel@tonic-gate if(gl) { 2047*7c478bd9Sstevel@tonic-gate /* 2048*7c478bd9Sstevel@tonic-gate * If the terminal is in raw server mode, reset it. 2049*7c478bd9Sstevel@tonic-gate */ 2050*7c478bd9Sstevel@tonic-gate _gl_normal_io(gl); 2051*7c478bd9Sstevel@tonic-gate /* 2052*7c478bd9Sstevel@tonic-gate * Deallocate all objects contained by gl. 2053*7c478bd9Sstevel@tonic-gate */ 2054*7c478bd9Sstevel@tonic-gate gl->err = _del_ErrMsg(gl->err); 2055*7c478bd9Sstevel@tonic-gate gl->glh = _del_GlHistory(gl->glh); 2056*7c478bd9Sstevel@tonic-gate gl->cpl = del_WordCompletion(gl->cpl); 2057*7c478bd9Sstevel@tonic-gate #ifndef WITHOUT_FILE_SYSTEM 2058*7c478bd9Sstevel@tonic-gate gl->ef = del_ExpandFile(gl->ef); 2059*7c478bd9Sstevel@tonic-gate #endif 2060*7c478bd9Sstevel@tonic-gate gl->capmem = _del_StringGroup(gl->capmem); 2061*7c478bd9Sstevel@tonic-gate gl->cq = _del_GlCharQueue(gl->cq); 2062*7c478bd9Sstevel@tonic-gate if(gl->file_fp) 2063*7c478bd9Sstevel@tonic-gate fclose(gl->file_fp); 2064*7c478bd9Sstevel@tonic-gate if(gl->term) 2065*7c478bd9Sstevel@tonic-gate free(gl->term); 2066*7c478bd9Sstevel@tonic-gate if(gl->line) 2067*7c478bd9Sstevel@tonic-gate free(gl->line); 2068*7c478bd9Sstevel@tonic-gate if(gl->cutbuf) 2069*7c478bd9Sstevel@tonic-gate free(gl->cutbuf); 2070*7c478bd9Sstevel@tonic-gate if(gl->prompt) 2071*7c478bd9Sstevel@tonic-gate free(gl->prompt); 2072*7c478bd9Sstevel@tonic-gate gl->cpl_mem = _del_FreeList(gl->cpl_mem, 1); 2073*7c478bd9Sstevel@tonic-gate gl->ext_act_mem = _del_FreeList(gl->ext_act_mem, 1); 2074*7c478bd9Sstevel@tonic-gate gl->sig_mem = _del_FreeList(gl->sig_mem, 1); 2075*7c478bd9Sstevel@tonic-gate gl->sigs = NULL; /* Already freed by freeing sig_mem */ 2076*7c478bd9Sstevel@tonic-gate gl->bindings = _del_KeyTab(gl->bindings); 2077*7c478bd9Sstevel@tonic-gate if(gl->vi.undo.line) 2078*7c478bd9Sstevel@tonic-gate free(gl->vi.undo.line); 2079*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMCAP 2080*7c478bd9Sstevel@tonic-gate if(gl->tgetent_buf) 2081*7c478bd9Sstevel@tonic-gate free(gl->tgetent_buf); 2082*7c478bd9Sstevel@tonic-gate if(gl->tgetstr_buf) 2083*7c478bd9Sstevel@tonic-gate free(gl->tgetstr_buf); 2084*7c478bd9Sstevel@tonic-gate #endif 2085*7c478bd9Sstevel@tonic-gate if(gl->app_file) 2086*7c478bd9Sstevel@tonic-gate free(gl->app_file); 2087*7c478bd9Sstevel@tonic-gate if(gl->user_file) 2088*7c478bd9Sstevel@tonic-gate free(gl->user_file); 2089*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 2090*7c478bd9Sstevel@tonic-gate gl->fd_node_mem = _del_FreeList(gl->fd_node_mem, 1); 2091*7c478bd9Sstevel@tonic-gate gl->fd_nodes = NULL; /* Already freed by freeing gl->fd_node_mem */ 2092*7c478bd9Sstevel@tonic-gate #endif 2093*7c478bd9Sstevel@tonic-gate /* 2094*7c478bd9Sstevel@tonic-gate * Delete the now empty container. 2095*7c478bd9Sstevel@tonic-gate */ 2096*7c478bd9Sstevel@tonic-gate free(gl); 2097*7c478bd9Sstevel@tonic-gate }; 2098*7c478bd9Sstevel@tonic-gate return NULL; 2099*7c478bd9Sstevel@tonic-gate } 2100*7c478bd9Sstevel@tonic-gate 2101*7c478bd9Sstevel@tonic-gate /*....................................................................... 2102*7c478bd9Sstevel@tonic-gate * Bind a control or meta character to an action. 2103*7c478bd9Sstevel@tonic-gate * 2104*7c478bd9Sstevel@tonic-gate * Input: 2105*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this program. 2106*7c478bd9Sstevel@tonic-gate * binder KtBinder The source of the binding. 2107*7c478bd9Sstevel@tonic-gate * c char The control or meta character. 2108*7c478bd9Sstevel@tonic-gate * If this is '\0', the call is ignored. 2109*7c478bd9Sstevel@tonic-gate * action const char * The action name to bind the key to. 2110*7c478bd9Sstevel@tonic-gate * Output: 2111*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 2112*7c478bd9Sstevel@tonic-gate * 1 - Error. 2113*7c478bd9Sstevel@tonic-gate */ 2114*7c478bd9Sstevel@tonic-gate static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c, 2115*7c478bd9Sstevel@tonic-gate const char *action) 2116*7c478bd9Sstevel@tonic-gate { 2117*7c478bd9Sstevel@tonic-gate char keyseq[2]; 2118*7c478bd9Sstevel@tonic-gate /* 2119*7c478bd9Sstevel@tonic-gate * Quietly reject binding to the NUL control character, since this 2120*7c478bd9Sstevel@tonic-gate * is an ambiguous prefix of all bindings. 2121*7c478bd9Sstevel@tonic-gate */ 2122*7c478bd9Sstevel@tonic-gate if(c == '\0') 2123*7c478bd9Sstevel@tonic-gate return 0; 2124*7c478bd9Sstevel@tonic-gate /* 2125*7c478bd9Sstevel@tonic-gate * Making sure not to bind characters which aren't either control or 2126*7c478bd9Sstevel@tonic-gate * meta characters. 2127*7c478bd9Sstevel@tonic-gate */ 2128*7c478bd9Sstevel@tonic-gate if(IS_CTRL_CHAR(c) || IS_META_CHAR(c)) { 2129*7c478bd9Sstevel@tonic-gate keyseq[0] = c; 2130*7c478bd9Sstevel@tonic-gate keyseq[1] = '\0'; 2131*7c478bd9Sstevel@tonic-gate } else { 2132*7c478bd9Sstevel@tonic-gate return 0; 2133*7c478bd9Sstevel@tonic-gate }; 2134*7c478bd9Sstevel@tonic-gate /* 2135*7c478bd9Sstevel@tonic-gate * Install the binding. 2136*7c478bd9Sstevel@tonic-gate */ 2137*7c478bd9Sstevel@tonic-gate if(_kt_set_keybinding(gl->bindings, binder, keyseq, action)) { 2138*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG); 2139*7c478bd9Sstevel@tonic-gate return 1; 2140*7c478bd9Sstevel@tonic-gate }; 2141*7c478bd9Sstevel@tonic-gate return 0; 2142*7c478bd9Sstevel@tonic-gate } 2143*7c478bd9Sstevel@tonic-gate 2144*7c478bd9Sstevel@tonic-gate /*....................................................................... 2145*7c478bd9Sstevel@tonic-gate * Read a line from the user. 2146*7c478bd9Sstevel@tonic-gate * 2147*7c478bd9Sstevel@tonic-gate * Input: 2148*7c478bd9Sstevel@tonic-gate * gl GetLine * A resource object returned by new_GetLine(). 2149*7c478bd9Sstevel@tonic-gate * prompt char * The prompt to prefix the line with. 2150*7c478bd9Sstevel@tonic-gate * start_line char * The initial contents of the input line, or NULL 2151*7c478bd9Sstevel@tonic-gate * if it should start out empty. 2152*7c478bd9Sstevel@tonic-gate * start_pos int If start_line isn't NULL, this specifies the 2153*7c478bd9Sstevel@tonic-gate * index of the character over which the cursor 2154*7c478bd9Sstevel@tonic-gate * should initially be positioned within the line. 2155*7c478bd9Sstevel@tonic-gate * If you just want it to follow the last character 2156*7c478bd9Sstevel@tonic-gate * of the line, send -1. 2157*7c478bd9Sstevel@tonic-gate * Output: 2158*7c478bd9Sstevel@tonic-gate * return char * An internal buffer containing the input line, or 2159*7c478bd9Sstevel@tonic-gate * NULL at the end of input. If the line fitted in 2160*7c478bd9Sstevel@tonic-gate * the buffer there will be a '\n' newline character 2161*7c478bd9Sstevel@tonic-gate * before the terminating '\0'. If it was truncated 2162*7c478bd9Sstevel@tonic-gate * there will be no newline character, and the remains 2163*7c478bd9Sstevel@tonic-gate * of the line should be retrieved via further calls 2164*7c478bd9Sstevel@tonic-gate * to this function. 2165*7c478bd9Sstevel@tonic-gate */ 2166*7c478bd9Sstevel@tonic-gate char *gl_get_line(GetLine *gl, const char *prompt, 2167*7c478bd9Sstevel@tonic-gate const char *start_line, int start_pos) 2168*7c478bd9Sstevel@tonic-gate { 2169*7c478bd9Sstevel@tonic-gate char *retval; /* The return value of _gl_get_line() */ 2170*7c478bd9Sstevel@tonic-gate /* 2171*7c478bd9Sstevel@tonic-gate * Check the arguments. 2172*7c478bd9Sstevel@tonic-gate */ 2173*7c478bd9Sstevel@tonic-gate if(!gl) { 2174*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2175*7c478bd9Sstevel@tonic-gate return NULL; 2176*7c478bd9Sstevel@tonic-gate }; 2177*7c478bd9Sstevel@tonic-gate /* 2178*7c478bd9Sstevel@tonic-gate * Temporarily block all of the signals that we have been asked to trap. 2179*7c478bd9Sstevel@tonic-gate */ 2180*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &gl->old_signal_set)) 2181*7c478bd9Sstevel@tonic-gate return NULL; 2182*7c478bd9Sstevel@tonic-gate /* 2183*7c478bd9Sstevel@tonic-gate * Perform the command-line editing task. 2184*7c478bd9Sstevel@tonic-gate */ 2185*7c478bd9Sstevel@tonic-gate retval = _gl_get_line(gl, prompt, start_line, start_pos); 2186*7c478bd9Sstevel@tonic-gate /* 2187*7c478bd9Sstevel@tonic-gate * Restore the process signal mask to how it was when this function was 2188*7c478bd9Sstevel@tonic-gate * first called. 2189*7c478bd9Sstevel@tonic-gate */ 2190*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &gl->old_signal_set); 2191*7c478bd9Sstevel@tonic-gate return retval; 2192*7c478bd9Sstevel@tonic-gate } 2193*7c478bd9Sstevel@tonic-gate 2194*7c478bd9Sstevel@tonic-gate 2195*7c478bd9Sstevel@tonic-gate /*....................................................................... 2196*7c478bd9Sstevel@tonic-gate * This is the main body of the public function gl_get_line(). 2197*7c478bd9Sstevel@tonic-gate */ 2198*7c478bd9Sstevel@tonic-gate static char *_gl_get_line(GetLine *gl, const char *prompt, 2199*7c478bd9Sstevel@tonic-gate const char *start_line, int start_pos) 2200*7c478bd9Sstevel@tonic-gate { 2201*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True if an error occurs */ 2202*7c478bd9Sstevel@tonic-gate /* 2203*7c478bd9Sstevel@tonic-gate * Assume that this call will successfully complete the input 2204*7c478bd9Sstevel@tonic-gate * line until proven otherwise. 2205*7c478bd9Sstevel@tonic-gate */ 2206*7c478bd9Sstevel@tonic-gate gl_clear_status(gl); 2207*7c478bd9Sstevel@tonic-gate /* 2208*7c478bd9Sstevel@tonic-gate * If this is the first call to this function since new_GetLine(), 2209*7c478bd9Sstevel@tonic-gate * complete any postponed configuration. 2210*7c478bd9Sstevel@tonic-gate */ 2211*7c478bd9Sstevel@tonic-gate if(!gl->configured) { 2212*7c478bd9Sstevel@tonic-gate (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE); 2213*7c478bd9Sstevel@tonic-gate gl->configured = 1; 2214*7c478bd9Sstevel@tonic-gate }; 2215*7c478bd9Sstevel@tonic-gate /* 2216*7c478bd9Sstevel@tonic-gate * Before installing our signal handler functions, record the fact 2217*7c478bd9Sstevel@tonic-gate * that there are no pending signals. 2218*7c478bd9Sstevel@tonic-gate */ 2219*7c478bd9Sstevel@tonic-gate gl_pending_signal = -1; 2220*7c478bd9Sstevel@tonic-gate /* 2221*7c478bd9Sstevel@tonic-gate * Temporarily override the signal handlers of the calling program, 2222*7c478bd9Sstevel@tonic-gate * so that we can intercept signals that would leave the terminal 2223*7c478bd9Sstevel@tonic-gate * in a bad state. 2224*7c478bd9Sstevel@tonic-gate */ 2225*7c478bd9Sstevel@tonic-gate waserr = gl_override_signal_handlers(gl); 2226*7c478bd9Sstevel@tonic-gate /* 2227*7c478bd9Sstevel@tonic-gate * After recording the current terminal settings, switch the terminal 2228*7c478bd9Sstevel@tonic-gate * into raw input mode. 2229*7c478bd9Sstevel@tonic-gate */ 2230*7c478bd9Sstevel@tonic-gate waserr = waserr || _gl_raw_io(gl, 1); 2231*7c478bd9Sstevel@tonic-gate /* 2232*7c478bd9Sstevel@tonic-gate * Attempt to read the line. This will require more than one attempt if 2233*7c478bd9Sstevel@tonic-gate * either a current temporary input file is opened by gl_get_input_line() 2234*7c478bd9Sstevel@tonic-gate * or the end of a temporary input file is reached by gl_read_stream_line(). 2235*7c478bd9Sstevel@tonic-gate */ 2236*7c478bd9Sstevel@tonic-gate while(!waserr) { 2237*7c478bd9Sstevel@tonic-gate /* 2238*7c478bd9Sstevel@tonic-gate * Read a line from a non-interactive stream? 2239*7c478bd9Sstevel@tonic-gate */ 2240*7c478bd9Sstevel@tonic-gate if(gl->file_fp || !gl->is_term) { 2241*7c478bd9Sstevel@tonic-gate if(gl_read_stream_line(gl)==0) { 2242*7c478bd9Sstevel@tonic-gate break; 2243*7c478bd9Sstevel@tonic-gate } else if(gl->file_fp) { 2244*7c478bd9Sstevel@tonic-gate gl_revert_input(gl); 2245*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_NEWLINE, 0); 2246*7c478bd9Sstevel@tonic-gate } else { 2247*7c478bd9Sstevel@tonic-gate waserr = 1; 2248*7c478bd9Sstevel@tonic-gate break; 2249*7c478bd9Sstevel@tonic-gate }; 2250*7c478bd9Sstevel@tonic-gate }; 2251*7c478bd9Sstevel@tonic-gate /* 2252*7c478bd9Sstevel@tonic-gate * Read from the terminal? Note that the above if() block may have 2253*7c478bd9Sstevel@tonic-gate * changed gl->file_fp, so it is necessary to retest it here, rather 2254*7c478bd9Sstevel@tonic-gate * than using an else statement. 2255*7c478bd9Sstevel@tonic-gate */ 2256*7c478bd9Sstevel@tonic-gate if(!gl->file_fp && gl->is_term) { 2257*7c478bd9Sstevel@tonic-gate if(gl_get_input_line(gl, prompt, start_line, start_pos)) 2258*7c478bd9Sstevel@tonic-gate waserr = 1; 2259*7c478bd9Sstevel@tonic-gate else 2260*7c478bd9Sstevel@tonic-gate break; 2261*7c478bd9Sstevel@tonic-gate }; 2262*7c478bd9Sstevel@tonic-gate }; 2263*7c478bd9Sstevel@tonic-gate /* 2264*7c478bd9Sstevel@tonic-gate * If an error occurred, but gl->rtn_status is still set to 2265*7c478bd9Sstevel@tonic-gate * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise 2266*7c478bd9Sstevel@tonic-gate * leave it at whatever specific value was assigned by the function 2267*7c478bd9Sstevel@tonic-gate * that aborted input. This means that only functions that trap 2268*7c478bd9Sstevel@tonic-gate * non-generic errors have to remember to update gl->rtn_status 2269*7c478bd9Sstevel@tonic-gate * themselves. 2270*7c478bd9Sstevel@tonic-gate */ 2271*7c478bd9Sstevel@tonic-gate if(waserr && gl->rtn_status == GLR_NEWLINE) 2272*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_ERROR, errno); 2273*7c478bd9Sstevel@tonic-gate /* 2274*7c478bd9Sstevel@tonic-gate * Restore terminal settings. 2275*7c478bd9Sstevel@tonic-gate */ 2276*7c478bd9Sstevel@tonic-gate if(gl->io_mode != GL_SERVER_MODE) 2277*7c478bd9Sstevel@tonic-gate _gl_normal_io(gl); 2278*7c478bd9Sstevel@tonic-gate /* 2279*7c478bd9Sstevel@tonic-gate * Restore the signal handlers. 2280*7c478bd9Sstevel@tonic-gate */ 2281*7c478bd9Sstevel@tonic-gate gl_restore_signal_handlers(gl); 2282*7c478bd9Sstevel@tonic-gate /* 2283*7c478bd9Sstevel@tonic-gate * If gl_get_line() gets aborted early, the errno value associated 2284*7c478bd9Sstevel@tonic-gate * with the event that caused this to happen is recorded in 2285*7c478bd9Sstevel@tonic-gate * gl->rtn_errno. Since errno may have been overwritten by cleanup 2286*7c478bd9Sstevel@tonic-gate * functions after this, restore its value to the value that it had 2287*7c478bd9Sstevel@tonic-gate * when the error condition occured, so that the caller can examine it 2288*7c478bd9Sstevel@tonic-gate * to find out what happened. 2289*7c478bd9Sstevel@tonic-gate */ 2290*7c478bd9Sstevel@tonic-gate errno = gl->rtn_errno; 2291*7c478bd9Sstevel@tonic-gate /* 2292*7c478bd9Sstevel@tonic-gate * Check the completion status to see how to return. 2293*7c478bd9Sstevel@tonic-gate */ 2294*7c478bd9Sstevel@tonic-gate switch(gl->rtn_status) { 2295*7c478bd9Sstevel@tonic-gate case GLR_NEWLINE: /* Success */ 2296*7c478bd9Sstevel@tonic-gate return gl->line; 2297*7c478bd9Sstevel@tonic-gate case GLR_BLOCKED: /* These events abort the current input line, */ 2298*7c478bd9Sstevel@tonic-gate case GLR_SIGNAL: /* when in normal blocking I/O mode, but only */ 2299*7c478bd9Sstevel@tonic-gate case GLR_TIMEOUT: /* temporarily pause line editing when in */ 2300*7c478bd9Sstevel@tonic-gate case GLR_FDABORT: /* non-blocking server I/O mode. */ 2301*7c478bd9Sstevel@tonic-gate if(gl->io_mode != GL_SERVER_MODE) 2302*7c478bd9Sstevel@tonic-gate _gl_abandon_line(gl); 2303*7c478bd9Sstevel@tonic-gate return NULL; 2304*7c478bd9Sstevel@tonic-gate case GLR_ERROR: /* Unrecoverable errors abort the input line, */ 2305*7c478bd9Sstevel@tonic-gate case GLR_EOF: /* regardless of the I/O mode. */ 2306*7c478bd9Sstevel@tonic-gate default: 2307*7c478bd9Sstevel@tonic-gate _gl_abandon_line(gl); 2308*7c478bd9Sstevel@tonic-gate return NULL; 2309*7c478bd9Sstevel@tonic-gate }; 2310*7c478bd9Sstevel@tonic-gate } 2311*7c478bd9Sstevel@tonic-gate 2312*7c478bd9Sstevel@tonic-gate /*....................................................................... 2313*7c478bd9Sstevel@tonic-gate * Read a single character from the user. 2314*7c478bd9Sstevel@tonic-gate * 2315*7c478bd9Sstevel@tonic-gate * Input: 2316*7c478bd9Sstevel@tonic-gate * gl GetLine * A resource object returned by new_GetLine(). 2317*7c478bd9Sstevel@tonic-gate * prompt char * The prompt to prefix the line with, or NULL if 2318*7c478bd9Sstevel@tonic-gate * no prompt is required. 2319*7c478bd9Sstevel@tonic-gate * defchar char The character to substitute if the 2320*7c478bd9Sstevel@tonic-gate * user simply hits return, or '\n' if you don't 2321*7c478bd9Sstevel@tonic-gate * need to substitute anything. 2322*7c478bd9Sstevel@tonic-gate * Output: 2323*7c478bd9Sstevel@tonic-gate * return int The character that was read, or EOF if the read 2324*7c478bd9Sstevel@tonic-gate * had to be aborted (in which case you can call 2325*7c478bd9Sstevel@tonic-gate * gl_return_status() to find out why). 2326*7c478bd9Sstevel@tonic-gate */ 2327*7c478bd9Sstevel@tonic-gate int gl_query_char(GetLine *gl, const char *prompt, char defchar) 2328*7c478bd9Sstevel@tonic-gate { 2329*7c478bd9Sstevel@tonic-gate int retval; /* The return value of _gl_query_char() */ 2330*7c478bd9Sstevel@tonic-gate /* 2331*7c478bd9Sstevel@tonic-gate * Check the arguments. 2332*7c478bd9Sstevel@tonic-gate */ 2333*7c478bd9Sstevel@tonic-gate if(!gl) { 2334*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2335*7c478bd9Sstevel@tonic-gate return EOF; 2336*7c478bd9Sstevel@tonic-gate }; 2337*7c478bd9Sstevel@tonic-gate /* 2338*7c478bd9Sstevel@tonic-gate * Temporarily block all of the signals that we have been asked to trap. 2339*7c478bd9Sstevel@tonic-gate */ 2340*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &gl->old_signal_set)) 2341*7c478bd9Sstevel@tonic-gate return EOF; 2342*7c478bd9Sstevel@tonic-gate /* 2343*7c478bd9Sstevel@tonic-gate * Perform the character reading task. 2344*7c478bd9Sstevel@tonic-gate */ 2345*7c478bd9Sstevel@tonic-gate retval = _gl_query_char(gl, prompt, defchar); 2346*7c478bd9Sstevel@tonic-gate /* 2347*7c478bd9Sstevel@tonic-gate * Restore the process signal mask to how it was when this function was 2348*7c478bd9Sstevel@tonic-gate * first called. 2349*7c478bd9Sstevel@tonic-gate */ 2350*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &gl->old_signal_set); 2351*7c478bd9Sstevel@tonic-gate return retval; 2352*7c478bd9Sstevel@tonic-gate } 2353*7c478bd9Sstevel@tonic-gate 2354*7c478bd9Sstevel@tonic-gate /*....................................................................... 2355*7c478bd9Sstevel@tonic-gate * This is the main body of the public function gl_query_char(). 2356*7c478bd9Sstevel@tonic-gate */ 2357*7c478bd9Sstevel@tonic-gate static int _gl_query_char(GetLine *gl, const char *prompt, char defchar) 2358*7c478bd9Sstevel@tonic-gate { 2359*7c478bd9Sstevel@tonic-gate int c = EOF; /* The character to be returned */ 2360*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True if an error occurs */ 2361*7c478bd9Sstevel@tonic-gate /* 2362*7c478bd9Sstevel@tonic-gate * Assume that this call will successfully complete the input operation 2363*7c478bd9Sstevel@tonic-gate * until proven otherwise. 2364*7c478bd9Sstevel@tonic-gate */ 2365*7c478bd9Sstevel@tonic-gate gl_clear_status(gl); 2366*7c478bd9Sstevel@tonic-gate /* 2367*7c478bd9Sstevel@tonic-gate * If this is the first call to this function or gl_get_line(), 2368*7c478bd9Sstevel@tonic-gate * since new_GetLine(), complete any postponed configuration. 2369*7c478bd9Sstevel@tonic-gate */ 2370*7c478bd9Sstevel@tonic-gate if(!gl->configured) { 2371*7c478bd9Sstevel@tonic-gate (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE); 2372*7c478bd9Sstevel@tonic-gate gl->configured = 1; 2373*7c478bd9Sstevel@tonic-gate }; 2374*7c478bd9Sstevel@tonic-gate /* 2375*7c478bd9Sstevel@tonic-gate * Before installing our signal handler functions, record the fact 2376*7c478bd9Sstevel@tonic-gate * that there are no pending signals. 2377*7c478bd9Sstevel@tonic-gate */ 2378*7c478bd9Sstevel@tonic-gate gl_pending_signal = -1; 2379*7c478bd9Sstevel@tonic-gate /* 2380*7c478bd9Sstevel@tonic-gate * Temporarily override the signal handlers of the calling program, 2381*7c478bd9Sstevel@tonic-gate * so that we can intercept signals that would leave the terminal 2382*7c478bd9Sstevel@tonic-gate * in a bad state. 2383*7c478bd9Sstevel@tonic-gate */ 2384*7c478bd9Sstevel@tonic-gate waserr = gl_override_signal_handlers(gl); 2385*7c478bd9Sstevel@tonic-gate /* 2386*7c478bd9Sstevel@tonic-gate * After recording the current terminal settings, switch the terminal 2387*7c478bd9Sstevel@tonic-gate * into raw input mode without redisplaying any partially entered 2388*7c478bd9Sstevel@tonic-gate * input line. 2389*7c478bd9Sstevel@tonic-gate */ 2390*7c478bd9Sstevel@tonic-gate waserr = waserr || _gl_raw_io(gl, 0); 2391*7c478bd9Sstevel@tonic-gate /* 2392*7c478bd9Sstevel@tonic-gate * Attempt to read the line. This will require more than one attempt if 2393*7c478bd9Sstevel@tonic-gate * either a current temporary input file is opened by gl_get_input_line() 2394*7c478bd9Sstevel@tonic-gate * or the end of a temporary input file is reached by gl_read_stream_line(). 2395*7c478bd9Sstevel@tonic-gate */ 2396*7c478bd9Sstevel@tonic-gate while(!waserr) { 2397*7c478bd9Sstevel@tonic-gate /* 2398*7c478bd9Sstevel@tonic-gate * Read a line from a non-interactive stream? 2399*7c478bd9Sstevel@tonic-gate */ 2400*7c478bd9Sstevel@tonic-gate if(gl->file_fp || !gl->is_term) { 2401*7c478bd9Sstevel@tonic-gate c = gl_read_stream_char(gl); 2402*7c478bd9Sstevel@tonic-gate if(c != EOF) { /* Success? */ 2403*7c478bd9Sstevel@tonic-gate if(c=='\n') c = defchar; 2404*7c478bd9Sstevel@tonic-gate break; 2405*7c478bd9Sstevel@tonic-gate } else if(gl->file_fp) { /* End of temporary input file? */ 2406*7c478bd9Sstevel@tonic-gate gl_revert_input(gl); 2407*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_NEWLINE, 0); 2408*7c478bd9Sstevel@tonic-gate } else { /* An error? */ 2409*7c478bd9Sstevel@tonic-gate waserr = 1; 2410*7c478bd9Sstevel@tonic-gate break; 2411*7c478bd9Sstevel@tonic-gate }; 2412*7c478bd9Sstevel@tonic-gate }; 2413*7c478bd9Sstevel@tonic-gate /* 2414*7c478bd9Sstevel@tonic-gate * Read from the terminal? Note that the above if() block may have 2415*7c478bd9Sstevel@tonic-gate * changed gl->file_fp, so it is necessary to retest it here, rather 2416*7c478bd9Sstevel@tonic-gate * than using an else statement. 2417*7c478bd9Sstevel@tonic-gate */ 2418*7c478bd9Sstevel@tonic-gate if(!gl->file_fp && gl->is_term) { 2419*7c478bd9Sstevel@tonic-gate c = gl_get_query_char(gl, prompt, defchar); 2420*7c478bd9Sstevel@tonic-gate if(c==EOF) 2421*7c478bd9Sstevel@tonic-gate waserr = 1; 2422*7c478bd9Sstevel@tonic-gate else 2423*7c478bd9Sstevel@tonic-gate break; 2424*7c478bd9Sstevel@tonic-gate }; 2425*7c478bd9Sstevel@tonic-gate }; 2426*7c478bd9Sstevel@tonic-gate /* 2427*7c478bd9Sstevel@tonic-gate * If an error occurred, but gl->rtn_status is still set to 2428*7c478bd9Sstevel@tonic-gate * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise 2429*7c478bd9Sstevel@tonic-gate * leave it at whatever specific value was assigned by the function 2430*7c478bd9Sstevel@tonic-gate * that aborted input. This means that only functions that trap 2431*7c478bd9Sstevel@tonic-gate * non-generic errors have to remember to update gl->rtn_status 2432*7c478bd9Sstevel@tonic-gate * themselves. 2433*7c478bd9Sstevel@tonic-gate */ 2434*7c478bd9Sstevel@tonic-gate if(waserr && gl->rtn_status == GLR_NEWLINE) 2435*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_ERROR, errno); 2436*7c478bd9Sstevel@tonic-gate /* 2437*7c478bd9Sstevel@tonic-gate * Restore terminal settings. 2438*7c478bd9Sstevel@tonic-gate */ 2439*7c478bd9Sstevel@tonic-gate if(gl->io_mode != GL_SERVER_MODE) 2440*7c478bd9Sstevel@tonic-gate _gl_normal_io(gl); 2441*7c478bd9Sstevel@tonic-gate /* 2442*7c478bd9Sstevel@tonic-gate * Restore the signal handlers. 2443*7c478bd9Sstevel@tonic-gate */ 2444*7c478bd9Sstevel@tonic-gate gl_restore_signal_handlers(gl); 2445*7c478bd9Sstevel@tonic-gate /* 2446*7c478bd9Sstevel@tonic-gate * If this function gets aborted early, the errno value associated 2447*7c478bd9Sstevel@tonic-gate * with the event that caused this to happen is recorded in 2448*7c478bd9Sstevel@tonic-gate * gl->rtn_errno. Since errno may have been overwritten by cleanup 2449*7c478bd9Sstevel@tonic-gate * functions after this, restore its value to the value that it had 2450*7c478bd9Sstevel@tonic-gate * when the error condition occured, so that the caller can examine it 2451*7c478bd9Sstevel@tonic-gate * to find out what happened. 2452*7c478bd9Sstevel@tonic-gate */ 2453*7c478bd9Sstevel@tonic-gate errno = gl->rtn_errno; 2454*7c478bd9Sstevel@tonic-gate /* 2455*7c478bd9Sstevel@tonic-gate * Error conditions are signalled to the caller, by setting the returned 2456*7c478bd9Sstevel@tonic-gate * character to EOF. 2457*7c478bd9Sstevel@tonic-gate */ 2458*7c478bd9Sstevel@tonic-gate if(gl->rtn_status != GLR_NEWLINE) 2459*7c478bd9Sstevel@tonic-gate c = EOF; 2460*7c478bd9Sstevel@tonic-gate /* 2461*7c478bd9Sstevel@tonic-gate * In this mode, every character that is read is a completed 2462*7c478bd9Sstevel@tonic-gate * transaction, just like reading a completed input line, so prepare 2463*7c478bd9Sstevel@tonic-gate * for the next input line or character. 2464*7c478bd9Sstevel@tonic-gate */ 2465*7c478bd9Sstevel@tonic-gate _gl_abandon_line(gl); 2466*7c478bd9Sstevel@tonic-gate /* 2467*7c478bd9Sstevel@tonic-gate * Return the acquired character. 2468*7c478bd9Sstevel@tonic-gate */ 2469*7c478bd9Sstevel@tonic-gate return c; 2470*7c478bd9Sstevel@tonic-gate } 2471*7c478bd9Sstevel@tonic-gate 2472*7c478bd9Sstevel@tonic-gate /*....................................................................... 2473*7c478bd9Sstevel@tonic-gate * Record of the signal handlers of the calling program, so that they 2474*7c478bd9Sstevel@tonic-gate * can be restored later. 2475*7c478bd9Sstevel@tonic-gate * 2476*7c478bd9Sstevel@tonic-gate * Input: 2477*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 2478*7c478bd9Sstevel@tonic-gate * Output: 2479*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 2480*7c478bd9Sstevel@tonic-gate * 1 - Error. 2481*7c478bd9Sstevel@tonic-gate */ 2482*7c478bd9Sstevel@tonic-gate static int gl_override_signal_handlers(GetLine *gl) 2483*7c478bd9Sstevel@tonic-gate { 2484*7c478bd9Sstevel@tonic-gate GlSignalNode *sig; /* A node in the list of signals to be caught */ 2485*7c478bd9Sstevel@tonic-gate /* 2486*7c478bd9Sstevel@tonic-gate * Set up our signal handler. 2487*7c478bd9Sstevel@tonic-gate */ 2488*7c478bd9Sstevel@tonic-gate SigAction act; 2489*7c478bd9Sstevel@tonic-gate act.sa_handler = gl_signal_handler; 2490*7c478bd9Sstevel@tonic-gate memcpy(&act.sa_mask, &gl->all_signal_set, sizeof(sigset_t)); 2491*7c478bd9Sstevel@tonic-gate act.sa_flags = 0; 2492*7c478bd9Sstevel@tonic-gate /* 2493*7c478bd9Sstevel@tonic-gate * Get the subset of the signals that we are supposed to trap that 2494*7c478bd9Sstevel@tonic-gate * should actually be trapped. 2495*7c478bd9Sstevel@tonic-gate */ 2496*7c478bd9Sstevel@tonic-gate sigemptyset(&gl->use_signal_set); 2497*7c478bd9Sstevel@tonic-gate for(sig=gl->sigs; sig; sig=sig->next) { 2498*7c478bd9Sstevel@tonic-gate /* 2499*7c478bd9Sstevel@tonic-gate * Trap this signal? If it is blocked by the calling program and we 2500*7c478bd9Sstevel@tonic-gate * haven't been told to unblock it, don't arrange to trap this signal. 2501*7c478bd9Sstevel@tonic-gate */ 2502*7c478bd9Sstevel@tonic-gate if(sig->flags & GLS_UNBLOCK_SIG || 2503*7c478bd9Sstevel@tonic-gate !sigismember(&gl->old_signal_set, sig->signo)) { 2504*7c478bd9Sstevel@tonic-gate if(sigaddset(&gl->use_signal_set, sig->signo) == -1) { 2505*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG); 2506*7c478bd9Sstevel@tonic-gate return 1; 2507*7c478bd9Sstevel@tonic-gate }; 2508*7c478bd9Sstevel@tonic-gate }; 2509*7c478bd9Sstevel@tonic-gate }; 2510*7c478bd9Sstevel@tonic-gate /* 2511*7c478bd9Sstevel@tonic-gate * Override the actions of the signals that we are trapping. 2512*7c478bd9Sstevel@tonic-gate */ 2513*7c478bd9Sstevel@tonic-gate for(sig=gl->sigs; sig; sig=sig->next) { 2514*7c478bd9Sstevel@tonic-gate if(sigismember(&gl->use_signal_set, sig->signo)) { 2515*7c478bd9Sstevel@tonic-gate sigdelset(&act.sa_mask, sig->signo); 2516*7c478bd9Sstevel@tonic-gate if(sigaction(sig->signo, &act, &sig->original)) { 2517*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "sigaction error", END_ERR_MSG); 2518*7c478bd9Sstevel@tonic-gate return 1; 2519*7c478bd9Sstevel@tonic-gate }; 2520*7c478bd9Sstevel@tonic-gate sigaddset(&act.sa_mask, sig->signo); 2521*7c478bd9Sstevel@tonic-gate }; 2522*7c478bd9Sstevel@tonic-gate }; 2523*7c478bd9Sstevel@tonic-gate /* 2524*7c478bd9Sstevel@tonic-gate * Record the fact that the application's signal handlers have now 2525*7c478bd9Sstevel@tonic-gate * been overriden. 2526*7c478bd9Sstevel@tonic-gate */ 2527*7c478bd9Sstevel@tonic-gate gl->signals_overriden = 1; 2528*7c478bd9Sstevel@tonic-gate /* 2529*7c478bd9Sstevel@tonic-gate * Just in case a SIGWINCH signal was sent to the process while our 2530*7c478bd9Sstevel@tonic-gate * SIGWINCH signal handler wasn't in place, check to see if the terminal 2531*7c478bd9Sstevel@tonic-gate * size needs updating. 2532*7c478bd9Sstevel@tonic-gate */ 2533*7c478bd9Sstevel@tonic-gate if(_gl_update_size(gl)) 2534*7c478bd9Sstevel@tonic-gate return 1; 2535*7c478bd9Sstevel@tonic-gate return 0; 2536*7c478bd9Sstevel@tonic-gate } 2537*7c478bd9Sstevel@tonic-gate 2538*7c478bd9Sstevel@tonic-gate /*....................................................................... 2539*7c478bd9Sstevel@tonic-gate * Restore the signal handlers of the calling program. 2540*7c478bd9Sstevel@tonic-gate * 2541*7c478bd9Sstevel@tonic-gate * Input: 2542*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 2543*7c478bd9Sstevel@tonic-gate * Output: 2544*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 2545*7c478bd9Sstevel@tonic-gate * 1 - Error. 2546*7c478bd9Sstevel@tonic-gate */ 2547*7c478bd9Sstevel@tonic-gate static int gl_restore_signal_handlers(GetLine *gl) 2548*7c478bd9Sstevel@tonic-gate { 2549*7c478bd9Sstevel@tonic-gate GlSignalNode *sig; /* A node in the list of signals to be caught */ 2550*7c478bd9Sstevel@tonic-gate /* 2551*7c478bd9Sstevel@tonic-gate * Restore application signal handlers that were overriden 2552*7c478bd9Sstevel@tonic-gate * by gl_override_signal_handlers(). 2553*7c478bd9Sstevel@tonic-gate */ 2554*7c478bd9Sstevel@tonic-gate for(sig=gl->sigs; sig; sig=sig->next) { 2555*7c478bd9Sstevel@tonic-gate if(sigismember(&gl->use_signal_set, sig->signo) && 2556*7c478bd9Sstevel@tonic-gate sigaction(sig->signo, &sig->original, NULL)) { 2557*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "sigaction error", END_ERR_MSG); 2558*7c478bd9Sstevel@tonic-gate return 1; 2559*7c478bd9Sstevel@tonic-gate }; 2560*7c478bd9Sstevel@tonic-gate }; 2561*7c478bd9Sstevel@tonic-gate /* 2562*7c478bd9Sstevel@tonic-gate * Record the fact that the application's signal handlers have now 2563*7c478bd9Sstevel@tonic-gate * been restored. 2564*7c478bd9Sstevel@tonic-gate */ 2565*7c478bd9Sstevel@tonic-gate gl->signals_overriden = 0; 2566*7c478bd9Sstevel@tonic-gate return 0; 2567*7c478bd9Sstevel@tonic-gate } 2568*7c478bd9Sstevel@tonic-gate 2569*7c478bd9Sstevel@tonic-gate /*....................................................................... 2570*7c478bd9Sstevel@tonic-gate * This signal handler simply records the fact that a given signal was 2571*7c478bd9Sstevel@tonic-gate * caught in the file-scope gl_pending_signal variable. 2572*7c478bd9Sstevel@tonic-gate */ 2573*7c478bd9Sstevel@tonic-gate static void gl_signal_handler(int signo) 2574*7c478bd9Sstevel@tonic-gate { 2575*7c478bd9Sstevel@tonic-gate gl_pending_signal = signo; 2576*7c478bd9Sstevel@tonic-gate siglongjmp(gl_setjmp_buffer, 1); 2577*7c478bd9Sstevel@tonic-gate } 2578*7c478bd9Sstevel@tonic-gate 2579*7c478bd9Sstevel@tonic-gate /*....................................................................... 2580*7c478bd9Sstevel@tonic-gate * Switch the terminal into raw mode after storing the previous terminal 2581*7c478bd9Sstevel@tonic-gate * settings in gl->attributes. 2582*7c478bd9Sstevel@tonic-gate * 2583*7c478bd9Sstevel@tonic-gate * Input: 2584*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this program. 2585*7c478bd9Sstevel@tonic-gate * Output: 2586*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 2587*7c478bd9Sstevel@tonic-gate * 1 - Error. 2588*7c478bd9Sstevel@tonic-gate */ 2589*7c478bd9Sstevel@tonic-gate static int gl_raw_terminal_mode(GetLine *gl) 2590*7c478bd9Sstevel@tonic-gate { 2591*7c478bd9Sstevel@tonic-gate Termios newattr; /* The new terminal attributes */ 2592*7c478bd9Sstevel@tonic-gate /* 2593*7c478bd9Sstevel@tonic-gate * If the terminal is already in raw mode, do nothing. 2594*7c478bd9Sstevel@tonic-gate */ 2595*7c478bd9Sstevel@tonic-gate if(gl->raw_mode) 2596*7c478bd9Sstevel@tonic-gate return 0; 2597*7c478bd9Sstevel@tonic-gate /* 2598*7c478bd9Sstevel@tonic-gate * Record the current terminal attributes. 2599*7c478bd9Sstevel@tonic-gate */ 2600*7c478bd9Sstevel@tonic-gate if(tcgetattr(gl->input_fd, &gl->oldattr)) { 2601*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG); 2602*7c478bd9Sstevel@tonic-gate return 1; 2603*7c478bd9Sstevel@tonic-gate }; 2604*7c478bd9Sstevel@tonic-gate /* 2605*7c478bd9Sstevel@tonic-gate * This function shouldn't do anything but record the current terminal 2606*7c478bd9Sstevel@tonic-gate * attritubes if editing has been disabled. 2607*7c478bd9Sstevel@tonic-gate */ 2608*7c478bd9Sstevel@tonic-gate if(gl->editor == GL_NO_EDITOR) 2609*7c478bd9Sstevel@tonic-gate return 0; 2610*7c478bd9Sstevel@tonic-gate /* 2611*7c478bd9Sstevel@tonic-gate * Modify the existing attributes. 2612*7c478bd9Sstevel@tonic-gate */ 2613*7c478bd9Sstevel@tonic-gate newattr = gl->oldattr; 2614*7c478bd9Sstevel@tonic-gate /* 2615*7c478bd9Sstevel@tonic-gate * Turn off local echo, canonical input mode and extended input processing. 2616*7c478bd9Sstevel@tonic-gate */ 2617*7c478bd9Sstevel@tonic-gate newattr.c_lflag &= ~(ECHO | ICANON | IEXTEN); 2618*7c478bd9Sstevel@tonic-gate /* 2619*7c478bd9Sstevel@tonic-gate * Don't translate carriage return to newline, turn off input parity 2620*7c478bd9Sstevel@tonic-gate * checking, don't strip off 8th bit, turn off output flow control. 2621*7c478bd9Sstevel@tonic-gate */ 2622*7c478bd9Sstevel@tonic-gate newattr.c_iflag &= ~(ICRNL | INPCK | ISTRIP); 2623*7c478bd9Sstevel@tonic-gate /* 2624*7c478bd9Sstevel@tonic-gate * Clear size bits, turn off parity checking, and allow 8-bit characters. 2625*7c478bd9Sstevel@tonic-gate */ 2626*7c478bd9Sstevel@tonic-gate newattr.c_cflag &= ~(CSIZE | PARENB); 2627*7c478bd9Sstevel@tonic-gate newattr.c_cflag |= CS8; 2628*7c478bd9Sstevel@tonic-gate /* 2629*7c478bd9Sstevel@tonic-gate * Turn off output processing. 2630*7c478bd9Sstevel@tonic-gate */ 2631*7c478bd9Sstevel@tonic-gate newattr.c_oflag &= ~(OPOST); 2632*7c478bd9Sstevel@tonic-gate /* 2633*7c478bd9Sstevel@tonic-gate * Request one byte at a time, without waiting. 2634*7c478bd9Sstevel@tonic-gate */ 2635*7c478bd9Sstevel@tonic-gate newattr.c_cc[VMIN] = gl->io_mode==GL_SERVER_MODE ? 0:1; 2636*7c478bd9Sstevel@tonic-gate newattr.c_cc[VTIME] = 0; 2637*7c478bd9Sstevel@tonic-gate /* 2638*7c478bd9Sstevel@tonic-gate * Install the new terminal modes. 2639*7c478bd9Sstevel@tonic-gate */ 2640*7c478bd9Sstevel@tonic-gate while(tcsetattr(gl->input_fd, TCSADRAIN, &newattr)) { 2641*7c478bd9Sstevel@tonic-gate if(errno != EINTR) { 2642*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG); 2643*7c478bd9Sstevel@tonic-gate return 1; 2644*7c478bd9Sstevel@tonic-gate }; 2645*7c478bd9Sstevel@tonic-gate }; 2646*7c478bd9Sstevel@tonic-gate /* 2647*7c478bd9Sstevel@tonic-gate * Record the new terminal mode. 2648*7c478bd9Sstevel@tonic-gate */ 2649*7c478bd9Sstevel@tonic-gate gl->raw_mode = 1; 2650*7c478bd9Sstevel@tonic-gate return 0; 2651*7c478bd9Sstevel@tonic-gate } 2652*7c478bd9Sstevel@tonic-gate 2653*7c478bd9Sstevel@tonic-gate /*....................................................................... 2654*7c478bd9Sstevel@tonic-gate * Restore the terminal attributes recorded in gl->oldattr. 2655*7c478bd9Sstevel@tonic-gate * 2656*7c478bd9Sstevel@tonic-gate * Input: 2657*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 2658*7c478bd9Sstevel@tonic-gate * Output: 2659*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 2660*7c478bd9Sstevel@tonic-gate * 1 - Error. 2661*7c478bd9Sstevel@tonic-gate */ 2662*7c478bd9Sstevel@tonic-gate static int gl_restore_terminal_attributes(GetLine *gl) 2663*7c478bd9Sstevel@tonic-gate { 2664*7c478bd9Sstevel@tonic-gate int waserr = 0; 2665*7c478bd9Sstevel@tonic-gate /* 2666*7c478bd9Sstevel@tonic-gate * If not in raw mode, do nothing. 2667*7c478bd9Sstevel@tonic-gate */ 2668*7c478bd9Sstevel@tonic-gate if(!gl->raw_mode) 2669*7c478bd9Sstevel@tonic-gate return 0; 2670*7c478bd9Sstevel@tonic-gate /* 2671*7c478bd9Sstevel@tonic-gate * Before changing the terminal attributes, make sure that all output 2672*7c478bd9Sstevel@tonic-gate * has been passed to the terminal. 2673*7c478bd9Sstevel@tonic-gate */ 2674*7c478bd9Sstevel@tonic-gate if(gl_flush_output(gl)) 2675*7c478bd9Sstevel@tonic-gate waserr = 1; 2676*7c478bd9Sstevel@tonic-gate /* 2677*7c478bd9Sstevel@tonic-gate * Reset the terminal attributes to the values that they had on 2678*7c478bd9Sstevel@tonic-gate * entry to gl_get_line(). 2679*7c478bd9Sstevel@tonic-gate */ 2680*7c478bd9Sstevel@tonic-gate while(tcsetattr(gl->input_fd, TCSADRAIN, &gl->oldattr)) { 2681*7c478bd9Sstevel@tonic-gate if(errno != EINTR) { 2682*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG); 2683*7c478bd9Sstevel@tonic-gate waserr = 1; 2684*7c478bd9Sstevel@tonic-gate break; 2685*7c478bd9Sstevel@tonic-gate }; 2686*7c478bd9Sstevel@tonic-gate }; 2687*7c478bd9Sstevel@tonic-gate /* 2688*7c478bd9Sstevel@tonic-gate * Record the new terminal mode. 2689*7c478bd9Sstevel@tonic-gate */ 2690*7c478bd9Sstevel@tonic-gate gl->raw_mode = 0; 2691*7c478bd9Sstevel@tonic-gate return waserr; 2692*7c478bd9Sstevel@tonic-gate } 2693*7c478bd9Sstevel@tonic-gate 2694*7c478bd9Sstevel@tonic-gate /*....................................................................... 2695*7c478bd9Sstevel@tonic-gate * Switch the terminal file descriptor to use non-blocking I/O. 2696*7c478bd9Sstevel@tonic-gate * 2697*7c478bd9Sstevel@tonic-gate * Input: 2698*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 2699*7c478bd9Sstevel@tonic-gate * fd int The file descriptor to make non-blocking. 2700*7c478bd9Sstevel@tonic-gate */ 2701*7c478bd9Sstevel@tonic-gate static int gl_nonblocking_io(GetLine *gl, int fd) 2702*7c478bd9Sstevel@tonic-gate { 2703*7c478bd9Sstevel@tonic-gate int fcntl_flags; /* The new file-descriptor control flags */ 2704*7c478bd9Sstevel@tonic-gate /* 2705*7c478bd9Sstevel@tonic-gate * Is non-blocking I/O supported on this system? Note that even 2706*7c478bd9Sstevel@tonic-gate * without non-blocking I/O, the terminal will probably still act as 2707*7c478bd9Sstevel@tonic-gate * though it was non-blocking, because we also set the terminal 2708*7c478bd9Sstevel@tonic-gate * attributes to return immediately if no input is available and we 2709*7c478bd9Sstevel@tonic-gate * use select() to wait to be able to write. If select() also isn't 2710*7c478bd9Sstevel@tonic-gate * available, then input will probably remain fine, but output could 2711*7c478bd9Sstevel@tonic-gate * block, depending on the behaviour of the terminal driver. 2712*7c478bd9Sstevel@tonic-gate */ 2713*7c478bd9Sstevel@tonic-gate #if defined(NON_BLOCKING_FLAG) 2714*7c478bd9Sstevel@tonic-gate /* 2715*7c478bd9Sstevel@tonic-gate * Query the current file-control flags, and add the 2716*7c478bd9Sstevel@tonic-gate * non-blocking I/O flag. 2717*7c478bd9Sstevel@tonic-gate */ 2718*7c478bd9Sstevel@tonic-gate fcntl_flags = fcntl(fd, F_GETFL) | NON_BLOCKING_FLAG; 2719*7c478bd9Sstevel@tonic-gate /* 2720*7c478bd9Sstevel@tonic-gate * Install the new control flags. 2721*7c478bd9Sstevel@tonic-gate */ 2722*7c478bd9Sstevel@tonic-gate if(fcntl(fd, F_SETFL, fcntl_flags) == -1) { 2723*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "fcntl error", END_ERR_MSG); 2724*7c478bd9Sstevel@tonic-gate return 1; 2725*7c478bd9Sstevel@tonic-gate }; 2726*7c478bd9Sstevel@tonic-gate #endif 2727*7c478bd9Sstevel@tonic-gate return 0; 2728*7c478bd9Sstevel@tonic-gate } 2729*7c478bd9Sstevel@tonic-gate 2730*7c478bd9Sstevel@tonic-gate /*....................................................................... 2731*7c478bd9Sstevel@tonic-gate * Switch to blocking terminal I/O. 2732*7c478bd9Sstevel@tonic-gate * 2733*7c478bd9Sstevel@tonic-gate * Input: 2734*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 2735*7c478bd9Sstevel@tonic-gate * fd int The file descriptor to make blocking. 2736*7c478bd9Sstevel@tonic-gate */ 2737*7c478bd9Sstevel@tonic-gate static int gl_blocking_io(GetLine *gl, int fd) 2738*7c478bd9Sstevel@tonic-gate { 2739*7c478bd9Sstevel@tonic-gate int fcntl_flags; /* The new file-descriptor control flags */ 2740*7c478bd9Sstevel@tonic-gate /* 2741*7c478bd9Sstevel@tonic-gate * Is non-blocking I/O implemented on this system? 2742*7c478bd9Sstevel@tonic-gate */ 2743*7c478bd9Sstevel@tonic-gate #if defined(NON_BLOCKING_FLAG) 2744*7c478bd9Sstevel@tonic-gate /* 2745*7c478bd9Sstevel@tonic-gate * Query the current file control flags and remove the non-blocking 2746*7c478bd9Sstevel@tonic-gate * I/O flag. 2747*7c478bd9Sstevel@tonic-gate */ 2748*7c478bd9Sstevel@tonic-gate fcntl_flags = fcntl(fd, F_GETFL) & ~NON_BLOCKING_FLAG; 2749*7c478bd9Sstevel@tonic-gate /* 2750*7c478bd9Sstevel@tonic-gate * Install the modified control flags. 2751*7c478bd9Sstevel@tonic-gate */ 2752*7c478bd9Sstevel@tonic-gate if(fcntl(fd, F_SETFL, fcntl_flags) == -1) { 2753*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "fcntl error", END_ERR_MSG); 2754*7c478bd9Sstevel@tonic-gate return 1; 2755*7c478bd9Sstevel@tonic-gate }; 2756*7c478bd9Sstevel@tonic-gate #endif 2757*7c478bd9Sstevel@tonic-gate return 0; 2758*7c478bd9Sstevel@tonic-gate } 2759*7c478bd9Sstevel@tonic-gate 2760*7c478bd9Sstevel@tonic-gate /*....................................................................... 2761*7c478bd9Sstevel@tonic-gate * Read a new input line from the user. 2762*7c478bd9Sstevel@tonic-gate * 2763*7c478bd9Sstevel@tonic-gate * Input: 2764*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 2765*7c478bd9Sstevel@tonic-gate * prompt char * The prompt to prefix the line with, or NULL to 2766*7c478bd9Sstevel@tonic-gate * use the same prompt that was used by the previous 2767*7c478bd9Sstevel@tonic-gate * line. 2768*7c478bd9Sstevel@tonic-gate * start_line char * The initial contents of the input line, or NULL 2769*7c478bd9Sstevel@tonic-gate * if it should start out empty. 2770*7c478bd9Sstevel@tonic-gate * start_pos int If start_line isn't NULL, this specifies the 2771*7c478bd9Sstevel@tonic-gate * index of the character over which the cursor 2772*7c478bd9Sstevel@tonic-gate * should initially be positioned within the line. 2773*7c478bd9Sstevel@tonic-gate * If you just want it to follow the last character 2774*7c478bd9Sstevel@tonic-gate * of the line, send -1. 2775*7c478bd9Sstevel@tonic-gate * Output: 2776*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 2777*7c478bd9Sstevel@tonic-gate * 1 - Error. 2778*7c478bd9Sstevel@tonic-gate */ 2779*7c478bd9Sstevel@tonic-gate static int gl_get_input_line(GetLine *gl, const char *prompt, 2780*7c478bd9Sstevel@tonic-gate const char *start_line, int start_pos) 2781*7c478bd9Sstevel@tonic-gate { 2782*7c478bd9Sstevel@tonic-gate char c; /* The character being read */ 2783*7c478bd9Sstevel@tonic-gate /* 2784*7c478bd9Sstevel@tonic-gate * Flush any pending output to the terminal. 2785*7c478bd9Sstevel@tonic-gate */ 2786*7c478bd9Sstevel@tonic-gate if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl)) 2787*7c478bd9Sstevel@tonic-gate return 1; 2788*7c478bd9Sstevel@tonic-gate /* 2789*7c478bd9Sstevel@tonic-gate * Are we starting a new line? 2790*7c478bd9Sstevel@tonic-gate */ 2791*7c478bd9Sstevel@tonic-gate if(gl->endline) { 2792*7c478bd9Sstevel@tonic-gate /* 2793*7c478bd9Sstevel@tonic-gate * Delete any incompletely enterred line. 2794*7c478bd9Sstevel@tonic-gate */ 2795*7c478bd9Sstevel@tonic-gate if(gl_erase_line(gl)) 2796*7c478bd9Sstevel@tonic-gate return 1; 2797*7c478bd9Sstevel@tonic-gate /* 2798*7c478bd9Sstevel@tonic-gate * Display the new line to be edited. 2799*7c478bd9Sstevel@tonic-gate */ 2800*7c478bd9Sstevel@tonic-gate if(gl_present_line(gl, prompt, start_line, start_pos)) 2801*7c478bd9Sstevel@tonic-gate return 1; 2802*7c478bd9Sstevel@tonic-gate }; 2803*7c478bd9Sstevel@tonic-gate /* 2804*7c478bd9Sstevel@tonic-gate * Read one character at a time. 2805*7c478bd9Sstevel@tonic-gate */ 2806*7c478bd9Sstevel@tonic-gate while(gl_read_terminal(gl, 1, &c) == 0) { 2807*7c478bd9Sstevel@tonic-gate /* 2808*7c478bd9Sstevel@tonic-gate * Increment the count of the number of key sequences entered. 2809*7c478bd9Sstevel@tonic-gate */ 2810*7c478bd9Sstevel@tonic-gate gl->keyseq_count++; 2811*7c478bd9Sstevel@tonic-gate /* 2812*7c478bd9Sstevel@tonic-gate * Interpret the character either as the start of a new key-sequence, 2813*7c478bd9Sstevel@tonic-gate * as a continuation of a repeat count, or as a printable character 2814*7c478bd9Sstevel@tonic-gate * to be added to the line. 2815*7c478bd9Sstevel@tonic-gate */ 2816*7c478bd9Sstevel@tonic-gate if(gl_interpret_char(gl, c)) 2817*7c478bd9Sstevel@tonic-gate break; 2818*7c478bd9Sstevel@tonic-gate /* 2819*7c478bd9Sstevel@tonic-gate * If we just ran an action function which temporarily asked for 2820*7c478bd9Sstevel@tonic-gate * input to be taken from a file, abort this call. 2821*7c478bd9Sstevel@tonic-gate */ 2822*7c478bd9Sstevel@tonic-gate if(gl->file_fp) 2823*7c478bd9Sstevel@tonic-gate return 0; 2824*7c478bd9Sstevel@tonic-gate /* 2825*7c478bd9Sstevel@tonic-gate * Has the line been completed? 2826*7c478bd9Sstevel@tonic-gate */ 2827*7c478bd9Sstevel@tonic-gate if(gl->endline) 2828*7c478bd9Sstevel@tonic-gate return gl_line_ended(gl, c); 2829*7c478bd9Sstevel@tonic-gate }; 2830*7c478bd9Sstevel@tonic-gate /* 2831*7c478bd9Sstevel@tonic-gate * To get here, gl_read_terminal() must have returned non-zero. See 2832*7c478bd9Sstevel@tonic-gate * whether a signal was caught that requested that the current line 2833*7c478bd9Sstevel@tonic-gate * be returned. 2834*7c478bd9Sstevel@tonic-gate */ 2835*7c478bd9Sstevel@tonic-gate if(gl->endline) 2836*7c478bd9Sstevel@tonic-gate return gl_line_ended(gl, '\n'); 2837*7c478bd9Sstevel@tonic-gate /* 2838*7c478bd9Sstevel@tonic-gate * If I/O blocked while attempting to get the latest character 2839*7c478bd9Sstevel@tonic-gate * of the key sequence, rewind the key buffer to allow interpretation of 2840*7c478bd9Sstevel@tonic-gate * the current key sequence to be restarted on the next call to this 2841*7c478bd9Sstevel@tonic-gate * function. 2842*7c478bd9Sstevel@tonic-gate */ 2843*7c478bd9Sstevel@tonic-gate if(gl->rtn_status == GLR_BLOCKED && gl->pending_io == GLP_READ) 2844*7c478bd9Sstevel@tonic-gate gl->nread = 0; 2845*7c478bd9Sstevel@tonic-gate return 1; 2846*7c478bd9Sstevel@tonic-gate } 2847*7c478bd9Sstevel@tonic-gate 2848*7c478bd9Sstevel@tonic-gate /*....................................................................... 2849*7c478bd9Sstevel@tonic-gate * This is the private function of gl_query_char() that handles 2850*7c478bd9Sstevel@tonic-gate * prompting the user, reading a character from the terminal, and 2851*7c478bd9Sstevel@tonic-gate * displaying what the user entered. 2852*7c478bd9Sstevel@tonic-gate * 2853*7c478bd9Sstevel@tonic-gate * Input: 2854*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 2855*7c478bd9Sstevel@tonic-gate * prompt char * The prompt to prefix the line with. 2856*7c478bd9Sstevel@tonic-gate * defchar char The character to substitute if the 2857*7c478bd9Sstevel@tonic-gate * user simply hits return, or '\n' if you don't 2858*7c478bd9Sstevel@tonic-gate * need to substitute anything. 2859*7c478bd9Sstevel@tonic-gate * Output: 2860*7c478bd9Sstevel@tonic-gate * return int The character that was read, or EOF if something 2861*7c478bd9Sstevel@tonic-gate * prevented a character from being read. 2862*7c478bd9Sstevel@tonic-gate */ 2863*7c478bd9Sstevel@tonic-gate static int gl_get_query_char(GetLine *gl, const char *prompt, int defchar) 2864*7c478bd9Sstevel@tonic-gate { 2865*7c478bd9Sstevel@tonic-gate char c; /* The character being read */ 2866*7c478bd9Sstevel@tonic-gate int retval; /* The return value of this function */ 2867*7c478bd9Sstevel@tonic-gate /* 2868*7c478bd9Sstevel@tonic-gate * Flush any pending output to the terminal. 2869*7c478bd9Sstevel@tonic-gate */ 2870*7c478bd9Sstevel@tonic-gate if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl)) 2871*7c478bd9Sstevel@tonic-gate return EOF; 2872*7c478bd9Sstevel@tonic-gate /* 2873*7c478bd9Sstevel@tonic-gate * Delete any incompletely entered line. 2874*7c478bd9Sstevel@tonic-gate */ 2875*7c478bd9Sstevel@tonic-gate if(gl_erase_line(gl)) 2876*7c478bd9Sstevel@tonic-gate return EOF; 2877*7c478bd9Sstevel@tonic-gate /* 2878*7c478bd9Sstevel@tonic-gate * Reset the line input parameters and display the prompt, if any. 2879*7c478bd9Sstevel@tonic-gate */ 2880*7c478bd9Sstevel@tonic-gate if(gl_present_line(gl, prompt, NULL, 0)) 2881*7c478bd9Sstevel@tonic-gate return EOF; 2882*7c478bd9Sstevel@tonic-gate /* 2883*7c478bd9Sstevel@tonic-gate * Read one character. 2884*7c478bd9Sstevel@tonic-gate */ 2885*7c478bd9Sstevel@tonic-gate if(gl_read_terminal(gl, 1, &c) == 0) { 2886*7c478bd9Sstevel@tonic-gate /* 2887*7c478bd9Sstevel@tonic-gate * In this mode, count each character as being a new key-sequence. 2888*7c478bd9Sstevel@tonic-gate */ 2889*7c478bd9Sstevel@tonic-gate gl->keyseq_count++; 2890*7c478bd9Sstevel@tonic-gate /* 2891*7c478bd9Sstevel@tonic-gate * Delete the character that was read, from the key-press buffer. 2892*7c478bd9Sstevel@tonic-gate */ 2893*7c478bd9Sstevel@tonic-gate gl_discard_chars(gl, gl->nread); 2894*7c478bd9Sstevel@tonic-gate /* 2895*7c478bd9Sstevel@tonic-gate * Convert carriage returns to newlines. 2896*7c478bd9Sstevel@tonic-gate */ 2897*7c478bd9Sstevel@tonic-gate if(c == '\r') 2898*7c478bd9Sstevel@tonic-gate c = '\n'; 2899*7c478bd9Sstevel@tonic-gate /* 2900*7c478bd9Sstevel@tonic-gate * If the user just hit return, subsitute the default character. 2901*7c478bd9Sstevel@tonic-gate */ 2902*7c478bd9Sstevel@tonic-gate if(c == '\n') 2903*7c478bd9Sstevel@tonic-gate c = defchar; 2904*7c478bd9Sstevel@tonic-gate /* 2905*7c478bd9Sstevel@tonic-gate * Display the entered character to the right of the prompt. 2906*7c478bd9Sstevel@tonic-gate */ 2907*7c478bd9Sstevel@tonic-gate if(c!='\n') { 2908*7c478bd9Sstevel@tonic-gate if(gl_end_of_line(gl, 1, NULL)==0) 2909*7c478bd9Sstevel@tonic-gate gl_print_char(gl, c, ' '); 2910*7c478bd9Sstevel@tonic-gate }; 2911*7c478bd9Sstevel@tonic-gate /* 2912*7c478bd9Sstevel@tonic-gate * Record the return character, and mark the call as successful. 2913*7c478bd9Sstevel@tonic-gate */ 2914*7c478bd9Sstevel@tonic-gate retval = c; 2915*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_NEWLINE, 0); 2916*7c478bd9Sstevel@tonic-gate /* 2917*7c478bd9Sstevel@tonic-gate * Was a signal caught whose disposition is to cause the current input 2918*7c478bd9Sstevel@tonic-gate * line to be returned? If so return a newline character. 2919*7c478bd9Sstevel@tonic-gate */ 2920*7c478bd9Sstevel@tonic-gate } else if(gl->endline) { 2921*7c478bd9Sstevel@tonic-gate retval = '\n'; 2922*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_NEWLINE, 0); 2923*7c478bd9Sstevel@tonic-gate } else { 2924*7c478bd9Sstevel@tonic-gate retval = EOF; 2925*7c478bd9Sstevel@tonic-gate }; 2926*7c478bd9Sstevel@tonic-gate /* 2927*7c478bd9Sstevel@tonic-gate * Start a new line. 2928*7c478bd9Sstevel@tonic-gate */ 2929*7c478bd9Sstevel@tonic-gate if(gl_start_newline(gl, 1)) 2930*7c478bd9Sstevel@tonic-gate return EOF; 2931*7c478bd9Sstevel@tonic-gate /* 2932*7c478bd9Sstevel@tonic-gate * Attempt to flush any pending output. 2933*7c478bd9Sstevel@tonic-gate */ 2934*7c478bd9Sstevel@tonic-gate (void) gl_flush_output(gl); 2935*7c478bd9Sstevel@tonic-gate /* 2936*7c478bd9Sstevel@tonic-gate * Return either the character that was read, or EOF if an error occurred. 2937*7c478bd9Sstevel@tonic-gate */ 2938*7c478bd9Sstevel@tonic-gate return retval; 2939*7c478bd9Sstevel@tonic-gate } 2940*7c478bd9Sstevel@tonic-gate 2941*7c478bd9Sstevel@tonic-gate /*....................................................................... 2942*7c478bd9Sstevel@tonic-gate * Add a character to the line buffer at the current cursor position, 2943*7c478bd9Sstevel@tonic-gate * inserting or overwriting according the current mode. 2944*7c478bd9Sstevel@tonic-gate * 2945*7c478bd9Sstevel@tonic-gate * Input: 2946*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 2947*7c478bd9Sstevel@tonic-gate * c char The character to be added. 2948*7c478bd9Sstevel@tonic-gate * Output: 2949*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 2950*7c478bd9Sstevel@tonic-gate * 1 - Insufficient room. 2951*7c478bd9Sstevel@tonic-gate */ 2952*7c478bd9Sstevel@tonic-gate static int gl_add_char_to_line(GetLine *gl, char c) 2953*7c478bd9Sstevel@tonic-gate { 2954*7c478bd9Sstevel@tonic-gate /* 2955*7c478bd9Sstevel@tonic-gate * Keep a record of the current cursor position. 2956*7c478bd9Sstevel@tonic-gate */ 2957*7c478bd9Sstevel@tonic-gate int buff_curpos = gl->buff_curpos; 2958*7c478bd9Sstevel@tonic-gate int term_curpos = gl->term_curpos; 2959*7c478bd9Sstevel@tonic-gate /* 2960*7c478bd9Sstevel@tonic-gate * Work out the displayed width of the new character. 2961*7c478bd9Sstevel@tonic-gate */ 2962*7c478bd9Sstevel@tonic-gate int width = gl_displayed_char_width(gl, c, term_curpos); 2963*7c478bd9Sstevel@tonic-gate /* 2964*7c478bd9Sstevel@tonic-gate * If we are in insert mode, or at the end of the line, 2965*7c478bd9Sstevel@tonic-gate * check that we can accomodate a new character in the buffer. 2966*7c478bd9Sstevel@tonic-gate * If not, simply return, leaving it up to the calling program 2967*7c478bd9Sstevel@tonic-gate * to check for the absence of a newline character. 2968*7c478bd9Sstevel@tonic-gate */ 2969*7c478bd9Sstevel@tonic-gate if((gl->insert || buff_curpos >= gl->ntotal) && gl->ntotal >= gl->linelen) 2970*7c478bd9Sstevel@tonic-gate return 0; 2971*7c478bd9Sstevel@tonic-gate /* 2972*7c478bd9Sstevel@tonic-gate * Are we adding characters to the line (ie. inserting or appending)? 2973*7c478bd9Sstevel@tonic-gate */ 2974*7c478bd9Sstevel@tonic-gate if(gl->insert || buff_curpos >= gl->ntotal) { 2975*7c478bd9Sstevel@tonic-gate /* 2976*7c478bd9Sstevel@tonic-gate * If inserting, make room for the new character. 2977*7c478bd9Sstevel@tonic-gate */ 2978*7c478bd9Sstevel@tonic-gate if(buff_curpos < gl->ntotal) 2979*7c478bd9Sstevel@tonic-gate gl_make_gap_in_buffer(gl, buff_curpos, 1); 2980*7c478bd9Sstevel@tonic-gate /* 2981*7c478bd9Sstevel@tonic-gate * Copy the character into the buffer. 2982*7c478bd9Sstevel@tonic-gate */ 2983*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, c, buff_curpos); 2984*7c478bd9Sstevel@tonic-gate gl->buff_curpos++; 2985*7c478bd9Sstevel@tonic-gate /* 2986*7c478bd9Sstevel@tonic-gate * Redraw the line from the cursor position to the end of the line, 2987*7c478bd9Sstevel@tonic-gate * and move the cursor to just after the added character. 2988*7c478bd9Sstevel@tonic-gate */ 2989*7c478bd9Sstevel@tonic-gate if(gl_print_string(gl, gl->line + buff_curpos, '\0') || 2990*7c478bd9Sstevel@tonic-gate gl_set_term_curpos(gl, term_curpos + width)) 2991*7c478bd9Sstevel@tonic-gate return 1; 2992*7c478bd9Sstevel@tonic-gate /* 2993*7c478bd9Sstevel@tonic-gate * Are we overwriting an existing character? 2994*7c478bd9Sstevel@tonic-gate */ 2995*7c478bd9Sstevel@tonic-gate } else { 2996*7c478bd9Sstevel@tonic-gate /* 2997*7c478bd9Sstevel@tonic-gate * Get the width of the character being overwritten. 2998*7c478bd9Sstevel@tonic-gate */ 2999*7c478bd9Sstevel@tonic-gate int old_width = gl_displayed_char_width(gl, gl->line[buff_curpos], 3000*7c478bd9Sstevel@tonic-gate term_curpos); 3001*7c478bd9Sstevel@tonic-gate /* 3002*7c478bd9Sstevel@tonic-gate * Overwrite the character in the buffer. 3003*7c478bd9Sstevel@tonic-gate */ 3004*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, c, buff_curpos); 3005*7c478bd9Sstevel@tonic-gate /* 3006*7c478bd9Sstevel@tonic-gate * If we are replacing with a narrower character, we need to 3007*7c478bd9Sstevel@tonic-gate * redraw the terminal string to the end of the line, then 3008*7c478bd9Sstevel@tonic-gate * overwrite the trailing old_width - width characters 3009*7c478bd9Sstevel@tonic-gate * with spaces. 3010*7c478bd9Sstevel@tonic-gate */ 3011*7c478bd9Sstevel@tonic-gate if(old_width > width) { 3012*7c478bd9Sstevel@tonic-gate if(gl_print_string(gl, gl->line + buff_curpos, '\0')) 3013*7c478bd9Sstevel@tonic-gate return 1; 3014*7c478bd9Sstevel@tonic-gate /* 3015*7c478bd9Sstevel@tonic-gate * Clear to the end of the terminal. 3016*7c478bd9Sstevel@tonic-gate */ 3017*7c478bd9Sstevel@tonic-gate if(gl_truncate_display(gl)) 3018*7c478bd9Sstevel@tonic-gate return 1; 3019*7c478bd9Sstevel@tonic-gate /* 3020*7c478bd9Sstevel@tonic-gate * Move the cursor to the end of the new character. 3021*7c478bd9Sstevel@tonic-gate */ 3022*7c478bd9Sstevel@tonic-gate if(gl_set_term_curpos(gl, term_curpos + width)) 3023*7c478bd9Sstevel@tonic-gate return 1; 3024*7c478bd9Sstevel@tonic-gate gl->buff_curpos++; 3025*7c478bd9Sstevel@tonic-gate /* 3026*7c478bd9Sstevel@tonic-gate * If we are replacing with a wider character, then we will be 3027*7c478bd9Sstevel@tonic-gate * inserting new characters, and thus extending the line. 3028*7c478bd9Sstevel@tonic-gate */ 3029*7c478bd9Sstevel@tonic-gate } else if(width > old_width) { 3030*7c478bd9Sstevel@tonic-gate /* 3031*7c478bd9Sstevel@tonic-gate * Redraw the line from the cursor position to the end of the line, 3032*7c478bd9Sstevel@tonic-gate * and move the cursor to just after the added character. 3033*7c478bd9Sstevel@tonic-gate */ 3034*7c478bd9Sstevel@tonic-gate if(gl_print_string(gl, gl->line + buff_curpos, '\0') || 3035*7c478bd9Sstevel@tonic-gate gl_set_term_curpos(gl, term_curpos + width)) 3036*7c478bd9Sstevel@tonic-gate return 1; 3037*7c478bd9Sstevel@tonic-gate gl->buff_curpos++; 3038*7c478bd9Sstevel@tonic-gate /* 3039*7c478bd9Sstevel@tonic-gate * The original and replacement characters have the same width, 3040*7c478bd9Sstevel@tonic-gate * so simply overwrite. 3041*7c478bd9Sstevel@tonic-gate */ 3042*7c478bd9Sstevel@tonic-gate } else { 3043*7c478bd9Sstevel@tonic-gate /* 3044*7c478bd9Sstevel@tonic-gate * Copy the character into the buffer. 3045*7c478bd9Sstevel@tonic-gate */ 3046*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, c, buff_curpos); 3047*7c478bd9Sstevel@tonic-gate gl->buff_curpos++; 3048*7c478bd9Sstevel@tonic-gate /* 3049*7c478bd9Sstevel@tonic-gate * Overwrite the original character. 3050*7c478bd9Sstevel@tonic-gate */ 3051*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, c, gl->line[gl->buff_curpos])) 3052*7c478bd9Sstevel@tonic-gate return 1; 3053*7c478bd9Sstevel@tonic-gate }; 3054*7c478bd9Sstevel@tonic-gate }; 3055*7c478bd9Sstevel@tonic-gate return 0; 3056*7c478bd9Sstevel@tonic-gate } 3057*7c478bd9Sstevel@tonic-gate 3058*7c478bd9Sstevel@tonic-gate /*....................................................................... 3059*7c478bd9Sstevel@tonic-gate * Insert/append a string to the line buffer and terminal at the current 3060*7c478bd9Sstevel@tonic-gate * cursor position. 3061*7c478bd9Sstevel@tonic-gate * 3062*7c478bd9Sstevel@tonic-gate * Input: 3063*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 3064*7c478bd9Sstevel@tonic-gate * s char * The string to be added. 3065*7c478bd9Sstevel@tonic-gate * Output: 3066*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 3067*7c478bd9Sstevel@tonic-gate * 1 - Insufficient room. 3068*7c478bd9Sstevel@tonic-gate */ 3069*7c478bd9Sstevel@tonic-gate static int gl_add_string_to_line(GetLine *gl, const char *s) 3070*7c478bd9Sstevel@tonic-gate { 3071*7c478bd9Sstevel@tonic-gate int buff_slen; /* The length of the string being added to line[] */ 3072*7c478bd9Sstevel@tonic-gate int term_slen; /* The length of the string being written to the terminal */ 3073*7c478bd9Sstevel@tonic-gate int buff_curpos; /* The original value of gl->buff_curpos */ 3074*7c478bd9Sstevel@tonic-gate int term_curpos; /* The original value of gl->term_curpos */ 3075*7c478bd9Sstevel@tonic-gate /* 3076*7c478bd9Sstevel@tonic-gate * Keep a record of the current cursor position. 3077*7c478bd9Sstevel@tonic-gate */ 3078*7c478bd9Sstevel@tonic-gate buff_curpos = gl->buff_curpos; 3079*7c478bd9Sstevel@tonic-gate term_curpos = gl->term_curpos; 3080*7c478bd9Sstevel@tonic-gate /* 3081*7c478bd9Sstevel@tonic-gate * How long is the string to be added? 3082*7c478bd9Sstevel@tonic-gate */ 3083*7c478bd9Sstevel@tonic-gate buff_slen = strlen(s); 3084*7c478bd9Sstevel@tonic-gate term_slen = gl_displayed_string_width(gl, s, buff_slen, term_curpos); 3085*7c478bd9Sstevel@tonic-gate /* 3086*7c478bd9Sstevel@tonic-gate * Check that we can accomodate the string in the buffer. 3087*7c478bd9Sstevel@tonic-gate * If not, simply return, leaving it up to the calling program 3088*7c478bd9Sstevel@tonic-gate * to check for the absence of a newline character. 3089*7c478bd9Sstevel@tonic-gate */ 3090*7c478bd9Sstevel@tonic-gate if(gl->ntotal + buff_slen > gl->linelen) 3091*7c478bd9Sstevel@tonic-gate return 0; 3092*7c478bd9Sstevel@tonic-gate /* 3093*7c478bd9Sstevel@tonic-gate * Move the characters that follow the cursor in the buffer by 3094*7c478bd9Sstevel@tonic-gate * buff_slen characters to the right. 3095*7c478bd9Sstevel@tonic-gate */ 3096*7c478bd9Sstevel@tonic-gate if(gl->ntotal > gl->buff_curpos) 3097*7c478bd9Sstevel@tonic-gate gl_make_gap_in_buffer(gl, gl->buff_curpos, buff_slen); 3098*7c478bd9Sstevel@tonic-gate /* 3099*7c478bd9Sstevel@tonic-gate * Copy the string into the buffer. 3100*7c478bd9Sstevel@tonic-gate */ 3101*7c478bd9Sstevel@tonic-gate gl_buffer_string(gl, s, buff_slen, gl->buff_curpos); 3102*7c478bd9Sstevel@tonic-gate gl->buff_curpos += buff_slen; 3103*7c478bd9Sstevel@tonic-gate /* 3104*7c478bd9Sstevel@tonic-gate * Write the modified part of the line to the terminal, then move 3105*7c478bd9Sstevel@tonic-gate * the terminal cursor to the end of the displayed input string. 3106*7c478bd9Sstevel@tonic-gate */ 3107*7c478bd9Sstevel@tonic-gate if(gl_print_string(gl, gl->line + buff_curpos, '\0') || 3108*7c478bd9Sstevel@tonic-gate gl_set_term_curpos(gl, term_curpos + term_slen)) 3109*7c478bd9Sstevel@tonic-gate return 1; 3110*7c478bd9Sstevel@tonic-gate return 0; 3111*7c478bd9Sstevel@tonic-gate } 3112*7c478bd9Sstevel@tonic-gate 3113*7c478bd9Sstevel@tonic-gate /*....................................................................... 3114*7c478bd9Sstevel@tonic-gate * Read a single character from the terminal. 3115*7c478bd9Sstevel@tonic-gate * 3116*7c478bd9Sstevel@tonic-gate * Input: 3117*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 3118*7c478bd9Sstevel@tonic-gate * keep int If true, the returned character will be kept in 3119*7c478bd9Sstevel@tonic-gate * the input buffer, for potential replays. It should 3120*7c478bd9Sstevel@tonic-gate * subsequently be removed from the buffer when the 3121*7c478bd9Sstevel@tonic-gate * key sequence that it belongs to has been fully 3122*7c478bd9Sstevel@tonic-gate * processed, by calling gl_discard_chars(). 3123*7c478bd9Sstevel@tonic-gate * Input/Output: 3124*7c478bd9Sstevel@tonic-gate * c char * The character that is read, is assigned to *c. 3125*7c478bd9Sstevel@tonic-gate * Output: 3126*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 3127*7c478bd9Sstevel@tonic-gate * 1 - Either an I/O error occurred, or a signal was 3128*7c478bd9Sstevel@tonic-gate * caught who's disposition is to abort gl_get_line() 3129*7c478bd9Sstevel@tonic-gate * or to have gl_get_line() return the current line 3130*7c478bd9Sstevel@tonic-gate * as though the user had pressed return. In the 3131*7c478bd9Sstevel@tonic-gate * latter case gl->endline will be non-zero. 3132*7c478bd9Sstevel@tonic-gate */ 3133*7c478bd9Sstevel@tonic-gate static int gl_read_terminal(GetLine *gl, int keep, char *c) 3134*7c478bd9Sstevel@tonic-gate { 3135*7c478bd9Sstevel@tonic-gate /* 3136*7c478bd9Sstevel@tonic-gate * Before waiting for a new character to be input, flush unwritten 3137*7c478bd9Sstevel@tonic-gate * characters to the terminal. 3138*7c478bd9Sstevel@tonic-gate */ 3139*7c478bd9Sstevel@tonic-gate if(gl_flush_output(gl)) 3140*7c478bd9Sstevel@tonic-gate return 1; 3141*7c478bd9Sstevel@tonic-gate /* 3142*7c478bd9Sstevel@tonic-gate * Record the fact that we are about to read from the terminal. 3143*7c478bd9Sstevel@tonic-gate */ 3144*7c478bd9Sstevel@tonic-gate gl->pending_io = GLP_READ; 3145*7c478bd9Sstevel@tonic-gate /* 3146*7c478bd9Sstevel@tonic-gate * If there is already an unread character in the buffer, 3147*7c478bd9Sstevel@tonic-gate * return it. 3148*7c478bd9Sstevel@tonic-gate */ 3149*7c478bd9Sstevel@tonic-gate if(gl->nread < gl->nbuf) { 3150*7c478bd9Sstevel@tonic-gate *c = gl->keybuf[gl->nread]; 3151*7c478bd9Sstevel@tonic-gate /* 3152*7c478bd9Sstevel@tonic-gate * Retain the character in the key buffer, but mark it as having been read? 3153*7c478bd9Sstevel@tonic-gate */ 3154*7c478bd9Sstevel@tonic-gate if(keep) { 3155*7c478bd9Sstevel@tonic-gate gl->nread++; 3156*7c478bd9Sstevel@tonic-gate /* 3157*7c478bd9Sstevel@tonic-gate * Completely remove the character from the key buffer? 3158*7c478bd9Sstevel@tonic-gate */ 3159*7c478bd9Sstevel@tonic-gate } else { 3160*7c478bd9Sstevel@tonic-gate memmove(gl->keybuf + gl->nread, gl->keybuf + gl->nread + 1, 3161*7c478bd9Sstevel@tonic-gate gl->nbuf - gl->nread - 1); 3162*7c478bd9Sstevel@tonic-gate }; 3163*7c478bd9Sstevel@tonic-gate return 0; 3164*7c478bd9Sstevel@tonic-gate }; 3165*7c478bd9Sstevel@tonic-gate /* 3166*7c478bd9Sstevel@tonic-gate * Make sure that there is space in the key buffer for one more character. 3167*7c478bd9Sstevel@tonic-gate * This should always be true if gl_interpret_char() is called for each 3168*7c478bd9Sstevel@tonic-gate * new character added, since it will clear the buffer once it has recognized 3169*7c478bd9Sstevel@tonic-gate * or rejected a key sequence. 3170*7c478bd9Sstevel@tonic-gate */ 3171*7c478bd9Sstevel@tonic-gate if(gl->nbuf + 1 > GL_KEY_MAX) { 3172*7c478bd9Sstevel@tonic-gate gl_print_info(gl, "gl_read_terminal: Buffer overflow avoided.", 3173*7c478bd9Sstevel@tonic-gate GL_END_INFO); 3174*7c478bd9Sstevel@tonic-gate errno = EIO; 3175*7c478bd9Sstevel@tonic-gate return 1; 3176*7c478bd9Sstevel@tonic-gate }; 3177*7c478bd9Sstevel@tonic-gate /* 3178*7c478bd9Sstevel@tonic-gate * Read one character from the terminal. 3179*7c478bd9Sstevel@tonic-gate */ 3180*7c478bd9Sstevel@tonic-gate switch(gl_read_input(gl, c)) { 3181*7c478bd9Sstevel@tonic-gate case GL_READ_OK: 3182*7c478bd9Sstevel@tonic-gate break; 3183*7c478bd9Sstevel@tonic-gate case GL_READ_BLOCKED: 3184*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO); 3185*7c478bd9Sstevel@tonic-gate return 1; 3186*7c478bd9Sstevel@tonic-gate break; 3187*7c478bd9Sstevel@tonic-gate default: 3188*7c478bd9Sstevel@tonic-gate return 1; 3189*7c478bd9Sstevel@tonic-gate break; 3190*7c478bd9Sstevel@tonic-gate }; 3191*7c478bd9Sstevel@tonic-gate /* 3192*7c478bd9Sstevel@tonic-gate * Append the character to the key buffer? 3193*7c478bd9Sstevel@tonic-gate */ 3194*7c478bd9Sstevel@tonic-gate if(keep) { 3195*7c478bd9Sstevel@tonic-gate gl->keybuf[gl->nbuf] = *c; 3196*7c478bd9Sstevel@tonic-gate gl->nread = ++gl->nbuf; 3197*7c478bd9Sstevel@tonic-gate }; 3198*7c478bd9Sstevel@tonic-gate return 0; 3199*7c478bd9Sstevel@tonic-gate } 3200*7c478bd9Sstevel@tonic-gate 3201*7c478bd9Sstevel@tonic-gate /*....................................................................... 3202*7c478bd9Sstevel@tonic-gate * Read one or more keypresses from the terminal of an input stream. 3203*7c478bd9Sstevel@tonic-gate * 3204*7c478bd9Sstevel@tonic-gate * Input: 3205*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this module. 3206*7c478bd9Sstevel@tonic-gate * c char * The character that was read is assigned to *c. 3207*7c478bd9Sstevel@tonic-gate * Output: 3208*7c478bd9Sstevel@tonic-gate * return GlReadStatus The completion status of the read operation. 3209*7c478bd9Sstevel@tonic-gate */ 3210*7c478bd9Sstevel@tonic-gate static GlReadStatus gl_read_input(GetLine *gl, char *c) 3211*7c478bd9Sstevel@tonic-gate { 3212*7c478bd9Sstevel@tonic-gate /* 3213*7c478bd9Sstevel@tonic-gate * We may have to repeat the read if window change signals are received. 3214*7c478bd9Sstevel@tonic-gate */ 3215*7c478bd9Sstevel@tonic-gate for(;;) { 3216*7c478bd9Sstevel@tonic-gate /* 3217*7c478bd9Sstevel@tonic-gate * Which file descriptor should we read from? Mark this volatile, so 3218*7c478bd9Sstevel@tonic-gate * that siglongjmp() can't clobber it. 3219*7c478bd9Sstevel@tonic-gate */ 3220*7c478bd9Sstevel@tonic-gate volatile int fd = gl->file_fp ? fileno(gl->file_fp) : gl->input_fd; 3221*7c478bd9Sstevel@tonic-gate /* 3222*7c478bd9Sstevel@tonic-gate * If the endline flag becomes set, don't wait for another character. 3223*7c478bd9Sstevel@tonic-gate */ 3224*7c478bd9Sstevel@tonic-gate if(gl->endline) 3225*7c478bd9Sstevel@tonic-gate return GL_READ_ERROR; 3226*7c478bd9Sstevel@tonic-gate /* 3227*7c478bd9Sstevel@tonic-gate * Since the code in this function can block, trap signals. 3228*7c478bd9Sstevel@tonic-gate */ 3229*7c478bd9Sstevel@tonic-gate if(sigsetjmp(gl_setjmp_buffer, 1)==0) { 3230*7c478bd9Sstevel@tonic-gate /* 3231*7c478bd9Sstevel@tonic-gate * Handle the different I/O modes. 3232*7c478bd9Sstevel@tonic-gate */ 3233*7c478bd9Sstevel@tonic-gate switch(gl->io_mode) { 3234*7c478bd9Sstevel@tonic-gate /* 3235*7c478bd9Sstevel@tonic-gate * In normal I/O mode, we call the event handler before attempting 3236*7c478bd9Sstevel@tonic-gate * to read, since read() blocks. 3237*7c478bd9Sstevel@tonic-gate */ 3238*7c478bd9Sstevel@tonic-gate case GL_NORMAL_MODE: 3239*7c478bd9Sstevel@tonic-gate if(gl_event_handler(gl, fd)) 3240*7c478bd9Sstevel@tonic-gate return GL_READ_ERROR; 3241*7c478bd9Sstevel@tonic-gate return gl_read_unmasked(gl, fd, c); /* Read one character */ 3242*7c478bd9Sstevel@tonic-gate break; 3243*7c478bd9Sstevel@tonic-gate /* 3244*7c478bd9Sstevel@tonic-gate * In non-blocking server I/O mode, we attempt to read a character, 3245*7c478bd9Sstevel@tonic-gate * and only if this fails, call the event handler to wait for a any 3246*7c478bd9Sstevel@tonic-gate * user-configured timeout and any other user-configured events. In 3247*7c478bd9Sstevel@tonic-gate * addition, we turn off the fcntl() non-blocking flag when reading 3248*7c478bd9Sstevel@tonic-gate * from the terminal, to work around a bug in Solaris. We can do this 3249*7c478bd9Sstevel@tonic-gate * without causing the read() to block, because when in non-blocking 3250*7c478bd9Sstevel@tonic-gate * server-I/O mode, gl_raw_io() sets the VMIN terminal attribute to 0, 3251*7c478bd9Sstevel@tonic-gate * which tells the terminal driver to return immediately if no 3252*7c478bd9Sstevel@tonic-gate * characters are available to be read. 3253*7c478bd9Sstevel@tonic-gate */ 3254*7c478bd9Sstevel@tonic-gate case GL_SERVER_MODE: 3255*7c478bd9Sstevel@tonic-gate { 3256*7c478bd9Sstevel@tonic-gate GlReadStatus status; /* The return status */ 3257*7c478bd9Sstevel@tonic-gate if(isatty(fd)) /* If we reading from a terminal, */ 3258*7c478bd9Sstevel@tonic-gate gl_blocking_io(gl, fd); /* switch to blocking I/O */ 3259*7c478bd9Sstevel@tonic-gate status = gl_read_unmasked(gl, fd, c); /* Try reading */ 3260*7c478bd9Sstevel@tonic-gate if(status == GL_READ_BLOCKED) { /* Nothing readable yet */ 3261*7c478bd9Sstevel@tonic-gate if(gl_event_handler(gl, fd)) /* Wait for input */ 3262*7c478bd9Sstevel@tonic-gate status = GL_READ_ERROR; 3263*7c478bd9Sstevel@tonic-gate else 3264*7c478bd9Sstevel@tonic-gate status = gl_read_unmasked(gl, fd, c); /* Try reading again */ 3265*7c478bd9Sstevel@tonic-gate }; 3266*7c478bd9Sstevel@tonic-gate gl_nonblocking_io(gl, fd); /* Restore non-blocking I/O */ 3267*7c478bd9Sstevel@tonic-gate return status; 3268*7c478bd9Sstevel@tonic-gate }; 3269*7c478bd9Sstevel@tonic-gate break; 3270*7c478bd9Sstevel@tonic-gate }; 3271*7c478bd9Sstevel@tonic-gate }; 3272*7c478bd9Sstevel@tonic-gate /* 3273*7c478bd9Sstevel@tonic-gate * To get here, one of the signals that we are trapping must have 3274*7c478bd9Sstevel@tonic-gate * been received. Note that by using sigsetjmp() instead of setjmp() 3275*7c478bd9Sstevel@tonic-gate * the signal mask that was blocking these signals will have been 3276*7c478bd9Sstevel@tonic-gate * reinstated, so we can be sure that no more of these signals will 3277*7c478bd9Sstevel@tonic-gate * be received until we explicitly unblock them again. 3278*7c478bd9Sstevel@tonic-gate * 3279*7c478bd9Sstevel@tonic-gate * First, if non-blocking I/O was temporarily disabled, reinstate it. 3280*7c478bd9Sstevel@tonic-gate */ 3281*7c478bd9Sstevel@tonic-gate if(gl->io_mode == GL_SERVER_MODE) 3282*7c478bd9Sstevel@tonic-gate gl_nonblocking_io(gl, fd); 3283*7c478bd9Sstevel@tonic-gate /* 3284*7c478bd9Sstevel@tonic-gate * Now respond to the signal that was caught. 3285*7c478bd9Sstevel@tonic-gate */ 3286*7c478bd9Sstevel@tonic-gate if(gl_check_caught_signal(gl)) 3287*7c478bd9Sstevel@tonic-gate return GL_READ_ERROR; 3288*7c478bd9Sstevel@tonic-gate }; 3289*7c478bd9Sstevel@tonic-gate } 3290*7c478bd9Sstevel@tonic-gate 3291*7c478bd9Sstevel@tonic-gate /*....................................................................... 3292*7c478bd9Sstevel@tonic-gate * This is a private function of gl_read_input(), which unblocks signals 3293*7c478bd9Sstevel@tonic-gate * temporarily while it reads a single character from the specified file 3294*7c478bd9Sstevel@tonic-gate * descriptor. 3295*7c478bd9Sstevel@tonic-gate * 3296*7c478bd9Sstevel@tonic-gate * Input: 3297*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this module. 3298*7c478bd9Sstevel@tonic-gate * fd int The file descriptor to read from. 3299*7c478bd9Sstevel@tonic-gate * c char * The character that was read is assigned to *c. 3300*7c478bd9Sstevel@tonic-gate * Output: 3301*7c478bd9Sstevel@tonic-gate * return GlReadStatus The completion status of the read. 3302*7c478bd9Sstevel@tonic-gate */ 3303*7c478bd9Sstevel@tonic-gate static int gl_read_unmasked(GetLine *gl, int fd, char *c) 3304*7c478bd9Sstevel@tonic-gate { 3305*7c478bd9Sstevel@tonic-gate int nread; /* The return value of read() */ 3306*7c478bd9Sstevel@tonic-gate /* 3307*7c478bd9Sstevel@tonic-gate * Unblock the signals that we are trapping, while waiting for I/O. 3308*7c478bd9Sstevel@tonic-gate */ 3309*7c478bd9Sstevel@tonic-gate gl_catch_signals(gl); 3310*7c478bd9Sstevel@tonic-gate /* 3311*7c478bd9Sstevel@tonic-gate * Attempt to read one character from the terminal, restarting the read 3312*7c478bd9Sstevel@tonic-gate * if any signals that we aren't trapping, are received. 3313*7c478bd9Sstevel@tonic-gate */ 3314*7c478bd9Sstevel@tonic-gate do { 3315*7c478bd9Sstevel@tonic-gate errno = 0; 3316*7c478bd9Sstevel@tonic-gate nread = read(fd, c, 1); 3317*7c478bd9Sstevel@tonic-gate } while(nread < 0 && errno==EINTR); 3318*7c478bd9Sstevel@tonic-gate /* 3319*7c478bd9Sstevel@tonic-gate * Block all of the signals that we are trapping. 3320*7c478bd9Sstevel@tonic-gate */ 3321*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, NULL); 3322*7c478bd9Sstevel@tonic-gate /* 3323*7c478bd9Sstevel@tonic-gate * Check the completion status of the read. 3324*7c478bd9Sstevel@tonic-gate */ 3325*7c478bd9Sstevel@tonic-gate switch(nread) { 3326*7c478bd9Sstevel@tonic-gate case 1: 3327*7c478bd9Sstevel@tonic-gate return GL_READ_OK; 3328*7c478bd9Sstevel@tonic-gate case 0: 3329*7c478bd9Sstevel@tonic-gate return (isatty(fd) || errno != 0) ? GL_READ_BLOCKED : GL_READ_EOF; 3330*7c478bd9Sstevel@tonic-gate default: 3331*7c478bd9Sstevel@tonic-gate return GL_READ_ERROR; 3332*7c478bd9Sstevel@tonic-gate }; 3333*7c478bd9Sstevel@tonic-gate } 3334*7c478bd9Sstevel@tonic-gate 3335*7c478bd9Sstevel@tonic-gate /*....................................................................... 3336*7c478bd9Sstevel@tonic-gate * Remove a specified number of characters from the start of the 3337*7c478bd9Sstevel@tonic-gate * key-press lookahead buffer, gl->keybuf[], and arrange for the next 3338*7c478bd9Sstevel@tonic-gate * read to start from the character at the start of the shifted buffer. 3339*7c478bd9Sstevel@tonic-gate * 3340*7c478bd9Sstevel@tonic-gate * Input: 3341*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this module. 3342*7c478bd9Sstevel@tonic-gate * nused int The number of characters to discard from the start 3343*7c478bd9Sstevel@tonic-gate * of the buffer. 3344*7c478bd9Sstevel@tonic-gate */ 3345*7c478bd9Sstevel@tonic-gate static void gl_discard_chars(GetLine *gl, int nused) 3346*7c478bd9Sstevel@tonic-gate { 3347*7c478bd9Sstevel@tonic-gate int nkeep = gl->nbuf - nused; 3348*7c478bd9Sstevel@tonic-gate if(nkeep > 0) { 3349*7c478bd9Sstevel@tonic-gate memmove(gl->keybuf, gl->keybuf + nused, nkeep); 3350*7c478bd9Sstevel@tonic-gate gl->nbuf = nkeep; 3351*7c478bd9Sstevel@tonic-gate gl->nread = 0; 3352*7c478bd9Sstevel@tonic-gate } else { 3353*7c478bd9Sstevel@tonic-gate gl->nbuf = gl->nread = 0; 3354*7c478bd9Sstevel@tonic-gate }; 3355*7c478bd9Sstevel@tonic-gate } 3356*7c478bd9Sstevel@tonic-gate 3357*7c478bd9Sstevel@tonic-gate /*....................................................................... 3358*7c478bd9Sstevel@tonic-gate * This function is called to handle signals caught between calls to 3359*7c478bd9Sstevel@tonic-gate * sigsetjmp() and siglongjmp(). 3360*7c478bd9Sstevel@tonic-gate * 3361*7c478bd9Sstevel@tonic-gate * Input: 3362*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 3363*7c478bd9Sstevel@tonic-gate * Output: 3364*7c478bd9Sstevel@tonic-gate * return int 0 - Signal handled internally. 3365*7c478bd9Sstevel@tonic-gate * 1 - Signal requires gl_get_line() to abort. 3366*7c478bd9Sstevel@tonic-gate */ 3367*7c478bd9Sstevel@tonic-gate static int gl_check_caught_signal(GetLine *gl) 3368*7c478bd9Sstevel@tonic-gate { 3369*7c478bd9Sstevel@tonic-gate GlSignalNode *sig; /* The signal disposition */ 3370*7c478bd9Sstevel@tonic-gate SigAction keep_action; /* The signal disposition of tecla signal handlers */ 3371*7c478bd9Sstevel@tonic-gate unsigned flags; /* The signal processing flags to use */ 3372*7c478bd9Sstevel@tonic-gate int signo; /* The signal to be handled */ 3373*7c478bd9Sstevel@tonic-gate /* 3374*7c478bd9Sstevel@tonic-gate * Was no signal caught? 3375*7c478bd9Sstevel@tonic-gate */ 3376*7c478bd9Sstevel@tonic-gate if(gl_pending_signal == -1) 3377*7c478bd9Sstevel@tonic-gate return 0; 3378*7c478bd9Sstevel@tonic-gate /* 3379*7c478bd9Sstevel@tonic-gate * Get the signal to be handled. 3380*7c478bd9Sstevel@tonic-gate */ 3381*7c478bd9Sstevel@tonic-gate signo = gl_pending_signal; 3382*7c478bd9Sstevel@tonic-gate /* 3383*7c478bd9Sstevel@tonic-gate * Mark the signal as handled. Note that at this point, all of 3384*7c478bd9Sstevel@tonic-gate * the signals that we are trapping are blocked from delivery. 3385*7c478bd9Sstevel@tonic-gate */ 3386*7c478bd9Sstevel@tonic-gate gl_pending_signal = -1; 3387*7c478bd9Sstevel@tonic-gate /* 3388*7c478bd9Sstevel@tonic-gate * Record the signal that was caught, so that the user can query it later. 3389*7c478bd9Sstevel@tonic-gate */ 3390*7c478bd9Sstevel@tonic-gate gl->last_signal = signo; 3391*7c478bd9Sstevel@tonic-gate /* 3392*7c478bd9Sstevel@tonic-gate * In non-blocking server mode, the application is responsible for 3393*7c478bd9Sstevel@tonic-gate * responding to terminal signals, and we don't want gl_get_line()s 3394*7c478bd9Sstevel@tonic-gate * normal signal handling to clash with this, so whenever a signal 3395*7c478bd9Sstevel@tonic-gate * is caught, we arrange for gl_get_line() to abort and requeue the 3396*7c478bd9Sstevel@tonic-gate * signal while signals are still blocked. If the application 3397*7c478bd9Sstevel@tonic-gate * had the signal unblocked when gl_get_line() was called, the signal 3398*7c478bd9Sstevel@tonic-gate * will be delivered again as soon as gl_get_line() restores the 3399*7c478bd9Sstevel@tonic-gate * process signal mask, just before returning to the application. 3400*7c478bd9Sstevel@tonic-gate * Note that the caller of this function should set gl->pending_io 3401*7c478bd9Sstevel@tonic-gate * to the appropriate choice of GLP_READ and GLP_WRITE, before returning. 3402*7c478bd9Sstevel@tonic-gate */ 3403*7c478bd9Sstevel@tonic-gate if(gl->io_mode==GL_SERVER_MODE) { 3404*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_SIGNAL, EINTR); 3405*7c478bd9Sstevel@tonic-gate raise(signo); 3406*7c478bd9Sstevel@tonic-gate return 1; 3407*7c478bd9Sstevel@tonic-gate }; 3408*7c478bd9Sstevel@tonic-gate /* 3409*7c478bd9Sstevel@tonic-gate * Lookup the requested disposition of this signal. 3410*7c478bd9Sstevel@tonic-gate */ 3411*7c478bd9Sstevel@tonic-gate for(sig=gl->sigs; sig && sig->signo != signo; sig=sig->next) 3412*7c478bd9Sstevel@tonic-gate ; 3413*7c478bd9Sstevel@tonic-gate if(!sig) 3414*7c478bd9Sstevel@tonic-gate return 0; 3415*7c478bd9Sstevel@tonic-gate /* 3416*7c478bd9Sstevel@tonic-gate * Get the signal response flags for this signal. 3417*7c478bd9Sstevel@tonic-gate */ 3418*7c478bd9Sstevel@tonic-gate flags = sig->flags; 3419*7c478bd9Sstevel@tonic-gate /* 3420*7c478bd9Sstevel@tonic-gate * Did we receive a terminal size signal? 3421*7c478bd9Sstevel@tonic-gate */ 3422*7c478bd9Sstevel@tonic-gate #ifdef SIGWINCH 3423*7c478bd9Sstevel@tonic-gate if(signo == SIGWINCH && _gl_update_size(gl)) 3424*7c478bd9Sstevel@tonic-gate return 1; 3425*7c478bd9Sstevel@tonic-gate #endif 3426*7c478bd9Sstevel@tonic-gate /* 3427*7c478bd9Sstevel@tonic-gate * Start a fresh line? 3428*7c478bd9Sstevel@tonic-gate */ 3429*7c478bd9Sstevel@tonic-gate if(flags & GLS_RESTORE_LINE) { 3430*7c478bd9Sstevel@tonic-gate if(gl_start_newline(gl, 0)) 3431*7c478bd9Sstevel@tonic-gate return 1; 3432*7c478bd9Sstevel@tonic-gate }; 3433*7c478bd9Sstevel@tonic-gate /* 3434*7c478bd9Sstevel@tonic-gate * Restore terminal settings to how they were before gl_get_line() was 3435*7c478bd9Sstevel@tonic-gate * called? 3436*7c478bd9Sstevel@tonic-gate */ 3437*7c478bd9Sstevel@tonic-gate if(flags & GLS_RESTORE_TTY) 3438*7c478bd9Sstevel@tonic-gate gl_restore_terminal_attributes(gl); 3439*7c478bd9Sstevel@tonic-gate /* 3440*7c478bd9Sstevel@tonic-gate * Restore signal handlers to how they were before gl_get_line() was 3441*7c478bd9Sstevel@tonic-gate * called? If this hasn't been requested, only reinstate the signal 3442*7c478bd9Sstevel@tonic-gate * handler of the signal that we are handling. 3443*7c478bd9Sstevel@tonic-gate */ 3444*7c478bd9Sstevel@tonic-gate if(flags & GLS_RESTORE_SIG) { 3445*7c478bd9Sstevel@tonic-gate gl_restore_signal_handlers(gl); 3446*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &gl->old_signal_set); 3447*7c478bd9Sstevel@tonic-gate } else { 3448*7c478bd9Sstevel@tonic-gate (void) sigaction(sig->signo, &sig->original, &keep_action); 3449*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &sig->proc_mask, NULL); 3450*7c478bd9Sstevel@tonic-gate }; 3451*7c478bd9Sstevel@tonic-gate /* 3452*7c478bd9Sstevel@tonic-gate * Forward the signal to the application's signal handler. 3453*7c478bd9Sstevel@tonic-gate */ 3454*7c478bd9Sstevel@tonic-gate if(!(flags & GLS_DONT_FORWARD)) 3455*7c478bd9Sstevel@tonic-gate raise(signo); 3456*7c478bd9Sstevel@tonic-gate /* 3457*7c478bd9Sstevel@tonic-gate * Reinstate our signal handlers. 3458*7c478bd9Sstevel@tonic-gate */ 3459*7c478bd9Sstevel@tonic-gate if(flags & GLS_RESTORE_SIG) { 3460*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, NULL); 3461*7c478bd9Sstevel@tonic-gate gl_override_signal_handlers(gl); 3462*7c478bd9Sstevel@tonic-gate } else { 3463*7c478bd9Sstevel@tonic-gate (void) sigaction(sig->signo, &keep_action, NULL); 3464*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &sig->proc_mask, NULL); 3465*7c478bd9Sstevel@tonic-gate }; 3466*7c478bd9Sstevel@tonic-gate /* 3467*7c478bd9Sstevel@tonic-gate * Do we need to reinstate our terminal settings? 3468*7c478bd9Sstevel@tonic-gate */ 3469*7c478bd9Sstevel@tonic-gate if(flags & GLS_RESTORE_TTY) 3470*7c478bd9Sstevel@tonic-gate gl_raw_terminal_mode(gl); 3471*7c478bd9Sstevel@tonic-gate /* 3472*7c478bd9Sstevel@tonic-gate * Redraw the line? 3473*7c478bd9Sstevel@tonic-gate */ 3474*7c478bd9Sstevel@tonic-gate if(flags & GLS_REDRAW_LINE) 3475*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 3476*7c478bd9Sstevel@tonic-gate /* 3477*7c478bd9Sstevel@tonic-gate * What next? 3478*7c478bd9Sstevel@tonic-gate */ 3479*7c478bd9Sstevel@tonic-gate switch(sig->after) { 3480*7c478bd9Sstevel@tonic-gate case GLS_RETURN: 3481*7c478bd9Sstevel@tonic-gate gl_newline(gl, 1, NULL); 3482*7c478bd9Sstevel@tonic-gate return gl_flush_output(gl); 3483*7c478bd9Sstevel@tonic-gate break; 3484*7c478bd9Sstevel@tonic-gate case GLS_ABORT: 3485*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_SIGNAL, sig->errno_value); 3486*7c478bd9Sstevel@tonic-gate return 1; 3487*7c478bd9Sstevel@tonic-gate break; 3488*7c478bd9Sstevel@tonic-gate case GLS_CONTINUE: 3489*7c478bd9Sstevel@tonic-gate return gl_flush_output(gl); 3490*7c478bd9Sstevel@tonic-gate break; 3491*7c478bd9Sstevel@tonic-gate }; 3492*7c478bd9Sstevel@tonic-gate return 0; 3493*7c478bd9Sstevel@tonic-gate } 3494*7c478bd9Sstevel@tonic-gate 3495*7c478bd9Sstevel@tonic-gate /*....................................................................... 3496*7c478bd9Sstevel@tonic-gate * Get pertinent terminal control strings and the initial terminal size. 3497*7c478bd9Sstevel@tonic-gate * 3498*7c478bd9Sstevel@tonic-gate * Input: 3499*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 3500*7c478bd9Sstevel@tonic-gate * term char * The type of the terminal. 3501*7c478bd9Sstevel@tonic-gate * Output: 3502*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 3503*7c478bd9Sstevel@tonic-gate * 1 - Error. 3504*7c478bd9Sstevel@tonic-gate */ 3505*7c478bd9Sstevel@tonic-gate static int gl_control_strings(GetLine *gl, const char *term) 3506*7c478bd9Sstevel@tonic-gate { 3507*7c478bd9Sstevel@tonic-gate int bad_term = 0; /* True if term is unusable */ 3508*7c478bd9Sstevel@tonic-gate /* 3509*7c478bd9Sstevel@tonic-gate * Discard any existing control strings from a previous terminal. 3510*7c478bd9Sstevel@tonic-gate */ 3511*7c478bd9Sstevel@tonic-gate gl->left = NULL; 3512*7c478bd9Sstevel@tonic-gate gl->right = NULL; 3513*7c478bd9Sstevel@tonic-gate gl->up = NULL; 3514*7c478bd9Sstevel@tonic-gate gl->down = NULL; 3515*7c478bd9Sstevel@tonic-gate gl->home = NULL; 3516*7c478bd9Sstevel@tonic-gate gl->bol = 0; 3517*7c478bd9Sstevel@tonic-gate gl->clear_eol = NULL; 3518*7c478bd9Sstevel@tonic-gate gl->clear_eod = NULL; 3519*7c478bd9Sstevel@tonic-gate gl->u_arrow = NULL; 3520*7c478bd9Sstevel@tonic-gate gl->d_arrow = NULL; 3521*7c478bd9Sstevel@tonic-gate gl->l_arrow = NULL; 3522*7c478bd9Sstevel@tonic-gate gl->r_arrow = NULL; 3523*7c478bd9Sstevel@tonic-gate gl->sound_bell = NULL; 3524*7c478bd9Sstevel@tonic-gate gl->bold = NULL; 3525*7c478bd9Sstevel@tonic-gate gl->underline = NULL; 3526*7c478bd9Sstevel@tonic-gate gl->standout = NULL; 3527*7c478bd9Sstevel@tonic-gate gl->dim = NULL; 3528*7c478bd9Sstevel@tonic-gate gl->reverse = NULL; 3529*7c478bd9Sstevel@tonic-gate gl->blink = NULL; 3530*7c478bd9Sstevel@tonic-gate gl->text_attr_off = NULL; 3531*7c478bd9Sstevel@tonic-gate gl->nline = 0; 3532*7c478bd9Sstevel@tonic-gate gl->ncolumn = 0; 3533*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 3534*7c478bd9Sstevel@tonic-gate gl->left_n = NULL; 3535*7c478bd9Sstevel@tonic-gate gl->right_n = NULL; 3536*7c478bd9Sstevel@tonic-gate #endif 3537*7c478bd9Sstevel@tonic-gate /* 3538*7c478bd9Sstevel@tonic-gate * If possible lookup the information in a terminal information 3539*7c478bd9Sstevel@tonic-gate * database. 3540*7c478bd9Sstevel@tonic-gate */ 3541*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 3542*7c478bd9Sstevel@tonic-gate if(!term || setupterm((char *)term, gl->input_fd, NULL) == ERR) { 3543*7c478bd9Sstevel@tonic-gate bad_term = 1; 3544*7c478bd9Sstevel@tonic-gate } else { 3545*7c478bd9Sstevel@tonic-gate _clr_StringGroup(gl->capmem); 3546*7c478bd9Sstevel@tonic-gate gl->left = gl_tigetstr(gl, "cub1"); 3547*7c478bd9Sstevel@tonic-gate gl->right = gl_tigetstr(gl, "cuf1"); 3548*7c478bd9Sstevel@tonic-gate gl->up = gl_tigetstr(gl, "cuu1"); 3549*7c478bd9Sstevel@tonic-gate gl->down = gl_tigetstr(gl, "cud1"); 3550*7c478bd9Sstevel@tonic-gate gl->home = gl_tigetstr(gl, "home"); 3551*7c478bd9Sstevel@tonic-gate gl->clear_eol = gl_tigetstr(gl, "el"); 3552*7c478bd9Sstevel@tonic-gate gl->clear_eod = gl_tigetstr(gl, "ed"); 3553*7c478bd9Sstevel@tonic-gate gl->u_arrow = gl_tigetstr(gl, "kcuu1"); 3554*7c478bd9Sstevel@tonic-gate gl->d_arrow = gl_tigetstr(gl, "kcud1"); 3555*7c478bd9Sstevel@tonic-gate gl->l_arrow = gl_tigetstr(gl, "kcub1"); 3556*7c478bd9Sstevel@tonic-gate gl->r_arrow = gl_tigetstr(gl, "kcuf1"); 3557*7c478bd9Sstevel@tonic-gate gl->left_n = gl_tigetstr(gl, "cub"); 3558*7c478bd9Sstevel@tonic-gate gl->right_n = gl_tigetstr(gl, "cuf"); 3559*7c478bd9Sstevel@tonic-gate gl->sound_bell = gl_tigetstr(gl, "bel"); 3560*7c478bd9Sstevel@tonic-gate gl->bold = gl_tigetstr(gl, "bold"); 3561*7c478bd9Sstevel@tonic-gate gl->underline = gl_tigetstr(gl, "smul"); 3562*7c478bd9Sstevel@tonic-gate gl->standout = gl_tigetstr(gl, "smso"); 3563*7c478bd9Sstevel@tonic-gate gl->dim = gl_tigetstr(gl, "dim"); 3564*7c478bd9Sstevel@tonic-gate gl->reverse = gl_tigetstr(gl, "rev"); 3565*7c478bd9Sstevel@tonic-gate gl->blink = gl_tigetstr(gl, "blink"); 3566*7c478bd9Sstevel@tonic-gate gl->text_attr_off = gl_tigetstr(gl, "sgr0"); 3567*7c478bd9Sstevel@tonic-gate }; 3568*7c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP) 3569*7c478bd9Sstevel@tonic-gate if(!term || tgetent(gl->tgetent_buf, (char *)term) < 0) { 3570*7c478bd9Sstevel@tonic-gate bad_term = 1; 3571*7c478bd9Sstevel@tonic-gate } else { 3572*7c478bd9Sstevel@tonic-gate char *tgetstr_buf_ptr = gl->tgetstr_buf; 3573*7c478bd9Sstevel@tonic-gate _clr_StringGroup(gl->capmem); 3574*7c478bd9Sstevel@tonic-gate gl->left = gl_tgetstr(gl, "le", &tgetstr_buf_ptr); 3575*7c478bd9Sstevel@tonic-gate gl->right = gl_tgetstr(gl, "nd", &tgetstr_buf_ptr); 3576*7c478bd9Sstevel@tonic-gate gl->up = gl_tgetstr(gl, "up", &tgetstr_buf_ptr); 3577*7c478bd9Sstevel@tonic-gate gl->down = gl_tgetstr(gl, "do", &tgetstr_buf_ptr); 3578*7c478bd9Sstevel@tonic-gate gl->home = gl_tgetstr(gl, "ho", &tgetstr_buf_ptr); 3579*7c478bd9Sstevel@tonic-gate gl->clear_eol = gl_tgetstr(gl, "ce", &tgetstr_buf_ptr); 3580*7c478bd9Sstevel@tonic-gate gl->clear_eod = gl_tgetstr(gl, "cd", &tgetstr_buf_ptr); 3581*7c478bd9Sstevel@tonic-gate gl->u_arrow = gl_tgetstr(gl, "ku", &tgetstr_buf_ptr); 3582*7c478bd9Sstevel@tonic-gate gl->d_arrow = gl_tgetstr(gl, "kd", &tgetstr_buf_ptr); 3583*7c478bd9Sstevel@tonic-gate gl->l_arrow = gl_tgetstr(gl, "kl", &tgetstr_buf_ptr); 3584*7c478bd9Sstevel@tonic-gate gl->r_arrow = gl_tgetstr(gl, "kr", &tgetstr_buf_ptr); 3585*7c478bd9Sstevel@tonic-gate gl->sound_bell = gl_tgetstr(gl, "bl", &tgetstr_buf_ptr); 3586*7c478bd9Sstevel@tonic-gate gl->bold = gl_tgetstr(gl, "md", &tgetstr_buf_ptr); 3587*7c478bd9Sstevel@tonic-gate gl->underline = gl_tgetstr(gl, "us", &tgetstr_buf_ptr); 3588*7c478bd9Sstevel@tonic-gate gl->standout = gl_tgetstr(gl, "so", &tgetstr_buf_ptr); 3589*7c478bd9Sstevel@tonic-gate gl->dim = gl_tgetstr(gl, "mh", &tgetstr_buf_ptr); 3590*7c478bd9Sstevel@tonic-gate gl->reverse = gl_tgetstr(gl, "mr", &tgetstr_buf_ptr); 3591*7c478bd9Sstevel@tonic-gate gl->blink = gl_tgetstr(gl, "mb", &tgetstr_buf_ptr); 3592*7c478bd9Sstevel@tonic-gate gl->text_attr_off = gl_tgetstr(gl, "me", &tgetstr_buf_ptr); 3593*7c478bd9Sstevel@tonic-gate }; 3594*7c478bd9Sstevel@tonic-gate #endif 3595*7c478bd9Sstevel@tonic-gate /* 3596*7c478bd9Sstevel@tonic-gate * Report term being unusable. 3597*7c478bd9Sstevel@tonic-gate */ 3598*7c478bd9Sstevel@tonic-gate if(bad_term) { 3599*7c478bd9Sstevel@tonic-gate gl_print_info(gl, "Bad terminal type: \"", term ? term : "(null)", 3600*7c478bd9Sstevel@tonic-gate "\". Will assume vt100.", GL_END_INFO); 3601*7c478bd9Sstevel@tonic-gate }; 3602*7c478bd9Sstevel@tonic-gate /* 3603*7c478bd9Sstevel@tonic-gate * Fill in missing information with ANSI VT100 strings. 3604*7c478bd9Sstevel@tonic-gate */ 3605*7c478bd9Sstevel@tonic-gate if(!gl->left) 3606*7c478bd9Sstevel@tonic-gate gl->left = "\b"; /* ^H */ 3607*7c478bd9Sstevel@tonic-gate if(!gl->right) 3608*7c478bd9Sstevel@tonic-gate gl->right = GL_ESC_STR "[C"; 3609*7c478bd9Sstevel@tonic-gate if(!gl->up) 3610*7c478bd9Sstevel@tonic-gate gl->up = GL_ESC_STR "[A"; 3611*7c478bd9Sstevel@tonic-gate if(!gl->down) 3612*7c478bd9Sstevel@tonic-gate gl->down = "\n"; 3613*7c478bd9Sstevel@tonic-gate if(!gl->home) 3614*7c478bd9Sstevel@tonic-gate gl->home = GL_ESC_STR "[H"; 3615*7c478bd9Sstevel@tonic-gate if(!gl->bol) 3616*7c478bd9Sstevel@tonic-gate gl->bol = "\r"; 3617*7c478bd9Sstevel@tonic-gate if(!gl->clear_eol) 3618*7c478bd9Sstevel@tonic-gate gl->clear_eol = GL_ESC_STR "[K"; 3619*7c478bd9Sstevel@tonic-gate if(!gl->clear_eod) 3620*7c478bd9Sstevel@tonic-gate gl->clear_eod = GL_ESC_STR "[J"; 3621*7c478bd9Sstevel@tonic-gate if(!gl->u_arrow) 3622*7c478bd9Sstevel@tonic-gate gl->u_arrow = GL_ESC_STR "[A"; 3623*7c478bd9Sstevel@tonic-gate if(!gl->d_arrow) 3624*7c478bd9Sstevel@tonic-gate gl->d_arrow = GL_ESC_STR "[B"; 3625*7c478bd9Sstevel@tonic-gate if(!gl->l_arrow) 3626*7c478bd9Sstevel@tonic-gate gl->l_arrow = GL_ESC_STR "[D"; 3627*7c478bd9Sstevel@tonic-gate if(!gl->r_arrow) 3628*7c478bd9Sstevel@tonic-gate gl->r_arrow = GL_ESC_STR "[C"; 3629*7c478bd9Sstevel@tonic-gate if(!gl->sound_bell) 3630*7c478bd9Sstevel@tonic-gate gl->sound_bell = "\a"; 3631*7c478bd9Sstevel@tonic-gate if(!gl->bold) 3632*7c478bd9Sstevel@tonic-gate gl->bold = GL_ESC_STR "[1m"; 3633*7c478bd9Sstevel@tonic-gate if(!gl->underline) 3634*7c478bd9Sstevel@tonic-gate gl->underline = GL_ESC_STR "[4m"; 3635*7c478bd9Sstevel@tonic-gate if(!gl->standout) 3636*7c478bd9Sstevel@tonic-gate gl->standout = GL_ESC_STR "[1;7m"; 3637*7c478bd9Sstevel@tonic-gate if(!gl->dim) 3638*7c478bd9Sstevel@tonic-gate gl->dim = ""; /* Not available */ 3639*7c478bd9Sstevel@tonic-gate if(!gl->reverse) 3640*7c478bd9Sstevel@tonic-gate gl->reverse = GL_ESC_STR "[7m"; 3641*7c478bd9Sstevel@tonic-gate if(!gl->blink) 3642*7c478bd9Sstevel@tonic-gate gl->blink = GL_ESC_STR "[5m"; 3643*7c478bd9Sstevel@tonic-gate if(!gl->text_attr_off) 3644*7c478bd9Sstevel@tonic-gate gl->text_attr_off = GL_ESC_STR "[m"; 3645*7c478bd9Sstevel@tonic-gate /* 3646*7c478bd9Sstevel@tonic-gate * Find out the current terminal size. 3647*7c478bd9Sstevel@tonic-gate */ 3648*7c478bd9Sstevel@tonic-gate (void) _gl_terminal_size(gl, GL_DEF_NCOLUMN, GL_DEF_NLINE, NULL); 3649*7c478bd9Sstevel@tonic-gate return 0; 3650*7c478bd9Sstevel@tonic-gate } 3651*7c478bd9Sstevel@tonic-gate 3652*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 3653*7c478bd9Sstevel@tonic-gate /*....................................................................... 3654*7c478bd9Sstevel@tonic-gate * This is a private function of gl_control_strings() used to look up 3655*7c478bd9Sstevel@tonic-gate * a termninal capability string from the terminfo database and make 3656*7c478bd9Sstevel@tonic-gate * a private copy of it. 3657*7c478bd9Sstevel@tonic-gate * 3658*7c478bd9Sstevel@tonic-gate * Input: 3659*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 3660*7c478bd9Sstevel@tonic-gate * name const char * The name of the terminfo string to look up. 3661*7c478bd9Sstevel@tonic-gate * Output: 3662*7c478bd9Sstevel@tonic-gate * return const char * The local copy of the capability, or NULL 3663*7c478bd9Sstevel@tonic-gate * if not available. 3664*7c478bd9Sstevel@tonic-gate */ 3665*7c478bd9Sstevel@tonic-gate static const char *gl_tigetstr(GetLine *gl, const char *name) 3666*7c478bd9Sstevel@tonic-gate { 3667*7c478bd9Sstevel@tonic-gate const char *value = tigetstr((char *)name); 3668*7c478bd9Sstevel@tonic-gate if(!value || value == (char *) -1) 3669*7c478bd9Sstevel@tonic-gate return NULL; 3670*7c478bd9Sstevel@tonic-gate return _sg_store_string(gl->capmem, value, 0); 3671*7c478bd9Sstevel@tonic-gate } 3672*7c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP) 3673*7c478bd9Sstevel@tonic-gate /*....................................................................... 3674*7c478bd9Sstevel@tonic-gate * This is a private function of gl_control_strings() used to look up 3675*7c478bd9Sstevel@tonic-gate * a termninal capability string from the termcap database and make 3676*7c478bd9Sstevel@tonic-gate * a private copy of it. Note that some emulations of tgetstr(), such 3677*7c478bd9Sstevel@tonic-gate * as that used by Solaris, ignores the buffer pointer that is past to 3678*7c478bd9Sstevel@tonic-gate * it, so we can't assume that a private copy has been made that won't 3679*7c478bd9Sstevel@tonic-gate * be trashed by another call to gl_control_strings() by another 3680*7c478bd9Sstevel@tonic-gate * GetLine object. So we make what may be a redundant private copy 3681*7c478bd9Sstevel@tonic-gate * of the string in gl->capmem. 3682*7c478bd9Sstevel@tonic-gate * 3683*7c478bd9Sstevel@tonic-gate * Input: 3684*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 3685*7c478bd9Sstevel@tonic-gate * name const char * The name of the terminfo string to look up. 3686*7c478bd9Sstevel@tonic-gate * Input/Output: 3687*7c478bd9Sstevel@tonic-gate * bufptr char ** On input *bufptr points to the location in 3688*7c478bd9Sstevel@tonic-gate * gl->tgetstr_buf at which to record the 3689*7c478bd9Sstevel@tonic-gate * capability string. On output *bufptr is 3690*7c478bd9Sstevel@tonic-gate * incremented over the stored string. 3691*7c478bd9Sstevel@tonic-gate * Output: 3692*7c478bd9Sstevel@tonic-gate * return const char * The local copy of the capability, or NULL 3693*7c478bd9Sstevel@tonic-gate * on error. 3694*7c478bd9Sstevel@tonic-gate */ 3695*7c478bd9Sstevel@tonic-gate static const char *gl_tgetstr(GetLine *gl, const char *name, char **bufptr) 3696*7c478bd9Sstevel@tonic-gate { 3697*7c478bd9Sstevel@tonic-gate const char *value = tgetstr((char *)name, bufptr); 3698*7c478bd9Sstevel@tonic-gate if(!value || value == (char *) -1) 3699*7c478bd9Sstevel@tonic-gate return NULL; 3700*7c478bd9Sstevel@tonic-gate return _sg_store_string(gl->capmem, value, 0); 3701*7c478bd9Sstevel@tonic-gate } 3702*7c478bd9Sstevel@tonic-gate #endif 3703*7c478bd9Sstevel@tonic-gate 3704*7c478bd9Sstevel@tonic-gate /*....................................................................... 3705*7c478bd9Sstevel@tonic-gate * This is an action function that implements a user interrupt (eg. ^C). 3706*7c478bd9Sstevel@tonic-gate */ 3707*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_user_interrupt) 3708*7c478bd9Sstevel@tonic-gate { 3709*7c478bd9Sstevel@tonic-gate raise(SIGINT); 3710*7c478bd9Sstevel@tonic-gate return 1; 3711*7c478bd9Sstevel@tonic-gate } 3712*7c478bd9Sstevel@tonic-gate 3713*7c478bd9Sstevel@tonic-gate /*....................................................................... 3714*7c478bd9Sstevel@tonic-gate * This is an action function that implements the abort signal. 3715*7c478bd9Sstevel@tonic-gate */ 3716*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_abort) 3717*7c478bd9Sstevel@tonic-gate { 3718*7c478bd9Sstevel@tonic-gate raise(SIGABRT); 3719*7c478bd9Sstevel@tonic-gate return 1; 3720*7c478bd9Sstevel@tonic-gate } 3721*7c478bd9Sstevel@tonic-gate 3722*7c478bd9Sstevel@tonic-gate /*....................................................................... 3723*7c478bd9Sstevel@tonic-gate * This is an action function that sends a suspend signal (eg. ^Z) to the 3724*7c478bd9Sstevel@tonic-gate * the parent process. 3725*7c478bd9Sstevel@tonic-gate */ 3726*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_suspend) 3727*7c478bd9Sstevel@tonic-gate { 3728*7c478bd9Sstevel@tonic-gate raise(SIGTSTP); 3729*7c478bd9Sstevel@tonic-gate return 0; 3730*7c478bd9Sstevel@tonic-gate } 3731*7c478bd9Sstevel@tonic-gate 3732*7c478bd9Sstevel@tonic-gate /*....................................................................... 3733*7c478bd9Sstevel@tonic-gate * This is an action function that halts output to the terminal. 3734*7c478bd9Sstevel@tonic-gate */ 3735*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_stop_output) 3736*7c478bd9Sstevel@tonic-gate { 3737*7c478bd9Sstevel@tonic-gate tcflow(gl->output_fd, TCOOFF); 3738*7c478bd9Sstevel@tonic-gate return 0; 3739*7c478bd9Sstevel@tonic-gate } 3740*7c478bd9Sstevel@tonic-gate 3741*7c478bd9Sstevel@tonic-gate /*....................................................................... 3742*7c478bd9Sstevel@tonic-gate * This is an action function that resumes halted terminal output. 3743*7c478bd9Sstevel@tonic-gate */ 3744*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_start_output) 3745*7c478bd9Sstevel@tonic-gate { 3746*7c478bd9Sstevel@tonic-gate tcflow(gl->output_fd, TCOON); 3747*7c478bd9Sstevel@tonic-gate return 0; 3748*7c478bd9Sstevel@tonic-gate } 3749*7c478bd9Sstevel@tonic-gate 3750*7c478bd9Sstevel@tonic-gate /*....................................................................... 3751*7c478bd9Sstevel@tonic-gate * This is an action function that allows the next character to be accepted 3752*7c478bd9Sstevel@tonic-gate * without any interpretation as a special character. 3753*7c478bd9Sstevel@tonic-gate */ 3754*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_literal_next) 3755*7c478bd9Sstevel@tonic-gate { 3756*7c478bd9Sstevel@tonic-gate char c; /* The character to be added to the line */ 3757*7c478bd9Sstevel@tonic-gate int i; 3758*7c478bd9Sstevel@tonic-gate /* 3759*7c478bd9Sstevel@tonic-gate * Get the character to be inserted literally. 3760*7c478bd9Sstevel@tonic-gate */ 3761*7c478bd9Sstevel@tonic-gate if(gl_read_terminal(gl, 1, &c)) 3762*7c478bd9Sstevel@tonic-gate return 1; 3763*7c478bd9Sstevel@tonic-gate /* 3764*7c478bd9Sstevel@tonic-gate * Add the character to the line 'count' times. 3765*7c478bd9Sstevel@tonic-gate */ 3766*7c478bd9Sstevel@tonic-gate for(i=0; i<count; i++) 3767*7c478bd9Sstevel@tonic-gate gl_add_char_to_line(gl, c); 3768*7c478bd9Sstevel@tonic-gate return 0; 3769*7c478bd9Sstevel@tonic-gate } 3770*7c478bd9Sstevel@tonic-gate 3771*7c478bd9Sstevel@tonic-gate /*....................................................................... 3772*7c478bd9Sstevel@tonic-gate * Return the width of a tab character at a given position when 3773*7c478bd9Sstevel@tonic-gate * displayed at a given position on the terminal. This is needed 3774*7c478bd9Sstevel@tonic-gate * because the width of tab characters depends on where they are, 3775*7c478bd9Sstevel@tonic-gate * relative to the preceding tab stops. 3776*7c478bd9Sstevel@tonic-gate * 3777*7c478bd9Sstevel@tonic-gate * Input: 3778*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 3779*7c478bd9Sstevel@tonic-gate * term_curpos int The destination terminal location of the character. 3780*7c478bd9Sstevel@tonic-gate * Output: 3781*7c478bd9Sstevel@tonic-gate * return int The number of terminal charaters needed. 3782*7c478bd9Sstevel@tonic-gate */ 3783*7c478bd9Sstevel@tonic-gate static int gl_displayed_tab_width(GetLine *gl, int term_curpos) 3784*7c478bd9Sstevel@tonic-gate { 3785*7c478bd9Sstevel@tonic-gate return TAB_WIDTH - ((term_curpos % gl->ncolumn) % TAB_WIDTH); 3786*7c478bd9Sstevel@tonic-gate } 3787*7c478bd9Sstevel@tonic-gate 3788*7c478bd9Sstevel@tonic-gate /*....................................................................... 3789*7c478bd9Sstevel@tonic-gate * Return the number of characters needed to display a given character 3790*7c478bd9Sstevel@tonic-gate * on the screen. Tab characters require eight spaces, and control 3791*7c478bd9Sstevel@tonic-gate * characters are represented by a caret followed by the modified 3792*7c478bd9Sstevel@tonic-gate * character. 3793*7c478bd9Sstevel@tonic-gate * 3794*7c478bd9Sstevel@tonic-gate * Input: 3795*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 3796*7c478bd9Sstevel@tonic-gate * c char The character to be displayed. 3797*7c478bd9Sstevel@tonic-gate * term_curpos int The destination terminal location of the character. 3798*7c478bd9Sstevel@tonic-gate * This is needed because the width of tab characters 3799*7c478bd9Sstevel@tonic-gate * depends on where they are, relative to the 3800*7c478bd9Sstevel@tonic-gate * preceding tab stops. 3801*7c478bd9Sstevel@tonic-gate * Output: 3802*7c478bd9Sstevel@tonic-gate * return int The number of terminal charaters needed. 3803*7c478bd9Sstevel@tonic-gate */ 3804*7c478bd9Sstevel@tonic-gate static int gl_displayed_char_width(GetLine *gl, char c, int term_curpos) 3805*7c478bd9Sstevel@tonic-gate { 3806*7c478bd9Sstevel@tonic-gate if(c=='\t') 3807*7c478bd9Sstevel@tonic-gate return gl_displayed_tab_width(gl, term_curpos); 3808*7c478bd9Sstevel@tonic-gate if(IS_CTRL_CHAR(c)) 3809*7c478bd9Sstevel@tonic-gate return 2; 3810*7c478bd9Sstevel@tonic-gate if(!isprint((int)(unsigned char) c)) 3811*7c478bd9Sstevel@tonic-gate return gl_octal_width((int)(unsigned char)c) + 1; 3812*7c478bd9Sstevel@tonic-gate return 1; 3813*7c478bd9Sstevel@tonic-gate } 3814*7c478bd9Sstevel@tonic-gate 3815*7c478bd9Sstevel@tonic-gate 3816*7c478bd9Sstevel@tonic-gate /*....................................................................... 3817*7c478bd9Sstevel@tonic-gate * Work out the length of given string of characters on the terminal. 3818*7c478bd9Sstevel@tonic-gate * 3819*7c478bd9Sstevel@tonic-gate * Input: 3820*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 3821*7c478bd9Sstevel@tonic-gate * string char * The string to be measured. 3822*7c478bd9Sstevel@tonic-gate * nc int The number of characters to be measured, or -1 3823*7c478bd9Sstevel@tonic-gate * to measure the whole string. 3824*7c478bd9Sstevel@tonic-gate * term_curpos int The destination terminal location of the character. 3825*7c478bd9Sstevel@tonic-gate * This is needed because the width of tab characters 3826*7c478bd9Sstevel@tonic-gate * depends on where they are, relative to the 3827*7c478bd9Sstevel@tonic-gate * preceding tab stops. 3828*7c478bd9Sstevel@tonic-gate * Output: 3829*7c478bd9Sstevel@tonic-gate * return int The number of displayed characters. 3830*7c478bd9Sstevel@tonic-gate */ 3831*7c478bd9Sstevel@tonic-gate static int gl_displayed_string_width(GetLine *gl, const char *string, int nc, 3832*7c478bd9Sstevel@tonic-gate int term_curpos) 3833*7c478bd9Sstevel@tonic-gate { 3834*7c478bd9Sstevel@tonic-gate int slen = 0; /* The displayed number of characters */ 3835*7c478bd9Sstevel@tonic-gate int i; 3836*7c478bd9Sstevel@tonic-gate /* 3837*7c478bd9Sstevel@tonic-gate * How many characters are to be measured? 3838*7c478bd9Sstevel@tonic-gate */ 3839*7c478bd9Sstevel@tonic-gate if(nc < 0) 3840*7c478bd9Sstevel@tonic-gate nc = strlen(string); 3841*7c478bd9Sstevel@tonic-gate /* 3842*7c478bd9Sstevel@tonic-gate * Add up the length of the displayed string. 3843*7c478bd9Sstevel@tonic-gate */ 3844*7c478bd9Sstevel@tonic-gate for(i=0; i<nc; i++) 3845*7c478bd9Sstevel@tonic-gate slen += gl_displayed_char_width(gl, string[i], term_curpos + slen); 3846*7c478bd9Sstevel@tonic-gate return slen; 3847*7c478bd9Sstevel@tonic-gate } 3848*7c478bd9Sstevel@tonic-gate 3849*7c478bd9Sstevel@tonic-gate /*....................................................................... 3850*7c478bd9Sstevel@tonic-gate * Write a string verbatim to the current terminal or output stream. 3851*7c478bd9Sstevel@tonic-gate * 3852*7c478bd9Sstevel@tonic-gate * Note that when async-signal safety is required, the 'buffered' 3853*7c478bd9Sstevel@tonic-gate * argument must be 0, and n must not be -1. 3854*7c478bd9Sstevel@tonic-gate * 3855*7c478bd9Sstevel@tonic-gate * Input: 3856*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of the gl_get_line(). 3857*7c478bd9Sstevel@tonic-gate * buffered int If true, used buffered I/O when writing to 3858*7c478bd9Sstevel@tonic-gate * the terminal. Otherwise use async-signal-safe 3859*7c478bd9Sstevel@tonic-gate * unbuffered I/O. 3860*7c478bd9Sstevel@tonic-gate * string const char * The string to be written (this need not be 3861*7c478bd9Sstevel@tonic-gate * '\0' terminated unless n<0). 3862*7c478bd9Sstevel@tonic-gate * n int The number of characters to write from the 3863*7c478bd9Sstevel@tonic-gate * prefix of string[], or -1 to request that 3864*7c478bd9Sstevel@tonic-gate * gl_print_raw_string() use strlen() to figure 3865*7c478bd9Sstevel@tonic-gate * out the length. 3866*7c478bd9Sstevel@tonic-gate * Output: 3867*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 3868*7c478bd9Sstevel@tonic-gate * 1 - Error. 3869*7c478bd9Sstevel@tonic-gate */ 3870*7c478bd9Sstevel@tonic-gate static int gl_print_raw_string(GetLine *gl, int buffered, 3871*7c478bd9Sstevel@tonic-gate const char *string, int n) 3872*7c478bd9Sstevel@tonic-gate { 3873*7c478bd9Sstevel@tonic-gate GlWriteFn *write_fn = buffered ? gl_write_fn : gl->flush_fn; 3874*7c478bd9Sstevel@tonic-gate /* 3875*7c478bd9Sstevel@tonic-gate * Only display output when echoing is turned on. 3876*7c478bd9Sstevel@tonic-gate */ 3877*7c478bd9Sstevel@tonic-gate if(gl->echo) { 3878*7c478bd9Sstevel@tonic-gate int ndone = 0; /* The number of characters written so far */ 3879*7c478bd9Sstevel@tonic-gate /* 3880*7c478bd9Sstevel@tonic-gate * When using un-buffered I/O, flush pending output first. 3881*7c478bd9Sstevel@tonic-gate */ 3882*7c478bd9Sstevel@tonic-gate if(!buffered) { 3883*7c478bd9Sstevel@tonic-gate if(gl_flush_output(gl)) 3884*7c478bd9Sstevel@tonic-gate return 1; 3885*7c478bd9Sstevel@tonic-gate }; 3886*7c478bd9Sstevel@tonic-gate /* 3887*7c478bd9Sstevel@tonic-gate * If no length has been provided, measure the length of the string. 3888*7c478bd9Sstevel@tonic-gate */ 3889*7c478bd9Sstevel@tonic-gate if(n < 0) 3890*7c478bd9Sstevel@tonic-gate n = strlen(string); 3891*7c478bd9Sstevel@tonic-gate /* 3892*7c478bd9Sstevel@tonic-gate * Write the string. 3893*7c478bd9Sstevel@tonic-gate */ 3894*7c478bd9Sstevel@tonic-gate if(write_fn(gl, string + ndone, n-ndone) != n) 3895*7c478bd9Sstevel@tonic-gate return 1; 3896*7c478bd9Sstevel@tonic-gate }; 3897*7c478bd9Sstevel@tonic-gate return 0; 3898*7c478bd9Sstevel@tonic-gate } 3899*7c478bd9Sstevel@tonic-gate 3900*7c478bd9Sstevel@tonic-gate /*....................................................................... 3901*7c478bd9Sstevel@tonic-gate * Output a terminal control sequence. When using terminfo, 3902*7c478bd9Sstevel@tonic-gate * this must be a sequence returned by tgetstr() or tigetstr() 3903*7c478bd9Sstevel@tonic-gate * respectively. 3904*7c478bd9Sstevel@tonic-gate * 3905*7c478bd9Sstevel@tonic-gate * Input: 3906*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 3907*7c478bd9Sstevel@tonic-gate * nline int The number of lines affected by the operation, 3908*7c478bd9Sstevel@tonic-gate * or 1 if not relevant. 3909*7c478bd9Sstevel@tonic-gate * string char * The control sequence to be sent. 3910*7c478bd9Sstevel@tonic-gate * Output: 3911*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 3912*7c478bd9Sstevel@tonic-gate * 1 - Error. 3913*7c478bd9Sstevel@tonic-gate */ 3914*7c478bd9Sstevel@tonic-gate static int gl_print_control_sequence(GetLine *gl, int nline, const char *string) 3915*7c478bd9Sstevel@tonic-gate { 3916*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True if an error occurs */ 3917*7c478bd9Sstevel@tonic-gate /* 3918*7c478bd9Sstevel@tonic-gate * Only write characters to the terminal when echoing is enabled. 3919*7c478bd9Sstevel@tonic-gate */ 3920*7c478bd9Sstevel@tonic-gate if(gl->echo) { 3921*7c478bd9Sstevel@tonic-gate #if defined(USE_TERMINFO) || defined(USE_TERMCAP) 3922*7c478bd9Sstevel@tonic-gate tputs_gl = gl; 3923*7c478bd9Sstevel@tonic-gate errno = 0; 3924*7c478bd9Sstevel@tonic-gate tputs((char *)string, nline, gl_tputs_putchar); 3925*7c478bd9Sstevel@tonic-gate waserr = errno != 0; 3926*7c478bd9Sstevel@tonic-gate #else 3927*7c478bd9Sstevel@tonic-gate waserr = gl_print_raw_string(gl, 1, string, -1); 3928*7c478bd9Sstevel@tonic-gate #endif 3929*7c478bd9Sstevel@tonic-gate }; 3930*7c478bd9Sstevel@tonic-gate return waserr; 3931*7c478bd9Sstevel@tonic-gate } 3932*7c478bd9Sstevel@tonic-gate 3933*7c478bd9Sstevel@tonic-gate #if defined(USE_TERMINFO) || defined(USE_TERMCAP) 3934*7c478bd9Sstevel@tonic-gate /*....................................................................... 3935*7c478bd9Sstevel@tonic-gate * The following callback function is called by tputs() to output a raw 3936*7c478bd9Sstevel@tonic-gate * control character to the terminal. 3937*7c478bd9Sstevel@tonic-gate */ 3938*7c478bd9Sstevel@tonic-gate static TputsRetType gl_tputs_putchar(TputsArgType c) 3939*7c478bd9Sstevel@tonic-gate { 3940*7c478bd9Sstevel@tonic-gate char ch = c; 3941*7c478bd9Sstevel@tonic-gate #if TPUTS_RETURNS_VALUE 3942*7c478bd9Sstevel@tonic-gate return gl_print_raw_string(tputs_gl, 1, &ch, 1); 3943*7c478bd9Sstevel@tonic-gate #else 3944*7c478bd9Sstevel@tonic-gate (void) gl_print_raw_string(tputs_gl, 1, &ch, 1); 3945*7c478bd9Sstevel@tonic-gate #endif 3946*7c478bd9Sstevel@tonic-gate } 3947*7c478bd9Sstevel@tonic-gate #endif 3948*7c478bd9Sstevel@tonic-gate 3949*7c478bd9Sstevel@tonic-gate /*....................................................................... 3950*7c478bd9Sstevel@tonic-gate * Move the terminal cursor n characters to the left or right. 3951*7c478bd9Sstevel@tonic-gate * 3952*7c478bd9Sstevel@tonic-gate * Input: 3953*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this program. 3954*7c478bd9Sstevel@tonic-gate * n int number of positions to the right (> 0) or left (< 0). 3955*7c478bd9Sstevel@tonic-gate * Output: 3956*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 3957*7c478bd9Sstevel@tonic-gate * 1 - Error. 3958*7c478bd9Sstevel@tonic-gate */ 3959*7c478bd9Sstevel@tonic-gate static int gl_terminal_move_cursor(GetLine *gl, int n) 3960*7c478bd9Sstevel@tonic-gate { 3961*7c478bd9Sstevel@tonic-gate int cur_row, cur_col; /* The current terminal row and column index of */ 3962*7c478bd9Sstevel@tonic-gate /* the cursor wrt the start of the input line. */ 3963*7c478bd9Sstevel@tonic-gate int new_row, new_col; /* The target terminal row and column index of */ 3964*7c478bd9Sstevel@tonic-gate /* the cursor wrt the start of the input line. */ 3965*7c478bd9Sstevel@tonic-gate /* 3966*7c478bd9Sstevel@tonic-gate * Do nothing if the input line isn't currently displayed. In this 3967*7c478bd9Sstevel@tonic-gate * case, the cursor will be moved to the right place when the line 3968*7c478bd9Sstevel@tonic-gate * is next redisplayed. 3969*7c478bd9Sstevel@tonic-gate */ 3970*7c478bd9Sstevel@tonic-gate if(!gl->displayed) 3971*7c478bd9Sstevel@tonic-gate return 0; 3972*7c478bd9Sstevel@tonic-gate /* 3973*7c478bd9Sstevel@tonic-gate * How far can we move left? 3974*7c478bd9Sstevel@tonic-gate */ 3975*7c478bd9Sstevel@tonic-gate if(gl->term_curpos + n < 0) 3976*7c478bd9Sstevel@tonic-gate n = gl->term_curpos; 3977*7c478bd9Sstevel@tonic-gate /* 3978*7c478bd9Sstevel@tonic-gate * Break down the current and target cursor locations into rows and columns. 3979*7c478bd9Sstevel@tonic-gate */ 3980*7c478bd9Sstevel@tonic-gate cur_row = gl->term_curpos / gl->ncolumn; 3981*7c478bd9Sstevel@tonic-gate cur_col = gl->term_curpos % gl->ncolumn; 3982*7c478bd9Sstevel@tonic-gate new_row = (gl->term_curpos + n) / gl->ncolumn; 3983*7c478bd9Sstevel@tonic-gate new_col = (gl->term_curpos + n) % gl->ncolumn; 3984*7c478bd9Sstevel@tonic-gate /* 3985*7c478bd9Sstevel@tonic-gate * Move down to the next line. 3986*7c478bd9Sstevel@tonic-gate */ 3987*7c478bd9Sstevel@tonic-gate for(; cur_row < new_row; cur_row++) { 3988*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->down)) 3989*7c478bd9Sstevel@tonic-gate return 1; 3990*7c478bd9Sstevel@tonic-gate }; 3991*7c478bd9Sstevel@tonic-gate /* 3992*7c478bd9Sstevel@tonic-gate * Move up to the previous line. 3993*7c478bd9Sstevel@tonic-gate */ 3994*7c478bd9Sstevel@tonic-gate for(; cur_row > new_row; cur_row--) { 3995*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->up)) 3996*7c478bd9Sstevel@tonic-gate return 1; 3997*7c478bd9Sstevel@tonic-gate }; 3998*7c478bd9Sstevel@tonic-gate /* 3999*7c478bd9Sstevel@tonic-gate * Move to the right within the target line? 4000*7c478bd9Sstevel@tonic-gate */ 4001*7c478bd9Sstevel@tonic-gate if(cur_col < new_col) { 4002*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 4003*7c478bd9Sstevel@tonic-gate /* 4004*7c478bd9Sstevel@tonic-gate * Use a parameterized control sequence if it generates less control 4005*7c478bd9Sstevel@tonic-gate * characters (guess based on ANSI terminal termcap entry). 4006*7c478bd9Sstevel@tonic-gate */ 4007*7c478bd9Sstevel@tonic-gate if(gl->right_n != NULL && new_col - cur_col > 1) { 4008*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, tparm((char *)gl->right_n, 4009*7c478bd9Sstevel@tonic-gate (long)(new_col - cur_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l))) 4010*7c478bd9Sstevel@tonic-gate return 1; 4011*7c478bd9Sstevel@tonic-gate } else 4012*7c478bd9Sstevel@tonic-gate #endif 4013*7c478bd9Sstevel@tonic-gate { 4014*7c478bd9Sstevel@tonic-gate for(; cur_col < new_col; cur_col++) { 4015*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->right)) 4016*7c478bd9Sstevel@tonic-gate return 1; 4017*7c478bd9Sstevel@tonic-gate }; 4018*7c478bd9Sstevel@tonic-gate }; 4019*7c478bd9Sstevel@tonic-gate /* 4020*7c478bd9Sstevel@tonic-gate * Move to the left within the target line? 4021*7c478bd9Sstevel@tonic-gate */ 4022*7c478bd9Sstevel@tonic-gate } else if(cur_col > new_col) { 4023*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 4024*7c478bd9Sstevel@tonic-gate /* 4025*7c478bd9Sstevel@tonic-gate * Use a parameterized control sequence if it generates less control 4026*7c478bd9Sstevel@tonic-gate * characters (guess based on ANSI terminal termcap entry). 4027*7c478bd9Sstevel@tonic-gate */ 4028*7c478bd9Sstevel@tonic-gate if(gl->left_n != NULL && cur_col - new_col > 3) { 4029*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, tparm((char *)gl->left_n, 4030*7c478bd9Sstevel@tonic-gate (long)(cur_col - new_col), 0l, 0l, 0l, 0l, 0l, 0l, 0l, 0l))) 4031*7c478bd9Sstevel@tonic-gate return 1; 4032*7c478bd9Sstevel@tonic-gate } else 4033*7c478bd9Sstevel@tonic-gate #endif 4034*7c478bd9Sstevel@tonic-gate { 4035*7c478bd9Sstevel@tonic-gate for(; cur_col > new_col; cur_col--) { 4036*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->left)) 4037*7c478bd9Sstevel@tonic-gate return 1; 4038*7c478bd9Sstevel@tonic-gate }; 4039*7c478bd9Sstevel@tonic-gate }; 4040*7c478bd9Sstevel@tonic-gate } 4041*7c478bd9Sstevel@tonic-gate /* 4042*7c478bd9Sstevel@tonic-gate * Update the recorded position of the terminal cursor. 4043*7c478bd9Sstevel@tonic-gate */ 4044*7c478bd9Sstevel@tonic-gate gl->term_curpos += n; 4045*7c478bd9Sstevel@tonic-gate return 0; 4046*7c478bd9Sstevel@tonic-gate } 4047*7c478bd9Sstevel@tonic-gate 4048*7c478bd9Sstevel@tonic-gate /*....................................................................... 4049*7c478bd9Sstevel@tonic-gate * Write a character to the terminal after expanding tabs and control 4050*7c478bd9Sstevel@tonic-gate * characters to their multi-character representations. 4051*7c478bd9Sstevel@tonic-gate * 4052*7c478bd9Sstevel@tonic-gate * Input: 4053*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this program. 4054*7c478bd9Sstevel@tonic-gate * c char The character to be output. 4055*7c478bd9Sstevel@tonic-gate * pad char Many terminals have the irritating feature that 4056*7c478bd9Sstevel@tonic-gate * when one writes a character in the last column of 4057*7c478bd9Sstevel@tonic-gate * of the terminal, the cursor isn't wrapped to the 4058*7c478bd9Sstevel@tonic-gate * start of the next line until one more character 4059*7c478bd9Sstevel@tonic-gate * is written. Some terminals don't do this, so 4060*7c478bd9Sstevel@tonic-gate * after such a write, we don't know where the 4061*7c478bd9Sstevel@tonic-gate * terminal is unless we output an extra character. 4062*7c478bd9Sstevel@tonic-gate * This argument specifies the character to write. 4063*7c478bd9Sstevel@tonic-gate * If at the end of the input line send '\0' or a 4064*7c478bd9Sstevel@tonic-gate * space, and a space will be written. Otherwise, 4065*7c478bd9Sstevel@tonic-gate * pass the next character in the input line 4066*7c478bd9Sstevel@tonic-gate * following the one being written. 4067*7c478bd9Sstevel@tonic-gate * Output: 4068*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 4069*7c478bd9Sstevel@tonic-gate */ 4070*7c478bd9Sstevel@tonic-gate static int gl_print_char(GetLine *gl, char c, char pad) 4071*7c478bd9Sstevel@tonic-gate { 4072*7c478bd9Sstevel@tonic-gate char string[TAB_WIDTH + 4]; /* A work area for composing compound strings */ 4073*7c478bd9Sstevel@tonic-gate int nchar; /* The number of terminal characters */ 4074*7c478bd9Sstevel@tonic-gate int i; 4075*7c478bd9Sstevel@tonic-gate /* 4076*7c478bd9Sstevel@tonic-gate * Check for special characters. 4077*7c478bd9Sstevel@tonic-gate */ 4078*7c478bd9Sstevel@tonic-gate if(c == '\t') { 4079*7c478bd9Sstevel@tonic-gate /* 4080*7c478bd9Sstevel@tonic-gate * How many spaces do we need to represent a tab at the current terminal 4081*7c478bd9Sstevel@tonic-gate * column? 4082*7c478bd9Sstevel@tonic-gate */ 4083*7c478bd9Sstevel@tonic-gate nchar = gl_displayed_tab_width(gl, gl->term_curpos); 4084*7c478bd9Sstevel@tonic-gate /* 4085*7c478bd9Sstevel@tonic-gate * Compose the tab string. 4086*7c478bd9Sstevel@tonic-gate */ 4087*7c478bd9Sstevel@tonic-gate for(i=0; i<nchar; i++) 4088*7c478bd9Sstevel@tonic-gate string[i] = ' '; 4089*7c478bd9Sstevel@tonic-gate } else if(IS_CTRL_CHAR(c)) { 4090*7c478bd9Sstevel@tonic-gate string[0] = '^'; 4091*7c478bd9Sstevel@tonic-gate string[1] = CTRL_TO_CHAR(c); 4092*7c478bd9Sstevel@tonic-gate nchar = 2; 4093*7c478bd9Sstevel@tonic-gate } else if(!isprint((int)(unsigned char) c)) { 4094*7c478bd9Sstevel@tonic-gate snprintf(string, sizeof(string), "\\%o", (int)(unsigned char)c); 4095*7c478bd9Sstevel@tonic-gate nchar = strlen(string); 4096*7c478bd9Sstevel@tonic-gate } else { 4097*7c478bd9Sstevel@tonic-gate string[0] = c; 4098*7c478bd9Sstevel@tonic-gate nchar = 1; 4099*7c478bd9Sstevel@tonic-gate }; 4100*7c478bd9Sstevel@tonic-gate /* 4101*7c478bd9Sstevel@tonic-gate * Terminate the string. 4102*7c478bd9Sstevel@tonic-gate */ 4103*7c478bd9Sstevel@tonic-gate string[nchar] = '\0'; 4104*7c478bd9Sstevel@tonic-gate /* 4105*7c478bd9Sstevel@tonic-gate * Write the string to the terminal. 4106*7c478bd9Sstevel@tonic-gate */ 4107*7c478bd9Sstevel@tonic-gate if(gl_print_raw_string(gl, 1, string, -1)) 4108*7c478bd9Sstevel@tonic-gate return 1; 4109*7c478bd9Sstevel@tonic-gate /* 4110*7c478bd9Sstevel@tonic-gate * Except for one exception to be described in a moment, the cursor should 4111*7c478bd9Sstevel@tonic-gate * now have been positioned after the character that was just output. 4112*7c478bd9Sstevel@tonic-gate */ 4113*7c478bd9Sstevel@tonic-gate gl->term_curpos += nchar; 4114*7c478bd9Sstevel@tonic-gate /* 4115*7c478bd9Sstevel@tonic-gate * Keep a record of the number of characters in the terminal version 4116*7c478bd9Sstevel@tonic-gate * of the input line. 4117*7c478bd9Sstevel@tonic-gate */ 4118*7c478bd9Sstevel@tonic-gate if(gl->term_curpos > gl->term_len) 4119*7c478bd9Sstevel@tonic-gate gl->term_len = gl->term_curpos; 4120*7c478bd9Sstevel@tonic-gate /* 4121*7c478bd9Sstevel@tonic-gate * If the new character ended exactly at the end of a line, 4122*7c478bd9Sstevel@tonic-gate * most terminals won't move the cursor onto the next line until we 4123*7c478bd9Sstevel@tonic-gate * have written a character on the next line, so append an extra 4124*7c478bd9Sstevel@tonic-gate * space then move the cursor back. 4125*7c478bd9Sstevel@tonic-gate */ 4126*7c478bd9Sstevel@tonic-gate if(gl->term_curpos % gl->ncolumn == 0) { 4127*7c478bd9Sstevel@tonic-gate int term_curpos = gl->term_curpos; 4128*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, pad ? pad : ' ', ' ') || 4129*7c478bd9Sstevel@tonic-gate gl_set_term_curpos(gl, term_curpos)) 4130*7c478bd9Sstevel@tonic-gate return 1; 4131*7c478bd9Sstevel@tonic-gate }; 4132*7c478bd9Sstevel@tonic-gate return 0; 4133*7c478bd9Sstevel@tonic-gate } 4134*7c478bd9Sstevel@tonic-gate 4135*7c478bd9Sstevel@tonic-gate /*....................................................................... 4136*7c478bd9Sstevel@tonic-gate * Write a string to the terminal after expanding tabs and control 4137*7c478bd9Sstevel@tonic-gate * characters to their multi-character representations. 4138*7c478bd9Sstevel@tonic-gate * 4139*7c478bd9Sstevel@tonic-gate * Input: 4140*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this program. 4141*7c478bd9Sstevel@tonic-gate * string char * The string to be output. 4142*7c478bd9Sstevel@tonic-gate * pad char Many terminals have the irritating feature that 4143*7c478bd9Sstevel@tonic-gate * when one writes a character in the last column of 4144*7c478bd9Sstevel@tonic-gate * of the terminal, the cursor isn't wrapped to the 4145*7c478bd9Sstevel@tonic-gate * start of the next line until one more character 4146*7c478bd9Sstevel@tonic-gate * is written. Some terminals don't do this, so 4147*7c478bd9Sstevel@tonic-gate * after such a write, we don't know where the 4148*7c478bd9Sstevel@tonic-gate * terminal is unless we output an extra character. 4149*7c478bd9Sstevel@tonic-gate * This argument specifies the character to write. 4150*7c478bd9Sstevel@tonic-gate * If at the end of the input line send '\0' or a 4151*7c478bd9Sstevel@tonic-gate * space, and a space will be written. Otherwise, 4152*7c478bd9Sstevel@tonic-gate * pass the next character in the input line 4153*7c478bd9Sstevel@tonic-gate * following the one being written. 4154*7c478bd9Sstevel@tonic-gate * Output: 4155*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 4156*7c478bd9Sstevel@tonic-gate */ 4157*7c478bd9Sstevel@tonic-gate static int gl_print_string(GetLine *gl, const char *string, char pad) 4158*7c478bd9Sstevel@tonic-gate { 4159*7c478bd9Sstevel@tonic-gate const char *cptr; /* A pointer into string[] */ 4160*7c478bd9Sstevel@tonic-gate for(cptr=string; *cptr; cptr++) { 4161*7c478bd9Sstevel@tonic-gate char nextc = cptr[1]; 4162*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, *cptr, nextc ? nextc : pad)) 4163*7c478bd9Sstevel@tonic-gate return 1; 4164*7c478bd9Sstevel@tonic-gate }; 4165*7c478bd9Sstevel@tonic-gate return 0; 4166*7c478bd9Sstevel@tonic-gate } 4167*7c478bd9Sstevel@tonic-gate 4168*7c478bd9Sstevel@tonic-gate /*....................................................................... 4169*7c478bd9Sstevel@tonic-gate * Move the terminal cursor position. 4170*7c478bd9Sstevel@tonic-gate * 4171*7c478bd9Sstevel@tonic-gate * Input: 4172*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 4173*7c478bd9Sstevel@tonic-gate * term_curpos int The destination terminal cursor position. 4174*7c478bd9Sstevel@tonic-gate * Output: 4175*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 4176*7c478bd9Sstevel@tonic-gate * 1 - Error. 4177*7c478bd9Sstevel@tonic-gate */ 4178*7c478bd9Sstevel@tonic-gate static int gl_set_term_curpos(GetLine *gl, int term_curpos) 4179*7c478bd9Sstevel@tonic-gate { 4180*7c478bd9Sstevel@tonic-gate return gl_terminal_move_cursor(gl, term_curpos - gl->term_curpos); 4181*7c478bd9Sstevel@tonic-gate } 4182*7c478bd9Sstevel@tonic-gate 4183*7c478bd9Sstevel@tonic-gate /*....................................................................... 4184*7c478bd9Sstevel@tonic-gate * This is an action function that moves the buffer cursor one character 4185*7c478bd9Sstevel@tonic-gate * left, and updates the terminal cursor to match. 4186*7c478bd9Sstevel@tonic-gate */ 4187*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_cursor_left) 4188*7c478bd9Sstevel@tonic-gate { 4189*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos - count); 4190*7c478bd9Sstevel@tonic-gate } 4191*7c478bd9Sstevel@tonic-gate 4192*7c478bd9Sstevel@tonic-gate /*....................................................................... 4193*7c478bd9Sstevel@tonic-gate * This is an action function that moves the buffer cursor one character 4194*7c478bd9Sstevel@tonic-gate * right, and updates the terminal cursor to match. 4195*7c478bd9Sstevel@tonic-gate */ 4196*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_cursor_right) 4197*7c478bd9Sstevel@tonic-gate { 4198*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos + count); 4199*7c478bd9Sstevel@tonic-gate } 4200*7c478bd9Sstevel@tonic-gate 4201*7c478bd9Sstevel@tonic-gate /*....................................................................... 4202*7c478bd9Sstevel@tonic-gate * This is an action function that toggles between overwrite and insert 4203*7c478bd9Sstevel@tonic-gate * mode. 4204*7c478bd9Sstevel@tonic-gate */ 4205*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_insert_mode) 4206*7c478bd9Sstevel@tonic-gate { 4207*7c478bd9Sstevel@tonic-gate gl->insert = !gl->insert; 4208*7c478bd9Sstevel@tonic-gate return 0; 4209*7c478bd9Sstevel@tonic-gate } 4210*7c478bd9Sstevel@tonic-gate 4211*7c478bd9Sstevel@tonic-gate /*....................................................................... 4212*7c478bd9Sstevel@tonic-gate * This is an action function which moves the cursor to the beginning of 4213*7c478bd9Sstevel@tonic-gate * the line. 4214*7c478bd9Sstevel@tonic-gate */ 4215*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_beginning_of_line) 4216*7c478bd9Sstevel@tonic-gate { 4217*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, 0); 4218*7c478bd9Sstevel@tonic-gate } 4219*7c478bd9Sstevel@tonic-gate 4220*7c478bd9Sstevel@tonic-gate /*....................................................................... 4221*7c478bd9Sstevel@tonic-gate * This is an action function which moves the cursor to the end of 4222*7c478bd9Sstevel@tonic-gate * the line. 4223*7c478bd9Sstevel@tonic-gate */ 4224*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_end_of_line) 4225*7c478bd9Sstevel@tonic-gate { 4226*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->ntotal); 4227*7c478bd9Sstevel@tonic-gate } 4228*7c478bd9Sstevel@tonic-gate 4229*7c478bd9Sstevel@tonic-gate /*....................................................................... 4230*7c478bd9Sstevel@tonic-gate * This is an action function which deletes the entire contents of the 4231*7c478bd9Sstevel@tonic-gate * current line. 4232*7c478bd9Sstevel@tonic-gate */ 4233*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_line) 4234*7c478bd9Sstevel@tonic-gate { 4235*7c478bd9Sstevel@tonic-gate /* 4236*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4237*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4238*7c478bd9Sstevel@tonic-gate */ 4239*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4240*7c478bd9Sstevel@tonic-gate /* 4241*7c478bd9Sstevel@tonic-gate * Copy the contents of the line to the cut buffer. 4242*7c478bd9Sstevel@tonic-gate */ 4243*7c478bd9Sstevel@tonic-gate strlcpy(gl->cutbuf, gl->line, gl->linelen); 4244*7c478bd9Sstevel@tonic-gate /* 4245*7c478bd9Sstevel@tonic-gate * Clear the buffer. 4246*7c478bd9Sstevel@tonic-gate */ 4247*7c478bd9Sstevel@tonic-gate gl_truncate_buffer(gl, 0); 4248*7c478bd9Sstevel@tonic-gate /* 4249*7c478bd9Sstevel@tonic-gate * Move the terminal cursor to just after the prompt. 4250*7c478bd9Sstevel@tonic-gate */ 4251*7c478bd9Sstevel@tonic-gate if(gl_place_cursor(gl, 0)) 4252*7c478bd9Sstevel@tonic-gate return 1; 4253*7c478bd9Sstevel@tonic-gate /* 4254*7c478bd9Sstevel@tonic-gate * Clear from the end of the prompt to the end of the terminal. 4255*7c478bd9Sstevel@tonic-gate */ 4256*7c478bd9Sstevel@tonic-gate if(gl_truncate_display(gl)) 4257*7c478bd9Sstevel@tonic-gate return 1; 4258*7c478bd9Sstevel@tonic-gate return 0; 4259*7c478bd9Sstevel@tonic-gate } 4260*7c478bd9Sstevel@tonic-gate 4261*7c478bd9Sstevel@tonic-gate /*....................................................................... 4262*7c478bd9Sstevel@tonic-gate * This is an action function which deletes all characters between the 4263*7c478bd9Sstevel@tonic-gate * current cursor position and the end of the line. 4264*7c478bd9Sstevel@tonic-gate */ 4265*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_kill_line) 4266*7c478bd9Sstevel@tonic-gate { 4267*7c478bd9Sstevel@tonic-gate /* 4268*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4269*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4270*7c478bd9Sstevel@tonic-gate */ 4271*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4272*7c478bd9Sstevel@tonic-gate /* 4273*7c478bd9Sstevel@tonic-gate * Copy the part of the line that is about to be deleted to the cut buffer. 4274*7c478bd9Sstevel@tonic-gate */ 4275*7c478bd9Sstevel@tonic-gate strlcpy(gl->cutbuf, gl->line + gl->buff_curpos, gl->linelen); 4276*7c478bd9Sstevel@tonic-gate /* 4277*7c478bd9Sstevel@tonic-gate * Terminate the buffered line at the current cursor position. 4278*7c478bd9Sstevel@tonic-gate */ 4279*7c478bd9Sstevel@tonic-gate gl_truncate_buffer(gl, gl->buff_curpos); 4280*7c478bd9Sstevel@tonic-gate /* 4281*7c478bd9Sstevel@tonic-gate * Clear the part of the line that follows the cursor. 4282*7c478bd9Sstevel@tonic-gate */ 4283*7c478bd9Sstevel@tonic-gate if(gl_truncate_display(gl)) 4284*7c478bd9Sstevel@tonic-gate return 1; 4285*7c478bd9Sstevel@tonic-gate /* 4286*7c478bd9Sstevel@tonic-gate * Explicitly reset the cursor position to allow vi command mode 4287*7c478bd9Sstevel@tonic-gate * constraints on its position to be set. 4288*7c478bd9Sstevel@tonic-gate */ 4289*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos); 4290*7c478bd9Sstevel@tonic-gate } 4291*7c478bd9Sstevel@tonic-gate 4292*7c478bd9Sstevel@tonic-gate /*....................................................................... 4293*7c478bd9Sstevel@tonic-gate * This is an action function which deletes all characters between the 4294*7c478bd9Sstevel@tonic-gate * start of the line and the current cursor position. 4295*7c478bd9Sstevel@tonic-gate */ 4296*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_kill_line) 4297*7c478bd9Sstevel@tonic-gate { 4298*7c478bd9Sstevel@tonic-gate /* 4299*7c478bd9Sstevel@tonic-gate * How many characters are to be deleted from before the cursor? 4300*7c478bd9Sstevel@tonic-gate */ 4301*7c478bd9Sstevel@tonic-gate int nc = gl->buff_curpos - gl->insert_curpos; 4302*7c478bd9Sstevel@tonic-gate if (!nc) 4303*7c478bd9Sstevel@tonic-gate return 0; 4304*7c478bd9Sstevel@tonic-gate /* 4305*7c478bd9Sstevel@tonic-gate * Move the cursor to the start of the line, or in vi input mode, 4306*7c478bd9Sstevel@tonic-gate * the start of the sub-line at which insertion started, and delete 4307*7c478bd9Sstevel@tonic-gate * up to the old cursor position. 4308*7c478bd9Sstevel@tonic-gate */ 4309*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->insert_curpos) || 4310*7c478bd9Sstevel@tonic-gate gl_delete_chars(gl, nc, gl->editor == GL_EMACS_MODE || gl->vi.command); 4311*7c478bd9Sstevel@tonic-gate } 4312*7c478bd9Sstevel@tonic-gate 4313*7c478bd9Sstevel@tonic-gate /*....................................................................... 4314*7c478bd9Sstevel@tonic-gate * This is an action function which moves the cursor forward by a word. 4315*7c478bd9Sstevel@tonic-gate */ 4316*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_word) 4317*7c478bd9Sstevel@tonic-gate { 4318*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl_nth_word_end_forward(gl, count) + 4319*7c478bd9Sstevel@tonic-gate (gl->editor==GL_EMACS_MODE)); 4320*7c478bd9Sstevel@tonic-gate } 4321*7c478bd9Sstevel@tonic-gate 4322*7c478bd9Sstevel@tonic-gate /*....................................................................... 4323*7c478bd9Sstevel@tonic-gate * This is an action function which moves the cursor forward to the start 4324*7c478bd9Sstevel@tonic-gate * of the next word. 4325*7c478bd9Sstevel@tonic-gate */ 4326*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_to_word) 4327*7c478bd9Sstevel@tonic-gate { 4328*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl_nth_word_start_forward(gl, count)); 4329*7c478bd9Sstevel@tonic-gate } 4330*7c478bd9Sstevel@tonic-gate 4331*7c478bd9Sstevel@tonic-gate /*....................................................................... 4332*7c478bd9Sstevel@tonic-gate * This is an action function which moves the cursor backward by a word. 4333*7c478bd9Sstevel@tonic-gate */ 4334*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_word) 4335*7c478bd9Sstevel@tonic-gate { 4336*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl_nth_word_start_backward(gl, count)); 4337*7c478bd9Sstevel@tonic-gate } 4338*7c478bd9Sstevel@tonic-gate 4339*7c478bd9Sstevel@tonic-gate /*....................................................................... 4340*7c478bd9Sstevel@tonic-gate * Delete one or more characters, starting with the one under the cursor. 4341*7c478bd9Sstevel@tonic-gate * 4342*7c478bd9Sstevel@tonic-gate * Input: 4343*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 4344*7c478bd9Sstevel@tonic-gate * nc int The number of characters to delete. 4345*7c478bd9Sstevel@tonic-gate * cut int If true, copy the characters to the cut buffer. 4346*7c478bd9Sstevel@tonic-gate * Output: 4347*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 4348*7c478bd9Sstevel@tonic-gate * 1 - Error. 4349*7c478bd9Sstevel@tonic-gate */ 4350*7c478bd9Sstevel@tonic-gate static int gl_delete_chars(GetLine *gl, int nc, int cut) 4351*7c478bd9Sstevel@tonic-gate { 4352*7c478bd9Sstevel@tonic-gate /* 4353*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4354*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4355*7c478bd9Sstevel@tonic-gate */ 4356*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4357*7c478bd9Sstevel@tonic-gate /* 4358*7c478bd9Sstevel@tonic-gate * If there are fewer than nc characters following the cursor, limit 4359*7c478bd9Sstevel@tonic-gate * nc to the number available. 4360*7c478bd9Sstevel@tonic-gate */ 4361*7c478bd9Sstevel@tonic-gate if(gl->buff_curpos + nc > gl->ntotal) 4362*7c478bd9Sstevel@tonic-gate nc = gl->ntotal - gl->buff_curpos; 4363*7c478bd9Sstevel@tonic-gate /* 4364*7c478bd9Sstevel@tonic-gate * Copy the about to be deleted region to the cut buffer. 4365*7c478bd9Sstevel@tonic-gate */ 4366*7c478bd9Sstevel@tonic-gate if(cut) { 4367*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + gl->buff_curpos, nc); 4368*7c478bd9Sstevel@tonic-gate gl->cutbuf[nc] = '\0'; 4369*7c478bd9Sstevel@tonic-gate } 4370*7c478bd9Sstevel@tonic-gate /* 4371*7c478bd9Sstevel@tonic-gate * Nothing to delete? 4372*7c478bd9Sstevel@tonic-gate */ 4373*7c478bd9Sstevel@tonic-gate if(nc <= 0) 4374*7c478bd9Sstevel@tonic-gate return 0; 4375*7c478bd9Sstevel@tonic-gate /* 4376*7c478bd9Sstevel@tonic-gate * In vi overwrite mode, restore any previously overwritten characters 4377*7c478bd9Sstevel@tonic-gate * from the undo buffer. 4378*7c478bd9Sstevel@tonic-gate */ 4379*7c478bd9Sstevel@tonic-gate if(gl->editor == GL_VI_MODE && !gl->vi.command && !gl->insert) { 4380*7c478bd9Sstevel@tonic-gate /* 4381*7c478bd9Sstevel@tonic-gate * How many of the characters being deleted can be restored from the 4382*7c478bd9Sstevel@tonic-gate * undo buffer? 4383*7c478bd9Sstevel@tonic-gate */ 4384*7c478bd9Sstevel@tonic-gate int nrestore = gl->buff_curpos + nc <= gl->vi.undo.ntotal ? 4385*7c478bd9Sstevel@tonic-gate nc : gl->vi.undo.ntotal - gl->buff_curpos; 4386*7c478bd9Sstevel@tonic-gate /* 4387*7c478bd9Sstevel@tonic-gate * Restore any available characters. 4388*7c478bd9Sstevel@tonic-gate */ 4389*7c478bd9Sstevel@tonic-gate if(nrestore > 0) { 4390*7c478bd9Sstevel@tonic-gate gl_buffer_string(gl, gl->vi.undo.line + gl->buff_curpos, nrestore, 4391*7c478bd9Sstevel@tonic-gate gl->buff_curpos); 4392*7c478bd9Sstevel@tonic-gate }; 4393*7c478bd9Sstevel@tonic-gate /* 4394*7c478bd9Sstevel@tonic-gate * If their were insufficient characters in the undo buffer, then this 4395*7c478bd9Sstevel@tonic-gate * implies that we are deleting from the end of the line, so we need 4396*7c478bd9Sstevel@tonic-gate * to terminate the line either where the undo buffer ran out, or if 4397*7c478bd9Sstevel@tonic-gate * we are deleting from beyond the end of the undo buffer, at the current 4398*7c478bd9Sstevel@tonic-gate * cursor position. 4399*7c478bd9Sstevel@tonic-gate */ 4400*7c478bd9Sstevel@tonic-gate if(nc != nrestore) { 4401*7c478bd9Sstevel@tonic-gate gl_truncate_buffer(gl, (gl->vi.undo.ntotal > gl->buff_curpos) ? 4402*7c478bd9Sstevel@tonic-gate gl->vi.undo.ntotal : gl->buff_curpos); 4403*7c478bd9Sstevel@tonic-gate }; 4404*7c478bd9Sstevel@tonic-gate } else { 4405*7c478bd9Sstevel@tonic-gate /* 4406*7c478bd9Sstevel@tonic-gate * Copy the remaining part of the line back over the deleted characters. 4407*7c478bd9Sstevel@tonic-gate */ 4408*7c478bd9Sstevel@tonic-gate gl_remove_from_buffer(gl, gl->buff_curpos, nc); 4409*7c478bd9Sstevel@tonic-gate }; 4410*7c478bd9Sstevel@tonic-gate /* 4411*7c478bd9Sstevel@tonic-gate * Redraw the remaining characters following the cursor. 4412*7c478bd9Sstevel@tonic-gate */ 4413*7c478bd9Sstevel@tonic-gate if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0')) 4414*7c478bd9Sstevel@tonic-gate return 1; 4415*7c478bd9Sstevel@tonic-gate /* 4416*7c478bd9Sstevel@tonic-gate * Clear to the end of the terminal. 4417*7c478bd9Sstevel@tonic-gate */ 4418*7c478bd9Sstevel@tonic-gate if(gl_truncate_display(gl)) 4419*7c478bd9Sstevel@tonic-gate return 1; 4420*7c478bd9Sstevel@tonic-gate /* 4421*7c478bd9Sstevel@tonic-gate * Place the cursor at the start of where the deletion was performed. 4422*7c478bd9Sstevel@tonic-gate */ 4423*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos); 4424*7c478bd9Sstevel@tonic-gate } 4425*7c478bd9Sstevel@tonic-gate 4426*7c478bd9Sstevel@tonic-gate /*....................................................................... 4427*7c478bd9Sstevel@tonic-gate * This is an action function which deletes character(s) under the 4428*7c478bd9Sstevel@tonic-gate * cursor without moving the cursor. 4429*7c478bd9Sstevel@tonic-gate */ 4430*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_char) 4431*7c478bd9Sstevel@tonic-gate { 4432*7c478bd9Sstevel@tonic-gate /* 4433*7c478bd9Sstevel@tonic-gate * Delete 'count' characters. 4434*7c478bd9Sstevel@tonic-gate */ 4435*7c478bd9Sstevel@tonic-gate return gl_delete_chars(gl, count, gl->vi.command); 4436*7c478bd9Sstevel@tonic-gate } 4437*7c478bd9Sstevel@tonic-gate 4438*7c478bd9Sstevel@tonic-gate /*....................................................................... 4439*7c478bd9Sstevel@tonic-gate * This is an action function which deletes character(s) under the 4440*7c478bd9Sstevel@tonic-gate * cursor and moves the cursor back one character. 4441*7c478bd9Sstevel@tonic-gate */ 4442*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_char) 4443*7c478bd9Sstevel@tonic-gate { 4444*7c478bd9Sstevel@tonic-gate /* 4445*7c478bd9Sstevel@tonic-gate * Restrict the deletion count to the number of characters that 4446*7c478bd9Sstevel@tonic-gate * precede the insertion point. 4447*7c478bd9Sstevel@tonic-gate */ 4448*7c478bd9Sstevel@tonic-gate if(count > gl->buff_curpos - gl->insert_curpos) 4449*7c478bd9Sstevel@tonic-gate count = gl->buff_curpos - gl->insert_curpos; 4450*7c478bd9Sstevel@tonic-gate /* 4451*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4452*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4453*7c478bd9Sstevel@tonic-gate */ 4454*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4455*7c478bd9Sstevel@tonic-gate return gl_cursor_left(gl, count, NULL) || 4456*7c478bd9Sstevel@tonic-gate gl_delete_chars(gl, count, gl->vi.command); 4457*7c478bd9Sstevel@tonic-gate } 4458*7c478bd9Sstevel@tonic-gate 4459*7c478bd9Sstevel@tonic-gate /*....................................................................... 4460*7c478bd9Sstevel@tonic-gate * Starting from the cursor position delete to the specified column. 4461*7c478bd9Sstevel@tonic-gate */ 4462*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_to_column) 4463*7c478bd9Sstevel@tonic-gate { 4464*7c478bd9Sstevel@tonic-gate if (--count >= gl->buff_curpos) 4465*7c478bd9Sstevel@tonic-gate return gl_forward_delete_char(gl, count - gl->buff_curpos, NULL); 4466*7c478bd9Sstevel@tonic-gate else 4467*7c478bd9Sstevel@tonic-gate return gl_backward_delete_char(gl, gl->buff_curpos - count, NULL); 4468*7c478bd9Sstevel@tonic-gate } 4469*7c478bd9Sstevel@tonic-gate 4470*7c478bd9Sstevel@tonic-gate /*....................................................................... 4471*7c478bd9Sstevel@tonic-gate * Starting from the cursor position delete characters to a matching 4472*7c478bd9Sstevel@tonic-gate * parenthesis. 4473*7c478bd9Sstevel@tonic-gate */ 4474*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_to_parenthesis) 4475*7c478bd9Sstevel@tonic-gate { 4476*7c478bd9Sstevel@tonic-gate int curpos = gl_index_of_matching_paren(gl); 4477*7c478bd9Sstevel@tonic-gate if(curpos >= 0) { 4478*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4479*7c478bd9Sstevel@tonic-gate if(curpos >= gl->buff_curpos) 4480*7c478bd9Sstevel@tonic-gate return gl_forward_delete_char(gl, curpos - gl->buff_curpos + 1, NULL); 4481*7c478bd9Sstevel@tonic-gate else 4482*7c478bd9Sstevel@tonic-gate return gl_backward_delete_char(gl, ++gl->buff_curpos - curpos + 1, NULL); 4483*7c478bd9Sstevel@tonic-gate }; 4484*7c478bd9Sstevel@tonic-gate return 0; 4485*7c478bd9Sstevel@tonic-gate } 4486*7c478bd9Sstevel@tonic-gate 4487*7c478bd9Sstevel@tonic-gate /*....................................................................... 4488*7c478bd9Sstevel@tonic-gate * This is an action function which deletes from the cursor to the end 4489*7c478bd9Sstevel@tonic-gate * of the word that the cursor is either in or precedes. 4490*7c478bd9Sstevel@tonic-gate */ 4491*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_word) 4492*7c478bd9Sstevel@tonic-gate { 4493*7c478bd9Sstevel@tonic-gate /* 4494*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4495*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4496*7c478bd9Sstevel@tonic-gate */ 4497*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4498*7c478bd9Sstevel@tonic-gate /* 4499*7c478bd9Sstevel@tonic-gate * In emacs mode delete to the end of the word. In vi mode delete to the 4500*7c478bd9Sstevel@tonic-gate * start of the net word. 4501*7c478bd9Sstevel@tonic-gate */ 4502*7c478bd9Sstevel@tonic-gate if(gl->editor == GL_EMACS_MODE) { 4503*7c478bd9Sstevel@tonic-gate return gl_delete_chars(gl, 4504*7c478bd9Sstevel@tonic-gate gl_nth_word_end_forward(gl,count) - gl->buff_curpos + 1, 1); 4505*7c478bd9Sstevel@tonic-gate } else { 4506*7c478bd9Sstevel@tonic-gate return gl_delete_chars(gl, 4507*7c478bd9Sstevel@tonic-gate gl_nth_word_start_forward(gl,count) - gl->buff_curpos, 4508*7c478bd9Sstevel@tonic-gate gl->vi.command); 4509*7c478bd9Sstevel@tonic-gate }; 4510*7c478bd9Sstevel@tonic-gate } 4511*7c478bd9Sstevel@tonic-gate 4512*7c478bd9Sstevel@tonic-gate /*....................................................................... 4513*7c478bd9Sstevel@tonic-gate * This is an action function which deletes the word that precedes the 4514*7c478bd9Sstevel@tonic-gate * cursor. 4515*7c478bd9Sstevel@tonic-gate */ 4516*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_word) 4517*7c478bd9Sstevel@tonic-gate { 4518*7c478bd9Sstevel@tonic-gate /* 4519*7c478bd9Sstevel@tonic-gate * Keep a record of the current cursor position. 4520*7c478bd9Sstevel@tonic-gate */ 4521*7c478bd9Sstevel@tonic-gate int buff_curpos = gl->buff_curpos; 4522*7c478bd9Sstevel@tonic-gate /* 4523*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4524*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4525*7c478bd9Sstevel@tonic-gate */ 4526*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4527*7c478bd9Sstevel@tonic-gate /* 4528*7c478bd9Sstevel@tonic-gate * Move back 'count' words. 4529*7c478bd9Sstevel@tonic-gate */ 4530*7c478bd9Sstevel@tonic-gate if(gl_backward_word(gl, count, NULL)) 4531*7c478bd9Sstevel@tonic-gate return 1; 4532*7c478bd9Sstevel@tonic-gate /* 4533*7c478bd9Sstevel@tonic-gate * Delete from the new cursor position to the original one. 4534*7c478bd9Sstevel@tonic-gate */ 4535*7c478bd9Sstevel@tonic-gate return gl_delete_chars(gl, buff_curpos - gl->buff_curpos, 4536*7c478bd9Sstevel@tonic-gate gl->editor == GL_EMACS_MODE || gl->vi.command); 4537*7c478bd9Sstevel@tonic-gate } 4538*7c478bd9Sstevel@tonic-gate 4539*7c478bd9Sstevel@tonic-gate /*....................................................................... 4540*7c478bd9Sstevel@tonic-gate * Searching in a given direction, delete to the count'th 4541*7c478bd9Sstevel@tonic-gate * instance of a specified or queried character, in the input line. 4542*7c478bd9Sstevel@tonic-gate * 4543*7c478bd9Sstevel@tonic-gate * Input: 4544*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 4545*7c478bd9Sstevel@tonic-gate * count int The number of times to search. 4546*7c478bd9Sstevel@tonic-gate * c char The character to be searched for, or '\0' if 4547*7c478bd9Sstevel@tonic-gate * the character should be read from the user. 4548*7c478bd9Sstevel@tonic-gate * forward int True if searching forward. 4549*7c478bd9Sstevel@tonic-gate * onto int True if the search should end on top of the 4550*7c478bd9Sstevel@tonic-gate * character, false if the search should stop 4551*7c478bd9Sstevel@tonic-gate * one character before the character in the 4552*7c478bd9Sstevel@tonic-gate * specified search direction. 4553*7c478bd9Sstevel@tonic-gate * change int If true, this function is being called upon 4554*7c478bd9Sstevel@tonic-gate * to do a vi change command, in which case the 4555*7c478bd9Sstevel@tonic-gate * user will be left in insert mode after the 4556*7c478bd9Sstevel@tonic-gate * deletion. 4557*7c478bd9Sstevel@tonic-gate * Output: 4558*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 4559*7c478bd9Sstevel@tonic-gate * 1 - Error. 4560*7c478bd9Sstevel@tonic-gate */ 4561*7c478bd9Sstevel@tonic-gate static int gl_delete_find(GetLine *gl, int count, char c, int forward, 4562*7c478bd9Sstevel@tonic-gate int onto, int change) 4563*7c478bd9Sstevel@tonic-gate { 4564*7c478bd9Sstevel@tonic-gate /* 4565*7c478bd9Sstevel@tonic-gate * Search for the character, and abort the deletion if not found. 4566*7c478bd9Sstevel@tonic-gate */ 4567*7c478bd9Sstevel@tonic-gate int pos = gl_find_char(gl, count, forward, onto, c); 4568*7c478bd9Sstevel@tonic-gate if(pos < 0) 4569*7c478bd9Sstevel@tonic-gate return 0; 4570*7c478bd9Sstevel@tonic-gate /* 4571*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4572*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4573*7c478bd9Sstevel@tonic-gate */ 4574*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4575*7c478bd9Sstevel@tonic-gate /* 4576*7c478bd9Sstevel@tonic-gate * Allow the cursor to be at the end of the line if this is a change 4577*7c478bd9Sstevel@tonic-gate * command. 4578*7c478bd9Sstevel@tonic-gate */ 4579*7c478bd9Sstevel@tonic-gate if(change) 4580*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; 4581*7c478bd9Sstevel@tonic-gate /* 4582*7c478bd9Sstevel@tonic-gate * Delete the appropriate span of characters. 4583*7c478bd9Sstevel@tonic-gate */ 4584*7c478bd9Sstevel@tonic-gate if(forward) { 4585*7c478bd9Sstevel@tonic-gate if(gl_delete_chars(gl, pos - gl->buff_curpos + 1, 1)) 4586*7c478bd9Sstevel@tonic-gate return 1; 4587*7c478bd9Sstevel@tonic-gate } else { 4588*7c478bd9Sstevel@tonic-gate int buff_curpos = gl->buff_curpos; 4589*7c478bd9Sstevel@tonic-gate if(gl_place_cursor(gl, pos) || 4590*7c478bd9Sstevel@tonic-gate gl_delete_chars(gl, buff_curpos - gl->buff_curpos, 1)) 4591*7c478bd9Sstevel@tonic-gate return 1; 4592*7c478bd9Sstevel@tonic-gate }; 4593*7c478bd9Sstevel@tonic-gate /* 4594*7c478bd9Sstevel@tonic-gate * If this is a change operation, switch the insert mode. 4595*7c478bd9Sstevel@tonic-gate */ 4596*7c478bd9Sstevel@tonic-gate if(change && gl_vi_insert(gl, 0, NULL)) 4597*7c478bd9Sstevel@tonic-gate return 1; 4598*7c478bd9Sstevel@tonic-gate return 0; 4599*7c478bd9Sstevel@tonic-gate } 4600*7c478bd9Sstevel@tonic-gate 4601*7c478bd9Sstevel@tonic-gate /*....................................................................... 4602*7c478bd9Sstevel@tonic-gate * This is an action function which deletes forward from the cursor up to and 4603*7c478bd9Sstevel@tonic-gate * including a specified character. 4604*7c478bd9Sstevel@tonic-gate */ 4605*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_find) 4606*7c478bd9Sstevel@tonic-gate { 4607*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, '\0', 1, 1, 0); 4608*7c478bd9Sstevel@tonic-gate } 4609*7c478bd9Sstevel@tonic-gate 4610*7c478bd9Sstevel@tonic-gate /*....................................................................... 4611*7c478bd9Sstevel@tonic-gate * This is an action function which deletes backward from the cursor back to 4612*7c478bd9Sstevel@tonic-gate * and including a specified character. 4613*7c478bd9Sstevel@tonic-gate */ 4614*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_find) 4615*7c478bd9Sstevel@tonic-gate { 4616*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, '\0', 0, 1, 0); 4617*7c478bd9Sstevel@tonic-gate } 4618*7c478bd9Sstevel@tonic-gate 4619*7c478bd9Sstevel@tonic-gate /*....................................................................... 4620*7c478bd9Sstevel@tonic-gate * This is an action function which deletes forward from the cursor up to but 4621*7c478bd9Sstevel@tonic-gate * not including a specified character. 4622*7c478bd9Sstevel@tonic-gate */ 4623*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_delete_to) 4624*7c478bd9Sstevel@tonic-gate { 4625*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, '\0', 1, 0, 0); 4626*7c478bd9Sstevel@tonic-gate } 4627*7c478bd9Sstevel@tonic-gate 4628*7c478bd9Sstevel@tonic-gate /*....................................................................... 4629*7c478bd9Sstevel@tonic-gate * This is an action function which deletes backward from the cursor back to 4630*7c478bd9Sstevel@tonic-gate * but not including a specified character. 4631*7c478bd9Sstevel@tonic-gate */ 4632*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_delete_to) 4633*7c478bd9Sstevel@tonic-gate { 4634*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, '\0', 0, 0, 0); 4635*7c478bd9Sstevel@tonic-gate } 4636*7c478bd9Sstevel@tonic-gate 4637*7c478bd9Sstevel@tonic-gate /*....................................................................... 4638*7c478bd9Sstevel@tonic-gate * This is an action function which deletes to a character specified by a 4639*7c478bd9Sstevel@tonic-gate * previous search. 4640*7c478bd9Sstevel@tonic-gate */ 4641*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_refind) 4642*7c478bd9Sstevel@tonic-gate { 4643*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward, 4644*7c478bd9Sstevel@tonic-gate gl->vi.find_onto, 0); 4645*7c478bd9Sstevel@tonic-gate } 4646*7c478bd9Sstevel@tonic-gate 4647*7c478bd9Sstevel@tonic-gate /*....................................................................... 4648*7c478bd9Sstevel@tonic-gate * This is an action function which deletes to a character specified by a 4649*7c478bd9Sstevel@tonic-gate * previous search, but in the opposite direction. 4650*7c478bd9Sstevel@tonic-gate */ 4651*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_delete_invert_refind) 4652*7c478bd9Sstevel@tonic-gate { 4653*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, gl->vi.find_char, 4654*7c478bd9Sstevel@tonic-gate !gl->vi.find_forward, gl->vi.find_onto, 0); 4655*7c478bd9Sstevel@tonic-gate } 4656*7c478bd9Sstevel@tonic-gate 4657*7c478bd9Sstevel@tonic-gate /*....................................................................... 4658*7c478bd9Sstevel@tonic-gate * This is an action function which converts the characters in the word 4659*7c478bd9Sstevel@tonic-gate * following the cursor to upper case. 4660*7c478bd9Sstevel@tonic-gate */ 4661*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_upcase_word) 4662*7c478bd9Sstevel@tonic-gate { 4663*7c478bd9Sstevel@tonic-gate /* 4664*7c478bd9Sstevel@tonic-gate * Locate the count'th word ending after the cursor. 4665*7c478bd9Sstevel@tonic-gate */ 4666*7c478bd9Sstevel@tonic-gate int last = gl_nth_word_end_forward(gl, count); 4667*7c478bd9Sstevel@tonic-gate /* 4668*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4669*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4670*7c478bd9Sstevel@tonic-gate */ 4671*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4672*7c478bd9Sstevel@tonic-gate /* 4673*7c478bd9Sstevel@tonic-gate * Upcase characters from the current cursor position to 'last'. 4674*7c478bd9Sstevel@tonic-gate */ 4675*7c478bd9Sstevel@tonic-gate while(gl->buff_curpos <= last) { 4676*7c478bd9Sstevel@tonic-gate char *cptr = gl->line + gl->buff_curpos; 4677*7c478bd9Sstevel@tonic-gate /* 4678*7c478bd9Sstevel@tonic-gate * Convert the character to upper case? 4679*7c478bd9Sstevel@tonic-gate */ 4680*7c478bd9Sstevel@tonic-gate if(islower((int)(unsigned char) *cptr)) 4681*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, toupper((int) *cptr), gl->buff_curpos); 4682*7c478bd9Sstevel@tonic-gate gl->buff_curpos++; 4683*7c478bd9Sstevel@tonic-gate /* 4684*7c478bd9Sstevel@tonic-gate * Write the possibly modified character back. Note that for non-modified 4685*7c478bd9Sstevel@tonic-gate * characters we want to do this as well, so as to advance the cursor. 4686*7c478bd9Sstevel@tonic-gate */ 4687*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, *cptr, cptr[1])) 4688*7c478bd9Sstevel@tonic-gate return 1; 4689*7c478bd9Sstevel@tonic-gate }; 4690*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */ 4691*7c478bd9Sstevel@tonic-gate } 4692*7c478bd9Sstevel@tonic-gate 4693*7c478bd9Sstevel@tonic-gate /*....................................................................... 4694*7c478bd9Sstevel@tonic-gate * This is an action function which converts the characters in the word 4695*7c478bd9Sstevel@tonic-gate * following the cursor to lower case. 4696*7c478bd9Sstevel@tonic-gate */ 4697*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_downcase_word) 4698*7c478bd9Sstevel@tonic-gate { 4699*7c478bd9Sstevel@tonic-gate /* 4700*7c478bd9Sstevel@tonic-gate * Locate the count'th word ending after the cursor. 4701*7c478bd9Sstevel@tonic-gate */ 4702*7c478bd9Sstevel@tonic-gate int last = gl_nth_word_end_forward(gl, count); 4703*7c478bd9Sstevel@tonic-gate /* 4704*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4705*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4706*7c478bd9Sstevel@tonic-gate */ 4707*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4708*7c478bd9Sstevel@tonic-gate /* 4709*7c478bd9Sstevel@tonic-gate * Upcase characters from the current cursor position to 'last'. 4710*7c478bd9Sstevel@tonic-gate */ 4711*7c478bd9Sstevel@tonic-gate while(gl->buff_curpos <= last) { 4712*7c478bd9Sstevel@tonic-gate char *cptr = gl->line + gl->buff_curpos; 4713*7c478bd9Sstevel@tonic-gate /* 4714*7c478bd9Sstevel@tonic-gate * Convert the character to upper case? 4715*7c478bd9Sstevel@tonic-gate */ 4716*7c478bd9Sstevel@tonic-gate if(isupper((int)(unsigned char) *cptr)) 4717*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, tolower((int) *cptr), gl->buff_curpos); 4718*7c478bd9Sstevel@tonic-gate gl->buff_curpos++; 4719*7c478bd9Sstevel@tonic-gate /* 4720*7c478bd9Sstevel@tonic-gate * Write the possibly modified character back. Note that for non-modified 4721*7c478bd9Sstevel@tonic-gate * characters we want to do this as well, so as to advance the cursor. 4722*7c478bd9Sstevel@tonic-gate */ 4723*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, *cptr, cptr[1])) 4724*7c478bd9Sstevel@tonic-gate return 1; 4725*7c478bd9Sstevel@tonic-gate }; 4726*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */ 4727*7c478bd9Sstevel@tonic-gate } 4728*7c478bd9Sstevel@tonic-gate 4729*7c478bd9Sstevel@tonic-gate /*....................................................................... 4730*7c478bd9Sstevel@tonic-gate * This is an action function which converts the first character of the 4731*7c478bd9Sstevel@tonic-gate * following word to upper case, in order to capitalize the word, and 4732*7c478bd9Sstevel@tonic-gate * leaves the cursor at the end of the word. 4733*7c478bd9Sstevel@tonic-gate */ 4734*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_capitalize_word) 4735*7c478bd9Sstevel@tonic-gate { 4736*7c478bd9Sstevel@tonic-gate char *cptr; /* &gl->line[gl->buff_curpos] */ 4737*7c478bd9Sstevel@tonic-gate int first; /* True for the first letter of the word */ 4738*7c478bd9Sstevel@tonic-gate int i; 4739*7c478bd9Sstevel@tonic-gate /* 4740*7c478bd9Sstevel@tonic-gate * Keep a record of the current insert mode and the cursor position. 4741*7c478bd9Sstevel@tonic-gate */ 4742*7c478bd9Sstevel@tonic-gate int insert = gl->insert; 4743*7c478bd9Sstevel@tonic-gate /* 4744*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4745*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4746*7c478bd9Sstevel@tonic-gate */ 4747*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4748*7c478bd9Sstevel@tonic-gate /* 4749*7c478bd9Sstevel@tonic-gate * We want to overwrite the modified word. 4750*7c478bd9Sstevel@tonic-gate */ 4751*7c478bd9Sstevel@tonic-gate gl->insert = 0; 4752*7c478bd9Sstevel@tonic-gate /* 4753*7c478bd9Sstevel@tonic-gate * Capitalize 'count' words. 4754*7c478bd9Sstevel@tonic-gate */ 4755*7c478bd9Sstevel@tonic-gate for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) { 4756*7c478bd9Sstevel@tonic-gate int pos = gl->buff_curpos; 4757*7c478bd9Sstevel@tonic-gate /* 4758*7c478bd9Sstevel@tonic-gate * If we are not already within a word, skip to the start of the word. 4759*7c478bd9Sstevel@tonic-gate */ 4760*7c478bd9Sstevel@tonic-gate for(cptr = gl->line + pos ; pos<gl->ntotal && !gl_is_word_char((int) *cptr); 4761*7c478bd9Sstevel@tonic-gate pos++, cptr++) 4762*7c478bd9Sstevel@tonic-gate ; 4763*7c478bd9Sstevel@tonic-gate /* 4764*7c478bd9Sstevel@tonic-gate * Move the cursor to the new position. 4765*7c478bd9Sstevel@tonic-gate */ 4766*7c478bd9Sstevel@tonic-gate if(gl_place_cursor(gl, pos)) 4767*7c478bd9Sstevel@tonic-gate return 1; 4768*7c478bd9Sstevel@tonic-gate /* 4769*7c478bd9Sstevel@tonic-gate * While searching for the end of the word, change lower case letters 4770*7c478bd9Sstevel@tonic-gate * to upper case. 4771*7c478bd9Sstevel@tonic-gate */ 4772*7c478bd9Sstevel@tonic-gate for(first=1; gl->buff_curpos<gl->ntotal && gl_is_word_char((int) *cptr); 4773*7c478bd9Sstevel@tonic-gate gl->buff_curpos++, cptr++) { 4774*7c478bd9Sstevel@tonic-gate /* 4775*7c478bd9Sstevel@tonic-gate * Convert the character to upper case? 4776*7c478bd9Sstevel@tonic-gate */ 4777*7c478bd9Sstevel@tonic-gate if(first) { 4778*7c478bd9Sstevel@tonic-gate if(islower((int)(unsigned char) *cptr)) 4779*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line); 4780*7c478bd9Sstevel@tonic-gate } else { 4781*7c478bd9Sstevel@tonic-gate if(isupper((int)(unsigned char) *cptr)) 4782*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line); 4783*7c478bd9Sstevel@tonic-gate }; 4784*7c478bd9Sstevel@tonic-gate first = 0; 4785*7c478bd9Sstevel@tonic-gate /* 4786*7c478bd9Sstevel@tonic-gate * Write the possibly modified character back. Note that for non-modified 4787*7c478bd9Sstevel@tonic-gate * characters we want to do this as well, so as to advance the cursor. 4788*7c478bd9Sstevel@tonic-gate */ 4789*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, *cptr, cptr[1])) 4790*7c478bd9Sstevel@tonic-gate return 1; 4791*7c478bd9Sstevel@tonic-gate }; 4792*7c478bd9Sstevel@tonic-gate }; 4793*7c478bd9Sstevel@tonic-gate /* 4794*7c478bd9Sstevel@tonic-gate * Restore the insertion mode. 4795*7c478bd9Sstevel@tonic-gate */ 4796*7c478bd9Sstevel@tonic-gate gl->insert = insert; 4797*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */ 4798*7c478bd9Sstevel@tonic-gate } 4799*7c478bd9Sstevel@tonic-gate 4800*7c478bd9Sstevel@tonic-gate /*....................................................................... 4801*7c478bd9Sstevel@tonic-gate * This is an action function which redraws the current line. 4802*7c478bd9Sstevel@tonic-gate */ 4803*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_redisplay) 4804*7c478bd9Sstevel@tonic-gate { 4805*7c478bd9Sstevel@tonic-gate /* 4806*7c478bd9Sstevel@tonic-gate * Keep a record of the current cursor position. 4807*7c478bd9Sstevel@tonic-gate */ 4808*7c478bd9Sstevel@tonic-gate int buff_curpos = gl->buff_curpos; 4809*7c478bd9Sstevel@tonic-gate /* 4810*7c478bd9Sstevel@tonic-gate * Do nothing if there is no line to be redisplayed. 4811*7c478bd9Sstevel@tonic-gate */ 4812*7c478bd9Sstevel@tonic-gate if(gl->endline) 4813*7c478bd9Sstevel@tonic-gate return 0; 4814*7c478bd9Sstevel@tonic-gate /* 4815*7c478bd9Sstevel@tonic-gate * Erase the current input line. 4816*7c478bd9Sstevel@tonic-gate */ 4817*7c478bd9Sstevel@tonic-gate if(gl_erase_line(gl)) 4818*7c478bd9Sstevel@tonic-gate return 1; 4819*7c478bd9Sstevel@tonic-gate /* 4820*7c478bd9Sstevel@tonic-gate * Display the current prompt. 4821*7c478bd9Sstevel@tonic-gate */ 4822*7c478bd9Sstevel@tonic-gate if(gl_display_prompt(gl)) 4823*7c478bd9Sstevel@tonic-gate return 1; 4824*7c478bd9Sstevel@tonic-gate /* 4825*7c478bd9Sstevel@tonic-gate * Render the part of the line that the user has typed in so far. 4826*7c478bd9Sstevel@tonic-gate */ 4827*7c478bd9Sstevel@tonic-gate if(gl_print_string(gl, gl->line, '\0')) 4828*7c478bd9Sstevel@tonic-gate return 1; 4829*7c478bd9Sstevel@tonic-gate /* 4830*7c478bd9Sstevel@tonic-gate * Restore the cursor position. 4831*7c478bd9Sstevel@tonic-gate */ 4832*7c478bd9Sstevel@tonic-gate if(gl_place_cursor(gl, buff_curpos)) 4833*7c478bd9Sstevel@tonic-gate return 1; 4834*7c478bd9Sstevel@tonic-gate /* 4835*7c478bd9Sstevel@tonic-gate * Mark the redisplay operation as having been completed. 4836*7c478bd9Sstevel@tonic-gate */ 4837*7c478bd9Sstevel@tonic-gate gl->redisplay = 0; 4838*7c478bd9Sstevel@tonic-gate /* 4839*7c478bd9Sstevel@tonic-gate * Flush the redisplayed line to the terminal. 4840*7c478bd9Sstevel@tonic-gate */ 4841*7c478bd9Sstevel@tonic-gate return gl_flush_output(gl); 4842*7c478bd9Sstevel@tonic-gate } 4843*7c478bd9Sstevel@tonic-gate 4844*7c478bd9Sstevel@tonic-gate /*....................................................................... 4845*7c478bd9Sstevel@tonic-gate * This is an action function which clears the display and redraws the 4846*7c478bd9Sstevel@tonic-gate * input line from the home position. 4847*7c478bd9Sstevel@tonic-gate */ 4848*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_clear_screen) 4849*7c478bd9Sstevel@tonic-gate { 4850*7c478bd9Sstevel@tonic-gate /* 4851*7c478bd9Sstevel@tonic-gate * Home the cursor and clear from there to the end of the display. 4852*7c478bd9Sstevel@tonic-gate */ 4853*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, gl->nline, gl->home) || 4854*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, gl->nline, gl->clear_eod)) 4855*7c478bd9Sstevel@tonic-gate return 1; 4856*7c478bd9Sstevel@tonic-gate /* 4857*7c478bd9Sstevel@tonic-gate * The input line is no longer displayed. 4858*7c478bd9Sstevel@tonic-gate */ 4859*7c478bd9Sstevel@tonic-gate gl_line_erased(gl); 4860*7c478bd9Sstevel@tonic-gate /* 4861*7c478bd9Sstevel@tonic-gate * Arrange for the input line to be redisplayed. 4862*7c478bd9Sstevel@tonic-gate */ 4863*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 4864*7c478bd9Sstevel@tonic-gate return 0; 4865*7c478bd9Sstevel@tonic-gate } 4866*7c478bd9Sstevel@tonic-gate 4867*7c478bd9Sstevel@tonic-gate /*....................................................................... 4868*7c478bd9Sstevel@tonic-gate * This is an action function which swaps the character under the cursor 4869*7c478bd9Sstevel@tonic-gate * with the character to the left of the cursor. 4870*7c478bd9Sstevel@tonic-gate */ 4871*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_transpose_chars) 4872*7c478bd9Sstevel@tonic-gate { 4873*7c478bd9Sstevel@tonic-gate char from[3]; /* The original string of 2 characters */ 4874*7c478bd9Sstevel@tonic-gate char swap[3]; /* The swapped string of two characters */ 4875*7c478bd9Sstevel@tonic-gate /* 4876*7c478bd9Sstevel@tonic-gate * If we are at the beginning or end of the line, there aren't two 4877*7c478bd9Sstevel@tonic-gate * characters to swap. 4878*7c478bd9Sstevel@tonic-gate */ 4879*7c478bd9Sstevel@tonic-gate if(gl->buff_curpos < 1 || gl->buff_curpos >= gl->ntotal) 4880*7c478bd9Sstevel@tonic-gate return 0; 4881*7c478bd9Sstevel@tonic-gate /* 4882*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4883*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4884*7c478bd9Sstevel@tonic-gate */ 4885*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4886*7c478bd9Sstevel@tonic-gate /* 4887*7c478bd9Sstevel@tonic-gate * Get the original and swapped strings of the two characters. 4888*7c478bd9Sstevel@tonic-gate */ 4889*7c478bd9Sstevel@tonic-gate from[0] = gl->line[gl->buff_curpos - 1]; 4890*7c478bd9Sstevel@tonic-gate from[1] = gl->line[gl->buff_curpos]; 4891*7c478bd9Sstevel@tonic-gate from[2] = '\0'; 4892*7c478bd9Sstevel@tonic-gate swap[0] = gl->line[gl->buff_curpos]; 4893*7c478bd9Sstevel@tonic-gate swap[1] = gl->line[gl->buff_curpos - 1]; 4894*7c478bd9Sstevel@tonic-gate swap[2] = '\0'; 4895*7c478bd9Sstevel@tonic-gate /* 4896*7c478bd9Sstevel@tonic-gate * Move the cursor to the start of the two characters. 4897*7c478bd9Sstevel@tonic-gate */ 4898*7c478bd9Sstevel@tonic-gate if(gl_place_cursor(gl, gl->buff_curpos-1)) 4899*7c478bd9Sstevel@tonic-gate return 1; 4900*7c478bd9Sstevel@tonic-gate /* 4901*7c478bd9Sstevel@tonic-gate * Swap the two characters in the buffer. 4902*7c478bd9Sstevel@tonic-gate */ 4903*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, swap[0], gl->buff_curpos); 4904*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, swap[1], gl->buff_curpos+1); 4905*7c478bd9Sstevel@tonic-gate /* 4906*7c478bd9Sstevel@tonic-gate * If the sum of the displayed width of the two characters 4907*7c478bd9Sstevel@tonic-gate * in their current and final positions is the same, swapping can 4908*7c478bd9Sstevel@tonic-gate * be done by just overwriting with the two swapped characters. 4909*7c478bd9Sstevel@tonic-gate */ 4910*7c478bd9Sstevel@tonic-gate if(gl_displayed_string_width(gl, from, -1, gl->term_curpos) == 4911*7c478bd9Sstevel@tonic-gate gl_displayed_string_width(gl, swap, -1, gl->term_curpos)) { 4912*7c478bd9Sstevel@tonic-gate int insert = gl->insert; 4913*7c478bd9Sstevel@tonic-gate gl->insert = 0; 4914*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, swap[0], swap[1]) || 4915*7c478bd9Sstevel@tonic-gate gl_print_char(gl, swap[1], gl->line[gl->buff_curpos+2])) 4916*7c478bd9Sstevel@tonic-gate return 1; 4917*7c478bd9Sstevel@tonic-gate gl->insert = insert; 4918*7c478bd9Sstevel@tonic-gate /* 4919*7c478bd9Sstevel@tonic-gate * If the swapped substring has a different displayed size, we need to 4920*7c478bd9Sstevel@tonic-gate * redraw everything after the first of the characters. 4921*7c478bd9Sstevel@tonic-gate */ 4922*7c478bd9Sstevel@tonic-gate } else { 4923*7c478bd9Sstevel@tonic-gate if(gl_print_string(gl, gl->line + gl->buff_curpos, '\0') || 4924*7c478bd9Sstevel@tonic-gate gl_truncate_display(gl)) 4925*7c478bd9Sstevel@tonic-gate return 1; 4926*7c478bd9Sstevel@tonic-gate }; 4927*7c478bd9Sstevel@tonic-gate /* 4928*7c478bd9Sstevel@tonic-gate * Advance the cursor to the character after the swapped pair. 4929*7c478bd9Sstevel@tonic-gate */ 4930*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos + 2); 4931*7c478bd9Sstevel@tonic-gate } 4932*7c478bd9Sstevel@tonic-gate 4933*7c478bd9Sstevel@tonic-gate /*....................................................................... 4934*7c478bd9Sstevel@tonic-gate * This is an action function which sets a mark at the current cursor 4935*7c478bd9Sstevel@tonic-gate * location. 4936*7c478bd9Sstevel@tonic-gate */ 4937*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_set_mark) 4938*7c478bd9Sstevel@tonic-gate { 4939*7c478bd9Sstevel@tonic-gate gl->buff_mark = gl->buff_curpos; 4940*7c478bd9Sstevel@tonic-gate return 0; 4941*7c478bd9Sstevel@tonic-gate } 4942*7c478bd9Sstevel@tonic-gate 4943*7c478bd9Sstevel@tonic-gate /*....................................................................... 4944*7c478bd9Sstevel@tonic-gate * This is an action function which swaps the mark location for the 4945*7c478bd9Sstevel@tonic-gate * cursor location. 4946*7c478bd9Sstevel@tonic-gate */ 4947*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_exchange_point_and_mark) 4948*7c478bd9Sstevel@tonic-gate { 4949*7c478bd9Sstevel@tonic-gate /* 4950*7c478bd9Sstevel@tonic-gate * Get the old mark position, and limit to the extent of the input 4951*7c478bd9Sstevel@tonic-gate * line. 4952*7c478bd9Sstevel@tonic-gate */ 4953*7c478bd9Sstevel@tonic-gate int old_mark = gl->buff_mark <= gl->ntotal ? gl->buff_mark : gl->ntotal; 4954*7c478bd9Sstevel@tonic-gate /* 4955*7c478bd9Sstevel@tonic-gate * Make the current cursor position the new mark. 4956*7c478bd9Sstevel@tonic-gate */ 4957*7c478bd9Sstevel@tonic-gate gl->buff_mark = gl->buff_curpos; 4958*7c478bd9Sstevel@tonic-gate /* 4959*7c478bd9Sstevel@tonic-gate * Move the cursor to the old mark position. 4960*7c478bd9Sstevel@tonic-gate */ 4961*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, old_mark); 4962*7c478bd9Sstevel@tonic-gate } 4963*7c478bd9Sstevel@tonic-gate 4964*7c478bd9Sstevel@tonic-gate /*....................................................................... 4965*7c478bd9Sstevel@tonic-gate * This is an action function which deletes the characters between the 4966*7c478bd9Sstevel@tonic-gate * mark and the cursor, recording them in gl->cutbuf for later pasting. 4967*7c478bd9Sstevel@tonic-gate */ 4968*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_kill_region) 4969*7c478bd9Sstevel@tonic-gate { 4970*7c478bd9Sstevel@tonic-gate /* 4971*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 4972*7c478bd9Sstevel@tonic-gate * use by vi-undo. 4973*7c478bd9Sstevel@tonic-gate */ 4974*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 4975*7c478bd9Sstevel@tonic-gate /* 4976*7c478bd9Sstevel@tonic-gate * Limit the mark to be within the line. 4977*7c478bd9Sstevel@tonic-gate */ 4978*7c478bd9Sstevel@tonic-gate if(gl->buff_mark > gl->ntotal) 4979*7c478bd9Sstevel@tonic-gate gl->buff_mark = gl->ntotal; 4980*7c478bd9Sstevel@tonic-gate /* 4981*7c478bd9Sstevel@tonic-gate * If there are no characters between the cursor and the mark, simply clear 4982*7c478bd9Sstevel@tonic-gate * the cut buffer. 4983*7c478bd9Sstevel@tonic-gate */ 4984*7c478bd9Sstevel@tonic-gate if(gl->buff_mark == gl->buff_curpos) { 4985*7c478bd9Sstevel@tonic-gate gl->cutbuf[0] = '\0'; 4986*7c478bd9Sstevel@tonic-gate return 0; 4987*7c478bd9Sstevel@tonic-gate }; 4988*7c478bd9Sstevel@tonic-gate /* 4989*7c478bd9Sstevel@tonic-gate * If the mark is before the cursor, swap the cursor and the mark. 4990*7c478bd9Sstevel@tonic-gate */ 4991*7c478bd9Sstevel@tonic-gate if(gl->buff_mark < gl->buff_curpos && gl_exchange_point_and_mark(gl,1,NULL)) 4992*7c478bd9Sstevel@tonic-gate return 1; 4993*7c478bd9Sstevel@tonic-gate /* 4994*7c478bd9Sstevel@tonic-gate * Delete the characters. 4995*7c478bd9Sstevel@tonic-gate */ 4996*7c478bd9Sstevel@tonic-gate if(gl_delete_chars(gl, gl->buff_mark - gl->buff_curpos, 1)) 4997*7c478bd9Sstevel@tonic-gate return 1; 4998*7c478bd9Sstevel@tonic-gate /* 4999*7c478bd9Sstevel@tonic-gate * Make the mark the same as the cursor position. 5000*7c478bd9Sstevel@tonic-gate */ 5001*7c478bd9Sstevel@tonic-gate gl->buff_mark = gl->buff_curpos; 5002*7c478bd9Sstevel@tonic-gate return 0; 5003*7c478bd9Sstevel@tonic-gate } 5004*7c478bd9Sstevel@tonic-gate 5005*7c478bd9Sstevel@tonic-gate /*....................................................................... 5006*7c478bd9Sstevel@tonic-gate * This is an action function which records the characters between the 5007*7c478bd9Sstevel@tonic-gate * mark and the cursor, in gl->cutbuf for later pasting. 5008*7c478bd9Sstevel@tonic-gate */ 5009*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_region_as_kill) 5010*7c478bd9Sstevel@tonic-gate { 5011*7c478bd9Sstevel@tonic-gate int ca, cb; /* The indexes of the first and last characters in the region */ 5012*7c478bd9Sstevel@tonic-gate int mark; /* The position of the mark */ 5013*7c478bd9Sstevel@tonic-gate /* 5014*7c478bd9Sstevel@tonic-gate * Get the position of the mark, limiting it to lie within the line. 5015*7c478bd9Sstevel@tonic-gate */ 5016*7c478bd9Sstevel@tonic-gate mark = gl->buff_mark > gl->ntotal ? gl->ntotal : gl->buff_mark; 5017*7c478bd9Sstevel@tonic-gate /* 5018*7c478bd9Sstevel@tonic-gate * If there are no characters between the cursor and the mark, clear 5019*7c478bd9Sstevel@tonic-gate * the cut buffer. 5020*7c478bd9Sstevel@tonic-gate */ 5021*7c478bd9Sstevel@tonic-gate if(mark == gl->buff_curpos) { 5022*7c478bd9Sstevel@tonic-gate gl->cutbuf[0] = '\0'; 5023*7c478bd9Sstevel@tonic-gate return 0; 5024*7c478bd9Sstevel@tonic-gate }; 5025*7c478bd9Sstevel@tonic-gate /* 5026*7c478bd9Sstevel@tonic-gate * Get the line indexes of the first and last characters in the region. 5027*7c478bd9Sstevel@tonic-gate */ 5028*7c478bd9Sstevel@tonic-gate if(mark < gl->buff_curpos) { 5029*7c478bd9Sstevel@tonic-gate ca = mark; 5030*7c478bd9Sstevel@tonic-gate cb = gl->buff_curpos - 1; 5031*7c478bd9Sstevel@tonic-gate } else { 5032*7c478bd9Sstevel@tonic-gate ca = gl->buff_curpos; 5033*7c478bd9Sstevel@tonic-gate cb = mark - 1; 5034*7c478bd9Sstevel@tonic-gate }; 5035*7c478bd9Sstevel@tonic-gate /* 5036*7c478bd9Sstevel@tonic-gate * Copy the region to the cut buffer. 5037*7c478bd9Sstevel@tonic-gate */ 5038*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + ca, cb + 1 - ca); 5039*7c478bd9Sstevel@tonic-gate gl->cutbuf[cb + 1 - ca] = '\0'; 5040*7c478bd9Sstevel@tonic-gate return 0; 5041*7c478bd9Sstevel@tonic-gate } 5042*7c478bd9Sstevel@tonic-gate 5043*7c478bd9Sstevel@tonic-gate /*....................................................................... 5044*7c478bd9Sstevel@tonic-gate * This is an action function which inserts the contents of the cut 5045*7c478bd9Sstevel@tonic-gate * buffer at the current cursor location. 5046*7c478bd9Sstevel@tonic-gate */ 5047*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_yank) 5048*7c478bd9Sstevel@tonic-gate { 5049*7c478bd9Sstevel@tonic-gate int i; 5050*7c478bd9Sstevel@tonic-gate /* 5051*7c478bd9Sstevel@tonic-gate * Set the mark at the current location. 5052*7c478bd9Sstevel@tonic-gate */ 5053*7c478bd9Sstevel@tonic-gate gl->buff_mark = gl->buff_curpos; 5054*7c478bd9Sstevel@tonic-gate /* 5055*7c478bd9Sstevel@tonic-gate * Do nothing else if the cut buffer is empty. 5056*7c478bd9Sstevel@tonic-gate */ 5057*7c478bd9Sstevel@tonic-gate if(gl->cutbuf[0] == '\0') 5058*7c478bd9Sstevel@tonic-gate return gl_ring_bell(gl, 1, NULL); 5059*7c478bd9Sstevel@tonic-gate /* 5060*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 5061*7c478bd9Sstevel@tonic-gate * use by vi-undo. 5062*7c478bd9Sstevel@tonic-gate */ 5063*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 5064*7c478bd9Sstevel@tonic-gate /* 5065*7c478bd9Sstevel@tonic-gate * Insert the string count times. 5066*7c478bd9Sstevel@tonic-gate */ 5067*7c478bd9Sstevel@tonic-gate for(i=0; i<count; i++) { 5068*7c478bd9Sstevel@tonic-gate if(gl_add_string_to_line(gl, gl->cutbuf)) 5069*7c478bd9Sstevel@tonic-gate return 1; 5070*7c478bd9Sstevel@tonic-gate }; 5071*7c478bd9Sstevel@tonic-gate /* 5072*7c478bd9Sstevel@tonic-gate * gl_add_string_to_line() leaves the cursor after the last character that 5073*7c478bd9Sstevel@tonic-gate * was pasted, whereas vi leaves the cursor over the last character pasted. 5074*7c478bd9Sstevel@tonic-gate */ 5075*7c478bd9Sstevel@tonic-gate if(gl->editor == GL_VI_MODE && gl_cursor_left(gl, 1, NULL)) 5076*7c478bd9Sstevel@tonic-gate return 1; 5077*7c478bd9Sstevel@tonic-gate return 0; 5078*7c478bd9Sstevel@tonic-gate } 5079*7c478bd9Sstevel@tonic-gate 5080*7c478bd9Sstevel@tonic-gate /*....................................................................... 5081*7c478bd9Sstevel@tonic-gate * This is an action function which inserts the contents of the cut 5082*7c478bd9Sstevel@tonic-gate * buffer one character beyond the current cursor location. 5083*7c478bd9Sstevel@tonic-gate */ 5084*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_append_yank) 5085*7c478bd9Sstevel@tonic-gate { 5086*7c478bd9Sstevel@tonic-gate int was_command = gl->vi.command; 5087*7c478bd9Sstevel@tonic-gate int i; 5088*7c478bd9Sstevel@tonic-gate /* 5089*7c478bd9Sstevel@tonic-gate * If the cut buffer is empty, ring the terminal bell. 5090*7c478bd9Sstevel@tonic-gate */ 5091*7c478bd9Sstevel@tonic-gate if(gl->cutbuf[0] == '\0') 5092*7c478bd9Sstevel@tonic-gate return gl_ring_bell(gl, 1, NULL); 5093*7c478bd9Sstevel@tonic-gate /* 5094*7c478bd9Sstevel@tonic-gate * Set the mark at the current location + 1. 5095*7c478bd9Sstevel@tonic-gate */ 5096*7c478bd9Sstevel@tonic-gate gl->buff_mark = gl->buff_curpos + 1; 5097*7c478bd9Sstevel@tonic-gate /* 5098*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 5099*7c478bd9Sstevel@tonic-gate * use by vi-undo. 5100*7c478bd9Sstevel@tonic-gate */ 5101*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 5102*7c478bd9Sstevel@tonic-gate /* 5103*7c478bd9Sstevel@tonic-gate * Arrange to paste the text in insert mode after the current character. 5104*7c478bd9Sstevel@tonic-gate */ 5105*7c478bd9Sstevel@tonic-gate if(gl_vi_append(gl, 0, NULL)) 5106*7c478bd9Sstevel@tonic-gate return 1; 5107*7c478bd9Sstevel@tonic-gate /* 5108*7c478bd9Sstevel@tonic-gate * Insert the string count times. 5109*7c478bd9Sstevel@tonic-gate */ 5110*7c478bd9Sstevel@tonic-gate for(i=0; i<count; i++) { 5111*7c478bd9Sstevel@tonic-gate if(gl_add_string_to_line(gl, gl->cutbuf)) 5112*7c478bd9Sstevel@tonic-gate return 1; 5113*7c478bd9Sstevel@tonic-gate }; 5114*7c478bd9Sstevel@tonic-gate /* 5115*7c478bd9Sstevel@tonic-gate * Switch back to command mode if necessary. 5116*7c478bd9Sstevel@tonic-gate */ 5117*7c478bd9Sstevel@tonic-gate if(was_command) 5118*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 5119*7c478bd9Sstevel@tonic-gate return 0; 5120*7c478bd9Sstevel@tonic-gate } 5121*7c478bd9Sstevel@tonic-gate 5122*7c478bd9Sstevel@tonic-gate /*....................................................................... 5123*7c478bd9Sstevel@tonic-gate * Attempt to ask the terminal for its current size. On systems that 5124*7c478bd9Sstevel@tonic-gate * don't support the TIOCWINSZ ioctl() for querying the terminal size, 5125*7c478bd9Sstevel@tonic-gate * the current values of gl->ncolumn and gl->nrow are returned. 5126*7c478bd9Sstevel@tonic-gate * 5127*7c478bd9Sstevel@tonic-gate * Input: 5128*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 5129*7c478bd9Sstevel@tonic-gate * Input/Output: 5130*7c478bd9Sstevel@tonic-gate * ncolumn int * The number of columns will be assigned to *ncolumn. 5131*7c478bd9Sstevel@tonic-gate * nline int * The number of lines will be assigned to *nline. 5132*7c478bd9Sstevel@tonic-gate */ 5133*7c478bd9Sstevel@tonic-gate static void gl_query_size(GetLine *gl, int *ncolumn, int *nline) 5134*7c478bd9Sstevel@tonic-gate { 5135*7c478bd9Sstevel@tonic-gate #ifdef TIOCGWINSZ 5136*7c478bd9Sstevel@tonic-gate /* 5137*7c478bd9Sstevel@tonic-gate * Query the new terminal window size. Ignore invalid responses. 5138*7c478bd9Sstevel@tonic-gate */ 5139*7c478bd9Sstevel@tonic-gate struct winsize size; 5140*7c478bd9Sstevel@tonic-gate if(ioctl(gl->output_fd, TIOCGWINSZ, &size) == 0 && 5141*7c478bd9Sstevel@tonic-gate size.ws_row > 0 && size.ws_col > 0) { 5142*7c478bd9Sstevel@tonic-gate *ncolumn = size.ws_col; 5143*7c478bd9Sstevel@tonic-gate *nline = size.ws_row; 5144*7c478bd9Sstevel@tonic-gate return; 5145*7c478bd9Sstevel@tonic-gate }; 5146*7c478bd9Sstevel@tonic-gate #endif 5147*7c478bd9Sstevel@tonic-gate /* 5148*7c478bd9Sstevel@tonic-gate * Return the existing values. 5149*7c478bd9Sstevel@tonic-gate */ 5150*7c478bd9Sstevel@tonic-gate *ncolumn = gl->ncolumn; 5151*7c478bd9Sstevel@tonic-gate *nline = gl->nline; 5152*7c478bd9Sstevel@tonic-gate return; 5153*7c478bd9Sstevel@tonic-gate } 5154*7c478bd9Sstevel@tonic-gate 5155*7c478bd9Sstevel@tonic-gate /*....................................................................... 5156*7c478bd9Sstevel@tonic-gate * Query the size of the terminal, and if it has changed, redraw the 5157*7c478bd9Sstevel@tonic-gate * current input line accordingly. 5158*7c478bd9Sstevel@tonic-gate * 5159*7c478bd9Sstevel@tonic-gate * Input: 5160*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 5161*7c478bd9Sstevel@tonic-gate * Output: 5162*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 5163*7c478bd9Sstevel@tonic-gate * 1 - Error. 5164*7c478bd9Sstevel@tonic-gate */ 5165*7c478bd9Sstevel@tonic-gate static int _gl_update_size(GetLine *gl) 5166*7c478bd9Sstevel@tonic-gate { 5167*7c478bd9Sstevel@tonic-gate int ncolumn, nline; /* The new size of the terminal */ 5168*7c478bd9Sstevel@tonic-gate /* 5169*7c478bd9Sstevel@tonic-gate * Query the new terminal window size. 5170*7c478bd9Sstevel@tonic-gate */ 5171*7c478bd9Sstevel@tonic-gate gl_query_size(gl, &ncolumn, &nline); 5172*7c478bd9Sstevel@tonic-gate /* 5173*7c478bd9Sstevel@tonic-gate * Update gl and the displayed line to fit the new dimensions. 5174*7c478bd9Sstevel@tonic-gate */ 5175*7c478bd9Sstevel@tonic-gate return gl_handle_tty_resize(gl, ncolumn, nline); 5176*7c478bd9Sstevel@tonic-gate } 5177*7c478bd9Sstevel@tonic-gate 5178*7c478bd9Sstevel@tonic-gate /*....................................................................... 5179*7c478bd9Sstevel@tonic-gate * Redraw the current input line to account for a change in the terminal 5180*7c478bd9Sstevel@tonic-gate * size. Also install the new size in gl. 5181*7c478bd9Sstevel@tonic-gate * 5182*7c478bd9Sstevel@tonic-gate * Input: 5183*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 5184*7c478bd9Sstevel@tonic-gate * ncolumn int The new number of columns. 5185*7c478bd9Sstevel@tonic-gate * nline int The new number of lines. 5186*7c478bd9Sstevel@tonic-gate * Output: 5187*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 5188*7c478bd9Sstevel@tonic-gate * 1 - Error. 5189*7c478bd9Sstevel@tonic-gate */ 5190*7c478bd9Sstevel@tonic-gate static int gl_handle_tty_resize(GetLine *gl, int ncolumn, int nline) 5191*7c478bd9Sstevel@tonic-gate { 5192*7c478bd9Sstevel@tonic-gate /* 5193*7c478bd9Sstevel@tonic-gate * If the input device isn't a terminal, just record the new size. 5194*7c478bd9Sstevel@tonic-gate */ 5195*7c478bd9Sstevel@tonic-gate if(!gl->is_term) { 5196*7c478bd9Sstevel@tonic-gate gl->nline = nline; 5197*7c478bd9Sstevel@tonic-gate gl->ncolumn = ncolumn; 5198*7c478bd9Sstevel@tonic-gate /* 5199*7c478bd9Sstevel@tonic-gate * Has the size actually changed? 5200*7c478bd9Sstevel@tonic-gate */ 5201*7c478bd9Sstevel@tonic-gate } else if(ncolumn != gl->ncolumn || nline != gl->nline) { 5202*7c478bd9Sstevel@tonic-gate /* 5203*7c478bd9Sstevel@tonic-gate * If we are currently editing a line, erase it. 5204*7c478bd9Sstevel@tonic-gate */ 5205*7c478bd9Sstevel@tonic-gate if(gl_erase_line(gl)) 5206*7c478bd9Sstevel@tonic-gate return 1; 5207*7c478bd9Sstevel@tonic-gate /* 5208*7c478bd9Sstevel@tonic-gate * Update the recorded window size. 5209*7c478bd9Sstevel@tonic-gate */ 5210*7c478bd9Sstevel@tonic-gate gl->nline = nline; 5211*7c478bd9Sstevel@tonic-gate gl->ncolumn = ncolumn; 5212*7c478bd9Sstevel@tonic-gate /* 5213*7c478bd9Sstevel@tonic-gate * Arrange for the input line to be redrawn before the next character 5214*7c478bd9Sstevel@tonic-gate * is read from the terminal. 5215*7c478bd9Sstevel@tonic-gate */ 5216*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 5217*7c478bd9Sstevel@tonic-gate }; 5218*7c478bd9Sstevel@tonic-gate return 0; 5219*7c478bd9Sstevel@tonic-gate } 5220*7c478bd9Sstevel@tonic-gate 5221*7c478bd9Sstevel@tonic-gate /*....................................................................... 5222*7c478bd9Sstevel@tonic-gate * This is the action function that recalls the previous line in the 5223*7c478bd9Sstevel@tonic-gate * history buffer. 5224*7c478bd9Sstevel@tonic-gate */ 5225*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_up_history) 5226*7c478bd9Sstevel@tonic-gate { 5227*7c478bd9Sstevel@tonic-gate /* 5228*7c478bd9Sstevel@tonic-gate * In vi mode, switch to command mode, since the user is very 5229*7c478bd9Sstevel@tonic-gate * likely to want to move around newly recalled lines. 5230*7c478bd9Sstevel@tonic-gate */ 5231*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 5232*7c478bd9Sstevel@tonic-gate /* 5233*7c478bd9Sstevel@tonic-gate * Forget any previous recall session. 5234*7c478bd9Sstevel@tonic-gate */ 5235*7c478bd9Sstevel@tonic-gate gl->preload_id = 0; 5236*7c478bd9Sstevel@tonic-gate /* 5237*7c478bd9Sstevel@tonic-gate * Record the key sequence number of this search action. 5238*7c478bd9Sstevel@tonic-gate */ 5239*7c478bd9Sstevel@tonic-gate gl->last_search = gl->keyseq_count; 5240*7c478bd9Sstevel@tonic-gate /* 5241*7c478bd9Sstevel@tonic-gate * We don't want a search prefix for this function. 5242*7c478bd9Sstevel@tonic-gate */ 5243*7c478bd9Sstevel@tonic-gate if(_glh_search_prefix(gl->glh, gl->line, 0)) { 5244*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 5245*7c478bd9Sstevel@tonic-gate return 1; 5246*7c478bd9Sstevel@tonic-gate }; 5247*7c478bd9Sstevel@tonic-gate /* 5248*7c478bd9Sstevel@tonic-gate * Recall the count'th next older line in the history list. If the first one 5249*7c478bd9Sstevel@tonic-gate * fails we can return since nothing has changed, otherwise we must continue 5250*7c478bd9Sstevel@tonic-gate * and update the line state. 5251*7c478bd9Sstevel@tonic-gate */ 5252*7c478bd9Sstevel@tonic-gate if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL) 5253*7c478bd9Sstevel@tonic-gate return 0; 5254*7c478bd9Sstevel@tonic-gate while(--count && _glh_find_backwards(gl->glh, gl->line, gl->linelen+1)) 5255*7c478bd9Sstevel@tonic-gate ; 5256*7c478bd9Sstevel@tonic-gate /* 5257*7c478bd9Sstevel@tonic-gate * Accomodate the new contents of gl->line[]. 5258*7c478bd9Sstevel@tonic-gate */ 5259*7c478bd9Sstevel@tonic-gate gl_update_buffer(gl); 5260*7c478bd9Sstevel@tonic-gate /* 5261*7c478bd9Sstevel@tonic-gate * Arrange to have the cursor placed at the end of the new line. 5262*7c478bd9Sstevel@tonic-gate */ 5263*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->ntotal; 5264*7c478bd9Sstevel@tonic-gate /* 5265*7c478bd9Sstevel@tonic-gate * Erase and display the new line. 5266*7c478bd9Sstevel@tonic-gate */ 5267*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 5268*7c478bd9Sstevel@tonic-gate return 0; 5269*7c478bd9Sstevel@tonic-gate } 5270*7c478bd9Sstevel@tonic-gate 5271*7c478bd9Sstevel@tonic-gate /*....................................................................... 5272*7c478bd9Sstevel@tonic-gate * This is the action function that recalls the next line in the 5273*7c478bd9Sstevel@tonic-gate * history buffer. 5274*7c478bd9Sstevel@tonic-gate */ 5275*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_down_history) 5276*7c478bd9Sstevel@tonic-gate { 5277*7c478bd9Sstevel@tonic-gate /* 5278*7c478bd9Sstevel@tonic-gate * In vi mode, switch to command mode, since the user is very 5279*7c478bd9Sstevel@tonic-gate * likely to want to move around newly recalled lines. 5280*7c478bd9Sstevel@tonic-gate */ 5281*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 5282*7c478bd9Sstevel@tonic-gate /* 5283*7c478bd9Sstevel@tonic-gate * Record the key sequence number of this search action. 5284*7c478bd9Sstevel@tonic-gate */ 5285*7c478bd9Sstevel@tonic-gate gl->last_search = gl->keyseq_count; 5286*7c478bd9Sstevel@tonic-gate /* 5287*7c478bd9Sstevel@tonic-gate * If no search is currently in progress continue a previous recall 5288*7c478bd9Sstevel@tonic-gate * session from a previous entered line if possible. 5289*7c478bd9Sstevel@tonic-gate */ 5290*7c478bd9Sstevel@tonic-gate if(_glh_line_id(gl->glh, 0) == 0 && gl->preload_id) { 5291*7c478bd9Sstevel@tonic-gate _glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1); 5292*7c478bd9Sstevel@tonic-gate gl->preload_id = 0; 5293*7c478bd9Sstevel@tonic-gate } else { 5294*7c478bd9Sstevel@tonic-gate /* 5295*7c478bd9Sstevel@tonic-gate * We don't want a search prefix for this function. 5296*7c478bd9Sstevel@tonic-gate */ 5297*7c478bd9Sstevel@tonic-gate if(_glh_search_prefix(gl->glh, gl->line, 0)) { 5298*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 5299*7c478bd9Sstevel@tonic-gate return 1; 5300*7c478bd9Sstevel@tonic-gate }; 5301*7c478bd9Sstevel@tonic-gate /* 5302*7c478bd9Sstevel@tonic-gate * Recall the count'th next newer line in the history list. If the first one 5303*7c478bd9Sstevel@tonic-gate * fails we can return since nothing has changed otherwise we must continue 5304*7c478bd9Sstevel@tonic-gate * and update the line state. 5305*7c478bd9Sstevel@tonic-gate */ 5306*7c478bd9Sstevel@tonic-gate if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL) 5307*7c478bd9Sstevel@tonic-gate return 0; 5308*7c478bd9Sstevel@tonic-gate while(--count && _glh_find_forwards(gl->glh, gl->line, gl->linelen+1)) 5309*7c478bd9Sstevel@tonic-gate ; 5310*7c478bd9Sstevel@tonic-gate }; 5311*7c478bd9Sstevel@tonic-gate /* 5312*7c478bd9Sstevel@tonic-gate * Accomodate the new contents of gl->line[]. 5313*7c478bd9Sstevel@tonic-gate */ 5314*7c478bd9Sstevel@tonic-gate gl_update_buffer(gl); 5315*7c478bd9Sstevel@tonic-gate /* 5316*7c478bd9Sstevel@tonic-gate * Arrange to have the cursor placed at the end of the new line. 5317*7c478bd9Sstevel@tonic-gate */ 5318*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->ntotal; 5319*7c478bd9Sstevel@tonic-gate /* 5320*7c478bd9Sstevel@tonic-gate * Erase and display the new line. 5321*7c478bd9Sstevel@tonic-gate */ 5322*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 5323*7c478bd9Sstevel@tonic-gate return 0; 5324*7c478bd9Sstevel@tonic-gate } 5325*7c478bd9Sstevel@tonic-gate 5326*7c478bd9Sstevel@tonic-gate /*....................................................................... 5327*7c478bd9Sstevel@tonic-gate * This is the action function that recalls the previous line in the 5328*7c478bd9Sstevel@tonic-gate * history buffer whos prefix matches the characters that currently 5329*7c478bd9Sstevel@tonic-gate * precede the cursor. By setting count=-1, this can be used internally 5330*7c478bd9Sstevel@tonic-gate * to force searching for the prefix used in the last search. 5331*7c478bd9Sstevel@tonic-gate */ 5332*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_search_backward) 5333*7c478bd9Sstevel@tonic-gate { 5334*7c478bd9Sstevel@tonic-gate /* 5335*7c478bd9Sstevel@tonic-gate * In vi mode, switch to command mode, since the user is very 5336*7c478bd9Sstevel@tonic-gate * likely to want to move around newly recalled lines. 5337*7c478bd9Sstevel@tonic-gate */ 5338*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 5339*7c478bd9Sstevel@tonic-gate /* 5340*7c478bd9Sstevel@tonic-gate * Forget any previous recall session. 5341*7c478bd9Sstevel@tonic-gate */ 5342*7c478bd9Sstevel@tonic-gate gl->preload_id = 0; 5343*7c478bd9Sstevel@tonic-gate /* 5344*7c478bd9Sstevel@tonic-gate * Record the key sequence number of this search action. 5345*7c478bd9Sstevel@tonic-gate */ 5346*7c478bd9Sstevel@tonic-gate gl->last_search = gl->keyseq_count; 5347*7c478bd9Sstevel@tonic-gate /* 5348*7c478bd9Sstevel@tonic-gate * If a prefix search isn't already in progress, replace the search 5349*7c478bd9Sstevel@tonic-gate * prefix to the string that precedes the cursor. In vi command mode 5350*7c478bd9Sstevel@tonic-gate * include the character that is under the cursor in the string. If 5351*7c478bd9Sstevel@tonic-gate * count<0 keep the previous search prefix regardless, so as to force 5352*7c478bd9Sstevel@tonic-gate * a repeat search even if the last command wasn't a history command. 5353*7c478bd9Sstevel@tonic-gate */ 5354*7c478bd9Sstevel@tonic-gate if(count >= 0 && !_glh_search_active(gl->glh) && 5355*7c478bd9Sstevel@tonic-gate _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos + 5356*7c478bd9Sstevel@tonic-gate (gl->editor==GL_VI_MODE && gl->ntotal>0))) { 5357*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 5358*7c478bd9Sstevel@tonic-gate return 1; 5359*7c478bd9Sstevel@tonic-gate }; 5360*7c478bd9Sstevel@tonic-gate /* 5361*7c478bd9Sstevel@tonic-gate * Search backwards for a match to the part of the line which precedes the 5362*7c478bd9Sstevel@tonic-gate * cursor. 5363*7c478bd9Sstevel@tonic-gate */ 5364*7c478bd9Sstevel@tonic-gate if(_glh_find_backwards(gl->glh, gl->line, gl->linelen+1) == NULL) 5365*7c478bd9Sstevel@tonic-gate return 0; 5366*7c478bd9Sstevel@tonic-gate /* 5367*7c478bd9Sstevel@tonic-gate * Accomodate the new contents of gl->line[]. 5368*7c478bd9Sstevel@tonic-gate */ 5369*7c478bd9Sstevel@tonic-gate gl_update_buffer(gl); 5370*7c478bd9Sstevel@tonic-gate /* 5371*7c478bd9Sstevel@tonic-gate * Arrange to have the cursor placed at the end of the new line. 5372*7c478bd9Sstevel@tonic-gate */ 5373*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->ntotal; 5374*7c478bd9Sstevel@tonic-gate /* 5375*7c478bd9Sstevel@tonic-gate * Erase and display the new line. 5376*7c478bd9Sstevel@tonic-gate */ 5377*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 5378*7c478bd9Sstevel@tonic-gate return 0; 5379*7c478bd9Sstevel@tonic-gate } 5380*7c478bd9Sstevel@tonic-gate 5381*7c478bd9Sstevel@tonic-gate /*....................................................................... 5382*7c478bd9Sstevel@tonic-gate * This is the action function that recalls the previous line in the 5383*7c478bd9Sstevel@tonic-gate * history buffer who's prefix matches that specified in an earlier call 5384*7c478bd9Sstevel@tonic-gate * to gl_history_search_backward() or gl_history_search_forward(). 5385*7c478bd9Sstevel@tonic-gate */ 5386*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_re_search_backward) 5387*7c478bd9Sstevel@tonic-gate { 5388*7c478bd9Sstevel@tonic-gate return gl_history_search_backward(gl, -1, NULL); 5389*7c478bd9Sstevel@tonic-gate } 5390*7c478bd9Sstevel@tonic-gate 5391*7c478bd9Sstevel@tonic-gate /*....................................................................... 5392*7c478bd9Sstevel@tonic-gate * This is the action function that recalls the next line in the 5393*7c478bd9Sstevel@tonic-gate * history buffer who's prefix matches that specified in the earlier call 5394*7c478bd9Sstevel@tonic-gate * to gl_history_search_backward) which started the history search. 5395*7c478bd9Sstevel@tonic-gate * By setting count=-1, this can be used internally to force searching 5396*7c478bd9Sstevel@tonic-gate * for the prefix used in the last search. 5397*7c478bd9Sstevel@tonic-gate */ 5398*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_search_forward) 5399*7c478bd9Sstevel@tonic-gate { 5400*7c478bd9Sstevel@tonic-gate /* 5401*7c478bd9Sstevel@tonic-gate * In vi mode, switch to command mode, since the user is very 5402*7c478bd9Sstevel@tonic-gate * likely to want to move around newly recalled lines. 5403*7c478bd9Sstevel@tonic-gate */ 5404*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 5405*7c478bd9Sstevel@tonic-gate /* 5406*7c478bd9Sstevel@tonic-gate * Record the key sequence number of this search action. 5407*7c478bd9Sstevel@tonic-gate */ 5408*7c478bd9Sstevel@tonic-gate gl->last_search = gl->keyseq_count; 5409*7c478bd9Sstevel@tonic-gate /* 5410*7c478bd9Sstevel@tonic-gate * If a prefix search isn't already in progress, replace the search 5411*7c478bd9Sstevel@tonic-gate * prefix to the string that precedes the cursor. In vi command mode 5412*7c478bd9Sstevel@tonic-gate * include the character that is under the cursor in the string. If 5413*7c478bd9Sstevel@tonic-gate * count<0 keep the previous search prefix regardless, so as to force 5414*7c478bd9Sstevel@tonic-gate * a repeat search even if the last command wasn't a history command. 5415*7c478bd9Sstevel@tonic-gate */ 5416*7c478bd9Sstevel@tonic-gate if(count >= 0 && !_glh_search_active(gl->glh) && 5417*7c478bd9Sstevel@tonic-gate _glh_search_prefix(gl->glh, gl->line, gl->buff_curpos + 5418*7c478bd9Sstevel@tonic-gate (gl->editor==GL_VI_MODE && gl->ntotal>0))) { 5419*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 5420*7c478bd9Sstevel@tonic-gate return 1; 5421*7c478bd9Sstevel@tonic-gate }; 5422*7c478bd9Sstevel@tonic-gate /* 5423*7c478bd9Sstevel@tonic-gate * Search forwards for the next matching line. 5424*7c478bd9Sstevel@tonic-gate */ 5425*7c478bd9Sstevel@tonic-gate if(_glh_find_forwards(gl->glh, gl->line, gl->linelen+1) == NULL) 5426*7c478bd9Sstevel@tonic-gate return 0; 5427*7c478bd9Sstevel@tonic-gate /* 5428*7c478bd9Sstevel@tonic-gate * Accomodate the new contents of gl->line[]. 5429*7c478bd9Sstevel@tonic-gate */ 5430*7c478bd9Sstevel@tonic-gate gl_update_buffer(gl); 5431*7c478bd9Sstevel@tonic-gate /* 5432*7c478bd9Sstevel@tonic-gate * Arrange for the cursor to be placed at the end of the new line. 5433*7c478bd9Sstevel@tonic-gate */ 5434*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->ntotal; 5435*7c478bd9Sstevel@tonic-gate /* 5436*7c478bd9Sstevel@tonic-gate * Erase and display the new line. 5437*7c478bd9Sstevel@tonic-gate */ 5438*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 5439*7c478bd9Sstevel@tonic-gate return 0; 5440*7c478bd9Sstevel@tonic-gate } 5441*7c478bd9Sstevel@tonic-gate 5442*7c478bd9Sstevel@tonic-gate /*....................................................................... 5443*7c478bd9Sstevel@tonic-gate * This is the action function that recalls the next line in the 5444*7c478bd9Sstevel@tonic-gate * history buffer who's prefix matches that specified in an earlier call 5445*7c478bd9Sstevel@tonic-gate * to gl_history_search_backward() or gl_history_search_forward(). 5446*7c478bd9Sstevel@tonic-gate */ 5447*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_history_re_search_forward) 5448*7c478bd9Sstevel@tonic-gate { 5449*7c478bd9Sstevel@tonic-gate return gl_history_search_forward(gl, -1, NULL); 5450*7c478bd9Sstevel@tonic-gate } 5451*7c478bd9Sstevel@tonic-gate 5452*7c478bd9Sstevel@tonic-gate #ifdef HIDE_FILE_SYSTEM 5453*7c478bd9Sstevel@tonic-gate /*....................................................................... 5454*7c478bd9Sstevel@tonic-gate * The following function is used as the default completion handler when 5455*7c478bd9Sstevel@tonic-gate * the filesystem is to be hidden. It simply reports no completions. 5456*7c478bd9Sstevel@tonic-gate */ 5457*7c478bd9Sstevel@tonic-gate static CPL_MATCH_FN(gl_no_completions) 5458*7c478bd9Sstevel@tonic-gate { 5459*7c478bd9Sstevel@tonic-gate return 0; 5460*7c478bd9Sstevel@tonic-gate } 5461*7c478bd9Sstevel@tonic-gate #endif 5462*7c478bd9Sstevel@tonic-gate 5463*7c478bd9Sstevel@tonic-gate /*....................................................................... 5464*7c478bd9Sstevel@tonic-gate * This is the tab completion function that completes the filename that 5465*7c478bd9Sstevel@tonic-gate * precedes the cursor position. Its callback data argument must be a 5466*7c478bd9Sstevel@tonic-gate * pointer to a GlCplCallback containing the completion callback function 5467*7c478bd9Sstevel@tonic-gate * and its callback data, or NULL to use the builtin filename completer. 5468*7c478bd9Sstevel@tonic-gate */ 5469*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_complete_word) 5470*7c478bd9Sstevel@tonic-gate { 5471*7c478bd9Sstevel@tonic-gate CplMatches *matches; /* The possible completions */ 5472*7c478bd9Sstevel@tonic-gate int suffix_len; /* The length of the completion extension */ 5473*7c478bd9Sstevel@tonic-gate int cont_len; /* The length of any continuation suffix */ 5474*7c478bd9Sstevel@tonic-gate int nextra; /* The number of characters being added to the */ 5475*7c478bd9Sstevel@tonic-gate /* total length of the line. */ 5476*7c478bd9Sstevel@tonic-gate int buff_pos; /* The buffer index at which the completion is */ 5477*7c478bd9Sstevel@tonic-gate /* to be inserted. */ 5478*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True after errors */ 5479*7c478bd9Sstevel@tonic-gate /* 5480*7c478bd9Sstevel@tonic-gate * Get the container of the completion callback and its callback data. 5481*7c478bd9Sstevel@tonic-gate */ 5482*7c478bd9Sstevel@tonic-gate GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn; 5483*7c478bd9Sstevel@tonic-gate /* 5484*7c478bd9Sstevel@tonic-gate * In vi command mode, switch to append mode so that the character under 5485*7c478bd9Sstevel@tonic-gate * the cursor is included in the completion (otherwise people can't 5486*7c478bd9Sstevel@tonic-gate * complete at the end of the line). 5487*7c478bd9Sstevel@tonic-gate */ 5488*7c478bd9Sstevel@tonic-gate if(gl->vi.command && gl_vi_append(gl, 0, NULL)) 5489*7c478bd9Sstevel@tonic-gate return 1; 5490*7c478bd9Sstevel@tonic-gate /* 5491*7c478bd9Sstevel@tonic-gate * Get the cursor position at which the completion is to be inserted. 5492*7c478bd9Sstevel@tonic-gate */ 5493*7c478bd9Sstevel@tonic-gate buff_pos = gl->buff_curpos; 5494*7c478bd9Sstevel@tonic-gate /* 5495*7c478bd9Sstevel@tonic-gate * Perform the completion. 5496*7c478bd9Sstevel@tonic-gate */ 5497*7c478bd9Sstevel@tonic-gate matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos, cb->data, 5498*7c478bd9Sstevel@tonic-gate cb->fn); 5499*7c478bd9Sstevel@tonic-gate /* 5500*7c478bd9Sstevel@tonic-gate * No matching completions? 5501*7c478bd9Sstevel@tonic-gate */ 5502*7c478bd9Sstevel@tonic-gate if(!matches) { 5503*7c478bd9Sstevel@tonic-gate waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO); 5504*7c478bd9Sstevel@tonic-gate /* 5505*7c478bd9Sstevel@tonic-gate * Are there any completions? 5506*7c478bd9Sstevel@tonic-gate */ 5507*7c478bd9Sstevel@tonic-gate } else if(matches->nmatch >= 1) { 5508*7c478bd9Sstevel@tonic-gate /* 5509*7c478bd9Sstevel@tonic-gate * If there any ambiguous matches, report them, starting on a new line. 5510*7c478bd9Sstevel@tonic-gate */ 5511*7c478bd9Sstevel@tonic-gate if(matches->nmatch > 1 && gl->echo) { 5512*7c478bd9Sstevel@tonic-gate if(_gl_normal_io(gl) || 5513*7c478bd9Sstevel@tonic-gate _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn)) 5514*7c478bd9Sstevel@tonic-gate waserr = 1; 5515*7c478bd9Sstevel@tonic-gate }; 5516*7c478bd9Sstevel@tonic-gate /* 5517*7c478bd9Sstevel@tonic-gate * Get the length of the suffix and any continuation suffix to add to it. 5518*7c478bd9Sstevel@tonic-gate */ 5519*7c478bd9Sstevel@tonic-gate suffix_len = strlen(matches->suffix); 5520*7c478bd9Sstevel@tonic-gate cont_len = strlen(matches->cont_suffix); 5521*7c478bd9Sstevel@tonic-gate /* 5522*7c478bd9Sstevel@tonic-gate * If there is an unambiguous match, and the continuation suffix ends in 5523*7c478bd9Sstevel@tonic-gate * a newline, strip that newline and arrange to have getline return 5524*7c478bd9Sstevel@tonic-gate * after this action function returns. 5525*7c478bd9Sstevel@tonic-gate */ 5526*7c478bd9Sstevel@tonic-gate if(matches->nmatch==1 && cont_len > 0 && 5527*7c478bd9Sstevel@tonic-gate matches->cont_suffix[cont_len - 1] == '\n') { 5528*7c478bd9Sstevel@tonic-gate cont_len--; 5529*7c478bd9Sstevel@tonic-gate if(gl_newline(gl, 1, NULL)) 5530*7c478bd9Sstevel@tonic-gate waserr = 1; 5531*7c478bd9Sstevel@tonic-gate }; 5532*7c478bd9Sstevel@tonic-gate /* 5533*7c478bd9Sstevel@tonic-gate * Work out the number of characters that are to be added. 5534*7c478bd9Sstevel@tonic-gate */ 5535*7c478bd9Sstevel@tonic-gate nextra = suffix_len + cont_len; 5536*7c478bd9Sstevel@tonic-gate /* 5537*7c478bd9Sstevel@tonic-gate * Is there anything to be added? 5538*7c478bd9Sstevel@tonic-gate */ 5539*7c478bd9Sstevel@tonic-gate if(!waserr && nextra) { 5540*7c478bd9Sstevel@tonic-gate /* 5541*7c478bd9Sstevel@tonic-gate * Will there be space for the expansion in the line buffer? 5542*7c478bd9Sstevel@tonic-gate */ 5543*7c478bd9Sstevel@tonic-gate if(gl->ntotal + nextra < gl->linelen) { 5544*7c478bd9Sstevel@tonic-gate /* 5545*7c478bd9Sstevel@tonic-gate * Make room to insert the filename extension. 5546*7c478bd9Sstevel@tonic-gate */ 5547*7c478bd9Sstevel@tonic-gate gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra); 5548*7c478bd9Sstevel@tonic-gate /* 5549*7c478bd9Sstevel@tonic-gate * Insert the filename extension. 5550*7c478bd9Sstevel@tonic-gate */ 5551*7c478bd9Sstevel@tonic-gate gl_buffer_string(gl, matches->suffix, suffix_len, gl->buff_curpos); 5552*7c478bd9Sstevel@tonic-gate /* 5553*7c478bd9Sstevel@tonic-gate * Add the terminating characters. 5554*7c478bd9Sstevel@tonic-gate */ 5555*7c478bd9Sstevel@tonic-gate gl_buffer_string(gl, matches->cont_suffix, cont_len, 5556*7c478bd9Sstevel@tonic-gate gl->buff_curpos + suffix_len); 5557*7c478bd9Sstevel@tonic-gate /* 5558*7c478bd9Sstevel@tonic-gate * Place the cursor position at the end of the completion. 5559*7c478bd9Sstevel@tonic-gate */ 5560*7c478bd9Sstevel@tonic-gate gl->buff_curpos += nextra; 5561*7c478bd9Sstevel@tonic-gate /* 5562*7c478bd9Sstevel@tonic-gate * If we don't have to redisplay the whole line, redisplay the part 5563*7c478bd9Sstevel@tonic-gate * of the line which follows the original cursor position, and place 5564*7c478bd9Sstevel@tonic-gate * the cursor at the end of the completion. 5565*7c478bd9Sstevel@tonic-gate */ 5566*7c478bd9Sstevel@tonic-gate if(gl->displayed) { 5567*7c478bd9Sstevel@tonic-gate if(gl_truncate_display(gl) || 5568*7c478bd9Sstevel@tonic-gate gl_print_string(gl, gl->line + buff_pos, '\0') || 5569*7c478bd9Sstevel@tonic-gate gl_place_cursor(gl, gl->buff_curpos)) 5570*7c478bd9Sstevel@tonic-gate waserr = 1; 5571*7c478bd9Sstevel@tonic-gate }; 5572*7c478bd9Sstevel@tonic-gate } else { 5573*7c478bd9Sstevel@tonic-gate (void) gl_print_info(gl, 5574*7c478bd9Sstevel@tonic-gate "Insufficient room in line for file completion.", 5575*7c478bd9Sstevel@tonic-gate GL_END_INFO); 5576*7c478bd9Sstevel@tonic-gate waserr = 1; 5577*7c478bd9Sstevel@tonic-gate }; 5578*7c478bd9Sstevel@tonic-gate }; 5579*7c478bd9Sstevel@tonic-gate }; 5580*7c478bd9Sstevel@tonic-gate /* 5581*7c478bd9Sstevel@tonic-gate * If any output had to be written to the terminal, then editing will 5582*7c478bd9Sstevel@tonic-gate * have been suspended, make sure that we are back in raw line editing 5583*7c478bd9Sstevel@tonic-gate * mode before returning. 5584*7c478bd9Sstevel@tonic-gate */ 5585*7c478bd9Sstevel@tonic-gate if(_gl_raw_io(gl, 1)) 5586*7c478bd9Sstevel@tonic-gate waserr = 1; 5587*7c478bd9Sstevel@tonic-gate return 0; 5588*7c478bd9Sstevel@tonic-gate } 5589*7c478bd9Sstevel@tonic-gate 5590*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 5591*7c478bd9Sstevel@tonic-gate /*....................................................................... 5592*7c478bd9Sstevel@tonic-gate * This is the function that expands the filename that precedes the 5593*7c478bd9Sstevel@tonic-gate * cursor position. It expands ~user/ expressions, $envvar expressions, 5594*7c478bd9Sstevel@tonic-gate * and wildcards. 5595*7c478bd9Sstevel@tonic-gate */ 5596*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_expand_filename) 5597*7c478bd9Sstevel@tonic-gate { 5598*7c478bd9Sstevel@tonic-gate char *start_path; /* The pointer to the start of the pathname in */ 5599*7c478bd9Sstevel@tonic-gate /* gl->line[]. */ 5600*7c478bd9Sstevel@tonic-gate FileExpansion *result; /* The results of the filename expansion */ 5601*7c478bd9Sstevel@tonic-gate int pathlen; /* The length of the pathname being expanded */ 5602*7c478bd9Sstevel@tonic-gate int length; /* The number of characters needed to display the */ 5603*7c478bd9Sstevel@tonic-gate /* expanded files. */ 5604*7c478bd9Sstevel@tonic-gate int nextra; /* The number of characters to be added */ 5605*7c478bd9Sstevel@tonic-gate int i,j; 5606*7c478bd9Sstevel@tonic-gate /* 5607*7c478bd9Sstevel@tonic-gate * In vi command mode, switch to append mode so that the character under 5608*7c478bd9Sstevel@tonic-gate * the cursor is included in the completion (otherwise people can't 5609*7c478bd9Sstevel@tonic-gate * complete at the end of the line). 5610*7c478bd9Sstevel@tonic-gate */ 5611*7c478bd9Sstevel@tonic-gate if(gl->vi.command && gl_vi_append(gl, 0, NULL)) 5612*7c478bd9Sstevel@tonic-gate return 1; 5613*7c478bd9Sstevel@tonic-gate /* 5614*7c478bd9Sstevel@tonic-gate * Locate the start of the filename that precedes the cursor position. 5615*7c478bd9Sstevel@tonic-gate */ 5616*7c478bd9Sstevel@tonic-gate start_path = _pu_start_of_path(gl->line, gl->buff_curpos); 5617*7c478bd9Sstevel@tonic-gate if(!start_path) 5618*7c478bd9Sstevel@tonic-gate return 1; 5619*7c478bd9Sstevel@tonic-gate /* 5620*7c478bd9Sstevel@tonic-gate * Get the length of the string that is to be expanded. 5621*7c478bd9Sstevel@tonic-gate */ 5622*7c478bd9Sstevel@tonic-gate pathlen = gl->buff_curpos - (start_path - gl->line); 5623*7c478bd9Sstevel@tonic-gate /* 5624*7c478bd9Sstevel@tonic-gate * Attempt to expand it. 5625*7c478bd9Sstevel@tonic-gate */ 5626*7c478bd9Sstevel@tonic-gate result = ef_expand_file(gl->ef, start_path, pathlen); 5627*7c478bd9Sstevel@tonic-gate /* 5628*7c478bd9Sstevel@tonic-gate * If there was an error, report the error on a new line. 5629*7c478bd9Sstevel@tonic-gate */ 5630*7c478bd9Sstevel@tonic-gate if(!result) 5631*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO); 5632*7c478bd9Sstevel@tonic-gate /* 5633*7c478bd9Sstevel@tonic-gate * If no files matched, report this as well. 5634*7c478bd9Sstevel@tonic-gate */ 5635*7c478bd9Sstevel@tonic-gate if(result->nfile == 0 || !result->exists) 5636*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, "No files match.", GL_END_INFO); 5637*7c478bd9Sstevel@tonic-gate /* 5638*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential use by 5639*7c478bd9Sstevel@tonic-gate * vi-undo. 5640*7c478bd9Sstevel@tonic-gate */ 5641*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 5642*7c478bd9Sstevel@tonic-gate /* 5643*7c478bd9Sstevel@tonic-gate * Work out how much space we will need to display all of the matching 5644*7c478bd9Sstevel@tonic-gate * filenames, taking account of the space that we need to place between 5645*7c478bd9Sstevel@tonic-gate * them, and the number of additional '\' characters needed to escape 5646*7c478bd9Sstevel@tonic-gate * spaces, tabs and backslash characters in the individual filenames. 5647*7c478bd9Sstevel@tonic-gate */ 5648*7c478bd9Sstevel@tonic-gate length = 0; 5649*7c478bd9Sstevel@tonic-gate for(i=0; i<result->nfile; i++) { 5650*7c478bd9Sstevel@tonic-gate char *file = result->files[i]; 5651*7c478bd9Sstevel@tonic-gate while(*file) { 5652*7c478bd9Sstevel@tonic-gate int c = *file++; 5653*7c478bd9Sstevel@tonic-gate switch(c) { 5654*7c478bd9Sstevel@tonic-gate case ' ': case '\t': case '\\': case '*': case '?': case '[': 5655*7c478bd9Sstevel@tonic-gate length++; /* Count extra backslash characters */ 5656*7c478bd9Sstevel@tonic-gate }; 5657*7c478bd9Sstevel@tonic-gate length++; /* Count the character itself */ 5658*7c478bd9Sstevel@tonic-gate }; 5659*7c478bd9Sstevel@tonic-gate length++; /* Count the space that follows each filename */ 5660*7c478bd9Sstevel@tonic-gate }; 5661*7c478bd9Sstevel@tonic-gate /* 5662*7c478bd9Sstevel@tonic-gate * Work out the number of characters that are to be added. 5663*7c478bd9Sstevel@tonic-gate */ 5664*7c478bd9Sstevel@tonic-gate nextra = length - pathlen; 5665*7c478bd9Sstevel@tonic-gate /* 5666*7c478bd9Sstevel@tonic-gate * Will there be space for the expansion in the line buffer? 5667*7c478bd9Sstevel@tonic-gate */ 5668*7c478bd9Sstevel@tonic-gate if(gl->ntotal + nextra >= gl->linelen) { 5669*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, "Insufficient room in line for file expansion.", 5670*7c478bd9Sstevel@tonic-gate GL_END_INFO); 5671*7c478bd9Sstevel@tonic-gate } else { 5672*7c478bd9Sstevel@tonic-gate /* 5673*7c478bd9Sstevel@tonic-gate * Do we need to move the part of the line that followed the unexpanded 5674*7c478bd9Sstevel@tonic-gate * filename? 5675*7c478bd9Sstevel@tonic-gate */ 5676*7c478bd9Sstevel@tonic-gate if(nextra > 0) { 5677*7c478bd9Sstevel@tonic-gate gl_make_gap_in_buffer(gl, gl->buff_curpos, nextra); 5678*7c478bd9Sstevel@tonic-gate } else if(nextra < 0) { 5679*7c478bd9Sstevel@tonic-gate gl->buff_curpos += nextra; 5680*7c478bd9Sstevel@tonic-gate gl_remove_from_buffer(gl, gl->buff_curpos, -nextra); 5681*7c478bd9Sstevel@tonic-gate }; 5682*7c478bd9Sstevel@tonic-gate /* 5683*7c478bd9Sstevel@tonic-gate * Insert the filenames, separated by spaces, and with internal spaces, 5684*7c478bd9Sstevel@tonic-gate * tabs and backslashes escaped with backslashes. 5685*7c478bd9Sstevel@tonic-gate */ 5686*7c478bd9Sstevel@tonic-gate for(i=0,j=start_path - gl->line; i<result->nfile; i++) { 5687*7c478bd9Sstevel@tonic-gate char *file = result->files[i]; 5688*7c478bd9Sstevel@tonic-gate while(*file) { 5689*7c478bd9Sstevel@tonic-gate int c = *file++; 5690*7c478bd9Sstevel@tonic-gate switch(c) { 5691*7c478bd9Sstevel@tonic-gate case ' ': case '\t': case '\\': case '*': case '?': case '[': 5692*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, '\\', j++); 5693*7c478bd9Sstevel@tonic-gate }; 5694*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, c, j++); 5695*7c478bd9Sstevel@tonic-gate }; 5696*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, ' ', j++); 5697*7c478bd9Sstevel@tonic-gate }; 5698*7c478bd9Sstevel@tonic-gate }; 5699*7c478bd9Sstevel@tonic-gate /* 5700*7c478bd9Sstevel@tonic-gate * Redisplay the part of the line which follows the start of 5701*7c478bd9Sstevel@tonic-gate * the original filename. 5702*7c478bd9Sstevel@tonic-gate */ 5703*7c478bd9Sstevel@tonic-gate if(gl_place_cursor(gl, start_path - gl->line) || 5704*7c478bd9Sstevel@tonic-gate gl_truncate_display(gl) || 5705*7c478bd9Sstevel@tonic-gate gl_print_string(gl, start_path, start_path[length])) 5706*7c478bd9Sstevel@tonic-gate return 1; 5707*7c478bd9Sstevel@tonic-gate /* 5708*7c478bd9Sstevel@tonic-gate * Move the cursor to the end of the expansion. 5709*7c478bd9Sstevel@tonic-gate */ 5710*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, (start_path - gl->line) + length); 5711*7c478bd9Sstevel@tonic-gate } 5712*7c478bd9Sstevel@tonic-gate #endif 5713*7c478bd9Sstevel@tonic-gate 5714*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 5715*7c478bd9Sstevel@tonic-gate /*....................................................................... 5716*7c478bd9Sstevel@tonic-gate * This is the action function that lists glob expansions of the 5717*7c478bd9Sstevel@tonic-gate * filename that precedes the cursor position. It expands ~user/ 5718*7c478bd9Sstevel@tonic-gate * expressions, $envvar expressions, and wildcards. 5719*7c478bd9Sstevel@tonic-gate */ 5720*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_glob) 5721*7c478bd9Sstevel@tonic-gate { 5722*7c478bd9Sstevel@tonic-gate char *start_path; /* The pointer to the start of the pathname in */ 5723*7c478bd9Sstevel@tonic-gate /* gl->line[]. */ 5724*7c478bd9Sstevel@tonic-gate FileExpansion *result; /* The results of the filename expansion */ 5725*7c478bd9Sstevel@tonic-gate int pathlen; /* The length of the pathname being expanded */ 5726*7c478bd9Sstevel@tonic-gate /* 5727*7c478bd9Sstevel@tonic-gate * Locate the start of the filename that precedes the cursor position. 5728*7c478bd9Sstevel@tonic-gate */ 5729*7c478bd9Sstevel@tonic-gate start_path = _pu_start_of_path(gl->line, gl->buff_curpos); 5730*7c478bd9Sstevel@tonic-gate if(!start_path) 5731*7c478bd9Sstevel@tonic-gate return 1; 5732*7c478bd9Sstevel@tonic-gate /* 5733*7c478bd9Sstevel@tonic-gate * Get the length of the string that is to be expanded. 5734*7c478bd9Sstevel@tonic-gate */ 5735*7c478bd9Sstevel@tonic-gate pathlen = gl->buff_curpos - (start_path - gl->line); 5736*7c478bd9Sstevel@tonic-gate /* 5737*7c478bd9Sstevel@tonic-gate * Attempt to expand it. 5738*7c478bd9Sstevel@tonic-gate */ 5739*7c478bd9Sstevel@tonic-gate result = ef_expand_file(gl->ef, start_path, pathlen); 5740*7c478bd9Sstevel@tonic-gate /* 5741*7c478bd9Sstevel@tonic-gate * If there was an error, report it. 5742*7c478bd9Sstevel@tonic-gate */ 5743*7c478bd9Sstevel@tonic-gate if(!result) { 5744*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO); 5745*7c478bd9Sstevel@tonic-gate /* 5746*7c478bd9Sstevel@tonic-gate * If no files matched, report this as well. 5747*7c478bd9Sstevel@tonic-gate */ 5748*7c478bd9Sstevel@tonic-gate } else if(result->nfile == 0 || !result->exists) { 5749*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, "No files match.", GL_END_INFO); 5750*7c478bd9Sstevel@tonic-gate /* 5751*7c478bd9Sstevel@tonic-gate * List the matching expansions. 5752*7c478bd9Sstevel@tonic-gate */ 5753*7c478bd9Sstevel@tonic-gate } else if(gl->echo) { 5754*7c478bd9Sstevel@tonic-gate if(gl_start_newline(gl, 1) || 5755*7c478bd9Sstevel@tonic-gate _ef_output_expansions(result, gl_write_fn, gl, gl->ncolumn)) 5756*7c478bd9Sstevel@tonic-gate return 1; 5757*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 5758*7c478bd9Sstevel@tonic-gate }; 5759*7c478bd9Sstevel@tonic-gate return 0; 5760*7c478bd9Sstevel@tonic-gate } 5761*7c478bd9Sstevel@tonic-gate #endif 5762*7c478bd9Sstevel@tonic-gate 5763*7c478bd9Sstevel@tonic-gate /*....................................................................... 5764*7c478bd9Sstevel@tonic-gate * Return non-zero if a character should be considered a part of a word. 5765*7c478bd9Sstevel@tonic-gate * 5766*7c478bd9Sstevel@tonic-gate * Input: 5767*7c478bd9Sstevel@tonic-gate * c int The character to be tested. 5768*7c478bd9Sstevel@tonic-gate * Output: 5769*7c478bd9Sstevel@tonic-gate * return int True if the character should be considered part of a word. 5770*7c478bd9Sstevel@tonic-gate */ 5771*7c478bd9Sstevel@tonic-gate static int gl_is_word_char(int c) 5772*7c478bd9Sstevel@tonic-gate { 5773*7c478bd9Sstevel@tonic-gate return isalnum((int)(unsigned char)c) || strchr(GL_WORD_CHARS, c) != NULL; 5774*7c478bd9Sstevel@tonic-gate } 5775*7c478bd9Sstevel@tonic-gate 5776*7c478bd9Sstevel@tonic-gate /*....................................................................... 5777*7c478bd9Sstevel@tonic-gate * Override the builtin file-completion callback that is bound to the 5778*7c478bd9Sstevel@tonic-gate * "complete_word" action function. 5779*7c478bd9Sstevel@tonic-gate * 5780*7c478bd9Sstevel@tonic-gate * Input: 5781*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of the command-line input 5782*7c478bd9Sstevel@tonic-gate * module. 5783*7c478bd9Sstevel@tonic-gate * data void * This is passed to match_fn() whenever it is 5784*7c478bd9Sstevel@tonic-gate * called. It could, for example, point to a 5785*7c478bd9Sstevel@tonic-gate * symbol table where match_fn() could look 5786*7c478bd9Sstevel@tonic-gate * for possible completions. 5787*7c478bd9Sstevel@tonic-gate * match_fn CplMatchFn * The function that will identify the prefix 5788*7c478bd9Sstevel@tonic-gate * to be completed from the input line, and 5789*7c478bd9Sstevel@tonic-gate * report matching symbols. 5790*7c478bd9Sstevel@tonic-gate * Output: 5791*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 5792*7c478bd9Sstevel@tonic-gate * 1 - Error. 5793*7c478bd9Sstevel@tonic-gate */ 5794*7c478bd9Sstevel@tonic-gate int gl_customize_completion(GetLine *gl, void *data, CplMatchFn *match_fn) 5795*7c478bd9Sstevel@tonic-gate { 5796*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 5797*7c478bd9Sstevel@tonic-gate /* 5798*7c478bd9Sstevel@tonic-gate * Check the arguments. 5799*7c478bd9Sstevel@tonic-gate */ 5800*7c478bd9Sstevel@tonic-gate if(!gl || !match_fn) { 5801*7c478bd9Sstevel@tonic-gate if(gl) 5802*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "NULL argument", END_ERR_MSG); 5803*7c478bd9Sstevel@tonic-gate errno = EINVAL; 5804*7c478bd9Sstevel@tonic-gate return 1; 5805*7c478bd9Sstevel@tonic-gate }; 5806*7c478bd9Sstevel@tonic-gate /* 5807*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 5808*7c478bd9Sstevel@tonic-gate */ 5809*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 5810*7c478bd9Sstevel@tonic-gate /* 5811*7c478bd9Sstevel@tonic-gate * Record the new completion function and its callback data. 5812*7c478bd9Sstevel@tonic-gate */ 5813*7c478bd9Sstevel@tonic-gate gl->cplfn.fn = match_fn; 5814*7c478bd9Sstevel@tonic-gate gl->cplfn.data = data; 5815*7c478bd9Sstevel@tonic-gate /* 5816*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 5817*7c478bd9Sstevel@tonic-gate */ 5818*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 5819*7c478bd9Sstevel@tonic-gate return 0; 5820*7c478bd9Sstevel@tonic-gate } 5821*7c478bd9Sstevel@tonic-gate 5822*7c478bd9Sstevel@tonic-gate /*....................................................................... 5823*7c478bd9Sstevel@tonic-gate * Change the terminal (or stream) that getline interacts with. 5824*7c478bd9Sstevel@tonic-gate * 5825*7c478bd9Sstevel@tonic-gate * Input: 5826*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of the command-line input 5827*7c478bd9Sstevel@tonic-gate * module. 5828*7c478bd9Sstevel@tonic-gate * input_fp FILE * The stdio stream to read from. 5829*7c478bd9Sstevel@tonic-gate * output_fp FILE * The stdio stream to write to. 5830*7c478bd9Sstevel@tonic-gate * term char * The terminal type. This can be NULL if 5831*7c478bd9Sstevel@tonic-gate * either or both of input_fp and output_fp don't 5832*7c478bd9Sstevel@tonic-gate * refer to a terminal. Otherwise it should refer 5833*7c478bd9Sstevel@tonic-gate * to an entry in the terminal information database. 5834*7c478bd9Sstevel@tonic-gate * Output: 5835*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 5836*7c478bd9Sstevel@tonic-gate * 1 - Error. 5837*7c478bd9Sstevel@tonic-gate */ 5838*7c478bd9Sstevel@tonic-gate int gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp, 5839*7c478bd9Sstevel@tonic-gate const char *term) 5840*7c478bd9Sstevel@tonic-gate { 5841*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 5842*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_change_terminal() */ 5843*7c478bd9Sstevel@tonic-gate /* 5844*7c478bd9Sstevel@tonic-gate * Check the arguments. 5845*7c478bd9Sstevel@tonic-gate */ 5846*7c478bd9Sstevel@tonic-gate if(!gl) { 5847*7c478bd9Sstevel@tonic-gate errno = EINVAL; 5848*7c478bd9Sstevel@tonic-gate return 1; 5849*7c478bd9Sstevel@tonic-gate }; 5850*7c478bd9Sstevel@tonic-gate /* 5851*7c478bd9Sstevel@tonic-gate * Block all signals. 5852*7c478bd9Sstevel@tonic-gate */ 5853*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 5854*7c478bd9Sstevel@tonic-gate return 1; 5855*7c478bd9Sstevel@tonic-gate /* 5856*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 5857*7c478bd9Sstevel@tonic-gate */ 5858*7c478bd9Sstevel@tonic-gate status = _gl_change_terminal(gl, input_fp, output_fp, term); 5859*7c478bd9Sstevel@tonic-gate /* 5860*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 5861*7c478bd9Sstevel@tonic-gate */ 5862*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 5863*7c478bd9Sstevel@tonic-gate return status; 5864*7c478bd9Sstevel@tonic-gate } 5865*7c478bd9Sstevel@tonic-gate 5866*7c478bd9Sstevel@tonic-gate /*....................................................................... 5867*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_change_terminal() function. It 5868*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 5869*7c478bd9Sstevel@tonic-gate * delivery of signals. 5870*7c478bd9Sstevel@tonic-gate */ 5871*7c478bd9Sstevel@tonic-gate static int _gl_change_terminal(GetLine *gl, FILE *input_fp, FILE *output_fp, 5872*7c478bd9Sstevel@tonic-gate const char *term) 5873*7c478bd9Sstevel@tonic-gate { 5874*7c478bd9Sstevel@tonic-gate int is_term = 0; /* True if both input_fd and output_fd are associated */ 5875*7c478bd9Sstevel@tonic-gate /* with a terminal. */ 5876*7c478bd9Sstevel@tonic-gate /* 5877*7c478bd9Sstevel@tonic-gate * Require that input_fp and output_fp both be valid. 5878*7c478bd9Sstevel@tonic-gate */ 5879*7c478bd9Sstevel@tonic-gate if(!input_fp || !output_fp) { 5880*7c478bd9Sstevel@tonic-gate gl_print_info(gl, "Can't change terminal. Bad input/output stream(s).", 5881*7c478bd9Sstevel@tonic-gate GL_END_INFO); 5882*7c478bd9Sstevel@tonic-gate return 1; 5883*7c478bd9Sstevel@tonic-gate }; 5884*7c478bd9Sstevel@tonic-gate /* 5885*7c478bd9Sstevel@tonic-gate * Are we displacing an existing terminal (as opposed to setting the 5886*7c478bd9Sstevel@tonic-gate * initial terminal)? 5887*7c478bd9Sstevel@tonic-gate */ 5888*7c478bd9Sstevel@tonic-gate if(gl->input_fd >= 0) { 5889*7c478bd9Sstevel@tonic-gate /* 5890*7c478bd9Sstevel@tonic-gate * Make sure to leave the previous terminal in a usable state. 5891*7c478bd9Sstevel@tonic-gate */ 5892*7c478bd9Sstevel@tonic-gate if(_gl_normal_io(gl)) 5893*7c478bd9Sstevel@tonic-gate return 1; 5894*7c478bd9Sstevel@tonic-gate /* 5895*7c478bd9Sstevel@tonic-gate * Remove the displaced terminal from the list of fds to watch. 5896*7c478bd9Sstevel@tonic-gate */ 5897*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 5898*7c478bd9Sstevel@tonic-gate FD_CLR(gl->input_fd, &gl->rfds); 5899*7c478bd9Sstevel@tonic-gate #endif 5900*7c478bd9Sstevel@tonic-gate }; 5901*7c478bd9Sstevel@tonic-gate /* 5902*7c478bd9Sstevel@tonic-gate * Record the file descriptors and streams. 5903*7c478bd9Sstevel@tonic-gate */ 5904*7c478bd9Sstevel@tonic-gate gl->input_fp = input_fp; 5905*7c478bd9Sstevel@tonic-gate gl->input_fd = fileno(input_fp); 5906*7c478bd9Sstevel@tonic-gate gl->output_fp = output_fp; 5907*7c478bd9Sstevel@tonic-gate gl->output_fd = fileno(output_fp); 5908*7c478bd9Sstevel@tonic-gate /* 5909*7c478bd9Sstevel@tonic-gate * If needed, expand the record of the maximum file-descriptor that might 5910*7c478bd9Sstevel@tonic-gate * need to be monitored with select(). 5911*7c478bd9Sstevel@tonic-gate */ 5912*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 5913*7c478bd9Sstevel@tonic-gate if(gl->input_fd > gl->max_fd) 5914*7c478bd9Sstevel@tonic-gate gl->max_fd = gl->input_fd; 5915*7c478bd9Sstevel@tonic-gate #endif 5916*7c478bd9Sstevel@tonic-gate /* 5917*7c478bd9Sstevel@tonic-gate * Disable terminal interaction until we have enough info to interact 5918*7c478bd9Sstevel@tonic-gate * with the terminal. 5919*7c478bd9Sstevel@tonic-gate */ 5920*7c478bd9Sstevel@tonic-gate gl->is_term = 0; 5921*7c478bd9Sstevel@tonic-gate /* 5922*7c478bd9Sstevel@tonic-gate * For terminal editing, we need both output_fd and input_fd to refer to 5923*7c478bd9Sstevel@tonic-gate * a terminal. While we can't verify that they both point to the same 5924*7c478bd9Sstevel@tonic-gate * terminal, we can verify that they point to terminals. 5925*7c478bd9Sstevel@tonic-gate */ 5926*7c478bd9Sstevel@tonic-gate is_term = isatty(gl->input_fd) && isatty(gl->output_fd); 5927*7c478bd9Sstevel@tonic-gate /* 5928*7c478bd9Sstevel@tonic-gate * If we are interacting with a terminal and no terminal type has been 5929*7c478bd9Sstevel@tonic-gate * specified, treat it as a generic ANSI terminal. 5930*7c478bd9Sstevel@tonic-gate */ 5931*7c478bd9Sstevel@tonic-gate if(is_term && !term) 5932*7c478bd9Sstevel@tonic-gate term = "ansi"; 5933*7c478bd9Sstevel@tonic-gate /* 5934*7c478bd9Sstevel@tonic-gate * Make a copy of the terminal type string. 5935*7c478bd9Sstevel@tonic-gate */ 5936*7c478bd9Sstevel@tonic-gate if(term != gl->term) { 5937*7c478bd9Sstevel@tonic-gate /* 5938*7c478bd9Sstevel@tonic-gate * Delete any old terminal type string. 5939*7c478bd9Sstevel@tonic-gate */ 5940*7c478bd9Sstevel@tonic-gate if(gl->term) { 5941*7c478bd9Sstevel@tonic-gate free(gl->term); 5942*7c478bd9Sstevel@tonic-gate gl->term = NULL; 5943*7c478bd9Sstevel@tonic-gate }; 5944*7c478bd9Sstevel@tonic-gate /* 5945*7c478bd9Sstevel@tonic-gate * Make a copy of the new terminal-type string, if any. 5946*7c478bd9Sstevel@tonic-gate */ 5947*7c478bd9Sstevel@tonic-gate if(term) { 5948*7c478bd9Sstevel@tonic-gate size_t termsz = strlen(term)+1; 5949*7c478bd9Sstevel@tonic-gate 5950*7c478bd9Sstevel@tonic-gate gl->term = (char *) malloc(termsz); 5951*7c478bd9Sstevel@tonic-gate if(gl->term) 5952*7c478bd9Sstevel@tonic-gate strlcpy(gl->term, term, termsz); 5953*7c478bd9Sstevel@tonic-gate }; 5954*7c478bd9Sstevel@tonic-gate }; 5955*7c478bd9Sstevel@tonic-gate /* 5956*7c478bd9Sstevel@tonic-gate * Clear any terminal-specific key bindings that were taken from the 5957*7c478bd9Sstevel@tonic-gate * settings of the last terminal. 5958*7c478bd9Sstevel@tonic-gate */ 5959*7c478bd9Sstevel@tonic-gate _kt_clear_bindings(gl->bindings, KTB_TERM); 5960*7c478bd9Sstevel@tonic-gate /* 5961*7c478bd9Sstevel@tonic-gate * If we have a terminal install new bindings for it. 5962*7c478bd9Sstevel@tonic-gate */ 5963*7c478bd9Sstevel@tonic-gate if(is_term) { 5964*7c478bd9Sstevel@tonic-gate /* 5965*7c478bd9Sstevel@tonic-gate * Get the current settings of the terminal. 5966*7c478bd9Sstevel@tonic-gate */ 5967*7c478bd9Sstevel@tonic-gate if(tcgetattr(gl->input_fd, &gl->oldattr)) { 5968*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG); 5969*7c478bd9Sstevel@tonic-gate return 1; 5970*7c478bd9Sstevel@tonic-gate }; 5971*7c478bd9Sstevel@tonic-gate /* 5972*7c478bd9Sstevel@tonic-gate * If we don't set this now, gl_control_strings() won't know 5973*7c478bd9Sstevel@tonic-gate * that it is talking to a terminal. 5974*7c478bd9Sstevel@tonic-gate */ 5975*7c478bd9Sstevel@tonic-gate gl->is_term = 1; 5976*7c478bd9Sstevel@tonic-gate /* 5977*7c478bd9Sstevel@tonic-gate * Lookup the terminal control string and size information. 5978*7c478bd9Sstevel@tonic-gate */ 5979*7c478bd9Sstevel@tonic-gate if(gl_control_strings(gl, term)) { 5980*7c478bd9Sstevel@tonic-gate gl->is_term = 0; 5981*7c478bd9Sstevel@tonic-gate return 1; 5982*7c478bd9Sstevel@tonic-gate }; 5983*7c478bd9Sstevel@tonic-gate /* 5984*7c478bd9Sstevel@tonic-gate * Bind terminal-specific keys. 5985*7c478bd9Sstevel@tonic-gate */ 5986*7c478bd9Sstevel@tonic-gate if(gl_bind_terminal_keys(gl)) 5987*7c478bd9Sstevel@tonic-gate return 1; 5988*7c478bd9Sstevel@tonic-gate }; 5989*7c478bd9Sstevel@tonic-gate /* 5990*7c478bd9Sstevel@tonic-gate * Assume that the caller has given us a terminal in a sane state. 5991*7c478bd9Sstevel@tonic-gate */ 5992*7c478bd9Sstevel@tonic-gate gl->io_mode = GL_NORMAL_MODE; 5993*7c478bd9Sstevel@tonic-gate /* 5994*7c478bd9Sstevel@tonic-gate * Switch into the currently configured I/O mode. 5995*7c478bd9Sstevel@tonic-gate */ 5996*7c478bd9Sstevel@tonic-gate if(_gl_io_mode(gl, gl->io_mode)) 5997*7c478bd9Sstevel@tonic-gate return 1; 5998*7c478bd9Sstevel@tonic-gate return 0; 5999*7c478bd9Sstevel@tonic-gate } 6000*7c478bd9Sstevel@tonic-gate 6001*7c478bd9Sstevel@tonic-gate /*....................................................................... 6002*7c478bd9Sstevel@tonic-gate * Set up terminal-specific key bindings. 6003*7c478bd9Sstevel@tonic-gate * 6004*7c478bd9Sstevel@tonic-gate * Input: 6005*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of the command-line input 6006*7c478bd9Sstevel@tonic-gate * module. 6007*7c478bd9Sstevel@tonic-gate * Output: 6008*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 6009*7c478bd9Sstevel@tonic-gate * 1 - Error. 6010*7c478bd9Sstevel@tonic-gate */ 6011*7c478bd9Sstevel@tonic-gate static int gl_bind_terminal_keys(GetLine *gl) 6012*7c478bd9Sstevel@tonic-gate { 6013*7c478bd9Sstevel@tonic-gate /* 6014*7c478bd9Sstevel@tonic-gate * Install key-bindings for the special terminal characters. 6015*7c478bd9Sstevel@tonic-gate */ 6016*7c478bd9Sstevel@tonic-gate if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VINTR], 6017*7c478bd9Sstevel@tonic-gate "user-interrupt") || 6018*7c478bd9Sstevel@tonic-gate gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VQUIT], "abort") || 6019*7c478bd9Sstevel@tonic-gate gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VSUSP], "suspend")) 6020*7c478bd9Sstevel@tonic-gate return 1; 6021*7c478bd9Sstevel@tonic-gate /* 6022*7c478bd9Sstevel@tonic-gate * In vi-mode, arrange for the above characters to be seen in command 6023*7c478bd9Sstevel@tonic-gate * mode. 6024*7c478bd9Sstevel@tonic-gate */ 6025*7c478bd9Sstevel@tonic-gate if(gl->editor == GL_VI_MODE) { 6026*7c478bd9Sstevel@tonic-gate if(gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VINTR]), 6027*7c478bd9Sstevel@tonic-gate "user-interrupt") || 6028*7c478bd9Sstevel@tonic-gate gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VQUIT]), 6029*7c478bd9Sstevel@tonic-gate "abort") || 6030*7c478bd9Sstevel@tonic-gate gl_bind_control_char(gl, KTB_TERM, MAKE_META(gl->oldattr.c_cc[VSUSP]), 6031*7c478bd9Sstevel@tonic-gate "suspend")) 6032*7c478bd9Sstevel@tonic-gate return 1; 6033*7c478bd9Sstevel@tonic-gate }; 6034*7c478bd9Sstevel@tonic-gate /* 6035*7c478bd9Sstevel@tonic-gate * Non-universal special keys. 6036*7c478bd9Sstevel@tonic-gate */ 6037*7c478bd9Sstevel@tonic-gate #ifdef VLNEXT 6038*7c478bd9Sstevel@tonic-gate if(gl_bind_control_char(gl, KTB_TERM, gl->oldattr.c_cc[VLNEXT], 6039*7c478bd9Sstevel@tonic-gate "literal-next")) 6040*7c478bd9Sstevel@tonic-gate return 1; 6041*7c478bd9Sstevel@tonic-gate #else 6042*7c478bd9Sstevel@tonic-gate if(_kt_set_keybinding(gl->bindings, KTB_TERM, "^V", "literal-next")) { 6043*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG); 6044*7c478bd9Sstevel@tonic-gate return 1; 6045*7c478bd9Sstevel@tonic-gate }; 6046*7c478bd9Sstevel@tonic-gate #endif 6047*7c478bd9Sstevel@tonic-gate /* 6048*7c478bd9Sstevel@tonic-gate * Bind action functions to the terminal-specific arrow keys 6049*7c478bd9Sstevel@tonic-gate * looked up by gl_control_strings(). 6050*7c478bd9Sstevel@tonic-gate */ 6051*7c478bd9Sstevel@tonic-gate if(_gl_bind_arrow_keys(gl)) 6052*7c478bd9Sstevel@tonic-gate return 1; 6053*7c478bd9Sstevel@tonic-gate return 0; 6054*7c478bd9Sstevel@tonic-gate } 6055*7c478bd9Sstevel@tonic-gate 6056*7c478bd9Sstevel@tonic-gate /*....................................................................... 6057*7c478bd9Sstevel@tonic-gate * This function is normally bound to control-D. When it is invoked within 6058*7c478bd9Sstevel@tonic-gate * a line it deletes the character which follows the cursor. When invoked 6059*7c478bd9Sstevel@tonic-gate * at the end of the line it lists possible file completions, and when 6060*7c478bd9Sstevel@tonic-gate * invoked on an empty line it causes gl_get_line() to return EOF. This 6061*7c478bd9Sstevel@tonic-gate * function emulates the one that is normally bound to control-D by tcsh. 6062*7c478bd9Sstevel@tonic-gate */ 6063*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_del_char_or_list_or_eof) 6064*7c478bd9Sstevel@tonic-gate { 6065*7c478bd9Sstevel@tonic-gate /* 6066*7c478bd9Sstevel@tonic-gate * If we have an empty line arrange to return EOF. 6067*7c478bd9Sstevel@tonic-gate */ 6068*7c478bd9Sstevel@tonic-gate if(gl->ntotal < 1) { 6069*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_EOF, 0); 6070*7c478bd9Sstevel@tonic-gate return 1; 6071*7c478bd9Sstevel@tonic-gate /* 6072*7c478bd9Sstevel@tonic-gate * If we are at the end of the line list possible completions. 6073*7c478bd9Sstevel@tonic-gate */ 6074*7c478bd9Sstevel@tonic-gate } else if(gl->buff_curpos >= gl->ntotal) { 6075*7c478bd9Sstevel@tonic-gate return gl_list_completions(gl, 1, NULL); 6076*7c478bd9Sstevel@tonic-gate /* 6077*7c478bd9Sstevel@tonic-gate * Within the line delete the character that follows the cursor. 6078*7c478bd9Sstevel@tonic-gate */ 6079*7c478bd9Sstevel@tonic-gate } else { 6080*7c478bd9Sstevel@tonic-gate /* 6081*7c478bd9Sstevel@tonic-gate * If in vi command mode, first preserve the current line for potential use 6082*7c478bd9Sstevel@tonic-gate * by vi-undo. 6083*7c478bd9Sstevel@tonic-gate */ 6084*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 6085*7c478bd9Sstevel@tonic-gate /* 6086*7c478bd9Sstevel@tonic-gate * Delete 'count' characters. 6087*7c478bd9Sstevel@tonic-gate */ 6088*7c478bd9Sstevel@tonic-gate return gl_forward_delete_char(gl, count, NULL); 6089*7c478bd9Sstevel@tonic-gate }; 6090*7c478bd9Sstevel@tonic-gate } 6091*7c478bd9Sstevel@tonic-gate 6092*7c478bd9Sstevel@tonic-gate /*....................................................................... 6093*7c478bd9Sstevel@tonic-gate * This function is normally bound to control-D in vi mode. When it is 6094*7c478bd9Sstevel@tonic-gate * invoked within a line it lists possible file completions, and when 6095*7c478bd9Sstevel@tonic-gate * invoked on an empty line it causes gl_get_line() to return EOF. This 6096*7c478bd9Sstevel@tonic-gate * function emulates the one that is normally bound to control-D by tcsh. 6097*7c478bd9Sstevel@tonic-gate */ 6098*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_or_eof) 6099*7c478bd9Sstevel@tonic-gate { 6100*7c478bd9Sstevel@tonic-gate /* 6101*7c478bd9Sstevel@tonic-gate * If we have an empty line arrange to return EOF. 6102*7c478bd9Sstevel@tonic-gate */ 6103*7c478bd9Sstevel@tonic-gate if(gl->ntotal < 1) { 6104*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_EOF, 0); 6105*7c478bd9Sstevel@tonic-gate return 1; 6106*7c478bd9Sstevel@tonic-gate /* 6107*7c478bd9Sstevel@tonic-gate * Otherwise list possible completions. 6108*7c478bd9Sstevel@tonic-gate */ 6109*7c478bd9Sstevel@tonic-gate } else { 6110*7c478bd9Sstevel@tonic-gate return gl_list_completions(gl, 1, NULL); 6111*7c478bd9Sstevel@tonic-gate }; 6112*7c478bd9Sstevel@tonic-gate } 6113*7c478bd9Sstevel@tonic-gate 6114*7c478bd9Sstevel@tonic-gate /*....................................................................... 6115*7c478bd9Sstevel@tonic-gate * List possible completions of the word that precedes the cursor. The 6116*7c478bd9Sstevel@tonic-gate * callback data argument must either be NULL to select the default 6117*7c478bd9Sstevel@tonic-gate * file completion callback, or be a GlCplCallback object containing the 6118*7c478bd9Sstevel@tonic-gate * completion callback function to call. 6119*7c478bd9Sstevel@tonic-gate */ 6120*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_completions) 6121*7c478bd9Sstevel@tonic-gate { 6122*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True after errors */ 6123*7c478bd9Sstevel@tonic-gate /* 6124*7c478bd9Sstevel@tonic-gate * Get the container of the completion callback and its callback data. 6125*7c478bd9Sstevel@tonic-gate */ 6126*7c478bd9Sstevel@tonic-gate GlCplCallback *cb = data ? (GlCplCallback *) data : &gl->cplfn; 6127*7c478bd9Sstevel@tonic-gate /* 6128*7c478bd9Sstevel@tonic-gate * Get the list of possible completions. 6129*7c478bd9Sstevel@tonic-gate */ 6130*7c478bd9Sstevel@tonic-gate CplMatches *matches = cpl_complete_word(gl->cpl, gl->line, gl->buff_curpos, 6131*7c478bd9Sstevel@tonic-gate cb->data, cb->fn); 6132*7c478bd9Sstevel@tonic-gate /* 6133*7c478bd9Sstevel@tonic-gate * No matching completions? 6134*7c478bd9Sstevel@tonic-gate */ 6135*7c478bd9Sstevel@tonic-gate if(!matches) { 6136*7c478bd9Sstevel@tonic-gate waserr = gl_print_info(gl, cpl_last_error(gl->cpl), GL_END_INFO); 6137*7c478bd9Sstevel@tonic-gate /* 6138*7c478bd9Sstevel@tonic-gate * List the matches. 6139*7c478bd9Sstevel@tonic-gate */ 6140*7c478bd9Sstevel@tonic-gate } else if(matches->nmatch > 0 && gl->echo) { 6141*7c478bd9Sstevel@tonic-gate if(_gl_normal_io(gl) || 6142*7c478bd9Sstevel@tonic-gate _cpl_output_completions(matches, gl_write_fn, gl, gl->ncolumn)) 6143*7c478bd9Sstevel@tonic-gate waserr = 1; 6144*7c478bd9Sstevel@tonic-gate }; 6145*7c478bd9Sstevel@tonic-gate /* 6146*7c478bd9Sstevel@tonic-gate * If any output had to be written to the terminal, then editing will 6147*7c478bd9Sstevel@tonic-gate * have been suspended, make sure that we are back in raw line editing 6148*7c478bd9Sstevel@tonic-gate * mode before returning. 6149*7c478bd9Sstevel@tonic-gate */ 6150*7c478bd9Sstevel@tonic-gate if(_gl_raw_io(gl, 1)) 6151*7c478bd9Sstevel@tonic-gate waserr = 1; 6152*7c478bd9Sstevel@tonic-gate return waserr; 6153*7c478bd9Sstevel@tonic-gate } 6154*7c478bd9Sstevel@tonic-gate 6155*7c478bd9Sstevel@tonic-gate /*....................................................................... 6156*7c478bd9Sstevel@tonic-gate * Where the user has used the symbolic arrow-key names to specify 6157*7c478bd9Sstevel@tonic-gate * arrow key bindings, bind the specified action functions to the default 6158*7c478bd9Sstevel@tonic-gate * and terminal specific arrow key sequences. 6159*7c478bd9Sstevel@tonic-gate * 6160*7c478bd9Sstevel@tonic-gate * Input: 6161*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 6162*7c478bd9Sstevel@tonic-gate * Output: 6163*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 6164*7c478bd9Sstevel@tonic-gate * 1 - Error. 6165*7c478bd9Sstevel@tonic-gate */ 6166*7c478bd9Sstevel@tonic-gate static int _gl_bind_arrow_keys(GetLine *gl) 6167*7c478bd9Sstevel@tonic-gate { 6168*7c478bd9Sstevel@tonic-gate /* 6169*7c478bd9Sstevel@tonic-gate * Process each of the arrow keys. 6170*7c478bd9Sstevel@tonic-gate */ 6171*7c478bd9Sstevel@tonic-gate if(_gl_rebind_arrow_key(gl, "up", gl->u_arrow, "^[[A", "^[OA") || 6172*7c478bd9Sstevel@tonic-gate _gl_rebind_arrow_key(gl, "down", gl->d_arrow, "^[[B", "^[OB") || 6173*7c478bd9Sstevel@tonic-gate _gl_rebind_arrow_key(gl, "left", gl->l_arrow, "^[[D", "^[OD") || 6174*7c478bd9Sstevel@tonic-gate _gl_rebind_arrow_key(gl, "right", gl->r_arrow, "^[[C", "^[OC")) 6175*7c478bd9Sstevel@tonic-gate return 1; 6176*7c478bd9Sstevel@tonic-gate return 0; 6177*7c478bd9Sstevel@tonic-gate } 6178*7c478bd9Sstevel@tonic-gate 6179*7c478bd9Sstevel@tonic-gate /*....................................................................... 6180*7c478bd9Sstevel@tonic-gate * Lookup the action function of a symbolic arrow-key binding, and bind 6181*7c478bd9Sstevel@tonic-gate * it to the terminal-specific and default arrow-key sequences. Note that 6182*7c478bd9Sstevel@tonic-gate * we don't trust the terminal-specified key sequences to be correct. 6183*7c478bd9Sstevel@tonic-gate * The main reason for this is that on some machines the xterm terminfo 6184*7c478bd9Sstevel@tonic-gate * entry is for hardware X-terminals, rather than xterm terminal emulators 6185*7c478bd9Sstevel@tonic-gate * and the two terminal types emit different character sequences when the 6186*7c478bd9Sstevel@tonic-gate * their cursor keys are pressed. As a result we also supply a couple 6187*7c478bd9Sstevel@tonic-gate * of default key sequences. 6188*7c478bd9Sstevel@tonic-gate * 6189*7c478bd9Sstevel@tonic-gate * Input: 6190*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 6191*7c478bd9Sstevel@tonic-gate * name char * The symbolic name of the arrow key. 6192*7c478bd9Sstevel@tonic-gate * term_seq char * The terminal-specific arrow-key sequence. 6193*7c478bd9Sstevel@tonic-gate * def_seq1 char * The first default arrow-key sequence. 6194*7c478bd9Sstevel@tonic-gate * def_seq2 char * The second arrow-key sequence. 6195*7c478bd9Sstevel@tonic-gate * Output: 6196*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 6197*7c478bd9Sstevel@tonic-gate * 1 - Error. 6198*7c478bd9Sstevel@tonic-gate */ 6199*7c478bd9Sstevel@tonic-gate static int _gl_rebind_arrow_key(GetLine *gl, const char *name, 6200*7c478bd9Sstevel@tonic-gate const char *term_seq, const char *def_seq1, 6201*7c478bd9Sstevel@tonic-gate const char *def_seq2) 6202*7c478bd9Sstevel@tonic-gate { 6203*7c478bd9Sstevel@tonic-gate KeySym *keysym; /* The binding-table entry matching the arrow-key name */ 6204*7c478bd9Sstevel@tonic-gate int nsym; /* The number of ambiguous matches */ 6205*7c478bd9Sstevel@tonic-gate /* 6206*7c478bd9Sstevel@tonic-gate * Lookup the key binding for the symbolic name of the arrow key. This 6207*7c478bd9Sstevel@tonic-gate * will either be the default action, or a user provided one. 6208*7c478bd9Sstevel@tonic-gate */ 6209*7c478bd9Sstevel@tonic-gate if(_kt_lookup_keybinding(gl->bindings, name, strlen(name), &keysym, &nsym) 6210*7c478bd9Sstevel@tonic-gate == KT_EXACT_MATCH) { 6211*7c478bd9Sstevel@tonic-gate /* 6212*7c478bd9Sstevel@tonic-gate * Get the action function. 6213*7c478bd9Sstevel@tonic-gate */ 6214*7c478bd9Sstevel@tonic-gate KtAction *action = keysym->actions + keysym->binder; 6215*7c478bd9Sstevel@tonic-gate KtKeyFn *fn = action->fn; 6216*7c478bd9Sstevel@tonic-gate void *data = action->data; 6217*7c478bd9Sstevel@tonic-gate /* 6218*7c478bd9Sstevel@tonic-gate * Bind this to each of the specified key sequences. 6219*7c478bd9Sstevel@tonic-gate */ 6220*7c478bd9Sstevel@tonic-gate if((term_seq && 6221*7c478bd9Sstevel@tonic-gate _kt_set_keyfn(gl->bindings, KTB_TERM, term_seq, fn, data)) || 6222*7c478bd9Sstevel@tonic-gate (def_seq1 && 6223*7c478bd9Sstevel@tonic-gate _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq1, fn, data)) || 6224*7c478bd9Sstevel@tonic-gate (def_seq2 && 6225*7c478bd9Sstevel@tonic-gate _kt_set_keyfn(gl->bindings, KTB_NORM, def_seq2, fn, data))) { 6226*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG); 6227*7c478bd9Sstevel@tonic-gate return 1; 6228*7c478bd9Sstevel@tonic-gate }; 6229*7c478bd9Sstevel@tonic-gate }; 6230*7c478bd9Sstevel@tonic-gate return 0; 6231*7c478bd9Sstevel@tonic-gate } 6232*7c478bd9Sstevel@tonic-gate 6233*7c478bd9Sstevel@tonic-gate /*....................................................................... 6234*7c478bd9Sstevel@tonic-gate * Read getline configuration information from a given file. 6235*7c478bd9Sstevel@tonic-gate * 6236*7c478bd9Sstevel@tonic-gate * Input: 6237*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 6238*7c478bd9Sstevel@tonic-gate * filename const char * The name of the file to read configuration 6239*7c478bd9Sstevel@tonic-gate * information from. The contents of this file 6240*7c478bd9Sstevel@tonic-gate * are as described in the gl_get_line(3) man 6241*7c478bd9Sstevel@tonic-gate * page for the default ~/.teclarc configuration 6242*7c478bd9Sstevel@tonic-gate * file. 6243*7c478bd9Sstevel@tonic-gate * who KtBinder Who bindings are to be installed for. 6244*7c478bd9Sstevel@tonic-gate * Output: 6245*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 6246*7c478bd9Sstevel@tonic-gate * 1 - Irrecoverable error. 6247*7c478bd9Sstevel@tonic-gate */ 6248*7c478bd9Sstevel@tonic-gate static int _gl_read_config_file(GetLine *gl, const char *filename, KtBinder who) 6249*7c478bd9Sstevel@tonic-gate { 6250*7c478bd9Sstevel@tonic-gate /* 6251*7c478bd9Sstevel@tonic-gate * If filesystem access is to be excluded, configuration files can't 6252*7c478bd9Sstevel@tonic-gate * be read. 6253*7c478bd9Sstevel@tonic-gate */ 6254*7c478bd9Sstevel@tonic-gate #ifdef WITHOUT_FILE_SYSTEM 6255*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, 6256*7c478bd9Sstevel@tonic-gate "Can't read configuration files without filesystem access", 6257*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 6258*7c478bd9Sstevel@tonic-gate errno = EINVAL; 6259*7c478bd9Sstevel@tonic-gate return 1; 6260*7c478bd9Sstevel@tonic-gate #else 6261*7c478bd9Sstevel@tonic-gate FileExpansion *expansion; /* The expansion of the filename */ 6262*7c478bd9Sstevel@tonic-gate FILE *fp; /* The opened file */ 6263*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True if an error occurred while reading */ 6264*7c478bd9Sstevel@tonic-gate int lineno = 1; /* The line number being processed */ 6265*7c478bd9Sstevel@tonic-gate /* 6266*7c478bd9Sstevel@tonic-gate * Check the arguments. 6267*7c478bd9Sstevel@tonic-gate */ 6268*7c478bd9Sstevel@tonic-gate if(!gl || !filename) { 6269*7c478bd9Sstevel@tonic-gate if(gl) 6270*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG); 6271*7c478bd9Sstevel@tonic-gate errno = EINVAL; 6272*7c478bd9Sstevel@tonic-gate return 1; 6273*7c478bd9Sstevel@tonic-gate }; 6274*7c478bd9Sstevel@tonic-gate /* 6275*7c478bd9Sstevel@tonic-gate * Expand the filename. 6276*7c478bd9Sstevel@tonic-gate */ 6277*7c478bd9Sstevel@tonic-gate expansion = ef_expand_file(gl->ef, filename, -1); 6278*7c478bd9Sstevel@tonic-gate if(!expansion) { 6279*7c478bd9Sstevel@tonic-gate gl_print_info(gl, "Unable to expand ", filename, " (", 6280*7c478bd9Sstevel@tonic-gate ef_last_error(gl->ef), ").", GL_END_INFO); 6281*7c478bd9Sstevel@tonic-gate return 1; 6282*7c478bd9Sstevel@tonic-gate }; 6283*7c478bd9Sstevel@tonic-gate /* 6284*7c478bd9Sstevel@tonic-gate * Attempt to open the file. 6285*7c478bd9Sstevel@tonic-gate */ 6286*7c478bd9Sstevel@tonic-gate fp = fopen(expansion->files[0], "r"); 6287*7c478bd9Sstevel@tonic-gate /* 6288*7c478bd9Sstevel@tonic-gate * It isn't an error for there to be no configuration file. 6289*7c478bd9Sstevel@tonic-gate */ 6290*7c478bd9Sstevel@tonic-gate if(!fp) 6291*7c478bd9Sstevel@tonic-gate return 0; 6292*7c478bd9Sstevel@tonic-gate /* 6293*7c478bd9Sstevel@tonic-gate * Parse the contents of the file. 6294*7c478bd9Sstevel@tonic-gate */ 6295*7c478bd9Sstevel@tonic-gate while(!waserr && !feof(fp)) 6296*7c478bd9Sstevel@tonic-gate waserr = _gl_parse_config_line(gl, fp, glc_file_getc, filename, who, 6297*7c478bd9Sstevel@tonic-gate &lineno); 6298*7c478bd9Sstevel@tonic-gate /* 6299*7c478bd9Sstevel@tonic-gate * Bind action functions to the terminal-specific arrow keys. 6300*7c478bd9Sstevel@tonic-gate */ 6301*7c478bd9Sstevel@tonic-gate if(_gl_bind_arrow_keys(gl)) 6302*7c478bd9Sstevel@tonic-gate return 1; 6303*7c478bd9Sstevel@tonic-gate /* 6304*7c478bd9Sstevel@tonic-gate * Clean up. 6305*7c478bd9Sstevel@tonic-gate */ 6306*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 6307*7c478bd9Sstevel@tonic-gate return waserr; 6308*7c478bd9Sstevel@tonic-gate #endif 6309*7c478bd9Sstevel@tonic-gate } 6310*7c478bd9Sstevel@tonic-gate 6311*7c478bd9Sstevel@tonic-gate /*....................................................................... 6312*7c478bd9Sstevel@tonic-gate * Read GetLine configuration information from a string. The contents of 6313*7c478bd9Sstevel@tonic-gate * the string are the same as those described in the gl_get_line(3) 6314*7c478bd9Sstevel@tonic-gate * man page for the contents of the ~/.teclarc configuration file. 6315*7c478bd9Sstevel@tonic-gate */ 6316*7c478bd9Sstevel@tonic-gate static int _gl_read_config_string(GetLine *gl, const char *buffer, KtBinder who) 6317*7c478bd9Sstevel@tonic-gate { 6318*7c478bd9Sstevel@tonic-gate const char *bptr; /* A pointer into buffer[] */ 6319*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True if an error occurred while reading */ 6320*7c478bd9Sstevel@tonic-gate int lineno = 1; /* The line number being processed */ 6321*7c478bd9Sstevel@tonic-gate /* 6322*7c478bd9Sstevel@tonic-gate * Check the arguments. 6323*7c478bd9Sstevel@tonic-gate */ 6324*7c478bd9Sstevel@tonic-gate if(!gl || !buffer) { 6325*7c478bd9Sstevel@tonic-gate if(gl) 6326*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG); 6327*7c478bd9Sstevel@tonic-gate errno = EINVAL; 6328*7c478bd9Sstevel@tonic-gate return 1; 6329*7c478bd9Sstevel@tonic-gate }; 6330*7c478bd9Sstevel@tonic-gate /* 6331*7c478bd9Sstevel@tonic-gate * Get a pointer to the start of the buffer. 6332*7c478bd9Sstevel@tonic-gate */ 6333*7c478bd9Sstevel@tonic-gate bptr = buffer; 6334*7c478bd9Sstevel@tonic-gate /* 6335*7c478bd9Sstevel@tonic-gate * Parse the contents of the buffer. 6336*7c478bd9Sstevel@tonic-gate */ 6337*7c478bd9Sstevel@tonic-gate while(!waserr && *bptr) 6338*7c478bd9Sstevel@tonic-gate waserr = _gl_parse_config_line(gl, &bptr, glc_buff_getc, "", who, &lineno); 6339*7c478bd9Sstevel@tonic-gate /* 6340*7c478bd9Sstevel@tonic-gate * Bind action functions to the terminal-specific arrow keys. 6341*7c478bd9Sstevel@tonic-gate */ 6342*7c478bd9Sstevel@tonic-gate if(_gl_bind_arrow_keys(gl)) 6343*7c478bd9Sstevel@tonic-gate return 1; 6344*7c478bd9Sstevel@tonic-gate return waserr; 6345*7c478bd9Sstevel@tonic-gate } 6346*7c478bd9Sstevel@tonic-gate 6347*7c478bd9Sstevel@tonic-gate /*....................................................................... 6348*7c478bd9Sstevel@tonic-gate * Parse the next line of a getline configuration file. 6349*7c478bd9Sstevel@tonic-gate * 6350*7c478bd9Sstevel@tonic-gate * Input: 6351*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 6352*7c478bd9Sstevel@tonic-gate * stream void * The pointer representing the stream to be read 6353*7c478bd9Sstevel@tonic-gate * by getc_fn(). 6354*7c478bd9Sstevel@tonic-gate * getc_fn GlcGetcFn * A callback function which when called with 6355*7c478bd9Sstevel@tonic-gate * 'stream' as its argument, returns the next 6356*7c478bd9Sstevel@tonic-gate * unread character from the stream. 6357*7c478bd9Sstevel@tonic-gate * origin const char * The name of the entity being read (eg. a 6358*7c478bd9Sstevel@tonic-gate * file name). 6359*7c478bd9Sstevel@tonic-gate * who KtBinder Who bindings are to be installed for. 6360*7c478bd9Sstevel@tonic-gate * Input/Output: 6361*7c478bd9Sstevel@tonic-gate * lineno int * The line number being processed is to be 6362*7c478bd9Sstevel@tonic-gate * maintained in *lineno. 6363*7c478bd9Sstevel@tonic-gate * Output: 6364*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 6365*7c478bd9Sstevel@tonic-gate * 1 - Irrecoverable error. 6366*7c478bd9Sstevel@tonic-gate */ 6367*7c478bd9Sstevel@tonic-gate static int _gl_parse_config_line(GetLine *gl, void *stream, GlcGetcFn *getc_fn, 6368*7c478bd9Sstevel@tonic-gate const char *origin, KtBinder who, int *lineno) 6369*7c478bd9Sstevel@tonic-gate { 6370*7c478bd9Sstevel@tonic-gate char buffer[GL_CONF_BUFLEN+1]; /* The input line buffer */ 6371*7c478bd9Sstevel@tonic-gate char *argv[GL_CONF_MAXARG]; /* The argument list */ 6372*7c478bd9Sstevel@tonic-gate int argc = 0; /* The number of arguments in argv[] */ 6373*7c478bd9Sstevel@tonic-gate int c; /* A character from the file */ 6374*7c478bd9Sstevel@tonic-gate int escaped = 0; /* True if the next character is escaped */ 6375*7c478bd9Sstevel@tonic-gate int i; 6376*7c478bd9Sstevel@tonic-gate /* 6377*7c478bd9Sstevel@tonic-gate * Skip spaces and tabs. 6378*7c478bd9Sstevel@tonic-gate */ 6379*7c478bd9Sstevel@tonic-gate do c = getc_fn(stream); while(c==' ' || c=='\t'); 6380*7c478bd9Sstevel@tonic-gate /* 6381*7c478bd9Sstevel@tonic-gate * Comments extend to the end of the line. 6382*7c478bd9Sstevel@tonic-gate */ 6383*7c478bd9Sstevel@tonic-gate if(c=='#') 6384*7c478bd9Sstevel@tonic-gate do c = getc_fn(stream); while(c != '\n' && c != EOF); 6385*7c478bd9Sstevel@tonic-gate /* 6386*7c478bd9Sstevel@tonic-gate * Ignore empty lines. 6387*7c478bd9Sstevel@tonic-gate */ 6388*7c478bd9Sstevel@tonic-gate if(c=='\n' || c==EOF) { 6389*7c478bd9Sstevel@tonic-gate (*lineno)++; 6390*7c478bd9Sstevel@tonic-gate return 0; 6391*7c478bd9Sstevel@tonic-gate }; 6392*7c478bd9Sstevel@tonic-gate /* 6393*7c478bd9Sstevel@tonic-gate * Record the buffer location of the start of the first argument. 6394*7c478bd9Sstevel@tonic-gate */ 6395*7c478bd9Sstevel@tonic-gate argv[argc] = buffer; 6396*7c478bd9Sstevel@tonic-gate /* 6397*7c478bd9Sstevel@tonic-gate * Read the rest of the line, stopping early if a comment is seen, or 6398*7c478bd9Sstevel@tonic-gate * the buffer overflows, and replacing sequences of spaces with a 6399*7c478bd9Sstevel@tonic-gate * '\0', and recording the thus terminated string as an argument. 6400*7c478bd9Sstevel@tonic-gate */ 6401*7c478bd9Sstevel@tonic-gate i = 0; 6402*7c478bd9Sstevel@tonic-gate while(i<GL_CONF_BUFLEN) { 6403*7c478bd9Sstevel@tonic-gate /* 6404*7c478bd9Sstevel@tonic-gate * Did we hit the end of the latest argument? 6405*7c478bd9Sstevel@tonic-gate */ 6406*7c478bd9Sstevel@tonic-gate if(c==EOF || (!escaped && (c==' ' || c=='\n' || c=='\t' || c=='#'))) { 6407*7c478bd9Sstevel@tonic-gate /* 6408*7c478bd9Sstevel@tonic-gate * Terminate the argument. 6409*7c478bd9Sstevel@tonic-gate */ 6410*7c478bd9Sstevel@tonic-gate buffer[i++] = '\0'; 6411*7c478bd9Sstevel@tonic-gate argc++; 6412*7c478bd9Sstevel@tonic-gate /* 6413*7c478bd9Sstevel@tonic-gate * Skip spaces and tabs. 6414*7c478bd9Sstevel@tonic-gate */ 6415*7c478bd9Sstevel@tonic-gate while(c==' ' || c=='\t') 6416*7c478bd9Sstevel@tonic-gate c = getc_fn(stream); 6417*7c478bd9Sstevel@tonic-gate /* 6418*7c478bd9Sstevel@tonic-gate * If we hit the end of the line, or the start of a comment, exit the loop. 6419*7c478bd9Sstevel@tonic-gate */ 6420*7c478bd9Sstevel@tonic-gate if(c==EOF || c=='\n' || c=='#') 6421*7c478bd9Sstevel@tonic-gate break; 6422*7c478bd9Sstevel@tonic-gate /* 6423*7c478bd9Sstevel@tonic-gate * Start recording the next argument. 6424*7c478bd9Sstevel@tonic-gate */ 6425*7c478bd9Sstevel@tonic-gate if(argc >= GL_CONF_MAXARG) { 6426*7c478bd9Sstevel@tonic-gate gl_report_config_error(gl, origin, *lineno, "Too many arguments."); 6427*7c478bd9Sstevel@tonic-gate do c = getc_fn(stream); while(c!='\n' && c!=EOF); /* Skip past eol */ 6428*7c478bd9Sstevel@tonic-gate return 0; 6429*7c478bd9Sstevel@tonic-gate }; 6430*7c478bd9Sstevel@tonic-gate argv[argc] = buffer + i; 6431*7c478bd9Sstevel@tonic-gate /* 6432*7c478bd9Sstevel@tonic-gate * The next character was preceded by spaces, so it isn't escaped. 6433*7c478bd9Sstevel@tonic-gate */ 6434*7c478bd9Sstevel@tonic-gate escaped = 0; 6435*7c478bd9Sstevel@tonic-gate } else { 6436*7c478bd9Sstevel@tonic-gate /* 6437*7c478bd9Sstevel@tonic-gate * If we hit an unescaped backslash, this means that we should arrange 6438*7c478bd9Sstevel@tonic-gate * to treat the next character like a simple alphabetical character. 6439*7c478bd9Sstevel@tonic-gate */ 6440*7c478bd9Sstevel@tonic-gate if(c=='\\' && !escaped) { 6441*7c478bd9Sstevel@tonic-gate escaped = 1; 6442*7c478bd9Sstevel@tonic-gate /* 6443*7c478bd9Sstevel@tonic-gate * Splice lines where the newline is escaped. 6444*7c478bd9Sstevel@tonic-gate */ 6445*7c478bd9Sstevel@tonic-gate } else if(c=='\n' && escaped) { 6446*7c478bd9Sstevel@tonic-gate (*lineno)++; 6447*7c478bd9Sstevel@tonic-gate /* 6448*7c478bd9Sstevel@tonic-gate * Record a normal character, preserving any preceding backslash. 6449*7c478bd9Sstevel@tonic-gate */ 6450*7c478bd9Sstevel@tonic-gate } else { 6451*7c478bd9Sstevel@tonic-gate if(escaped) 6452*7c478bd9Sstevel@tonic-gate buffer[i++] = '\\'; 6453*7c478bd9Sstevel@tonic-gate if(i>=GL_CONF_BUFLEN) 6454*7c478bd9Sstevel@tonic-gate break; 6455*7c478bd9Sstevel@tonic-gate escaped = 0; 6456*7c478bd9Sstevel@tonic-gate buffer[i++] = c; 6457*7c478bd9Sstevel@tonic-gate }; 6458*7c478bd9Sstevel@tonic-gate /* 6459*7c478bd9Sstevel@tonic-gate * Get the next character. 6460*7c478bd9Sstevel@tonic-gate */ 6461*7c478bd9Sstevel@tonic-gate c = getc_fn(stream); 6462*7c478bd9Sstevel@tonic-gate }; 6463*7c478bd9Sstevel@tonic-gate }; 6464*7c478bd9Sstevel@tonic-gate /* 6465*7c478bd9Sstevel@tonic-gate * Did the buffer overflow? 6466*7c478bd9Sstevel@tonic-gate */ 6467*7c478bd9Sstevel@tonic-gate if(i>=GL_CONF_BUFLEN) { 6468*7c478bd9Sstevel@tonic-gate gl_report_config_error(gl, origin, *lineno, "Line too long."); 6469*7c478bd9Sstevel@tonic-gate return 0; 6470*7c478bd9Sstevel@tonic-gate }; 6471*7c478bd9Sstevel@tonic-gate /* 6472*7c478bd9Sstevel@tonic-gate * The first argument should be a command name. 6473*7c478bd9Sstevel@tonic-gate */ 6474*7c478bd9Sstevel@tonic-gate if(strcmp(argv[0], "bind") == 0) { 6475*7c478bd9Sstevel@tonic-gate const char *action = NULL; /* A NULL action removes a keybinding */ 6476*7c478bd9Sstevel@tonic-gate const char *keyseq = NULL; 6477*7c478bd9Sstevel@tonic-gate switch(argc) { 6478*7c478bd9Sstevel@tonic-gate case 3: 6479*7c478bd9Sstevel@tonic-gate action = argv[2]; 6480*7c478bd9Sstevel@tonic-gate case 2: /* Note the intentional fallthrough */ 6481*7c478bd9Sstevel@tonic-gate keyseq = argv[1]; 6482*7c478bd9Sstevel@tonic-gate /* 6483*7c478bd9Sstevel@tonic-gate * Attempt to record the new keybinding. 6484*7c478bd9Sstevel@tonic-gate */ 6485*7c478bd9Sstevel@tonic-gate if(_kt_set_keybinding(gl->bindings, who, keyseq, action)) { 6486*7c478bd9Sstevel@tonic-gate gl_report_config_error(gl, origin, *lineno, 6487*7c478bd9Sstevel@tonic-gate _kt_last_error(gl->bindings)); 6488*7c478bd9Sstevel@tonic-gate }; 6489*7c478bd9Sstevel@tonic-gate break; 6490*7c478bd9Sstevel@tonic-gate default: 6491*7c478bd9Sstevel@tonic-gate gl_report_config_error(gl, origin, *lineno, "Wrong number of arguments."); 6492*7c478bd9Sstevel@tonic-gate }; 6493*7c478bd9Sstevel@tonic-gate } else if(strcmp(argv[0], "edit-mode") == 0) { 6494*7c478bd9Sstevel@tonic-gate if(argc == 2 && strcmp(argv[1], "emacs") == 0) { 6495*7c478bd9Sstevel@tonic-gate gl_change_editor(gl, GL_EMACS_MODE); 6496*7c478bd9Sstevel@tonic-gate } else if(argc == 2 && strcmp(argv[1], "vi") == 0) { 6497*7c478bd9Sstevel@tonic-gate gl_change_editor(gl, GL_VI_MODE); 6498*7c478bd9Sstevel@tonic-gate } else if(argc == 2 && strcmp(argv[1], "none") == 0) { 6499*7c478bd9Sstevel@tonic-gate gl_change_editor(gl, GL_NO_EDITOR); 6500*7c478bd9Sstevel@tonic-gate } else { 6501*7c478bd9Sstevel@tonic-gate gl_report_config_error(gl, origin, *lineno, 6502*7c478bd9Sstevel@tonic-gate "The argument of editor should be vi or emacs."); 6503*7c478bd9Sstevel@tonic-gate }; 6504*7c478bd9Sstevel@tonic-gate } else if(strcmp(argv[0], "nobeep") == 0) { 6505*7c478bd9Sstevel@tonic-gate gl->silence_bell = 1; 6506*7c478bd9Sstevel@tonic-gate } else { 6507*7c478bd9Sstevel@tonic-gate gl_report_config_error(gl, origin, *lineno, "Unknown command name."); 6508*7c478bd9Sstevel@tonic-gate }; 6509*7c478bd9Sstevel@tonic-gate /* 6510*7c478bd9Sstevel@tonic-gate * Skip any trailing comment. 6511*7c478bd9Sstevel@tonic-gate */ 6512*7c478bd9Sstevel@tonic-gate while(c != '\n' && c != EOF) 6513*7c478bd9Sstevel@tonic-gate c = getc_fn(stream); 6514*7c478bd9Sstevel@tonic-gate (*lineno)++; 6515*7c478bd9Sstevel@tonic-gate return 0; 6516*7c478bd9Sstevel@tonic-gate } 6517*7c478bd9Sstevel@tonic-gate 6518*7c478bd9Sstevel@tonic-gate /*....................................................................... 6519*7c478bd9Sstevel@tonic-gate * This is a private function of _gl_parse_config_line() which prints 6520*7c478bd9Sstevel@tonic-gate * out an error message about the contents of the line, prefixed by the 6521*7c478bd9Sstevel@tonic-gate * name of the origin of the line and its line number. 6522*7c478bd9Sstevel@tonic-gate * 6523*7c478bd9Sstevel@tonic-gate * Input: 6524*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 6525*7c478bd9Sstevel@tonic-gate * origin const char * The name of the entity being read (eg. a 6526*7c478bd9Sstevel@tonic-gate * file name). 6527*7c478bd9Sstevel@tonic-gate * lineno int The line number at which the error occurred. 6528*7c478bd9Sstevel@tonic-gate * errmsg const char * The error message. 6529*7c478bd9Sstevel@tonic-gate * Output: 6530*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 6531*7c478bd9Sstevel@tonic-gate * 1 - Error. 6532*7c478bd9Sstevel@tonic-gate */ 6533*7c478bd9Sstevel@tonic-gate static int gl_report_config_error(GetLine *gl, const char *origin, int lineno, 6534*7c478bd9Sstevel@tonic-gate const char *errmsg) 6535*7c478bd9Sstevel@tonic-gate { 6536*7c478bd9Sstevel@tonic-gate char lnum[20]; /* A buffer in which to render a single integer */ 6537*7c478bd9Sstevel@tonic-gate /* 6538*7c478bd9Sstevel@tonic-gate * Convert the line number into a string. 6539*7c478bd9Sstevel@tonic-gate */ 6540*7c478bd9Sstevel@tonic-gate snprintf(lnum, sizeof(lnum), "%d", lineno); 6541*7c478bd9Sstevel@tonic-gate /* 6542*7c478bd9Sstevel@tonic-gate * Have the string printed on the terminal. 6543*7c478bd9Sstevel@tonic-gate */ 6544*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, origin, ":", lnum, ": ", errmsg, GL_END_INFO); 6545*7c478bd9Sstevel@tonic-gate } 6546*7c478bd9Sstevel@tonic-gate 6547*7c478bd9Sstevel@tonic-gate /*....................................................................... 6548*7c478bd9Sstevel@tonic-gate * This is the _gl_parse_config_line() callback function which reads the 6549*7c478bd9Sstevel@tonic-gate * next character from a configuration file. 6550*7c478bd9Sstevel@tonic-gate */ 6551*7c478bd9Sstevel@tonic-gate static GLC_GETC_FN(glc_file_getc) 6552*7c478bd9Sstevel@tonic-gate { 6553*7c478bd9Sstevel@tonic-gate return fgetc((FILE *) stream); 6554*7c478bd9Sstevel@tonic-gate } 6555*7c478bd9Sstevel@tonic-gate 6556*7c478bd9Sstevel@tonic-gate /*....................................................................... 6557*7c478bd9Sstevel@tonic-gate * This is the _gl_parse_config_line() callback function which reads the 6558*7c478bd9Sstevel@tonic-gate * next character from a buffer. Its stream argument is a pointer to a 6559*7c478bd9Sstevel@tonic-gate * variable which is, in turn, a pointer into the buffer being read from. 6560*7c478bd9Sstevel@tonic-gate */ 6561*7c478bd9Sstevel@tonic-gate static GLC_GETC_FN(glc_buff_getc) 6562*7c478bd9Sstevel@tonic-gate { 6563*7c478bd9Sstevel@tonic-gate const char **lptr = (char const **) stream; 6564*7c478bd9Sstevel@tonic-gate return **lptr ? *(*lptr)++ : EOF; 6565*7c478bd9Sstevel@tonic-gate } 6566*7c478bd9Sstevel@tonic-gate 6567*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 6568*7c478bd9Sstevel@tonic-gate /*....................................................................... 6569*7c478bd9Sstevel@tonic-gate * When this action is triggered, it arranges to temporarily read command 6570*7c478bd9Sstevel@tonic-gate * lines from the regular file whos name precedes the cursor. 6571*7c478bd9Sstevel@tonic-gate * The current line is first discarded. 6572*7c478bd9Sstevel@tonic-gate */ 6573*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_read_from_file) 6574*7c478bd9Sstevel@tonic-gate { 6575*7c478bd9Sstevel@tonic-gate char *start_path; /* The pointer to the start of the pathname in */ 6576*7c478bd9Sstevel@tonic-gate /* gl->line[]. */ 6577*7c478bd9Sstevel@tonic-gate FileExpansion *result; /* The results of the filename expansion */ 6578*7c478bd9Sstevel@tonic-gate int pathlen; /* The length of the pathname being expanded */ 6579*7c478bd9Sstevel@tonic-gate /* 6580*7c478bd9Sstevel@tonic-gate * Locate the start of the filename that precedes the cursor position. 6581*7c478bd9Sstevel@tonic-gate */ 6582*7c478bd9Sstevel@tonic-gate start_path = _pu_start_of_path(gl->line, gl->buff_curpos); 6583*7c478bd9Sstevel@tonic-gate if(!start_path) 6584*7c478bd9Sstevel@tonic-gate return 1; 6585*7c478bd9Sstevel@tonic-gate /* 6586*7c478bd9Sstevel@tonic-gate * Get the length of the pathname string. 6587*7c478bd9Sstevel@tonic-gate */ 6588*7c478bd9Sstevel@tonic-gate pathlen = gl->buff_curpos - (start_path - gl->line); 6589*7c478bd9Sstevel@tonic-gate /* 6590*7c478bd9Sstevel@tonic-gate * Attempt to expand the pathname. 6591*7c478bd9Sstevel@tonic-gate */ 6592*7c478bd9Sstevel@tonic-gate result = ef_expand_file(gl->ef, start_path, pathlen); 6593*7c478bd9Sstevel@tonic-gate /* 6594*7c478bd9Sstevel@tonic-gate * If there was an error, report the error on a new line. 6595*7c478bd9Sstevel@tonic-gate */ 6596*7c478bd9Sstevel@tonic-gate if(!result) { 6597*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, ef_last_error(gl->ef), GL_END_INFO); 6598*7c478bd9Sstevel@tonic-gate /* 6599*7c478bd9Sstevel@tonic-gate * If no files matched, report this as well. 6600*7c478bd9Sstevel@tonic-gate */ 6601*7c478bd9Sstevel@tonic-gate } else if(result->nfile == 0 || !result->exists) { 6602*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, "No files match.", GL_END_INFO); 6603*7c478bd9Sstevel@tonic-gate /* 6604*7c478bd9Sstevel@tonic-gate * Complain if more than one file matches. 6605*7c478bd9Sstevel@tonic-gate */ 6606*7c478bd9Sstevel@tonic-gate } else if(result->nfile > 1) { 6607*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, "More than one file matches.", GL_END_INFO); 6608*7c478bd9Sstevel@tonic-gate /* 6609*7c478bd9Sstevel@tonic-gate * Disallow input from anything but normal files. In principle we could 6610*7c478bd9Sstevel@tonic-gate * also support input from named pipes. Terminal files would be a problem 6611*7c478bd9Sstevel@tonic-gate * since we wouldn't know the terminal type, and other types of files 6612*7c478bd9Sstevel@tonic-gate * might cause the library to lock up. 6613*7c478bd9Sstevel@tonic-gate */ 6614*7c478bd9Sstevel@tonic-gate } else if(!_pu_path_is_file(result->files[0])) { 6615*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, "Not a normal file.", GL_END_INFO); 6616*7c478bd9Sstevel@tonic-gate } else { 6617*7c478bd9Sstevel@tonic-gate /* 6618*7c478bd9Sstevel@tonic-gate * Attempt to open and install the specified file for reading. 6619*7c478bd9Sstevel@tonic-gate */ 6620*7c478bd9Sstevel@tonic-gate gl->file_fp = fopen(result->files[0], "r"); 6621*7c478bd9Sstevel@tonic-gate if(!gl->file_fp) { 6622*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, "Unable to open: ", result->files[0], 6623*7c478bd9Sstevel@tonic-gate GL_END_INFO); 6624*7c478bd9Sstevel@tonic-gate }; 6625*7c478bd9Sstevel@tonic-gate /* 6626*7c478bd9Sstevel@tonic-gate * If needed, expand the record of the maximum file-descriptor that might 6627*7c478bd9Sstevel@tonic-gate * need to be monitored with select(). 6628*7c478bd9Sstevel@tonic-gate */ 6629*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SELECT 6630*7c478bd9Sstevel@tonic-gate if(fileno(gl->file_fp) > gl->max_fd) 6631*7c478bd9Sstevel@tonic-gate gl->max_fd = fileno(gl->file_fp); 6632*7c478bd9Sstevel@tonic-gate #endif 6633*7c478bd9Sstevel@tonic-gate /* 6634*7c478bd9Sstevel@tonic-gate * Is non-blocking I/O needed? 6635*7c478bd9Sstevel@tonic-gate */ 6636*7c478bd9Sstevel@tonic-gate if(gl->raw_mode && gl->io_mode==GL_SERVER_MODE && 6637*7c478bd9Sstevel@tonic-gate gl_nonblocking_io(gl, fileno(gl->file_fp))) { 6638*7c478bd9Sstevel@tonic-gate gl_revert_input(gl); 6639*7c478bd9Sstevel@tonic-gate return gl_print_info(gl, "Can't read file %s with non-blocking I/O", 6640*7c478bd9Sstevel@tonic-gate result->files[0]); 6641*7c478bd9Sstevel@tonic-gate }; 6642*7c478bd9Sstevel@tonic-gate /* 6643*7c478bd9Sstevel@tonic-gate * Inform the user what is happening. 6644*7c478bd9Sstevel@tonic-gate */ 6645*7c478bd9Sstevel@tonic-gate if(gl_print_info(gl, "<Taking input from ", result->files[0], ">", 6646*7c478bd9Sstevel@tonic-gate GL_END_INFO)) 6647*7c478bd9Sstevel@tonic-gate return 1; 6648*7c478bd9Sstevel@tonic-gate }; 6649*7c478bd9Sstevel@tonic-gate return 0; 6650*7c478bd9Sstevel@tonic-gate } 6651*7c478bd9Sstevel@tonic-gate #endif 6652*7c478bd9Sstevel@tonic-gate 6653*7c478bd9Sstevel@tonic-gate /*....................................................................... 6654*7c478bd9Sstevel@tonic-gate * Close any temporary file that is being used for input. 6655*7c478bd9Sstevel@tonic-gate * 6656*7c478bd9Sstevel@tonic-gate * Input: 6657*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 6658*7c478bd9Sstevel@tonic-gate */ 6659*7c478bd9Sstevel@tonic-gate static void gl_revert_input(GetLine *gl) 6660*7c478bd9Sstevel@tonic-gate { 6661*7c478bd9Sstevel@tonic-gate if(gl->file_fp) 6662*7c478bd9Sstevel@tonic-gate fclose(gl->file_fp); 6663*7c478bd9Sstevel@tonic-gate gl->file_fp = NULL; 6664*7c478bd9Sstevel@tonic-gate gl->endline = 1; 6665*7c478bd9Sstevel@tonic-gate } 6666*7c478bd9Sstevel@tonic-gate 6667*7c478bd9Sstevel@tonic-gate /*....................................................................... 6668*7c478bd9Sstevel@tonic-gate * This is the action function that recalls the oldest line in the 6669*7c478bd9Sstevel@tonic-gate * history buffer. 6670*7c478bd9Sstevel@tonic-gate */ 6671*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_beginning_of_history) 6672*7c478bd9Sstevel@tonic-gate { 6673*7c478bd9Sstevel@tonic-gate /* 6674*7c478bd9Sstevel@tonic-gate * In vi mode, switch to command mode, since the user is very 6675*7c478bd9Sstevel@tonic-gate * likely to want to move around newly recalled lines. 6676*7c478bd9Sstevel@tonic-gate */ 6677*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 6678*7c478bd9Sstevel@tonic-gate /* 6679*7c478bd9Sstevel@tonic-gate * Forget any previous recall session. 6680*7c478bd9Sstevel@tonic-gate */ 6681*7c478bd9Sstevel@tonic-gate gl->preload_id = 0; 6682*7c478bd9Sstevel@tonic-gate /* 6683*7c478bd9Sstevel@tonic-gate * Record the key sequence number of this search action. 6684*7c478bd9Sstevel@tonic-gate */ 6685*7c478bd9Sstevel@tonic-gate gl->last_search = gl->keyseq_count; 6686*7c478bd9Sstevel@tonic-gate /* 6687*7c478bd9Sstevel@tonic-gate * Recall the next oldest line in the history list. 6688*7c478bd9Sstevel@tonic-gate */ 6689*7c478bd9Sstevel@tonic-gate if(_glh_oldest_line(gl->glh, gl->line, gl->linelen+1) == NULL) 6690*7c478bd9Sstevel@tonic-gate return 0; 6691*7c478bd9Sstevel@tonic-gate /* 6692*7c478bd9Sstevel@tonic-gate * Accomodate the new contents of gl->line[]. 6693*7c478bd9Sstevel@tonic-gate */ 6694*7c478bd9Sstevel@tonic-gate gl_update_buffer(gl); 6695*7c478bd9Sstevel@tonic-gate /* 6696*7c478bd9Sstevel@tonic-gate * Arrange to have the cursor placed at the end of the new line. 6697*7c478bd9Sstevel@tonic-gate */ 6698*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->ntotal; 6699*7c478bd9Sstevel@tonic-gate /* 6700*7c478bd9Sstevel@tonic-gate * Erase and display the new line. 6701*7c478bd9Sstevel@tonic-gate */ 6702*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 6703*7c478bd9Sstevel@tonic-gate return 0; 6704*7c478bd9Sstevel@tonic-gate } 6705*7c478bd9Sstevel@tonic-gate 6706*7c478bd9Sstevel@tonic-gate /*....................................................................... 6707*7c478bd9Sstevel@tonic-gate * If a history session is currently in progress, this action function 6708*7c478bd9Sstevel@tonic-gate * recalls the line that was being edited when the session started. If 6709*7c478bd9Sstevel@tonic-gate * no history session is in progress, it does nothing. 6710*7c478bd9Sstevel@tonic-gate */ 6711*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_end_of_history) 6712*7c478bd9Sstevel@tonic-gate { 6713*7c478bd9Sstevel@tonic-gate /* 6714*7c478bd9Sstevel@tonic-gate * In vi mode, switch to command mode, since the user is very 6715*7c478bd9Sstevel@tonic-gate * likely to want to move around newly recalled lines. 6716*7c478bd9Sstevel@tonic-gate */ 6717*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 6718*7c478bd9Sstevel@tonic-gate /* 6719*7c478bd9Sstevel@tonic-gate * Forget any previous recall session. 6720*7c478bd9Sstevel@tonic-gate */ 6721*7c478bd9Sstevel@tonic-gate gl->preload_id = 0; 6722*7c478bd9Sstevel@tonic-gate /* 6723*7c478bd9Sstevel@tonic-gate * Record the key sequence number of this search action. 6724*7c478bd9Sstevel@tonic-gate */ 6725*7c478bd9Sstevel@tonic-gate gl->last_search = gl->keyseq_count; 6726*7c478bd9Sstevel@tonic-gate /* 6727*7c478bd9Sstevel@tonic-gate * Recall the next oldest line in the history list. 6728*7c478bd9Sstevel@tonic-gate */ 6729*7c478bd9Sstevel@tonic-gate if(_glh_current_line(gl->glh, gl->line, gl->linelen+1) == NULL) 6730*7c478bd9Sstevel@tonic-gate return 0; 6731*7c478bd9Sstevel@tonic-gate /* 6732*7c478bd9Sstevel@tonic-gate * Accomodate the new contents of gl->line[]. 6733*7c478bd9Sstevel@tonic-gate */ 6734*7c478bd9Sstevel@tonic-gate gl_update_buffer(gl); 6735*7c478bd9Sstevel@tonic-gate /* 6736*7c478bd9Sstevel@tonic-gate * Arrange to have the cursor placed at the end of the new line. 6737*7c478bd9Sstevel@tonic-gate */ 6738*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->ntotal; 6739*7c478bd9Sstevel@tonic-gate /* 6740*7c478bd9Sstevel@tonic-gate * Erase and display the new line. 6741*7c478bd9Sstevel@tonic-gate */ 6742*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 6743*7c478bd9Sstevel@tonic-gate return 0; 6744*7c478bd9Sstevel@tonic-gate } 6745*7c478bd9Sstevel@tonic-gate 6746*7c478bd9Sstevel@tonic-gate /*....................................................................... 6747*7c478bd9Sstevel@tonic-gate * This action function is treated specially, in that its count argument 6748*7c478bd9Sstevel@tonic-gate * is set to the end keystroke of the keysequence that activated it. 6749*7c478bd9Sstevel@tonic-gate * It accumulates a numeric argument, adding one digit on each call in 6750*7c478bd9Sstevel@tonic-gate * which the last keystroke was a numeric digit. 6751*7c478bd9Sstevel@tonic-gate */ 6752*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_digit_argument) 6753*7c478bd9Sstevel@tonic-gate { 6754*7c478bd9Sstevel@tonic-gate /* 6755*7c478bd9Sstevel@tonic-gate * Was the last keystroke a digit? 6756*7c478bd9Sstevel@tonic-gate */ 6757*7c478bd9Sstevel@tonic-gate int is_digit = isdigit((int)(unsigned char) count); 6758*7c478bd9Sstevel@tonic-gate /* 6759*7c478bd9Sstevel@tonic-gate * In vi command mode, a lone '0' means goto-start-of-line. 6760*7c478bd9Sstevel@tonic-gate */ 6761*7c478bd9Sstevel@tonic-gate if(gl->vi.command && gl->number < 0 && count == '0') 6762*7c478bd9Sstevel@tonic-gate return gl_beginning_of_line(gl, count, NULL); 6763*7c478bd9Sstevel@tonic-gate /* 6764*7c478bd9Sstevel@tonic-gate * Are we starting to accumulate a new number? 6765*7c478bd9Sstevel@tonic-gate */ 6766*7c478bd9Sstevel@tonic-gate if(gl->number < 0 || !is_digit) 6767*7c478bd9Sstevel@tonic-gate gl->number = 0; 6768*7c478bd9Sstevel@tonic-gate /* 6769*7c478bd9Sstevel@tonic-gate * Was the last keystroke a digit? 6770*7c478bd9Sstevel@tonic-gate */ 6771*7c478bd9Sstevel@tonic-gate if(is_digit) { 6772*7c478bd9Sstevel@tonic-gate /* 6773*7c478bd9Sstevel@tonic-gate * Read the numeric value of the digit, without assuming ASCII. 6774*7c478bd9Sstevel@tonic-gate */ 6775*7c478bd9Sstevel@tonic-gate int n; 6776*7c478bd9Sstevel@tonic-gate char s[2]; s[0] = count; s[1] = '\0'; 6777*7c478bd9Sstevel@tonic-gate n = atoi(s); 6778*7c478bd9Sstevel@tonic-gate /* 6779*7c478bd9Sstevel@tonic-gate * Append the new digit. 6780*7c478bd9Sstevel@tonic-gate */ 6781*7c478bd9Sstevel@tonic-gate gl->number = gl->number * 10 + n; 6782*7c478bd9Sstevel@tonic-gate }; 6783*7c478bd9Sstevel@tonic-gate return 0; 6784*7c478bd9Sstevel@tonic-gate } 6785*7c478bd9Sstevel@tonic-gate 6786*7c478bd9Sstevel@tonic-gate /*....................................................................... 6787*7c478bd9Sstevel@tonic-gate * The newline action function sets gl->endline to tell 6788*7c478bd9Sstevel@tonic-gate * gl_get_input_line() that the line is now complete. 6789*7c478bd9Sstevel@tonic-gate */ 6790*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_newline) 6791*7c478bd9Sstevel@tonic-gate { 6792*7c478bd9Sstevel@tonic-gate GlhLineID id; /* The last history line recalled while entering this line */ 6793*7c478bd9Sstevel@tonic-gate /* 6794*7c478bd9Sstevel@tonic-gate * Flag the line as ended. 6795*7c478bd9Sstevel@tonic-gate */ 6796*7c478bd9Sstevel@tonic-gate gl->endline = 1; 6797*7c478bd9Sstevel@tonic-gate /* 6798*7c478bd9Sstevel@tonic-gate * Record the next position in the history buffer, for potential 6799*7c478bd9Sstevel@tonic-gate * recall by an action function on the next call to gl_get_line(). 6800*7c478bd9Sstevel@tonic-gate */ 6801*7c478bd9Sstevel@tonic-gate id = _glh_line_id(gl->glh, 1); 6802*7c478bd9Sstevel@tonic-gate if(id) 6803*7c478bd9Sstevel@tonic-gate gl->preload_id = id; 6804*7c478bd9Sstevel@tonic-gate return 0; 6805*7c478bd9Sstevel@tonic-gate } 6806*7c478bd9Sstevel@tonic-gate 6807*7c478bd9Sstevel@tonic-gate /*....................................................................... 6808*7c478bd9Sstevel@tonic-gate * The 'repeat' action function sets gl->endline to tell 6809*7c478bd9Sstevel@tonic-gate * gl_get_input_line() that the line is now complete, and records the 6810*7c478bd9Sstevel@tonic-gate * ID of the next history line in gl->preload_id so that the next call 6811*7c478bd9Sstevel@tonic-gate * to gl_get_input_line() will preload the line with that history line. 6812*7c478bd9Sstevel@tonic-gate */ 6813*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_repeat_history) 6814*7c478bd9Sstevel@tonic-gate { 6815*7c478bd9Sstevel@tonic-gate gl->endline = 1; 6816*7c478bd9Sstevel@tonic-gate gl->preload_id = _glh_line_id(gl->glh, 1); 6817*7c478bd9Sstevel@tonic-gate gl->preload_history = 1; 6818*7c478bd9Sstevel@tonic-gate return 0; 6819*7c478bd9Sstevel@tonic-gate } 6820*7c478bd9Sstevel@tonic-gate 6821*7c478bd9Sstevel@tonic-gate /*....................................................................... 6822*7c478bd9Sstevel@tonic-gate * Flush unwritten characters to the terminal. 6823*7c478bd9Sstevel@tonic-gate * 6824*7c478bd9Sstevel@tonic-gate * Input: 6825*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 6826*7c478bd9Sstevel@tonic-gate * Output: 6827*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 6828*7c478bd9Sstevel@tonic-gate * 1 - Either an error occured, or the output 6829*7c478bd9Sstevel@tonic-gate * blocked and non-blocking I/O is being used. 6830*7c478bd9Sstevel@tonic-gate * See gl->rtn_status for details. 6831*7c478bd9Sstevel@tonic-gate */ 6832*7c478bd9Sstevel@tonic-gate static int gl_flush_output(GetLine *gl) 6833*7c478bd9Sstevel@tonic-gate { 6834*7c478bd9Sstevel@tonic-gate /* 6835*7c478bd9Sstevel@tonic-gate * Record the fact that we are about to write to the terminal. 6836*7c478bd9Sstevel@tonic-gate */ 6837*7c478bd9Sstevel@tonic-gate gl->pending_io = GLP_WRITE; 6838*7c478bd9Sstevel@tonic-gate /* 6839*7c478bd9Sstevel@tonic-gate * Attempt to flush the output to the terminal. 6840*7c478bd9Sstevel@tonic-gate */ 6841*7c478bd9Sstevel@tonic-gate errno = 0; 6842*7c478bd9Sstevel@tonic-gate switch(_glq_flush_queue(gl->cq, gl->flush_fn, gl)) { 6843*7c478bd9Sstevel@tonic-gate case GLQ_FLUSH_DONE: 6844*7c478bd9Sstevel@tonic-gate return gl->redisplay && !gl->postpone && gl_redisplay(gl, 1, NULL); 6845*7c478bd9Sstevel@tonic-gate break; 6846*7c478bd9Sstevel@tonic-gate case GLQ_FLUSH_AGAIN: /* Output blocked */ 6847*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO); 6848*7c478bd9Sstevel@tonic-gate return 1; 6849*7c478bd9Sstevel@tonic-gate break; 6850*7c478bd9Sstevel@tonic-gate default: /* Abort the line if an error occurs */ 6851*7c478bd9Sstevel@tonic-gate gl_record_status(gl, errno==EINTR ? GLR_SIGNAL : GLR_ERROR, errno); 6852*7c478bd9Sstevel@tonic-gate return 1; 6853*7c478bd9Sstevel@tonic-gate break; 6854*7c478bd9Sstevel@tonic-gate }; 6855*7c478bd9Sstevel@tonic-gate } 6856*7c478bd9Sstevel@tonic-gate 6857*7c478bd9Sstevel@tonic-gate /*....................................................................... 6858*7c478bd9Sstevel@tonic-gate * This is the callback which _glq_flush_queue() uses to write buffered 6859*7c478bd9Sstevel@tonic-gate * characters to the terminal. 6860*7c478bd9Sstevel@tonic-gate */ 6861*7c478bd9Sstevel@tonic-gate static GL_WRITE_FN(gl_flush_terminal) 6862*7c478bd9Sstevel@tonic-gate { 6863*7c478bd9Sstevel@tonic-gate int ndone = 0; /* The number of characters written so far */ 6864*7c478bd9Sstevel@tonic-gate /* 6865*7c478bd9Sstevel@tonic-gate * Get the line-editor resource object. 6866*7c478bd9Sstevel@tonic-gate */ 6867*7c478bd9Sstevel@tonic-gate GetLine *gl = (GetLine *) data; 6868*7c478bd9Sstevel@tonic-gate /* 6869*7c478bd9Sstevel@tonic-gate * Transfer the latest array of characters to stdio. 6870*7c478bd9Sstevel@tonic-gate */ 6871*7c478bd9Sstevel@tonic-gate while(ndone < n) { 6872*7c478bd9Sstevel@tonic-gate int nnew = write(gl->output_fd, s, n-ndone); 6873*7c478bd9Sstevel@tonic-gate /* 6874*7c478bd9Sstevel@tonic-gate * If the write was successful, add to the recorded number of bytes 6875*7c478bd9Sstevel@tonic-gate * that have now been written. 6876*7c478bd9Sstevel@tonic-gate */ 6877*7c478bd9Sstevel@tonic-gate if(nnew > 0) { 6878*7c478bd9Sstevel@tonic-gate ndone += nnew; 6879*7c478bd9Sstevel@tonic-gate /* 6880*7c478bd9Sstevel@tonic-gate * If a signal interrupted the call, restart the write(), since all of 6881*7c478bd9Sstevel@tonic-gate * the signals that gl_get_line() has been told to watch for are 6882*7c478bd9Sstevel@tonic-gate * currently blocked. 6883*7c478bd9Sstevel@tonic-gate */ 6884*7c478bd9Sstevel@tonic-gate } else if(errno == EINTR) { 6885*7c478bd9Sstevel@tonic-gate continue; 6886*7c478bd9Sstevel@tonic-gate /* 6887*7c478bd9Sstevel@tonic-gate * If we managed to write something before an I/O error occurred, or 6888*7c478bd9Sstevel@tonic-gate * output blocked before anything was written, report the number of 6889*7c478bd9Sstevel@tonic-gate * bytes that were successfully written before this happened. 6890*7c478bd9Sstevel@tonic-gate */ 6891*7c478bd9Sstevel@tonic-gate } else if(ndone > 0 6892*7c478bd9Sstevel@tonic-gate #if defined(EAGAIN) 6893*7c478bd9Sstevel@tonic-gate || errno==EAGAIN 6894*7c478bd9Sstevel@tonic-gate #endif 6895*7c478bd9Sstevel@tonic-gate #if defined(EWOULDBLOCK) 6896*7c478bd9Sstevel@tonic-gate || errno==EWOULDBLOCK 6897*7c478bd9Sstevel@tonic-gate #endif 6898*7c478bd9Sstevel@tonic-gate ) { 6899*7c478bd9Sstevel@tonic-gate return ndone; 6900*7c478bd9Sstevel@tonic-gate 6901*7c478bd9Sstevel@tonic-gate /* 6902*7c478bd9Sstevel@tonic-gate * To get here, an error must have occurred before anything new could 6903*7c478bd9Sstevel@tonic-gate * be written. 6904*7c478bd9Sstevel@tonic-gate */ 6905*7c478bd9Sstevel@tonic-gate } else { 6906*7c478bd9Sstevel@tonic-gate return -1; 6907*7c478bd9Sstevel@tonic-gate }; 6908*7c478bd9Sstevel@tonic-gate }; 6909*7c478bd9Sstevel@tonic-gate /* 6910*7c478bd9Sstevel@tonic-gate * To get here, we must have successfully written the number of 6911*7c478bd9Sstevel@tonic-gate * bytes that was specified. 6912*7c478bd9Sstevel@tonic-gate */ 6913*7c478bd9Sstevel@tonic-gate return n; 6914*7c478bd9Sstevel@tonic-gate } 6915*7c478bd9Sstevel@tonic-gate 6916*7c478bd9Sstevel@tonic-gate /*....................................................................... 6917*7c478bd9Sstevel@tonic-gate * Change the style of editing to emulate a given editor. 6918*7c478bd9Sstevel@tonic-gate * 6919*7c478bd9Sstevel@tonic-gate * Input: 6920*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 6921*7c478bd9Sstevel@tonic-gate * editor GlEditor The type of editor to emulate. 6922*7c478bd9Sstevel@tonic-gate * Output: 6923*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 6924*7c478bd9Sstevel@tonic-gate * 1 - Error. 6925*7c478bd9Sstevel@tonic-gate */ 6926*7c478bd9Sstevel@tonic-gate static int gl_change_editor(GetLine *gl, GlEditor editor) 6927*7c478bd9Sstevel@tonic-gate { 6928*7c478bd9Sstevel@tonic-gate /* 6929*7c478bd9Sstevel@tonic-gate * Install the default key-bindings of the requested editor. 6930*7c478bd9Sstevel@tonic-gate */ 6931*7c478bd9Sstevel@tonic-gate switch(editor) { 6932*7c478bd9Sstevel@tonic-gate case GL_EMACS_MODE: 6933*7c478bd9Sstevel@tonic-gate _kt_clear_bindings(gl->bindings, KTB_NORM); 6934*7c478bd9Sstevel@tonic-gate _kt_clear_bindings(gl->bindings, KTB_TERM); 6935*7c478bd9Sstevel@tonic-gate (void) _kt_add_bindings(gl->bindings, KTB_NORM, gl_emacs_bindings, 6936*7c478bd9Sstevel@tonic-gate sizeof(gl_emacs_bindings)/sizeof(gl_emacs_bindings[0])); 6937*7c478bd9Sstevel@tonic-gate break; 6938*7c478bd9Sstevel@tonic-gate case GL_VI_MODE: 6939*7c478bd9Sstevel@tonic-gate _kt_clear_bindings(gl->bindings, KTB_NORM); 6940*7c478bd9Sstevel@tonic-gate _kt_clear_bindings(gl->bindings, KTB_TERM); 6941*7c478bd9Sstevel@tonic-gate (void) _kt_add_bindings(gl->bindings, KTB_NORM, gl_vi_bindings, 6942*7c478bd9Sstevel@tonic-gate sizeof(gl_vi_bindings)/sizeof(gl_vi_bindings[0])); 6943*7c478bd9Sstevel@tonic-gate break; 6944*7c478bd9Sstevel@tonic-gate case GL_NO_EDITOR: 6945*7c478bd9Sstevel@tonic-gate break; 6946*7c478bd9Sstevel@tonic-gate default: 6947*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Unknown editor", END_ERR_MSG); 6948*7c478bd9Sstevel@tonic-gate errno = EINVAL; 6949*7c478bd9Sstevel@tonic-gate return 1; 6950*7c478bd9Sstevel@tonic-gate }; 6951*7c478bd9Sstevel@tonic-gate /* 6952*7c478bd9Sstevel@tonic-gate * Record the new editing mode. 6953*7c478bd9Sstevel@tonic-gate */ 6954*7c478bd9Sstevel@tonic-gate gl->editor = editor; 6955*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; /* Start in input mode */ 6956*7c478bd9Sstevel@tonic-gate gl->insert_curpos = 0; 6957*7c478bd9Sstevel@tonic-gate /* 6958*7c478bd9Sstevel@tonic-gate * Reinstate terminal-specific bindings. 6959*7c478bd9Sstevel@tonic-gate */ 6960*7c478bd9Sstevel@tonic-gate if(gl->editor != GL_NO_EDITOR && gl->input_fp) 6961*7c478bd9Sstevel@tonic-gate (void) gl_bind_terminal_keys(gl); 6962*7c478bd9Sstevel@tonic-gate return 0; 6963*7c478bd9Sstevel@tonic-gate } 6964*7c478bd9Sstevel@tonic-gate 6965*7c478bd9Sstevel@tonic-gate /*....................................................................... 6966*7c478bd9Sstevel@tonic-gate * This is an action function that switches to editing using emacs bindings 6967*7c478bd9Sstevel@tonic-gate */ 6968*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_emacs_editing_mode) 6969*7c478bd9Sstevel@tonic-gate { 6970*7c478bd9Sstevel@tonic-gate return gl_change_editor(gl, GL_EMACS_MODE); 6971*7c478bd9Sstevel@tonic-gate } 6972*7c478bd9Sstevel@tonic-gate 6973*7c478bd9Sstevel@tonic-gate /*....................................................................... 6974*7c478bd9Sstevel@tonic-gate * This is an action function that switches to editing using vi bindings 6975*7c478bd9Sstevel@tonic-gate */ 6976*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_editing_mode) 6977*7c478bd9Sstevel@tonic-gate { 6978*7c478bd9Sstevel@tonic-gate return gl_change_editor(gl, GL_VI_MODE); 6979*7c478bd9Sstevel@tonic-gate } 6980*7c478bd9Sstevel@tonic-gate 6981*7c478bd9Sstevel@tonic-gate /*....................................................................... 6982*7c478bd9Sstevel@tonic-gate * This is the action function that switches to insert mode. 6983*7c478bd9Sstevel@tonic-gate */ 6984*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_insert) 6985*7c478bd9Sstevel@tonic-gate { 6986*7c478bd9Sstevel@tonic-gate /* 6987*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 6988*7c478bd9Sstevel@tonic-gate * use by vi-undo. 6989*7c478bd9Sstevel@tonic-gate */ 6990*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 6991*7c478bd9Sstevel@tonic-gate /* 6992*7c478bd9Sstevel@tonic-gate * Switch to vi insert mode. 6993*7c478bd9Sstevel@tonic-gate */ 6994*7c478bd9Sstevel@tonic-gate gl->insert = 1; 6995*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; 6996*7c478bd9Sstevel@tonic-gate gl->insert_curpos = gl->buff_curpos; 6997*7c478bd9Sstevel@tonic-gate return 0; 6998*7c478bd9Sstevel@tonic-gate } 6999*7c478bd9Sstevel@tonic-gate 7000*7c478bd9Sstevel@tonic-gate /*....................................................................... 7001*7c478bd9Sstevel@tonic-gate * This is an action function that switches to overwrite mode. 7002*7c478bd9Sstevel@tonic-gate */ 7003*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_overwrite) 7004*7c478bd9Sstevel@tonic-gate { 7005*7c478bd9Sstevel@tonic-gate /* 7006*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 7007*7c478bd9Sstevel@tonic-gate * use by vi-undo. 7008*7c478bd9Sstevel@tonic-gate */ 7009*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7010*7c478bd9Sstevel@tonic-gate /* 7011*7c478bd9Sstevel@tonic-gate * Switch to vi overwrite mode. 7012*7c478bd9Sstevel@tonic-gate */ 7013*7c478bd9Sstevel@tonic-gate gl->insert = 0; 7014*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; 7015*7c478bd9Sstevel@tonic-gate gl->insert_curpos = gl->buff_curpos; 7016*7c478bd9Sstevel@tonic-gate return 0; 7017*7c478bd9Sstevel@tonic-gate } 7018*7c478bd9Sstevel@tonic-gate 7019*7c478bd9Sstevel@tonic-gate /*....................................................................... 7020*7c478bd9Sstevel@tonic-gate * This action function toggles the case of the character under the 7021*7c478bd9Sstevel@tonic-gate * cursor. 7022*7c478bd9Sstevel@tonic-gate */ 7023*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_change_case) 7024*7c478bd9Sstevel@tonic-gate { 7025*7c478bd9Sstevel@tonic-gate int i; 7026*7c478bd9Sstevel@tonic-gate /* 7027*7c478bd9Sstevel@tonic-gate * Keep a record of the current insert mode and the cursor position. 7028*7c478bd9Sstevel@tonic-gate */ 7029*7c478bd9Sstevel@tonic-gate int insert = gl->insert; 7030*7c478bd9Sstevel@tonic-gate /* 7031*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 7032*7c478bd9Sstevel@tonic-gate * use by vi-undo. 7033*7c478bd9Sstevel@tonic-gate */ 7034*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7035*7c478bd9Sstevel@tonic-gate /* 7036*7c478bd9Sstevel@tonic-gate * We want to overwrite the modified word. 7037*7c478bd9Sstevel@tonic-gate */ 7038*7c478bd9Sstevel@tonic-gate gl->insert = 0; 7039*7c478bd9Sstevel@tonic-gate /* 7040*7c478bd9Sstevel@tonic-gate * Toggle the case of 'count' characters. 7041*7c478bd9Sstevel@tonic-gate */ 7042*7c478bd9Sstevel@tonic-gate for(i=0; i<count && gl->buff_curpos < gl->ntotal; i++) { 7043*7c478bd9Sstevel@tonic-gate char *cptr = gl->line + gl->buff_curpos++; 7044*7c478bd9Sstevel@tonic-gate /* 7045*7c478bd9Sstevel@tonic-gate * Convert the character to upper case? 7046*7c478bd9Sstevel@tonic-gate */ 7047*7c478bd9Sstevel@tonic-gate if(islower((int)(unsigned char) *cptr)) 7048*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, toupper((int) *cptr), cptr - gl->line); 7049*7c478bd9Sstevel@tonic-gate else if(isupper((int)(unsigned char) *cptr)) 7050*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, tolower((int) *cptr), cptr - gl->line); 7051*7c478bd9Sstevel@tonic-gate /* 7052*7c478bd9Sstevel@tonic-gate * Write the possibly modified character back. Note that for non-modified 7053*7c478bd9Sstevel@tonic-gate * characters we want to do this as well, so as to advance the cursor. 7054*7c478bd9Sstevel@tonic-gate */ 7055*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, *cptr, cptr[1])) 7056*7c478bd9Sstevel@tonic-gate return 1; 7057*7c478bd9Sstevel@tonic-gate }; 7058*7c478bd9Sstevel@tonic-gate /* 7059*7c478bd9Sstevel@tonic-gate * Restore the insertion mode. 7060*7c478bd9Sstevel@tonic-gate */ 7061*7c478bd9Sstevel@tonic-gate gl->insert = insert; 7062*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */ 7063*7c478bd9Sstevel@tonic-gate } 7064*7c478bd9Sstevel@tonic-gate 7065*7c478bd9Sstevel@tonic-gate /*....................................................................... 7066*7c478bd9Sstevel@tonic-gate * This is the action function which implements the vi-style action which 7067*7c478bd9Sstevel@tonic-gate * moves the cursor to the start of the line, then switches to insert mode. 7068*7c478bd9Sstevel@tonic-gate */ 7069*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_insert_at_bol) 7070*7c478bd9Sstevel@tonic-gate { 7071*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7072*7c478bd9Sstevel@tonic-gate return gl_beginning_of_line(gl, 0, NULL) || 7073*7c478bd9Sstevel@tonic-gate gl_vi_insert(gl, 0, NULL); 7074*7c478bd9Sstevel@tonic-gate 7075*7c478bd9Sstevel@tonic-gate } 7076*7c478bd9Sstevel@tonic-gate 7077*7c478bd9Sstevel@tonic-gate /*....................................................................... 7078*7c478bd9Sstevel@tonic-gate * This is the action function which implements the vi-style action which 7079*7c478bd9Sstevel@tonic-gate * moves the cursor to the end of the line, then switches to insert mode 7080*7c478bd9Sstevel@tonic-gate * to allow text to be appended to the line. 7081*7c478bd9Sstevel@tonic-gate */ 7082*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_append_at_eol) 7083*7c478bd9Sstevel@tonic-gate { 7084*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7085*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; /* Allow cursor at EOL */ 7086*7c478bd9Sstevel@tonic-gate return gl_end_of_line(gl, 0, NULL) || 7087*7c478bd9Sstevel@tonic-gate gl_vi_insert(gl, 0, NULL); 7088*7c478bd9Sstevel@tonic-gate } 7089*7c478bd9Sstevel@tonic-gate 7090*7c478bd9Sstevel@tonic-gate /*....................................................................... 7091*7c478bd9Sstevel@tonic-gate * This is the action function which implements the vi-style action which 7092*7c478bd9Sstevel@tonic-gate * moves the cursor to right one then switches to insert mode, thus 7093*7c478bd9Sstevel@tonic-gate * allowing text to be appended after the next character. 7094*7c478bd9Sstevel@tonic-gate */ 7095*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_append) 7096*7c478bd9Sstevel@tonic-gate { 7097*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7098*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; /* Allow cursor at EOL */ 7099*7c478bd9Sstevel@tonic-gate return gl_cursor_right(gl, 1, NULL) || 7100*7c478bd9Sstevel@tonic-gate gl_vi_insert(gl, 0, NULL); 7101*7c478bd9Sstevel@tonic-gate } 7102*7c478bd9Sstevel@tonic-gate 7103*7c478bd9Sstevel@tonic-gate /*....................................................................... 7104*7c478bd9Sstevel@tonic-gate * This action function moves the cursor to the column specified by the 7105*7c478bd9Sstevel@tonic-gate * numeric argument. Column indexes start at 1. 7106*7c478bd9Sstevel@tonic-gate */ 7107*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_goto_column) 7108*7c478bd9Sstevel@tonic-gate { 7109*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, count - 1); 7110*7c478bd9Sstevel@tonic-gate } 7111*7c478bd9Sstevel@tonic-gate 7112*7c478bd9Sstevel@tonic-gate /*....................................................................... 7113*7c478bd9Sstevel@tonic-gate * Starting with the character under the cursor, replace 'count' 7114*7c478bd9Sstevel@tonic-gate * characters with the next character that the user types. 7115*7c478bd9Sstevel@tonic-gate */ 7116*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_replace_char) 7117*7c478bd9Sstevel@tonic-gate { 7118*7c478bd9Sstevel@tonic-gate char c; /* The replacement character */ 7119*7c478bd9Sstevel@tonic-gate int i; 7120*7c478bd9Sstevel@tonic-gate /* 7121*7c478bd9Sstevel@tonic-gate * Keep a record of the current insert mode. 7122*7c478bd9Sstevel@tonic-gate */ 7123*7c478bd9Sstevel@tonic-gate int insert = gl->insert; 7124*7c478bd9Sstevel@tonic-gate /* 7125*7c478bd9Sstevel@tonic-gate * Get the replacement character. 7126*7c478bd9Sstevel@tonic-gate */ 7127*7c478bd9Sstevel@tonic-gate if(gl->vi.repeat.active) { 7128*7c478bd9Sstevel@tonic-gate c = gl->vi.repeat.input_char; 7129*7c478bd9Sstevel@tonic-gate } else { 7130*7c478bd9Sstevel@tonic-gate if(gl_read_terminal(gl, 1, &c)) 7131*7c478bd9Sstevel@tonic-gate return 1; 7132*7c478bd9Sstevel@tonic-gate gl->vi.repeat.input_char = c; 7133*7c478bd9Sstevel@tonic-gate }; 7134*7c478bd9Sstevel@tonic-gate /* 7135*7c478bd9Sstevel@tonic-gate * Are there 'count' characters to be replaced? 7136*7c478bd9Sstevel@tonic-gate */ 7137*7c478bd9Sstevel@tonic-gate if(gl->ntotal - gl->buff_curpos >= count) { 7138*7c478bd9Sstevel@tonic-gate /* 7139*7c478bd9Sstevel@tonic-gate * If in vi command mode, preserve the current line for potential 7140*7c478bd9Sstevel@tonic-gate * use by vi-undo. 7141*7c478bd9Sstevel@tonic-gate */ 7142*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7143*7c478bd9Sstevel@tonic-gate /* 7144*7c478bd9Sstevel@tonic-gate * Temporarily switch to overwrite mode. 7145*7c478bd9Sstevel@tonic-gate */ 7146*7c478bd9Sstevel@tonic-gate gl->insert = 0; 7147*7c478bd9Sstevel@tonic-gate /* 7148*7c478bd9Sstevel@tonic-gate * Overwrite the current character plus count-1 subsequent characters 7149*7c478bd9Sstevel@tonic-gate * with the replacement character. 7150*7c478bd9Sstevel@tonic-gate */ 7151*7c478bd9Sstevel@tonic-gate for(i=0; i<count; i++) 7152*7c478bd9Sstevel@tonic-gate gl_add_char_to_line(gl, c); 7153*7c478bd9Sstevel@tonic-gate /* 7154*7c478bd9Sstevel@tonic-gate * Restore the original insert/overwrite mode. 7155*7c478bd9Sstevel@tonic-gate */ 7156*7c478bd9Sstevel@tonic-gate gl->insert = insert; 7157*7c478bd9Sstevel@tonic-gate }; 7158*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, gl->buff_curpos); /* bounds check */ 7159*7c478bd9Sstevel@tonic-gate } 7160*7c478bd9Sstevel@tonic-gate 7161*7c478bd9Sstevel@tonic-gate /*....................................................................... 7162*7c478bd9Sstevel@tonic-gate * This is an action function which changes all characters between the 7163*7c478bd9Sstevel@tonic-gate * current cursor position and the end of the line. 7164*7c478bd9Sstevel@tonic-gate */ 7165*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_rest_of_line) 7166*7c478bd9Sstevel@tonic-gate { 7167*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7168*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; /* Allow cursor at EOL */ 7169*7c478bd9Sstevel@tonic-gate return gl_kill_line(gl, count, NULL) || gl_vi_insert(gl, 0, NULL); 7170*7c478bd9Sstevel@tonic-gate } 7171*7c478bd9Sstevel@tonic-gate 7172*7c478bd9Sstevel@tonic-gate /*....................................................................... 7173*7c478bd9Sstevel@tonic-gate * This is an action function which changes all characters between the 7174*7c478bd9Sstevel@tonic-gate * start of the line and the current cursor position. 7175*7c478bd9Sstevel@tonic-gate */ 7176*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_bol) 7177*7c478bd9Sstevel@tonic-gate { 7178*7c478bd9Sstevel@tonic-gate return gl_backward_kill_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL); 7179*7c478bd9Sstevel@tonic-gate } 7180*7c478bd9Sstevel@tonic-gate 7181*7c478bd9Sstevel@tonic-gate /*....................................................................... 7182*7c478bd9Sstevel@tonic-gate * This is an action function which deletes the entire contents of the 7183*7c478bd9Sstevel@tonic-gate * current line and switches to insert mode. 7184*7c478bd9Sstevel@tonic-gate */ 7185*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_line) 7186*7c478bd9Sstevel@tonic-gate { 7187*7c478bd9Sstevel@tonic-gate return gl_delete_line(gl,count,NULL) || gl_vi_insert(gl,0,NULL); 7188*7c478bd9Sstevel@tonic-gate } 7189*7c478bd9Sstevel@tonic-gate 7190*7c478bd9Sstevel@tonic-gate /*....................................................................... 7191*7c478bd9Sstevel@tonic-gate * Starting from the cursor position and looking towards the end of the 7192*7c478bd9Sstevel@tonic-gate * line, copy 'count' characters to the cut buffer. 7193*7c478bd9Sstevel@tonic-gate */ 7194*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_char) 7195*7c478bd9Sstevel@tonic-gate { 7196*7c478bd9Sstevel@tonic-gate /* 7197*7c478bd9Sstevel@tonic-gate * Limit the count to the number of characters available. 7198*7c478bd9Sstevel@tonic-gate */ 7199*7c478bd9Sstevel@tonic-gate if(gl->buff_curpos + count >= gl->ntotal) 7200*7c478bd9Sstevel@tonic-gate count = gl->ntotal - gl->buff_curpos; 7201*7c478bd9Sstevel@tonic-gate if(count < 0) 7202*7c478bd9Sstevel@tonic-gate count = 0; 7203*7c478bd9Sstevel@tonic-gate /* 7204*7c478bd9Sstevel@tonic-gate * Copy the characters to the cut buffer. 7205*7c478bd9Sstevel@tonic-gate */ 7206*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + gl->buff_curpos, count); 7207*7c478bd9Sstevel@tonic-gate gl->cutbuf[count] = '\0'; 7208*7c478bd9Sstevel@tonic-gate return 0; 7209*7c478bd9Sstevel@tonic-gate } 7210*7c478bd9Sstevel@tonic-gate 7211*7c478bd9Sstevel@tonic-gate /*....................................................................... 7212*7c478bd9Sstevel@tonic-gate * Starting from the character before the cursor position and looking 7213*7c478bd9Sstevel@tonic-gate * backwards towards the start of the line, copy 'count' characters to 7214*7c478bd9Sstevel@tonic-gate * the cut buffer. 7215*7c478bd9Sstevel@tonic-gate */ 7216*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_char) 7217*7c478bd9Sstevel@tonic-gate { 7218*7c478bd9Sstevel@tonic-gate /* 7219*7c478bd9Sstevel@tonic-gate * Limit the count to the number of characters available. 7220*7c478bd9Sstevel@tonic-gate */ 7221*7c478bd9Sstevel@tonic-gate if(count > gl->buff_curpos) 7222*7c478bd9Sstevel@tonic-gate count = gl->buff_curpos; 7223*7c478bd9Sstevel@tonic-gate if(count < 0) 7224*7c478bd9Sstevel@tonic-gate count = 0; 7225*7c478bd9Sstevel@tonic-gate gl_place_cursor(gl, gl->buff_curpos - count); 7226*7c478bd9Sstevel@tonic-gate /* 7227*7c478bd9Sstevel@tonic-gate * Copy the characters to the cut buffer. 7228*7c478bd9Sstevel@tonic-gate */ 7229*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + gl->buff_curpos, count); 7230*7c478bd9Sstevel@tonic-gate gl->cutbuf[count] = '\0'; 7231*7c478bd9Sstevel@tonic-gate return 0; 7232*7c478bd9Sstevel@tonic-gate } 7233*7c478bd9Sstevel@tonic-gate 7234*7c478bd9Sstevel@tonic-gate /*....................................................................... 7235*7c478bd9Sstevel@tonic-gate * Starting from the cursor position copy to the specified column into the 7236*7c478bd9Sstevel@tonic-gate * cut buffer. 7237*7c478bd9Sstevel@tonic-gate */ 7238*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_column) 7239*7c478bd9Sstevel@tonic-gate { 7240*7c478bd9Sstevel@tonic-gate if (--count >= gl->buff_curpos) 7241*7c478bd9Sstevel@tonic-gate return gl_forward_copy_char(gl, count - gl->buff_curpos, NULL); 7242*7c478bd9Sstevel@tonic-gate else 7243*7c478bd9Sstevel@tonic-gate return gl_backward_copy_char(gl, gl->buff_curpos - count, NULL); 7244*7c478bd9Sstevel@tonic-gate } 7245*7c478bd9Sstevel@tonic-gate 7246*7c478bd9Sstevel@tonic-gate /*....................................................................... 7247*7c478bd9Sstevel@tonic-gate * Starting from the cursor position copy characters up to a matching 7248*7c478bd9Sstevel@tonic-gate * parenthesis into the cut buffer. 7249*7c478bd9Sstevel@tonic-gate */ 7250*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_parenthesis) 7251*7c478bd9Sstevel@tonic-gate { 7252*7c478bd9Sstevel@tonic-gate int curpos = gl_index_of_matching_paren(gl); 7253*7c478bd9Sstevel@tonic-gate if(curpos >= 0) { 7254*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7255*7c478bd9Sstevel@tonic-gate if(curpos >= gl->buff_curpos) 7256*7c478bd9Sstevel@tonic-gate return gl_forward_copy_char(gl, curpos - gl->buff_curpos + 1, NULL); 7257*7c478bd9Sstevel@tonic-gate else 7258*7c478bd9Sstevel@tonic-gate return gl_backward_copy_char(gl, ++gl->buff_curpos - curpos + 1, NULL); 7259*7c478bd9Sstevel@tonic-gate }; 7260*7c478bd9Sstevel@tonic-gate return 0; 7261*7c478bd9Sstevel@tonic-gate } 7262*7c478bd9Sstevel@tonic-gate 7263*7c478bd9Sstevel@tonic-gate /*....................................................................... 7264*7c478bd9Sstevel@tonic-gate * Starting from the cursor position copy the rest of the line into the 7265*7c478bd9Sstevel@tonic-gate * cut buffer. 7266*7c478bd9Sstevel@tonic-gate */ 7267*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_rest_of_line) 7268*7c478bd9Sstevel@tonic-gate { 7269*7c478bd9Sstevel@tonic-gate /* 7270*7c478bd9Sstevel@tonic-gate * Copy the characters to the cut buffer. 7271*7c478bd9Sstevel@tonic-gate */ 7272*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + gl->buff_curpos, gl->ntotal - gl->buff_curpos); 7273*7c478bd9Sstevel@tonic-gate gl->cutbuf[gl->ntotal - gl->buff_curpos] = '\0'; 7274*7c478bd9Sstevel@tonic-gate return 0; 7275*7c478bd9Sstevel@tonic-gate } 7276*7c478bd9Sstevel@tonic-gate 7277*7c478bd9Sstevel@tonic-gate /*....................................................................... 7278*7c478bd9Sstevel@tonic-gate * Copy from the beginning of the line to the cursor position into the 7279*7c478bd9Sstevel@tonic-gate * cut buffer. 7280*7c478bd9Sstevel@tonic-gate */ 7281*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_to_bol) 7282*7c478bd9Sstevel@tonic-gate { 7283*7c478bd9Sstevel@tonic-gate /* 7284*7c478bd9Sstevel@tonic-gate * Copy the characters to the cut buffer. 7285*7c478bd9Sstevel@tonic-gate */ 7286*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line, gl->buff_curpos); 7287*7c478bd9Sstevel@tonic-gate gl->cutbuf[gl->buff_curpos] = '\0'; 7288*7c478bd9Sstevel@tonic-gate gl_place_cursor(gl, 0); 7289*7c478bd9Sstevel@tonic-gate return 0; 7290*7c478bd9Sstevel@tonic-gate } 7291*7c478bd9Sstevel@tonic-gate 7292*7c478bd9Sstevel@tonic-gate /*....................................................................... 7293*7c478bd9Sstevel@tonic-gate * Copy the entire line into the cut buffer. 7294*7c478bd9Sstevel@tonic-gate */ 7295*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_line) 7296*7c478bd9Sstevel@tonic-gate { 7297*7c478bd9Sstevel@tonic-gate /* 7298*7c478bd9Sstevel@tonic-gate * Copy the characters to the cut buffer. 7299*7c478bd9Sstevel@tonic-gate */ 7300*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line, gl->ntotal); 7301*7c478bd9Sstevel@tonic-gate gl->cutbuf[gl->ntotal] = '\0'; 7302*7c478bd9Sstevel@tonic-gate return 0; 7303*7c478bd9Sstevel@tonic-gate } 7304*7c478bd9Sstevel@tonic-gate 7305*7c478bd9Sstevel@tonic-gate /*....................................................................... 7306*7c478bd9Sstevel@tonic-gate * Search forwards for the next character that the user enters. 7307*7c478bd9Sstevel@tonic-gate */ 7308*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_find_char) 7309*7c478bd9Sstevel@tonic-gate { 7310*7c478bd9Sstevel@tonic-gate int pos = gl_find_char(gl, count, 1, 1, '\0'); 7311*7c478bd9Sstevel@tonic-gate return pos >= 0 && gl_place_cursor(gl, pos); 7312*7c478bd9Sstevel@tonic-gate } 7313*7c478bd9Sstevel@tonic-gate 7314*7c478bd9Sstevel@tonic-gate /*....................................................................... 7315*7c478bd9Sstevel@tonic-gate * Search backwards for the next character that the user enters. 7316*7c478bd9Sstevel@tonic-gate */ 7317*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_find_char) 7318*7c478bd9Sstevel@tonic-gate { 7319*7c478bd9Sstevel@tonic-gate int pos = gl_find_char(gl, count, 0, 1, '\0'); 7320*7c478bd9Sstevel@tonic-gate return pos >= 0 && gl_place_cursor(gl, pos); 7321*7c478bd9Sstevel@tonic-gate } 7322*7c478bd9Sstevel@tonic-gate 7323*7c478bd9Sstevel@tonic-gate /*....................................................................... 7324*7c478bd9Sstevel@tonic-gate * Search forwards for the next character that the user enters. Move up to, 7325*7c478bd9Sstevel@tonic-gate * but not onto, the found character. 7326*7c478bd9Sstevel@tonic-gate */ 7327*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_to_char) 7328*7c478bd9Sstevel@tonic-gate { 7329*7c478bd9Sstevel@tonic-gate int pos = gl_find_char(gl, count, 1, 0, '\0'); 7330*7c478bd9Sstevel@tonic-gate return pos >= 0 && gl_place_cursor(gl, pos); 7331*7c478bd9Sstevel@tonic-gate } 7332*7c478bd9Sstevel@tonic-gate 7333*7c478bd9Sstevel@tonic-gate /*....................................................................... 7334*7c478bd9Sstevel@tonic-gate * Search backwards for the next character that the user enters. Move back to, 7335*7c478bd9Sstevel@tonic-gate * but not onto, the found character. 7336*7c478bd9Sstevel@tonic-gate */ 7337*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_to_char) 7338*7c478bd9Sstevel@tonic-gate { 7339*7c478bd9Sstevel@tonic-gate int pos = gl_find_char(gl, count, 0, 0, '\0'); 7340*7c478bd9Sstevel@tonic-gate return pos >= 0 && gl_place_cursor(gl, pos); 7341*7c478bd9Sstevel@tonic-gate } 7342*7c478bd9Sstevel@tonic-gate 7343*7c478bd9Sstevel@tonic-gate /*....................................................................... 7344*7c478bd9Sstevel@tonic-gate * Searching in a given direction, return the index of a given (or 7345*7c478bd9Sstevel@tonic-gate * read) character in the input line, or the character that precedes 7346*7c478bd9Sstevel@tonic-gate * it in the specified search direction. Return -1 if not found. 7347*7c478bd9Sstevel@tonic-gate * 7348*7c478bd9Sstevel@tonic-gate * Input: 7349*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 7350*7c478bd9Sstevel@tonic-gate * count int The number of times to search. 7351*7c478bd9Sstevel@tonic-gate * forward int True if searching forward. 7352*7c478bd9Sstevel@tonic-gate * onto int True if the search should end on top of the 7353*7c478bd9Sstevel@tonic-gate * character, false if the search should stop 7354*7c478bd9Sstevel@tonic-gate * one character before the character in the 7355*7c478bd9Sstevel@tonic-gate * specified search direction. 7356*7c478bd9Sstevel@tonic-gate * c char The character to be sought, or '\0' if the 7357*7c478bd9Sstevel@tonic-gate * character should be read from the user. 7358*7c478bd9Sstevel@tonic-gate * Output: 7359*7c478bd9Sstevel@tonic-gate * return int The index of the character in gl->line[], or 7360*7c478bd9Sstevel@tonic-gate * -1 if not found. 7361*7c478bd9Sstevel@tonic-gate */ 7362*7c478bd9Sstevel@tonic-gate static int gl_find_char(GetLine *gl, int count, int forward, int onto, char c) 7363*7c478bd9Sstevel@tonic-gate { 7364*7c478bd9Sstevel@tonic-gate int pos; /* The index reached in searching the input line */ 7365*7c478bd9Sstevel@tonic-gate int i; 7366*7c478bd9Sstevel@tonic-gate /* 7367*7c478bd9Sstevel@tonic-gate * Get a character from the user? 7368*7c478bd9Sstevel@tonic-gate */ 7369*7c478bd9Sstevel@tonic-gate if(!c) { 7370*7c478bd9Sstevel@tonic-gate /* 7371*7c478bd9Sstevel@tonic-gate * If we are in the process of repeating a previous change command, substitute 7372*7c478bd9Sstevel@tonic-gate * the last find character. 7373*7c478bd9Sstevel@tonic-gate */ 7374*7c478bd9Sstevel@tonic-gate if(gl->vi.repeat.active) { 7375*7c478bd9Sstevel@tonic-gate c = gl->vi.find_char; 7376*7c478bd9Sstevel@tonic-gate } else { 7377*7c478bd9Sstevel@tonic-gate if(gl_read_terminal(gl, 1, &c)) 7378*7c478bd9Sstevel@tonic-gate return -1; 7379*7c478bd9Sstevel@tonic-gate /* 7380*7c478bd9Sstevel@tonic-gate * Record the details of the new search, for use by repeat finds. 7381*7c478bd9Sstevel@tonic-gate */ 7382*7c478bd9Sstevel@tonic-gate gl->vi.find_forward = forward; 7383*7c478bd9Sstevel@tonic-gate gl->vi.find_onto = onto; 7384*7c478bd9Sstevel@tonic-gate gl->vi.find_char = c; 7385*7c478bd9Sstevel@tonic-gate }; 7386*7c478bd9Sstevel@tonic-gate }; 7387*7c478bd9Sstevel@tonic-gate /* 7388*7c478bd9Sstevel@tonic-gate * Which direction should we search? 7389*7c478bd9Sstevel@tonic-gate */ 7390*7c478bd9Sstevel@tonic-gate if(forward) { 7391*7c478bd9Sstevel@tonic-gate /* 7392*7c478bd9Sstevel@tonic-gate * Search forwards 'count' times for the character, starting with the 7393*7c478bd9Sstevel@tonic-gate * character that follows the cursor. 7394*7c478bd9Sstevel@tonic-gate */ 7395*7c478bd9Sstevel@tonic-gate for(i=0, pos=gl->buff_curpos; i<count && pos < gl->ntotal; i++) { 7396*7c478bd9Sstevel@tonic-gate /* 7397*7c478bd9Sstevel@tonic-gate * Advance past the last match (or past the current cursor position 7398*7c478bd9Sstevel@tonic-gate * on the first search). 7399*7c478bd9Sstevel@tonic-gate */ 7400*7c478bd9Sstevel@tonic-gate pos++; 7401*7c478bd9Sstevel@tonic-gate /* 7402*7c478bd9Sstevel@tonic-gate * Search for the next instance of c. 7403*7c478bd9Sstevel@tonic-gate */ 7404*7c478bd9Sstevel@tonic-gate for( ; pos<gl->ntotal && c!=gl->line[pos]; pos++) 7405*7c478bd9Sstevel@tonic-gate ; 7406*7c478bd9Sstevel@tonic-gate }; 7407*7c478bd9Sstevel@tonic-gate /* 7408*7c478bd9Sstevel@tonic-gate * If the character was found and we have been requested to return the 7409*7c478bd9Sstevel@tonic-gate * position of the character that precedes the desired character, then 7410*7c478bd9Sstevel@tonic-gate * we have gone one character too far. 7411*7c478bd9Sstevel@tonic-gate */ 7412*7c478bd9Sstevel@tonic-gate if(!onto && pos<gl->ntotal) 7413*7c478bd9Sstevel@tonic-gate pos--; 7414*7c478bd9Sstevel@tonic-gate } else { 7415*7c478bd9Sstevel@tonic-gate /* 7416*7c478bd9Sstevel@tonic-gate * Search backwards 'count' times for the character, starting with the 7417*7c478bd9Sstevel@tonic-gate * character that precedes the cursor. 7418*7c478bd9Sstevel@tonic-gate */ 7419*7c478bd9Sstevel@tonic-gate for(i=0, pos=gl->buff_curpos; i<count && pos >= gl->insert_curpos; i++) { 7420*7c478bd9Sstevel@tonic-gate /* 7421*7c478bd9Sstevel@tonic-gate * Step back one from the last match (or from the current cursor 7422*7c478bd9Sstevel@tonic-gate * position on the first search). 7423*7c478bd9Sstevel@tonic-gate */ 7424*7c478bd9Sstevel@tonic-gate pos--; 7425*7c478bd9Sstevel@tonic-gate /* 7426*7c478bd9Sstevel@tonic-gate * Search for the next instance of c. 7427*7c478bd9Sstevel@tonic-gate */ 7428*7c478bd9Sstevel@tonic-gate for( ; pos>=gl->insert_curpos && c!=gl->line[pos]; pos--) 7429*7c478bd9Sstevel@tonic-gate ; 7430*7c478bd9Sstevel@tonic-gate }; 7431*7c478bd9Sstevel@tonic-gate /* 7432*7c478bd9Sstevel@tonic-gate * If the character was found and we have been requested to return the 7433*7c478bd9Sstevel@tonic-gate * position of the character that precedes the desired character, then 7434*7c478bd9Sstevel@tonic-gate * we have gone one character too far. 7435*7c478bd9Sstevel@tonic-gate */ 7436*7c478bd9Sstevel@tonic-gate if(!onto && pos>=gl->insert_curpos) 7437*7c478bd9Sstevel@tonic-gate pos++; 7438*7c478bd9Sstevel@tonic-gate }; 7439*7c478bd9Sstevel@tonic-gate /* 7440*7c478bd9Sstevel@tonic-gate * If found, return the cursor position of the count'th match. 7441*7c478bd9Sstevel@tonic-gate * Otherwise ring the terminal bell. 7442*7c478bd9Sstevel@tonic-gate */ 7443*7c478bd9Sstevel@tonic-gate if(pos >= gl->insert_curpos && pos < gl->ntotal) { 7444*7c478bd9Sstevel@tonic-gate return pos; 7445*7c478bd9Sstevel@tonic-gate } else { 7446*7c478bd9Sstevel@tonic-gate (void) gl_ring_bell(gl, 1, NULL); 7447*7c478bd9Sstevel@tonic-gate return -1; 7448*7c478bd9Sstevel@tonic-gate } 7449*7c478bd9Sstevel@tonic-gate } 7450*7c478bd9Sstevel@tonic-gate 7451*7c478bd9Sstevel@tonic-gate /*....................................................................... 7452*7c478bd9Sstevel@tonic-gate * Repeat the last character search in the same direction as the last 7453*7c478bd9Sstevel@tonic-gate * search. 7454*7c478bd9Sstevel@tonic-gate */ 7455*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_repeat_find_char) 7456*7c478bd9Sstevel@tonic-gate { 7457*7c478bd9Sstevel@tonic-gate int pos = gl->vi.find_char ? 7458*7c478bd9Sstevel@tonic-gate gl_find_char(gl, count, gl->vi.find_forward, gl->vi.find_onto, 7459*7c478bd9Sstevel@tonic-gate gl->vi.find_char) : -1; 7460*7c478bd9Sstevel@tonic-gate return pos >= 0 && gl_place_cursor(gl, pos); 7461*7c478bd9Sstevel@tonic-gate } 7462*7c478bd9Sstevel@tonic-gate 7463*7c478bd9Sstevel@tonic-gate /*....................................................................... 7464*7c478bd9Sstevel@tonic-gate * Repeat the last character search in the opposite direction as the last 7465*7c478bd9Sstevel@tonic-gate * search. 7466*7c478bd9Sstevel@tonic-gate */ 7467*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_invert_refind_char) 7468*7c478bd9Sstevel@tonic-gate { 7469*7c478bd9Sstevel@tonic-gate int pos = gl->vi.find_char ? 7470*7c478bd9Sstevel@tonic-gate gl_find_char(gl, count, !gl->vi.find_forward, gl->vi.find_onto, 7471*7c478bd9Sstevel@tonic-gate gl->vi.find_char) : -1; 7472*7c478bd9Sstevel@tonic-gate return pos >= 0 && gl_place_cursor(gl, pos); 7473*7c478bd9Sstevel@tonic-gate } 7474*7c478bd9Sstevel@tonic-gate 7475*7c478bd9Sstevel@tonic-gate /*....................................................................... 7476*7c478bd9Sstevel@tonic-gate * Search forward from the current position of the cursor for 'count' 7477*7c478bd9Sstevel@tonic-gate * word endings, returning the index of the last one found, or the end of 7478*7c478bd9Sstevel@tonic-gate * the line if there were less than 'count' words. 7479*7c478bd9Sstevel@tonic-gate * 7480*7c478bd9Sstevel@tonic-gate * Input: 7481*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 7482*7c478bd9Sstevel@tonic-gate * n int The number of word boundaries to search for. 7483*7c478bd9Sstevel@tonic-gate * Output: 7484*7c478bd9Sstevel@tonic-gate * return int The buffer index of the located position. 7485*7c478bd9Sstevel@tonic-gate */ 7486*7c478bd9Sstevel@tonic-gate static int gl_nth_word_end_forward(GetLine *gl, int n) 7487*7c478bd9Sstevel@tonic-gate { 7488*7c478bd9Sstevel@tonic-gate int bufpos; /* The buffer index being checked. */ 7489*7c478bd9Sstevel@tonic-gate int i; 7490*7c478bd9Sstevel@tonic-gate /* 7491*7c478bd9Sstevel@tonic-gate * In order to guarantee forward motion to the next word ending, 7492*7c478bd9Sstevel@tonic-gate * we need to start from one position to the right of the cursor 7493*7c478bd9Sstevel@tonic-gate * position, since this may already be at the end of a word. 7494*7c478bd9Sstevel@tonic-gate */ 7495*7c478bd9Sstevel@tonic-gate bufpos = gl->buff_curpos + 1; 7496*7c478bd9Sstevel@tonic-gate /* 7497*7c478bd9Sstevel@tonic-gate * If we are at the end of the line, return the index of the last 7498*7c478bd9Sstevel@tonic-gate * real character on the line. Note that this will be -1 if the line 7499*7c478bd9Sstevel@tonic-gate * is empty. 7500*7c478bd9Sstevel@tonic-gate */ 7501*7c478bd9Sstevel@tonic-gate if(bufpos >= gl->ntotal) 7502*7c478bd9Sstevel@tonic-gate return gl->ntotal - 1; 7503*7c478bd9Sstevel@tonic-gate /* 7504*7c478bd9Sstevel@tonic-gate * Search 'n' times, unless the end of the input line is reached first. 7505*7c478bd9Sstevel@tonic-gate */ 7506*7c478bd9Sstevel@tonic-gate for(i=0; i<n && bufpos<gl->ntotal; i++) { 7507*7c478bd9Sstevel@tonic-gate /* 7508*7c478bd9Sstevel@tonic-gate * If we are not already within a word, skip to the start of the next word. 7509*7c478bd9Sstevel@tonic-gate */ 7510*7c478bd9Sstevel@tonic-gate for( ; bufpos<gl->ntotal && !gl_is_word_char((int)gl->line[bufpos]); 7511*7c478bd9Sstevel@tonic-gate bufpos++) 7512*7c478bd9Sstevel@tonic-gate ; 7513*7c478bd9Sstevel@tonic-gate /* 7514*7c478bd9Sstevel@tonic-gate * Find the end of the next word. 7515*7c478bd9Sstevel@tonic-gate */ 7516*7c478bd9Sstevel@tonic-gate for( ; bufpos<gl->ntotal && gl_is_word_char((int)gl->line[bufpos]); 7517*7c478bd9Sstevel@tonic-gate bufpos++) 7518*7c478bd9Sstevel@tonic-gate ; 7519*7c478bd9Sstevel@tonic-gate }; 7520*7c478bd9Sstevel@tonic-gate /* 7521*7c478bd9Sstevel@tonic-gate * We will have overshot. 7522*7c478bd9Sstevel@tonic-gate */ 7523*7c478bd9Sstevel@tonic-gate return bufpos > 0 ? bufpos-1 : bufpos; 7524*7c478bd9Sstevel@tonic-gate } 7525*7c478bd9Sstevel@tonic-gate 7526*7c478bd9Sstevel@tonic-gate /*....................................................................... 7527*7c478bd9Sstevel@tonic-gate * Search forward from the current position of the cursor for 'count' 7528*7c478bd9Sstevel@tonic-gate * word starts, returning the index of the last one found, or the end of 7529*7c478bd9Sstevel@tonic-gate * the line if there were less than 'count' words. 7530*7c478bd9Sstevel@tonic-gate * 7531*7c478bd9Sstevel@tonic-gate * Input: 7532*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 7533*7c478bd9Sstevel@tonic-gate * n int The number of word boundaries to search for. 7534*7c478bd9Sstevel@tonic-gate * Output: 7535*7c478bd9Sstevel@tonic-gate * return int The buffer index of the located position. 7536*7c478bd9Sstevel@tonic-gate */ 7537*7c478bd9Sstevel@tonic-gate static int gl_nth_word_start_forward(GetLine *gl, int n) 7538*7c478bd9Sstevel@tonic-gate { 7539*7c478bd9Sstevel@tonic-gate int bufpos; /* The buffer index being checked. */ 7540*7c478bd9Sstevel@tonic-gate int i; 7541*7c478bd9Sstevel@tonic-gate /* 7542*7c478bd9Sstevel@tonic-gate * Get the current cursor position. 7543*7c478bd9Sstevel@tonic-gate */ 7544*7c478bd9Sstevel@tonic-gate bufpos = gl->buff_curpos; 7545*7c478bd9Sstevel@tonic-gate /* 7546*7c478bd9Sstevel@tonic-gate * Search 'n' times, unless the end of the input line is reached first. 7547*7c478bd9Sstevel@tonic-gate */ 7548*7c478bd9Sstevel@tonic-gate for(i=0; i<n && bufpos<gl->ntotal; i++) { 7549*7c478bd9Sstevel@tonic-gate /* 7550*7c478bd9Sstevel@tonic-gate * Find the end of the current word. 7551*7c478bd9Sstevel@tonic-gate */ 7552*7c478bd9Sstevel@tonic-gate for( ; bufpos<gl->ntotal && gl_is_word_char((int)gl->line[bufpos]); 7553*7c478bd9Sstevel@tonic-gate bufpos++) 7554*7c478bd9Sstevel@tonic-gate ; 7555*7c478bd9Sstevel@tonic-gate /* 7556*7c478bd9Sstevel@tonic-gate * Skip to the start of the next word. 7557*7c478bd9Sstevel@tonic-gate */ 7558*7c478bd9Sstevel@tonic-gate for( ; bufpos<gl->ntotal && !gl_is_word_char((int)gl->line[bufpos]); 7559*7c478bd9Sstevel@tonic-gate bufpos++) 7560*7c478bd9Sstevel@tonic-gate ; 7561*7c478bd9Sstevel@tonic-gate }; 7562*7c478bd9Sstevel@tonic-gate return bufpos; 7563*7c478bd9Sstevel@tonic-gate } 7564*7c478bd9Sstevel@tonic-gate 7565*7c478bd9Sstevel@tonic-gate /*....................................................................... 7566*7c478bd9Sstevel@tonic-gate * Search backward from the current position of the cursor for 'count' 7567*7c478bd9Sstevel@tonic-gate * word starts, returning the index of the last one found, or the start 7568*7c478bd9Sstevel@tonic-gate * of the line if there were less than 'count' words. 7569*7c478bd9Sstevel@tonic-gate * 7570*7c478bd9Sstevel@tonic-gate * Input: 7571*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 7572*7c478bd9Sstevel@tonic-gate * n int The number of word boundaries to search for. 7573*7c478bd9Sstevel@tonic-gate * Output: 7574*7c478bd9Sstevel@tonic-gate * return int The buffer index of the located position. 7575*7c478bd9Sstevel@tonic-gate */ 7576*7c478bd9Sstevel@tonic-gate static int gl_nth_word_start_backward(GetLine *gl, int n) 7577*7c478bd9Sstevel@tonic-gate { 7578*7c478bd9Sstevel@tonic-gate int bufpos; /* The buffer index being checked. */ 7579*7c478bd9Sstevel@tonic-gate int i; 7580*7c478bd9Sstevel@tonic-gate /* 7581*7c478bd9Sstevel@tonic-gate * Get the current cursor position. 7582*7c478bd9Sstevel@tonic-gate */ 7583*7c478bd9Sstevel@tonic-gate bufpos = gl->buff_curpos; 7584*7c478bd9Sstevel@tonic-gate /* 7585*7c478bd9Sstevel@tonic-gate * Search 'n' times, unless the beginning of the input line (or vi insertion 7586*7c478bd9Sstevel@tonic-gate * point) is reached first. 7587*7c478bd9Sstevel@tonic-gate */ 7588*7c478bd9Sstevel@tonic-gate for(i=0; i<n && bufpos > gl->insert_curpos; i++) { 7589*7c478bd9Sstevel@tonic-gate /* 7590*7c478bd9Sstevel@tonic-gate * Starting one character back from the last search, so as not to keep 7591*7c478bd9Sstevel@tonic-gate * settling on the same word-start, search backwards until finding a 7592*7c478bd9Sstevel@tonic-gate * word character. 7593*7c478bd9Sstevel@tonic-gate */ 7594*7c478bd9Sstevel@tonic-gate while(--bufpos >= gl->insert_curpos && 7595*7c478bd9Sstevel@tonic-gate !gl_is_word_char((int)gl->line[bufpos])) 7596*7c478bd9Sstevel@tonic-gate ; 7597*7c478bd9Sstevel@tonic-gate /* 7598*7c478bd9Sstevel@tonic-gate * Find the start of the word. 7599*7c478bd9Sstevel@tonic-gate */ 7600*7c478bd9Sstevel@tonic-gate while(--bufpos >= gl->insert_curpos && 7601*7c478bd9Sstevel@tonic-gate gl_is_word_char((int)gl->line[bufpos])) 7602*7c478bd9Sstevel@tonic-gate ; 7603*7c478bd9Sstevel@tonic-gate /* 7604*7c478bd9Sstevel@tonic-gate * We will have gone one character too far. 7605*7c478bd9Sstevel@tonic-gate */ 7606*7c478bd9Sstevel@tonic-gate bufpos++; 7607*7c478bd9Sstevel@tonic-gate }; 7608*7c478bd9Sstevel@tonic-gate return bufpos >= gl->insert_curpos ? bufpos : gl->insert_curpos; 7609*7c478bd9Sstevel@tonic-gate } 7610*7c478bd9Sstevel@tonic-gate 7611*7c478bd9Sstevel@tonic-gate /*....................................................................... 7612*7c478bd9Sstevel@tonic-gate * Copy one or more words into the cut buffer without moving the cursor 7613*7c478bd9Sstevel@tonic-gate * or deleting text. 7614*7c478bd9Sstevel@tonic-gate */ 7615*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_word) 7616*7c478bd9Sstevel@tonic-gate { 7617*7c478bd9Sstevel@tonic-gate /* 7618*7c478bd9Sstevel@tonic-gate * Find the location of the count'th start or end of a word 7619*7c478bd9Sstevel@tonic-gate * after the cursor, depending on whether in emacs or vi mode. 7620*7c478bd9Sstevel@tonic-gate */ 7621*7c478bd9Sstevel@tonic-gate int next = gl->editor == GL_EMACS_MODE ? 7622*7c478bd9Sstevel@tonic-gate gl_nth_word_end_forward(gl, count) : 7623*7c478bd9Sstevel@tonic-gate gl_nth_word_start_forward(gl, count); 7624*7c478bd9Sstevel@tonic-gate /* 7625*7c478bd9Sstevel@tonic-gate * How many characters are to be copied into the cut buffer? 7626*7c478bd9Sstevel@tonic-gate */ 7627*7c478bd9Sstevel@tonic-gate int n = next - gl->buff_curpos; 7628*7c478bd9Sstevel@tonic-gate /* 7629*7c478bd9Sstevel@tonic-gate * Copy the specified segment and terminate the string. 7630*7c478bd9Sstevel@tonic-gate */ 7631*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + gl->buff_curpos, n); 7632*7c478bd9Sstevel@tonic-gate gl->cutbuf[n] = '\0'; 7633*7c478bd9Sstevel@tonic-gate return 0; 7634*7c478bd9Sstevel@tonic-gate } 7635*7c478bd9Sstevel@tonic-gate 7636*7c478bd9Sstevel@tonic-gate /*....................................................................... 7637*7c478bd9Sstevel@tonic-gate * Copy one or more words preceding the cursor into the cut buffer, 7638*7c478bd9Sstevel@tonic-gate * without moving the cursor or deleting text. 7639*7c478bd9Sstevel@tonic-gate */ 7640*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_word) 7641*7c478bd9Sstevel@tonic-gate { 7642*7c478bd9Sstevel@tonic-gate /* 7643*7c478bd9Sstevel@tonic-gate * Find the location of the count'th start of word before the cursor. 7644*7c478bd9Sstevel@tonic-gate */ 7645*7c478bd9Sstevel@tonic-gate int next = gl_nth_word_start_backward(gl, count); 7646*7c478bd9Sstevel@tonic-gate /* 7647*7c478bd9Sstevel@tonic-gate * How many characters are to be copied into the cut buffer? 7648*7c478bd9Sstevel@tonic-gate */ 7649*7c478bd9Sstevel@tonic-gate int n = gl->buff_curpos - next; 7650*7c478bd9Sstevel@tonic-gate gl_place_cursor(gl, next); 7651*7c478bd9Sstevel@tonic-gate /* 7652*7c478bd9Sstevel@tonic-gate * Copy the specified segment and terminate the string. 7653*7c478bd9Sstevel@tonic-gate */ 7654*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + next, n); 7655*7c478bd9Sstevel@tonic-gate gl->cutbuf[n] = '\0'; 7656*7c478bd9Sstevel@tonic-gate return 0; 7657*7c478bd9Sstevel@tonic-gate } 7658*7c478bd9Sstevel@tonic-gate 7659*7c478bd9Sstevel@tonic-gate /*....................................................................... 7660*7c478bd9Sstevel@tonic-gate * Copy the characters between the cursor and the count'th instance of 7661*7c478bd9Sstevel@tonic-gate * a specified character in the input line, into the cut buffer. 7662*7c478bd9Sstevel@tonic-gate * 7663*7c478bd9Sstevel@tonic-gate * Input: 7664*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 7665*7c478bd9Sstevel@tonic-gate * count int The number of times to search. 7666*7c478bd9Sstevel@tonic-gate * c char The character to be searched for, or '\0' if 7667*7c478bd9Sstevel@tonic-gate * the character should be read from the user. 7668*7c478bd9Sstevel@tonic-gate * forward int True if searching forward. 7669*7c478bd9Sstevel@tonic-gate * onto int True if the search should end on top of the 7670*7c478bd9Sstevel@tonic-gate * character, false if the search should stop 7671*7c478bd9Sstevel@tonic-gate * one character before the character in the 7672*7c478bd9Sstevel@tonic-gate * specified search direction. 7673*7c478bd9Sstevel@tonic-gate * Output: 7674*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 7675*7c478bd9Sstevel@tonic-gate * 1 - Error. 7676*7c478bd9Sstevel@tonic-gate * 7677*7c478bd9Sstevel@tonic-gate */ 7678*7c478bd9Sstevel@tonic-gate static int gl_copy_find(GetLine *gl, int count, char c, int forward, int onto) 7679*7c478bd9Sstevel@tonic-gate { 7680*7c478bd9Sstevel@tonic-gate int n; /* The number of characters in the cut buffer */ 7681*7c478bd9Sstevel@tonic-gate /* 7682*7c478bd9Sstevel@tonic-gate * Search for the character, and abort the operation if not found. 7683*7c478bd9Sstevel@tonic-gate */ 7684*7c478bd9Sstevel@tonic-gate int pos = gl_find_char(gl, count, forward, onto, c); 7685*7c478bd9Sstevel@tonic-gate if(pos < 0) 7686*7c478bd9Sstevel@tonic-gate return 0; 7687*7c478bd9Sstevel@tonic-gate /* 7688*7c478bd9Sstevel@tonic-gate * Copy the specified segment. 7689*7c478bd9Sstevel@tonic-gate */ 7690*7c478bd9Sstevel@tonic-gate if(forward) { 7691*7c478bd9Sstevel@tonic-gate n = pos + 1 - gl->buff_curpos; 7692*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + gl->buff_curpos, n); 7693*7c478bd9Sstevel@tonic-gate } else { 7694*7c478bd9Sstevel@tonic-gate n = gl->buff_curpos - pos; 7695*7c478bd9Sstevel@tonic-gate memcpy(gl->cutbuf, gl->line + pos, n); 7696*7c478bd9Sstevel@tonic-gate if(gl->editor == GL_VI_MODE) 7697*7c478bd9Sstevel@tonic-gate gl_place_cursor(gl, pos); 7698*7c478bd9Sstevel@tonic-gate } 7699*7c478bd9Sstevel@tonic-gate /* 7700*7c478bd9Sstevel@tonic-gate * Terminate the copy. 7701*7c478bd9Sstevel@tonic-gate */ 7702*7c478bd9Sstevel@tonic-gate gl->cutbuf[n] = '\0'; 7703*7c478bd9Sstevel@tonic-gate return 0; 7704*7c478bd9Sstevel@tonic-gate } 7705*7c478bd9Sstevel@tonic-gate 7706*7c478bd9Sstevel@tonic-gate /*....................................................................... 7707*7c478bd9Sstevel@tonic-gate * Copy a section up to and including a specified character into the cut 7708*7c478bd9Sstevel@tonic-gate * buffer without moving the cursor or deleting text. 7709*7c478bd9Sstevel@tonic-gate */ 7710*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_find) 7711*7c478bd9Sstevel@tonic-gate { 7712*7c478bd9Sstevel@tonic-gate return gl_copy_find(gl, count, '\0', 1, 1); 7713*7c478bd9Sstevel@tonic-gate } 7714*7c478bd9Sstevel@tonic-gate 7715*7c478bd9Sstevel@tonic-gate /*....................................................................... 7716*7c478bd9Sstevel@tonic-gate * Copy a section back to and including a specified character into the cut 7717*7c478bd9Sstevel@tonic-gate * buffer without moving the cursor or deleting text. 7718*7c478bd9Sstevel@tonic-gate */ 7719*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_find) 7720*7c478bd9Sstevel@tonic-gate { 7721*7c478bd9Sstevel@tonic-gate return gl_copy_find(gl, count, '\0', 0, 1); 7722*7c478bd9Sstevel@tonic-gate } 7723*7c478bd9Sstevel@tonic-gate 7724*7c478bd9Sstevel@tonic-gate /*....................................................................... 7725*7c478bd9Sstevel@tonic-gate * Copy a section up to and not including a specified character into the cut 7726*7c478bd9Sstevel@tonic-gate * buffer without moving the cursor or deleting text. 7727*7c478bd9Sstevel@tonic-gate */ 7728*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_forward_copy_to) 7729*7c478bd9Sstevel@tonic-gate { 7730*7c478bd9Sstevel@tonic-gate return gl_copy_find(gl, count, '\0', 1, 0); 7731*7c478bd9Sstevel@tonic-gate } 7732*7c478bd9Sstevel@tonic-gate 7733*7c478bd9Sstevel@tonic-gate /*....................................................................... 7734*7c478bd9Sstevel@tonic-gate * Copy a section back to and not including a specified character into the cut 7735*7c478bd9Sstevel@tonic-gate * buffer without moving the cursor or deleting text. 7736*7c478bd9Sstevel@tonic-gate */ 7737*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_backward_copy_to) 7738*7c478bd9Sstevel@tonic-gate { 7739*7c478bd9Sstevel@tonic-gate return gl_copy_find(gl, count, '\0', 0, 0); 7740*7c478bd9Sstevel@tonic-gate } 7741*7c478bd9Sstevel@tonic-gate 7742*7c478bd9Sstevel@tonic-gate /*....................................................................... 7743*7c478bd9Sstevel@tonic-gate * Copy to a character specified in a previous search into the cut 7744*7c478bd9Sstevel@tonic-gate * buffer without moving the cursor or deleting text. 7745*7c478bd9Sstevel@tonic-gate */ 7746*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_refind) 7747*7c478bd9Sstevel@tonic-gate { 7748*7c478bd9Sstevel@tonic-gate return gl_copy_find(gl, count, gl->vi.find_char, gl->vi.find_forward, 7749*7c478bd9Sstevel@tonic-gate gl->vi.find_onto); 7750*7c478bd9Sstevel@tonic-gate } 7751*7c478bd9Sstevel@tonic-gate 7752*7c478bd9Sstevel@tonic-gate /*....................................................................... 7753*7c478bd9Sstevel@tonic-gate * Copy to a character specified in a previous search, but in the opposite 7754*7c478bd9Sstevel@tonic-gate * direction, into the cut buffer without moving the cursor or deleting text. 7755*7c478bd9Sstevel@tonic-gate */ 7756*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_copy_invert_refind) 7757*7c478bd9Sstevel@tonic-gate { 7758*7c478bd9Sstevel@tonic-gate return gl_copy_find(gl, count, gl->vi.find_char, !gl->vi.find_forward, 7759*7c478bd9Sstevel@tonic-gate gl->vi.find_onto); 7760*7c478bd9Sstevel@tonic-gate } 7761*7c478bd9Sstevel@tonic-gate 7762*7c478bd9Sstevel@tonic-gate /*....................................................................... 7763*7c478bd9Sstevel@tonic-gate * Set the position of the cursor in the line input buffer and the 7764*7c478bd9Sstevel@tonic-gate * terminal. 7765*7c478bd9Sstevel@tonic-gate * 7766*7c478bd9Sstevel@tonic-gate * Input: 7767*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 7768*7c478bd9Sstevel@tonic-gate * buff_curpos int The new buffer cursor position. 7769*7c478bd9Sstevel@tonic-gate * Output: 7770*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 7771*7c478bd9Sstevel@tonic-gate * 1 - Error. 7772*7c478bd9Sstevel@tonic-gate */ 7773*7c478bd9Sstevel@tonic-gate static int gl_place_cursor(GetLine *gl, int buff_curpos) 7774*7c478bd9Sstevel@tonic-gate { 7775*7c478bd9Sstevel@tonic-gate /* 7776*7c478bd9Sstevel@tonic-gate * Don't allow the cursor position to go out of the bounds of the input 7777*7c478bd9Sstevel@tonic-gate * line. 7778*7c478bd9Sstevel@tonic-gate */ 7779*7c478bd9Sstevel@tonic-gate if(buff_curpos >= gl->ntotal) 7780*7c478bd9Sstevel@tonic-gate buff_curpos = gl->vi.command ? gl->ntotal-1 : gl->ntotal; 7781*7c478bd9Sstevel@tonic-gate if(buff_curpos < 0) 7782*7c478bd9Sstevel@tonic-gate buff_curpos = 0; 7783*7c478bd9Sstevel@tonic-gate /* 7784*7c478bd9Sstevel@tonic-gate * Record the new buffer position. 7785*7c478bd9Sstevel@tonic-gate */ 7786*7c478bd9Sstevel@tonic-gate gl->buff_curpos = buff_curpos; 7787*7c478bd9Sstevel@tonic-gate /* 7788*7c478bd9Sstevel@tonic-gate * Move the terminal cursor to the corresponding character. 7789*7c478bd9Sstevel@tonic-gate */ 7790*7c478bd9Sstevel@tonic-gate return gl_set_term_curpos(gl, gl->prompt_len + 7791*7c478bd9Sstevel@tonic-gate gl_displayed_string_width(gl, gl->line, buff_curpos, gl->prompt_len)); 7792*7c478bd9Sstevel@tonic-gate } 7793*7c478bd9Sstevel@tonic-gate 7794*7c478bd9Sstevel@tonic-gate /*....................................................................... 7795*7c478bd9Sstevel@tonic-gate * In vi command mode, this function saves the current line to the 7796*7c478bd9Sstevel@tonic-gate * historical buffer needed by the undo command. In emacs mode it does 7797*7c478bd9Sstevel@tonic-gate * nothing. In order to allow action functions to call other action 7798*7c478bd9Sstevel@tonic-gate * functions, gl_interpret_char() sets gl->vi.undo.saved to 0 before 7799*7c478bd9Sstevel@tonic-gate * invoking an action, and thereafter once any call to this function 7800*7c478bd9Sstevel@tonic-gate * has set it to 1, further calls are ignored. 7801*7c478bd9Sstevel@tonic-gate * 7802*7c478bd9Sstevel@tonic-gate * Input: 7803*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 7804*7c478bd9Sstevel@tonic-gate */ 7805*7c478bd9Sstevel@tonic-gate static void gl_save_for_undo(GetLine *gl) 7806*7c478bd9Sstevel@tonic-gate { 7807*7c478bd9Sstevel@tonic-gate if(gl->vi.command && !gl->vi.undo.saved) { 7808*7c478bd9Sstevel@tonic-gate strlcpy(gl->vi.undo.line, gl->line, gl->linelen); 7809*7c478bd9Sstevel@tonic-gate gl->vi.undo.buff_curpos = gl->buff_curpos; 7810*7c478bd9Sstevel@tonic-gate gl->vi.undo.ntotal = gl->ntotal; 7811*7c478bd9Sstevel@tonic-gate gl->vi.undo.saved = 1; 7812*7c478bd9Sstevel@tonic-gate }; 7813*7c478bd9Sstevel@tonic-gate if(gl->vi.command && !gl->vi.repeat.saved && 7814*7c478bd9Sstevel@tonic-gate gl->current_action.fn != gl_vi_repeat_change) { 7815*7c478bd9Sstevel@tonic-gate gl->vi.repeat.action = gl->current_action; 7816*7c478bd9Sstevel@tonic-gate gl->vi.repeat.count = gl->current_count; 7817*7c478bd9Sstevel@tonic-gate gl->vi.repeat.saved = 1; 7818*7c478bd9Sstevel@tonic-gate }; 7819*7c478bd9Sstevel@tonic-gate return; 7820*7c478bd9Sstevel@tonic-gate } 7821*7c478bd9Sstevel@tonic-gate 7822*7c478bd9Sstevel@tonic-gate /*....................................................................... 7823*7c478bd9Sstevel@tonic-gate * In vi mode, restore the line to the way it was before the last command 7824*7c478bd9Sstevel@tonic-gate * mode operation, storing the current line in the buffer so that the 7825*7c478bd9Sstevel@tonic-gate * undo operation itself can subsequently be undone. 7826*7c478bd9Sstevel@tonic-gate */ 7827*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_undo) 7828*7c478bd9Sstevel@tonic-gate { 7829*7c478bd9Sstevel@tonic-gate /* 7830*7c478bd9Sstevel@tonic-gate * Get pointers into the two lines. 7831*7c478bd9Sstevel@tonic-gate */ 7832*7c478bd9Sstevel@tonic-gate char *undo_ptr = gl->vi.undo.line; 7833*7c478bd9Sstevel@tonic-gate char *line_ptr = gl->line; 7834*7c478bd9Sstevel@tonic-gate /* 7835*7c478bd9Sstevel@tonic-gate * Swap the characters of the two buffers up to the length of the shortest 7836*7c478bd9Sstevel@tonic-gate * line. 7837*7c478bd9Sstevel@tonic-gate */ 7838*7c478bd9Sstevel@tonic-gate while(*undo_ptr && *line_ptr) { 7839*7c478bd9Sstevel@tonic-gate char c = *undo_ptr; 7840*7c478bd9Sstevel@tonic-gate *undo_ptr++ = *line_ptr; 7841*7c478bd9Sstevel@tonic-gate *line_ptr++ = c; 7842*7c478bd9Sstevel@tonic-gate }; 7843*7c478bd9Sstevel@tonic-gate /* 7844*7c478bd9Sstevel@tonic-gate * Copy the rest directly. 7845*7c478bd9Sstevel@tonic-gate */ 7846*7c478bd9Sstevel@tonic-gate if(gl->ntotal > gl->vi.undo.ntotal) { 7847*7c478bd9Sstevel@tonic-gate strlcpy(undo_ptr, line_ptr, gl->linelen); 7848*7c478bd9Sstevel@tonic-gate *line_ptr = '\0'; 7849*7c478bd9Sstevel@tonic-gate } else { 7850*7c478bd9Sstevel@tonic-gate strlcpy(line_ptr, undo_ptr, gl->linelen); 7851*7c478bd9Sstevel@tonic-gate *undo_ptr = '\0'; 7852*7c478bd9Sstevel@tonic-gate }; 7853*7c478bd9Sstevel@tonic-gate /* 7854*7c478bd9Sstevel@tonic-gate * Record the length of the stored string. 7855*7c478bd9Sstevel@tonic-gate */ 7856*7c478bd9Sstevel@tonic-gate gl->vi.undo.ntotal = gl->ntotal; 7857*7c478bd9Sstevel@tonic-gate /* 7858*7c478bd9Sstevel@tonic-gate * Accomodate the new contents of gl->line[]. 7859*7c478bd9Sstevel@tonic-gate */ 7860*7c478bd9Sstevel@tonic-gate gl_update_buffer(gl); 7861*7c478bd9Sstevel@tonic-gate /* 7862*7c478bd9Sstevel@tonic-gate * Set both cursor positions to the leftmost of the saved and current 7863*7c478bd9Sstevel@tonic-gate * cursor positions to emulate what vi does. 7864*7c478bd9Sstevel@tonic-gate */ 7865*7c478bd9Sstevel@tonic-gate if(gl->buff_curpos < gl->vi.undo.buff_curpos) 7866*7c478bd9Sstevel@tonic-gate gl->vi.undo.buff_curpos = gl->buff_curpos; 7867*7c478bd9Sstevel@tonic-gate else 7868*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->vi.undo.buff_curpos; 7869*7c478bd9Sstevel@tonic-gate /* 7870*7c478bd9Sstevel@tonic-gate * Since we have bipassed calling gl_save_for_undo(), record repeat 7871*7c478bd9Sstevel@tonic-gate * information inline. 7872*7c478bd9Sstevel@tonic-gate */ 7873*7c478bd9Sstevel@tonic-gate gl->vi.repeat.action.fn = gl_vi_undo; 7874*7c478bd9Sstevel@tonic-gate gl->vi.repeat.action.data = NULL; 7875*7c478bd9Sstevel@tonic-gate gl->vi.repeat.count = 1; 7876*7c478bd9Sstevel@tonic-gate /* 7877*7c478bd9Sstevel@tonic-gate * Display the restored line. 7878*7c478bd9Sstevel@tonic-gate */ 7879*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 7880*7c478bd9Sstevel@tonic-gate return 0; 7881*7c478bd9Sstevel@tonic-gate } 7882*7c478bd9Sstevel@tonic-gate 7883*7c478bd9Sstevel@tonic-gate /*....................................................................... 7884*7c478bd9Sstevel@tonic-gate * Delete the following word and leave the user in vi insert mode. 7885*7c478bd9Sstevel@tonic-gate */ 7886*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_word) 7887*7c478bd9Sstevel@tonic-gate { 7888*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7889*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; /* Allow cursor at EOL */ 7890*7c478bd9Sstevel@tonic-gate return gl_forward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL); 7891*7c478bd9Sstevel@tonic-gate } 7892*7c478bd9Sstevel@tonic-gate 7893*7c478bd9Sstevel@tonic-gate /*....................................................................... 7894*7c478bd9Sstevel@tonic-gate * Delete the preceding word and leave the user in vi insert mode. 7895*7c478bd9Sstevel@tonic-gate */ 7896*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_word) 7897*7c478bd9Sstevel@tonic-gate { 7898*7c478bd9Sstevel@tonic-gate return gl_backward_delete_word(gl, count, NULL) || gl_vi_insert(gl, 0, NULL); 7899*7c478bd9Sstevel@tonic-gate } 7900*7c478bd9Sstevel@tonic-gate 7901*7c478bd9Sstevel@tonic-gate /*....................................................................... 7902*7c478bd9Sstevel@tonic-gate * Delete the following section and leave the user in vi insert mode. 7903*7c478bd9Sstevel@tonic-gate */ 7904*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_find) 7905*7c478bd9Sstevel@tonic-gate { 7906*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, '\0', 1, 1, 1); 7907*7c478bd9Sstevel@tonic-gate } 7908*7c478bd9Sstevel@tonic-gate 7909*7c478bd9Sstevel@tonic-gate /*....................................................................... 7910*7c478bd9Sstevel@tonic-gate * Delete the preceding section and leave the user in vi insert mode. 7911*7c478bd9Sstevel@tonic-gate */ 7912*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_find) 7913*7c478bd9Sstevel@tonic-gate { 7914*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, '\0', 0, 1, 1); 7915*7c478bd9Sstevel@tonic-gate } 7916*7c478bd9Sstevel@tonic-gate 7917*7c478bd9Sstevel@tonic-gate /*....................................................................... 7918*7c478bd9Sstevel@tonic-gate * Delete the following section and leave the user in vi insert mode. 7919*7c478bd9Sstevel@tonic-gate */ 7920*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_to) 7921*7c478bd9Sstevel@tonic-gate { 7922*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, '\0', 1, 0, 1); 7923*7c478bd9Sstevel@tonic-gate } 7924*7c478bd9Sstevel@tonic-gate 7925*7c478bd9Sstevel@tonic-gate /*....................................................................... 7926*7c478bd9Sstevel@tonic-gate * Delete the preceding section and leave the user in vi insert mode. 7927*7c478bd9Sstevel@tonic-gate */ 7928*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_to) 7929*7c478bd9Sstevel@tonic-gate { 7930*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, '\0', 0, 0, 1); 7931*7c478bd9Sstevel@tonic-gate } 7932*7c478bd9Sstevel@tonic-gate 7933*7c478bd9Sstevel@tonic-gate /*....................................................................... 7934*7c478bd9Sstevel@tonic-gate * Delete to a character specified by a previous search and leave the user 7935*7c478bd9Sstevel@tonic-gate * in vi insert mode. 7936*7c478bd9Sstevel@tonic-gate */ 7937*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_refind) 7938*7c478bd9Sstevel@tonic-gate { 7939*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, gl->vi.find_char, gl->vi.find_forward, 7940*7c478bd9Sstevel@tonic-gate gl->vi.find_onto, 1); 7941*7c478bd9Sstevel@tonic-gate } 7942*7c478bd9Sstevel@tonic-gate 7943*7c478bd9Sstevel@tonic-gate /*....................................................................... 7944*7c478bd9Sstevel@tonic-gate * Delete to a character specified by a previous search, but in the opposite 7945*7c478bd9Sstevel@tonic-gate * direction, and leave the user in vi insert mode. 7946*7c478bd9Sstevel@tonic-gate */ 7947*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_invert_refind) 7948*7c478bd9Sstevel@tonic-gate { 7949*7c478bd9Sstevel@tonic-gate return gl_delete_find(gl, count, gl->vi.find_char, !gl->vi.find_forward, 7950*7c478bd9Sstevel@tonic-gate gl->vi.find_onto, 1); 7951*7c478bd9Sstevel@tonic-gate } 7952*7c478bd9Sstevel@tonic-gate 7953*7c478bd9Sstevel@tonic-gate /*....................................................................... 7954*7c478bd9Sstevel@tonic-gate * Delete the following character and leave the user in vi insert mode. 7955*7c478bd9Sstevel@tonic-gate */ 7956*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_forward_change_char) 7957*7c478bd9Sstevel@tonic-gate { 7958*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7959*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; /* Allow cursor at EOL */ 7960*7c478bd9Sstevel@tonic-gate return gl_delete_chars(gl, count, 1) || gl_vi_insert(gl, 0, NULL); 7961*7c478bd9Sstevel@tonic-gate } 7962*7c478bd9Sstevel@tonic-gate 7963*7c478bd9Sstevel@tonic-gate /*....................................................................... 7964*7c478bd9Sstevel@tonic-gate * Delete the preceding character and leave the user in vi insert mode. 7965*7c478bd9Sstevel@tonic-gate */ 7966*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_backward_change_char) 7967*7c478bd9Sstevel@tonic-gate { 7968*7c478bd9Sstevel@tonic-gate return gl_backward_delete_char(gl, count, NULL) || gl_vi_insert(gl, 0, NULL); 7969*7c478bd9Sstevel@tonic-gate } 7970*7c478bd9Sstevel@tonic-gate 7971*7c478bd9Sstevel@tonic-gate /*....................................................................... 7972*7c478bd9Sstevel@tonic-gate * Starting from the cursor position change characters to the specified column. 7973*7c478bd9Sstevel@tonic-gate */ 7974*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_column) 7975*7c478bd9Sstevel@tonic-gate { 7976*7c478bd9Sstevel@tonic-gate if (--count >= gl->buff_curpos) 7977*7c478bd9Sstevel@tonic-gate return gl_vi_forward_change_char(gl, count - gl->buff_curpos, NULL); 7978*7c478bd9Sstevel@tonic-gate else 7979*7c478bd9Sstevel@tonic-gate return gl_vi_backward_change_char(gl, gl->buff_curpos - count, NULL); 7980*7c478bd9Sstevel@tonic-gate } 7981*7c478bd9Sstevel@tonic-gate 7982*7c478bd9Sstevel@tonic-gate /*....................................................................... 7983*7c478bd9Sstevel@tonic-gate * Starting from the cursor position change characters to a matching 7984*7c478bd9Sstevel@tonic-gate * parenthesis. 7985*7c478bd9Sstevel@tonic-gate */ 7986*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_change_to_parenthesis) 7987*7c478bd9Sstevel@tonic-gate { 7988*7c478bd9Sstevel@tonic-gate int curpos = gl_index_of_matching_paren(gl); 7989*7c478bd9Sstevel@tonic-gate if(curpos >= 0) { 7990*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 7991*7c478bd9Sstevel@tonic-gate if(curpos >= gl->buff_curpos) 7992*7c478bd9Sstevel@tonic-gate return gl_vi_forward_change_char(gl, curpos - gl->buff_curpos + 1, NULL); 7993*7c478bd9Sstevel@tonic-gate else 7994*7c478bd9Sstevel@tonic-gate return gl_vi_backward_change_char(gl, ++gl->buff_curpos - curpos + 1, 7995*7c478bd9Sstevel@tonic-gate NULL); 7996*7c478bd9Sstevel@tonic-gate }; 7997*7c478bd9Sstevel@tonic-gate return 0; 7998*7c478bd9Sstevel@tonic-gate } 7999*7c478bd9Sstevel@tonic-gate 8000*7c478bd9Sstevel@tonic-gate /*....................................................................... 8001*7c478bd9Sstevel@tonic-gate * If in vi mode, switch to vi command mode. 8002*7c478bd9Sstevel@tonic-gate * 8003*7c478bd9Sstevel@tonic-gate * Input: 8004*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 8005*7c478bd9Sstevel@tonic-gate */ 8006*7c478bd9Sstevel@tonic-gate static void gl_vi_command_mode(GetLine *gl) 8007*7c478bd9Sstevel@tonic-gate { 8008*7c478bd9Sstevel@tonic-gate if(gl->editor == GL_VI_MODE && !gl->vi.command) { 8009*7c478bd9Sstevel@tonic-gate gl->insert = 1; 8010*7c478bd9Sstevel@tonic-gate gl->vi.command = 1; 8011*7c478bd9Sstevel@tonic-gate gl->vi.repeat.input_curpos = gl->insert_curpos; 8012*7c478bd9Sstevel@tonic-gate gl->vi.repeat.command_curpos = gl->buff_curpos; 8013*7c478bd9Sstevel@tonic-gate gl->insert_curpos = 0; /* unrestrict left motion boundary */ 8014*7c478bd9Sstevel@tonic-gate gl_cursor_left(gl, 1, NULL); /* Vi moves 1 left on entering command mode */ 8015*7c478bd9Sstevel@tonic-gate }; 8016*7c478bd9Sstevel@tonic-gate } 8017*7c478bd9Sstevel@tonic-gate 8018*7c478bd9Sstevel@tonic-gate /*....................................................................... 8019*7c478bd9Sstevel@tonic-gate * This is an action function which rings the terminal bell. 8020*7c478bd9Sstevel@tonic-gate */ 8021*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_ring_bell) 8022*7c478bd9Sstevel@tonic-gate { 8023*7c478bd9Sstevel@tonic-gate return gl->silence_bell ? 0 : 8024*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, 1, gl->sound_bell); 8025*7c478bd9Sstevel@tonic-gate } 8026*7c478bd9Sstevel@tonic-gate 8027*7c478bd9Sstevel@tonic-gate /*....................................................................... 8028*7c478bd9Sstevel@tonic-gate * This is the action function which implements the vi-repeat-change 8029*7c478bd9Sstevel@tonic-gate * action. 8030*7c478bd9Sstevel@tonic-gate */ 8031*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_vi_repeat_change) 8032*7c478bd9Sstevel@tonic-gate { 8033*7c478bd9Sstevel@tonic-gate int status; /* The return status of the repeated action function */ 8034*7c478bd9Sstevel@tonic-gate int i; 8035*7c478bd9Sstevel@tonic-gate /* 8036*7c478bd9Sstevel@tonic-gate * Nothing to repeat? 8037*7c478bd9Sstevel@tonic-gate */ 8038*7c478bd9Sstevel@tonic-gate if(!gl->vi.repeat.action.fn) 8039*7c478bd9Sstevel@tonic-gate return gl_ring_bell(gl, 1, NULL); 8040*7c478bd9Sstevel@tonic-gate /* 8041*7c478bd9Sstevel@tonic-gate * Provide a way for action functions to know whether they are being 8042*7c478bd9Sstevel@tonic-gate * called by us. 8043*7c478bd9Sstevel@tonic-gate */ 8044*7c478bd9Sstevel@tonic-gate gl->vi.repeat.active = 1; 8045*7c478bd9Sstevel@tonic-gate /* 8046*7c478bd9Sstevel@tonic-gate * Re-run the recorded function. 8047*7c478bd9Sstevel@tonic-gate */ 8048*7c478bd9Sstevel@tonic-gate status = gl->vi.repeat.action.fn(gl, gl->vi.repeat.count, 8049*7c478bd9Sstevel@tonic-gate gl->vi.repeat.action.data); 8050*7c478bd9Sstevel@tonic-gate /* 8051*7c478bd9Sstevel@tonic-gate * Mark the repeat as completed. 8052*7c478bd9Sstevel@tonic-gate */ 8053*7c478bd9Sstevel@tonic-gate gl->vi.repeat.active = 0; 8054*7c478bd9Sstevel@tonic-gate /* 8055*7c478bd9Sstevel@tonic-gate * Is we are repeating a function that has just switched to input 8056*7c478bd9Sstevel@tonic-gate * mode to allow the user to type, re-enter the text that the user 8057*7c478bd9Sstevel@tonic-gate * previously entered. 8058*7c478bd9Sstevel@tonic-gate */ 8059*7c478bd9Sstevel@tonic-gate if(status==0 && !gl->vi.command) { 8060*7c478bd9Sstevel@tonic-gate /* 8061*7c478bd9Sstevel@tonic-gate * Make sure that the current line has been saved. 8062*7c478bd9Sstevel@tonic-gate */ 8063*7c478bd9Sstevel@tonic-gate gl_save_for_undo(gl); 8064*7c478bd9Sstevel@tonic-gate /* 8065*7c478bd9Sstevel@tonic-gate * Repeat a previous insertion or overwrite? 8066*7c478bd9Sstevel@tonic-gate */ 8067*7c478bd9Sstevel@tonic-gate if(gl->vi.repeat.input_curpos >= 0 && 8068*7c478bd9Sstevel@tonic-gate gl->vi.repeat.input_curpos <= gl->vi.repeat.command_curpos && 8069*7c478bd9Sstevel@tonic-gate gl->vi.repeat.command_curpos <= gl->vi.undo.ntotal) { 8070*7c478bd9Sstevel@tonic-gate /* 8071*7c478bd9Sstevel@tonic-gate * Using the current line which is saved in the undo buffer, plus 8072*7c478bd9Sstevel@tonic-gate * the range of characters therein, as recorded by gl_vi_command_mode(), 8073*7c478bd9Sstevel@tonic-gate * add the characters that the user previously entered, to the input 8074*7c478bd9Sstevel@tonic-gate * line. 8075*7c478bd9Sstevel@tonic-gate */ 8076*7c478bd9Sstevel@tonic-gate for(i=gl->vi.repeat.input_curpos; i<gl->vi.repeat.command_curpos; i++) { 8077*7c478bd9Sstevel@tonic-gate if(gl_add_char_to_line(gl, gl->vi.undo.line[i])) 8078*7c478bd9Sstevel@tonic-gate return 1; 8079*7c478bd9Sstevel@tonic-gate }; 8080*7c478bd9Sstevel@tonic-gate }; 8081*7c478bd9Sstevel@tonic-gate /* 8082*7c478bd9Sstevel@tonic-gate * Switch back to command mode, now that the insertion has been repeated. 8083*7c478bd9Sstevel@tonic-gate */ 8084*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 8085*7c478bd9Sstevel@tonic-gate }; 8086*7c478bd9Sstevel@tonic-gate return status; 8087*7c478bd9Sstevel@tonic-gate } 8088*7c478bd9Sstevel@tonic-gate 8089*7c478bd9Sstevel@tonic-gate /*....................................................................... 8090*7c478bd9Sstevel@tonic-gate * If the cursor is currently over a parenthesis character, return the 8091*7c478bd9Sstevel@tonic-gate * index of its matching parenthesis. If not currently over a parenthesis 8092*7c478bd9Sstevel@tonic-gate * character, return the next close parenthesis character to the right of 8093*7c478bd9Sstevel@tonic-gate * the cursor. If the respective parenthesis character isn't found, 8094*7c478bd9Sstevel@tonic-gate * ring the terminal bell and return -1. 8095*7c478bd9Sstevel@tonic-gate * 8096*7c478bd9Sstevel@tonic-gate * Input: 8097*7c478bd9Sstevel@tonic-gate * gl GetLine * The getline resource object. 8098*7c478bd9Sstevel@tonic-gate * Output: 8099*7c478bd9Sstevel@tonic-gate * return int Either the index of the matching parenthesis, 8100*7c478bd9Sstevel@tonic-gate * or -1 if not found. 8101*7c478bd9Sstevel@tonic-gate */ 8102*7c478bd9Sstevel@tonic-gate static int gl_index_of_matching_paren(GetLine *gl) 8103*7c478bd9Sstevel@tonic-gate { 8104*7c478bd9Sstevel@tonic-gate int i; 8105*7c478bd9Sstevel@tonic-gate /* 8106*7c478bd9Sstevel@tonic-gate * List the recognized parentheses, and their matches. 8107*7c478bd9Sstevel@tonic-gate */ 8108*7c478bd9Sstevel@tonic-gate const char *o_paren = "([{"; 8109*7c478bd9Sstevel@tonic-gate const char *c_paren = ")]}"; 8110*7c478bd9Sstevel@tonic-gate const char *cptr; 8111*7c478bd9Sstevel@tonic-gate /* 8112*7c478bd9Sstevel@tonic-gate * Get the character that is currently under the cursor. 8113*7c478bd9Sstevel@tonic-gate */ 8114*7c478bd9Sstevel@tonic-gate char c = gl->line[gl->buff_curpos]; 8115*7c478bd9Sstevel@tonic-gate /* 8116*7c478bd9Sstevel@tonic-gate * If the character under the cursor is an open parenthesis, look forward 8117*7c478bd9Sstevel@tonic-gate * for the matching close parenthesis. 8118*7c478bd9Sstevel@tonic-gate */ 8119*7c478bd9Sstevel@tonic-gate if((cptr=strchr(o_paren, c))) { 8120*7c478bd9Sstevel@tonic-gate char match = c_paren[cptr - o_paren]; 8121*7c478bd9Sstevel@tonic-gate int matches_needed = 1; 8122*7c478bd9Sstevel@tonic-gate for(i=gl->buff_curpos+1; i<gl->ntotal; i++) { 8123*7c478bd9Sstevel@tonic-gate if(gl->line[i] == c) 8124*7c478bd9Sstevel@tonic-gate matches_needed++; 8125*7c478bd9Sstevel@tonic-gate else if(gl->line[i] == match && --matches_needed==0) 8126*7c478bd9Sstevel@tonic-gate return i; 8127*7c478bd9Sstevel@tonic-gate }; 8128*7c478bd9Sstevel@tonic-gate /* 8129*7c478bd9Sstevel@tonic-gate * If the character under the cursor is an close parenthesis, look forward 8130*7c478bd9Sstevel@tonic-gate * for the matching open parenthesis. 8131*7c478bd9Sstevel@tonic-gate */ 8132*7c478bd9Sstevel@tonic-gate } else if((cptr=strchr(c_paren, c))) { 8133*7c478bd9Sstevel@tonic-gate char match = o_paren[cptr - c_paren]; 8134*7c478bd9Sstevel@tonic-gate int matches_needed = 1; 8135*7c478bd9Sstevel@tonic-gate for(i=gl->buff_curpos-1; i>=0; i--) { 8136*7c478bd9Sstevel@tonic-gate if(gl->line[i] == c) 8137*7c478bd9Sstevel@tonic-gate matches_needed++; 8138*7c478bd9Sstevel@tonic-gate else if(gl->line[i] == match && --matches_needed==0) 8139*7c478bd9Sstevel@tonic-gate return i; 8140*7c478bd9Sstevel@tonic-gate }; 8141*7c478bd9Sstevel@tonic-gate /* 8142*7c478bd9Sstevel@tonic-gate * If not currently over a parenthesis character, search forwards for 8143*7c478bd9Sstevel@tonic-gate * the first close parenthesis (this is what the vi % binding does). 8144*7c478bd9Sstevel@tonic-gate */ 8145*7c478bd9Sstevel@tonic-gate } else { 8146*7c478bd9Sstevel@tonic-gate for(i=gl->buff_curpos+1; i<gl->ntotal; i++) 8147*7c478bd9Sstevel@tonic-gate if(strchr(c_paren, gl->line[i]) != NULL) 8148*7c478bd9Sstevel@tonic-gate return i; 8149*7c478bd9Sstevel@tonic-gate }; 8150*7c478bd9Sstevel@tonic-gate /* 8151*7c478bd9Sstevel@tonic-gate * Not found. 8152*7c478bd9Sstevel@tonic-gate */ 8153*7c478bd9Sstevel@tonic-gate (void) gl_ring_bell(gl, 1, NULL); 8154*7c478bd9Sstevel@tonic-gate return -1; 8155*7c478bd9Sstevel@tonic-gate } 8156*7c478bd9Sstevel@tonic-gate 8157*7c478bd9Sstevel@tonic-gate /*....................................................................... 8158*7c478bd9Sstevel@tonic-gate * If the cursor is currently over a parenthesis character, this action 8159*7c478bd9Sstevel@tonic-gate * function moves the cursor to its matching parenthesis. 8160*7c478bd9Sstevel@tonic-gate */ 8161*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_find_parenthesis) 8162*7c478bd9Sstevel@tonic-gate { 8163*7c478bd9Sstevel@tonic-gate int curpos = gl_index_of_matching_paren(gl); 8164*7c478bd9Sstevel@tonic-gate if(curpos >= 0) 8165*7c478bd9Sstevel@tonic-gate return gl_place_cursor(gl, curpos); 8166*7c478bd9Sstevel@tonic-gate return 0; 8167*7c478bd9Sstevel@tonic-gate } 8168*7c478bd9Sstevel@tonic-gate 8169*7c478bd9Sstevel@tonic-gate /*....................................................................... 8170*7c478bd9Sstevel@tonic-gate * Handle the receipt of the potential start of a new key-sequence from 8171*7c478bd9Sstevel@tonic-gate * the user. 8172*7c478bd9Sstevel@tonic-gate * 8173*7c478bd9Sstevel@tonic-gate * Input: 8174*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 8175*7c478bd9Sstevel@tonic-gate * first_char char The first character of the sequence. 8176*7c478bd9Sstevel@tonic-gate * Output: 8177*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 8178*7c478bd9Sstevel@tonic-gate * 1 - Error. 8179*7c478bd9Sstevel@tonic-gate */ 8180*7c478bd9Sstevel@tonic-gate static int gl_interpret_char(GetLine *gl, char first_char) 8181*7c478bd9Sstevel@tonic-gate { 8182*7c478bd9Sstevel@tonic-gate char keyseq[GL_KEY_MAX+1]; /* A special key sequence being read */ 8183*7c478bd9Sstevel@tonic-gate int nkey=0; /* The number of characters in the key sequence */ 8184*7c478bd9Sstevel@tonic-gate int count; /* The repeat count of an action function */ 8185*7c478bd9Sstevel@tonic-gate int ret; /* The return value of an action function */ 8186*7c478bd9Sstevel@tonic-gate int i; 8187*7c478bd9Sstevel@tonic-gate /* 8188*7c478bd9Sstevel@tonic-gate * Get the first character. 8189*7c478bd9Sstevel@tonic-gate */ 8190*7c478bd9Sstevel@tonic-gate char c = first_char; 8191*7c478bd9Sstevel@tonic-gate /* 8192*7c478bd9Sstevel@tonic-gate * If editing is disabled, just add newly entered characters to the 8193*7c478bd9Sstevel@tonic-gate * input line buffer, and watch for the end of the line. 8194*7c478bd9Sstevel@tonic-gate */ 8195*7c478bd9Sstevel@tonic-gate if(gl->editor == GL_NO_EDITOR) { 8196*7c478bd9Sstevel@tonic-gate gl_discard_chars(gl, 1); 8197*7c478bd9Sstevel@tonic-gate if(gl->ntotal >= gl->linelen) 8198*7c478bd9Sstevel@tonic-gate return 0; 8199*7c478bd9Sstevel@tonic-gate if(c == '\n' || c == '\r') 8200*7c478bd9Sstevel@tonic-gate return gl_newline(gl, 1, NULL); 8201*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, c, gl->ntotal); 8202*7c478bd9Sstevel@tonic-gate return 0; 8203*7c478bd9Sstevel@tonic-gate }; 8204*7c478bd9Sstevel@tonic-gate /* 8205*7c478bd9Sstevel@tonic-gate * If the user is in the process of specifying a repeat count and the 8206*7c478bd9Sstevel@tonic-gate * new character is a digit, increment the repeat count accordingly. 8207*7c478bd9Sstevel@tonic-gate */ 8208*7c478bd9Sstevel@tonic-gate if(gl->number >= 0 && isdigit((int)(unsigned char) c)) { 8209*7c478bd9Sstevel@tonic-gate gl_discard_chars(gl, 1); 8210*7c478bd9Sstevel@tonic-gate return gl_digit_argument(gl, c, NULL); 8211*7c478bd9Sstevel@tonic-gate /* 8212*7c478bd9Sstevel@tonic-gate * In vi command mode, all key-sequences entered need to be 8213*7c478bd9Sstevel@tonic-gate * either implicitly or explicitly prefixed with an escape character. 8214*7c478bd9Sstevel@tonic-gate */ 8215*7c478bd9Sstevel@tonic-gate } else if(gl->vi.command && c != GL_ESC_CHAR) { 8216*7c478bd9Sstevel@tonic-gate keyseq[nkey++] = GL_ESC_CHAR; 8217*7c478bd9Sstevel@tonic-gate /* 8218*7c478bd9Sstevel@tonic-gate * If the first character of the sequence is a printable character, 8219*7c478bd9Sstevel@tonic-gate * then to avoid confusion with the special "up", "down", "left" 8220*7c478bd9Sstevel@tonic-gate * or "right" cursor key bindings, we need to prefix the 8221*7c478bd9Sstevel@tonic-gate * printable character with a backslash escape before looking it up. 8222*7c478bd9Sstevel@tonic-gate */ 8223*7c478bd9Sstevel@tonic-gate } else if(!IS_META_CHAR(c) && !IS_CTRL_CHAR(c)) { 8224*7c478bd9Sstevel@tonic-gate keyseq[nkey++] = '\\'; 8225*7c478bd9Sstevel@tonic-gate }; 8226*7c478bd9Sstevel@tonic-gate /* 8227*7c478bd9Sstevel@tonic-gate * Compose a potentially multiple key-sequence in gl->keyseq. 8228*7c478bd9Sstevel@tonic-gate */ 8229*7c478bd9Sstevel@tonic-gate while(nkey < GL_KEY_MAX) { 8230*7c478bd9Sstevel@tonic-gate KtAction *action; /* An action function */ 8231*7c478bd9Sstevel@tonic-gate KeySym *keysym; /* The symbol-table entry of a key-sequence */ 8232*7c478bd9Sstevel@tonic-gate int nsym; /* The number of ambiguously matching key-sequences */ 8233*7c478bd9Sstevel@tonic-gate /* 8234*7c478bd9Sstevel@tonic-gate * If the character is an unprintable meta character, split it 8235*7c478bd9Sstevel@tonic-gate * into two characters, an escape character and the character 8236*7c478bd9Sstevel@tonic-gate * that was modified by the meta key. 8237*7c478bd9Sstevel@tonic-gate */ 8238*7c478bd9Sstevel@tonic-gate if(IS_META_CHAR(c)) { 8239*7c478bd9Sstevel@tonic-gate keyseq[nkey++] = GL_ESC_CHAR; 8240*7c478bd9Sstevel@tonic-gate c = META_TO_CHAR(c); 8241*7c478bd9Sstevel@tonic-gate continue; 8242*7c478bd9Sstevel@tonic-gate }; 8243*7c478bd9Sstevel@tonic-gate /* 8244*7c478bd9Sstevel@tonic-gate * Append the latest character to the key sequence. 8245*7c478bd9Sstevel@tonic-gate */ 8246*7c478bd9Sstevel@tonic-gate keyseq[nkey++] = c; 8247*7c478bd9Sstevel@tonic-gate /* 8248*7c478bd9Sstevel@tonic-gate * When doing vi-style editing, an escape at the beginning of any binding 8249*7c478bd9Sstevel@tonic-gate * switches to command mode. 8250*7c478bd9Sstevel@tonic-gate */ 8251*7c478bd9Sstevel@tonic-gate if(keyseq[0] == GL_ESC_CHAR && !gl->vi.command) 8252*7c478bd9Sstevel@tonic-gate gl_vi_command_mode(gl); 8253*7c478bd9Sstevel@tonic-gate /* 8254*7c478bd9Sstevel@tonic-gate * Lookup the key sequence. 8255*7c478bd9Sstevel@tonic-gate */ 8256*7c478bd9Sstevel@tonic-gate switch(_kt_lookup_keybinding(gl->bindings, keyseq, nkey, &keysym, &nsym)) { 8257*7c478bd9Sstevel@tonic-gate case KT_EXACT_MATCH: 8258*7c478bd9Sstevel@tonic-gate /* 8259*7c478bd9Sstevel@tonic-gate * Get the matching action function. 8260*7c478bd9Sstevel@tonic-gate */ 8261*7c478bd9Sstevel@tonic-gate action = keysym->actions + keysym->binder; 8262*7c478bd9Sstevel@tonic-gate /* 8263*7c478bd9Sstevel@tonic-gate * Get the repeat count, passing the last keystroke if executing the 8264*7c478bd9Sstevel@tonic-gate * digit-argument action. 8265*7c478bd9Sstevel@tonic-gate */ 8266*7c478bd9Sstevel@tonic-gate if(action->fn == gl_digit_argument) { 8267*7c478bd9Sstevel@tonic-gate count = c; 8268*7c478bd9Sstevel@tonic-gate } else { 8269*7c478bd9Sstevel@tonic-gate count = gl->number >= 0 ? gl->number : 1; 8270*7c478bd9Sstevel@tonic-gate }; 8271*7c478bd9Sstevel@tonic-gate /* 8272*7c478bd9Sstevel@tonic-gate * Record the function that is being invoked. 8273*7c478bd9Sstevel@tonic-gate */ 8274*7c478bd9Sstevel@tonic-gate gl->current_action = *action; 8275*7c478bd9Sstevel@tonic-gate gl->current_count = count; 8276*7c478bd9Sstevel@tonic-gate /* 8277*7c478bd9Sstevel@tonic-gate * Mark the current line as not yet preserved for use by the vi undo command. 8278*7c478bd9Sstevel@tonic-gate */ 8279*7c478bd9Sstevel@tonic-gate gl->vi.undo.saved = 0; 8280*7c478bd9Sstevel@tonic-gate gl->vi.repeat.saved = 0; 8281*7c478bd9Sstevel@tonic-gate /* 8282*7c478bd9Sstevel@tonic-gate * Execute the action function. Note the action function can tell 8283*7c478bd9Sstevel@tonic-gate * whether the provided repeat count was defaulted or specified 8284*7c478bd9Sstevel@tonic-gate * explicitly by looking at whether gl->number is -1 or not. If 8285*7c478bd9Sstevel@tonic-gate * it is negative, then no repeat count was specified by the user. 8286*7c478bd9Sstevel@tonic-gate */ 8287*7c478bd9Sstevel@tonic-gate ret = action->fn(gl, count, action->data); 8288*7c478bd9Sstevel@tonic-gate /* 8289*7c478bd9Sstevel@tonic-gate * In server mode, the action will return immediately if it tries to 8290*7c478bd9Sstevel@tonic-gate * read input from the terminal, and no input is currently available. 8291*7c478bd9Sstevel@tonic-gate * If this happens, abort. Note that gl_get_input_line() will rewind 8292*7c478bd9Sstevel@tonic-gate * the read-ahead buffer to allow the next call to redo the function 8293*7c478bd9Sstevel@tonic-gate * from scratch. 8294*7c478bd9Sstevel@tonic-gate */ 8295*7c478bd9Sstevel@tonic-gate if(gl->rtn_status == GLR_BLOCKED && gl->pending_io==GLP_READ) 8296*7c478bd9Sstevel@tonic-gate return 1; 8297*7c478bd9Sstevel@tonic-gate /* 8298*7c478bd9Sstevel@tonic-gate * Discard the now processed characters from the key sequence buffer. 8299*7c478bd9Sstevel@tonic-gate */ 8300*7c478bd9Sstevel@tonic-gate gl_discard_chars(gl, gl->nread); 8301*7c478bd9Sstevel@tonic-gate /* 8302*7c478bd9Sstevel@tonic-gate * If the latest action function wasn't a history action, cancel any 8303*7c478bd9Sstevel@tonic-gate * current history search. 8304*7c478bd9Sstevel@tonic-gate */ 8305*7c478bd9Sstevel@tonic-gate if(gl->last_search != gl->keyseq_count) 8306*7c478bd9Sstevel@tonic-gate _glh_cancel_search(gl->glh); 8307*7c478bd9Sstevel@tonic-gate /* 8308*7c478bd9Sstevel@tonic-gate * Reset the repeat count after running action functions. 8309*7c478bd9Sstevel@tonic-gate */ 8310*7c478bd9Sstevel@tonic-gate if(action->fn != gl_digit_argument) 8311*7c478bd9Sstevel@tonic-gate gl->number = -1; 8312*7c478bd9Sstevel@tonic-gate return ret ? 1 : 0; 8313*7c478bd9Sstevel@tonic-gate break; 8314*7c478bd9Sstevel@tonic-gate case KT_AMBIG_MATCH: /* Ambiguous match - so read the next character */ 8315*7c478bd9Sstevel@tonic-gate if(gl_read_terminal(gl, 1, &c)) 8316*7c478bd9Sstevel@tonic-gate return 1; 8317*7c478bd9Sstevel@tonic-gate break; 8318*7c478bd9Sstevel@tonic-gate case KT_NO_MATCH: 8319*7c478bd9Sstevel@tonic-gate /* 8320*7c478bd9Sstevel@tonic-gate * If the first character looked like it might be a prefix of a key-sequence 8321*7c478bd9Sstevel@tonic-gate * but it turned out not to be, ring the bell to tell the user that it 8322*7c478bd9Sstevel@tonic-gate * wasn't recognised. 8323*7c478bd9Sstevel@tonic-gate */ 8324*7c478bd9Sstevel@tonic-gate if(keyseq[0] != '\\' && keyseq[0] != '\t') { 8325*7c478bd9Sstevel@tonic-gate gl_ring_bell(gl, 1, NULL); 8326*7c478bd9Sstevel@tonic-gate } else { 8327*7c478bd9Sstevel@tonic-gate /* 8328*7c478bd9Sstevel@tonic-gate * The user typed a single printable character that doesn't match 8329*7c478bd9Sstevel@tonic-gate * the start of any keysequence, so add it to the line in accordance 8330*7c478bd9Sstevel@tonic-gate * with the current repeat count. 8331*7c478bd9Sstevel@tonic-gate */ 8332*7c478bd9Sstevel@tonic-gate count = gl->number >= 0 ? gl->number : 1; 8333*7c478bd9Sstevel@tonic-gate for(i=0; i<count; i++) 8334*7c478bd9Sstevel@tonic-gate gl_add_char_to_line(gl, first_char); 8335*7c478bd9Sstevel@tonic-gate gl->number = -1; 8336*7c478bd9Sstevel@tonic-gate }; 8337*7c478bd9Sstevel@tonic-gate gl_discard_chars(gl, 1); 8338*7c478bd9Sstevel@tonic-gate _glh_cancel_search(gl->glh); 8339*7c478bd9Sstevel@tonic-gate return 0; 8340*7c478bd9Sstevel@tonic-gate break; 8341*7c478bd9Sstevel@tonic-gate case KT_BAD_MATCH: 8342*7c478bd9Sstevel@tonic-gate gl_ring_bell(gl, 1, NULL); 8343*7c478bd9Sstevel@tonic-gate gl_discard_chars(gl, gl->nread); 8344*7c478bd9Sstevel@tonic-gate _glh_cancel_search(gl->glh); 8345*7c478bd9Sstevel@tonic-gate return 1; 8346*7c478bd9Sstevel@tonic-gate break; 8347*7c478bd9Sstevel@tonic-gate }; 8348*7c478bd9Sstevel@tonic-gate }; 8349*7c478bd9Sstevel@tonic-gate /* 8350*7c478bd9Sstevel@tonic-gate * If the key sequence was too long to match, ring the bell, then 8351*7c478bd9Sstevel@tonic-gate * discard the first character, so that the next attempt to match a 8352*7c478bd9Sstevel@tonic-gate * key-sequence continues with the next key press. In practice this 8353*7c478bd9Sstevel@tonic-gate * shouldn't happen, since one isn't allowed to bind action functions 8354*7c478bd9Sstevel@tonic-gate * to keysequences that are longer than GL_KEY_MAX. 8355*7c478bd9Sstevel@tonic-gate */ 8356*7c478bd9Sstevel@tonic-gate gl_ring_bell(gl, 1, NULL); 8357*7c478bd9Sstevel@tonic-gate gl_discard_chars(gl, 1); 8358*7c478bd9Sstevel@tonic-gate return 0; 8359*7c478bd9Sstevel@tonic-gate } 8360*7c478bd9Sstevel@tonic-gate 8361*7c478bd9Sstevel@tonic-gate /*....................................................................... 8362*7c478bd9Sstevel@tonic-gate * Configure the application and/or user-specific behavior of 8363*7c478bd9Sstevel@tonic-gate * gl_get_line(). 8364*7c478bd9Sstevel@tonic-gate * 8365*7c478bd9Sstevel@tonic-gate * Note that calling this function between calling new_GetLine() and 8366*7c478bd9Sstevel@tonic-gate * the first call to gl_get_line(), disables the otherwise automatic 8367*7c478bd9Sstevel@tonic-gate * reading of ~/.teclarc on the first call to gl_get_line(). 8368*7c478bd9Sstevel@tonic-gate * 8369*7c478bd9Sstevel@tonic-gate * Input: 8370*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 8371*7c478bd9Sstevel@tonic-gate * app_string const char * Either NULL, or a string containing one 8372*7c478bd9Sstevel@tonic-gate * or more .teclarc command lines, separated 8373*7c478bd9Sstevel@tonic-gate * by newline characters. This can be used to 8374*7c478bd9Sstevel@tonic-gate * establish an application-specific 8375*7c478bd9Sstevel@tonic-gate * configuration, without the need for an external 8376*7c478bd9Sstevel@tonic-gate * file. This is particularly useful in embedded 8377*7c478bd9Sstevel@tonic-gate * environments where there is no filesystem. 8378*7c478bd9Sstevel@tonic-gate * app_file const char * Either NULL, or the pathname of an 8379*7c478bd9Sstevel@tonic-gate * application-specific .teclarc file. The 8380*7c478bd9Sstevel@tonic-gate * contents of this file, if provided, are 8381*7c478bd9Sstevel@tonic-gate * read after the contents of app_string[]. 8382*7c478bd9Sstevel@tonic-gate * user_file const char * Either NULL, or the pathname of a 8383*7c478bd9Sstevel@tonic-gate * user-specific .teclarc file. Except in 8384*7c478bd9Sstevel@tonic-gate * embedded applications, this should 8385*7c478bd9Sstevel@tonic-gate * usually be "~/.teclarc". 8386*7c478bd9Sstevel@tonic-gate * Output: 8387*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 8388*7c478bd9Sstevel@tonic-gate * 1 - Bad argument(s). 8389*7c478bd9Sstevel@tonic-gate */ 8390*7c478bd9Sstevel@tonic-gate int gl_configure_getline(GetLine *gl, const char *app_string, 8391*7c478bd9Sstevel@tonic-gate const char *app_file, const char *user_file) 8392*7c478bd9Sstevel@tonic-gate { 8393*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 8394*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_configure_getline() */ 8395*7c478bd9Sstevel@tonic-gate /* 8396*7c478bd9Sstevel@tonic-gate * Check the arguments. 8397*7c478bd9Sstevel@tonic-gate */ 8398*7c478bd9Sstevel@tonic-gate if(!gl) { 8399*7c478bd9Sstevel@tonic-gate errno = EINVAL; 8400*7c478bd9Sstevel@tonic-gate return 1; 8401*7c478bd9Sstevel@tonic-gate }; 8402*7c478bd9Sstevel@tonic-gate /* 8403*7c478bd9Sstevel@tonic-gate * Block all signals. 8404*7c478bd9Sstevel@tonic-gate */ 8405*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 8406*7c478bd9Sstevel@tonic-gate return 1; 8407*7c478bd9Sstevel@tonic-gate /* 8408*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 8409*7c478bd9Sstevel@tonic-gate */ 8410*7c478bd9Sstevel@tonic-gate status = _gl_configure_getline(gl, app_string, app_file, user_file); 8411*7c478bd9Sstevel@tonic-gate /* 8412*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 8413*7c478bd9Sstevel@tonic-gate */ 8414*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 8415*7c478bd9Sstevel@tonic-gate return status; 8416*7c478bd9Sstevel@tonic-gate } 8417*7c478bd9Sstevel@tonic-gate 8418*7c478bd9Sstevel@tonic-gate /*....................................................................... 8419*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_configure_getline() function. It 8420*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 8421*7c478bd9Sstevel@tonic-gate * delivery of signals. 8422*7c478bd9Sstevel@tonic-gate */ 8423*7c478bd9Sstevel@tonic-gate static int _gl_configure_getline(GetLine *gl, const char *app_string, 8424*7c478bd9Sstevel@tonic-gate const char *app_file, const char *user_file) 8425*7c478bd9Sstevel@tonic-gate { 8426*7c478bd9Sstevel@tonic-gate /* 8427*7c478bd9Sstevel@tonic-gate * Mark getline as having been explicitly configured. 8428*7c478bd9Sstevel@tonic-gate */ 8429*7c478bd9Sstevel@tonic-gate gl->configured = 1; 8430*7c478bd9Sstevel@tonic-gate /* 8431*7c478bd9Sstevel@tonic-gate * Start by parsing the configuration string, if provided. 8432*7c478bd9Sstevel@tonic-gate */ 8433*7c478bd9Sstevel@tonic-gate if(app_string) 8434*7c478bd9Sstevel@tonic-gate (void) _gl_read_config_string(gl, app_string, KTB_NORM); 8435*7c478bd9Sstevel@tonic-gate /* 8436*7c478bd9Sstevel@tonic-gate * Now parse the application-specific configuration file, if provided. 8437*7c478bd9Sstevel@tonic-gate */ 8438*7c478bd9Sstevel@tonic-gate if(app_file) 8439*7c478bd9Sstevel@tonic-gate (void) _gl_read_config_file(gl, app_file, KTB_NORM); 8440*7c478bd9Sstevel@tonic-gate /* 8441*7c478bd9Sstevel@tonic-gate * Finally, parse the user-specific configuration file, if provided. 8442*7c478bd9Sstevel@tonic-gate */ 8443*7c478bd9Sstevel@tonic-gate if(user_file) 8444*7c478bd9Sstevel@tonic-gate (void) _gl_read_config_file(gl, user_file, KTB_USER); 8445*7c478bd9Sstevel@tonic-gate /* 8446*7c478bd9Sstevel@tonic-gate * Record the names of the configuration files to allow them to 8447*7c478bd9Sstevel@tonic-gate * be re-read if requested at a later time. 8448*7c478bd9Sstevel@tonic-gate */ 8449*7c478bd9Sstevel@tonic-gate if(gl_record_string(&gl->app_file, app_file) || 8450*7c478bd9Sstevel@tonic-gate gl_record_string(&gl->user_file, user_file)) { 8451*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 8452*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, 8453*7c478bd9Sstevel@tonic-gate "Insufficient memory to record tecla configuration file names", 8454*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 8455*7c478bd9Sstevel@tonic-gate return 1; 8456*7c478bd9Sstevel@tonic-gate }; 8457*7c478bd9Sstevel@tonic-gate return 0; 8458*7c478bd9Sstevel@tonic-gate } 8459*7c478bd9Sstevel@tonic-gate 8460*7c478bd9Sstevel@tonic-gate /*....................................................................... 8461*7c478bd9Sstevel@tonic-gate * Replace a malloc'd string (or NULL), with another malloc'd copy of 8462*7c478bd9Sstevel@tonic-gate * a string (or NULL). 8463*7c478bd9Sstevel@tonic-gate * 8464*7c478bd9Sstevel@tonic-gate * Input: 8465*7c478bd9Sstevel@tonic-gate * sptr char ** On input if *sptr!=NULL, *sptr will be 8466*7c478bd9Sstevel@tonic-gate * free'd and *sptr will be set to NULL. Then, 8467*7c478bd9Sstevel@tonic-gate * on output, if string!=NULL a malloc'd copy 8468*7c478bd9Sstevel@tonic-gate * of this string will be assigned to *sptr. 8469*7c478bd9Sstevel@tonic-gate * string const char * The string to be copied, or NULL to simply 8470*7c478bd9Sstevel@tonic-gate * discard any existing string. 8471*7c478bd9Sstevel@tonic-gate * Output: 8472*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 8473*7c478bd9Sstevel@tonic-gate * 1 - Malloc failure (no error message is generated). 8474*7c478bd9Sstevel@tonic-gate */ 8475*7c478bd9Sstevel@tonic-gate static int gl_record_string(char **sptr, const char *string) 8476*7c478bd9Sstevel@tonic-gate { 8477*7c478bd9Sstevel@tonic-gate /* 8478*7c478bd9Sstevel@tonic-gate * If the original string is the same string, don't do anything. 8479*7c478bd9Sstevel@tonic-gate */ 8480*7c478bd9Sstevel@tonic-gate if(*sptr == string || (*sptr && string && strcmp(*sptr, string)==0)) 8481*7c478bd9Sstevel@tonic-gate return 0; 8482*7c478bd9Sstevel@tonic-gate /* 8483*7c478bd9Sstevel@tonic-gate * Discard any existing cached string. 8484*7c478bd9Sstevel@tonic-gate */ 8485*7c478bd9Sstevel@tonic-gate if(*sptr) { 8486*7c478bd9Sstevel@tonic-gate free(*sptr); 8487*7c478bd9Sstevel@tonic-gate *sptr = NULL; 8488*7c478bd9Sstevel@tonic-gate }; 8489*7c478bd9Sstevel@tonic-gate /* 8490*7c478bd9Sstevel@tonic-gate * Allocate memory for a copy of the specified string. 8491*7c478bd9Sstevel@tonic-gate */ 8492*7c478bd9Sstevel@tonic-gate if(string) { 8493*7c478bd9Sstevel@tonic-gate size_t ssz = strlen(string) + 1; 8494*7c478bd9Sstevel@tonic-gate *sptr = (char *) malloc(ssz); 8495*7c478bd9Sstevel@tonic-gate if(!*sptr) 8496*7c478bd9Sstevel@tonic-gate return 1; 8497*7c478bd9Sstevel@tonic-gate /* 8498*7c478bd9Sstevel@tonic-gate * Copy the string. 8499*7c478bd9Sstevel@tonic-gate */ 8500*7c478bd9Sstevel@tonic-gate strlcpy(*sptr, string, ssz); 8501*7c478bd9Sstevel@tonic-gate }; 8502*7c478bd9Sstevel@tonic-gate return 0; 8503*7c478bd9Sstevel@tonic-gate } 8504*7c478bd9Sstevel@tonic-gate 8505*7c478bd9Sstevel@tonic-gate #ifndef HIDE_FILE_SYSTEM 8506*7c478bd9Sstevel@tonic-gate /*....................................................................... 8507*7c478bd9Sstevel@tonic-gate * Re-read any application-specific and user-specific files previously 8508*7c478bd9Sstevel@tonic-gate * specified via the gl_configure_getline() function. 8509*7c478bd9Sstevel@tonic-gate */ 8510*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_read_init_files) 8511*7c478bd9Sstevel@tonic-gate { 8512*7c478bd9Sstevel@tonic-gate return _gl_configure_getline(gl, NULL, gl->app_file, gl->user_file); 8513*7c478bd9Sstevel@tonic-gate } 8514*7c478bd9Sstevel@tonic-gate #endif 8515*7c478bd9Sstevel@tonic-gate 8516*7c478bd9Sstevel@tonic-gate /*....................................................................... 8517*7c478bd9Sstevel@tonic-gate * Save the contents of the history buffer to a given new file. 8518*7c478bd9Sstevel@tonic-gate * 8519*7c478bd9Sstevel@tonic-gate * Input: 8520*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 8521*7c478bd9Sstevel@tonic-gate * filename const char * The name of the new file to write to. 8522*7c478bd9Sstevel@tonic-gate * comment const char * Extra information such as timestamps will 8523*7c478bd9Sstevel@tonic-gate * be recorded on a line started with this 8524*7c478bd9Sstevel@tonic-gate * string, the idea being that the file can 8525*7c478bd9Sstevel@tonic-gate * double as a command file. Specify "" if 8526*7c478bd9Sstevel@tonic-gate * you don't care. 8527*7c478bd9Sstevel@tonic-gate * max_lines int The maximum number of lines to save, or -1 8528*7c478bd9Sstevel@tonic-gate * to save all of the lines in the history 8529*7c478bd9Sstevel@tonic-gate * list. 8530*7c478bd9Sstevel@tonic-gate * Output: 8531*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 8532*7c478bd9Sstevel@tonic-gate * 1 - Error. 8533*7c478bd9Sstevel@tonic-gate */ 8534*7c478bd9Sstevel@tonic-gate int gl_save_history(GetLine *gl, const char *filename, const char *comment, 8535*7c478bd9Sstevel@tonic-gate int max_lines) 8536*7c478bd9Sstevel@tonic-gate { 8537*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 8538*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_save_history() */ 8539*7c478bd9Sstevel@tonic-gate /* 8540*7c478bd9Sstevel@tonic-gate * Check the arguments. 8541*7c478bd9Sstevel@tonic-gate */ 8542*7c478bd9Sstevel@tonic-gate if(!gl || !filename || !comment) { 8543*7c478bd9Sstevel@tonic-gate if(gl) 8544*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG); 8545*7c478bd9Sstevel@tonic-gate errno = EINVAL; 8546*7c478bd9Sstevel@tonic-gate return 1; 8547*7c478bd9Sstevel@tonic-gate }; 8548*7c478bd9Sstevel@tonic-gate /* 8549*7c478bd9Sstevel@tonic-gate * Block all signals. 8550*7c478bd9Sstevel@tonic-gate */ 8551*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 8552*7c478bd9Sstevel@tonic-gate return 1; 8553*7c478bd9Sstevel@tonic-gate /* 8554*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 8555*7c478bd9Sstevel@tonic-gate */ 8556*7c478bd9Sstevel@tonic-gate status = _gl_save_history(gl, filename, comment, max_lines); 8557*7c478bd9Sstevel@tonic-gate /* 8558*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 8559*7c478bd9Sstevel@tonic-gate */ 8560*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 8561*7c478bd9Sstevel@tonic-gate return status; 8562*7c478bd9Sstevel@tonic-gate } 8563*7c478bd9Sstevel@tonic-gate 8564*7c478bd9Sstevel@tonic-gate /*....................................................................... 8565*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_save_history() function. It 8566*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 8567*7c478bd9Sstevel@tonic-gate * delivery of signals. 8568*7c478bd9Sstevel@tonic-gate */ 8569*7c478bd9Sstevel@tonic-gate static int _gl_save_history(GetLine *gl, const char *filename, 8570*7c478bd9Sstevel@tonic-gate const char *comment, int max_lines) 8571*7c478bd9Sstevel@tonic-gate { 8572*7c478bd9Sstevel@tonic-gate /* 8573*7c478bd9Sstevel@tonic-gate * If filesystem access is to be excluded, then history files can't 8574*7c478bd9Sstevel@tonic-gate * be written. 8575*7c478bd9Sstevel@tonic-gate */ 8576*7c478bd9Sstevel@tonic-gate #ifdef WITHOUT_FILE_SYSTEM 8577*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Can't save history without filesystem access", 8578*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 8579*7c478bd9Sstevel@tonic-gate errno = EINVAL; 8580*7c478bd9Sstevel@tonic-gate return 1; 8581*7c478bd9Sstevel@tonic-gate #else 8582*7c478bd9Sstevel@tonic-gate FileExpansion *expansion; /* The expansion of the filename */ 8583*7c478bd9Sstevel@tonic-gate /* 8584*7c478bd9Sstevel@tonic-gate * Expand the filename. 8585*7c478bd9Sstevel@tonic-gate */ 8586*7c478bd9Sstevel@tonic-gate expansion = ef_expand_file(gl->ef, filename, -1); 8587*7c478bd9Sstevel@tonic-gate if(!expansion) { 8588*7c478bd9Sstevel@tonic-gate gl_print_info(gl, "Unable to expand ", filename, " (", 8589*7c478bd9Sstevel@tonic-gate ef_last_error(gl->ef), ").", GL_END_INFO); 8590*7c478bd9Sstevel@tonic-gate return 1; 8591*7c478bd9Sstevel@tonic-gate }; 8592*7c478bd9Sstevel@tonic-gate /* 8593*7c478bd9Sstevel@tonic-gate * Attempt to save to the specified file. 8594*7c478bd9Sstevel@tonic-gate */ 8595*7c478bd9Sstevel@tonic-gate if(_glh_save_history(gl->glh, expansion->files[0], comment, max_lines)) { 8596*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 8597*7c478bd9Sstevel@tonic-gate return 1; 8598*7c478bd9Sstevel@tonic-gate }; 8599*7c478bd9Sstevel@tonic-gate return 0; 8600*7c478bd9Sstevel@tonic-gate #endif 8601*7c478bd9Sstevel@tonic-gate } 8602*7c478bd9Sstevel@tonic-gate 8603*7c478bd9Sstevel@tonic-gate /*....................................................................... 8604*7c478bd9Sstevel@tonic-gate * Restore the contents of the history buffer from a given new file. 8605*7c478bd9Sstevel@tonic-gate * 8606*7c478bd9Sstevel@tonic-gate * Input: 8607*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 8608*7c478bd9Sstevel@tonic-gate * filename const char * The name of the new file to write to. 8609*7c478bd9Sstevel@tonic-gate * comment const char * This must be the same string that was 8610*7c478bd9Sstevel@tonic-gate * passed to gl_save_history() when the file 8611*7c478bd9Sstevel@tonic-gate * was written. 8612*7c478bd9Sstevel@tonic-gate * Output: 8613*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 8614*7c478bd9Sstevel@tonic-gate * 1 - Error. 8615*7c478bd9Sstevel@tonic-gate */ 8616*7c478bd9Sstevel@tonic-gate int gl_load_history(GetLine *gl, const char *filename, const char *comment) 8617*7c478bd9Sstevel@tonic-gate { 8618*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 8619*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_load_history() */ 8620*7c478bd9Sstevel@tonic-gate /* 8621*7c478bd9Sstevel@tonic-gate * Check the arguments. 8622*7c478bd9Sstevel@tonic-gate */ 8623*7c478bd9Sstevel@tonic-gate if(!gl || !filename || !comment) { 8624*7c478bd9Sstevel@tonic-gate if(gl) 8625*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG); 8626*7c478bd9Sstevel@tonic-gate errno = EINVAL; 8627*7c478bd9Sstevel@tonic-gate return 1; 8628*7c478bd9Sstevel@tonic-gate }; 8629*7c478bd9Sstevel@tonic-gate /* 8630*7c478bd9Sstevel@tonic-gate * Block all signals. 8631*7c478bd9Sstevel@tonic-gate */ 8632*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 8633*7c478bd9Sstevel@tonic-gate return 1; 8634*7c478bd9Sstevel@tonic-gate /* 8635*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 8636*7c478bd9Sstevel@tonic-gate */ 8637*7c478bd9Sstevel@tonic-gate status = _gl_load_history(gl, filename, comment); 8638*7c478bd9Sstevel@tonic-gate /* 8639*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 8640*7c478bd9Sstevel@tonic-gate */ 8641*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 8642*7c478bd9Sstevel@tonic-gate return status; 8643*7c478bd9Sstevel@tonic-gate } 8644*7c478bd9Sstevel@tonic-gate 8645*7c478bd9Sstevel@tonic-gate /*....................................................................... 8646*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_load_history() function. It 8647*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 8648*7c478bd9Sstevel@tonic-gate * delivery of signals. 8649*7c478bd9Sstevel@tonic-gate */ 8650*7c478bd9Sstevel@tonic-gate static int _gl_load_history(GetLine *gl, const char *filename, 8651*7c478bd9Sstevel@tonic-gate const char *comment) 8652*7c478bd9Sstevel@tonic-gate { 8653*7c478bd9Sstevel@tonic-gate /* 8654*7c478bd9Sstevel@tonic-gate * If filesystem access is to be excluded, then history files can't 8655*7c478bd9Sstevel@tonic-gate * be read. 8656*7c478bd9Sstevel@tonic-gate */ 8657*7c478bd9Sstevel@tonic-gate #ifdef WITHOUT_FILE_SYSTEM 8658*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Can't load history without filesystem access", 8659*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 8660*7c478bd9Sstevel@tonic-gate errno = EINVAL; 8661*7c478bd9Sstevel@tonic-gate return 1; 8662*7c478bd9Sstevel@tonic-gate #else 8663*7c478bd9Sstevel@tonic-gate FileExpansion *expansion; /* The expansion of the filename */ 8664*7c478bd9Sstevel@tonic-gate /* 8665*7c478bd9Sstevel@tonic-gate * Expand the filename. 8666*7c478bd9Sstevel@tonic-gate */ 8667*7c478bd9Sstevel@tonic-gate expansion = ef_expand_file(gl->ef, filename, -1); 8668*7c478bd9Sstevel@tonic-gate if(!expansion) { 8669*7c478bd9Sstevel@tonic-gate gl_print_info(gl, "Unable to expand ", filename, " (", 8670*7c478bd9Sstevel@tonic-gate ef_last_error(gl->ef), ").", GL_END_INFO); 8671*7c478bd9Sstevel@tonic-gate return 1; 8672*7c478bd9Sstevel@tonic-gate }; 8673*7c478bd9Sstevel@tonic-gate /* 8674*7c478bd9Sstevel@tonic-gate * Attempt to load from the specified file. 8675*7c478bd9Sstevel@tonic-gate */ 8676*7c478bd9Sstevel@tonic-gate if(_glh_load_history(gl->glh, expansion->files[0], comment, 8677*7c478bd9Sstevel@tonic-gate gl->cutbuf, gl->linelen+1)) { 8678*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 8679*7c478bd9Sstevel@tonic-gate gl->cutbuf[0] = '\0'; 8680*7c478bd9Sstevel@tonic-gate return 1; 8681*7c478bd9Sstevel@tonic-gate }; 8682*7c478bd9Sstevel@tonic-gate gl->cutbuf[0] = '\0'; 8683*7c478bd9Sstevel@tonic-gate return 0; 8684*7c478bd9Sstevel@tonic-gate #endif 8685*7c478bd9Sstevel@tonic-gate } 8686*7c478bd9Sstevel@tonic-gate 8687*7c478bd9Sstevel@tonic-gate /*....................................................................... 8688*7c478bd9Sstevel@tonic-gate * Where possible, register a function and associated data to be called 8689*7c478bd9Sstevel@tonic-gate * whenever a specified event is seen on a file descriptor. 8690*7c478bd9Sstevel@tonic-gate * 8691*7c478bd9Sstevel@tonic-gate * Input: 8692*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of the command-line input 8693*7c478bd9Sstevel@tonic-gate * module. 8694*7c478bd9Sstevel@tonic-gate * fd int The file descriptor to watch. 8695*7c478bd9Sstevel@tonic-gate * event GlFdEvent The type of activity to watch for. 8696*7c478bd9Sstevel@tonic-gate * callback GlFdEventFn * The function to call when the specified 8697*7c478bd9Sstevel@tonic-gate * event occurs. Setting this to 0 removes 8698*7c478bd9Sstevel@tonic-gate * any existing callback. 8699*7c478bd9Sstevel@tonic-gate * data void * A pointer to arbitrary data to pass to the 8700*7c478bd9Sstevel@tonic-gate * callback function. 8701*7c478bd9Sstevel@tonic-gate * Output: 8702*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 8703*7c478bd9Sstevel@tonic-gate * 1 - Either gl==NULL, or this facility isn't 8704*7c478bd9Sstevel@tonic-gate * available on the the host system 8705*7c478bd9Sstevel@tonic-gate * (ie. select() isn't available). No 8706*7c478bd9Sstevel@tonic-gate * error message is generated in the latter 8707*7c478bd9Sstevel@tonic-gate * case. 8708*7c478bd9Sstevel@tonic-gate */ 8709*7c478bd9Sstevel@tonic-gate int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event, 8710*7c478bd9Sstevel@tonic-gate GlFdEventFn *callback, void *data) 8711*7c478bd9Sstevel@tonic-gate { 8712*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 8713*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_watch_fd() */ 8714*7c478bd9Sstevel@tonic-gate /* 8715*7c478bd9Sstevel@tonic-gate * Check the arguments. 8716*7c478bd9Sstevel@tonic-gate */ 8717*7c478bd9Sstevel@tonic-gate if(!gl) { 8718*7c478bd9Sstevel@tonic-gate errno = EINVAL; 8719*7c478bd9Sstevel@tonic-gate return 1; 8720*7c478bd9Sstevel@tonic-gate }; 8721*7c478bd9Sstevel@tonic-gate if(fd < 0) { 8722*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Error: fd < 0", END_ERR_MSG); 8723*7c478bd9Sstevel@tonic-gate errno = EINVAL; 8724*7c478bd9Sstevel@tonic-gate return 1; 8725*7c478bd9Sstevel@tonic-gate }; 8726*7c478bd9Sstevel@tonic-gate /* 8727*7c478bd9Sstevel@tonic-gate * Block all signals. 8728*7c478bd9Sstevel@tonic-gate */ 8729*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 8730*7c478bd9Sstevel@tonic-gate return 1; 8731*7c478bd9Sstevel@tonic-gate /* 8732*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 8733*7c478bd9Sstevel@tonic-gate */ 8734*7c478bd9Sstevel@tonic-gate status = _gl_watch_fd(gl, fd, event, callback, data); 8735*7c478bd9Sstevel@tonic-gate /* 8736*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 8737*7c478bd9Sstevel@tonic-gate */ 8738*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 8739*7c478bd9Sstevel@tonic-gate return status; 8740*7c478bd9Sstevel@tonic-gate } 8741*7c478bd9Sstevel@tonic-gate 8742*7c478bd9Sstevel@tonic-gate /*....................................................................... 8743*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_watch_fd() function. It 8744*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 8745*7c478bd9Sstevel@tonic-gate * delivery of signals. 8746*7c478bd9Sstevel@tonic-gate */ 8747*7c478bd9Sstevel@tonic-gate static int _gl_watch_fd(GetLine *gl, int fd, GlFdEvent event, 8748*7c478bd9Sstevel@tonic-gate GlFdEventFn *callback, void *data) 8749*7c478bd9Sstevel@tonic-gate #if !defined(HAVE_SELECT) 8750*7c478bd9Sstevel@tonic-gate {return 1;} /* The facility isn't supported on this system */ 8751*7c478bd9Sstevel@tonic-gate #else 8752*7c478bd9Sstevel@tonic-gate { 8753*7c478bd9Sstevel@tonic-gate GlFdNode *prev; /* The node that precedes 'node' in gl->fd_nodes */ 8754*7c478bd9Sstevel@tonic-gate GlFdNode *node; /* The file-descriptor node being checked */ 8755*7c478bd9Sstevel@tonic-gate /* 8756*7c478bd9Sstevel@tonic-gate * Search the list of already registered fd activity nodes for the specified 8757*7c478bd9Sstevel@tonic-gate * file descriptor. 8758*7c478bd9Sstevel@tonic-gate */ 8759*7c478bd9Sstevel@tonic-gate for(prev=NULL,node=gl->fd_nodes; node && node->fd != fd; 8760*7c478bd9Sstevel@tonic-gate prev=node, node=node->next) 8761*7c478bd9Sstevel@tonic-gate ; 8762*7c478bd9Sstevel@tonic-gate /* 8763*7c478bd9Sstevel@tonic-gate * Hasn't a node been allocated for this fd yet? 8764*7c478bd9Sstevel@tonic-gate */ 8765*7c478bd9Sstevel@tonic-gate if(!node) { 8766*7c478bd9Sstevel@tonic-gate /* 8767*7c478bd9Sstevel@tonic-gate * If there is no callback to record, just ignore the call. 8768*7c478bd9Sstevel@tonic-gate */ 8769*7c478bd9Sstevel@tonic-gate if(!callback) 8770*7c478bd9Sstevel@tonic-gate return 0; 8771*7c478bd9Sstevel@tonic-gate /* 8772*7c478bd9Sstevel@tonic-gate * Allocate the new node. 8773*7c478bd9Sstevel@tonic-gate */ 8774*7c478bd9Sstevel@tonic-gate node = (GlFdNode *) _new_FreeListNode(gl->fd_node_mem); 8775*7c478bd9Sstevel@tonic-gate if(!node) { 8776*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 8777*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Insufficient memory", END_ERR_MSG); 8778*7c478bd9Sstevel@tonic-gate return 1; 8779*7c478bd9Sstevel@tonic-gate }; 8780*7c478bd9Sstevel@tonic-gate /* 8781*7c478bd9Sstevel@tonic-gate * Prepend the node to the list. 8782*7c478bd9Sstevel@tonic-gate */ 8783*7c478bd9Sstevel@tonic-gate node->next = gl->fd_nodes; 8784*7c478bd9Sstevel@tonic-gate gl->fd_nodes = node; 8785*7c478bd9Sstevel@tonic-gate /* 8786*7c478bd9Sstevel@tonic-gate * Initialize the node. 8787*7c478bd9Sstevel@tonic-gate */ 8788*7c478bd9Sstevel@tonic-gate node->fd = fd; 8789*7c478bd9Sstevel@tonic-gate node->rd.fn = 0; 8790*7c478bd9Sstevel@tonic-gate node->rd.data = NULL; 8791*7c478bd9Sstevel@tonic-gate node->ur = node->wr = node->rd; 8792*7c478bd9Sstevel@tonic-gate }; 8793*7c478bd9Sstevel@tonic-gate /* 8794*7c478bd9Sstevel@tonic-gate * Record the new callback. 8795*7c478bd9Sstevel@tonic-gate */ 8796*7c478bd9Sstevel@tonic-gate switch(event) { 8797*7c478bd9Sstevel@tonic-gate case GLFD_READ: 8798*7c478bd9Sstevel@tonic-gate node->rd.fn = callback; 8799*7c478bd9Sstevel@tonic-gate node->rd.data = data; 8800*7c478bd9Sstevel@tonic-gate if(callback) 8801*7c478bd9Sstevel@tonic-gate FD_SET(fd, &gl->rfds); 8802*7c478bd9Sstevel@tonic-gate else 8803*7c478bd9Sstevel@tonic-gate FD_CLR(fd, &gl->rfds); 8804*7c478bd9Sstevel@tonic-gate break; 8805*7c478bd9Sstevel@tonic-gate case GLFD_WRITE: 8806*7c478bd9Sstevel@tonic-gate node->wr.fn = callback; 8807*7c478bd9Sstevel@tonic-gate node->wr.data = data; 8808*7c478bd9Sstevel@tonic-gate if(callback) 8809*7c478bd9Sstevel@tonic-gate FD_SET(fd, &gl->wfds); 8810*7c478bd9Sstevel@tonic-gate else 8811*7c478bd9Sstevel@tonic-gate FD_CLR(fd, &gl->wfds); 8812*7c478bd9Sstevel@tonic-gate break; 8813*7c478bd9Sstevel@tonic-gate case GLFD_URGENT: 8814*7c478bd9Sstevel@tonic-gate node->ur.fn = callback; 8815*7c478bd9Sstevel@tonic-gate node->ur.data = data; 8816*7c478bd9Sstevel@tonic-gate if(callback) 8817*7c478bd9Sstevel@tonic-gate FD_SET(fd, &gl->ufds); 8818*7c478bd9Sstevel@tonic-gate else 8819*7c478bd9Sstevel@tonic-gate FD_CLR(fd, &gl->ufds); 8820*7c478bd9Sstevel@tonic-gate break; 8821*7c478bd9Sstevel@tonic-gate }; 8822*7c478bd9Sstevel@tonic-gate /* 8823*7c478bd9Sstevel@tonic-gate * Keep a record of the largest file descriptor being watched. 8824*7c478bd9Sstevel@tonic-gate */ 8825*7c478bd9Sstevel@tonic-gate if(fd > gl->max_fd) 8826*7c478bd9Sstevel@tonic-gate gl->max_fd = fd; 8827*7c478bd9Sstevel@tonic-gate /* 8828*7c478bd9Sstevel@tonic-gate * If we are deleting an existing callback, also delete the parent 8829*7c478bd9Sstevel@tonic-gate * activity node if no callbacks are registered to the fd anymore. 8830*7c478bd9Sstevel@tonic-gate */ 8831*7c478bd9Sstevel@tonic-gate if(!callback) { 8832*7c478bd9Sstevel@tonic-gate if(!node->rd.fn && !node->wr.fn && !node->ur.fn) { 8833*7c478bd9Sstevel@tonic-gate if(prev) 8834*7c478bd9Sstevel@tonic-gate prev->next = node->next; 8835*7c478bd9Sstevel@tonic-gate else 8836*7c478bd9Sstevel@tonic-gate gl->fd_nodes = node->next; 8837*7c478bd9Sstevel@tonic-gate node = (GlFdNode *) _del_FreeListNode(gl->fd_node_mem, node); 8838*7c478bd9Sstevel@tonic-gate }; 8839*7c478bd9Sstevel@tonic-gate }; 8840*7c478bd9Sstevel@tonic-gate return 0; 8841*7c478bd9Sstevel@tonic-gate } 8842*7c478bd9Sstevel@tonic-gate #endif 8843*7c478bd9Sstevel@tonic-gate 8844*7c478bd9Sstevel@tonic-gate /*....................................................................... 8845*7c478bd9Sstevel@tonic-gate * On systems with the select() system call, the gl_inactivity_timeout() 8846*7c478bd9Sstevel@tonic-gate * function provides the option of setting (or cancelling) an 8847*7c478bd9Sstevel@tonic-gate * inactivity timeout. Inactivity, in this case, refers both to 8848*7c478bd9Sstevel@tonic-gate * terminal input received from the user, and to I/O on any file 8849*7c478bd9Sstevel@tonic-gate * descriptors registered by calls to gl_watch_fd(). If at any time, 8850*7c478bd9Sstevel@tonic-gate * no activity is seen for the requested time period, the specified 8851*7c478bd9Sstevel@tonic-gate * timeout callback function is called. On returning, this callback 8852*7c478bd9Sstevel@tonic-gate * returns a code which tells gl_get_line() what to do next. Note that 8853*7c478bd9Sstevel@tonic-gate * each call to gl_inactivity_timeout() replaces any previously installed 8854*7c478bd9Sstevel@tonic-gate * timeout callback, and that specifying a callback of 0, turns off 8855*7c478bd9Sstevel@tonic-gate * inactivity timing. 8856*7c478bd9Sstevel@tonic-gate * 8857*7c478bd9Sstevel@tonic-gate * Beware that although the timeout argument includes a nano-second 8858*7c478bd9Sstevel@tonic-gate * component, few computer clocks presently have resolutions finer 8859*7c478bd9Sstevel@tonic-gate * than a few milliseconds, so asking for less than a few milliseconds 8860*7c478bd9Sstevel@tonic-gate * is equivalent to zero on a lot of systems. 8861*7c478bd9Sstevel@tonic-gate * 8862*7c478bd9Sstevel@tonic-gate * Input: 8863*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of the command-line input 8864*7c478bd9Sstevel@tonic-gate * module. 8865*7c478bd9Sstevel@tonic-gate * callback GlTimeoutFn * The function to call when the inactivity 8866*7c478bd9Sstevel@tonic-gate * timeout is exceeded. To turn off 8867*7c478bd9Sstevel@tonic-gate * inactivity timeouts altogether, send 0. 8868*7c478bd9Sstevel@tonic-gate * data void * A pointer to arbitrary data to pass to the 8869*7c478bd9Sstevel@tonic-gate * callback function. 8870*7c478bd9Sstevel@tonic-gate * sec unsigned long The number of whole seconds in the timeout. 8871*7c478bd9Sstevel@tonic-gate * nsec unsigned long The fractional number of seconds in the 8872*7c478bd9Sstevel@tonic-gate * timeout, expressed in nano-seconds (see 8873*7c478bd9Sstevel@tonic-gate * the caveat above). 8874*7c478bd9Sstevel@tonic-gate * Output: 8875*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 8876*7c478bd9Sstevel@tonic-gate * 1 - Either gl==NULL, or this facility isn't 8877*7c478bd9Sstevel@tonic-gate * available on the the host system 8878*7c478bd9Sstevel@tonic-gate * (ie. select() isn't available). No 8879*7c478bd9Sstevel@tonic-gate * error message is generated in the latter 8880*7c478bd9Sstevel@tonic-gate * case. 8881*7c478bd9Sstevel@tonic-gate */ 8882*7c478bd9Sstevel@tonic-gate int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *timeout_fn, void *data, 8883*7c478bd9Sstevel@tonic-gate unsigned long sec, unsigned long nsec) 8884*7c478bd9Sstevel@tonic-gate #if !defined(HAVE_SELECT) 8885*7c478bd9Sstevel@tonic-gate {return 1;} /* The facility isn't supported on this system */ 8886*7c478bd9Sstevel@tonic-gate #else 8887*7c478bd9Sstevel@tonic-gate { 8888*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 8889*7c478bd9Sstevel@tonic-gate /* 8890*7c478bd9Sstevel@tonic-gate * Check the arguments. 8891*7c478bd9Sstevel@tonic-gate */ 8892*7c478bd9Sstevel@tonic-gate if(!gl) { 8893*7c478bd9Sstevel@tonic-gate errno = EINVAL; 8894*7c478bd9Sstevel@tonic-gate return 1; 8895*7c478bd9Sstevel@tonic-gate }; 8896*7c478bd9Sstevel@tonic-gate /* 8897*7c478bd9Sstevel@tonic-gate * Block all signals. 8898*7c478bd9Sstevel@tonic-gate */ 8899*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 8900*7c478bd9Sstevel@tonic-gate return 1; 8901*7c478bd9Sstevel@tonic-gate /* 8902*7c478bd9Sstevel@tonic-gate * Install a new timeout? 8903*7c478bd9Sstevel@tonic-gate */ 8904*7c478bd9Sstevel@tonic-gate if(timeout_fn) { 8905*7c478bd9Sstevel@tonic-gate gl->timer.dt.tv_sec = sec; 8906*7c478bd9Sstevel@tonic-gate gl->timer.dt.tv_usec = nsec / 1000; 8907*7c478bd9Sstevel@tonic-gate gl->timer.fn = timeout_fn; 8908*7c478bd9Sstevel@tonic-gate gl->timer.data = data; 8909*7c478bd9Sstevel@tonic-gate } else { 8910*7c478bd9Sstevel@tonic-gate gl->timer.fn = 0; 8911*7c478bd9Sstevel@tonic-gate gl->timer.data = NULL; 8912*7c478bd9Sstevel@tonic-gate }; 8913*7c478bd9Sstevel@tonic-gate /* 8914*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 8915*7c478bd9Sstevel@tonic-gate */ 8916*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 8917*7c478bd9Sstevel@tonic-gate return 0; 8918*7c478bd9Sstevel@tonic-gate } 8919*7c478bd9Sstevel@tonic-gate #endif 8920*7c478bd9Sstevel@tonic-gate 8921*7c478bd9Sstevel@tonic-gate /*....................................................................... 8922*7c478bd9Sstevel@tonic-gate * When select() is available, this is a private function of 8923*7c478bd9Sstevel@tonic-gate * gl_read_input() which responds to file-descriptor events registered by 8924*7c478bd9Sstevel@tonic-gate * the caller. Note that it assumes that it is being called from within 8925*7c478bd9Sstevel@tonic-gate * gl_read_input()'s sigsetjump() clause. 8926*7c478bd9Sstevel@tonic-gate * 8927*7c478bd9Sstevel@tonic-gate * Input: 8928*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this module. 8929*7c478bd9Sstevel@tonic-gate * fd int The file descriptor to be watched for user input. 8930*7c478bd9Sstevel@tonic-gate * Output: 8931*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 8932*7c478bd9Sstevel@tonic-gate * 1 - An error occurred. 8933*7c478bd9Sstevel@tonic-gate */ 8934*7c478bd9Sstevel@tonic-gate static int gl_event_handler(GetLine *gl, int fd) 8935*7c478bd9Sstevel@tonic-gate { 8936*7c478bd9Sstevel@tonic-gate #if !defined(HAVE_SELECT) 8937*7c478bd9Sstevel@tonic-gate return 0; 8938*7c478bd9Sstevel@tonic-gate #else 8939*7c478bd9Sstevel@tonic-gate /* 8940*7c478bd9Sstevel@tonic-gate * Set up a zero-second timeout. 8941*7c478bd9Sstevel@tonic-gate */ 8942*7c478bd9Sstevel@tonic-gate struct timeval zero; 8943*7c478bd9Sstevel@tonic-gate zero.tv_sec = zero.tv_usec = 0; 8944*7c478bd9Sstevel@tonic-gate /* 8945*7c478bd9Sstevel@tonic-gate * If at any time no external callbacks remain, quit the loop return, 8946*7c478bd9Sstevel@tonic-gate * so that we can simply wait in read(). This is designed as an 8947*7c478bd9Sstevel@tonic-gate * optimization for when no callbacks have been registered on entry to 8948*7c478bd9Sstevel@tonic-gate * this function, but since callbacks can delete themselves, it can 8949*7c478bd9Sstevel@tonic-gate * also help later. 8950*7c478bd9Sstevel@tonic-gate */ 8951*7c478bd9Sstevel@tonic-gate while(gl->fd_nodes || gl->timer.fn) { 8952*7c478bd9Sstevel@tonic-gate int nready; /* The number of file descriptors that are ready for I/O */ 8953*7c478bd9Sstevel@tonic-gate /* 8954*7c478bd9Sstevel@tonic-gate * Get the set of descriptors to be watched. 8955*7c478bd9Sstevel@tonic-gate */ 8956*7c478bd9Sstevel@tonic-gate fd_set rfds = gl->rfds; 8957*7c478bd9Sstevel@tonic-gate fd_set wfds = gl->wfds; 8958*7c478bd9Sstevel@tonic-gate fd_set ufds = gl->ufds; 8959*7c478bd9Sstevel@tonic-gate /* 8960*7c478bd9Sstevel@tonic-gate * Get the appropriate timeout. 8961*7c478bd9Sstevel@tonic-gate */ 8962*7c478bd9Sstevel@tonic-gate struct timeval dt = gl->timer.fn ? gl->timer.dt : zero; 8963*7c478bd9Sstevel@tonic-gate /* 8964*7c478bd9Sstevel@tonic-gate * Add the specified user-input file descriptor tot he set that is to 8965*7c478bd9Sstevel@tonic-gate * be watched. 8966*7c478bd9Sstevel@tonic-gate */ 8967*7c478bd9Sstevel@tonic-gate FD_SET(fd, &rfds); 8968*7c478bd9Sstevel@tonic-gate /* 8969*7c478bd9Sstevel@tonic-gate * Unblock the signals that we are watching, while select is blocked 8970*7c478bd9Sstevel@tonic-gate * waiting for I/O. 8971*7c478bd9Sstevel@tonic-gate */ 8972*7c478bd9Sstevel@tonic-gate gl_catch_signals(gl); 8973*7c478bd9Sstevel@tonic-gate /* 8974*7c478bd9Sstevel@tonic-gate * Wait for activity on any of the file descriptors. 8975*7c478bd9Sstevel@tonic-gate */ 8976*7c478bd9Sstevel@tonic-gate nready = select(gl->max_fd+1, &rfds, &wfds, &ufds, 8977*7c478bd9Sstevel@tonic-gate (gl->timer.fn || gl->io_mode==GL_SERVER_MODE) ? &dt : NULL); 8978*7c478bd9Sstevel@tonic-gate /* 8979*7c478bd9Sstevel@tonic-gate * We don't want to do a longjmp in the middle of a callback that 8980*7c478bd9Sstevel@tonic-gate * might be modifying global or heap data, so block all the signals 8981*7c478bd9Sstevel@tonic-gate * that we are trapping before executing callback functions. Note that 8982*7c478bd9Sstevel@tonic-gate * the caller will unblock them again when it needs to, so there is 8983*7c478bd9Sstevel@tonic-gate * no need to undo this before returning. 8984*7c478bd9Sstevel@tonic-gate */ 8985*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, NULL); 8986*7c478bd9Sstevel@tonic-gate /* 8987*7c478bd9Sstevel@tonic-gate * If select() returns but none of the file descriptors are reported 8988*7c478bd9Sstevel@tonic-gate * to have activity, then select() timed out. 8989*7c478bd9Sstevel@tonic-gate */ 8990*7c478bd9Sstevel@tonic-gate if(nready == 0) { 8991*7c478bd9Sstevel@tonic-gate /* 8992*7c478bd9Sstevel@tonic-gate * Note that in non-blocking server mode, the inactivity timer is used 8993*7c478bd9Sstevel@tonic-gate * to allow I/O to block for a specified amount of time, so in this 8994*7c478bd9Sstevel@tonic-gate * mode we return the postponed blocked status when an abort is 8995*7c478bd9Sstevel@tonic-gate * requested. 8996*7c478bd9Sstevel@tonic-gate */ 8997*7c478bd9Sstevel@tonic-gate if(gl_call_timeout_handler(gl)) { 8998*7c478bd9Sstevel@tonic-gate return 1; 8999*7c478bd9Sstevel@tonic-gate } else if(gl->io_mode == GL_SERVER_MODE) { 9000*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO); 9001*7c478bd9Sstevel@tonic-gate return 1; 9002*7c478bd9Sstevel@tonic-gate }; 9003*7c478bd9Sstevel@tonic-gate /* 9004*7c478bd9Sstevel@tonic-gate * If nready < 0, this means an error occurred. 9005*7c478bd9Sstevel@tonic-gate */ 9006*7c478bd9Sstevel@tonic-gate } else if(nready < 0) { 9007*7c478bd9Sstevel@tonic-gate if(errno != EINTR) { 9008*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_ERROR, errno); 9009*7c478bd9Sstevel@tonic-gate return 1; 9010*7c478bd9Sstevel@tonic-gate }; 9011*7c478bd9Sstevel@tonic-gate /* 9012*7c478bd9Sstevel@tonic-gate * If the user-input file descriptor has data available, return. 9013*7c478bd9Sstevel@tonic-gate */ 9014*7c478bd9Sstevel@tonic-gate } else if(FD_ISSET(fd, &rfds)) { 9015*7c478bd9Sstevel@tonic-gate return 0; 9016*7c478bd9Sstevel@tonic-gate /* 9017*7c478bd9Sstevel@tonic-gate * Check for activity on any of the file descriptors registered by the 9018*7c478bd9Sstevel@tonic-gate * calling application, and call the associated callback functions. 9019*7c478bd9Sstevel@tonic-gate */ 9020*7c478bd9Sstevel@tonic-gate } else { 9021*7c478bd9Sstevel@tonic-gate GlFdNode *node; /* The fd event node being checked */ 9022*7c478bd9Sstevel@tonic-gate /* 9023*7c478bd9Sstevel@tonic-gate * Search the list for the file descriptor that caused select() to return. 9024*7c478bd9Sstevel@tonic-gate */ 9025*7c478bd9Sstevel@tonic-gate for(node=gl->fd_nodes; node; node=node->next) { 9026*7c478bd9Sstevel@tonic-gate /* 9027*7c478bd9Sstevel@tonic-gate * Is there urgent out of band data waiting to be read on fd? 9028*7c478bd9Sstevel@tonic-gate */ 9029*7c478bd9Sstevel@tonic-gate if(node->ur.fn && FD_ISSET(node->fd, &ufds)) { 9030*7c478bd9Sstevel@tonic-gate if(gl_call_fd_handler(gl, &node->ur, node->fd, GLFD_URGENT)) 9031*7c478bd9Sstevel@tonic-gate return 1; 9032*7c478bd9Sstevel@tonic-gate break; /* The callback may have changed the list of nodes */ 9033*7c478bd9Sstevel@tonic-gate /* 9034*7c478bd9Sstevel@tonic-gate * Is the fd readable? 9035*7c478bd9Sstevel@tonic-gate */ 9036*7c478bd9Sstevel@tonic-gate } else if(node->rd.fn && FD_ISSET(node->fd, &rfds)) { 9037*7c478bd9Sstevel@tonic-gate if(gl_call_fd_handler(gl, &node->rd, node->fd, GLFD_READ)) 9038*7c478bd9Sstevel@tonic-gate return 1; 9039*7c478bd9Sstevel@tonic-gate break; /* The callback may have changed the list of nodes */ 9040*7c478bd9Sstevel@tonic-gate /* 9041*7c478bd9Sstevel@tonic-gate * Is the fd writable? 9042*7c478bd9Sstevel@tonic-gate */ 9043*7c478bd9Sstevel@tonic-gate } else if(node->wr.fn && FD_ISSET(node->fd, &wfds)) { 9044*7c478bd9Sstevel@tonic-gate if(gl_call_fd_handler(gl, &node->wr, node->fd, GLFD_WRITE)) 9045*7c478bd9Sstevel@tonic-gate return 1; 9046*7c478bd9Sstevel@tonic-gate break; /* The callback may have changed the list of nodes */ 9047*7c478bd9Sstevel@tonic-gate }; 9048*7c478bd9Sstevel@tonic-gate }; 9049*7c478bd9Sstevel@tonic-gate }; 9050*7c478bd9Sstevel@tonic-gate /* 9051*7c478bd9Sstevel@tonic-gate * Just in case the above event handlers asked for the input line to 9052*7c478bd9Sstevel@tonic-gate * be redrawn, flush any pending output. 9053*7c478bd9Sstevel@tonic-gate */ 9054*7c478bd9Sstevel@tonic-gate if(gl_flush_output(gl)) 9055*7c478bd9Sstevel@tonic-gate return 1; 9056*7c478bd9Sstevel@tonic-gate }; 9057*7c478bd9Sstevel@tonic-gate return 0; 9058*7c478bd9Sstevel@tonic-gate } 9059*7c478bd9Sstevel@tonic-gate #endif 9060*7c478bd9Sstevel@tonic-gate 9061*7c478bd9Sstevel@tonic-gate #if defined(HAVE_SELECT) 9062*7c478bd9Sstevel@tonic-gate /*....................................................................... 9063*7c478bd9Sstevel@tonic-gate * This is a private function of gl_event_handler(), used to call a 9064*7c478bd9Sstevel@tonic-gate * file-descriptor callback. 9065*7c478bd9Sstevel@tonic-gate * 9066*7c478bd9Sstevel@tonic-gate * Input: 9067*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9068*7c478bd9Sstevel@tonic-gate * gfh GlFdHandler * The I/O handler. 9069*7c478bd9Sstevel@tonic-gate * fd int The file-descriptor being reported. 9070*7c478bd9Sstevel@tonic-gate * event GlFdEvent The I/O event being reported. 9071*7c478bd9Sstevel@tonic-gate * Output: 9072*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 9073*7c478bd9Sstevel@tonic-gate * 1 - Error. 9074*7c478bd9Sstevel@tonic-gate */ 9075*7c478bd9Sstevel@tonic-gate static int gl_call_fd_handler(GetLine *gl, GlFdHandler *gfh, int fd, 9076*7c478bd9Sstevel@tonic-gate GlFdEvent event) 9077*7c478bd9Sstevel@tonic-gate { 9078*7c478bd9Sstevel@tonic-gate Termios attr; /* The terminal attributes */ 9079*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True after any error */ 9080*7c478bd9Sstevel@tonic-gate /* 9081*7c478bd9Sstevel@tonic-gate * Re-enable conversion of newline characters to carriage-return/linefeed, 9082*7c478bd9Sstevel@tonic-gate * so that the callback can write to the terminal without having to do 9083*7c478bd9Sstevel@tonic-gate * anything special. 9084*7c478bd9Sstevel@tonic-gate */ 9085*7c478bd9Sstevel@tonic-gate if(tcgetattr(gl->input_fd, &attr)) { 9086*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG); 9087*7c478bd9Sstevel@tonic-gate return 1; 9088*7c478bd9Sstevel@tonic-gate }; 9089*7c478bd9Sstevel@tonic-gate attr.c_oflag |= OPOST; 9090*7c478bd9Sstevel@tonic-gate while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) { 9091*7c478bd9Sstevel@tonic-gate if(errno != EINTR) { 9092*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG); 9093*7c478bd9Sstevel@tonic-gate return 1; 9094*7c478bd9Sstevel@tonic-gate }; 9095*7c478bd9Sstevel@tonic-gate }; 9096*7c478bd9Sstevel@tonic-gate /* 9097*7c478bd9Sstevel@tonic-gate * Invoke the application's callback function. 9098*7c478bd9Sstevel@tonic-gate */ 9099*7c478bd9Sstevel@tonic-gate switch(gfh->fn(gl, gfh->data, fd, event)) { 9100*7c478bd9Sstevel@tonic-gate default: 9101*7c478bd9Sstevel@tonic-gate case GLFD_ABORT: 9102*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_FDABORT, 0); 9103*7c478bd9Sstevel@tonic-gate waserr = 1; 9104*7c478bd9Sstevel@tonic-gate break; 9105*7c478bd9Sstevel@tonic-gate case GLFD_REFRESH: 9106*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 9107*7c478bd9Sstevel@tonic-gate break; 9108*7c478bd9Sstevel@tonic-gate case GLFD_CONTINUE: 9109*7c478bd9Sstevel@tonic-gate break; 9110*7c478bd9Sstevel@tonic-gate }; 9111*7c478bd9Sstevel@tonic-gate /* 9112*7c478bd9Sstevel@tonic-gate * Disable conversion of newline characters to carriage-return/linefeed. 9113*7c478bd9Sstevel@tonic-gate */ 9114*7c478bd9Sstevel@tonic-gate attr.c_oflag &= ~(OPOST); 9115*7c478bd9Sstevel@tonic-gate while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) { 9116*7c478bd9Sstevel@tonic-gate if(errno != EINTR) { 9117*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG); 9118*7c478bd9Sstevel@tonic-gate return 1; 9119*7c478bd9Sstevel@tonic-gate }; 9120*7c478bd9Sstevel@tonic-gate }; 9121*7c478bd9Sstevel@tonic-gate return waserr; 9122*7c478bd9Sstevel@tonic-gate } 9123*7c478bd9Sstevel@tonic-gate 9124*7c478bd9Sstevel@tonic-gate /*....................................................................... 9125*7c478bd9Sstevel@tonic-gate * This is a private function of gl_event_handler(), used to call a 9126*7c478bd9Sstevel@tonic-gate * inactivity timer callbacks. 9127*7c478bd9Sstevel@tonic-gate * 9128*7c478bd9Sstevel@tonic-gate * Input: 9129*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9130*7c478bd9Sstevel@tonic-gate * Output: 9131*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 9132*7c478bd9Sstevel@tonic-gate * 1 - Error. 9133*7c478bd9Sstevel@tonic-gate */ 9134*7c478bd9Sstevel@tonic-gate static int gl_call_timeout_handler(GetLine *gl) 9135*7c478bd9Sstevel@tonic-gate { 9136*7c478bd9Sstevel@tonic-gate Termios attr; /* The terminal attributes */ 9137*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True after any error */ 9138*7c478bd9Sstevel@tonic-gate /* 9139*7c478bd9Sstevel@tonic-gate * Make sure that there is an inactivity timeout callback. 9140*7c478bd9Sstevel@tonic-gate */ 9141*7c478bd9Sstevel@tonic-gate if(!gl->timer.fn) 9142*7c478bd9Sstevel@tonic-gate return 0; 9143*7c478bd9Sstevel@tonic-gate /* 9144*7c478bd9Sstevel@tonic-gate * Re-enable conversion of newline characters to carriage-return/linefeed, 9145*7c478bd9Sstevel@tonic-gate * so that the callback can write to the terminal without having to do 9146*7c478bd9Sstevel@tonic-gate * anything special. 9147*7c478bd9Sstevel@tonic-gate */ 9148*7c478bd9Sstevel@tonic-gate if(tcgetattr(gl->input_fd, &attr)) { 9149*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcgetattr error", END_ERR_MSG); 9150*7c478bd9Sstevel@tonic-gate return 1; 9151*7c478bd9Sstevel@tonic-gate }; 9152*7c478bd9Sstevel@tonic-gate attr.c_oflag |= OPOST; 9153*7c478bd9Sstevel@tonic-gate while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) { 9154*7c478bd9Sstevel@tonic-gate if(errno != EINTR) { 9155*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG); 9156*7c478bd9Sstevel@tonic-gate return 1; 9157*7c478bd9Sstevel@tonic-gate }; 9158*7c478bd9Sstevel@tonic-gate }; 9159*7c478bd9Sstevel@tonic-gate /* 9160*7c478bd9Sstevel@tonic-gate * Invoke the application's callback function. 9161*7c478bd9Sstevel@tonic-gate */ 9162*7c478bd9Sstevel@tonic-gate switch(gl->timer.fn(gl, gl->timer.data)) { 9163*7c478bd9Sstevel@tonic-gate default: 9164*7c478bd9Sstevel@tonic-gate case GLTO_ABORT: 9165*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_TIMEOUT, 0); 9166*7c478bd9Sstevel@tonic-gate waserr = 1; 9167*7c478bd9Sstevel@tonic-gate break; 9168*7c478bd9Sstevel@tonic-gate case GLTO_REFRESH: 9169*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 9170*7c478bd9Sstevel@tonic-gate break; 9171*7c478bd9Sstevel@tonic-gate case GLTO_CONTINUE: 9172*7c478bd9Sstevel@tonic-gate break; 9173*7c478bd9Sstevel@tonic-gate }; 9174*7c478bd9Sstevel@tonic-gate /* 9175*7c478bd9Sstevel@tonic-gate * Disable conversion of newline characters to carriage-return/linefeed. 9176*7c478bd9Sstevel@tonic-gate */ 9177*7c478bd9Sstevel@tonic-gate attr.c_oflag &= ~(OPOST); 9178*7c478bd9Sstevel@tonic-gate while(tcsetattr(gl->input_fd, TCSADRAIN, &attr)) { 9179*7c478bd9Sstevel@tonic-gate if(errno != EINTR) { 9180*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "tcsetattr error", END_ERR_MSG); 9181*7c478bd9Sstevel@tonic-gate return 1; 9182*7c478bd9Sstevel@tonic-gate }; 9183*7c478bd9Sstevel@tonic-gate }; 9184*7c478bd9Sstevel@tonic-gate return waserr; 9185*7c478bd9Sstevel@tonic-gate } 9186*7c478bd9Sstevel@tonic-gate #endif /* HAVE_SELECT */ 9187*7c478bd9Sstevel@tonic-gate 9188*7c478bd9Sstevel@tonic-gate /*....................................................................... 9189*7c478bd9Sstevel@tonic-gate * Switch history groups. History groups represent separate history 9190*7c478bd9Sstevel@tonic-gate * lists recorded within a single history buffer. Different groups 9191*7c478bd9Sstevel@tonic-gate * are distinguished by integer identifiers chosen by the calling 9192*7c478bd9Sstevel@tonic-gate * appplicaton. Initially new_GetLine() sets the group identifier to 9193*7c478bd9Sstevel@tonic-gate * 0. Whenever a new line is appended to the history list, the current 9194*7c478bd9Sstevel@tonic-gate * group identifier is recorded with it, and history lookups only 9195*7c478bd9Sstevel@tonic-gate * consider lines marked with the current group identifier. 9196*7c478bd9Sstevel@tonic-gate * 9197*7c478bd9Sstevel@tonic-gate * Input: 9198*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9199*7c478bd9Sstevel@tonic-gate * id unsigned The new history group identifier. 9200*7c478bd9Sstevel@tonic-gate * Output: 9201*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 9202*7c478bd9Sstevel@tonic-gate * 1 - Error. 9203*7c478bd9Sstevel@tonic-gate */ 9204*7c478bd9Sstevel@tonic-gate int gl_group_history(GetLine *gl, unsigned id) 9205*7c478bd9Sstevel@tonic-gate { 9206*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 9207*7c478bd9Sstevel@tonic-gate int status; /* The return status of this function */ 9208*7c478bd9Sstevel@tonic-gate /* 9209*7c478bd9Sstevel@tonic-gate * Check the arguments. 9210*7c478bd9Sstevel@tonic-gate */ 9211*7c478bd9Sstevel@tonic-gate if(!gl) { 9212*7c478bd9Sstevel@tonic-gate errno = EINVAL; 9213*7c478bd9Sstevel@tonic-gate return 1; 9214*7c478bd9Sstevel@tonic-gate }; 9215*7c478bd9Sstevel@tonic-gate /* 9216*7c478bd9Sstevel@tonic-gate * Block all signals while we install the new configuration. 9217*7c478bd9Sstevel@tonic-gate */ 9218*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 9219*7c478bd9Sstevel@tonic-gate return 1; 9220*7c478bd9Sstevel@tonic-gate /* 9221*7c478bd9Sstevel@tonic-gate * If the group isn't being changed, do nothing. 9222*7c478bd9Sstevel@tonic-gate */ 9223*7c478bd9Sstevel@tonic-gate if(_glh_get_group(gl->glh) == id) { 9224*7c478bd9Sstevel@tonic-gate status = 0; 9225*7c478bd9Sstevel@tonic-gate /* 9226*7c478bd9Sstevel@tonic-gate * Establish the new group. 9227*7c478bd9Sstevel@tonic-gate */ 9228*7c478bd9Sstevel@tonic-gate } else if(_glh_set_group(gl->glh, id)) { 9229*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 9230*7c478bd9Sstevel@tonic-gate status = 1; 9231*7c478bd9Sstevel@tonic-gate /* 9232*7c478bd9Sstevel@tonic-gate * Prevent history information from the previous group being 9233*7c478bd9Sstevel@tonic-gate * inappropriately used by the next call to gl_get_line(). 9234*7c478bd9Sstevel@tonic-gate */ 9235*7c478bd9Sstevel@tonic-gate } else { 9236*7c478bd9Sstevel@tonic-gate gl->preload_history = 0; 9237*7c478bd9Sstevel@tonic-gate gl->last_search = -1; 9238*7c478bd9Sstevel@tonic-gate status = 0; 9239*7c478bd9Sstevel@tonic-gate }; 9240*7c478bd9Sstevel@tonic-gate /* 9241*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 9242*7c478bd9Sstevel@tonic-gate */ 9243*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9244*7c478bd9Sstevel@tonic-gate return status; 9245*7c478bd9Sstevel@tonic-gate } 9246*7c478bd9Sstevel@tonic-gate 9247*7c478bd9Sstevel@tonic-gate /*....................................................................... 9248*7c478bd9Sstevel@tonic-gate * Display the contents of the history list. 9249*7c478bd9Sstevel@tonic-gate * 9250*7c478bd9Sstevel@tonic-gate * Input: 9251*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9252*7c478bd9Sstevel@tonic-gate * fp FILE * The stdio output stream to write to. 9253*7c478bd9Sstevel@tonic-gate * fmt const char * A format string. This containing characters to be 9254*7c478bd9Sstevel@tonic-gate * written verbatim, plus any of the following 9255*7c478bd9Sstevel@tonic-gate * format directives: 9256*7c478bd9Sstevel@tonic-gate * %D - The date, formatted like 2001-11-20 9257*7c478bd9Sstevel@tonic-gate * %T - The time of day, formatted like 23:59:59 9258*7c478bd9Sstevel@tonic-gate * %N - The sequential entry number of the 9259*7c478bd9Sstevel@tonic-gate * line in the history buffer. 9260*7c478bd9Sstevel@tonic-gate * %G - The number of the history group that 9261*7c478bd9Sstevel@tonic-gate * the line belongs to. 9262*7c478bd9Sstevel@tonic-gate * %% - A literal % character. 9263*7c478bd9Sstevel@tonic-gate * %H - The history line itself. 9264*7c478bd9Sstevel@tonic-gate * Note that a '\n' newline character is not 9265*7c478bd9Sstevel@tonic-gate * appended by default. 9266*7c478bd9Sstevel@tonic-gate * all_groups int If true, display history lines from all 9267*7c478bd9Sstevel@tonic-gate * history groups. Otherwise only display 9268*7c478bd9Sstevel@tonic-gate * those of the current history group. 9269*7c478bd9Sstevel@tonic-gate * max_lines int If max_lines is < 0, all available lines 9270*7c478bd9Sstevel@tonic-gate * are displayed. Otherwise only the most 9271*7c478bd9Sstevel@tonic-gate * recent max_lines lines will be displayed. 9272*7c478bd9Sstevel@tonic-gate * Output: 9273*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 9274*7c478bd9Sstevel@tonic-gate * 1 - Error. 9275*7c478bd9Sstevel@tonic-gate */ 9276*7c478bd9Sstevel@tonic-gate int gl_show_history(GetLine *gl, FILE *fp, const char *fmt, int all_groups, 9277*7c478bd9Sstevel@tonic-gate int max_lines) 9278*7c478bd9Sstevel@tonic-gate { 9279*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 9280*7c478bd9Sstevel@tonic-gate int status; /* The return status of this function */ 9281*7c478bd9Sstevel@tonic-gate /* 9282*7c478bd9Sstevel@tonic-gate * Check the arguments. 9283*7c478bd9Sstevel@tonic-gate */ 9284*7c478bd9Sstevel@tonic-gate if(!gl || !fp || !fmt) { 9285*7c478bd9Sstevel@tonic-gate if(gl) 9286*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG); 9287*7c478bd9Sstevel@tonic-gate errno = EINVAL; 9288*7c478bd9Sstevel@tonic-gate return 1; 9289*7c478bd9Sstevel@tonic-gate }; 9290*7c478bd9Sstevel@tonic-gate /* 9291*7c478bd9Sstevel@tonic-gate * Block all signals. 9292*7c478bd9Sstevel@tonic-gate */ 9293*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 9294*7c478bd9Sstevel@tonic-gate return 1; 9295*7c478bd9Sstevel@tonic-gate /* 9296*7c478bd9Sstevel@tonic-gate * Display the specified history group(s) while signals are blocked. 9297*7c478bd9Sstevel@tonic-gate */ 9298*7c478bd9Sstevel@tonic-gate status = _glh_show_history(gl->glh, _io_write_stdio, fp, fmt, all_groups, 9299*7c478bd9Sstevel@tonic-gate max_lines) || fflush(fp)==EOF; 9300*7c478bd9Sstevel@tonic-gate if(!status) 9301*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 9302*7c478bd9Sstevel@tonic-gate /* 9303*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 9304*7c478bd9Sstevel@tonic-gate */ 9305*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9306*7c478bd9Sstevel@tonic-gate return status; 9307*7c478bd9Sstevel@tonic-gate } 9308*7c478bd9Sstevel@tonic-gate 9309*7c478bd9Sstevel@tonic-gate /*....................................................................... 9310*7c478bd9Sstevel@tonic-gate * Update if necessary, and return the current size of the terminal. 9311*7c478bd9Sstevel@tonic-gate * 9312*7c478bd9Sstevel@tonic-gate * Input: 9313*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9314*7c478bd9Sstevel@tonic-gate * def_ncolumn int If the number of columns in the terminal 9315*7c478bd9Sstevel@tonic-gate * can't be determined, substitute this number. 9316*7c478bd9Sstevel@tonic-gate * def_nline int If the number of lines in the terminal can't 9317*7c478bd9Sstevel@tonic-gate * be determined, substitute this number. 9318*7c478bd9Sstevel@tonic-gate * Output: 9319*7c478bd9Sstevel@tonic-gate * return GlTerminalSize The current terminal size. 9320*7c478bd9Sstevel@tonic-gate */ 9321*7c478bd9Sstevel@tonic-gate GlTerminalSize gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline) 9322*7c478bd9Sstevel@tonic-gate { 9323*7c478bd9Sstevel@tonic-gate GlTerminalSize size; /* The object to be returned */ 9324*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry */ 9325*7c478bd9Sstevel@tonic-gate /* to this function */ 9326*7c478bd9Sstevel@tonic-gate /* 9327*7c478bd9Sstevel@tonic-gate * Block all signals while accessing gl. 9328*7c478bd9Sstevel@tonic-gate */ 9329*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9330*7c478bd9Sstevel@tonic-gate /* 9331*7c478bd9Sstevel@tonic-gate * Lookup/configure the terminal size. 9332*7c478bd9Sstevel@tonic-gate */ 9333*7c478bd9Sstevel@tonic-gate _gl_terminal_size(gl, def_ncolumn, def_nline, &size); 9334*7c478bd9Sstevel@tonic-gate /* 9335*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9336*7c478bd9Sstevel@tonic-gate */ 9337*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9338*7c478bd9Sstevel@tonic-gate return size; 9339*7c478bd9Sstevel@tonic-gate } 9340*7c478bd9Sstevel@tonic-gate 9341*7c478bd9Sstevel@tonic-gate /*....................................................................... 9342*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_terminal_size() function. It 9343*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 9344*7c478bd9Sstevel@tonic-gate * delivery of signals. 9345*7c478bd9Sstevel@tonic-gate */ 9346*7c478bd9Sstevel@tonic-gate static void _gl_terminal_size(GetLine *gl, int def_ncolumn, int def_nline, 9347*7c478bd9Sstevel@tonic-gate GlTerminalSize *size) 9348*7c478bd9Sstevel@tonic-gate { 9349*7c478bd9Sstevel@tonic-gate const char *env; /* The value of an environment variable */ 9350*7c478bd9Sstevel@tonic-gate int n; /* A number read from env[] */ 9351*7c478bd9Sstevel@tonic-gate /* 9352*7c478bd9Sstevel@tonic-gate * Set the number of lines and columns to non-sensical values so that 9353*7c478bd9Sstevel@tonic-gate * we know later if they have been set. 9354*7c478bd9Sstevel@tonic-gate */ 9355*7c478bd9Sstevel@tonic-gate gl->nline = 0; 9356*7c478bd9Sstevel@tonic-gate gl->ncolumn = 0; 9357*7c478bd9Sstevel@tonic-gate /* 9358*7c478bd9Sstevel@tonic-gate * Are we reading from a terminal? 9359*7c478bd9Sstevel@tonic-gate */ 9360*7c478bd9Sstevel@tonic-gate if(gl->is_term) { 9361*7c478bd9Sstevel@tonic-gate /* 9362*7c478bd9Sstevel@tonic-gate * Ask the terminal directly if possible. 9363*7c478bd9Sstevel@tonic-gate */ 9364*7c478bd9Sstevel@tonic-gate (void) _gl_update_size(gl); 9365*7c478bd9Sstevel@tonic-gate /* 9366*7c478bd9Sstevel@tonic-gate * If gl_update_size() couldn't ask the terminal, it will have 9367*7c478bd9Sstevel@tonic-gate * left gl->nrow and gl->ncolumn unchanged. If these values haven't 9368*7c478bd9Sstevel@tonic-gate * been changed from their initial values of zero, we need to find 9369*7c478bd9Sstevel@tonic-gate * a different method to get the terminal size. 9370*7c478bd9Sstevel@tonic-gate * 9371*7c478bd9Sstevel@tonic-gate * If the number of lines isn't known yet, first see if the 9372*7c478bd9Sstevel@tonic-gate * LINES environment ariable exists and specifies a believable number. 9373*7c478bd9Sstevel@tonic-gate * If this doesn't work, look up the default size in the terminal 9374*7c478bd9Sstevel@tonic-gate * information database. 9375*7c478bd9Sstevel@tonic-gate */ 9376*7c478bd9Sstevel@tonic-gate if(gl->nline < 1) { 9377*7c478bd9Sstevel@tonic-gate if((env = getenv("LINES")) && (n=atoi(env)) > 0) 9378*7c478bd9Sstevel@tonic-gate gl->nline = n; 9379*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 9380*7c478bd9Sstevel@tonic-gate else 9381*7c478bd9Sstevel@tonic-gate gl->nline = tigetnum((char *)"lines"); 9382*7c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP) 9383*7c478bd9Sstevel@tonic-gate else 9384*7c478bd9Sstevel@tonic-gate gl->nline = tgetnum("li"); 9385*7c478bd9Sstevel@tonic-gate #endif 9386*7c478bd9Sstevel@tonic-gate }; 9387*7c478bd9Sstevel@tonic-gate /* 9388*7c478bd9Sstevel@tonic-gate * If the number of lines isn't known yet, first see if the COLUMNS 9389*7c478bd9Sstevel@tonic-gate * environment ariable exists and specifies a believable number. If 9390*7c478bd9Sstevel@tonic-gate * this doesn't work, look up the default size in the terminal 9391*7c478bd9Sstevel@tonic-gate * information database. 9392*7c478bd9Sstevel@tonic-gate */ 9393*7c478bd9Sstevel@tonic-gate if(gl->ncolumn < 1) { 9394*7c478bd9Sstevel@tonic-gate if((env = getenv("COLUMNS")) && (n=atoi(env)) > 0) 9395*7c478bd9Sstevel@tonic-gate gl->ncolumn = n; 9396*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMINFO 9397*7c478bd9Sstevel@tonic-gate else 9398*7c478bd9Sstevel@tonic-gate gl->ncolumn = tigetnum((char *)"cols"); 9399*7c478bd9Sstevel@tonic-gate #elif defined(USE_TERMCAP) 9400*7c478bd9Sstevel@tonic-gate else 9401*7c478bd9Sstevel@tonic-gate gl->ncolumn = tgetnum("co"); 9402*7c478bd9Sstevel@tonic-gate #endif 9403*7c478bd9Sstevel@tonic-gate }; 9404*7c478bd9Sstevel@tonic-gate }; 9405*7c478bd9Sstevel@tonic-gate /* 9406*7c478bd9Sstevel@tonic-gate * If we still haven't been able to acquire reasonable values, substitute 9407*7c478bd9Sstevel@tonic-gate * the default values specified by the caller. 9408*7c478bd9Sstevel@tonic-gate */ 9409*7c478bd9Sstevel@tonic-gate if(gl->nline <= 0) 9410*7c478bd9Sstevel@tonic-gate gl->nline = def_nline; 9411*7c478bd9Sstevel@tonic-gate if(gl->ncolumn <= 0) 9412*7c478bd9Sstevel@tonic-gate gl->ncolumn = def_ncolumn; 9413*7c478bd9Sstevel@tonic-gate /* 9414*7c478bd9Sstevel@tonic-gate * Copy the new size into the return value. 9415*7c478bd9Sstevel@tonic-gate */ 9416*7c478bd9Sstevel@tonic-gate if(size) { 9417*7c478bd9Sstevel@tonic-gate size->nline = gl->nline; 9418*7c478bd9Sstevel@tonic-gate size->ncolumn = gl->ncolumn; 9419*7c478bd9Sstevel@tonic-gate }; 9420*7c478bd9Sstevel@tonic-gate return; 9421*7c478bd9Sstevel@tonic-gate } 9422*7c478bd9Sstevel@tonic-gate 9423*7c478bd9Sstevel@tonic-gate /*....................................................................... 9424*7c478bd9Sstevel@tonic-gate * Resize or delete the history buffer. 9425*7c478bd9Sstevel@tonic-gate * 9426*7c478bd9Sstevel@tonic-gate * Input: 9427*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9428*7c478bd9Sstevel@tonic-gate * bufsize size_t The number of bytes in the history buffer, or 0 9429*7c478bd9Sstevel@tonic-gate * to delete the buffer completely. 9430*7c478bd9Sstevel@tonic-gate * Output: 9431*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 9432*7c478bd9Sstevel@tonic-gate * 1 - Insufficient memory (the previous buffer 9433*7c478bd9Sstevel@tonic-gate * will have been retained). No error message 9434*7c478bd9Sstevel@tonic-gate * will be displayed. 9435*7c478bd9Sstevel@tonic-gate */ 9436*7c478bd9Sstevel@tonic-gate int gl_resize_history(GetLine *gl, size_t bufsize) 9437*7c478bd9Sstevel@tonic-gate { 9438*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 9439*7c478bd9Sstevel@tonic-gate int status; /* The return status of this function */ 9440*7c478bd9Sstevel@tonic-gate /* 9441*7c478bd9Sstevel@tonic-gate * Check the arguments. 9442*7c478bd9Sstevel@tonic-gate */ 9443*7c478bd9Sstevel@tonic-gate if(!gl) 9444*7c478bd9Sstevel@tonic-gate return 1; 9445*7c478bd9Sstevel@tonic-gate /* 9446*7c478bd9Sstevel@tonic-gate * Block all signals while modifying the contents of gl. 9447*7c478bd9Sstevel@tonic-gate */ 9448*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 9449*7c478bd9Sstevel@tonic-gate return 1; 9450*7c478bd9Sstevel@tonic-gate /* 9451*7c478bd9Sstevel@tonic-gate * Perform the resize while signals are blocked. 9452*7c478bd9Sstevel@tonic-gate */ 9453*7c478bd9Sstevel@tonic-gate status = _glh_resize_history(gl->glh, bufsize); 9454*7c478bd9Sstevel@tonic-gate if(status) 9455*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 9456*7c478bd9Sstevel@tonic-gate /* 9457*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9458*7c478bd9Sstevel@tonic-gate */ 9459*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9460*7c478bd9Sstevel@tonic-gate return status; 9461*7c478bd9Sstevel@tonic-gate } 9462*7c478bd9Sstevel@tonic-gate 9463*7c478bd9Sstevel@tonic-gate /*....................................................................... 9464*7c478bd9Sstevel@tonic-gate * Set an upper limit to the number of lines that can be recorded in the 9465*7c478bd9Sstevel@tonic-gate * history list, or remove a previously specified limit. 9466*7c478bd9Sstevel@tonic-gate * 9467*7c478bd9Sstevel@tonic-gate * Input: 9468*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9469*7c478bd9Sstevel@tonic-gate * max_lines int The maximum number of lines to allow, or -1 to 9470*7c478bd9Sstevel@tonic-gate * cancel a previous limit and allow as many lines 9471*7c478bd9Sstevel@tonic-gate * as will fit in the current history buffer size. 9472*7c478bd9Sstevel@tonic-gate */ 9473*7c478bd9Sstevel@tonic-gate void gl_limit_history(GetLine *gl, int max_lines) 9474*7c478bd9Sstevel@tonic-gate { 9475*7c478bd9Sstevel@tonic-gate if(gl) { 9476*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 9477*7c478bd9Sstevel@tonic-gate /* 9478*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 9479*7c478bd9Sstevel@tonic-gate */ 9480*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9481*7c478bd9Sstevel@tonic-gate /* 9482*7c478bd9Sstevel@tonic-gate * Apply the limit while signals are blocked. 9483*7c478bd9Sstevel@tonic-gate */ 9484*7c478bd9Sstevel@tonic-gate _glh_limit_history(gl->glh, max_lines); 9485*7c478bd9Sstevel@tonic-gate /* 9486*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9487*7c478bd9Sstevel@tonic-gate */ 9488*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9489*7c478bd9Sstevel@tonic-gate }; 9490*7c478bd9Sstevel@tonic-gate } 9491*7c478bd9Sstevel@tonic-gate 9492*7c478bd9Sstevel@tonic-gate /*....................................................................... 9493*7c478bd9Sstevel@tonic-gate * Discard either all historical lines, or just those associated with the 9494*7c478bd9Sstevel@tonic-gate * current history group. 9495*7c478bd9Sstevel@tonic-gate * 9496*7c478bd9Sstevel@tonic-gate * Input: 9497*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9498*7c478bd9Sstevel@tonic-gate * all_groups int If true, clear all of the history. If false, 9499*7c478bd9Sstevel@tonic-gate * clear only the stored lines associated with the 9500*7c478bd9Sstevel@tonic-gate * currently selected history group. 9501*7c478bd9Sstevel@tonic-gate */ 9502*7c478bd9Sstevel@tonic-gate void gl_clear_history(GetLine *gl, int all_groups) 9503*7c478bd9Sstevel@tonic-gate { 9504*7c478bd9Sstevel@tonic-gate if(gl) { 9505*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 9506*7c478bd9Sstevel@tonic-gate /* 9507*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 9508*7c478bd9Sstevel@tonic-gate */ 9509*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9510*7c478bd9Sstevel@tonic-gate /* 9511*7c478bd9Sstevel@tonic-gate * Clear the history buffer while signals are blocked. 9512*7c478bd9Sstevel@tonic-gate */ 9513*7c478bd9Sstevel@tonic-gate _glh_clear_history(gl->glh, all_groups); 9514*7c478bd9Sstevel@tonic-gate /* 9515*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9516*7c478bd9Sstevel@tonic-gate */ 9517*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9518*7c478bd9Sstevel@tonic-gate }; 9519*7c478bd9Sstevel@tonic-gate } 9520*7c478bd9Sstevel@tonic-gate 9521*7c478bd9Sstevel@tonic-gate /*....................................................................... 9522*7c478bd9Sstevel@tonic-gate * Temporarily enable or disable the gl_get_line() history mechanism. 9523*7c478bd9Sstevel@tonic-gate * 9524*7c478bd9Sstevel@tonic-gate * Input: 9525*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9526*7c478bd9Sstevel@tonic-gate * enable int If true, turn on the history mechanism. If 9527*7c478bd9Sstevel@tonic-gate * false, disable it. 9528*7c478bd9Sstevel@tonic-gate */ 9529*7c478bd9Sstevel@tonic-gate void gl_toggle_history(GetLine *gl, int enable) 9530*7c478bd9Sstevel@tonic-gate { 9531*7c478bd9Sstevel@tonic-gate if(gl) { 9532*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 9533*7c478bd9Sstevel@tonic-gate /* 9534*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 9535*7c478bd9Sstevel@tonic-gate */ 9536*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9537*7c478bd9Sstevel@tonic-gate /* 9538*7c478bd9Sstevel@tonic-gate * Change the history recording mode while signals are blocked. 9539*7c478bd9Sstevel@tonic-gate */ 9540*7c478bd9Sstevel@tonic-gate _glh_toggle_history(gl->glh, enable); 9541*7c478bd9Sstevel@tonic-gate /* 9542*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9543*7c478bd9Sstevel@tonic-gate */ 9544*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9545*7c478bd9Sstevel@tonic-gate }; 9546*7c478bd9Sstevel@tonic-gate } 9547*7c478bd9Sstevel@tonic-gate 9548*7c478bd9Sstevel@tonic-gate /*....................................................................... 9549*7c478bd9Sstevel@tonic-gate * Lookup a history line by its sequential number of entry in the 9550*7c478bd9Sstevel@tonic-gate * history buffer. 9551*7c478bd9Sstevel@tonic-gate * 9552*7c478bd9Sstevel@tonic-gate * Input: 9553*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9554*7c478bd9Sstevel@tonic-gate * id unsigned long The identification number of the line to 9555*7c478bd9Sstevel@tonic-gate * be returned, where 0 denotes the first line 9556*7c478bd9Sstevel@tonic-gate * that was entered in the history list, and 9557*7c478bd9Sstevel@tonic-gate * each subsequently added line has a number 9558*7c478bd9Sstevel@tonic-gate * one greater than the previous one. For 9559*7c478bd9Sstevel@tonic-gate * the range of lines currently in the list, 9560*7c478bd9Sstevel@tonic-gate * see the gl_range_of_history() function. 9561*7c478bd9Sstevel@tonic-gate * Input/Output: 9562*7c478bd9Sstevel@tonic-gate * line GlHistoryLine * A pointer to the variable in which to 9563*7c478bd9Sstevel@tonic-gate * return the details of the line. 9564*7c478bd9Sstevel@tonic-gate * Output: 9565*7c478bd9Sstevel@tonic-gate * return int 0 - The line is no longer in the history 9566*7c478bd9Sstevel@tonic-gate * list, and *line has not been changed. 9567*7c478bd9Sstevel@tonic-gate * 1 - The requested line can be found in 9568*7c478bd9Sstevel@tonic-gate * *line. Note that line->line is part 9569*7c478bd9Sstevel@tonic-gate * of the history buffer, so a 9570*7c478bd9Sstevel@tonic-gate * private copy should be made if you 9571*7c478bd9Sstevel@tonic-gate * wish to use it after subsequent calls 9572*7c478bd9Sstevel@tonic-gate * to any functions that take *gl as an 9573*7c478bd9Sstevel@tonic-gate * argument. 9574*7c478bd9Sstevel@tonic-gate */ 9575*7c478bd9Sstevel@tonic-gate int gl_lookup_history(GetLine *gl, unsigned long id, GlHistoryLine *line) 9576*7c478bd9Sstevel@tonic-gate { 9577*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 9578*7c478bd9Sstevel@tonic-gate int status; /* The return status of this function */ 9579*7c478bd9Sstevel@tonic-gate /* 9580*7c478bd9Sstevel@tonic-gate * Check the arguments. 9581*7c478bd9Sstevel@tonic-gate */ 9582*7c478bd9Sstevel@tonic-gate if(!gl) 9583*7c478bd9Sstevel@tonic-gate return 0; 9584*7c478bd9Sstevel@tonic-gate /* 9585*7c478bd9Sstevel@tonic-gate * Block all signals while modifying the contents of gl. 9586*7c478bd9Sstevel@tonic-gate */ 9587*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 9588*7c478bd9Sstevel@tonic-gate return 1; 9589*7c478bd9Sstevel@tonic-gate /* 9590*7c478bd9Sstevel@tonic-gate * Perform the lookup while signals are blocked. 9591*7c478bd9Sstevel@tonic-gate */ 9592*7c478bd9Sstevel@tonic-gate status = _glh_lookup_history(gl->glh, (GlhLineID) id, &line->line, 9593*7c478bd9Sstevel@tonic-gate &line->group, &line->timestamp); 9594*7c478bd9Sstevel@tonic-gate if(status) 9595*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 9596*7c478bd9Sstevel@tonic-gate /* 9597*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9598*7c478bd9Sstevel@tonic-gate */ 9599*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9600*7c478bd9Sstevel@tonic-gate return status; 9601*7c478bd9Sstevel@tonic-gate } 9602*7c478bd9Sstevel@tonic-gate 9603*7c478bd9Sstevel@tonic-gate /*....................................................................... 9604*7c478bd9Sstevel@tonic-gate * Query the state of the history list. Note that any of the input/output 9605*7c478bd9Sstevel@tonic-gate * pointers can be specified as NULL. 9606*7c478bd9Sstevel@tonic-gate * 9607*7c478bd9Sstevel@tonic-gate * Input: 9608*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9609*7c478bd9Sstevel@tonic-gate * Input/Output: 9610*7c478bd9Sstevel@tonic-gate * state GlHistoryState * A pointer to the variable in which to record 9611*7c478bd9Sstevel@tonic-gate * the return values. 9612*7c478bd9Sstevel@tonic-gate */ 9613*7c478bd9Sstevel@tonic-gate void gl_state_of_history(GetLine *gl, GlHistoryState *state) 9614*7c478bd9Sstevel@tonic-gate { 9615*7c478bd9Sstevel@tonic-gate if(gl && state) { 9616*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 9617*7c478bd9Sstevel@tonic-gate /* 9618*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 9619*7c478bd9Sstevel@tonic-gate */ 9620*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9621*7c478bd9Sstevel@tonic-gate /* 9622*7c478bd9Sstevel@tonic-gate * Lookup the status while signals are blocked. 9623*7c478bd9Sstevel@tonic-gate */ 9624*7c478bd9Sstevel@tonic-gate _glh_state_of_history(gl->glh, &state->enabled, &state->group, 9625*7c478bd9Sstevel@tonic-gate &state->max_lines); 9626*7c478bd9Sstevel@tonic-gate /* 9627*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9628*7c478bd9Sstevel@tonic-gate */ 9629*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9630*7c478bd9Sstevel@tonic-gate }; 9631*7c478bd9Sstevel@tonic-gate } 9632*7c478bd9Sstevel@tonic-gate 9633*7c478bd9Sstevel@tonic-gate /*....................................................................... 9634*7c478bd9Sstevel@tonic-gate * Query the number and range of lines in the history buffer. 9635*7c478bd9Sstevel@tonic-gate * 9636*7c478bd9Sstevel@tonic-gate * Input: 9637*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9638*7c478bd9Sstevel@tonic-gate * range GlHistoryRange * A pointer to the variable in which to record 9639*7c478bd9Sstevel@tonic-gate * the return values. If range->nline=0, the 9640*7c478bd9Sstevel@tonic-gate * range of lines will be given as 0-0. 9641*7c478bd9Sstevel@tonic-gate */ 9642*7c478bd9Sstevel@tonic-gate void gl_range_of_history(GetLine *gl, GlHistoryRange *range) 9643*7c478bd9Sstevel@tonic-gate { 9644*7c478bd9Sstevel@tonic-gate if(gl && range) { 9645*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 9646*7c478bd9Sstevel@tonic-gate /* 9647*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 9648*7c478bd9Sstevel@tonic-gate */ 9649*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9650*7c478bd9Sstevel@tonic-gate /* 9651*7c478bd9Sstevel@tonic-gate * Lookup the information while signals are blocked. 9652*7c478bd9Sstevel@tonic-gate */ 9653*7c478bd9Sstevel@tonic-gate _glh_range_of_history(gl->glh, &range->oldest, &range->newest, 9654*7c478bd9Sstevel@tonic-gate &range->nlines); 9655*7c478bd9Sstevel@tonic-gate /* 9656*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9657*7c478bd9Sstevel@tonic-gate */ 9658*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9659*7c478bd9Sstevel@tonic-gate }; 9660*7c478bd9Sstevel@tonic-gate } 9661*7c478bd9Sstevel@tonic-gate 9662*7c478bd9Sstevel@tonic-gate /*....................................................................... 9663*7c478bd9Sstevel@tonic-gate * Return the size of the history buffer and the amount of the 9664*7c478bd9Sstevel@tonic-gate * buffer that is currently in use. 9665*7c478bd9Sstevel@tonic-gate * 9666*7c478bd9Sstevel@tonic-gate * Input: 9667*7c478bd9Sstevel@tonic-gate * gl GetLine * The gl_get_line() resource object. 9668*7c478bd9Sstevel@tonic-gate * Input/Output: 9669*7c478bd9Sstevel@tonic-gate * GlHistorySize size * A pointer to the variable in which to return 9670*7c478bd9Sstevel@tonic-gate * the results. 9671*7c478bd9Sstevel@tonic-gate */ 9672*7c478bd9Sstevel@tonic-gate void gl_size_of_history(GetLine *gl, GlHistorySize *size) 9673*7c478bd9Sstevel@tonic-gate { 9674*7c478bd9Sstevel@tonic-gate if(gl && size) { 9675*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 9676*7c478bd9Sstevel@tonic-gate /* 9677*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 9678*7c478bd9Sstevel@tonic-gate */ 9679*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9680*7c478bd9Sstevel@tonic-gate /* 9681*7c478bd9Sstevel@tonic-gate * Lookup the information while signals are blocked. 9682*7c478bd9Sstevel@tonic-gate */ 9683*7c478bd9Sstevel@tonic-gate _glh_size_of_history(gl->glh, &size->size, &size->used); 9684*7c478bd9Sstevel@tonic-gate /* 9685*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9686*7c478bd9Sstevel@tonic-gate */ 9687*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9688*7c478bd9Sstevel@tonic-gate }; 9689*7c478bd9Sstevel@tonic-gate } 9690*7c478bd9Sstevel@tonic-gate 9691*7c478bd9Sstevel@tonic-gate /*....................................................................... 9692*7c478bd9Sstevel@tonic-gate * This is the action function that lists the contents of the history 9693*7c478bd9Sstevel@tonic-gate * list. 9694*7c478bd9Sstevel@tonic-gate */ 9695*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_list_history) 9696*7c478bd9Sstevel@tonic-gate { 9697*7c478bd9Sstevel@tonic-gate /* 9698*7c478bd9Sstevel@tonic-gate * Start a new line. 9699*7c478bd9Sstevel@tonic-gate */ 9700*7c478bd9Sstevel@tonic-gate if(gl_start_newline(gl, 1)) 9701*7c478bd9Sstevel@tonic-gate return 1; 9702*7c478bd9Sstevel@tonic-gate /* 9703*7c478bd9Sstevel@tonic-gate * List history lines that belong to the current group. 9704*7c478bd9Sstevel@tonic-gate */ 9705*7c478bd9Sstevel@tonic-gate _glh_show_history(gl->glh, gl_write_fn, gl, "%N %T %H\r\n", 0, 9706*7c478bd9Sstevel@tonic-gate count<=1 ? -1 : count); 9707*7c478bd9Sstevel@tonic-gate /* 9708*7c478bd9Sstevel@tonic-gate * Arrange for the input line to be redisplayed. 9709*7c478bd9Sstevel@tonic-gate */ 9710*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 9711*7c478bd9Sstevel@tonic-gate return 0; 9712*7c478bd9Sstevel@tonic-gate } 9713*7c478bd9Sstevel@tonic-gate 9714*7c478bd9Sstevel@tonic-gate /*....................................................................... 9715*7c478bd9Sstevel@tonic-gate * Specify whether text that users type should be displayed or hidden. 9716*7c478bd9Sstevel@tonic-gate * In the latter case, only the prompt is displayed, and the final 9717*7c478bd9Sstevel@tonic-gate * input line is not archived in the history list. 9718*7c478bd9Sstevel@tonic-gate * 9719*7c478bd9Sstevel@tonic-gate * Input: 9720*7c478bd9Sstevel@tonic-gate * gl GetLine * The gl_get_line() resource object. 9721*7c478bd9Sstevel@tonic-gate * enable int 0 - Disable echoing. 9722*7c478bd9Sstevel@tonic-gate * 1 - Enable echoing. 9723*7c478bd9Sstevel@tonic-gate * -1 - Just query the mode without changing it. 9724*7c478bd9Sstevel@tonic-gate * Output: 9725*7c478bd9Sstevel@tonic-gate * return int The echoing disposition that was in effect 9726*7c478bd9Sstevel@tonic-gate * before this function was called: 9727*7c478bd9Sstevel@tonic-gate * 0 - Echoing was disabled. 9728*7c478bd9Sstevel@tonic-gate * 1 - Echoing was enabled. 9729*7c478bd9Sstevel@tonic-gate */ 9730*7c478bd9Sstevel@tonic-gate int gl_echo_mode(GetLine *gl, int enable) 9731*7c478bd9Sstevel@tonic-gate { 9732*7c478bd9Sstevel@tonic-gate if(gl) { 9733*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 9734*7c478bd9Sstevel@tonic-gate int was_echoing; /* The echoing disposition on entry to this function */ 9735*7c478bd9Sstevel@tonic-gate /* 9736*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 9737*7c478bd9Sstevel@tonic-gate */ 9738*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9739*7c478bd9Sstevel@tonic-gate /* 9740*7c478bd9Sstevel@tonic-gate * Install the new disposition while signals are blocked. 9741*7c478bd9Sstevel@tonic-gate */ 9742*7c478bd9Sstevel@tonic-gate was_echoing = gl->echo; 9743*7c478bd9Sstevel@tonic-gate if(enable >= 0) 9744*7c478bd9Sstevel@tonic-gate gl->echo = enable; 9745*7c478bd9Sstevel@tonic-gate /* 9746*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9747*7c478bd9Sstevel@tonic-gate */ 9748*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9749*7c478bd9Sstevel@tonic-gate /* 9750*7c478bd9Sstevel@tonic-gate * Return the original echoing disposition. 9751*7c478bd9Sstevel@tonic-gate */ 9752*7c478bd9Sstevel@tonic-gate return was_echoing; 9753*7c478bd9Sstevel@tonic-gate }; 9754*7c478bd9Sstevel@tonic-gate return 1; 9755*7c478bd9Sstevel@tonic-gate } 9756*7c478bd9Sstevel@tonic-gate 9757*7c478bd9Sstevel@tonic-gate /*....................................................................... 9758*7c478bd9Sstevel@tonic-gate * Display the prompt. 9759*7c478bd9Sstevel@tonic-gate * 9760*7c478bd9Sstevel@tonic-gate * Input: 9761*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9762*7c478bd9Sstevel@tonic-gate * Output: 9763*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 9764*7c478bd9Sstevel@tonic-gate * 1 - Error. 9765*7c478bd9Sstevel@tonic-gate */ 9766*7c478bd9Sstevel@tonic-gate static int gl_display_prompt(GetLine *gl) 9767*7c478bd9Sstevel@tonic-gate { 9768*7c478bd9Sstevel@tonic-gate const char *pptr; /* A pointer into gl->prompt[] */ 9769*7c478bd9Sstevel@tonic-gate unsigned old_attr=0; /* The current text display attributes */ 9770*7c478bd9Sstevel@tonic-gate unsigned new_attr=0; /* The requested text display attributes */ 9771*7c478bd9Sstevel@tonic-gate /* 9772*7c478bd9Sstevel@tonic-gate * Temporarily switch to echoing output characters. 9773*7c478bd9Sstevel@tonic-gate */ 9774*7c478bd9Sstevel@tonic-gate int kept_echo = gl->echo; 9775*7c478bd9Sstevel@tonic-gate gl->echo = 1; 9776*7c478bd9Sstevel@tonic-gate /* 9777*7c478bd9Sstevel@tonic-gate * In case the screen got messed up, send a carriage return to 9778*7c478bd9Sstevel@tonic-gate * put the cursor at the beginning of the current terminal line. 9779*7c478bd9Sstevel@tonic-gate */ 9780*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->bol)) 9781*7c478bd9Sstevel@tonic-gate return 1; 9782*7c478bd9Sstevel@tonic-gate /* 9783*7c478bd9Sstevel@tonic-gate * Mark the line as partially displayed. 9784*7c478bd9Sstevel@tonic-gate */ 9785*7c478bd9Sstevel@tonic-gate gl->displayed = 1; 9786*7c478bd9Sstevel@tonic-gate /* 9787*7c478bd9Sstevel@tonic-gate * Write the prompt, using the currently selected prompt style. 9788*7c478bd9Sstevel@tonic-gate */ 9789*7c478bd9Sstevel@tonic-gate switch(gl->prompt_style) { 9790*7c478bd9Sstevel@tonic-gate case GL_LITERAL_PROMPT: 9791*7c478bd9Sstevel@tonic-gate if(gl_print_string(gl, gl->prompt, '\0')) 9792*7c478bd9Sstevel@tonic-gate return 1; 9793*7c478bd9Sstevel@tonic-gate break; 9794*7c478bd9Sstevel@tonic-gate case GL_FORMAT_PROMPT: 9795*7c478bd9Sstevel@tonic-gate for(pptr=gl->prompt; *pptr; pptr++) { 9796*7c478bd9Sstevel@tonic-gate /* 9797*7c478bd9Sstevel@tonic-gate * Does the latest character appear to be the start of a directive? 9798*7c478bd9Sstevel@tonic-gate */ 9799*7c478bd9Sstevel@tonic-gate if(*pptr == '%') { 9800*7c478bd9Sstevel@tonic-gate /* 9801*7c478bd9Sstevel@tonic-gate * Check for and act on attribute changing directives. 9802*7c478bd9Sstevel@tonic-gate */ 9803*7c478bd9Sstevel@tonic-gate switch(pptr[1]) { 9804*7c478bd9Sstevel@tonic-gate /* 9805*7c478bd9Sstevel@tonic-gate * Add or remove a text attribute from the new set of attributes. 9806*7c478bd9Sstevel@tonic-gate */ 9807*7c478bd9Sstevel@tonic-gate case 'B': case 'U': case 'S': case 'P': case 'F': case 'V': 9808*7c478bd9Sstevel@tonic-gate case 'b': case 'u': case 's': case 'p': case 'f': case 'v': 9809*7c478bd9Sstevel@tonic-gate switch(*++pptr) { 9810*7c478bd9Sstevel@tonic-gate case 'B': /* Switch to a bold font */ 9811*7c478bd9Sstevel@tonic-gate new_attr |= GL_TXT_BOLD; 9812*7c478bd9Sstevel@tonic-gate break; 9813*7c478bd9Sstevel@tonic-gate case 'b': /* Switch to a non-bold font */ 9814*7c478bd9Sstevel@tonic-gate new_attr &= ~GL_TXT_BOLD; 9815*7c478bd9Sstevel@tonic-gate break; 9816*7c478bd9Sstevel@tonic-gate case 'U': /* Start underlining */ 9817*7c478bd9Sstevel@tonic-gate new_attr |= GL_TXT_UNDERLINE; 9818*7c478bd9Sstevel@tonic-gate break; 9819*7c478bd9Sstevel@tonic-gate case 'u': /* Stop underlining */ 9820*7c478bd9Sstevel@tonic-gate new_attr &= ~GL_TXT_UNDERLINE; 9821*7c478bd9Sstevel@tonic-gate break; 9822*7c478bd9Sstevel@tonic-gate case 'S': /* Start highlighting */ 9823*7c478bd9Sstevel@tonic-gate new_attr |= GL_TXT_STANDOUT; 9824*7c478bd9Sstevel@tonic-gate break; 9825*7c478bd9Sstevel@tonic-gate case 's': /* Stop highlighting */ 9826*7c478bd9Sstevel@tonic-gate new_attr &= ~GL_TXT_STANDOUT; 9827*7c478bd9Sstevel@tonic-gate break; 9828*7c478bd9Sstevel@tonic-gate case 'P': /* Switch to a pale font */ 9829*7c478bd9Sstevel@tonic-gate new_attr |= GL_TXT_DIM; 9830*7c478bd9Sstevel@tonic-gate break; 9831*7c478bd9Sstevel@tonic-gate case 'p': /* Switch to a non-pale font */ 9832*7c478bd9Sstevel@tonic-gate new_attr &= ~GL_TXT_DIM; 9833*7c478bd9Sstevel@tonic-gate break; 9834*7c478bd9Sstevel@tonic-gate case 'F': /* Switch to a flashing font */ 9835*7c478bd9Sstevel@tonic-gate new_attr |= GL_TXT_BLINK; 9836*7c478bd9Sstevel@tonic-gate break; 9837*7c478bd9Sstevel@tonic-gate case 'f': /* Switch to a steady font */ 9838*7c478bd9Sstevel@tonic-gate new_attr &= ~GL_TXT_BLINK; 9839*7c478bd9Sstevel@tonic-gate break; 9840*7c478bd9Sstevel@tonic-gate case 'V': /* Switch to reverse video */ 9841*7c478bd9Sstevel@tonic-gate new_attr |= GL_TXT_REVERSE; 9842*7c478bd9Sstevel@tonic-gate break; 9843*7c478bd9Sstevel@tonic-gate case 'v': /* Switch out of reverse video */ 9844*7c478bd9Sstevel@tonic-gate new_attr &= ~GL_TXT_REVERSE; 9845*7c478bd9Sstevel@tonic-gate break; 9846*7c478bd9Sstevel@tonic-gate }; 9847*7c478bd9Sstevel@tonic-gate continue; 9848*7c478bd9Sstevel@tonic-gate /* 9849*7c478bd9Sstevel@tonic-gate * A literal % is represented by %%. Skip the leading %. 9850*7c478bd9Sstevel@tonic-gate */ 9851*7c478bd9Sstevel@tonic-gate case '%': 9852*7c478bd9Sstevel@tonic-gate pptr++; 9853*7c478bd9Sstevel@tonic-gate break; 9854*7c478bd9Sstevel@tonic-gate }; 9855*7c478bd9Sstevel@tonic-gate }; 9856*7c478bd9Sstevel@tonic-gate /* 9857*7c478bd9Sstevel@tonic-gate * Many terminals, when asked to turn off a single text attribute, turn 9858*7c478bd9Sstevel@tonic-gate * them all off, so the portable way to turn one off individually is to 9859*7c478bd9Sstevel@tonic-gate * explicitly turn them all off, then specify those that we want from 9860*7c478bd9Sstevel@tonic-gate * scratch. 9861*7c478bd9Sstevel@tonic-gate */ 9862*7c478bd9Sstevel@tonic-gate if(old_attr & ~new_attr) { 9863*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->text_attr_off)) 9864*7c478bd9Sstevel@tonic-gate return 1; 9865*7c478bd9Sstevel@tonic-gate old_attr = 0; 9866*7c478bd9Sstevel@tonic-gate }; 9867*7c478bd9Sstevel@tonic-gate /* 9868*7c478bd9Sstevel@tonic-gate * Install new text attributes? 9869*7c478bd9Sstevel@tonic-gate */ 9870*7c478bd9Sstevel@tonic-gate if(new_attr != old_attr) { 9871*7c478bd9Sstevel@tonic-gate if(new_attr & GL_TXT_BOLD && !(old_attr & GL_TXT_BOLD) && 9872*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, 1, gl->bold)) 9873*7c478bd9Sstevel@tonic-gate return 1; 9874*7c478bd9Sstevel@tonic-gate if(new_attr & GL_TXT_UNDERLINE && !(old_attr & GL_TXT_UNDERLINE) && 9875*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, 1, gl->underline)) 9876*7c478bd9Sstevel@tonic-gate return 1; 9877*7c478bd9Sstevel@tonic-gate if(new_attr & GL_TXT_STANDOUT && !(old_attr & GL_TXT_STANDOUT) && 9878*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, 1, gl->standout)) 9879*7c478bd9Sstevel@tonic-gate return 1; 9880*7c478bd9Sstevel@tonic-gate if(new_attr & GL_TXT_DIM && !(old_attr & GL_TXT_DIM) && 9881*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, 1, gl->dim)) 9882*7c478bd9Sstevel@tonic-gate return 1; 9883*7c478bd9Sstevel@tonic-gate if(new_attr & GL_TXT_REVERSE && !(old_attr & GL_TXT_REVERSE) && 9884*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, 1, gl->reverse)) 9885*7c478bd9Sstevel@tonic-gate return 1; 9886*7c478bd9Sstevel@tonic-gate if(new_attr & GL_TXT_BLINK && !(old_attr & GL_TXT_BLINK) && 9887*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, 1, gl->blink)) 9888*7c478bd9Sstevel@tonic-gate return 1; 9889*7c478bd9Sstevel@tonic-gate old_attr = new_attr; 9890*7c478bd9Sstevel@tonic-gate }; 9891*7c478bd9Sstevel@tonic-gate /* 9892*7c478bd9Sstevel@tonic-gate * Display the latest character. 9893*7c478bd9Sstevel@tonic-gate */ 9894*7c478bd9Sstevel@tonic-gate if(gl_print_char(gl, *pptr, pptr[1])) 9895*7c478bd9Sstevel@tonic-gate return 1; 9896*7c478bd9Sstevel@tonic-gate }; 9897*7c478bd9Sstevel@tonic-gate /* 9898*7c478bd9Sstevel@tonic-gate * Turn off all text attributes now that we have finished drawing 9899*7c478bd9Sstevel@tonic-gate * the prompt. 9900*7c478bd9Sstevel@tonic-gate */ 9901*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->text_attr_off)) 9902*7c478bd9Sstevel@tonic-gate return 1; 9903*7c478bd9Sstevel@tonic-gate break; 9904*7c478bd9Sstevel@tonic-gate }; 9905*7c478bd9Sstevel@tonic-gate /* 9906*7c478bd9Sstevel@tonic-gate * Restore the original echo mode. 9907*7c478bd9Sstevel@tonic-gate */ 9908*7c478bd9Sstevel@tonic-gate gl->echo = kept_echo; 9909*7c478bd9Sstevel@tonic-gate /* 9910*7c478bd9Sstevel@tonic-gate * The prompt has now been displayed at least once. 9911*7c478bd9Sstevel@tonic-gate */ 9912*7c478bd9Sstevel@tonic-gate gl->prompt_changed = 0; 9913*7c478bd9Sstevel@tonic-gate return 0; 9914*7c478bd9Sstevel@tonic-gate } 9915*7c478bd9Sstevel@tonic-gate 9916*7c478bd9Sstevel@tonic-gate /*....................................................................... 9917*7c478bd9Sstevel@tonic-gate * This function can be called from gl_get_line() callbacks to have 9918*7c478bd9Sstevel@tonic-gate * the prompt changed when they return. It has no effect if gl_get_line() 9919*7c478bd9Sstevel@tonic-gate * is not currently being invoked. 9920*7c478bd9Sstevel@tonic-gate * 9921*7c478bd9Sstevel@tonic-gate * Input: 9922*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 9923*7c478bd9Sstevel@tonic-gate * prompt const char * The new prompt. 9924*7c478bd9Sstevel@tonic-gate */ 9925*7c478bd9Sstevel@tonic-gate void gl_replace_prompt(GetLine *gl, const char *prompt) 9926*7c478bd9Sstevel@tonic-gate { 9927*7c478bd9Sstevel@tonic-gate if(gl) { 9928*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 9929*7c478bd9Sstevel@tonic-gate /* 9930*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 9931*7c478bd9Sstevel@tonic-gate */ 9932*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 9933*7c478bd9Sstevel@tonic-gate /* 9934*7c478bd9Sstevel@tonic-gate * Replace the prompt. 9935*7c478bd9Sstevel@tonic-gate */ 9936*7c478bd9Sstevel@tonic-gate _gl_replace_prompt(gl, prompt); 9937*7c478bd9Sstevel@tonic-gate /* 9938*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 9939*7c478bd9Sstevel@tonic-gate */ 9940*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 9941*7c478bd9Sstevel@tonic-gate }; 9942*7c478bd9Sstevel@tonic-gate } 9943*7c478bd9Sstevel@tonic-gate 9944*7c478bd9Sstevel@tonic-gate /*....................................................................... 9945*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_replace_prompt() function. It 9946*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 9947*7c478bd9Sstevel@tonic-gate * delivery of signals. 9948*7c478bd9Sstevel@tonic-gate */ 9949*7c478bd9Sstevel@tonic-gate static void _gl_replace_prompt(GetLine *gl, const char *prompt) 9950*7c478bd9Sstevel@tonic-gate { 9951*7c478bd9Sstevel@tonic-gate size_t size; 9952*7c478bd9Sstevel@tonic-gate 9953*7c478bd9Sstevel@tonic-gate /* 9954*7c478bd9Sstevel@tonic-gate * Substitute an empty prompt? 9955*7c478bd9Sstevel@tonic-gate */ 9956*7c478bd9Sstevel@tonic-gate if(!prompt) 9957*7c478bd9Sstevel@tonic-gate prompt = ""; 9958*7c478bd9Sstevel@tonic-gate /* 9959*7c478bd9Sstevel@tonic-gate * Gaurd against aliasing between prompt and gl->prompt. 9960*7c478bd9Sstevel@tonic-gate */ 9961*7c478bd9Sstevel@tonic-gate if(gl->prompt != prompt) { 9962*7c478bd9Sstevel@tonic-gate /* 9963*7c478bd9Sstevel@tonic-gate * Get the length of the new prompt string. 9964*7c478bd9Sstevel@tonic-gate */ 9965*7c478bd9Sstevel@tonic-gate size_t slen = strlen(prompt); 9966*7c478bd9Sstevel@tonic-gate /* 9967*7c478bd9Sstevel@tonic-gate * If needed, allocate a new buffer for the prompt string. 9968*7c478bd9Sstevel@tonic-gate */ 9969*7c478bd9Sstevel@tonic-gate size = sizeof(char) * (slen + 1); 9970*7c478bd9Sstevel@tonic-gate if(!gl->prompt || slen > strlen(gl->prompt)) { 9971*7c478bd9Sstevel@tonic-gate char *new_prompt = gl->prompt ? realloc(gl->prompt, size) : malloc(size); 9972*7c478bd9Sstevel@tonic-gate if(!new_prompt) 9973*7c478bd9Sstevel@tonic-gate return; 9974*7c478bd9Sstevel@tonic-gate gl->prompt = new_prompt; 9975*7c478bd9Sstevel@tonic-gate }; 9976*7c478bd9Sstevel@tonic-gate /* 9977*7c478bd9Sstevel@tonic-gate * Make a copy of the new prompt. 9978*7c478bd9Sstevel@tonic-gate */ 9979*7c478bd9Sstevel@tonic-gate strlcpy(gl->prompt, prompt, size); 9980*7c478bd9Sstevel@tonic-gate }; 9981*7c478bd9Sstevel@tonic-gate /* 9982*7c478bd9Sstevel@tonic-gate * Record the statistics of the new prompt. 9983*7c478bd9Sstevel@tonic-gate */ 9984*7c478bd9Sstevel@tonic-gate gl->prompt_len = gl_displayed_prompt_width(gl); 9985*7c478bd9Sstevel@tonic-gate gl->prompt_changed = 1; 9986*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 9987*7c478bd9Sstevel@tonic-gate return; 9988*7c478bd9Sstevel@tonic-gate } 9989*7c478bd9Sstevel@tonic-gate 9990*7c478bd9Sstevel@tonic-gate /*....................................................................... 9991*7c478bd9Sstevel@tonic-gate * Work out the length of the current prompt on the terminal, according 9992*7c478bd9Sstevel@tonic-gate * to the current prompt formatting style. 9993*7c478bd9Sstevel@tonic-gate * 9994*7c478bd9Sstevel@tonic-gate * Input: 9995*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 9996*7c478bd9Sstevel@tonic-gate * Output: 9997*7c478bd9Sstevel@tonic-gate * return int The number of displayed characters. 9998*7c478bd9Sstevel@tonic-gate */ 9999*7c478bd9Sstevel@tonic-gate static int gl_displayed_prompt_width(GetLine *gl) 10000*7c478bd9Sstevel@tonic-gate { 10001*7c478bd9Sstevel@tonic-gate int slen=0; /* The displayed number of characters */ 10002*7c478bd9Sstevel@tonic-gate const char *pptr; /* A pointer into prompt[] */ 10003*7c478bd9Sstevel@tonic-gate /* 10004*7c478bd9Sstevel@tonic-gate * The length differs according to the prompt display style. 10005*7c478bd9Sstevel@tonic-gate */ 10006*7c478bd9Sstevel@tonic-gate switch(gl->prompt_style) { 10007*7c478bd9Sstevel@tonic-gate case GL_LITERAL_PROMPT: 10008*7c478bd9Sstevel@tonic-gate return gl_displayed_string_width(gl, gl->prompt, -1, 0); 10009*7c478bd9Sstevel@tonic-gate break; 10010*7c478bd9Sstevel@tonic-gate case GL_FORMAT_PROMPT: 10011*7c478bd9Sstevel@tonic-gate /* 10012*7c478bd9Sstevel@tonic-gate * Add up the length of the displayed string, while filtering out 10013*7c478bd9Sstevel@tonic-gate * attribute directives. 10014*7c478bd9Sstevel@tonic-gate */ 10015*7c478bd9Sstevel@tonic-gate for(pptr=gl->prompt; *pptr; pptr++) { 10016*7c478bd9Sstevel@tonic-gate /* 10017*7c478bd9Sstevel@tonic-gate * Does the latest character appear to be the start of a directive? 10018*7c478bd9Sstevel@tonic-gate */ 10019*7c478bd9Sstevel@tonic-gate if(*pptr == '%') { 10020*7c478bd9Sstevel@tonic-gate /* 10021*7c478bd9Sstevel@tonic-gate * Check for and skip attribute changing directives. 10022*7c478bd9Sstevel@tonic-gate */ 10023*7c478bd9Sstevel@tonic-gate switch(pptr[1]) { 10024*7c478bd9Sstevel@tonic-gate case 'B': case 'b': case 'U': case 'u': case 'S': case 's': 10025*7c478bd9Sstevel@tonic-gate pptr++; 10026*7c478bd9Sstevel@tonic-gate continue; 10027*7c478bd9Sstevel@tonic-gate /* 10028*7c478bd9Sstevel@tonic-gate * A literal % is represented by %%. Skip the leading %. 10029*7c478bd9Sstevel@tonic-gate */ 10030*7c478bd9Sstevel@tonic-gate case '%': 10031*7c478bd9Sstevel@tonic-gate pptr++; 10032*7c478bd9Sstevel@tonic-gate break; 10033*7c478bd9Sstevel@tonic-gate }; 10034*7c478bd9Sstevel@tonic-gate }; 10035*7c478bd9Sstevel@tonic-gate slen += gl_displayed_char_width(gl, *pptr, slen); 10036*7c478bd9Sstevel@tonic-gate }; 10037*7c478bd9Sstevel@tonic-gate break; 10038*7c478bd9Sstevel@tonic-gate }; 10039*7c478bd9Sstevel@tonic-gate return slen; 10040*7c478bd9Sstevel@tonic-gate } 10041*7c478bd9Sstevel@tonic-gate 10042*7c478bd9Sstevel@tonic-gate /*....................................................................... 10043*7c478bd9Sstevel@tonic-gate * Specify whether to heed text attribute directives within prompt 10044*7c478bd9Sstevel@tonic-gate * strings. 10045*7c478bd9Sstevel@tonic-gate * 10046*7c478bd9Sstevel@tonic-gate * Input: 10047*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 10048*7c478bd9Sstevel@tonic-gate * style GlPromptStyle The style of prompt (see the definition of 10049*7c478bd9Sstevel@tonic-gate * GlPromptStyle in libtecla.h for details). 10050*7c478bd9Sstevel@tonic-gate */ 10051*7c478bd9Sstevel@tonic-gate void gl_prompt_style(GetLine *gl, GlPromptStyle style) 10052*7c478bd9Sstevel@tonic-gate { 10053*7c478bd9Sstevel@tonic-gate if(gl) { 10054*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 10055*7c478bd9Sstevel@tonic-gate /* 10056*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 10057*7c478bd9Sstevel@tonic-gate */ 10058*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 10059*7c478bd9Sstevel@tonic-gate /* 10060*7c478bd9Sstevel@tonic-gate * Install the new style in gl while signals are blocked. 10061*7c478bd9Sstevel@tonic-gate */ 10062*7c478bd9Sstevel@tonic-gate if(style != gl->prompt_style) { 10063*7c478bd9Sstevel@tonic-gate gl->prompt_style = style; 10064*7c478bd9Sstevel@tonic-gate gl->prompt_len = gl_displayed_prompt_width(gl); 10065*7c478bd9Sstevel@tonic-gate gl->prompt_changed = 1; 10066*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 10067*7c478bd9Sstevel@tonic-gate }; 10068*7c478bd9Sstevel@tonic-gate /* 10069*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 10070*7c478bd9Sstevel@tonic-gate */ 10071*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10072*7c478bd9Sstevel@tonic-gate }; 10073*7c478bd9Sstevel@tonic-gate } 10074*7c478bd9Sstevel@tonic-gate 10075*7c478bd9Sstevel@tonic-gate /*....................................................................... 10076*7c478bd9Sstevel@tonic-gate * Tell gl_get_line() how to respond to a given signal. This can be used 10077*7c478bd9Sstevel@tonic-gate * both to override the default responses to signals that gl_get_line() 10078*7c478bd9Sstevel@tonic-gate * normally catches and to add new signals to the list that are to be 10079*7c478bd9Sstevel@tonic-gate * caught. 10080*7c478bd9Sstevel@tonic-gate * 10081*7c478bd9Sstevel@tonic-gate * Input: 10082*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 10083*7c478bd9Sstevel@tonic-gate * signo int The number of the signal to be caught. 10084*7c478bd9Sstevel@tonic-gate * flags unsigned A bitwise union of GlSignalFlags enumerators. 10085*7c478bd9Sstevel@tonic-gate * after GlAfterSignal What to do after the application's signal 10086*7c478bd9Sstevel@tonic-gate * handler has been called. 10087*7c478bd9Sstevel@tonic-gate * errno_value int The value to set errno to. 10088*7c478bd9Sstevel@tonic-gate * Output: 10089*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10090*7c478bd9Sstevel@tonic-gate * 1 - Error. 10091*7c478bd9Sstevel@tonic-gate */ 10092*7c478bd9Sstevel@tonic-gate int gl_trap_signal(GetLine *gl, int signo, unsigned flags, 10093*7c478bd9Sstevel@tonic-gate GlAfterSignal after, int errno_value) 10094*7c478bd9Sstevel@tonic-gate { 10095*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 10096*7c478bd9Sstevel@tonic-gate int status; /* The return status of this function */ 10097*7c478bd9Sstevel@tonic-gate /* 10098*7c478bd9Sstevel@tonic-gate * Check the arguments. 10099*7c478bd9Sstevel@tonic-gate */ 10100*7c478bd9Sstevel@tonic-gate if(!gl) { 10101*7c478bd9Sstevel@tonic-gate errno = EINVAL; 10102*7c478bd9Sstevel@tonic-gate return 1; 10103*7c478bd9Sstevel@tonic-gate }; 10104*7c478bd9Sstevel@tonic-gate /* 10105*7c478bd9Sstevel@tonic-gate * Block all signals while modifying the contents of gl. 10106*7c478bd9Sstevel@tonic-gate */ 10107*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 10108*7c478bd9Sstevel@tonic-gate return 1; 10109*7c478bd9Sstevel@tonic-gate /* 10110*7c478bd9Sstevel@tonic-gate * Perform the modification while signals are blocked. 10111*7c478bd9Sstevel@tonic-gate */ 10112*7c478bd9Sstevel@tonic-gate status = _gl_trap_signal(gl, signo, flags, after, errno_value); 10113*7c478bd9Sstevel@tonic-gate /* 10114*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 10115*7c478bd9Sstevel@tonic-gate */ 10116*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10117*7c478bd9Sstevel@tonic-gate return status; 10118*7c478bd9Sstevel@tonic-gate } 10119*7c478bd9Sstevel@tonic-gate 10120*7c478bd9Sstevel@tonic-gate /*....................................................................... 10121*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_trap_signal() function. It 10122*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 10123*7c478bd9Sstevel@tonic-gate * delivery of signals. 10124*7c478bd9Sstevel@tonic-gate */ 10125*7c478bd9Sstevel@tonic-gate static int _gl_trap_signal(GetLine *gl, int signo, unsigned flags, 10126*7c478bd9Sstevel@tonic-gate GlAfterSignal after, int errno_value) 10127*7c478bd9Sstevel@tonic-gate { 10128*7c478bd9Sstevel@tonic-gate GlSignalNode *sig; 10129*7c478bd9Sstevel@tonic-gate /* 10130*7c478bd9Sstevel@tonic-gate * Complain if an attempt is made to trap untrappable signals. 10131*7c478bd9Sstevel@tonic-gate * These would otherwise cause errors later in gl_mask_signals(). 10132*7c478bd9Sstevel@tonic-gate */ 10133*7c478bd9Sstevel@tonic-gate if(0 10134*7c478bd9Sstevel@tonic-gate #ifdef SIGKILL 10135*7c478bd9Sstevel@tonic-gate || signo==SIGKILL 10136*7c478bd9Sstevel@tonic-gate #endif 10137*7c478bd9Sstevel@tonic-gate #ifdef SIGBLOCK 10138*7c478bd9Sstevel@tonic-gate || signo==SIGBLOCK 10139*7c478bd9Sstevel@tonic-gate #endif 10140*7c478bd9Sstevel@tonic-gate ) { 10141*7c478bd9Sstevel@tonic-gate return 1; 10142*7c478bd9Sstevel@tonic-gate }; 10143*7c478bd9Sstevel@tonic-gate /* 10144*7c478bd9Sstevel@tonic-gate * See if the signal has already been registered. 10145*7c478bd9Sstevel@tonic-gate */ 10146*7c478bd9Sstevel@tonic-gate for(sig=gl->sigs; sig && sig->signo != signo; sig = sig->next) 10147*7c478bd9Sstevel@tonic-gate ; 10148*7c478bd9Sstevel@tonic-gate /* 10149*7c478bd9Sstevel@tonic-gate * If the signal hasn't already been registered, allocate a node for 10150*7c478bd9Sstevel@tonic-gate * it. 10151*7c478bd9Sstevel@tonic-gate */ 10152*7c478bd9Sstevel@tonic-gate if(!sig) { 10153*7c478bd9Sstevel@tonic-gate sig = (GlSignalNode *) _new_FreeListNode(gl->sig_mem); 10154*7c478bd9Sstevel@tonic-gate if(!sig) 10155*7c478bd9Sstevel@tonic-gate return 1; 10156*7c478bd9Sstevel@tonic-gate /* 10157*7c478bd9Sstevel@tonic-gate * Add the new node to the head of the list. 10158*7c478bd9Sstevel@tonic-gate */ 10159*7c478bd9Sstevel@tonic-gate sig->next = gl->sigs; 10160*7c478bd9Sstevel@tonic-gate gl->sigs = sig; 10161*7c478bd9Sstevel@tonic-gate /* 10162*7c478bd9Sstevel@tonic-gate * Record the signal number. 10163*7c478bd9Sstevel@tonic-gate */ 10164*7c478bd9Sstevel@tonic-gate sig->signo = signo; 10165*7c478bd9Sstevel@tonic-gate /* 10166*7c478bd9Sstevel@tonic-gate * Create a signal set that includes just this signal. 10167*7c478bd9Sstevel@tonic-gate */ 10168*7c478bd9Sstevel@tonic-gate sigemptyset(&sig->proc_mask); 10169*7c478bd9Sstevel@tonic-gate if(sigaddset(&sig->proc_mask, signo) == -1) { 10170*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "sigaddset error", END_ERR_MSG); 10171*7c478bd9Sstevel@tonic-gate sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig); 10172*7c478bd9Sstevel@tonic-gate return 1; 10173*7c478bd9Sstevel@tonic-gate }; 10174*7c478bd9Sstevel@tonic-gate /* 10175*7c478bd9Sstevel@tonic-gate * Add the signal to the bit-mask of signals being trapped. 10176*7c478bd9Sstevel@tonic-gate */ 10177*7c478bd9Sstevel@tonic-gate sigaddset(&gl->all_signal_set, signo); 10178*7c478bd9Sstevel@tonic-gate }; 10179*7c478bd9Sstevel@tonic-gate /* 10180*7c478bd9Sstevel@tonic-gate * Record the new signal attributes. 10181*7c478bd9Sstevel@tonic-gate */ 10182*7c478bd9Sstevel@tonic-gate sig->flags = flags; 10183*7c478bd9Sstevel@tonic-gate sig->after = after; 10184*7c478bd9Sstevel@tonic-gate sig->errno_value = errno_value; 10185*7c478bd9Sstevel@tonic-gate return 0; 10186*7c478bd9Sstevel@tonic-gate } 10187*7c478bd9Sstevel@tonic-gate 10188*7c478bd9Sstevel@tonic-gate /*....................................................................... 10189*7c478bd9Sstevel@tonic-gate * Remove a signal from the list of signals that gl_get_line() traps. 10190*7c478bd9Sstevel@tonic-gate * 10191*7c478bd9Sstevel@tonic-gate * Input: 10192*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 10193*7c478bd9Sstevel@tonic-gate * signo int The number of the signal to be ignored. 10194*7c478bd9Sstevel@tonic-gate * Output: 10195*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10196*7c478bd9Sstevel@tonic-gate * 1 - Error. 10197*7c478bd9Sstevel@tonic-gate */ 10198*7c478bd9Sstevel@tonic-gate int gl_ignore_signal(GetLine *gl, int signo) 10199*7c478bd9Sstevel@tonic-gate { 10200*7c478bd9Sstevel@tonic-gate GlSignalNode *sig; /* The gl->sigs list node of the specified signal */ 10201*7c478bd9Sstevel@tonic-gate GlSignalNode *prev; /* The node that precedes sig in the list */ 10202*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this */ 10203*7c478bd9Sstevel@tonic-gate /* function. */ 10204*7c478bd9Sstevel@tonic-gate /* 10205*7c478bd9Sstevel@tonic-gate * Check the arguments. 10206*7c478bd9Sstevel@tonic-gate */ 10207*7c478bd9Sstevel@tonic-gate if(!gl) { 10208*7c478bd9Sstevel@tonic-gate errno = EINVAL; 10209*7c478bd9Sstevel@tonic-gate return 1; 10210*7c478bd9Sstevel@tonic-gate }; 10211*7c478bd9Sstevel@tonic-gate /* 10212*7c478bd9Sstevel@tonic-gate * Block all signals while modifying the contents of gl. 10213*7c478bd9Sstevel@tonic-gate */ 10214*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 10215*7c478bd9Sstevel@tonic-gate return 1; 10216*7c478bd9Sstevel@tonic-gate /* 10217*7c478bd9Sstevel@tonic-gate * Find the node of the gl->sigs list which records the disposition 10218*7c478bd9Sstevel@tonic-gate * of the specified signal. 10219*7c478bd9Sstevel@tonic-gate */ 10220*7c478bd9Sstevel@tonic-gate for(prev=NULL,sig=gl->sigs; sig && sig->signo != signo; 10221*7c478bd9Sstevel@tonic-gate prev=sig,sig=sig->next) 10222*7c478bd9Sstevel@tonic-gate ; 10223*7c478bd9Sstevel@tonic-gate if(sig) { 10224*7c478bd9Sstevel@tonic-gate /* 10225*7c478bd9Sstevel@tonic-gate * Remove the node from the list. 10226*7c478bd9Sstevel@tonic-gate */ 10227*7c478bd9Sstevel@tonic-gate if(prev) 10228*7c478bd9Sstevel@tonic-gate prev->next = sig->next; 10229*7c478bd9Sstevel@tonic-gate else 10230*7c478bd9Sstevel@tonic-gate gl->sigs = sig->next; 10231*7c478bd9Sstevel@tonic-gate /* 10232*7c478bd9Sstevel@tonic-gate * Return the node to the freelist. 10233*7c478bd9Sstevel@tonic-gate */ 10234*7c478bd9Sstevel@tonic-gate sig = (GlSignalNode *) _del_FreeListNode(gl->sig_mem, sig); 10235*7c478bd9Sstevel@tonic-gate /* 10236*7c478bd9Sstevel@tonic-gate * Remove the signal from the bit-mask union of signals being trapped. 10237*7c478bd9Sstevel@tonic-gate */ 10238*7c478bd9Sstevel@tonic-gate sigdelset(&gl->all_signal_set, signo); 10239*7c478bd9Sstevel@tonic-gate }; 10240*7c478bd9Sstevel@tonic-gate /* 10241*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 10242*7c478bd9Sstevel@tonic-gate */ 10243*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10244*7c478bd9Sstevel@tonic-gate return 0; 10245*7c478bd9Sstevel@tonic-gate } 10246*7c478bd9Sstevel@tonic-gate 10247*7c478bd9Sstevel@tonic-gate /*....................................................................... 10248*7c478bd9Sstevel@tonic-gate * This function is called when an input line has been completed. It 10249*7c478bd9Sstevel@tonic-gate * appends the specified newline character, terminates the line, 10250*7c478bd9Sstevel@tonic-gate * records the line in the history buffer if appropriate, and positions 10251*7c478bd9Sstevel@tonic-gate * the terminal cursor at the start of the next line. 10252*7c478bd9Sstevel@tonic-gate * 10253*7c478bd9Sstevel@tonic-gate * Input: 10254*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 10255*7c478bd9Sstevel@tonic-gate * newline_char int The newline character to add to the end 10256*7c478bd9Sstevel@tonic-gate * of the line. 10257*7c478bd9Sstevel@tonic-gate * Output: 10258*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10259*7c478bd9Sstevel@tonic-gate * 1 - Error. 10260*7c478bd9Sstevel@tonic-gate */ 10261*7c478bd9Sstevel@tonic-gate static int gl_line_ended(GetLine *gl, int newline_char) 10262*7c478bd9Sstevel@tonic-gate { 10263*7c478bd9Sstevel@tonic-gate /* 10264*7c478bd9Sstevel@tonic-gate * If the newline character is printable, display it at the end of 10265*7c478bd9Sstevel@tonic-gate * the line, and add it to the input line buffer. 10266*7c478bd9Sstevel@tonic-gate */ 10267*7c478bd9Sstevel@tonic-gate if(isprint((int)(unsigned char) newline_char)) { 10268*7c478bd9Sstevel@tonic-gate if(gl_end_of_line(gl, 1, NULL) || gl_add_char_to_line(gl, newline_char)) 10269*7c478bd9Sstevel@tonic-gate return 1; 10270*7c478bd9Sstevel@tonic-gate } else { 10271*7c478bd9Sstevel@tonic-gate /* 10272*7c478bd9Sstevel@tonic-gate * Otherwise just append a newline character to the input line buffer. 10273*7c478bd9Sstevel@tonic-gate */ 10274*7c478bd9Sstevel@tonic-gate newline_char = '\n'; 10275*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, newline_char, gl->ntotal); 10276*7c478bd9Sstevel@tonic-gate }; 10277*7c478bd9Sstevel@tonic-gate /* 10278*7c478bd9Sstevel@tonic-gate * Add the line to the history buffer if it was entered with a 10279*7c478bd9Sstevel@tonic-gate * newline character. 10280*7c478bd9Sstevel@tonic-gate */ 10281*7c478bd9Sstevel@tonic-gate if(gl->echo && gl->automatic_history && newline_char=='\n') 10282*7c478bd9Sstevel@tonic-gate (void) _gl_append_history(gl, gl->line); 10283*7c478bd9Sstevel@tonic-gate /* 10284*7c478bd9Sstevel@tonic-gate * Except when depending on the system-provided line editing, start a new 10285*7c478bd9Sstevel@tonic-gate * line after the end of the line that has just been entered. 10286*7c478bd9Sstevel@tonic-gate */ 10287*7c478bd9Sstevel@tonic-gate if(gl->editor != GL_NO_EDITOR && gl_start_newline(gl, 1)) 10288*7c478bd9Sstevel@tonic-gate return 1; 10289*7c478bd9Sstevel@tonic-gate /* 10290*7c478bd9Sstevel@tonic-gate * Record the successful return status. 10291*7c478bd9Sstevel@tonic-gate */ 10292*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_NEWLINE, 0); 10293*7c478bd9Sstevel@tonic-gate /* 10294*7c478bd9Sstevel@tonic-gate * Attempt to flush any pending output. 10295*7c478bd9Sstevel@tonic-gate */ 10296*7c478bd9Sstevel@tonic-gate (void) gl_flush_output(gl); 10297*7c478bd9Sstevel@tonic-gate /* 10298*7c478bd9Sstevel@tonic-gate * The next call to gl_get_line() will write the prompt for a new line 10299*7c478bd9Sstevel@tonic-gate * (or continue the above flush if incomplete), so if we manage to 10300*7c478bd9Sstevel@tonic-gate * flush the terminal now, report that we are waiting to write to the 10301*7c478bd9Sstevel@tonic-gate * terminal. 10302*7c478bd9Sstevel@tonic-gate */ 10303*7c478bd9Sstevel@tonic-gate gl->pending_io = GLP_WRITE; 10304*7c478bd9Sstevel@tonic-gate return 0; 10305*7c478bd9Sstevel@tonic-gate } 10306*7c478bd9Sstevel@tonic-gate 10307*7c478bd9Sstevel@tonic-gate /*....................................................................... 10308*7c478bd9Sstevel@tonic-gate * Return the last signal that was caught by the most recent call to 10309*7c478bd9Sstevel@tonic-gate * gl_get_line(), or -1 if no signals were caught. This is useful if 10310*7c478bd9Sstevel@tonic-gate * gl_get_line() returns errno=EINTR and you need to find out what signal 10311*7c478bd9Sstevel@tonic-gate * caused it to abort. 10312*7c478bd9Sstevel@tonic-gate * 10313*7c478bd9Sstevel@tonic-gate * Input: 10314*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 10315*7c478bd9Sstevel@tonic-gate * Output: 10316*7c478bd9Sstevel@tonic-gate * return int The last signal caught by the most recent 10317*7c478bd9Sstevel@tonic-gate * call to gl_get_line(), or -1 if no signals 10318*7c478bd9Sstevel@tonic-gate * were caught. 10319*7c478bd9Sstevel@tonic-gate */ 10320*7c478bd9Sstevel@tonic-gate int gl_last_signal(GetLine *gl) 10321*7c478bd9Sstevel@tonic-gate { 10322*7c478bd9Sstevel@tonic-gate int signo = -1; /* The requested signal number */ 10323*7c478bd9Sstevel@tonic-gate if(gl) { 10324*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 10325*7c478bd9Sstevel@tonic-gate /* 10326*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 10327*7c478bd9Sstevel@tonic-gate */ 10328*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 10329*7c478bd9Sstevel@tonic-gate /* 10330*7c478bd9Sstevel@tonic-gate * Access gl now that signals are blocked. 10331*7c478bd9Sstevel@tonic-gate */ 10332*7c478bd9Sstevel@tonic-gate signo = gl->last_signal; 10333*7c478bd9Sstevel@tonic-gate /* 10334*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 10335*7c478bd9Sstevel@tonic-gate */ 10336*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10337*7c478bd9Sstevel@tonic-gate }; 10338*7c478bd9Sstevel@tonic-gate return signo; 10339*7c478bd9Sstevel@tonic-gate } 10340*7c478bd9Sstevel@tonic-gate 10341*7c478bd9Sstevel@tonic-gate /*....................................................................... 10342*7c478bd9Sstevel@tonic-gate * Prepare to edit a new line. 10343*7c478bd9Sstevel@tonic-gate * 10344*7c478bd9Sstevel@tonic-gate * Input: 10345*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this library. 10346*7c478bd9Sstevel@tonic-gate * prompt char * The prompt to prefix the line with, or NULL to 10347*7c478bd9Sstevel@tonic-gate * use the same prompt that was used by the previous 10348*7c478bd9Sstevel@tonic-gate * line. 10349*7c478bd9Sstevel@tonic-gate * start_line char * The initial contents of the input line, or NULL 10350*7c478bd9Sstevel@tonic-gate * if it should start out empty. 10351*7c478bd9Sstevel@tonic-gate * start_pos int If start_line isn't NULL, this specifies the 10352*7c478bd9Sstevel@tonic-gate * index of the character over which the cursor 10353*7c478bd9Sstevel@tonic-gate * should initially be positioned within the line. 10354*7c478bd9Sstevel@tonic-gate * If you just want it to follow the last character 10355*7c478bd9Sstevel@tonic-gate * of the line, send -1. 10356*7c478bd9Sstevel@tonic-gate * Output: 10357*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10358*7c478bd9Sstevel@tonic-gate * 1 - Error. 10359*7c478bd9Sstevel@tonic-gate */ 10360*7c478bd9Sstevel@tonic-gate static int gl_present_line(GetLine *gl, const char *prompt, 10361*7c478bd9Sstevel@tonic-gate const char *start_line, int start_pos) 10362*7c478bd9Sstevel@tonic-gate { 10363*7c478bd9Sstevel@tonic-gate /* 10364*7c478bd9Sstevel@tonic-gate * Reset the properties of the line. 10365*7c478bd9Sstevel@tonic-gate */ 10366*7c478bd9Sstevel@tonic-gate gl_reset_input_line(gl); 10367*7c478bd9Sstevel@tonic-gate /* 10368*7c478bd9Sstevel@tonic-gate * Record the new prompt and its displayed width. 10369*7c478bd9Sstevel@tonic-gate */ 10370*7c478bd9Sstevel@tonic-gate if(prompt) 10371*7c478bd9Sstevel@tonic-gate _gl_replace_prompt(gl, prompt); 10372*7c478bd9Sstevel@tonic-gate /* 10373*7c478bd9Sstevel@tonic-gate * Reset the history search pointers. 10374*7c478bd9Sstevel@tonic-gate */ 10375*7c478bd9Sstevel@tonic-gate if(_glh_cancel_search(gl->glh)) { 10376*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 10377*7c478bd9Sstevel@tonic-gate return 1; 10378*7c478bd9Sstevel@tonic-gate }; 10379*7c478bd9Sstevel@tonic-gate /* 10380*7c478bd9Sstevel@tonic-gate * If the previous line was entered via the repeat-history action, 10381*7c478bd9Sstevel@tonic-gate * preload the specified history line. 10382*7c478bd9Sstevel@tonic-gate */ 10383*7c478bd9Sstevel@tonic-gate if(gl->preload_history) { 10384*7c478bd9Sstevel@tonic-gate gl->preload_history = 0; 10385*7c478bd9Sstevel@tonic-gate if(gl->preload_id) { 10386*7c478bd9Sstevel@tonic-gate if(_glh_recall_line(gl->glh, gl->preload_id, gl->line, gl->linelen+1)) { 10387*7c478bd9Sstevel@tonic-gate gl_update_buffer(gl); /* Compute gl->ntotal etc.. */ 10388*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->ntotal; 10389*7c478bd9Sstevel@tonic-gate } else { 10390*7c478bd9Sstevel@tonic-gate gl_truncate_buffer(gl, 0); 10391*7c478bd9Sstevel@tonic-gate }; 10392*7c478bd9Sstevel@tonic-gate gl->preload_id = 0; 10393*7c478bd9Sstevel@tonic-gate }; 10394*7c478bd9Sstevel@tonic-gate /* 10395*7c478bd9Sstevel@tonic-gate * Present a specified initial line? 10396*7c478bd9Sstevel@tonic-gate */ 10397*7c478bd9Sstevel@tonic-gate } else if(start_line) { 10398*7c478bd9Sstevel@tonic-gate char *cptr; /* A pointer into gl->line[] */ 10399*7c478bd9Sstevel@tonic-gate /* 10400*7c478bd9Sstevel@tonic-gate * Measure the length of the starting line. 10401*7c478bd9Sstevel@tonic-gate */ 10402*7c478bd9Sstevel@tonic-gate int start_len = strlen(start_line); 10403*7c478bd9Sstevel@tonic-gate /* 10404*7c478bd9Sstevel@tonic-gate * If the length of the line is greater than the available space, 10405*7c478bd9Sstevel@tonic-gate * truncate it. 10406*7c478bd9Sstevel@tonic-gate */ 10407*7c478bd9Sstevel@tonic-gate if(start_len > gl->linelen) 10408*7c478bd9Sstevel@tonic-gate start_len = gl->linelen; 10409*7c478bd9Sstevel@tonic-gate /* 10410*7c478bd9Sstevel@tonic-gate * Load the line into the buffer. 10411*7c478bd9Sstevel@tonic-gate */ 10412*7c478bd9Sstevel@tonic-gate if(start_line != gl->line) 10413*7c478bd9Sstevel@tonic-gate gl_buffer_string(gl, start_line, start_len, 0); 10414*7c478bd9Sstevel@tonic-gate /* 10415*7c478bd9Sstevel@tonic-gate * Strip off any trailing newline and carriage return characters. 10416*7c478bd9Sstevel@tonic-gate */ 10417*7c478bd9Sstevel@tonic-gate for(cptr=gl->line + gl->ntotal - 1; cptr >= gl->line && 10418*7c478bd9Sstevel@tonic-gate (*cptr=='\n' || *cptr=='\r'); cptr--,gl->ntotal--) 10419*7c478bd9Sstevel@tonic-gate ; 10420*7c478bd9Sstevel@tonic-gate gl_truncate_buffer(gl, gl->ntotal < 0 ? 0 : gl->ntotal); 10421*7c478bd9Sstevel@tonic-gate /* 10422*7c478bd9Sstevel@tonic-gate * Where should the cursor be placed within the line? 10423*7c478bd9Sstevel@tonic-gate */ 10424*7c478bd9Sstevel@tonic-gate if(start_pos < 0 || start_pos > gl->ntotal) { 10425*7c478bd9Sstevel@tonic-gate if(gl_place_cursor(gl, gl->ntotal)) 10426*7c478bd9Sstevel@tonic-gate return 1; 10427*7c478bd9Sstevel@tonic-gate } else { 10428*7c478bd9Sstevel@tonic-gate if(gl_place_cursor(gl, start_pos)) 10429*7c478bd9Sstevel@tonic-gate return 1; 10430*7c478bd9Sstevel@tonic-gate }; 10431*7c478bd9Sstevel@tonic-gate /* 10432*7c478bd9Sstevel@tonic-gate * Clear the input line? 10433*7c478bd9Sstevel@tonic-gate */ 10434*7c478bd9Sstevel@tonic-gate } else { 10435*7c478bd9Sstevel@tonic-gate gl_truncate_buffer(gl, 0); 10436*7c478bd9Sstevel@tonic-gate }; 10437*7c478bd9Sstevel@tonic-gate /* 10438*7c478bd9Sstevel@tonic-gate * Arrange for the line to be displayed by gl_flush_output(). 10439*7c478bd9Sstevel@tonic-gate */ 10440*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 10441*7c478bd9Sstevel@tonic-gate /* 10442*7c478bd9Sstevel@tonic-gate * Update the display. 10443*7c478bd9Sstevel@tonic-gate */ 10444*7c478bd9Sstevel@tonic-gate return gl_flush_output(gl); 10445*7c478bd9Sstevel@tonic-gate } 10446*7c478bd9Sstevel@tonic-gate 10447*7c478bd9Sstevel@tonic-gate /*....................................................................... 10448*7c478bd9Sstevel@tonic-gate * Reset all line input parameters for a new input line. 10449*7c478bd9Sstevel@tonic-gate * 10450*7c478bd9Sstevel@tonic-gate * Input: 10451*7c478bd9Sstevel@tonic-gate * gl GetLine * The line editor resource object. 10452*7c478bd9Sstevel@tonic-gate */ 10453*7c478bd9Sstevel@tonic-gate static void gl_reset_input_line(GetLine *gl) 10454*7c478bd9Sstevel@tonic-gate { 10455*7c478bd9Sstevel@tonic-gate gl->ntotal = 0; 10456*7c478bd9Sstevel@tonic-gate gl->line[0] = '\0'; 10457*7c478bd9Sstevel@tonic-gate gl->buff_curpos = 0; 10458*7c478bd9Sstevel@tonic-gate gl->term_curpos = 0; 10459*7c478bd9Sstevel@tonic-gate gl->term_len = 0; 10460*7c478bd9Sstevel@tonic-gate gl->insert_curpos = 0; 10461*7c478bd9Sstevel@tonic-gate gl->number = -1; 10462*7c478bd9Sstevel@tonic-gate gl->displayed = 0; 10463*7c478bd9Sstevel@tonic-gate gl->endline = 0; 10464*7c478bd9Sstevel@tonic-gate gl->redisplay = 0; 10465*7c478bd9Sstevel@tonic-gate gl->postpone = 0; 10466*7c478bd9Sstevel@tonic-gate gl->nbuf = 0; 10467*7c478bd9Sstevel@tonic-gate gl->nread = 0; 10468*7c478bd9Sstevel@tonic-gate gl->vi.command = 0; 10469*7c478bd9Sstevel@tonic-gate gl->vi.undo.line[0] = '\0'; 10470*7c478bd9Sstevel@tonic-gate gl->vi.undo.ntotal = 0; 10471*7c478bd9Sstevel@tonic-gate gl->vi.undo.buff_curpos = 0; 10472*7c478bd9Sstevel@tonic-gate gl->vi.repeat.action.fn = 0; 10473*7c478bd9Sstevel@tonic-gate gl->vi.repeat.action.data = 0; 10474*7c478bd9Sstevel@tonic-gate gl->last_signal = -1; 10475*7c478bd9Sstevel@tonic-gate } 10476*7c478bd9Sstevel@tonic-gate 10477*7c478bd9Sstevel@tonic-gate /*....................................................................... 10478*7c478bd9Sstevel@tonic-gate * Print an informational message to the terminal, after starting a new 10479*7c478bd9Sstevel@tonic-gate * line. 10480*7c478bd9Sstevel@tonic-gate * 10481*7c478bd9Sstevel@tonic-gate * Input: 10482*7c478bd9Sstevel@tonic-gate * gl GetLine * The line editor resource object. 10483*7c478bd9Sstevel@tonic-gate * ... const char * Zero or more strings to be printed. 10484*7c478bd9Sstevel@tonic-gate * ... void * The last argument must always be GL_END_INFO. 10485*7c478bd9Sstevel@tonic-gate * Output: 10486*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10487*7c478bd9Sstevel@tonic-gate * 1 - Error. 10488*7c478bd9Sstevel@tonic-gate */ 10489*7c478bd9Sstevel@tonic-gate static int gl_print_info(GetLine *gl, ...) 10490*7c478bd9Sstevel@tonic-gate { 10491*7c478bd9Sstevel@tonic-gate va_list ap; /* The variable argument list */ 10492*7c478bd9Sstevel@tonic-gate const char *s; /* The string being printed */ 10493*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True after an error */ 10494*7c478bd9Sstevel@tonic-gate /* 10495*7c478bd9Sstevel@tonic-gate * Only display output when echoing is on. 10496*7c478bd9Sstevel@tonic-gate */ 10497*7c478bd9Sstevel@tonic-gate if(gl->echo) { 10498*7c478bd9Sstevel@tonic-gate /* 10499*7c478bd9Sstevel@tonic-gate * Skip to the start of the next empty line before displaying the message. 10500*7c478bd9Sstevel@tonic-gate */ 10501*7c478bd9Sstevel@tonic-gate if(gl_start_newline(gl, 1)) 10502*7c478bd9Sstevel@tonic-gate return 1; 10503*7c478bd9Sstevel@tonic-gate /* 10504*7c478bd9Sstevel@tonic-gate * Display the list of provided messages. 10505*7c478bd9Sstevel@tonic-gate */ 10506*7c478bd9Sstevel@tonic-gate va_start(ap, gl); 10507*7c478bd9Sstevel@tonic-gate while(!waserr && (s = va_arg(ap, const char *)) != GL_END_INFO) 10508*7c478bd9Sstevel@tonic-gate waserr = gl_print_raw_string(gl, 1, s, -1); 10509*7c478bd9Sstevel@tonic-gate va_end(ap); 10510*7c478bd9Sstevel@tonic-gate /* 10511*7c478bd9Sstevel@tonic-gate * Start a newline. 10512*7c478bd9Sstevel@tonic-gate */ 10513*7c478bd9Sstevel@tonic-gate waserr = waserr || gl_print_raw_string(gl, 1, "\n\r", -1); 10514*7c478bd9Sstevel@tonic-gate /* 10515*7c478bd9Sstevel@tonic-gate * Arrange for the input line to be redrawn. 10516*7c478bd9Sstevel@tonic-gate */ 10517*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 10518*7c478bd9Sstevel@tonic-gate }; 10519*7c478bd9Sstevel@tonic-gate return waserr; 10520*7c478bd9Sstevel@tonic-gate } 10521*7c478bd9Sstevel@tonic-gate 10522*7c478bd9Sstevel@tonic-gate /*....................................................................... 10523*7c478bd9Sstevel@tonic-gate * Go to the start of the next empty line, ready to output miscellaneous 10524*7c478bd9Sstevel@tonic-gate * text to the screen. 10525*7c478bd9Sstevel@tonic-gate * 10526*7c478bd9Sstevel@tonic-gate * Note that when async-signal safety is required, the 'buffered' 10527*7c478bd9Sstevel@tonic-gate * argument must be 0. 10528*7c478bd9Sstevel@tonic-gate * 10529*7c478bd9Sstevel@tonic-gate * Input: 10530*7c478bd9Sstevel@tonic-gate * gl GetLine * The line editor resource object. 10531*7c478bd9Sstevel@tonic-gate * buffered int If true, used buffered I/O when writing to 10532*7c478bd9Sstevel@tonic-gate * the terminal. Otherwise use async-signal-safe 10533*7c478bd9Sstevel@tonic-gate * unbuffered I/O. 10534*7c478bd9Sstevel@tonic-gate * Output: 10535*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10536*7c478bd9Sstevel@tonic-gate * 1 - Error. 10537*7c478bd9Sstevel@tonic-gate */ 10538*7c478bd9Sstevel@tonic-gate static int gl_start_newline(GetLine *gl, int buffered) 10539*7c478bd9Sstevel@tonic-gate { 10540*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True after any I/O error */ 10541*7c478bd9Sstevel@tonic-gate /* 10542*7c478bd9Sstevel@tonic-gate * Move the cursor to the start of the terminal line that follows the 10543*7c478bd9Sstevel@tonic-gate * last line of the partially enterred line. In order that this 10544*7c478bd9Sstevel@tonic-gate * function remain async-signal safe when write_fn is signal safe, we 10545*7c478bd9Sstevel@tonic-gate * can't call our normal output functions, since they call tputs(), 10546*7c478bd9Sstevel@tonic-gate * who's signal saftey isn't defined. Fortunately, we can simply use 10547*7c478bd9Sstevel@tonic-gate * \r and \n to move the cursor to the right place. 10548*7c478bd9Sstevel@tonic-gate */ 10549*7c478bd9Sstevel@tonic-gate if(gl->displayed) { /* Is an input line currently displayed? */ 10550*7c478bd9Sstevel@tonic-gate /* 10551*7c478bd9Sstevel@tonic-gate * On which terminal lines are the cursor and the last character of the 10552*7c478bd9Sstevel@tonic-gate * input line? 10553*7c478bd9Sstevel@tonic-gate */ 10554*7c478bd9Sstevel@tonic-gate int curs_line = gl->term_curpos / gl->ncolumn; 10555*7c478bd9Sstevel@tonic-gate int last_line = gl->term_len / gl->ncolumn; 10556*7c478bd9Sstevel@tonic-gate /* 10557*7c478bd9Sstevel@tonic-gate * Move the cursor to the start of the line that follows the last 10558*7c478bd9Sstevel@tonic-gate * terminal line that is occupied by the input line. 10559*7c478bd9Sstevel@tonic-gate */ 10560*7c478bd9Sstevel@tonic-gate for( ; curs_line < last_line + 1; curs_line++) 10561*7c478bd9Sstevel@tonic-gate waserr = waserr || gl_print_raw_string(gl, buffered, "\n", 1); 10562*7c478bd9Sstevel@tonic-gate waserr = waserr || gl_print_raw_string(gl, buffered, "\r", 1); 10563*7c478bd9Sstevel@tonic-gate /* 10564*7c478bd9Sstevel@tonic-gate * Mark the line as no longer displayed. 10565*7c478bd9Sstevel@tonic-gate */ 10566*7c478bd9Sstevel@tonic-gate gl_line_erased(gl); 10567*7c478bd9Sstevel@tonic-gate }; 10568*7c478bd9Sstevel@tonic-gate return waserr; 10569*7c478bd9Sstevel@tonic-gate } 10570*7c478bd9Sstevel@tonic-gate 10571*7c478bd9Sstevel@tonic-gate /*....................................................................... 10572*7c478bd9Sstevel@tonic-gate * The callback through which all terminal output is routed. 10573*7c478bd9Sstevel@tonic-gate * This simply appends characters to a queue buffer, which is 10574*7c478bd9Sstevel@tonic-gate * subsequently flushed to the output channel by gl_flush_output(). 10575*7c478bd9Sstevel@tonic-gate * 10576*7c478bd9Sstevel@tonic-gate * Input: 10577*7c478bd9Sstevel@tonic-gate * data void * The pointer to a GetLine line editor resource object 10578*7c478bd9Sstevel@tonic-gate * cast to (void *). 10579*7c478bd9Sstevel@tonic-gate * s const char * The string to be written. 10580*7c478bd9Sstevel@tonic-gate * n int The number of characters to write from s[]. 10581*7c478bd9Sstevel@tonic-gate * Output: 10582*7c478bd9Sstevel@tonic-gate * return int The number of characters written. This will always 10583*7c478bd9Sstevel@tonic-gate * be equal to 'n' unless an error occurs. 10584*7c478bd9Sstevel@tonic-gate */ 10585*7c478bd9Sstevel@tonic-gate static GL_WRITE_FN(gl_write_fn) 10586*7c478bd9Sstevel@tonic-gate { 10587*7c478bd9Sstevel@tonic-gate GetLine *gl = (GetLine *) data; 10588*7c478bd9Sstevel@tonic-gate int ndone = _glq_append_chars(gl->cq, s, n, gl->flush_fn, gl); 10589*7c478bd9Sstevel@tonic-gate if(ndone != n) 10590*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glq_last_error(gl->cq), END_ERR_MSG); 10591*7c478bd9Sstevel@tonic-gate return ndone; 10592*7c478bd9Sstevel@tonic-gate } 10593*7c478bd9Sstevel@tonic-gate 10594*7c478bd9Sstevel@tonic-gate /*....................................................................... 10595*7c478bd9Sstevel@tonic-gate * Ask gl_get_line() what caused it to return. 10596*7c478bd9Sstevel@tonic-gate * 10597*7c478bd9Sstevel@tonic-gate * Input: 10598*7c478bd9Sstevel@tonic-gate * gl GetLine * The line editor resource object. 10599*7c478bd9Sstevel@tonic-gate * Output: 10600*7c478bd9Sstevel@tonic-gate * return GlReturnStatus The return status of the last call to 10601*7c478bd9Sstevel@tonic-gate * gl_get_line(). 10602*7c478bd9Sstevel@tonic-gate */ 10603*7c478bd9Sstevel@tonic-gate GlReturnStatus gl_return_status(GetLine *gl) 10604*7c478bd9Sstevel@tonic-gate { 10605*7c478bd9Sstevel@tonic-gate GlReturnStatus rtn_status = GLR_ERROR; /* The requested status */ 10606*7c478bd9Sstevel@tonic-gate if(gl) { 10607*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 10608*7c478bd9Sstevel@tonic-gate /* 10609*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 10610*7c478bd9Sstevel@tonic-gate */ 10611*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 10612*7c478bd9Sstevel@tonic-gate /* 10613*7c478bd9Sstevel@tonic-gate * Access gl while signals are blocked. 10614*7c478bd9Sstevel@tonic-gate */ 10615*7c478bd9Sstevel@tonic-gate rtn_status = gl->rtn_status; 10616*7c478bd9Sstevel@tonic-gate /* 10617*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 10618*7c478bd9Sstevel@tonic-gate */ 10619*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10620*7c478bd9Sstevel@tonic-gate }; 10621*7c478bd9Sstevel@tonic-gate return rtn_status; 10622*7c478bd9Sstevel@tonic-gate } 10623*7c478bd9Sstevel@tonic-gate 10624*7c478bd9Sstevel@tonic-gate /*....................................................................... 10625*7c478bd9Sstevel@tonic-gate * In non-blocking server-I/O mode, this function should be called 10626*7c478bd9Sstevel@tonic-gate * from the application's external event loop to see what type of 10627*7c478bd9Sstevel@tonic-gate * terminal I/O is being waited for by gl_get_line(), and thus what 10628*7c478bd9Sstevel@tonic-gate * direction of I/O to wait for with select() or poll(). 10629*7c478bd9Sstevel@tonic-gate * 10630*7c478bd9Sstevel@tonic-gate * Input: 10631*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 10632*7c478bd9Sstevel@tonic-gate * Output: 10633*7c478bd9Sstevel@tonic-gate * return GlPendingIO The type of pending I/O being waited for. 10634*7c478bd9Sstevel@tonic-gate */ 10635*7c478bd9Sstevel@tonic-gate GlPendingIO gl_pending_io(GetLine *gl) 10636*7c478bd9Sstevel@tonic-gate { 10637*7c478bd9Sstevel@tonic-gate GlPendingIO pending_io = GLP_WRITE; /* The requested information */ 10638*7c478bd9Sstevel@tonic-gate if(gl) { 10639*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 10640*7c478bd9Sstevel@tonic-gate /* 10641*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 10642*7c478bd9Sstevel@tonic-gate */ 10643*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 10644*7c478bd9Sstevel@tonic-gate /* 10645*7c478bd9Sstevel@tonic-gate * Access gl while signals are blocked. 10646*7c478bd9Sstevel@tonic-gate */ 10647*7c478bd9Sstevel@tonic-gate pending_io = gl->pending_io; 10648*7c478bd9Sstevel@tonic-gate /* 10649*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 10650*7c478bd9Sstevel@tonic-gate */ 10651*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10652*7c478bd9Sstevel@tonic-gate }; 10653*7c478bd9Sstevel@tonic-gate return pending_io; 10654*7c478bd9Sstevel@tonic-gate } 10655*7c478bd9Sstevel@tonic-gate 10656*7c478bd9Sstevel@tonic-gate /*....................................................................... 10657*7c478bd9Sstevel@tonic-gate * In server mode, this function configures the terminal for non-blocking 10658*7c478bd9Sstevel@tonic-gate * raw terminal I/O. In normal I/O mode it does nothing. 10659*7c478bd9Sstevel@tonic-gate * 10660*7c478bd9Sstevel@tonic-gate * Callers of this function must be careful to trap all signals that 10661*7c478bd9Sstevel@tonic-gate * terminate or suspend the program, and call gl_normal_io() 10662*7c478bd9Sstevel@tonic-gate * from the corresponding signal handlers in order to restore the 10663*7c478bd9Sstevel@tonic-gate * terminal to its original settings before the program is terminated 10664*7c478bd9Sstevel@tonic-gate * or suspended. They should also trap the SIGCONT signal to detect 10665*7c478bd9Sstevel@tonic-gate * when the program resumes, and ensure that its signal handler 10666*7c478bd9Sstevel@tonic-gate * call gl_raw_io() to redisplay the line and resume editing. 10667*7c478bd9Sstevel@tonic-gate * 10668*7c478bd9Sstevel@tonic-gate * This function is async signal safe. 10669*7c478bd9Sstevel@tonic-gate * 10670*7c478bd9Sstevel@tonic-gate * Input: 10671*7c478bd9Sstevel@tonic-gate * gl GetLine * The line editor resource object. 10672*7c478bd9Sstevel@tonic-gate * Output: 10673*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10674*7c478bd9Sstevel@tonic-gate * 1 - Error. 10675*7c478bd9Sstevel@tonic-gate */ 10676*7c478bd9Sstevel@tonic-gate int gl_raw_io(GetLine *gl) 10677*7c478bd9Sstevel@tonic-gate { 10678*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 10679*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_raw_io() */ 10680*7c478bd9Sstevel@tonic-gate /* 10681*7c478bd9Sstevel@tonic-gate * Check the arguments. 10682*7c478bd9Sstevel@tonic-gate */ 10683*7c478bd9Sstevel@tonic-gate if(!gl) { 10684*7c478bd9Sstevel@tonic-gate errno = EINVAL; 10685*7c478bd9Sstevel@tonic-gate return 1; 10686*7c478bd9Sstevel@tonic-gate }; 10687*7c478bd9Sstevel@tonic-gate /* 10688*7c478bd9Sstevel@tonic-gate * Block all signals. 10689*7c478bd9Sstevel@tonic-gate */ 10690*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 10691*7c478bd9Sstevel@tonic-gate return 1; 10692*7c478bd9Sstevel@tonic-gate /* 10693*7c478bd9Sstevel@tonic-gate * Don't allow applications to switch into raw mode unless in server mode. 10694*7c478bd9Sstevel@tonic-gate */ 10695*7c478bd9Sstevel@tonic-gate if(gl->io_mode != GL_SERVER_MODE) { 10696*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Can't switch to raw I/O unless in server mode", 10697*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 10698*7c478bd9Sstevel@tonic-gate errno = EPERM; 10699*7c478bd9Sstevel@tonic-gate status = 1; 10700*7c478bd9Sstevel@tonic-gate } else { 10701*7c478bd9Sstevel@tonic-gate /* 10702*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 10703*7c478bd9Sstevel@tonic-gate */ 10704*7c478bd9Sstevel@tonic-gate status = _gl_raw_io(gl, 1); 10705*7c478bd9Sstevel@tonic-gate }; 10706*7c478bd9Sstevel@tonic-gate /* 10707*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 10708*7c478bd9Sstevel@tonic-gate */ 10709*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10710*7c478bd9Sstevel@tonic-gate return status; 10711*7c478bd9Sstevel@tonic-gate } 10712*7c478bd9Sstevel@tonic-gate 10713*7c478bd9Sstevel@tonic-gate /*....................................................................... 10714*7c478bd9Sstevel@tonic-gate * This is the private body of the public function, gl_raw_io(). 10715*7c478bd9Sstevel@tonic-gate * It assumes that the caller has checked its arguments and blocked the 10716*7c478bd9Sstevel@tonic-gate * delivery of signals. 10717*7c478bd9Sstevel@tonic-gate * 10718*7c478bd9Sstevel@tonic-gate * This function is async signal safe. 10719*7c478bd9Sstevel@tonic-gate */ 10720*7c478bd9Sstevel@tonic-gate static int _gl_raw_io(GetLine *gl, int redisplay) 10721*7c478bd9Sstevel@tonic-gate { 10722*7c478bd9Sstevel@tonic-gate /* 10723*7c478bd9Sstevel@tonic-gate * If we are already in the correct mode, do nothing. 10724*7c478bd9Sstevel@tonic-gate */ 10725*7c478bd9Sstevel@tonic-gate if(gl->raw_mode) 10726*7c478bd9Sstevel@tonic-gate return 0; 10727*7c478bd9Sstevel@tonic-gate /* 10728*7c478bd9Sstevel@tonic-gate * Switch the terminal to raw mode. 10729*7c478bd9Sstevel@tonic-gate */ 10730*7c478bd9Sstevel@tonic-gate if(gl->is_term && gl_raw_terminal_mode(gl)) 10731*7c478bd9Sstevel@tonic-gate return 1; 10732*7c478bd9Sstevel@tonic-gate /* 10733*7c478bd9Sstevel@tonic-gate * Switch to non-blocking I/O mode? 10734*7c478bd9Sstevel@tonic-gate */ 10735*7c478bd9Sstevel@tonic-gate if(gl->io_mode==GL_SERVER_MODE && 10736*7c478bd9Sstevel@tonic-gate (gl_nonblocking_io(gl, gl->input_fd) || 10737*7c478bd9Sstevel@tonic-gate gl_nonblocking_io(gl, gl->output_fd) || 10738*7c478bd9Sstevel@tonic-gate (gl->file_fp && gl_nonblocking_io(gl, fileno(gl->file_fp))))) { 10739*7c478bd9Sstevel@tonic-gate if(gl->is_term) 10740*7c478bd9Sstevel@tonic-gate gl_restore_terminal_attributes(gl); 10741*7c478bd9Sstevel@tonic-gate return 1; 10742*7c478bd9Sstevel@tonic-gate }; 10743*7c478bd9Sstevel@tonic-gate /* 10744*7c478bd9Sstevel@tonic-gate * If an input line is being entered, arrange for it to be 10745*7c478bd9Sstevel@tonic-gate * displayed. 10746*7c478bd9Sstevel@tonic-gate */ 10747*7c478bd9Sstevel@tonic-gate if(redisplay) { 10748*7c478bd9Sstevel@tonic-gate gl->postpone = 0; 10749*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 10750*7c478bd9Sstevel@tonic-gate }; 10751*7c478bd9Sstevel@tonic-gate return 0; 10752*7c478bd9Sstevel@tonic-gate } 10753*7c478bd9Sstevel@tonic-gate 10754*7c478bd9Sstevel@tonic-gate /*....................................................................... 10755*7c478bd9Sstevel@tonic-gate * Restore the terminal to the state that it had when 10756*7c478bd9Sstevel@tonic-gate * gl_raw_io() was last called. After calling 10757*7c478bd9Sstevel@tonic-gate * gl_raw_io(), this function must be called before 10758*7c478bd9Sstevel@tonic-gate * terminating or suspending the program, and before attempting other 10759*7c478bd9Sstevel@tonic-gate * uses of the terminal from within the program. See gl_raw_io() 10760*7c478bd9Sstevel@tonic-gate * for more details. 10761*7c478bd9Sstevel@tonic-gate * 10762*7c478bd9Sstevel@tonic-gate * Input: 10763*7c478bd9Sstevel@tonic-gate * gl GetLine * The line editor resource object. 10764*7c478bd9Sstevel@tonic-gate * Output: 10765*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10766*7c478bd9Sstevel@tonic-gate * 1 - Error. 10767*7c478bd9Sstevel@tonic-gate */ 10768*7c478bd9Sstevel@tonic-gate int gl_normal_io(GetLine *gl) 10769*7c478bd9Sstevel@tonic-gate { 10770*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 10771*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_normal_io() */ 10772*7c478bd9Sstevel@tonic-gate /* 10773*7c478bd9Sstevel@tonic-gate * Check the arguments. 10774*7c478bd9Sstevel@tonic-gate */ 10775*7c478bd9Sstevel@tonic-gate if(!gl) { 10776*7c478bd9Sstevel@tonic-gate errno = EINVAL; 10777*7c478bd9Sstevel@tonic-gate return 1; 10778*7c478bd9Sstevel@tonic-gate }; 10779*7c478bd9Sstevel@tonic-gate /* 10780*7c478bd9Sstevel@tonic-gate * Block all signals. 10781*7c478bd9Sstevel@tonic-gate */ 10782*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 10783*7c478bd9Sstevel@tonic-gate return 1; 10784*7c478bd9Sstevel@tonic-gate /* 10785*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 10786*7c478bd9Sstevel@tonic-gate */ 10787*7c478bd9Sstevel@tonic-gate status = _gl_normal_io(gl); 10788*7c478bd9Sstevel@tonic-gate /* 10789*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 10790*7c478bd9Sstevel@tonic-gate */ 10791*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10792*7c478bd9Sstevel@tonic-gate return status; 10793*7c478bd9Sstevel@tonic-gate } 10794*7c478bd9Sstevel@tonic-gate 10795*7c478bd9Sstevel@tonic-gate /*....................................................................... 10796*7c478bd9Sstevel@tonic-gate * This is the private body of the public function, gl_normal_io(). 10797*7c478bd9Sstevel@tonic-gate * It assumes that the caller has checked its arguments and blocked the 10798*7c478bd9Sstevel@tonic-gate * delivery of signals. 10799*7c478bd9Sstevel@tonic-gate */ 10800*7c478bd9Sstevel@tonic-gate static int _gl_normal_io(GetLine *gl) 10801*7c478bd9Sstevel@tonic-gate { 10802*7c478bd9Sstevel@tonic-gate /* 10803*7c478bd9Sstevel@tonic-gate * If we are already in normal mode, do nothing. 10804*7c478bd9Sstevel@tonic-gate */ 10805*7c478bd9Sstevel@tonic-gate if(!gl->raw_mode) 10806*7c478bd9Sstevel@tonic-gate return 0; 10807*7c478bd9Sstevel@tonic-gate /* 10808*7c478bd9Sstevel@tonic-gate * Postpone subsequent redisplays until after _gl_raw_io(gl, 1) 10809*7c478bd9Sstevel@tonic-gate * is next called. 10810*7c478bd9Sstevel@tonic-gate */ 10811*7c478bd9Sstevel@tonic-gate gl->postpone = 1; 10812*7c478bd9Sstevel@tonic-gate /* 10813*7c478bd9Sstevel@tonic-gate * Switch back to blocking I/O. Note that this is essential to do 10814*7c478bd9Sstevel@tonic-gate * here, because when using non-blocking I/O, the terminal output 10815*7c478bd9Sstevel@tonic-gate * buffering code can't always make room for new output without calling 10816*7c478bd9Sstevel@tonic-gate * malloc(), and a call to malloc() would mean that this function 10817*7c478bd9Sstevel@tonic-gate * couldn't safely be called from signal handlers. 10818*7c478bd9Sstevel@tonic-gate */ 10819*7c478bd9Sstevel@tonic-gate if(gl->io_mode==GL_SERVER_MODE && 10820*7c478bd9Sstevel@tonic-gate (gl_blocking_io(gl, gl->input_fd) || 10821*7c478bd9Sstevel@tonic-gate gl_blocking_io(gl, gl->output_fd) || 10822*7c478bd9Sstevel@tonic-gate (gl->file_fp && gl_blocking_io(gl, fileno(gl->file_fp))))) 10823*7c478bd9Sstevel@tonic-gate return 1; 10824*7c478bd9Sstevel@tonic-gate /* 10825*7c478bd9Sstevel@tonic-gate * Move the cursor to the next empty terminal line. Note that 10826*7c478bd9Sstevel@tonic-gate * unbuffered I/O is requested, to ensure that gl_start_newline() be 10827*7c478bd9Sstevel@tonic-gate * async-signal-safe. 10828*7c478bd9Sstevel@tonic-gate */ 10829*7c478bd9Sstevel@tonic-gate if(gl->is_term && gl_start_newline(gl, 0)) 10830*7c478bd9Sstevel@tonic-gate return 1; 10831*7c478bd9Sstevel@tonic-gate /* 10832*7c478bd9Sstevel@tonic-gate * Switch the terminal to normal mode. 10833*7c478bd9Sstevel@tonic-gate */ 10834*7c478bd9Sstevel@tonic-gate if(gl->is_term && gl_restore_terminal_attributes(gl)) { 10835*7c478bd9Sstevel@tonic-gate /* 10836*7c478bd9Sstevel@tonic-gate * On error, revert to non-blocking I/O if needed, so that on failure 10837*7c478bd9Sstevel@tonic-gate * we remain in raw mode. 10838*7c478bd9Sstevel@tonic-gate */ 10839*7c478bd9Sstevel@tonic-gate if(gl->io_mode==GL_SERVER_MODE) { 10840*7c478bd9Sstevel@tonic-gate gl_nonblocking_io(gl, gl->input_fd); 10841*7c478bd9Sstevel@tonic-gate gl_nonblocking_io(gl, gl->output_fd); 10842*7c478bd9Sstevel@tonic-gate if(gl->file_fp) 10843*7c478bd9Sstevel@tonic-gate gl_nonblocking_io(gl, fileno(gl->file_fp)); 10844*7c478bd9Sstevel@tonic-gate }; 10845*7c478bd9Sstevel@tonic-gate return 1; 10846*7c478bd9Sstevel@tonic-gate }; 10847*7c478bd9Sstevel@tonic-gate return 0; 10848*7c478bd9Sstevel@tonic-gate } 10849*7c478bd9Sstevel@tonic-gate 10850*7c478bd9Sstevel@tonic-gate /*....................................................................... 10851*7c478bd9Sstevel@tonic-gate * This function allows you to install an additional completion 10852*7c478bd9Sstevel@tonic-gate * action, or to change the completion function of an existing 10853*7c478bd9Sstevel@tonic-gate * one. This should be called before the first call to gl_get_line() 10854*7c478bd9Sstevel@tonic-gate * so that the name of the action be defined before the user's 10855*7c478bd9Sstevel@tonic-gate * configuration file is read. 10856*7c478bd9Sstevel@tonic-gate * 10857*7c478bd9Sstevel@tonic-gate * Input: 10858*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of the command-line input 10859*7c478bd9Sstevel@tonic-gate * module. 10860*7c478bd9Sstevel@tonic-gate * data void * This is passed to match_fn() whenever it is 10861*7c478bd9Sstevel@tonic-gate * called. It could, for example, point to a 10862*7c478bd9Sstevel@tonic-gate * symbol table that match_fn() would look up 10863*7c478bd9Sstevel@tonic-gate * matches in. 10864*7c478bd9Sstevel@tonic-gate * match_fn CplMatchFn * The function that will identify the prefix 10865*7c478bd9Sstevel@tonic-gate * to be completed from the input line, and 10866*7c478bd9Sstevel@tonic-gate * report matching symbols. 10867*7c478bd9Sstevel@tonic-gate * list_only int If non-zero, install an action that only lists 10868*7c478bd9Sstevel@tonic-gate * possible completions, rather than attempting 10869*7c478bd9Sstevel@tonic-gate * to perform the completion. 10870*7c478bd9Sstevel@tonic-gate * name const char * The name with which users can refer to the 10871*7c478bd9Sstevel@tonic-gate * binding in tecla configuration files. 10872*7c478bd9Sstevel@tonic-gate * keyseq const char * Either NULL, or a key sequence with which 10873*7c478bd9Sstevel@tonic-gate * to invoke the binding. This should be 10874*7c478bd9Sstevel@tonic-gate * specified in the same manner as key-sequences 10875*7c478bd9Sstevel@tonic-gate * in tecla configuration files (eg. "M-^I"). 10876*7c478bd9Sstevel@tonic-gate * Output: 10877*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 10878*7c478bd9Sstevel@tonic-gate * 1 - Error. 10879*7c478bd9Sstevel@tonic-gate */ 10880*7c478bd9Sstevel@tonic-gate int gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn, 10881*7c478bd9Sstevel@tonic-gate int list_only, const char *name, const char *keyseq) 10882*7c478bd9Sstevel@tonic-gate { 10883*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 10884*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_completion_action() */ 10885*7c478bd9Sstevel@tonic-gate /* 10886*7c478bd9Sstevel@tonic-gate * Check the arguments. 10887*7c478bd9Sstevel@tonic-gate */ 10888*7c478bd9Sstevel@tonic-gate if(!gl || !name || !match_fn) { 10889*7c478bd9Sstevel@tonic-gate errno = EINVAL; 10890*7c478bd9Sstevel@tonic-gate return 1; 10891*7c478bd9Sstevel@tonic-gate }; 10892*7c478bd9Sstevel@tonic-gate /* 10893*7c478bd9Sstevel@tonic-gate * Block all signals. 10894*7c478bd9Sstevel@tonic-gate */ 10895*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 10896*7c478bd9Sstevel@tonic-gate return 1; 10897*7c478bd9Sstevel@tonic-gate /* 10898*7c478bd9Sstevel@tonic-gate * Install the new action while signals are blocked. 10899*7c478bd9Sstevel@tonic-gate */ 10900*7c478bd9Sstevel@tonic-gate status = _gl_completion_action(gl, data, match_fn, list_only, name, keyseq); 10901*7c478bd9Sstevel@tonic-gate /* 10902*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 10903*7c478bd9Sstevel@tonic-gate */ 10904*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 10905*7c478bd9Sstevel@tonic-gate return status; 10906*7c478bd9Sstevel@tonic-gate } 10907*7c478bd9Sstevel@tonic-gate 10908*7c478bd9Sstevel@tonic-gate /*....................................................................... 10909*7c478bd9Sstevel@tonic-gate * This is the private body of the public function, gl_completion_action(). 10910*7c478bd9Sstevel@tonic-gate * It assumes that the caller has checked its arguments and blocked the 10911*7c478bd9Sstevel@tonic-gate * delivery of signals. 10912*7c478bd9Sstevel@tonic-gate */ 10913*7c478bd9Sstevel@tonic-gate static int _gl_completion_action(GetLine *gl, void *data, CplMatchFn *match_fn, 10914*7c478bd9Sstevel@tonic-gate int list_only, const char *name, 10915*7c478bd9Sstevel@tonic-gate const char *keyseq) 10916*7c478bd9Sstevel@tonic-gate { 10917*7c478bd9Sstevel@tonic-gate KtKeyFn *current_fn; /* An existing action function */ 10918*7c478bd9Sstevel@tonic-gate void *current_data; /* The action-function callback data */ 10919*7c478bd9Sstevel@tonic-gate /* 10920*7c478bd9Sstevel@tonic-gate * Which action function is desired? 10921*7c478bd9Sstevel@tonic-gate */ 10922*7c478bd9Sstevel@tonic-gate KtKeyFn *action_fn = list_only ? gl_list_completions : gl_complete_word; 10923*7c478bd9Sstevel@tonic-gate /* 10924*7c478bd9Sstevel@tonic-gate * Is there already an action of the specified name? 10925*7c478bd9Sstevel@tonic-gate */ 10926*7c478bd9Sstevel@tonic-gate if(_kt_lookup_action(gl->bindings, name, ¤t_fn, ¤t_data) == 0) { 10927*7c478bd9Sstevel@tonic-gate /* 10928*7c478bd9Sstevel@tonic-gate * If the action has the same type as the one being requested, 10929*7c478bd9Sstevel@tonic-gate * simply change the contents of its GlCplCallback callback data. 10930*7c478bd9Sstevel@tonic-gate */ 10931*7c478bd9Sstevel@tonic-gate if(current_fn == action_fn) { 10932*7c478bd9Sstevel@tonic-gate GlCplCallback *cb = (GlCplCallback *) current_data; 10933*7c478bd9Sstevel@tonic-gate cb->fn = match_fn; 10934*7c478bd9Sstevel@tonic-gate cb->data = data; 10935*7c478bd9Sstevel@tonic-gate } else { 10936*7c478bd9Sstevel@tonic-gate errno = EINVAL; 10937*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, 10938*7c478bd9Sstevel@tonic-gate "Illegal attempt to change the type of an existing completion action", 10939*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 10940*7c478bd9Sstevel@tonic-gate return 1; 10941*7c478bd9Sstevel@tonic-gate }; 10942*7c478bd9Sstevel@tonic-gate /* 10943*7c478bd9Sstevel@tonic-gate * No existing action has the specified name. 10944*7c478bd9Sstevel@tonic-gate */ 10945*7c478bd9Sstevel@tonic-gate } else { 10946*7c478bd9Sstevel@tonic-gate /* 10947*7c478bd9Sstevel@tonic-gate * Allocate a new GlCplCallback callback object. 10948*7c478bd9Sstevel@tonic-gate */ 10949*7c478bd9Sstevel@tonic-gate GlCplCallback *cb = (GlCplCallback *) _new_FreeListNode(gl->cpl_mem); 10950*7c478bd9Sstevel@tonic-gate if(!cb) { 10951*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 10952*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Insufficient memory to add completion action", 10953*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 10954*7c478bd9Sstevel@tonic-gate return 1; 10955*7c478bd9Sstevel@tonic-gate }; 10956*7c478bd9Sstevel@tonic-gate /* 10957*7c478bd9Sstevel@tonic-gate * Record the completion callback data. 10958*7c478bd9Sstevel@tonic-gate */ 10959*7c478bd9Sstevel@tonic-gate cb->fn = match_fn; 10960*7c478bd9Sstevel@tonic-gate cb->data = data; 10961*7c478bd9Sstevel@tonic-gate /* 10962*7c478bd9Sstevel@tonic-gate * Attempt to register the new action. 10963*7c478bd9Sstevel@tonic-gate */ 10964*7c478bd9Sstevel@tonic-gate if(_kt_set_action(gl->bindings, name, action_fn, cb)) { 10965*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG); 10966*7c478bd9Sstevel@tonic-gate _del_FreeListNode(gl->cpl_mem, (void *) cb); 10967*7c478bd9Sstevel@tonic-gate return 1; 10968*7c478bd9Sstevel@tonic-gate }; 10969*7c478bd9Sstevel@tonic-gate }; 10970*7c478bd9Sstevel@tonic-gate /* 10971*7c478bd9Sstevel@tonic-gate * Bind the action to a given key-sequence? 10972*7c478bd9Sstevel@tonic-gate */ 10973*7c478bd9Sstevel@tonic-gate if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) { 10974*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG); 10975*7c478bd9Sstevel@tonic-gate return 1; 10976*7c478bd9Sstevel@tonic-gate }; 10977*7c478bd9Sstevel@tonic-gate return 0; 10978*7c478bd9Sstevel@tonic-gate } 10979*7c478bd9Sstevel@tonic-gate 10980*7c478bd9Sstevel@tonic-gate /*....................................................................... 10981*7c478bd9Sstevel@tonic-gate * Register an application-provided function as an action function. 10982*7c478bd9Sstevel@tonic-gate * This should preferably be called before the first call to gl_get_line() 10983*7c478bd9Sstevel@tonic-gate * so that the name of the action becomes defined before the user's 10984*7c478bd9Sstevel@tonic-gate * configuration file is read. 10985*7c478bd9Sstevel@tonic-gate * 10986*7c478bd9Sstevel@tonic-gate * Input: 10987*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of the command-line input 10988*7c478bd9Sstevel@tonic-gate * module. 10989*7c478bd9Sstevel@tonic-gate * data void * Arbitrary application-specific callback 10990*7c478bd9Sstevel@tonic-gate * data to be passed to the callback 10991*7c478bd9Sstevel@tonic-gate * function, fn(). 10992*7c478bd9Sstevel@tonic-gate * fn GlActionFn * The application-specific function that 10993*7c478bd9Sstevel@tonic-gate * implements the action. This will be invoked 10994*7c478bd9Sstevel@tonic-gate * whenever the user presses any 10995*7c478bd9Sstevel@tonic-gate * key-sequence which is bound to this action. 10996*7c478bd9Sstevel@tonic-gate * name const char * The name with which users can refer to the 10997*7c478bd9Sstevel@tonic-gate * binding in tecla configuration files. 10998*7c478bd9Sstevel@tonic-gate * keyseq const char * The key sequence with which to invoke 10999*7c478bd9Sstevel@tonic-gate * the binding. This should be specified in the 11000*7c478bd9Sstevel@tonic-gate * same manner as key-sequences in tecla 11001*7c478bd9Sstevel@tonic-gate * configuration files (eg. "M-^I"). 11002*7c478bd9Sstevel@tonic-gate * Output: 11003*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11004*7c478bd9Sstevel@tonic-gate * 1 - Error. 11005*7c478bd9Sstevel@tonic-gate */ 11006*7c478bd9Sstevel@tonic-gate int gl_register_action(GetLine *gl, void *data, GlActionFn *fn, 11007*7c478bd9Sstevel@tonic-gate const char *name, const char *keyseq) 11008*7c478bd9Sstevel@tonic-gate { 11009*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 11010*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_register_action() */ 11011*7c478bd9Sstevel@tonic-gate /* 11012*7c478bd9Sstevel@tonic-gate * Check the arguments. 11013*7c478bd9Sstevel@tonic-gate */ 11014*7c478bd9Sstevel@tonic-gate if(!gl || !name || !fn) { 11015*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11016*7c478bd9Sstevel@tonic-gate return 1; 11017*7c478bd9Sstevel@tonic-gate }; 11018*7c478bd9Sstevel@tonic-gate /* 11019*7c478bd9Sstevel@tonic-gate * Block all signals. 11020*7c478bd9Sstevel@tonic-gate */ 11021*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 11022*7c478bd9Sstevel@tonic-gate return 1; 11023*7c478bd9Sstevel@tonic-gate /* 11024*7c478bd9Sstevel@tonic-gate * Install the new action while signals are blocked. 11025*7c478bd9Sstevel@tonic-gate */ 11026*7c478bd9Sstevel@tonic-gate status = _gl_register_action(gl, data, fn, name, keyseq); 11027*7c478bd9Sstevel@tonic-gate /* 11028*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 11029*7c478bd9Sstevel@tonic-gate */ 11030*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 11031*7c478bd9Sstevel@tonic-gate return status; 11032*7c478bd9Sstevel@tonic-gate } 11033*7c478bd9Sstevel@tonic-gate 11034*7c478bd9Sstevel@tonic-gate /*....................................................................... 11035*7c478bd9Sstevel@tonic-gate * This is the private body of the public function, gl_register_action(). 11036*7c478bd9Sstevel@tonic-gate * It assumes that the caller has checked its arguments and blocked the 11037*7c478bd9Sstevel@tonic-gate * delivery of signals. 11038*7c478bd9Sstevel@tonic-gate */ 11039*7c478bd9Sstevel@tonic-gate static int _gl_register_action(GetLine *gl, void *data, GlActionFn *fn, 11040*7c478bd9Sstevel@tonic-gate const char *name, const char *keyseq) 11041*7c478bd9Sstevel@tonic-gate { 11042*7c478bd9Sstevel@tonic-gate KtKeyFn *current_fn; /* An existing action function */ 11043*7c478bd9Sstevel@tonic-gate void *current_data; /* The action-function callback data */ 11044*7c478bd9Sstevel@tonic-gate /* 11045*7c478bd9Sstevel@tonic-gate * Get the action function which actually runs the application-provided 11046*7c478bd9Sstevel@tonic-gate * function. 11047*7c478bd9Sstevel@tonic-gate */ 11048*7c478bd9Sstevel@tonic-gate KtKeyFn *action_fn = gl_run_external_action; 11049*7c478bd9Sstevel@tonic-gate /* 11050*7c478bd9Sstevel@tonic-gate * Is there already an action of the specified name? 11051*7c478bd9Sstevel@tonic-gate */ 11052*7c478bd9Sstevel@tonic-gate if(_kt_lookup_action(gl->bindings, name, ¤t_fn, ¤t_data) == 0) { 11053*7c478bd9Sstevel@tonic-gate /* 11054*7c478bd9Sstevel@tonic-gate * If the action has the same type as the one being requested, 11055*7c478bd9Sstevel@tonic-gate * simply change the contents of its GlCplCallback callback data. 11056*7c478bd9Sstevel@tonic-gate */ 11057*7c478bd9Sstevel@tonic-gate if(current_fn == action_fn) { 11058*7c478bd9Sstevel@tonic-gate GlExternalAction *a = (GlExternalAction *) current_data; 11059*7c478bd9Sstevel@tonic-gate a->fn = fn; 11060*7c478bd9Sstevel@tonic-gate a->data = data; 11061*7c478bd9Sstevel@tonic-gate } else { 11062*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11063*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, 11064*7c478bd9Sstevel@tonic-gate "Illegal attempt to change the type of an existing action", 11065*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 11066*7c478bd9Sstevel@tonic-gate return 1; 11067*7c478bd9Sstevel@tonic-gate }; 11068*7c478bd9Sstevel@tonic-gate /* 11069*7c478bd9Sstevel@tonic-gate * No existing action has the specified name. 11070*7c478bd9Sstevel@tonic-gate */ 11071*7c478bd9Sstevel@tonic-gate } else { 11072*7c478bd9Sstevel@tonic-gate /* 11073*7c478bd9Sstevel@tonic-gate * Allocate a new GlCplCallback callback object. 11074*7c478bd9Sstevel@tonic-gate */ 11075*7c478bd9Sstevel@tonic-gate GlExternalAction *a = 11076*7c478bd9Sstevel@tonic-gate (GlExternalAction *) _new_FreeListNode(gl->ext_act_mem); 11077*7c478bd9Sstevel@tonic-gate if(!a) { 11078*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 11079*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Insufficient memory to add completion action", 11080*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 11081*7c478bd9Sstevel@tonic-gate return 1; 11082*7c478bd9Sstevel@tonic-gate }; 11083*7c478bd9Sstevel@tonic-gate /* 11084*7c478bd9Sstevel@tonic-gate * Record the completion callback data. 11085*7c478bd9Sstevel@tonic-gate */ 11086*7c478bd9Sstevel@tonic-gate a->fn = fn; 11087*7c478bd9Sstevel@tonic-gate a->data = data; 11088*7c478bd9Sstevel@tonic-gate /* 11089*7c478bd9Sstevel@tonic-gate * Attempt to register the new action. 11090*7c478bd9Sstevel@tonic-gate */ 11091*7c478bd9Sstevel@tonic-gate if(_kt_set_action(gl->bindings, name, action_fn, a)) { 11092*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG); 11093*7c478bd9Sstevel@tonic-gate _del_FreeListNode(gl->cpl_mem, (void *) a); 11094*7c478bd9Sstevel@tonic-gate return 1; 11095*7c478bd9Sstevel@tonic-gate }; 11096*7c478bd9Sstevel@tonic-gate }; 11097*7c478bd9Sstevel@tonic-gate /* 11098*7c478bd9Sstevel@tonic-gate * Bind the action to a given key-sequence? 11099*7c478bd9Sstevel@tonic-gate */ 11100*7c478bd9Sstevel@tonic-gate if(keyseq && _kt_set_keybinding(gl->bindings, KTB_NORM, keyseq, name)) { 11101*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG); 11102*7c478bd9Sstevel@tonic-gate return 1; 11103*7c478bd9Sstevel@tonic-gate }; 11104*7c478bd9Sstevel@tonic-gate return 0; 11105*7c478bd9Sstevel@tonic-gate } 11106*7c478bd9Sstevel@tonic-gate 11107*7c478bd9Sstevel@tonic-gate /*....................................................................... 11108*7c478bd9Sstevel@tonic-gate * Invoke an action function previously registered by a call to 11109*7c478bd9Sstevel@tonic-gate * gl_register_action(). 11110*7c478bd9Sstevel@tonic-gate */ 11111*7c478bd9Sstevel@tonic-gate static KT_KEY_FN(gl_run_external_action) 11112*7c478bd9Sstevel@tonic-gate { 11113*7c478bd9Sstevel@tonic-gate GlAfterAction status; /* The return value of the action function */ 11114*7c478bd9Sstevel@tonic-gate /* 11115*7c478bd9Sstevel@tonic-gate * Get the container of the action function and associated callback data. 11116*7c478bd9Sstevel@tonic-gate */ 11117*7c478bd9Sstevel@tonic-gate GlExternalAction *a = (GlExternalAction *) data; 11118*7c478bd9Sstevel@tonic-gate /* 11119*7c478bd9Sstevel@tonic-gate * Invoke the action function. 11120*7c478bd9Sstevel@tonic-gate */ 11121*7c478bd9Sstevel@tonic-gate status = a->fn(gl, a->data, count, gl->buff_curpos, gl->line); 11122*7c478bd9Sstevel@tonic-gate /* 11123*7c478bd9Sstevel@tonic-gate * If the callback took us out of raw (possibly non-blocking) input 11124*7c478bd9Sstevel@tonic-gate * mode, restore this mode, and queue a redisplay of the input line. 11125*7c478bd9Sstevel@tonic-gate */ 11126*7c478bd9Sstevel@tonic-gate if(_gl_raw_io(gl, 1)) 11127*7c478bd9Sstevel@tonic-gate return 1; 11128*7c478bd9Sstevel@tonic-gate /* 11129*7c478bd9Sstevel@tonic-gate * Finally, check to see what the action function wants us to do next. 11130*7c478bd9Sstevel@tonic-gate */ 11131*7c478bd9Sstevel@tonic-gate switch(status) { 11132*7c478bd9Sstevel@tonic-gate default: 11133*7c478bd9Sstevel@tonic-gate case GLA_ABORT: 11134*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_ERROR, errno); 11135*7c478bd9Sstevel@tonic-gate return 1; 11136*7c478bd9Sstevel@tonic-gate break; 11137*7c478bd9Sstevel@tonic-gate case GLA_RETURN: 11138*7c478bd9Sstevel@tonic-gate return gl_newline(gl, 1, NULL); 11139*7c478bd9Sstevel@tonic-gate break; 11140*7c478bd9Sstevel@tonic-gate case GLA_CONTINUE: 11141*7c478bd9Sstevel@tonic-gate break; 11142*7c478bd9Sstevel@tonic-gate }; 11143*7c478bd9Sstevel@tonic-gate return 0; 11144*7c478bd9Sstevel@tonic-gate } 11145*7c478bd9Sstevel@tonic-gate 11146*7c478bd9Sstevel@tonic-gate /*....................................................................... 11147*7c478bd9Sstevel@tonic-gate * In server-I/O mode the terminal is left in raw mode between calls 11148*7c478bd9Sstevel@tonic-gate * to gl_get_line(), so it is necessary for the application to install 11149*7c478bd9Sstevel@tonic-gate * terminal restoring signal handlers for signals that could terminate 11150*7c478bd9Sstevel@tonic-gate * or suspend the process, plus a terminal reconfiguration handler to 11151*7c478bd9Sstevel@tonic-gate * be called when a process resumption signal is received, and finally 11152*7c478bd9Sstevel@tonic-gate * a handler to be called when a terminal-resize signal is received. 11153*7c478bd9Sstevel@tonic-gate * 11154*7c478bd9Sstevel@tonic-gate * Since there are many signals that by default terminate or suspend 11155*7c478bd9Sstevel@tonic-gate * processes, and different systems support different sub-sets of 11156*7c478bd9Sstevel@tonic-gate * these signals, this function provides a convenient wrapper around 11157*7c478bd9Sstevel@tonic-gate * sigaction() for assigning the specified handlers to all appropriate 11158*7c478bd9Sstevel@tonic-gate * signals. It also arranges that when any one of these signals is 11159*7c478bd9Sstevel@tonic-gate * being handled, all other catchable signals are blocked. This is 11160*7c478bd9Sstevel@tonic-gate * necessary so that the specified signal handlers can safely call 11161*7c478bd9Sstevel@tonic-gate * gl_raw_io(), gl_normal_io() and gl_update_size() without 11162*7c478bd9Sstevel@tonic-gate * reentrancy issues. 11163*7c478bd9Sstevel@tonic-gate * 11164*7c478bd9Sstevel@tonic-gate * Input: 11165*7c478bd9Sstevel@tonic-gate * term_handler void (*)(int) The signal handler to invoke when 11166*7c478bd9Sstevel@tonic-gate * a process terminating signal is 11167*7c478bd9Sstevel@tonic-gate * received. 11168*7c478bd9Sstevel@tonic-gate * susp_handler void (*)(int) The signal handler to invoke when 11169*7c478bd9Sstevel@tonic-gate * a process suspending signal is 11170*7c478bd9Sstevel@tonic-gate * received. 11171*7c478bd9Sstevel@tonic-gate * cont_handler void (*)(int) The signal handler to invoke when 11172*7c478bd9Sstevel@tonic-gate * a process resumption signal is 11173*7c478bd9Sstevel@tonic-gate * received (ie. SIGCONT). 11174*7c478bd9Sstevel@tonic-gate * size_handler void (*)(int) The signal handler to invoke when 11175*7c478bd9Sstevel@tonic-gate * a terminal-resize signal (ie. SIGWINCH) 11176*7c478bd9Sstevel@tonic-gate * is received. 11177*7c478bd9Sstevel@tonic-gate * Output: 11178*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11179*7c478bd9Sstevel@tonic-gate * 1 - Error. 11180*7c478bd9Sstevel@tonic-gate */ 11181*7c478bd9Sstevel@tonic-gate int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int), 11182*7c478bd9Sstevel@tonic-gate void (*cont_handler)(int), void (*size_handler)(int)) 11183*7c478bd9Sstevel@tonic-gate { 11184*7c478bd9Sstevel@tonic-gate int i; 11185*7c478bd9Sstevel@tonic-gate /* 11186*7c478bd9Sstevel@tonic-gate * Search for signals of the specified classes, and assign the 11187*7c478bd9Sstevel@tonic-gate * associated signal handler to them. 11188*7c478bd9Sstevel@tonic-gate */ 11189*7c478bd9Sstevel@tonic-gate for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) { 11190*7c478bd9Sstevel@tonic-gate const struct GlDefSignal *sig = gl_signal_list + i; 11191*7c478bd9Sstevel@tonic-gate if(sig->attr & GLSA_SUSP) { 11192*7c478bd9Sstevel@tonic-gate if(gl_set_tty_signal(sig->signo, term_handler)) 11193*7c478bd9Sstevel@tonic-gate return 1; 11194*7c478bd9Sstevel@tonic-gate } else if(sig->attr & GLSA_TERM) { 11195*7c478bd9Sstevel@tonic-gate if(gl_set_tty_signal(sig->signo, susp_handler)) 11196*7c478bd9Sstevel@tonic-gate return 1; 11197*7c478bd9Sstevel@tonic-gate } else if(sig->attr & GLSA_CONT) { 11198*7c478bd9Sstevel@tonic-gate if(gl_set_tty_signal(sig->signo, cont_handler)) 11199*7c478bd9Sstevel@tonic-gate return 1; 11200*7c478bd9Sstevel@tonic-gate } else if(sig->attr & GLSA_SIZE) { 11201*7c478bd9Sstevel@tonic-gate if(gl_set_tty_signal(sig->signo, size_handler)) 11202*7c478bd9Sstevel@tonic-gate return 1; 11203*7c478bd9Sstevel@tonic-gate }; 11204*7c478bd9Sstevel@tonic-gate }; 11205*7c478bd9Sstevel@tonic-gate return 0; 11206*7c478bd9Sstevel@tonic-gate } 11207*7c478bd9Sstevel@tonic-gate 11208*7c478bd9Sstevel@tonic-gate /*....................................................................... 11209*7c478bd9Sstevel@tonic-gate * This is a private function of gl_tty_signals(). It installs a given 11210*7c478bd9Sstevel@tonic-gate * signal handler, and arranges that when that signal handler is being 11211*7c478bd9Sstevel@tonic-gate * invoked other signals are blocked. The latter is important to allow 11212*7c478bd9Sstevel@tonic-gate * functions like gl_normal_io(), gl_raw_io() and gl_update_size() 11213*7c478bd9Sstevel@tonic-gate * to be called from signal handlers. 11214*7c478bd9Sstevel@tonic-gate * 11215*7c478bd9Sstevel@tonic-gate * Input: 11216*7c478bd9Sstevel@tonic-gate * signo int The signal to be trapped. 11217*7c478bd9Sstevel@tonic-gate * handler void (*)(int) The signal handler to assign to the signal. 11218*7c478bd9Sstevel@tonic-gate */ 11219*7c478bd9Sstevel@tonic-gate static int gl_set_tty_signal(int signo, void (*handler)(int)) 11220*7c478bd9Sstevel@tonic-gate { 11221*7c478bd9Sstevel@tonic-gate SigAction act; /* The signal handler configuation */ 11222*7c478bd9Sstevel@tonic-gate /* 11223*7c478bd9Sstevel@tonic-gate * Arrange to block all trappable signals except the one that is being 11224*7c478bd9Sstevel@tonic-gate * assigned (the trapped signal will be blocked automatically by the 11225*7c478bd9Sstevel@tonic-gate * system). 11226*7c478bd9Sstevel@tonic-gate */ 11227*7c478bd9Sstevel@tonic-gate gl_list_trappable_signals(&act.sa_mask); 11228*7c478bd9Sstevel@tonic-gate sigdelset(&act.sa_mask, signo); 11229*7c478bd9Sstevel@tonic-gate /* 11230*7c478bd9Sstevel@tonic-gate * Assign the signal handler. 11231*7c478bd9Sstevel@tonic-gate */ 11232*7c478bd9Sstevel@tonic-gate act.sa_handler = handler; 11233*7c478bd9Sstevel@tonic-gate /* 11234*7c478bd9Sstevel@tonic-gate * There is only one portable signal handling flag, and it isn't 11235*7c478bd9Sstevel@tonic-gate * relevant to us, so don't specify any flags. 11236*7c478bd9Sstevel@tonic-gate */ 11237*7c478bd9Sstevel@tonic-gate act.sa_flags = 0; 11238*7c478bd9Sstevel@tonic-gate /* 11239*7c478bd9Sstevel@tonic-gate * Register the signal handler. 11240*7c478bd9Sstevel@tonic-gate */ 11241*7c478bd9Sstevel@tonic-gate if(sigaction(signo, &act, NULL)) 11242*7c478bd9Sstevel@tonic-gate return 1; 11243*7c478bd9Sstevel@tonic-gate return 0; 11244*7c478bd9Sstevel@tonic-gate } 11245*7c478bd9Sstevel@tonic-gate 11246*7c478bd9Sstevel@tonic-gate /*....................................................................... 11247*7c478bd9Sstevel@tonic-gate * Display a left-justified string over multiple terminal lines, 11248*7c478bd9Sstevel@tonic-gate * taking account of the current width of the terminal. Optional 11249*7c478bd9Sstevel@tonic-gate * indentation and an optional prefix string can be specified to be 11250*7c478bd9Sstevel@tonic-gate * displayed at the start of each new terminal line used. Similarly, 11251*7c478bd9Sstevel@tonic-gate * an optional suffix can be specified to be displayed at the end of 11252*7c478bd9Sstevel@tonic-gate * each terminal line. If needed, a single paragraph can be broken 11253*7c478bd9Sstevel@tonic-gate * across multiple calls. Note that literal newlines in the input 11254*7c478bd9Sstevel@tonic-gate * string can be used to force a newline at any point and that you 11255*7c478bd9Sstevel@tonic-gate * should use this feature to explicitly end all paragraphs, including 11256*7c478bd9Sstevel@tonic-gate * at the end of the last string that you write. Note that when a new 11257*7c478bd9Sstevel@tonic-gate * line is started between two words that are separated by spaces, 11258*7c478bd9Sstevel@tonic-gate * those spaces are not output, whereas when a new line is started 11259*7c478bd9Sstevel@tonic-gate * because a newline character was found in the string, only the 11260*7c478bd9Sstevel@tonic-gate * spaces before the newline character are discarded. 11261*7c478bd9Sstevel@tonic-gate * 11262*7c478bd9Sstevel@tonic-gate * Input: 11263*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11264*7c478bd9Sstevel@tonic-gate * indentation int The number of spaces of indentation to write 11265*7c478bd9Sstevel@tonic-gate * at the beginning of each new terminal line. 11266*7c478bd9Sstevel@tonic-gate * prefix const char * An optional prefix string to write after the 11267*7c478bd9Sstevel@tonic-gate * indentation margin at the start of each new 11268*7c478bd9Sstevel@tonic-gate * terminal line. You can specify NULL if no 11269*7c478bd9Sstevel@tonic-gate * prefix is required. 11270*7c478bd9Sstevel@tonic-gate * suffix const char * An optional suffix string to draw at the end 11271*7c478bd9Sstevel@tonic-gate * of the terminal line. Spaces will be added 11272*7c478bd9Sstevel@tonic-gate * where necessary to ensure that the suffix ends 11273*7c478bd9Sstevel@tonic-gate * in the last column of the terminal line. If 11274*7c478bd9Sstevel@tonic-gate * no suffix is desired, specify NULL. 11275*7c478bd9Sstevel@tonic-gate * fill_char int The padding character to use when indenting 11276*7c478bd9Sstevel@tonic-gate * the line or padding up to the suffix. 11277*7c478bd9Sstevel@tonic-gate * def_width int If the terminal width isn't known, such as when 11278*7c478bd9Sstevel@tonic-gate * writing to a pipe or redirecting to a file, 11279*7c478bd9Sstevel@tonic-gate * this number specifies what width to assume. 11280*7c478bd9Sstevel@tonic-gate * start int The number of characters already written to 11281*7c478bd9Sstevel@tonic-gate * the start of the current terminal line. This 11282*7c478bd9Sstevel@tonic-gate * is primarily used to allow individual 11283*7c478bd9Sstevel@tonic-gate * paragraphs to be written over multiple calls 11284*7c478bd9Sstevel@tonic-gate * to this function, but can also be used to 11285*7c478bd9Sstevel@tonic-gate * allow you to start the first line of a 11286*7c478bd9Sstevel@tonic-gate * paragraph with a different prefix or 11287*7c478bd9Sstevel@tonic-gate * indentation than those specified above. 11288*7c478bd9Sstevel@tonic-gate * string const char * The string to be written. 11289*7c478bd9Sstevel@tonic-gate * Output: 11290*7c478bd9Sstevel@tonic-gate * return int On error -1 is returned. Otherwise the 11291*7c478bd9Sstevel@tonic-gate * return value is the terminal column index at 11292*7c478bd9Sstevel@tonic-gate * which the cursor was left after writing the 11293*7c478bd9Sstevel@tonic-gate * final word in the string. Successful return 11294*7c478bd9Sstevel@tonic-gate * values can thus be passed verbatim to the 11295*7c478bd9Sstevel@tonic-gate * 'start' arguments of subsequent calls to 11296*7c478bd9Sstevel@tonic-gate * gl_display_text() to allow the printing of a 11297*7c478bd9Sstevel@tonic-gate * paragraph to be broken across multiple calls 11298*7c478bd9Sstevel@tonic-gate * to gl_display_text(). 11299*7c478bd9Sstevel@tonic-gate */ 11300*7c478bd9Sstevel@tonic-gate int gl_display_text(GetLine *gl, int indentation, const char *prefix, 11301*7c478bd9Sstevel@tonic-gate const char *suffix, int fill_char, 11302*7c478bd9Sstevel@tonic-gate int def_width, int start, const char *string) 11303*7c478bd9Sstevel@tonic-gate { 11304*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 11305*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_completion_action() */ 11306*7c478bd9Sstevel@tonic-gate /* 11307*7c478bd9Sstevel@tonic-gate * Check the arguments? 11308*7c478bd9Sstevel@tonic-gate */ 11309*7c478bd9Sstevel@tonic-gate if(!gl || !string) { 11310*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11311*7c478bd9Sstevel@tonic-gate return -1; 11312*7c478bd9Sstevel@tonic-gate }; 11313*7c478bd9Sstevel@tonic-gate /* 11314*7c478bd9Sstevel@tonic-gate * Block all signals. 11315*7c478bd9Sstevel@tonic-gate */ 11316*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 11317*7c478bd9Sstevel@tonic-gate return -1; 11318*7c478bd9Sstevel@tonic-gate /* 11319*7c478bd9Sstevel@tonic-gate * Display the text while signals are blocked. 11320*7c478bd9Sstevel@tonic-gate */ 11321*7c478bd9Sstevel@tonic-gate status = _io_display_text(_io_write_stdio, gl->output_fp, indentation, 11322*7c478bd9Sstevel@tonic-gate prefix, suffix, fill_char, 11323*7c478bd9Sstevel@tonic-gate gl->ncolumn > 0 ? gl->ncolumn : def_width, 11324*7c478bd9Sstevel@tonic-gate start, string); 11325*7c478bd9Sstevel@tonic-gate /* 11326*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 11327*7c478bd9Sstevel@tonic-gate */ 11328*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 11329*7c478bd9Sstevel@tonic-gate return status; 11330*7c478bd9Sstevel@tonic-gate } 11331*7c478bd9Sstevel@tonic-gate 11332*7c478bd9Sstevel@tonic-gate /*....................................................................... 11333*7c478bd9Sstevel@tonic-gate * Block all of the signals that we are currently trapping. 11334*7c478bd9Sstevel@tonic-gate * 11335*7c478bd9Sstevel@tonic-gate * Input: 11336*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11337*7c478bd9Sstevel@tonic-gate * Input/Output: 11338*7c478bd9Sstevel@tonic-gate * oldset sigset_t * The superseded process signal mask 11339*7c478bd9Sstevel@tonic-gate * will be return in *oldset unless oldset is 11340*7c478bd9Sstevel@tonic-gate * NULL. 11341*7c478bd9Sstevel@tonic-gate * Output: 11342*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11343*7c478bd9Sstevel@tonic-gate * 1 - Error. 11344*7c478bd9Sstevel@tonic-gate */ 11345*7c478bd9Sstevel@tonic-gate static int gl_mask_signals(GetLine *gl, sigset_t *oldset) 11346*7c478bd9Sstevel@tonic-gate { 11347*7c478bd9Sstevel@tonic-gate /* 11348*7c478bd9Sstevel@tonic-gate * Block all signals in all_signal_set, along with any others that are 11349*7c478bd9Sstevel@tonic-gate * already blocked by the application. 11350*7c478bd9Sstevel@tonic-gate */ 11351*7c478bd9Sstevel@tonic-gate if(sigprocmask(SIG_BLOCK, &gl->all_signal_set, oldset) >= 0) { 11352*7c478bd9Sstevel@tonic-gate gl->signals_masked = 1; 11353*7c478bd9Sstevel@tonic-gate return 0; 11354*7c478bd9Sstevel@tonic-gate }; 11355*7c478bd9Sstevel@tonic-gate /* 11356*7c478bd9Sstevel@tonic-gate * On error attempt to query the current process signal mask, so 11357*7c478bd9Sstevel@tonic-gate * that oldset be the correct process signal mask to restore later 11358*7c478bd9Sstevel@tonic-gate * if the caller of this function ignores the error return value. 11359*7c478bd9Sstevel@tonic-gate */ 11360*7c478bd9Sstevel@tonic-gate if(oldset) 11361*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, NULL, oldset); 11362*7c478bd9Sstevel@tonic-gate gl->signals_masked = 0; 11363*7c478bd9Sstevel@tonic-gate return 1; 11364*7c478bd9Sstevel@tonic-gate } 11365*7c478bd9Sstevel@tonic-gate 11366*7c478bd9Sstevel@tonic-gate /*....................................................................... 11367*7c478bd9Sstevel@tonic-gate * Restore a process signal mask that was previously returned via the 11368*7c478bd9Sstevel@tonic-gate * oldset argument of gl_mask_signals(). 11369*7c478bd9Sstevel@tonic-gate * 11370*7c478bd9Sstevel@tonic-gate * Input: 11371*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11372*7c478bd9Sstevel@tonic-gate * Input/Output: 11373*7c478bd9Sstevel@tonic-gate * oldset sigset_t * The process signal mask to be restored. 11374*7c478bd9Sstevel@tonic-gate * Output: 11375*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11376*7c478bd9Sstevel@tonic-gate * 1 - Error. 11377*7c478bd9Sstevel@tonic-gate */ 11378*7c478bd9Sstevel@tonic-gate static int gl_unmask_signals(GetLine *gl, sigset_t *oldset) 11379*7c478bd9Sstevel@tonic-gate { 11380*7c478bd9Sstevel@tonic-gate gl->signals_masked = 0; 11381*7c478bd9Sstevel@tonic-gate return sigprocmask(SIG_SETMASK, oldset, NULL) < 0; 11382*7c478bd9Sstevel@tonic-gate } 11383*7c478bd9Sstevel@tonic-gate 11384*7c478bd9Sstevel@tonic-gate /*....................................................................... 11385*7c478bd9Sstevel@tonic-gate * Arrange to temporarily catch the signals marked in gl->use_signal_set. 11386*7c478bd9Sstevel@tonic-gate * 11387*7c478bd9Sstevel@tonic-gate * Input: 11388*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11389*7c478bd9Sstevel@tonic-gate * Output: 11390*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11391*7c478bd9Sstevel@tonic-gate * 1 - Error. 11392*7c478bd9Sstevel@tonic-gate */ 11393*7c478bd9Sstevel@tonic-gate static int gl_catch_signals(GetLine *gl) 11394*7c478bd9Sstevel@tonic-gate { 11395*7c478bd9Sstevel@tonic-gate return sigprocmask(SIG_UNBLOCK, &gl->use_signal_set, NULL) < 0; 11396*7c478bd9Sstevel@tonic-gate } 11397*7c478bd9Sstevel@tonic-gate 11398*7c478bd9Sstevel@tonic-gate /*....................................................................... 11399*7c478bd9Sstevel@tonic-gate * Select the I/O mode to be used by gl_get_line(). 11400*7c478bd9Sstevel@tonic-gate * 11401*7c478bd9Sstevel@tonic-gate * Input: 11402*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11403*7c478bd9Sstevel@tonic-gate * mode GlIOMode The I/O mode to establish. 11404*7c478bd9Sstevel@tonic-gate * Output: 11405*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11406*7c478bd9Sstevel@tonic-gate * 1 - Error. 11407*7c478bd9Sstevel@tonic-gate */ 11408*7c478bd9Sstevel@tonic-gate int gl_io_mode(GetLine *gl, GlIOMode mode) 11409*7c478bd9Sstevel@tonic-gate { 11410*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this function */ 11411*7c478bd9Sstevel@tonic-gate int status; /* The return status of _gl_io_mode() */ 11412*7c478bd9Sstevel@tonic-gate /* 11413*7c478bd9Sstevel@tonic-gate * Check the arguments. 11414*7c478bd9Sstevel@tonic-gate */ 11415*7c478bd9Sstevel@tonic-gate if(!gl) { 11416*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11417*7c478bd9Sstevel@tonic-gate return 1; 11418*7c478bd9Sstevel@tonic-gate }; 11419*7c478bd9Sstevel@tonic-gate /* 11420*7c478bd9Sstevel@tonic-gate * Check that the requested mode is known. 11421*7c478bd9Sstevel@tonic-gate */ 11422*7c478bd9Sstevel@tonic-gate switch(mode) { 11423*7c478bd9Sstevel@tonic-gate case GL_NORMAL_MODE: 11424*7c478bd9Sstevel@tonic-gate case GL_SERVER_MODE: 11425*7c478bd9Sstevel@tonic-gate break; 11426*7c478bd9Sstevel@tonic-gate default: 11427*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11428*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Unknown gl_get_line() I/O mode requested.", 11429*7c478bd9Sstevel@tonic-gate END_ERR_MSG); 11430*7c478bd9Sstevel@tonic-gate return 1; 11431*7c478bd9Sstevel@tonic-gate }; 11432*7c478bd9Sstevel@tonic-gate /* 11433*7c478bd9Sstevel@tonic-gate * Block all signals. 11434*7c478bd9Sstevel@tonic-gate */ 11435*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 11436*7c478bd9Sstevel@tonic-gate return 1; 11437*7c478bd9Sstevel@tonic-gate /* 11438*7c478bd9Sstevel@tonic-gate * Invoke the private body of this function. 11439*7c478bd9Sstevel@tonic-gate */ 11440*7c478bd9Sstevel@tonic-gate status = _gl_io_mode(gl, mode); 11441*7c478bd9Sstevel@tonic-gate /* 11442*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 11443*7c478bd9Sstevel@tonic-gate */ 11444*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 11445*7c478bd9Sstevel@tonic-gate return status; 11446*7c478bd9Sstevel@tonic-gate } 11447*7c478bd9Sstevel@tonic-gate 11448*7c478bd9Sstevel@tonic-gate /*....................................................................... 11449*7c478bd9Sstevel@tonic-gate * This is the private body of the public function, gl_io_mode(). 11450*7c478bd9Sstevel@tonic-gate * It assumes that the caller has checked its arguments and blocked the 11451*7c478bd9Sstevel@tonic-gate * delivery of signals. 11452*7c478bd9Sstevel@tonic-gate */ 11453*7c478bd9Sstevel@tonic-gate static int _gl_io_mode(GetLine *gl, GlIOMode mode) 11454*7c478bd9Sstevel@tonic-gate { 11455*7c478bd9Sstevel@tonic-gate /* 11456*7c478bd9Sstevel@tonic-gate * Are we already in the specified mode? 11457*7c478bd9Sstevel@tonic-gate */ 11458*7c478bd9Sstevel@tonic-gate if(mode == gl->io_mode) 11459*7c478bd9Sstevel@tonic-gate return 0; 11460*7c478bd9Sstevel@tonic-gate /* 11461*7c478bd9Sstevel@tonic-gate * First revert to normal I/O in the current I/O mode. 11462*7c478bd9Sstevel@tonic-gate */ 11463*7c478bd9Sstevel@tonic-gate _gl_normal_io(gl); 11464*7c478bd9Sstevel@tonic-gate /* 11465*7c478bd9Sstevel@tonic-gate * Record the new mode. 11466*7c478bd9Sstevel@tonic-gate */ 11467*7c478bd9Sstevel@tonic-gate gl->io_mode = mode; 11468*7c478bd9Sstevel@tonic-gate /* 11469*7c478bd9Sstevel@tonic-gate * Perform any actions needed by the new mode. 11470*7c478bd9Sstevel@tonic-gate */ 11471*7c478bd9Sstevel@tonic-gate if(mode==GL_SERVER_MODE) { 11472*7c478bd9Sstevel@tonic-gate if(_gl_raw_io(gl, 1)) 11473*7c478bd9Sstevel@tonic-gate return 1; 11474*7c478bd9Sstevel@tonic-gate }; 11475*7c478bd9Sstevel@tonic-gate return 0; 11476*7c478bd9Sstevel@tonic-gate } 11477*7c478bd9Sstevel@tonic-gate 11478*7c478bd9Sstevel@tonic-gate /*....................................................................... 11479*7c478bd9Sstevel@tonic-gate * Return extra information (ie. in addition to that provided by errno) 11480*7c478bd9Sstevel@tonic-gate * about the last error to occur in either gl_get_line() or its 11481*7c478bd9Sstevel@tonic-gate * associated public functions. 11482*7c478bd9Sstevel@tonic-gate * 11483*7c478bd9Sstevel@tonic-gate * Input: 11484*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11485*7c478bd9Sstevel@tonic-gate * Input/Output: 11486*7c478bd9Sstevel@tonic-gate * buff char * An optional output buffer. Note that if the 11487*7c478bd9Sstevel@tonic-gate * calling application calls any gl_*() 11488*7c478bd9Sstevel@tonic-gate * functions from signal handlers, it should 11489*7c478bd9Sstevel@tonic-gate * provide a buffer here, so that a copy of 11490*7c478bd9Sstevel@tonic-gate * the latest error message can safely be made 11491*7c478bd9Sstevel@tonic-gate * while signals are blocked. 11492*7c478bd9Sstevel@tonic-gate * n size_t The allocated size of buff[]. 11493*7c478bd9Sstevel@tonic-gate * Output: 11494*7c478bd9Sstevel@tonic-gate * return const char * A pointer to the error message. This will 11495*7c478bd9Sstevel@tonic-gate * be the buff argument, unless buff==NULL, in 11496*7c478bd9Sstevel@tonic-gate * which case it will be a pointer to an 11497*7c478bd9Sstevel@tonic-gate * internal error buffer. In the latter case, 11498*7c478bd9Sstevel@tonic-gate * note that the contents of the returned buffer 11499*7c478bd9Sstevel@tonic-gate * will change on subsequent calls to any gl_*() 11500*7c478bd9Sstevel@tonic-gate * functions. 11501*7c478bd9Sstevel@tonic-gate */ 11502*7c478bd9Sstevel@tonic-gate const char *gl_error_message(GetLine *gl, char *buff, size_t n) 11503*7c478bd9Sstevel@tonic-gate { 11504*7c478bd9Sstevel@tonic-gate if(!gl) { 11505*7c478bd9Sstevel@tonic-gate static const char *msg = "NULL GetLine argument"; 11506*7c478bd9Sstevel@tonic-gate if(buff) { 11507*7c478bd9Sstevel@tonic-gate strncpy(buff, msg, n); 11508*7c478bd9Sstevel@tonic-gate buff[n-1] = '\0'; 11509*7c478bd9Sstevel@tonic-gate } else { 11510*7c478bd9Sstevel@tonic-gate return msg; 11511*7c478bd9Sstevel@tonic-gate }; 11512*7c478bd9Sstevel@tonic-gate } else if(buff) { 11513*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry to this block */ 11514*7c478bd9Sstevel@tonic-gate /* 11515*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 11516*7c478bd9Sstevel@tonic-gate */ 11517*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 11518*7c478bd9Sstevel@tonic-gate /* 11519*7c478bd9Sstevel@tonic-gate * Copy the error message into the specified buffer. 11520*7c478bd9Sstevel@tonic-gate */ 11521*7c478bd9Sstevel@tonic-gate if(buff && n > 0) { 11522*7c478bd9Sstevel@tonic-gate strncpy(buff, _err_get_msg(gl->err), n); 11523*7c478bd9Sstevel@tonic-gate buff[n-1] = '\0'; 11524*7c478bd9Sstevel@tonic-gate }; 11525*7c478bd9Sstevel@tonic-gate /* 11526*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 11527*7c478bd9Sstevel@tonic-gate */ 11528*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 11529*7c478bd9Sstevel@tonic-gate } else { 11530*7c478bd9Sstevel@tonic-gate return _err_get_msg(gl->err); 11531*7c478bd9Sstevel@tonic-gate }; 11532*7c478bd9Sstevel@tonic-gate return buff; 11533*7c478bd9Sstevel@tonic-gate } 11534*7c478bd9Sstevel@tonic-gate 11535*7c478bd9Sstevel@tonic-gate /*....................................................................... 11536*7c478bd9Sstevel@tonic-gate * Return the signal mask used by gl_get_line(). This is the set of 11537*7c478bd9Sstevel@tonic-gate * signals that gl_get_line() is currently configured to trap. 11538*7c478bd9Sstevel@tonic-gate * 11539*7c478bd9Sstevel@tonic-gate * Input: 11540*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11541*7c478bd9Sstevel@tonic-gate * Input/Output: 11542*7c478bd9Sstevel@tonic-gate * set sigset_t * The set of signals will be returned in *set, 11543*7c478bd9Sstevel@tonic-gate * in the form of a signal process mask, as 11544*7c478bd9Sstevel@tonic-gate * used by sigaction(), sigprocmask(), 11545*7c478bd9Sstevel@tonic-gate * sigpending(), sigsuspend(), sigsetjmp() and 11546*7c478bd9Sstevel@tonic-gate * other standard POSIX signal-aware 11547*7c478bd9Sstevel@tonic-gate * functions. 11548*7c478bd9Sstevel@tonic-gate * Output: 11549*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11550*7c478bd9Sstevel@tonic-gate * 1 - Error (examine errno for reason). 11551*7c478bd9Sstevel@tonic-gate */ 11552*7c478bd9Sstevel@tonic-gate int gl_list_signals(GetLine *gl, sigset_t *set) 11553*7c478bd9Sstevel@tonic-gate { 11554*7c478bd9Sstevel@tonic-gate /* 11555*7c478bd9Sstevel@tonic-gate * Check the arguments. 11556*7c478bd9Sstevel@tonic-gate */ 11557*7c478bd9Sstevel@tonic-gate if(!gl || !set) { 11558*7c478bd9Sstevel@tonic-gate if(gl) 11559*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG); 11560*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11561*7c478bd9Sstevel@tonic-gate return 1; 11562*7c478bd9Sstevel@tonic-gate }; 11563*7c478bd9Sstevel@tonic-gate /* 11564*7c478bd9Sstevel@tonic-gate * Copy the signal mask into *set. 11565*7c478bd9Sstevel@tonic-gate */ 11566*7c478bd9Sstevel@tonic-gate memcpy(set, &gl->all_signal_set, sizeof(*set)); 11567*7c478bd9Sstevel@tonic-gate return 0; 11568*7c478bd9Sstevel@tonic-gate } 11569*7c478bd9Sstevel@tonic-gate 11570*7c478bd9Sstevel@tonic-gate /*....................................................................... 11571*7c478bd9Sstevel@tonic-gate * By default, gl_get_line() doesn't trap signals that are blocked 11572*7c478bd9Sstevel@tonic-gate * when it is called. This default can be changed either on a 11573*7c478bd9Sstevel@tonic-gate * per-signal basis by calling gl_trap_signal(), or on a global basis 11574*7c478bd9Sstevel@tonic-gate * by calling this function. What this function does is add the 11575*7c478bd9Sstevel@tonic-gate * GLS_UNBLOCK_SIG flag to all signals that are currently configured 11576*7c478bd9Sstevel@tonic-gate * to be trapped by gl_get_line(), such that when subsequent calls to 11577*7c478bd9Sstevel@tonic-gate * gl_get_line() wait for I/O, these signals are temporarily 11578*7c478bd9Sstevel@tonic-gate * unblocked. This behavior is useful in non-blocking server-I/O mode, 11579*7c478bd9Sstevel@tonic-gate * where it is used to avoid race conditions related to handling these 11580*7c478bd9Sstevel@tonic-gate * signals externally to gl_get_line(). See the demonstration code in 11581*7c478bd9Sstevel@tonic-gate * demo3.c, or the gl_handle_signal() man page for further 11582*7c478bd9Sstevel@tonic-gate * information. 11583*7c478bd9Sstevel@tonic-gate * 11584*7c478bd9Sstevel@tonic-gate * Input: 11585*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11586*7c478bd9Sstevel@tonic-gate */ 11587*7c478bd9Sstevel@tonic-gate void gl_catch_blocked(GetLine *gl) 11588*7c478bd9Sstevel@tonic-gate { 11589*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The process signal mask to restore */ 11590*7c478bd9Sstevel@tonic-gate GlSignalNode *sig; /* A signal node in gl->sigs */ 11591*7c478bd9Sstevel@tonic-gate /* 11592*7c478bd9Sstevel@tonic-gate * Check the arguments. 11593*7c478bd9Sstevel@tonic-gate */ 11594*7c478bd9Sstevel@tonic-gate if(!gl) { 11595*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11596*7c478bd9Sstevel@tonic-gate return; 11597*7c478bd9Sstevel@tonic-gate }; 11598*7c478bd9Sstevel@tonic-gate /* 11599*7c478bd9Sstevel@tonic-gate * Temporarily block all signals while we modify the contents of gl. 11600*7c478bd9Sstevel@tonic-gate */ 11601*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 11602*7c478bd9Sstevel@tonic-gate /* 11603*7c478bd9Sstevel@tonic-gate * Add the GLS_UNBLOCK_SIG flag to all configured signals. 11604*7c478bd9Sstevel@tonic-gate */ 11605*7c478bd9Sstevel@tonic-gate for(sig=gl->sigs; sig; sig=sig->next) 11606*7c478bd9Sstevel@tonic-gate sig->flags |= GLS_UNBLOCK_SIG; 11607*7c478bd9Sstevel@tonic-gate /* 11608*7c478bd9Sstevel@tonic-gate * Restore the process signal mask that was superseded by the call 11609*7c478bd9Sstevel@tonic-gate * to gl_mask_signals(). 11610*7c478bd9Sstevel@tonic-gate */ 11611*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 11612*7c478bd9Sstevel@tonic-gate return; 11613*7c478bd9Sstevel@tonic-gate } 11614*7c478bd9Sstevel@tonic-gate 11615*7c478bd9Sstevel@tonic-gate /*....................................................................... 11616*7c478bd9Sstevel@tonic-gate * Respond to signals who's default effects have important 11617*7c478bd9Sstevel@tonic-gate * consequences to gl_get_line(). This is intended for use in 11618*7c478bd9Sstevel@tonic-gate * non-blocking server mode, where the external event loop is 11619*7c478bd9Sstevel@tonic-gate * responsible for catching signals. Signals that are handled include 11620*7c478bd9Sstevel@tonic-gate * those that by default terminate or suspend the process, and the 11621*7c478bd9Sstevel@tonic-gate * signal that indicates that the terminal size has changed. Note that 11622*7c478bd9Sstevel@tonic-gate * this function is not signal safe and should thus not be called from 11623*7c478bd9Sstevel@tonic-gate * a signal handler itself. See the gl_io_mode() man page for how it 11624*7c478bd9Sstevel@tonic-gate * should be used. 11625*7c478bd9Sstevel@tonic-gate * 11626*7c478bd9Sstevel@tonic-gate * In the case of signals that by default terminate or suspend 11627*7c478bd9Sstevel@tonic-gate * processes, command-line editing will be suspended, the terminal 11628*7c478bd9Sstevel@tonic-gate * returned to a usable state, then the default disposition of the 11629*7c478bd9Sstevel@tonic-gate * signal restored and the signal resent, in order to suspend or 11630*7c478bd9Sstevel@tonic-gate * terminate the process. If the process subsequently resumes, 11631*7c478bd9Sstevel@tonic-gate * command-line editing is resumed. 11632*7c478bd9Sstevel@tonic-gate * 11633*7c478bd9Sstevel@tonic-gate * In the case of signals that indicate that the terminal has been 11634*7c478bd9Sstevel@tonic-gate * resized, the new size will be queried, and any input line that is 11635*7c478bd9Sstevel@tonic-gate * being edited will be redrawn to fit the new dimensions of the 11636*7c478bd9Sstevel@tonic-gate * terminal. 11637*7c478bd9Sstevel@tonic-gate * 11638*7c478bd9Sstevel@tonic-gate * Input: 11639*7c478bd9Sstevel@tonic-gate * signo int The number of the signal to respond to. 11640*7c478bd9Sstevel@tonic-gate * gl GetLine * The first element of an array of 'ngl' GetLine 11641*7c478bd9Sstevel@tonic-gate * objects. 11642*7c478bd9Sstevel@tonic-gate * ngl int The number of elements in the gl[] array. Normally 11643*7c478bd9Sstevel@tonic-gate * this will be one. 11644*7c478bd9Sstevel@tonic-gate */ 11645*7c478bd9Sstevel@tonic-gate void gl_handle_signal(int signo, GetLine *gl, int ngl) 11646*7c478bd9Sstevel@tonic-gate { 11647*7c478bd9Sstevel@tonic-gate int attr; /* The attributes of the specified signal */ 11648*7c478bd9Sstevel@tonic-gate sigset_t all_signals; /* The set of trappable signals */ 11649*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The process signal mask to restore */ 11650*7c478bd9Sstevel@tonic-gate int i; 11651*7c478bd9Sstevel@tonic-gate /* 11652*7c478bd9Sstevel@tonic-gate * NULL operation? 11653*7c478bd9Sstevel@tonic-gate */ 11654*7c478bd9Sstevel@tonic-gate if(ngl < 1 || !gl) 11655*7c478bd9Sstevel@tonic-gate return; 11656*7c478bd9Sstevel@tonic-gate /* 11657*7c478bd9Sstevel@tonic-gate * Look up the default attributes of the specified signal. 11658*7c478bd9Sstevel@tonic-gate */ 11659*7c478bd9Sstevel@tonic-gate attr = gl_classify_signal(signo); 11660*7c478bd9Sstevel@tonic-gate /* 11661*7c478bd9Sstevel@tonic-gate * If the signal isn't known, we are done. 11662*7c478bd9Sstevel@tonic-gate */ 11663*7c478bd9Sstevel@tonic-gate if(!attr) 11664*7c478bd9Sstevel@tonic-gate return; 11665*7c478bd9Sstevel@tonic-gate /* 11666*7c478bd9Sstevel@tonic-gate * Temporarily block all signals while we modify the gl objects. 11667*7c478bd9Sstevel@tonic-gate */ 11668*7c478bd9Sstevel@tonic-gate gl_list_trappable_signals(&all_signals); 11669*7c478bd9Sstevel@tonic-gate sigprocmask(SIG_BLOCK, &all_signals, &oldset); 11670*7c478bd9Sstevel@tonic-gate /* 11671*7c478bd9Sstevel@tonic-gate * Suspend or terminate the process? 11672*7c478bd9Sstevel@tonic-gate */ 11673*7c478bd9Sstevel@tonic-gate if(attr & (GLSA_SUSP | GLSA_TERM)) { 11674*7c478bd9Sstevel@tonic-gate gl_suspend_process(signo, gl, ngl); 11675*7c478bd9Sstevel@tonic-gate /* 11676*7c478bd9Sstevel@tonic-gate * Resize the terminal? Note that ioctl() isn't defined as being 11677*7c478bd9Sstevel@tonic-gate * signal safe, so we can't call gl_update_size() here. However, 11678*7c478bd9Sstevel@tonic-gate * gl_get_line() checks for resizes on each call, so simply arrange 11679*7c478bd9Sstevel@tonic-gate * for the application's event loop to call gl_get_line() as soon as 11680*7c478bd9Sstevel@tonic-gate * it becomes possible to write to the terminal. Note that if the 11681*7c478bd9Sstevel@tonic-gate * caller is calling select() or poll when this happens, these functions 11682*7c478bd9Sstevel@tonic-gate * get interrupted, since a signal has been caught. 11683*7c478bd9Sstevel@tonic-gate */ 11684*7c478bd9Sstevel@tonic-gate } else if(attr & GLSA_SIZE) { 11685*7c478bd9Sstevel@tonic-gate for(i=0; i<ngl; i++) 11686*7c478bd9Sstevel@tonic-gate gl[i].pending_io = GLP_WRITE; 11687*7c478bd9Sstevel@tonic-gate }; 11688*7c478bd9Sstevel@tonic-gate /* 11689*7c478bd9Sstevel@tonic-gate * Restore the process signal mask that was superseded by the call 11690*7c478bd9Sstevel@tonic-gate * to gl_mask_signals(). 11691*7c478bd9Sstevel@tonic-gate */ 11692*7c478bd9Sstevel@tonic-gate sigprocmask(SIG_SETMASK, &oldset, NULL); 11693*7c478bd9Sstevel@tonic-gate return; 11694*7c478bd9Sstevel@tonic-gate } 11695*7c478bd9Sstevel@tonic-gate 11696*7c478bd9Sstevel@tonic-gate /*....................................................................... 11697*7c478bd9Sstevel@tonic-gate * Respond to an externally caught process suspension or 11698*7c478bd9Sstevel@tonic-gate * termination signal. 11699*7c478bd9Sstevel@tonic-gate * 11700*7c478bd9Sstevel@tonic-gate * After restoring the terminal to a usable state, suspend or 11701*7c478bd9Sstevel@tonic-gate * terminate the calling process, using the original signal with its 11702*7c478bd9Sstevel@tonic-gate * default disposition restored to do so. If the process subsequently 11703*7c478bd9Sstevel@tonic-gate * resumes, resume editing any input lines that were being entered. 11704*7c478bd9Sstevel@tonic-gate * 11705*7c478bd9Sstevel@tonic-gate * Input: 11706*7c478bd9Sstevel@tonic-gate * signo int The signal number to suspend the process with. Note 11707*7c478bd9Sstevel@tonic-gate * that the default disposition of this signal will be 11708*7c478bd9Sstevel@tonic-gate * restored before the signal is sent, so provided 11709*7c478bd9Sstevel@tonic-gate * that the default disposition of this signal is to 11710*7c478bd9Sstevel@tonic-gate * either suspend or terminate the application, 11711*7c478bd9Sstevel@tonic-gate * that is what wil happen, regardless of what signal 11712*7c478bd9Sstevel@tonic-gate * handler is currently assigned to this signal. 11713*7c478bd9Sstevel@tonic-gate * gl GetLine * The first element of an array of 'ngl' GetLine objects 11714*7c478bd9Sstevel@tonic-gate * whose terminals should be restored to a sane state 11715*7c478bd9Sstevel@tonic-gate * while the application is suspended. 11716*7c478bd9Sstevel@tonic-gate * ngl int The number of elements in the gl[] array. 11717*7c478bd9Sstevel@tonic-gate */ 11718*7c478bd9Sstevel@tonic-gate static void gl_suspend_process(int signo, GetLine *gl, int ngl) 11719*7c478bd9Sstevel@tonic-gate { 11720*7c478bd9Sstevel@tonic-gate sigset_t only_signo; /* A signal set containing just signo */ 11721*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signal mask on entry to this function */ 11722*7c478bd9Sstevel@tonic-gate sigset_t all_signals; /* A signal set containing all signals */ 11723*7c478bd9Sstevel@tonic-gate struct sigaction old_action; /* The current signal handler */ 11724*7c478bd9Sstevel@tonic-gate struct sigaction def_action; /* The default signal handler */ 11725*7c478bd9Sstevel@tonic-gate int i; 11726*7c478bd9Sstevel@tonic-gate /* 11727*7c478bd9Sstevel@tonic-gate * Create a signal mask containing the signal that was trapped. 11728*7c478bd9Sstevel@tonic-gate */ 11729*7c478bd9Sstevel@tonic-gate sigemptyset(&only_signo); 11730*7c478bd9Sstevel@tonic-gate sigaddset(&only_signo, signo); 11731*7c478bd9Sstevel@tonic-gate /* 11732*7c478bd9Sstevel@tonic-gate * Temporarily block all signals. 11733*7c478bd9Sstevel@tonic-gate */ 11734*7c478bd9Sstevel@tonic-gate gl_list_trappable_signals(&all_signals); 11735*7c478bd9Sstevel@tonic-gate sigprocmask(SIG_BLOCK, &all_signals, &oldset); 11736*7c478bd9Sstevel@tonic-gate /* 11737*7c478bd9Sstevel@tonic-gate * Restore the terminal to a usable state. 11738*7c478bd9Sstevel@tonic-gate */ 11739*7c478bd9Sstevel@tonic-gate for(i=0; i<ngl; i++) { 11740*7c478bd9Sstevel@tonic-gate GetLine *obj = gl + i; 11741*7c478bd9Sstevel@tonic-gate if(obj->raw_mode) { 11742*7c478bd9Sstevel@tonic-gate _gl_normal_io(obj); 11743*7c478bd9Sstevel@tonic-gate if(!obj->raw_mode) /* Check that gl_normal_io() succeded */ 11744*7c478bd9Sstevel@tonic-gate obj->raw_mode = -1; /* Flag raw mode as needing to be restored */ 11745*7c478bd9Sstevel@tonic-gate }; 11746*7c478bd9Sstevel@tonic-gate }; 11747*7c478bd9Sstevel@tonic-gate /* 11748*7c478bd9Sstevel@tonic-gate * Restore the system default disposition of the signal that we 11749*7c478bd9Sstevel@tonic-gate * caught. Note that this signal is currently blocked. Note that we 11750*7c478bd9Sstevel@tonic-gate * don't use memcpy() to copy signal sets here, because the signal safety 11751*7c478bd9Sstevel@tonic-gate * of memcpy() is undefined. 11752*7c478bd9Sstevel@tonic-gate */ 11753*7c478bd9Sstevel@tonic-gate def_action.sa_handler = SIG_DFL; 11754*7c478bd9Sstevel@tonic-gate { 11755*7c478bd9Sstevel@tonic-gate char *orig = (char *) &all_signals; 11756*7c478bd9Sstevel@tonic-gate char *dest = (char *) &def_action.sa_mask; 11757*7c478bd9Sstevel@tonic-gate for(i=0; i<sizeof(sigset_t); i++) 11758*7c478bd9Sstevel@tonic-gate *dest++ = *orig++; 11759*7c478bd9Sstevel@tonic-gate }; 11760*7c478bd9Sstevel@tonic-gate sigaction(signo, &def_action, &old_action); 11761*7c478bd9Sstevel@tonic-gate /* 11762*7c478bd9Sstevel@tonic-gate * Resend the signal, and unblock it so that it gets delivered to 11763*7c478bd9Sstevel@tonic-gate * the application. This will invoke the default action of this signal. 11764*7c478bd9Sstevel@tonic-gate */ 11765*7c478bd9Sstevel@tonic-gate raise(signo); 11766*7c478bd9Sstevel@tonic-gate sigprocmask(SIG_UNBLOCK, &only_signo, NULL); 11767*7c478bd9Sstevel@tonic-gate /* 11768*7c478bd9Sstevel@tonic-gate * If the process resumes again, it will resume here. 11769*7c478bd9Sstevel@tonic-gate * Block the signal again, then restore our signal handler. 11770*7c478bd9Sstevel@tonic-gate */ 11771*7c478bd9Sstevel@tonic-gate sigprocmask(SIG_BLOCK, &only_signo, NULL); 11772*7c478bd9Sstevel@tonic-gate sigaction(signo, &old_action, NULL); 11773*7c478bd9Sstevel@tonic-gate /* 11774*7c478bd9Sstevel@tonic-gate * Resume command-line editing. 11775*7c478bd9Sstevel@tonic-gate */ 11776*7c478bd9Sstevel@tonic-gate for(i=0; i<ngl; i++) { 11777*7c478bd9Sstevel@tonic-gate GetLine *obj = gl + i; 11778*7c478bd9Sstevel@tonic-gate if(obj->raw_mode == -1) { /* Did we flag the need to restore raw mode? */ 11779*7c478bd9Sstevel@tonic-gate obj->raw_mode = 0; /* gl_raw_io() does nothing unless raw_mode==0 */ 11780*7c478bd9Sstevel@tonic-gate _gl_raw_io(obj, 1); 11781*7c478bd9Sstevel@tonic-gate }; 11782*7c478bd9Sstevel@tonic-gate }; 11783*7c478bd9Sstevel@tonic-gate /* 11784*7c478bd9Sstevel@tonic-gate * Restore the process signal mask to the way it was when this function 11785*7c478bd9Sstevel@tonic-gate * was called. 11786*7c478bd9Sstevel@tonic-gate */ 11787*7c478bd9Sstevel@tonic-gate sigprocmask(SIG_SETMASK, &oldset, NULL); 11788*7c478bd9Sstevel@tonic-gate return; 11789*7c478bd9Sstevel@tonic-gate } 11790*7c478bd9Sstevel@tonic-gate 11791*7c478bd9Sstevel@tonic-gate /*....................................................................... 11792*7c478bd9Sstevel@tonic-gate * Return the information about the default attributes of a given signal. 11793*7c478bd9Sstevel@tonic-gate * The attributes that are returned are as defined by the standards that 11794*7c478bd9Sstevel@tonic-gate * created them, including POSIX, SVR4 and 4.3+BSD, and are taken from a 11795*7c478bd9Sstevel@tonic-gate * table in Richard Steven's book, "Advanced programming in the UNIX 11796*7c478bd9Sstevel@tonic-gate * environment". 11797*7c478bd9Sstevel@tonic-gate * 11798*7c478bd9Sstevel@tonic-gate * Input: 11799*7c478bd9Sstevel@tonic-gate * signo int The signal to be characterized. 11800*7c478bd9Sstevel@tonic-gate * Output: 11801*7c478bd9Sstevel@tonic-gate * return int A bitwise union of GlSigAttr enumerators, or 0 11802*7c478bd9Sstevel@tonic-gate * if the signal isn't known. 11803*7c478bd9Sstevel@tonic-gate */ 11804*7c478bd9Sstevel@tonic-gate static int gl_classify_signal(int signo) 11805*7c478bd9Sstevel@tonic-gate { 11806*7c478bd9Sstevel@tonic-gate int i; 11807*7c478bd9Sstevel@tonic-gate /* 11808*7c478bd9Sstevel@tonic-gate * Search for the specified signal in the gl_signal_list[] table. 11809*7c478bd9Sstevel@tonic-gate */ 11810*7c478bd9Sstevel@tonic-gate for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) { 11811*7c478bd9Sstevel@tonic-gate const struct GlDefSignal *sig = gl_signal_list + i; 11812*7c478bd9Sstevel@tonic-gate if(sig->signo == signo) 11813*7c478bd9Sstevel@tonic-gate return sig->attr; 11814*7c478bd9Sstevel@tonic-gate }; 11815*7c478bd9Sstevel@tonic-gate /* 11816*7c478bd9Sstevel@tonic-gate * Signal not known. 11817*7c478bd9Sstevel@tonic-gate */ 11818*7c478bd9Sstevel@tonic-gate return 0; 11819*7c478bd9Sstevel@tonic-gate } 11820*7c478bd9Sstevel@tonic-gate 11821*7c478bd9Sstevel@tonic-gate /*....................................................................... 11822*7c478bd9Sstevel@tonic-gate * When in non-blocking server mode, this function can be used to abandon 11823*7c478bd9Sstevel@tonic-gate * the current incompletely entered input line, and prepare to start 11824*7c478bd9Sstevel@tonic-gate * editing a new line on the next call to gl_get_line(). 11825*7c478bd9Sstevel@tonic-gate * 11826*7c478bd9Sstevel@tonic-gate * Input: 11827*7c478bd9Sstevel@tonic-gate * gl GetLine * The line editor resource object. 11828*7c478bd9Sstevel@tonic-gate */ 11829*7c478bd9Sstevel@tonic-gate void gl_abandon_line(GetLine *gl) 11830*7c478bd9Sstevel@tonic-gate { 11831*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The process signal mask to restore */ 11832*7c478bd9Sstevel@tonic-gate /* 11833*7c478bd9Sstevel@tonic-gate * Check the arguments. 11834*7c478bd9Sstevel@tonic-gate */ 11835*7c478bd9Sstevel@tonic-gate if(!gl) { 11836*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11837*7c478bd9Sstevel@tonic-gate return; 11838*7c478bd9Sstevel@tonic-gate }; 11839*7c478bd9Sstevel@tonic-gate /* 11840*7c478bd9Sstevel@tonic-gate * Temporarily block all signals while we modify the contents of gl. 11841*7c478bd9Sstevel@tonic-gate */ 11842*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 11843*7c478bd9Sstevel@tonic-gate /* 11844*7c478bd9Sstevel@tonic-gate * Mark the input line as discarded. 11845*7c478bd9Sstevel@tonic-gate */ 11846*7c478bd9Sstevel@tonic-gate _gl_abandon_line(gl); 11847*7c478bd9Sstevel@tonic-gate /* 11848*7c478bd9Sstevel@tonic-gate * Restore the process signal mask that was superseded by the call 11849*7c478bd9Sstevel@tonic-gate * to gl_mask_signals(). 11850*7c478bd9Sstevel@tonic-gate */ 11851*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 11852*7c478bd9Sstevel@tonic-gate return; 11853*7c478bd9Sstevel@tonic-gate } 11854*7c478bd9Sstevel@tonic-gate 11855*7c478bd9Sstevel@tonic-gate /*....................................................................... 11856*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_abandon_line() function. It 11857*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 11858*7c478bd9Sstevel@tonic-gate * delivery of signals. 11859*7c478bd9Sstevel@tonic-gate */ 11860*7c478bd9Sstevel@tonic-gate void _gl_abandon_line(GetLine *gl) 11861*7c478bd9Sstevel@tonic-gate { 11862*7c478bd9Sstevel@tonic-gate gl->endline = 1; 11863*7c478bd9Sstevel@tonic-gate gl->pending_io = GLP_WRITE; 11864*7c478bd9Sstevel@tonic-gate } 11865*7c478bd9Sstevel@tonic-gate 11866*7c478bd9Sstevel@tonic-gate /*....................................................................... 11867*7c478bd9Sstevel@tonic-gate * How many characters are needed to write a number as an octal string? 11868*7c478bd9Sstevel@tonic-gate * 11869*7c478bd9Sstevel@tonic-gate * Input: 11870*7c478bd9Sstevel@tonic-gate * num unsigned The to be measured. 11871*7c478bd9Sstevel@tonic-gate * Output: 11872*7c478bd9Sstevel@tonic-gate * return int The number of characters needed. 11873*7c478bd9Sstevel@tonic-gate */ 11874*7c478bd9Sstevel@tonic-gate static int gl_octal_width(unsigned num) 11875*7c478bd9Sstevel@tonic-gate { 11876*7c478bd9Sstevel@tonic-gate int n; /* The number of characters needed to render the number */ 11877*7c478bd9Sstevel@tonic-gate for(n=1; num /= 8; n++) 11878*7c478bd9Sstevel@tonic-gate ; 11879*7c478bd9Sstevel@tonic-gate return n; 11880*7c478bd9Sstevel@tonic-gate } 11881*7c478bd9Sstevel@tonic-gate 11882*7c478bd9Sstevel@tonic-gate /*....................................................................... 11883*7c478bd9Sstevel@tonic-gate * Tell gl_get_line() the current terminal size. Note that this is only 11884*7c478bd9Sstevel@tonic-gate * necessary on systems where changes in terminal size aren't reported 11885*7c478bd9Sstevel@tonic-gate * via SIGWINCH. 11886*7c478bd9Sstevel@tonic-gate * 11887*7c478bd9Sstevel@tonic-gate * Input: 11888*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11889*7c478bd9Sstevel@tonic-gate * ncolumn int The number of columns in the terminal. 11890*7c478bd9Sstevel@tonic-gate * nline int The number of lines in the terminal. 11891*7c478bd9Sstevel@tonic-gate * Output: 11892*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11893*7c478bd9Sstevel@tonic-gate * 1 - Error. 11894*7c478bd9Sstevel@tonic-gate */ 11895*7c478bd9Sstevel@tonic-gate int gl_set_term_size(GetLine *gl, int ncolumn, int nline) 11896*7c478bd9Sstevel@tonic-gate { 11897*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry */ 11898*7c478bd9Sstevel@tonic-gate /* to this function */ 11899*7c478bd9Sstevel@tonic-gate int status; /* The return status */ 11900*7c478bd9Sstevel@tonic-gate /* 11901*7c478bd9Sstevel@tonic-gate * Block all signals while accessing gl. 11902*7c478bd9Sstevel@tonic-gate */ 11903*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 11904*7c478bd9Sstevel@tonic-gate /* 11905*7c478bd9Sstevel@tonic-gate * Install the new terminal size. 11906*7c478bd9Sstevel@tonic-gate */ 11907*7c478bd9Sstevel@tonic-gate status = _gl_set_term_size(gl, ncolumn, nline); 11908*7c478bd9Sstevel@tonic-gate /* 11909*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 11910*7c478bd9Sstevel@tonic-gate */ 11911*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 11912*7c478bd9Sstevel@tonic-gate return status; 11913*7c478bd9Sstevel@tonic-gate } 11914*7c478bd9Sstevel@tonic-gate 11915*7c478bd9Sstevel@tonic-gate /*....................................................................... 11916*7c478bd9Sstevel@tonic-gate * This is the private body of the gl_set_term_size() function. It 11917*7c478bd9Sstevel@tonic-gate * assumes that the caller has checked its arguments and blocked the 11918*7c478bd9Sstevel@tonic-gate * delivery of signals. 11919*7c478bd9Sstevel@tonic-gate */ 11920*7c478bd9Sstevel@tonic-gate static int _gl_set_term_size(GetLine *gl, int ncolumn, int nline) 11921*7c478bd9Sstevel@tonic-gate { 11922*7c478bd9Sstevel@tonic-gate /* 11923*7c478bd9Sstevel@tonic-gate * Check the arguments. 11924*7c478bd9Sstevel@tonic-gate */ 11925*7c478bd9Sstevel@tonic-gate if(!gl) { 11926*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11927*7c478bd9Sstevel@tonic-gate return 1; 11928*7c478bd9Sstevel@tonic-gate }; 11929*7c478bd9Sstevel@tonic-gate /* 11930*7c478bd9Sstevel@tonic-gate * Reject non-sensical dimensions. 11931*7c478bd9Sstevel@tonic-gate */ 11932*7c478bd9Sstevel@tonic-gate if(ncolumn <= 0 || nline <= 0) { 11933*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Invalid terminal size", END_ERR_MSG); 11934*7c478bd9Sstevel@tonic-gate errno = EINVAL; 11935*7c478bd9Sstevel@tonic-gate return 1; 11936*7c478bd9Sstevel@tonic-gate }; 11937*7c478bd9Sstevel@tonic-gate /* 11938*7c478bd9Sstevel@tonic-gate * Install the new dimensions in the terminal driver if possible, so 11939*7c478bd9Sstevel@tonic-gate * that future calls to gl_query_size() get the new value. 11940*7c478bd9Sstevel@tonic-gate */ 11941*7c478bd9Sstevel@tonic-gate #ifdef TIOCSWINSZ 11942*7c478bd9Sstevel@tonic-gate if(gl->is_term) { 11943*7c478bd9Sstevel@tonic-gate struct winsize size; 11944*7c478bd9Sstevel@tonic-gate size.ws_row = nline; 11945*7c478bd9Sstevel@tonic-gate size.ws_col = ncolumn; 11946*7c478bd9Sstevel@tonic-gate size.ws_xpixel = 0; 11947*7c478bd9Sstevel@tonic-gate size.ws_ypixel = 0; 11948*7c478bd9Sstevel@tonic-gate if(ioctl(gl->output_fd, TIOCSWINSZ, &size) == -1) { 11949*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "Can't change terminal size", END_ERR_MSG); 11950*7c478bd9Sstevel@tonic-gate return 1; 11951*7c478bd9Sstevel@tonic-gate }; 11952*7c478bd9Sstevel@tonic-gate }; 11953*7c478bd9Sstevel@tonic-gate #endif 11954*7c478bd9Sstevel@tonic-gate /* 11955*7c478bd9Sstevel@tonic-gate * If an input line is in the process of being edited, redisplay it to 11956*7c478bd9Sstevel@tonic-gate * accomodate the new dimensions, and record the new dimensions in 11957*7c478bd9Sstevel@tonic-gate * gl->nline and gl->ncolumn. 11958*7c478bd9Sstevel@tonic-gate */ 11959*7c478bd9Sstevel@tonic-gate return gl_handle_tty_resize(gl, ncolumn, nline); 11960*7c478bd9Sstevel@tonic-gate } 11961*7c478bd9Sstevel@tonic-gate 11962*7c478bd9Sstevel@tonic-gate /*....................................................................... 11963*7c478bd9Sstevel@tonic-gate * Record a character in the input line buffer at a given position. 11964*7c478bd9Sstevel@tonic-gate * 11965*7c478bd9Sstevel@tonic-gate * Input: 11966*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 11967*7c478bd9Sstevel@tonic-gate * c char The character to be recorded. 11968*7c478bd9Sstevel@tonic-gate * bufpos int The index in the buffer at which to record the 11969*7c478bd9Sstevel@tonic-gate * character. 11970*7c478bd9Sstevel@tonic-gate * Output: 11971*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 11972*7c478bd9Sstevel@tonic-gate * 1 - Insufficient room. 11973*7c478bd9Sstevel@tonic-gate */ 11974*7c478bd9Sstevel@tonic-gate static int gl_buffer_char(GetLine *gl, char c, int bufpos) 11975*7c478bd9Sstevel@tonic-gate { 11976*7c478bd9Sstevel@tonic-gate /* 11977*7c478bd9Sstevel@tonic-gate * Guard against buffer overruns. 11978*7c478bd9Sstevel@tonic-gate */ 11979*7c478bd9Sstevel@tonic-gate if(bufpos >= gl->linelen) 11980*7c478bd9Sstevel@tonic-gate return 1; 11981*7c478bd9Sstevel@tonic-gate /* 11982*7c478bd9Sstevel@tonic-gate * Record the new character. 11983*7c478bd9Sstevel@tonic-gate */ 11984*7c478bd9Sstevel@tonic-gate gl->line[bufpos] = c; 11985*7c478bd9Sstevel@tonic-gate /* 11986*7c478bd9Sstevel@tonic-gate * If the new character was placed beyond the end of the current input 11987*7c478bd9Sstevel@tonic-gate * line, update gl->ntotal to reflect the increased number of characters 11988*7c478bd9Sstevel@tonic-gate * that are in gl->line, and terminate the string. 11989*7c478bd9Sstevel@tonic-gate */ 11990*7c478bd9Sstevel@tonic-gate if(bufpos >= gl->ntotal) { 11991*7c478bd9Sstevel@tonic-gate gl->ntotal = bufpos+1; 11992*7c478bd9Sstevel@tonic-gate gl->line[gl->ntotal] = '\0'; 11993*7c478bd9Sstevel@tonic-gate }; 11994*7c478bd9Sstevel@tonic-gate return 0; 11995*7c478bd9Sstevel@tonic-gate } 11996*7c478bd9Sstevel@tonic-gate 11997*7c478bd9Sstevel@tonic-gate /*....................................................................... 11998*7c478bd9Sstevel@tonic-gate * Copy a given string into the input buffer, overwriting the current 11999*7c478bd9Sstevel@tonic-gate * contents. 12000*7c478bd9Sstevel@tonic-gate * 12001*7c478bd9Sstevel@tonic-gate * Input: 12002*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12003*7c478bd9Sstevel@tonic-gate * s const char * The string to be recorded. 12004*7c478bd9Sstevel@tonic-gate * n int The number of characters to be copied from the 12005*7c478bd9Sstevel@tonic-gate * string. 12006*7c478bd9Sstevel@tonic-gate * bufpos int The index in the buffer at which to place the 12007*7c478bd9Sstevel@tonic-gate * the first character of the string. 12008*7c478bd9Sstevel@tonic-gate * Output: 12009*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 12010*7c478bd9Sstevel@tonic-gate * 1 - String truncated to fit. 12011*7c478bd9Sstevel@tonic-gate */ 12012*7c478bd9Sstevel@tonic-gate static int gl_buffer_string(GetLine *gl, const char *s, int n, int bufpos) 12013*7c478bd9Sstevel@tonic-gate { 12014*7c478bd9Sstevel@tonic-gate int nnew; /* The number of characters actually recorded */ 12015*7c478bd9Sstevel@tonic-gate int i; 12016*7c478bd9Sstevel@tonic-gate /* 12017*7c478bd9Sstevel@tonic-gate * How many of the characters will fit within the buffer? 12018*7c478bd9Sstevel@tonic-gate */ 12019*7c478bd9Sstevel@tonic-gate nnew = bufpos + n <= gl->linelen ? n : (gl->linelen - bufpos); 12020*7c478bd9Sstevel@tonic-gate /* 12021*7c478bd9Sstevel@tonic-gate * Record the first nnew characters of s[] in the buffer. 12022*7c478bd9Sstevel@tonic-gate */ 12023*7c478bd9Sstevel@tonic-gate for(i=0; i<nnew; i++) 12024*7c478bd9Sstevel@tonic-gate gl_buffer_char(gl, s[i], bufpos + i); 12025*7c478bd9Sstevel@tonic-gate /* 12026*7c478bd9Sstevel@tonic-gate * Was the string truncated? 12027*7c478bd9Sstevel@tonic-gate */ 12028*7c478bd9Sstevel@tonic-gate return nnew < n; 12029*7c478bd9Sstevel@tonic-gate } 12030*7c478bd9Sstevel@tonic-gate 12031*7c478bd9Sstevel@tonic-gate /*....................................................................... 12032*7c478bd9Sstevel@tonic-gate * Make room in the input buffer for a string to be inserted. This 12033*7c478bd9Sstevel@tonic-gate * involves moving the characters that follow a specified point, towards 12034*7c478bd9Sstevel@tonic-gate * the end of the buffer. 12035*7c478bd9Sstevel@tonic-gate * 12036*7c478bd9Sstevel@tonic-gate * Input: 12037*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12038*7c478bd9Sstevel@tonic-gate * start int The index of the first character to be moved. 12039*7c478bd9Sstevel@tonic-gate * n int The width of the gap. 12040*7c478bd9Sstevel@tonic-gate * Output: 12041*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 12042*7c478bd9Sstevel@tonic-gate * 1 - Insufficient room. 12043*7c478bd9Sstevel@tonic-gate */ 12044*7c478bd9Sstevel@tonic-gate static int gl_make_gap_in_buffer(GetLine *gl, int start, int n) 12045*7c478bd9Sstevel@tonic-gate { 12046*7c478bd9Sstevel@tonic-gate /* 12047*7c478bd9Sstevel@tonic-gate * Ensure that the buffer has sufficient space. 12048*7c478bd9Sstevel@tonic-gate */ 12049*7c478bd9Sstevel@tonic-gate if(gl->ntotal + n > gl->linelen) 12050*7c478bd9Sstevel@tonic-gate return 1; 12051*7c478bd9Sstevel@tonic-gate /* 12052*7c478bd9Sstevel@tonic-gate * Move everything including and beyond the character at 'start' 12053*7c478bd9Sstevel@tonic-gate * towards the end of the string. 12054*7c478bd9Sstevel@tonic-gate */ 12055*7c478bd9Sstevel@tonic-gate memmove(gl->line + start + n, gl->line + start, gl->ntotal - start + 1); 12056*7c478bd9Sstevel@tonic-gate /* 12057*7c478bd9Sstevel@tonic-gate * Update the recorded size of the line. 12058*7c478bd9Sstevel@tonic-gate */ 12059*7c478bd9Sstevel@tonic-gate gl->ntotal += n; 12060*7c478bd9Sstevel@tonic-gate return 1; 12061*7c478bd9Sstevel@tonic-gate } 12062*7c478bd9Sstevel@tonic-gate 12063*7c478bd9Sstevel@tonic-gate /*....................................................................... 12064*7c478bd9Sstevel@tonic-gate * Remove a given number of characters from the input buffer. This 12065*7c478bd9Sstevel@tonic-gate * involves moving the characters that follow the removed characters to 12066*7c478bd9Sstevel@tonic-gate * where the removed sub-string started in the input buffer. 12067*7c478bd9Sstevel@tonic-gate * 12068*7c478bd9Sstevel@tonic-gate * Input: 12069*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12070*7c478bd9Sstevel@tonic-gate * start int The first character to be removed. 12071*7c478bd9Sstevel@tonic-gate * n int The number of characters to remove. 12072*7c478bd9Sstevel@tonic-gate */ 12073*7c478bd9Sstevel@tonic-gate static void gl_remove_from_buffer(GetLine *gl, int start, int n) 12074*7c478bd9Sstevel@tonic-gate { 12075*7c478bd9Sstevel@tonic-gate memmove(gl->line + start, gl->line + start + n, gl->ntotal - start - n + 1); 12076*7c478bd9Sstevel@tonic-gate /* 12077*7c478bd9Sstevel@tonic-gate * Update the recorded size of the line. 12078*7c478bd9Sstevel@tonic-gate */ 12079*7c478bd9Sstevel@tonic-gate gl->ntotal -= n; 12080*7c478bd9Sstevel@tonic-gate } 12081*7c478bd9Sstevel@tonic-gate 12082*7c478bd9Sstevel@tonic-gate /*....................................................................... 12083*7c478bd9Sstevel@tonic-gate * Truncate the string in the input line buffer after a given number of 12084*7c478bd9Sstevel@tonic-gate * characters. 12085*7c478bd9Sstevel@tonic-gate * 12086*7c478bd9Sstevel@tonic-gate * Input: 12087*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12088*7c478bd9Sstevel@tonic-gate * n int The new length of the line. 12089*7c478bd9Sstevel@tonic-gate * Output: 12090*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 12091*7c478bd9Sstevel@tonic-gate * 1 - n > gl->linelen. 12092*7c478bd9Sstevel@tonic-gate */ 12093*7c478bd9Sstevel@tonic-gate static int gl_truncate_buffer(GetLine *gl, int n) 12094*7c478bd9Sstevel@tonic-gate { 12095*7c478bd9Sstevel@tonic-gate if(n > gl->linelen) 12096*7c478bd9Sstevel@tonic-gate return 1; 12097*7c478bd9Sstevel@tonic-gate gl->line[n] = '\0'; 12098*7c478bd9Sstevel@tonic-gate gl->ntotal = n; 12099*7c478bd9Sstevel@tonic-gate return 0; 12100*7c478bd9Sstevel@tonic-gate } 12101*7c478bd9Sstevel@tonic-gate 12102*7c478bd9Sstevel@tonic-gate /*....................................................................... 12103*7c478bd9Sstevel@tonic-gate * When the contents of gl->line[] are changed without calling any of the 12104*7c478bd9Sstevel@tonic-gate * gl_ buffer manipulation functions, this function must be called to 12105*7c478bd9Sstevel@tonic-gate * compute the length of this string, and ancillary information. 12106*7c478bd9Sstevel@tonic-gate * 12107*7c478bd9Sstevel@tonic-gate * Input: 12108*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12109*7c478bd9Sstevel@tonic-gate */ 12110*7c478bd9Sstevel@tonic-gate static void gl_update_buffer(GetLine *gl) 12111*7c478bd9Sstevel@tonic-gate { 12112*7c478bd9Sstevel@tonic-gate int len; /* The length of the line */ 12113*7c478bd9Sstevel@tonic-gate /* 12114*7c478bd9Sstevel@tonic-gate * Measure the length of the input line. 12115*7c478bd9Sstevel@tonic-gate */ 12116*7c478bd9Sstevel@tonic-gate for(len=0; len <= gl->linelen && gl->line[len]; len++) 12117*7c478bd9Sstevel@tonic-gate ; 12118*7c478bd9Sstevel@tonic-gate /* 12119*7c478bd9Sstevel@tonic-gate * Just in case the string wasn't correctly terminated, do so here. 12120*7c478bd9Sstevel@tonic-gate */ 12121*7c478bd9Sstevel@tonic-gate gl->line[len] = '\0'; 12122*7c478bd9Sstevel@tonic-gate /* 12123*7c478bd9Sstevel@tonic-gate * Record the number of characters that are now in gl->line[]. 12124*7c478bd9Sstevel@tonic-gate */ 12125*7c478bd9Sstevel@tonic-gate gl->ntotal = len; 12126*7c478bd9Sstevel@tonic-gate /* 12127*7c478bd9Sstevel@tonic-gate * Ensure that the cursor stays within the bounds of the modified 12128*7c478bd9Sstevel@tonic-gate * input line. 12129*7c478bd9Sstevel@tonic-gate */ 12130*7c478bd9Sstevel@tonic-gate if(gl->buff_curpos > gl->ntotal) 12131*7c478bd9Sstevel@tonic-gate gl->buff_curpos = gl->ntotal; 12132*7c478bd9Sstevel@tonic-gate /* 12133*7c478bd9Sstevel@tonic-gate * Arrange for the input line to be redrawn. 12134*7c478bd9Sstevel@tonic-gate */ 12135*7c478bd9Sstevel@tonic-gate gl_queue_redisplay(gl); 12136*7c478bd9Sstevel@tonic-gate return; 12137*7c478bd9Sstevel@tonic-gate } 12138*7c478bd9Sstevel@tonic-gate 12139*7c478bd9Sstevel@tonic-gate /*....................................................................... 12140*7c478bd9Sstevel@tonic-gate * Erase the displayed input line, including its prompt, and leave the 12141*7c478bd9Sstevel@tonic-gate * cursor where the erased line started. Note that to allow this 12142*7c478bd9Sstevel@tonic-gate * function to be used when responding to a terminal resize, this 12143*7c478bd9Sstevel@tonic-gate * function is designed to work even if the horizontal cursor position 12144*7c478bd9Sstevel@tonic-gate * doesn't match the internally recorded position. 12145*7c478bd9Sstevel@tonic-gate * 12146*7c478bd9Sstevel@tonic-gate * Input: 12147*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12148*7c478bd9Sstevel@tonic-gate * Output: 12149*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 12150*7c478bd9Sstevel@tonic-gate * 1 - Error. 12151*7c478bd9Sstevel@tonic-gate */ 12152*7c478bd9Sstevel@tonic-gate static int gl_erase_line(GetLine *gl) 12153*7c478bd9Sstevel@tonic-gate { 12154*7c478bd9Sstevel@tonic-gate /* 12155*7c478bd9Sstevel@tonic-gate * Is a line currently displayed? 12156*7c478bd9Sstevel@tonic-gate */ 12157*7c478bd9Sstevel@tonic-gate if(gl->displayed) { 12158*7c478bd9Sstevel@tonic-gate /* 12159*7c478bd9Sstevel@tonic-gate * Relative the the start of the input line, which terminal line of 12160*7c478bd9Sstevel@tonic-gate * the current input line is the cursor currently on? 12161*7c478bd9Sstevel@tonic-gate */ 12162*7c478bd9Sstevel@tonic-gate int cursor_line = gl->term_curpos / gl->ncolumn; 12163*7c478bd9Sstevel@tonic-gate /* 12164*7c478bd9Sstevel@tonic-gate * Move the cursor to the start of the line. 12165*7c478bd9Sstevel@tonic-gate */ 12166*7c478bd9Sstevel@tonic-gate for( ; cursor_line > 0; cursor_line--) { 12167*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->up)) 12168*7c478bd9Sstevel@tonic-gate return 1; 12169*7c478bd9Sstevel@tonic-gate }; 12170*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->bol)) 12171*7c478bd9Sstevel@tonic-gate return 1; 12172*7c478bd9Sstevel@tonic-gate /* 12173*7c478bd9Sstevel@tonic-gate * Clear from the start of the line to the end of the terminal. 12174*7c478bd9Sstevel@tonic-gate */ 12175*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, gl->nline, gl->clear_eod)) 12176*7c478bd9Sstevel@tonic-gate return 1; 12177*7c478bd9Sstevel@tonic-gate /* 12178*7c478bd9Sstevel@tonic-gate * Mark the line as no longer displayed. 12179*7c478bd9Sstevel@tonic-gate */ 12180*7c478bd9Sstevel@tonic-gate gl_line_erased(gl); 12181*7c478bd9Sstevel@tonic-gate }; 12182*7c478bd9Sstevel@tonic-gate return 0; 12183*7c478bd9Sstevel@tonic-gate } 12184*7c478bd9Sstevel@tonic-gate 12185*7c478bd9Sstevel@tonic-gate /*....................................................................... 12186*7c478bd9Sstevel@tonic-gate * Arrange for the input line to be redisplayed by gl_flush_output(), 12187*7c478bd9Sstevel@tonic-gate * as soon as the output queue becomes empty. 12188*7c478bd9Sstevel@tonic-gate * 12189*7c478bd9Sstevel@tonic-gate * Input: 12190*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12191*7c478bd9Sstevel@tonic-gate */ 12192*7c478bd9Sstevel@tonic-gate static void gl_queue_redisplay(GetLine *gl) 12193*7c478bd9Sstevel@tonic-gate { 12194*7c478bd9Sstevel@tonic-gate gl->redisplay = 1; 12195*7c478bd9Sstevel@tonic-gate gl->pending_io = GLP_WRITE; 12196*7c478bd9Sstevel@tonic-gate } 12197*7c478bd9Sstevel@tonic-gate 12198*7c478bd9Sstevel@tonic-gate /*....................................................................... 12199*7c478bd9Sstevel@tonic-gate * Truncate the displayed input line starting from the current 12200*7c478bd9Sstevel@tonic-gate * terminal cursor position, and leave the cursor at the end of the 12201*7c478bd9Sstevel@tonic-gate * truncated line. The input-line buffer is not affected. 12202*7c478bd9Sstevel@tonic-gate * 12203*7c478bd9Sstevel@tonic-gate * Input: 12204*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12205*7c478bd9Sstevel@tonic-gate * Output: 12206*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 12207*7c478bd9Sstevel@tonic-gate * 1 - Error. 12208*7c478bd9Sstevel@tonic-gate */ 12209*7c478bd9Sstevel@tonic-gate static int gl_truncate_display(GetLine *gl) 12210*7c478bd9Sstevel@tonic-gate { 12211*7c478bd9Sstevel@tonic-gate /* 12212*7c478bd9Sstevel@tonic-gate * Keep a record of the current terminal cursor position. 12213*7c478bd9Sstevel@tonic-gate */ 12214*7c478bd9Sstevel@tonic-gate int term_curpos = gl->term_curpos; 12215*7c478bd9Sstevel@tonic-gate /* 12216*7c478bd9Sstevel@tonic-gate * First clear from the cursor to the end of the current input line. 12217*7c478bd9Sstevel@tonic-gate */ 12218*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->clear_eol)) 12219*7c478bd9Sstevel@tonic-gate return 1; 12220*7c478bd9Sstevel@tonic-gate /* 12221*7c478bd9Sstevel@tonic-gate * If there is more than one line displayed, go to the start of the 12222*7c478bd9Sstevel@tonic-gate * next line and clear from there to the end of the display. Note that 12223*7c478bd9Sstevel@tonic-gate * we can't use clear_eod to do the whole job of clearing from the 12224*7c478bd9Sstevel@tonic-gate * current cursor position to the end of the terminal because 12225*7c478bd9Sstevel@tonic-gate * clear_eod is only defined when used at the start of a terminal line 12226*7c478bd9Sstevel@tonic-gate * (eg. with gnome terminals, clear_eod clears from the start of the 12227*7c478bd9Sstevel@tonic-gate * current terminal line, rather than from the current cursor 12228*7c478bd9Sstevel@tonic-gate * position). 12229*7c478bd9Sstevel@tonic-gate */ 12230*7c478bd9Sstevel@tonic-gate if(gl->term_len / gl->ncolumn > gl->term_curpos / gl->ncolumn) { 12231*7c478bd9Sstevel@tonic-gate if(gl_print_control_sequence(gl, 1, gl->down) || 12232*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, 1, gl->bol) || 12233*7c478bd9Sstevel@tonic-gate gl_print_control_sequence(gl, gl->nline, gl->clear_eod)) 12234*7c478bd9Sstevel@tonic-gate return 1; 12235*7c478bd9Sstevel@tonic-gate /* 12236*7c478bd9Sstevel@tonic-gate * Where is the cursor now? 12237*7c478bd9Sstevel@tonic-gate */ 12238*7c478bd9Sstevel@tonic-gate gl->term_curpos = gl->ncolumn * (term_curpos / gl->ncolumn + 1); 12239*7c478bd9Sstevel@tonic-gate /* 12240*7c478bd9Sstevel@tonic-gate * Restore the cursor position. 12241*7c478bd9Sstevel@tonic-gate */ 12242*7c478bd9Sstevel@tonic-gate gl_set_term_curpos(gl, term_curpos); 12243*7c478bd9Sstevel@tonic-gate }; 12244*7c478bd9Sstevel@tonic-gate /* 12245*7c478bd9Sstevel@tonic-gate * Update the recorded position of the final character. 12246*7c478bd9Sstevel@tonic-gate */ 12247*7c478bd9Sstevel@tonic-gate gl->term_len = gl->term_curpos; 12248*7c478bd9Sstevel@tonic-gate return 0; 12249*7c478bd9Sstevel@tonic-gate } 12250*7c478bd9Sstevel@tonic-gate 12251*7c478bd9Sstevel@tonic-gate /*....................................................................... 12252*7c478bd9Sstevel@tonic-gate * Return the set of all trappable signals. 12253*7c478bd9Sstevel@tonic-gate * 12254*7c478bd9Sstevel@tonic-gate * Input: 12255*7c478bd9Sstevel@tonic-gate * signals sigset_t * The set of signals will be recorded in 12256*7c478bd9Sstevel@tonic-gate * *signals. 12257*7c478bd9Sstevel@tonic-gate */ 12258*7c478bd9Sstevel@tonic-gate static void gl_list_trappable_signals(sigset_t *signals) 12259*7c478bd9Sstevel@tonic-gate { 12260*7c478bd9Sstevel@tonic-gate /* 12261*7c478bd9Sstevel@tonic-gate * Start with the set of all signals. 12262*7c478bd9Sstevel@tonic-gate */ 12263*7c478bd9Sstevel@tonic-gate sigfillset(signals); 12264*7c478bd9Sstevel@tonic-gate /* 12265*7c478bd9Sstevel@tonic-gate * Remove un-trappable signals from this set. 12266*7c478bd9Sstevel@tonic-gate */ 12267*7c478bd9Sstevel@tonic-gate #ifdef SIGKILL 12268*7c478bd9Sstevel@tonic-gate sigdelset(signals, SIGKILL); 12269*7c478bd9Sstevel@tonic-gate #endif 12270*7c478bd9Sstevel@tonic-gate #ifdef SIGSTOP 12271*7c478bd9Sstevel@tonic-gate sigdelset(signals, SIGSTOP); 12272*7c478bd9Sstevel@tonic-gate #endif 12273*7c478bd9Sstevel@tonic-gate } 12274*7c478bd9Sstevel@tonic-gate 12275*7c478bd9Sstevel@tonic-gate /*....................................................................... 12276*7c478bd9Sstevel@tonic-gate * Read an input line from a non-interactive input stream. 12277*7c478bd9Sstevel@tonic-gate * 12278*7c478bd9Sstevel@tonic-gate * Input: 12279*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12280*7c478bd9Sstevel@tonic-gate * Output: 12281*7c478bd9Sstevel@tonic-gate * return int 0 - OK 12282*7c478bd9Sstevel@tonic-gate * 1 - Error. 12283*7c478bd9Sstevel@tonic-gate */ 12284*7c478bd9Sstevel@tonic-gate static int gl_read_stream_line(GetLine *gl) 12285*7c478bd9Sstevel@tonic-gate { 12286*7c478bd9Sstevel@tonic-gate char c = '\0'; /* The latest character read from fp */ 12287*7c478bd9Sstevel@tonic-gate /* 12288*7c478bd9Sstevel@tonic-gate * Record the fact that we are about to read input. 12289*7c478bd9Sstevel@tonic-gate */ 12290*7c478bd9Sstevel@tonic-gate gl->pending_io = GLP_READ; 12291*7c478bd9Sstevel@tonic-gate /* 12292*7c478bd9Sstevel@tonic-gate * If we are starting a new line, reset the line-input parameters. 12293*7c478bd9Sstevel@tonic-gate */ 12294*7c478bd9Sstevel@tonic-gate if(gl->endline) 12295*7c478bd9Sstevel@tonic-gate gl_reset_input_line(gl); 12296*7c478bd9Sstevel@tonic-gate /* 12297*7c478bd9Sstevel@tonic-gate * Read one character at a time. 12298*7c478bd9Sstevel@tonic-gate */ 12299*7c478bd9Sstevel@tonic-gate while(gl->ntotal < gl->linelen && c != '\n') { 12300*7c478bd9Sstevel@tonic-gate /* 12301*7c478bd9Sstevel@tonic-gate * Attempt to read one more character. 12302*7c478bd9Sstevel@tonic-gate */ 12303*7c478bd9Sstevel@tonic-gate switch(gl_read_input(gl, &c)) { 12304*7c478bd9Sstevel@tonic-gate case GL_READ_OK: 12305*7c478bd9Sstevel@tonic-gate break; 12306*7c478bd9Sstevel@tonic-gate case GL_READ_EOF: /* Reached end-of-file? */ 12307*7c478bd9Sstevel@tonic-gate /* 12308*7c478bd9Sstevel@tonic-gate * If any characters were read before the end-of-file condition, 12309*7c478bd9Sstevel@tonic-gate * interpolate a newline character, so that the caller sees a 12310*7c478bd9Sstevel@tonic-gate * properly terminated line. Otherwise return an end-of-file 12311*7c478bd9Sstevel@tonic-gate * condition. 12312*7c478bd9Sstevel@tonic-gate */ 12313*7c478bd9Sstevel@tonic-gate if(gl->ntotal > 0) { 12314*7c478bd9Sstevel@tonic-gate c = '\n'; 12315*7c478bd9Sstevel@tonic-gate } else { 12316*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_EOF, 0); 12317*7c478bd9Sstevel@tonic-gate return 1; 12318*7c478bd9Sstevel@tonic-gate }; 12319*7c478bd9Sstevel@tonic-gate break; 12320*7c478bd9Sstevel@tonic-gate case GL_READ_BLOCKED: /* Input blocked? */ 12321*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO); 12322*7c478bd9Sstevel@tonic-gate return 1; 12323*7c478bd9Sstevel@tonic-gate break; 12324*7c478bd9Sstevel@tonic-gate case GL_READ_ERROR: /* I/O error? */ 12325*7c478bd9Sstevel@tonic-gate return 1; 12326*7c478bd9Sstevel@tonic-gate break; 12327*7c478bd9Sstevel@tonic-gate }; 12328*7c478bd9Sstevel@tonic-gate /* 12329*7c478bd9Sstevel@tonic-gate * Append the character to the line buffer. 12330*7c478bd9Sstevel@tonic-gate */ 12331*7c478bd9Sstevel@tonic-gate if(gl_buffer_char(gl, c, gl->ntotal)) 12332*7c478bd9Sstevel@tonic-gate return 1; 12333*7c478bd9Sstevel@tonic-gate }; 12334*7c478bd9Sstevel@tonic-gate /* 12335*7c478bd9Sstevel@tonic-gate * Was the end of the input line reached before running out of buffer space? 12336*7c478bd9Sstevel@tonic-gate */ 12337*7c478bd9Sstevel@tonic-gate gl->endline = (c == '\n'); 12338*7c478bd9Sstevel@tonic-gate return 0; 12339*7c478bd9Sstevel@tonic-gate } 12340*7c478bd9Sstevel@tonic-gate 12341*7c478bd9Sstevel@tonic-gate /*....................................................................... 12342*7c478bd9Sstevel@tonic-gate * Read a single character from a non-interactive input stream. 12343*7c478bd9Sstevel@tonic-gate * 12344*7c478bd9Sstevel@tonic-gate * Input: 12345*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12346*7c478bd9Sstevel@tonic-gate * Output: 12347*7c478bd9Sstevel@tonic-gate * return int The character, or EOF on error. 12348*7c478bd9Sstevel@tonic-gate */ 12349*7c478bd9Sstevel@tonic-gate static int gl_read_stream_char(GetLine *gl) 12350*7c478bd9Sstevel@tonic-gate { 12351*7c478bd9Sstevel@tonic-gate char c = '\0'; /* The latest character read from fp */ 12352*7c478bd9Sstevel@tonic-gate int retval = EOF; /* The return value of this function */ 12353*7c478bd9Sstevel@tonic-gate /* 12354*7c478bd9Sstevel@tonic-gate * Arrange to discard any incomplete input line. 12355*7c478bd9Sstevel@tonic-gate */ 12356*7c478bd9Sstevel@tonic-gate _gl_abandon_line(gl); 12357*7c478bd9Sstevel@tonic-gate /* 12358*7c478bd9Sstevel@tonic-gate * Record the fact that we are about to read input. 12359*7c478bd9Sstevel@tonic-gate */ 12360*7c478bd9Sstevel@tonic-gate gl->pending_io = GLP_READ; 12361*7c478bd9Sstevel@tonic-gate /* 12362*7c478bd9Sstevel@tonic-gate * Attempt to read one more character. 12363*7c478bd9Sstevel@tonic-gate */ 12364*7c478bd9Sstevel@tonic-gate switch(gl_read_input(gl, &c)) { 12365*7c478bd9Sstevel@tonic-gate case GL_READ_OK: /* Success */ 12366*7c478bd9Sstevel@tonic-gate retval = c; 12367*7c478bd9Sstevel@tonic-gate break; 12368*7c478bd9Sstevel@tonic-gate case GL_READ_BLOCKED: /* The read blocked */ 12369*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_BLOCKED, BLOCKED_ERRNO); 12370*7c478bd9Sstevel@tonic-gate retval = EOF; /* Failure */ 12371*7c478bd9Sstevel@tonic-gate break; 12372*7c478bd9Sstevel@tonic-gate case GL_READ_EOF: /* End of file reached */ 12373*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_EOF, 0); 12374*7c478bd9Sstevel@tonic-gate retval = EOF; /* Failure */ 12375*7c478bd9Sstevel@tonic-gate break; 12376*7c478bd9Sstevel@tonic-gate case GL_READ_ERROR: 12377*7c478bd9Sstevel@tonic-gate retval = EOF; /* Failure */ 12378*7c478bd9Sstevel@tonic-gate break; 12379*7c478bd9Sstevel@tonic-gate }; 12380*7c478bd9Sstevel@tonic-gate return retval; 12381*7c478bd9Sstevel@tonic-gate } 12382*7c478bd9Sstevel@tonic-gate 12383*7c478bd9Sstevel@tonic-gate /*....................................................................... 12384*7c478bd9Sstevel@tonic-gate * Bind a key sequence to a given action. 12385*7c478bd9Sstevel@tonic-gate * 12386*7c478bd9Sstevel@tonic-gate * Input: 12387*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12388*7c478bd9Sstevel@tonic-gate * origin GlKeyOrigin The originator of the key binding. 12389*7c478bd9Sstevel@tonic-gate * key const char * The key-sequence to be bound (or unbound). 12390*7c478bd9Sstevel@tonic-gate * action const char * The name of the action to bind the key to, 12391*7c478bd9Sstevel@tonic-gate * or either NULL or "" to unbind the 12392*7c478bd9Sstevel@tonic-gate * key-sequence. 12393*7c478bd9Sstevel@tonic-gate * Output: 12394*7c478bd9Sstevel@tonic-gate * return int 0 - OK 12395*7c478bd9Sstevel@tonic-gate * 1 - Error. 12396*7c478bd9Sstevel@tonic-gate */ 12397*7c478bd9Sstevel@tonic-gate int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin, const char *keyseq, 12398*7c478bd9Sstevel@tonic-gate const char *action) 12399*7c478bd9Sstevel@tonic-gate { 12400*7c478bd9Sstevel@tonic-gate KtBinder binder; /* The private internal equivalent of 'origin' */ 12401*7c478bd9Sstevel@tonic-gate /* 12402*7c478bd9Sstevel@tonic-gate * Check the arguments. 12403*7c478bd9Sstevel@tonic-gate */ 12404*7c478bd9Sstevel@tonic-gate if(!gl || !keyseq) { 12405*7c478bd9Sstevel@tonic-gate errno = EINVAL; 12406*7c478bd9Sstevel@tonic-gate if(gl) 12407*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, "NULL argument(s)", END_ERR_MSG); 12408*7c478bd9Sstevel@tonic-gate return 1; 12409*7c478bd9Sstevel@tonic-gate }; 12410*7c478bd9Sstevel@tonic-gate /* 12411*7c478bd9Sstevel@tonic-gate * An empty action string requests that the key-sequence be unbound. 12412*7c478bd9Sstevel@tonic-gate * This is indicated to _kt_set_keybinding() by passing a NULL action 12413*7c478bd9Sstevel@tonic-gate * string, so convert an empty string to a NULL action pointer. 12414*7c478bd9Sstevel@tonic-gate */ 12415*7c478bd9Sstevel@tonic-gate if(action && *action=='\0') 12416*7c478bd9Sstevel@tonic-gate action = NULL; 12417*7c478bd9Sstevel@tonic-gate /* 12418*7c478bd9Sstevel@tonic-gate * Translate the public originator enumeration to the private equivalent. 12419*7c478bd9Sstevel@tonic-gate */ 12420*7c478bd9Sstevel@tonic-gate binder = origin==GL_USER_KEY ? KTB_USER : KTB_NORM; 12421*7c478bd9Sstevel@tonic-gate /* 12422*7c478bd9Sstevel@tonic-gate * Bind the action to a given key-sequence? 12423*7c478bd9Sstevel@tonic-gate */ 12424*7c478bd9Sstevel@tonic-gate if(keyseq && _kt_set_keybinding(gl->bindings, binder, keyseq, action)) { 12425*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _kt_last_error(gl->bindings), END_ERR_MSG); 12426*7c478bd9Sstevel@tonic-gate return 1; 12427*7c478bd9Sstevel@tonic-gate }; 12428*7c478bd9Sstevel@tonic-gate return 0; 12429*7c478bd9Sstevel@tonic-gate } 12430*7c478bd9Sstevel@tonic-gate 12431*7c478bd9Sstevel@tonic-gate /*....................................................................... 12432*7c478bd9Sstevel@tonic-gate * This is the public wrapper around the gl_clear_termina() function. 12433*7c478bd9Sstevel@tonic-gate * It clears the terminal and leaves the cursor at the home position. 12434*7c478bd9Sstevel@tonic-gate * In server I/O mode, the next call to gl_get_line() will also 12435*7c478bd9Sstevel@tonic-gate * redisplay the current input line. 12436*7c478bd9Sstevel@tonic-gate * 12437*7c478bd9Sstevel@tonic-gate * Input: 12438*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12439*7c478bd9Sstevel@tonic-gate * Output: 12440*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 12441*7c478bd9Sstevel@tonic-gate * 1 - Error. 12442*7c478bd9Sstevel@tonic-gate */ 12443*7c478bd9Sstevel@tonic-gate int gl_erase_terminal(GetLine *gl) 12444*7c478bd9Sstevel@tonic-gate { 12445*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry */ 12446*7c478bd9Sstevel@tonic-gate /* to this function */ 12447*7c478bd9Sstevel@tonic-gate int status; /* The return status */ 12448*7c478bd9Sstevel@tonic-gate /* 12449*7c478bd9Sstevel@tonic-gate * Block all signals while accessing gl. 12450*7c478bd9Sstevel@tonic-gate */ 12451*7c478bd9Sstevel@tonic-gate gl_mask_signals(gl, &oldset); 12452*7c478bd9Sstevel@tonic-gate /* 12453*7c478bd9Sstevel@tonic-gate * Clear the terminal. 12454*7c478bd9Sstevel@tonic-gate */ 12455*7c478bd9Sstevel@tonic-gate status = gl_clear_screen(gl, 1, NULL); 12456*7c478bd9Sstevel@tonic-gate /* 12457*7c478bd9Sstevel@tonic-gate * Attempt to flush the clear-screen control codes to the terminal. 12458*7c478bd9Sstevel@tonic-gate * If this doesn't complete the job, the next call to gl_get_line() 12459*7c478bd9Sstevel@tonic-gate * will. 12460*7c478bd9Sstevel@tonic-gate */ 12461*7c478bd9Sstevel@tonic-gate (void) gl_flush_output(gl); 12462*7c478bd9Sstevel@tonic-gate /* 12463*7c478bd9Sstevel@tonic-gate * Restore the process signal mask before returning. 12464*7c478bd9Sstevel@tonic-gate */ 12465*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 12466*7c478bd9Sstevel@tonic-gate return status; 12467*7c478bd9Sstevel@tonic-gate } 12468*7c478bd9Sstevel@tonic-gate 12469*7c478bd9Sstevel@tonic-gate /*....................................................................... 12470*7c478bd9Sstevel@tonic-gate * This function must be called by any function that erases the input 12471*7c478bd9Sstevel@tonic-gate * line. 12472*7c478bd9Sstevel@tonic-gate * 12473*7c478bd9Sstevel@tonic-gate * Input: 12474*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12475*7c478bd9Sstevel@tonic-gate */ 12476*7c478bd9Sstevel@tonic-gate static void gl_line_erased(GetLine *gl) 12477*7c478bd9Sstevel@tonic-gate { 12478*7c478bd9Sstevel@tonic-gate gl->displayed = 0; 12479*7c478bd9Sstevel@tonic-gate gl->term_curpos = 0; 12480*7c478bd9Sstevel@tonic-gate gl->term_len = 0; 12481*7c478bd9Sstevel@tonic-gate } 12482*7c478bd9Sstevel@tonic-gate 12483*7c478bd9Sstevel@tonic-gate /*....................................................................... 12484*7c478bd9Sstevel@tonic-gate * Append a specified line to the history list. 12485*7c478bd9Sstevel@tonic-gate * 12486*7c478bd9Sstevel@tonic-gate * Input: 12487*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12488*7c478bd9Sstevel@tonic-gate * line const char * The line to be added. 12489*7c478bd9Sstevel@tonic-gate * Output: 12490*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 12491*7c478bd9Sstevel@tonic-gate * 1 - Error. 12492*7c478bd9Sstevel@tonic-gate */ 12493*7c478bd9Sstevel@tonic-gate int gl_append_history(GetLine *gl, const char *line) 12494*7c478bd9Sstevel@tonic-gate { 12495*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry */ 12496*7c478bd9Sstevel@tonic-gate /* to this function */ 12497*7c478bd9Sstevel@tonic-gate int status; /* The return status */ 12498*7c478bd9Sstevel@tonic-gate /* 12499*7c478bd9Sstevel@tonic-gate * Check the arguments. 12500*7c478bd9Sstevel@tonic-gate */ 12501*7c478bd9Sstevel@tonic-gate if(!gl || !line) { 12502*7c478bd9Sstevel@tonic-gate errno = EINVAL; 12503*7c478bd9Sstevel@tonic-gate return 1; 12504*7c478bd9Sstevel@tonic-gate }; 12505*7c478bd9Sstevel@tonic-gate /* 12506*7c478bd9Sstevel@tonic-gate * Block all signals. 12507*7c478bd9Sstevel@tonic-gate */ 12508*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 12509*7c478bd9Sstevel@tonic-gate return 1; 12510*7c478bd9Sstevel@tonic-gate /* 12511*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 12512*7c478bd9Sstevel@tonic-gate */ 12513*7c478bd9Sstevel@tonic-gate status = _gl_append_history(gl, line); 12514*7c478bd9Sstevel@tonic-gate /* 12515*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 12516*7c478bd9Sstevel@tonic-gate */ 12517*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 12518*7c478bd9Sstevel@tonic-gate return status; 12519*7c478bd9Sstevel@tonic-gate } 12520*7c478bd9Sstevel@tonic-gate 12521*7c478bd9Sstevel@tonic-gate /*....................................................................... 12522*7c478bd9Sstevel@tonic-gate * This is the private body of the public function, gl_append_history(). 12523*7c478bd9Sstevel@tonic-gate * It assumes that the caller has checked its arguments and blocked the 12524*7c478bd9Sstevel@tonic-gate * delivery of signals. 12525*7c478bd9Sstevel@tonic-gate */ 12526*7c478bd9Sstevel@tonic-gate static int _gl_append_history(GetLine *gl, const char *line) 12527*7c478bd9Sstevel@tonic-gate { 12528*7c478bd9Sstevel@tonic-gate int status =_glh_add_history(gl->glh, line, 0); 12529*7c478bd9Sstevel@tonic-gate if(status) 12530*7c478bd9Sstevel@tonic-gate _err_record_msg(gl->err, _glh_last_error(gl->glh), END_ERR_MSG); 12531*7c478bd9Sstevel@tonic-gate return status; 12532*7c478bd9Sstevel@tonic-gate } 12533*7c478bd9Sstevel@tonic-gate 12534*7c478bd9Sstevel@tonic-gate /*....................................................................... 12535*7c478bd9Sstevel@tonic-gate * Enable or disable the automatic addition of newly entered lines to the 12536*7c478bd9Sstevel@tonic-gate * history list. 12537*7c478bd9Sstevel@tonic-gate * 12538*7c478bd9Sstevel@tonic-gate * Input: 12539*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of gl_get_line(). 12540*7c478bd9Sstevel@tonic-gate * enable int If true, subsequently entered lines will 12541*7c478bd9Sstevel@tonic-gate * automatically be added to the history list 12542*7c478bd9Sstevel@tonic-gate * before they are returned to the caller of 12543*7c478bd9Sstevel@tonic-gate * gl_get_line(). If 0, the choice of how and 12544*7c478bd9Sstevel@tonic-gate * when to archive lines in the history list, 12545*7c478bd9Sstevel@tonic-gate * is left up to the calling application, which 12546*7c478bd9Sstevel@tonic-gate * can do so via calls to gl_append_history(). 12547*7c478bd9Sstevel@tonic-gate * Output: 12548*7c478bd9Sstevel@tonic-gate * return int 0 - OK. 12549*7c478bd9Sstevel@tonic-gate * 1 - Error. 12550*7c478bd9Sstevel@tonic-gate */ 12551*7c478bd9Sstevel@tonic-gate int gl_automatic_history(GetLine *gl, int enable) 12552*7c478bd9Sstevel@tonic-gate { 12553*7c478bd9Sstevel@tonic-gate sigset_t oldset; /* The signals that were blocked on entry */ 12554*7c478bd9Sstevel@tonic-gate /* to this function */ 12555*7c478bd9Sstevel@tonic-gate /* 12556*7c478bd9Sstevel@tonic-gate * Check the arguments. 12557*7c478bd9Sstevel@tonic-gate */ 12558*7c478bd9Sstevel@tonic-gate if(!gl) { 12559*7c478bd9Sstevel@tonic-gate errno = EINVAL; 12560*7c478bd9Sstevel@tonic-gate return 1; 12561*7c478bd9Sstevel@tonic-gate }; 12562*7c478bd9Sstevel@tonic-gate /* 12563*7c478bd9Sstevel@tonic-gate * Block all signals. 12564*7c478bd9Sstevel@tonic-gate */ 12565*7c478bd9Sstevel@tonic-gate if(gl_mask_signals(gl, &oldset)) 12566*7c478bd9Sstevel@tonic-gate return 1; 12567*7c478bd9Sstevel@tonic-gate /* 12568*7c478bd9Sstevel@tonic-gate * Execute the private body of the function while signals are blocked. 12569*7c478bd9Sstevel@tonic-gate */ 12570*7c478bd9Sstevel@tonic-gate gl->automatic_history = enable; 12571*7c478bd9Sstevel@tonic-gate /* 12572*7c478bd9Sstevel@tonic-gate * Restore the process signal mask. 12573*7c478bd9Sstevel@tonic-gate */ 12574*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &oldset); 12575*7c478bd9Sstevel@tonic-gate return 0; 12576*7c478bd9Sstevel@tonic-gate } 12577*7c478bd9Sstevel@tonic-gate 12578*7c478bd9Sstevel@tonic-gate /*....................................................................... 12579*7c478bd9Sstevel@tonic-gate * This is a public function that reads a single uninterpretted 12580*7c478bd9Sstevel@tonic-gate * character from the user, without displaying anything. 12581*7c478bd9Sstevel@tonic-gate * 12582*7c478bd9Sstevel@tonic-gate * Input: 12583*7c478bd9Sstevel@tonic-gate * gl GetLine * A resource object previously returned by 12584*7c478bd9Sstevel@tonic-gate * new_GetLine(). 12585*7c478bd9Sstevel@tonic-gate * Output: 12586*7c478bd9Sstevel@tonic-gate * return int The character that was read, or EOF if the read 12587*7c478bd9Sstevel@tonic-gate * had to be aborted (in which case you can call 12588*7c478bd9Sstevel@tonic-gate * gl_return_status() to find out why). 12589*7c478bd9Sstevel@tonic-gate */ 12590*7c478bd9Sstevel@tonic-gate int gl_read_char(GetLine *gl) 12591*7c478bd9Sstevel@tonic-gate { 12592*7c478bd9Sstevel@tonic-gate int retval; /* The return value of _gl_read_char() */ 12593*7c478bd9Sstevel@tonic-gate /* 12594*7c478bd9Sstevel@tonic-gate * This function can be called from application callback functions, 12595*7c478bd9Sstevel@tonic-gate * so check whether signals have already been masked, so that we don't 12596*7c478bd9Sstevel@tonic-gate * do it again, and overwrite gl->old_signal_set. 12597*7c478bd9Sstevel@tonic-gate */ 12598*7c478bd9Sstevel@tonic-gate int was_masked = gl->signals_masked; 12599*7c478bd9Sstevel@tonic-gate /* 12600*7c478bd9Sstevel@tonic-gate * Check the arguments. 12601*7c478bd9Sstevel@tonic-gate */ 12602*7c478bd9Sstevel@tonic-gate if(!gl) { 12603*7c478bd9Sstevel@tonic-gate errno = EINVAL; 12604*7c478bd9Sstevel@tonic-gate return EOF; 12605*7c478bd9Sstevel@tonic-gate }; 12606*7c478bd9Sstevel@tonic-gate /* 12607*7c478bd9Sstevel@tonic-gate * Temporarily block all of the signals that we have been asked to trap. 12608*7c478bd9Sstevel@tonic-gate */ 12609*7c478bd9Sstevel@tonic-gate if(!was_masked && gl_mask_signals(gl, &gl->old_signal_set)) 12610*7c478bd9Sstevel@tonic-gate return EOF; 12611*7c478bd9Sstevel@tonic-gate /* 12612*7c478bd9Sstevel@tonic-gate * Perform the character reading task. 12613*7c478bd9Sstevel@tonic-gate */ 12614*7c478bd9Sstevel@tonic-gate retval = _gl_read_char(gl); 12615*7c478bd9Sstevel@tonic-gate /* 12616*7c478bd9Sstevel@tonic-gate * Restore the process signal mask to how it was when this function was 12617*7c478bd9Sstevel@tonic-gate * first called. 12618*7c478bd9Sstevel@tonic-gate */ 12619*7c478bd9Sstevel@tonic-gate if(!was_masked) 12620*7c478bd9Sstevel@tonic-gate gl_unmask_signals(gl, &gl->old_signal_set); 12621*7c478bd9Sstevel@tonic-gate return retval; 12622*7c478bd9Sstevel@tonic-gate } 12623*7c478bd9Sstevel@tonic-gate 12624*7c478bd9Sstevel@tonic-gate /*....................................................................... 12625*7c478bd9Sstevel@tonic-gate * This is the main body of the public function gl_read_char(). 12626*7c478bd9Sstevel@tonic-gate */ 12627*7c478bd9Sstevel@tonic-gate static int _gl_read_char(GetLine *gl) 12628*7c478bd9Sstevel@tonic-gate { 12629*7c478bd9Sstevel@tonic-gate int retval = EOF; /* The return value */ 12630*7c478bd9Sstevel@tonic-gate int waserr = 0; /* True if an error occurs */ 12631*7c478bd9Sstevel@tonic-gate char c; /* The character read */ 12632*7c478bd9Sstevel@tonic-gate /* 12633*7c478bd9Sstevel@tonic-gate * This function can be called from application callback functions, 12634*7c478bd9Sstevel@tonic-gate * so check whether signals have already been overriden, so that we don't 12635*7c478bd9Sstevel@tonic-gate * overwrite the preserved signal handlers with gl_get_line()s. Also 12636*7c478bd9Sstevel@tonic-gate * record whether we are currently in raw I/O mode or not, so that this 12637*7c478bd9Sstevel@tonic-gate * can be left in the same state on leaving this function. 12638*7c478bd9Sstevel@tonic-gate */ 12639*7c478bd9Sstevel@tonic-gate int was_overriden = gl->signals_overriden; 12640*7c478bd9Sstevel@tonic-gate int was_raw = gl->raw_mode; 12641*7c478bd9Sstevel@tonic-gate /* 12642*7c478bd9Sstevel@tonic-gate * Also keep a record of the direction of any I/O that gl_get_line() 12643*7c478bd9Sstevel@tonic-gate * is awaiting, so that we can restore this status on return. 12644*7c478bd9Sstevel@tonic-gate */ 12645*7c478bd9Sstevel@tonic-gate GlPendingIO old_pending_io = gl->pending_io; 12646*7c478bd9Sstevel@tonic-gate /* 12647*7c478bd9Sstevel@tonic-gate * Assume that this call will successfully complete the input operation 12648*7c478bd9Sstevel@tonic-gate * until proven otherwise. 12649*7c478bd9Sstevel@tonic-gate */ 12650*7c478bd9Sstevel@tonic-gate gl_clear_status(gl); 12651*7c478bd9Sstevel@tonic-gate /* 12652*7c478bd9Sstevel@tonic-gate * If this is the first call to this function or gl_get_line(), 12653*7c478bd9Sstevel@tonic-gate * since new_GetLine(), complete any postponed configuration. 12654*7c478bd9Sstevel@tonic-gate */ 12655*7c478bd9Sstevel@tonic-gate if(!gl->configured) { 12656*7c478bd9Sstevel@tonic-gate (void) _gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE); 12657*7c478bd9Sstevel@tonic-gate gl->configured = 1; 12658*7c478bd9Sstevel@tonic-gate }; 12659*7c478bd9Sstevel@tonic-gate /* 12660*7c478bd9Sstevel@tonic-gate * Before installing our signal handler functions, record the fact 12661*7c478bd9Sstevel@tonic-gate * that there are no pending signals. 12662*7c478bd9Sstevel@tonic-gate */ 12663*7c478bd9Sstevel@tonic-gate gl_pending_signal = -1; 12664*7c478bd9Sstevel@tonic-gate /* 12665*7c478bd9Sstevel@tonic-gate * Temporarily override the signal handlers of the calling program, 12666*7c478bd9Sstevel@tonic-gate * so that we can intercept signals that would leave the terminal 12667*7c478bd9Sstevel@tonic-gate * in a bad state. 12668*7c478bd9Sstevel@tonic-gate */ 12669*7c478bd9Sstevel@tonic-gate if(!was_overriden) 12670*7c478bd9Sstevel@tonic-gate waserr = gl_override_signal_handlers(gl); 12671*7c478bd9Sstevel@tonic-gate /* 12672*7c478bd9Sstevel@tonic-gate * After recording the current terminal settings, switch the terminal 12673*7c478bd9Sstevel@tonic-gate * into raw input mode, without redisplaying any partially entered input 12674*7c478bd9Sstevel@tonic-gate * line. 12675*7c478bd9Sstevel@tonic-gate */ 12676*7c478bd9Sstevel@tonic-gate if(!was_raw) 12677*7c478bd9Sstevel@tonic-gate waserr = waserr || _gl_raw_io(gl, 0); 12678*7c478bd9Sstevel@tonic-gate /* 12679*7c478bd9Sstevel@tonic-gate * Attempt to read the line. This will require more than one attempt if 12680*7c478bd9Sstevel@tonic-gate * either a current temporary input file is opened by gl_get_input_line() 12681*7c478bd9Sstevel@tonic-gate * or the end of a temporary input file is reached by gl_read_stream_line(). 12682*7c478bd9Sstevel@tonic-gate */ 12683*7c478bd9Sstevel@tonic-gate while(!waserr) { 12684*7c478bd9Sstevel@tonic-gate /* 12685*7c478bd9Sstevel@tonic-gate * Read a line from a non-interactive stream? 12686*7c478bd9Sstevel@tonic-gate */ 12687*7c478bd9Sstevel@tonic-gate if(gl->file_fp || !gl->is_term) { 12688*7c478bd9Sstevel@tonic-gate retval = gl_read_stream_char(gl); 12689*7c478bd9Sstevel@tonic-gate if(retval != EOF) { /* Success? */ 12690*7c478bd9Sstevel@tonic-gate break; 12691*7c478bd9Sstevel@tonic-gate } else if(gl->file_fp) { /* End of temporary input file? */ 12692*7c478bd9Sstevel@tonic-gate gl_revert_input(gl); 12693*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_NEWLINE, 0); 12694*7c478bd9Sstevel@tonic-gate } else { /* An error? */ 12695*7c478bd9Sstevel@tonic-gate waserr = 1; 12696*7c478bd9Sstevel@tonic-gate break; 12697*7c478bd9Sstevel@tonic-gate }; 12698*7c478bd9Sstevel@tonic-gate }; 12699*7c478bd9Sstevel@tonic-gate /* 12700*7c478bd9Sstevel@tonic-gate * Read from the terminal? Note that the above if() block may have 12701*7c478bd9Sstevel@tonic-gate * changed gl->file_fp, so it is necessary to retest it here, rather 12702*7c478bd9Sstevel@tonic-gate * than using an else statement. 12703*7c478bd9Sstevel@tonic-gate */ 12704*7c478bd9Sstevel@tonic-gate if(!gl->file_fp && gl->is_term) { 12705*7c478bd9Sstevel@tonic-gate /* 12706*7c478bd9Sstevel@tonic-gate * Flush any pending output to the terminal before waiting 12707*7c478bd9Sstevel@tonic-gate * for the user to type a character. 12708*7c478bd9Sstevel@tonic-gate */ 12709*7c478bd9Sstevel@tonic-gate if(_glq_char_count(gl->cq) > 0 && gl_flush_output(gl)) { 12710*7c478bd9Sstevel@tonic-gate retval = EOF; 12711*7c478bd9Sstevel@tonic-gate /* 12712*7c478bd9Sstevel@tonic-gate * Read one character. Don't append it to the key buffer, since 12713*7c478bd9Sstevel@tonic-gate * this would subseuqnely appear as bogus input to the line editor. 12714*7c478bd9Sstevel@tonic-gate */ 12715*7c478bd9Sstevel@tonic-gate } else if(gl_read_terminal(gl, 0, &c) == 0) { 12716*7c478bd9Sstevel@tonic-gate /* 12717*7c478bd9Sstevel@tonic-gate * Record the character for return. 12718*7c478bd9Sstevel@tonic-gate */ 12719*7c478bd9Sstevel@tonic-gate retval = c; 12720*7c478bd9Sstevel@tonic-gate /* 12721*7c478bd9Sstevel@tonic-gate * In this mode, count each character as being a new key-sequence. 12722*7c478bd9Sstevel@tonic-gate */ 12723*7c478bd9Sstevel@tonic-gate gl->keyseq_count++; 12724*7c478bd9Sstevel@tonic-gate /* 12725*7c478bd9Sstevel@tonic-gate * Delete the character that was read, from the key-press buffer. 12726*7c478bd9Sstevel@tonic-gate */ 12727*7c478bd9Sstevel@tonic-gate gl_discard_chars(gl, 1); 12728*7c478bd9Sstevel@tonic-gate }; 12729*7c478bd9Sstevel@tonic-gate if(retval==EOF) 12730*7c478bd9Sstevel@tonic-gate waserr = 1; 12731*7c478bd9Sstevel@tonic-gate else 12732*7c478bd9Sstevel@tonic-gate break; 12733*7c478bd9Sstevel@tonic-gate }; 12734*7c478bd9Sstevel@tonic-gate }; 12735*7c478bd9Sstevel@tonic-gate /* 12736*7c478bd9Sstevel@tonic-gate * If an error occurred, but gl->rtn_status is still set to 12737*7c478bd9Sstevel@tonic-gate * GLR_NEWLINE, change the status to GLR_ERROR. Otherwise 12738*7c478bd9Sstevel@tonic-gate * leave it at whatever specific value was assigned by the function 12739*7c478bd9Sstevel@tonic-gate * that aborted input. This means that only functions that trap 12740*7c478bd9Sstevel@tonic-gate * non-generic errors have to remember to update gl->rtn_status 12741*7c478bd9Sstevel@tonic-gate * themselves. 12742*7c478bd9Sstevel@tonic-gate */ 12743*7c478bd9Sstevel@tonic-gate if(waserr && gl->rtn_status == GLR_NEWLINE) 12744*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_ERROR, errno); 12745*7c478bd9Sstevel@tonic-gate /* 12746*7c478bd9Sstevel@tonic-gate * Restore terminal settings, if they were changed by this function. 12747*7c478bd9Sstevel@tonic-gate */ 12748*7c478bd9Sstevel@tonic-gate if(!was_raw && gl->io_mode != GL_SERVER_MODE) 12749*7c478bd9Sstevel@tonic-gate _gl_normal_io(gl); 12750*7c478bd9Sstevel@tonic-gate /* 12751*7c478bd9Sstevel@tonic-gate * Restore the signal handlers, if they were overriden by this function. 12752*7c478bd9Sstevel@tonic-gate */ 12753*7c478bd9Sstevel@tonic-gate if(!was_overriden) 12754*7c478bd9Sstevel@tonic-gate gl_restore_signal_handlers(gl); 12755*7c478bd9Sstevel@tonic-gate /* 12756*7c478bd9Sstevel@tonic-gate * If this function gets aborted early, the errno value associated 12757*7c478bd9Sstevel@tonic-gate * with the event that caused this to happen is recorded in 12758*7c478bd9Sstevel@tonic-gate * gl->rtn_errno. Since errno may have been overwritten by cleanup 12759*7c478bd9Sstevel@tonic-gate * functions after this, restore its value to the value that it had 12760*7c478bd9Sstevel@tonic-gate * when the error condition occured, so that the caller can examine it 12761*7c478bd9Sstevel@tonic-gate * to find out what happened. 12762*7c478bd9Sstevel@tonic-gate */ 12763*7c478bd9Sstevel@tonic-gate errno = gl->rtn_errno; 12764*7c478bd9Sstevel@tonic-gate /* 12765*7c478bd9Sstevel@tonic-gate * Error conditions are signalled to the caller, by setting the returned 12766*7c478bd9Sstevel@tonic-gate * character to EOF. 12767*7c478bd9Sstevel@tonic-gate */ 12768*7c478bd9Sstevel@tonic-gate if(gl->rtn_status != GLR_NEWLINE) 12769*7c478bd9Sstevel@tonic-gate retval = EOF; 12770*7c478bd9Sstevel@tonic-gate /* 12771*7c478bd9Sstevel@tonic-gate * Restore the indication of what direction of I/O gl_get_line() 12772*7c478bd9Sstevel@tonic-gate * was awaiting before this call. 12773*7c478bd9Sstevel@tonic-gate */ 12774*7c478bd9Sstevel@tonic-gate gl->pending_io = old_pending_io; 12775*7c478bd9Sstevel@tonic-gate /* 12776*7c478bd9Sstevel@tonic-gate * Return the acquired character. 12777*7c478bd9Sstevel@tonic-gate */ 12778*7c478bd9Sstevel@tonic-gate return retval; 12779*7c478bd9Sstevel@tonic-gate } 12780*7c478bd9Sstevel@tonic-gate 12781*7c478bd9Sstevel@tonic-gate /*....................................................................... 12782*7c478bd9Sstevel@tonic-gate * Reset the GetLine completion status. This function should be called 12783*7c478bd9Sstevel@tonic-gate * at the start of gl_get_line(), gl_read_char() and gl_query_char() 12784*7c478bd9Sstevel@tonic-gate * to discard the completion status and non-zero errno value of any 12785*7c478bd9Sstevel@tonic-gate * preceding calls to these functions. 12786*7c478bd9Sstevel@tonic-gate * 12787*7c478bd9Sstevel@tonic-gate * Input: 12788*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this module. 12789*7c478bd9Sstevel@tonic-gate */ 12790*7c478bd9Sstevel@tonic-gate static void gl_clear_status(GetLine *gl) 12791*7c478bd9Sstevel@tonic-gate { 12792*7c478bd9Sstevel@tonic-gate gl_record_status(gl, GLR_NEWLINE, 0); 12793*7c478bd9Sstevel@tonic-gate } 12794*7c478bd9Sstevel@tonic-gate 12795*7c478bd9Sstevel@tonic-gate /*....................................................................... 12796*7c478bd9Sstevel@tonic-gate * When an error or other event causes gl_get_line() to return, this 12797*7c478bd9Sstevel@tonic-gate * function should be called to record information about what 12798*7c478bd9Sstevel@tonic-gate * happened, including the value of errno and the value that 12799*7c478bd9Sstevel@tonic-gate * gl_return_status() should return. 12800*7c478bd9Sstevel@tonic-gate * 12801*7c478bd9Sstevel@tonic-gate * Input: 12802*7c478bd9Sstevel@tonic-gate * gl GetLine * The resource object of this module. 12803*7c478bd9Sstevel@tonic-gate * rtn_status GlReturnStatus The completion status. To clear a 12804*7c478bd9Sstevel@tonic-gate * previous abnormal completion status, 12805*7c478bd9Sstevel@tonic-gate * specify GLR_NEWLINE (this is what 12806*7c478bd9Sstevel@tonic-gate * gl_clear_status() does). 12807*7c478bd9Sstevel@tonic-gate * rtn_errno int The associated value of errno. 12808*7c478bd9Sstevel@tonic-gate */ 12809*7c478bd9Sstevel@tonic-gate static void gl_record_status(GetLine *gl, GlReturnStatus rtn_status, 12810*7c478bd9Sstevel@tonic-gate int rtn_errno) 12811*7c478bd9Sstevel@tonic-gate { 12812*7c478bd9Sstevel@tonic-gate /* 12813*7c478bd9Sstevel@tonic-gate * If rtn_status==GLR_NEWLINE, then this resets the completion status, so we 12814*7c478bd9Sstevel@tonic-gate * should always heed this. Otherwise, only record the first abnormal 12815*7c478bd9Sstevel@tonic-gate * condition that occurs after such a reset. 12816*7c478bd9Sstevel@tonic-gate */ 12817*7c478bd9Sstevel@tonic-gate if(rtn_status == GLR_NEWLINE || gl->rtn_status == GLR_NEWLINE) { 12818*7c478bd9Sstevel@tonic-gate gl->rtn_status = rtn_status; 12819*7c478bd9Sstevel@tonic-gate gl->rtn_errno = rtn_errno; 12820*7c478bd9Sstevel@tonic-gate }; 12821*7c478bd9Sstevel@tonic-gate } 12822*7c478bd9Sstevel@tonic-gate 12823