#ifndef lint
|
#ifndef lint
|
static char rcsid[] =
|
static char rcsid[] =
|
"$Id: getline.c,v 3.11 1993/12/02 15:54:31 thewalt Exp thewalt $";
|
"$Id: getline.c,v 3.11 1993/12/02 15:54:31 thewalt Exp thewalt $";
|
static char *copyright = "Copyright (C) 1991, 1992, 1993, Chris Thewalt";
|
static char *copyright = "Copyright (C) 1991, 1992, 1993, Chris Thewalt";
|
#endif
|
#endif
|
|
|
/*
|
/*
|
* Copyright (C) 1991, 1992, 1993 by Chris Thewalt (thewalt@ce.berkeley.edu)
|
* Copyright (C) 1991, 1992, 1993 by Chris Thewalt (thewalt@ce.berkeley.edu)
|
*
|
*
|
* Permission to use, copy, modify, and distribute this software
|
* Permission to use, copy, modify, and distribute this software
|
* for any purpose and without fee is hereby granted, provided
|
* for any purpose and without fee is hereby granted, provided
|
* that the above copyright notices appear in all copies and that both the
|
* that the above copyright notices appear in all copies and that both the
|
* copyright notice and this permission notice appear in supporting
|
* copyright notice and this permission notice appear in supporting
|
* documentation. This software is provided "as is" without express or
|
* documentation. This software is provided "as is" without express or
|
* implied warranty.
|
* implied warranty.
|
*
|
*
|
* Thanks to the following people who have provided enhancements and fixes:
|
* Thanks to the following people who have provided enhancements and fixes:
|
* Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List,
|
* Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List,
|
* DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten,
|
* DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten,
|
* Edin Hodzic, Eric J Bivona, Kai Uwe Rommel, Danny Quah, Ulrich Betzler
|
* Edin Hodzic, Eric J Bivona, Kai Uwe Rommel, Danny Quah, Ulrich Betzler
|
*/
|
*/
|
|
|
#include "getline.h"
|
#include "getline.h"
|
static int gl_tab(); /* forward reference needed for gl_tab_hook */
|
static int gl_tab(); /* forward reference needed for gl_tab_hook */
|
|
|
/******************** imported interface *********************************/
|
/******************** imported interface *********************************/
|
|
|
#include <string.h>
|
#include <string.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
#include <errno.h>
|
#include <errno.h>
|
#include <signal.h>
|
#include <signal.h>
|
|
|
extern int isatty();
|
extern int isatty();
|
extern void *malloc();
|
extern void *malloc();
|
extern void free();
|
extern void free();
|
|
|
/********************* exported interface ********************************/
|
/********************* exported interface ********************************/
|
|
|
char *gl_getline(); /* read a line of input */
|
char *gl_getline(); /* read a line of input */
|
void gl_setwidth(); /* specify width of screen */
|
void gl_setwidth(); /* specify width of screen */
|
void gl_histadd(); /* adds entries to hist */
|
void gl_histadd(); /* adds entries to hist */
|
void gl_strwidth(); /* to bind gl_strlen */
|
void gl_strwidth(); /* to bind gl_strlen */
|
|
|
int (*gl_in_hook)() = 0;
|
int (*gl_in_hook)() = 0;
|
int (*gl_out_hook)() = 0;
|
int (*gl_out_hook)() = 0;
|
int (*gl_tab_hook)() = gl_tab;
|
int (*gl_tab_hook)() = gl_tab;
|
|
|
/******************** internal interface *********************************/
|
/******************** internal interface *********************************/
|
|
|
#define BUF_SIZE 1024
|
#define BUF_SIZE 1024
|
|
|
static int gl_init_done = -1; /* terminal mode flag */
|
static int gl_init_done = -1; /* terminal mode flag */
|
static int gl_termw = 80; /* actual terminal width */
|
static int gl_termw = 80; /* actual terminal width */
|
static int gl_scroll = 27; /* width of EOL scrolling region */
|
static int gl_scroll = 27; /* width of EOL scrolling region */
|
static int gl_width = 0; /* net size available for input */
|
static int gl_width = 0; /* net size available for input */
|
static int gl_extent = 0; /* how far to redraw, 0 means all */
|
static int gl_extent = 0; /* how far to redraw, 0 means all */
|
static int gl_overwrite = 0; /* overwrite mode */
|
static int gl_overwrite = 0; /* overwrite mode */
|
static int gl_pos, gl_cnt = 0; /* position and size of input */
|
static int gl_pos, gl_cnt = 0; /* position and size of input */
|
static char gl_buf[BUF_SIZE]; /* input buffer */
|
static char gl_buf[BUF_SIZE]; /* input buffer */
|
static char gl_killbuf[BUF_SIZE]=""; /* killed text */
|
static char gl_killbuf[BUF_SIZE]=""; /* killed text */
|
static char *gl_prompt; /* to save the prompt string */
|
static char *gl_prompt; /* to save the prompt string */
|
static char gl_intrc = 0; /* keyboard SIGINT char */
|
static char gl_intrc = 0; /* keyboard SIGINT char */
|
static char gl_quitc = 0; /* keyboard SIGQUIT char */
|
static char gl_quitc = 0; /* keyboard SIGQUIT char */
|
static char gl_suspc = 0; /* keyboard SIGTSTP char */
|
static char gl_suspc = 0; /* keyboard SIGTSTP char */
|
static char gl_dsuspc = 0; /* delayed SIGTSTP char */
|
static char gl_dsuspc = 0; /* delayed SIGTSTP char */
|
static int gl_search_mode = 0; /* search mode flag */
|
static int gl_search_mode = 0; /* search mode flag */
|
|
|
static void gl_init(); /* prepare to edit a line */
|
static void gl_init(); /* prepare to edit a line */
|
static void gl_cleanup(); /* to undo gl_init */
|
static void gl_cleanup(); /* to undo gl_init */
|
static void gl_char_init(); /* get ready for no echo input */
|
static void gl_char_init(); /* get ready for no echo input */
|
static void gl_char_cleanup(); /* undo gl_char_init */
|
static void gl_char_cleanup(); /* undo gl_char_init */
|
static size_t (*gl_strlen)() = (size_t(*)())strlen;
|
static size_t (*gl_strlen)() = (size_t(*)())strlen;
|
/* returns printable prompt width */
|
/* returns printable prompt width */
|
|
|
static void gl_addchar(); /* install specified char */
|
static void gl_addchar(); /* install specified char */
|
static void gl_del(); /* del, either left (-1) or cur (0) */
|
static void gl_del(); /* del, either left (-1) or cur (0) */
|
static void gl_error(); /* write error msg and die */
|
static void gl_error(); /* write error msg and die */
|
static void gl_fixup(); /* fixup state variables and screen */
|
static void gl_fixup(); /* fixup state variables and screen */
|
static int gl_getc(); /* read one char from terminal */
|
static int gl_getc(); /* read one char from terminal */
|
static void gl_kill(); /* delete to EOL */
|
static void gl_kill(); /* delete to EOL */
|
static void gl_newline(); /* handle \n or \r */
|
static void gl_newline(); /* handle \n or \r */
|
static void gl_putc(); /* write one char to terminal */
|
static void gl_putc(); /* write one char to terminal */
|
static void gl_puts(); /* write a line to terminal */
|
static void gl_puts(); /* write a line to terminal */
|
static void gl_redraw(); /* issue \n and redraw all */
|
static void gl_redraw(); /* issue \n and redraw all */
|
static void gl_transpose(); /* transpose two chars */
|
static void gl_transpose(); /* transpose two chars */
|
static void gl_yank(); /* yank killed text */
|
static void gl_yank(); /* yank killed text */
|
static void gl_word(); /* move a word */
|
static void gl_word(); /* move a word */
|
|
|
static void hist_init(); /* initializes hist pointers */
|
static void hist_init(); /* initializes hist pointers */
|
static char *hist_next(); /* return ptr to next item */
|
static char *hist_next(); /* return ptr to next item */
|
static char *hist_prev(); /* return ptr to prev item */
|
static char *hist_prev(); /* return ptr to prev item */
|
static char *hist_save(); /* makes copy of a string, without NL */
|
static char *hist_save(); /* makes copy of a string, without NL */
|
|
|
static void search_addchar(); /* increment search string */
|
static void search_addchar(); /* increment search string */
|
static void search_term(); /* reset with current contents */
|
static void search_term(); /* reset with current contents */
|
static void search_back(); /* look back for current string */
|
static void search_back(); /* look back for current string */
|
static void search_forw(); /* look forw for current string */
|
static void search_forw(); /* look forw for current string */
|
|
|
/************************ nonportable part *********************************/
|
/************************ nonportable part *********************************/
|
|
|
extern int write();
|
extern int write();
|
extern void exit();
|
extern void exit();
|
|
|
#ifdef unix
|
#ifdef unix
|
#ifndef __unix__
|
#ifndef __unix__
|
#define __unix__
|
#define __unix__
|
#endif /* not __unix__ */
|
#endif /* not __unix__ */
|
#endif /* unix */
|
#endif /* unix */
|
|
|
#ifdef _IBMR2
|
#ifdef _IBMR2
|
#ifndef __unix__
|
#ifndef __unix__
|
#define __unix__
|
#define __unix__
|
#endif
|
#endif
|
#endif
|
#endif
|
|
|
#ifdef __GO32__
|
#ifdef __GO32__
|
#include <pc.h>
|
#include <pc.h>
|
#undef MSDOS
|
#undef MSDOS
|
#undef __unix__
|
#undef __unix__
|
#endif
|
#endif
|
|
|
#ifdef MSDOS
|
#ifdef MSDOS
|
#include <bios.h>
|
#include <bios.h>
|
#endif
|
#endif
|
|
|
#ifdef __unix__
|
#ifdef __unix__
|
#ifndef __convexc__
|
#ifndef __convexc__
|
extern int read();
|
extern int read();
|
extern int kill();
|
extern int kill();
|
extern int ioctl();
|
extern int ioctl();
|
#endif /* not __convexc__ */
|
#endif /* not __convexc__ */
|
#ifdef POSIX /* use POSIX interface */
|
#ifdef POSIX /* use POSIX interface */
|
#include <termios.h>
|
#include <termios.h>
|
struct termios new_termios, old_termios;
|
struct termios new_termios, old_termios;
|
#else /* not POSIX */
|
#else /* not POSIX */
|
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
#ifdef M_XENIX /* does not really use bsd terminal interface */
|
#ifdef M_XENIX /* does not really use bsd terminal interface */
|
#undef TIOCSETN
|
#undef TIOCSETN
|
#endif /* M_XENIX */
|
#endif /* M_XENIX */
|
#ifdef TIOCSETN /* use BSD interface */
|
#ifdef TIOCSETN /* use BSD interface */
|
#include <sgtty.h>
|
#include <sgtty.h>
|
struct sgttyb new_tty, old_tty;
|
struct sgttyb new_tty, old_tty;
|
struct tchars tch;
|
struct tchars tch;
|
struct ltchars ltch;
|
struct ltchars ltch;
|
#else /* use SYSV interface */
|
#else /* use SYSV interface */
|
#include <termio.h>
|
#include <termio.h>
|
struct termio new_termio, old_termio;
|
struct termio new_termio, old_termio;
|
#endif /* TIOCSETN */
|
#endif /* TIOCSETN */
|
#endif /* POSIX */
|
#endif /* POSIX */
|
#endif /* __unix__ */
|
#endif /* __unix__ */
|
|
|
#ifdef vms
|
#ifdef vms
|
#include <descrip.h>
|
#include <descrip.h>
|
#include <ttdef.h>
|
#include <ttdef.h>
|
#include <iodef.h>
|
#include <iodef.h>
|
#include unixio
|
#include unixio
|
|
|
static int setbuff[2]; /* buffer to set terminal attributes */
|
static int setbuff[2]; /* buffer to set terminal attributes */
|
static short chan = -1; /* channel to terminal */
|
static short chan = -1; /* channel to terminal */
|
struct dsc$descriptor_s descrip; /* VMS descriptor */
|
struct dsc$descriptor_s descrip; /* VMS descriptor */
|
#endif
|
#endif
|
|
|
static void
|
static void
|
gl_char_init() /* turn off input echo */
|
gl_char_init() /* turn off input echo */
|
{
|
{
|
#ifdef __unix__
|
#ifdef __unix__
|
#ifdef POSIX
|
#ifdef POSIX
|
tcgetattr(0, &old_termios);
|
tcgetattr(0, &old_termios);
|
gl_intrc = old_termios.c_cc[VINTR];
|
gl_intrc = old_termios.c_cc[VINTR];
|
gl_quitc = old_termios.c_cc[VQUIT];
|
gl_quitc = old_termios.c_cc[VQUIT];
|
#ifdef VSUSP
|
#ifdef VSUSP
|
gl_suspc = old_termios.c_cc[VSUSP];
|
gl_suspc = old_termios.c_cc[VSUSP];
|
#endif
|
#endif
|
#ifdef VDSUSP
|
#ifdef VDSUSP
|
gl_dsuspc = old_termios.c_cc[VDSUSP];
|
gl_dsuspc = old_termios.c_cc[VDSUSP];
|
#endif
|
#endif
|
new_termios = old_termios;
|
new_termios = old_termios;
|
new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
|
new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
|
new_termios.c_iflag |= (IGNBRK|IGNPAR);
|
new_termios.c_iflag |= (IGNBRK|IGNPAR);
|
new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
|
new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
|
new_termios.c_cc[VMIN] = 1;
|
new_termios.c_cc[VMIN] = 1;
|
new_termios.c_cc[VTIME] = 0;
|
new_termios.c_cc[VTIME] = 0;
|
tcsetattr(0, TCSANOW, &new_termios);
|
tcsetattr(0, TCSANOW, &new_termios);
|
#else /* not POSIX */
|
#else /* not POSIX */
|
#ifdef TIOCSETN /* BSD */
|
#ifdef TIOCSETN /* BSD */
|
ioctl(0, TIOCGETC, &tch);
|
ioctl(0, TIOCGETC, &tch);
|
ioctl(0, TIOCGLTC, <ch);
|
ioctl(0, TIOCGLTC, <ch);
|
gl_intrc = tch.t_intrc;
|
gl_intrc = tch.t_intrc;
|
gl_quitc = tch.t_quitc;
|
gl_quitc = tch.t_quitc;
|
gl_suspc = ltch.t_suspc;
|
gl_suspc = ltch.t_suspc;
|
gl_dsuspc = ltch.t_dsuspc;
|
gl_dsuspc = ltch.t_dsuspc;
|
ioctl(0, TIOCGETP, &old_tty);
|
ioctl(0, TIOCGETP, &old_tty);
|
new_tty = old_tty;
|
new_tty = old_tty;
|
new_tty.sg_flags |= RAW;
|
new_tty.sg_flags |= RAW;
|
new_tty.sg_flags &= ~ECHO;
|
new_tty.sg_flags &= ~ECHO;
|
ioctl(0, TIOCSETN, &new_tty);
|
ioctl(0, TIOCSETN, &new_tty);
|
#else /* SYSV */
|
#else /* SYSV */
|
ioctl(0, TCGETA, &old_termio);
|
ioctl(0, TCGETA, &old_termio);
|
gl_intrc = old_termio.c_cc[VINTR];
|
gl_intrc = old_termio.c_cc[VINTR];
|
gl_quitc = old_termio.c_cc[VQUIT];
|
gl_quitc = old_termio.c_cc[VQUIT];
|
new_termio = old_termio;
|
new_termio = old_termio;
|
new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
|
new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
|
new_termio.c_iflag |= (IGNBRK|IGNPAR);
|
new_termio.c_iflag |= (IGNBRK|IGNPAR);
|
new_termio.c_lflag &= ~(ICANON|ISIG|ECHO);
|
new_termio.c_lflag &= ~(ICANON|ISIG|ECHO);
|
new_termio.c_cc[VMIN] = 1;
|
new_termio.c_cc[VMIN] = 1;
|
new_termio.c_cc[VTIME] = 0;
|
new_termio.c_cc[VTIME] = 0;
|
ioctl(0, TCSETA, &new_termio);
|
ioctl(0, TCSETA, &new_termio);
|
#endif /* TIOCSETN */
|
#endif /* TIOCSETN */
|
#endif /* POSIX */
|
#endif /* POSIX */
|
#endif /* __unix__ */
|
#endif /* __unix__ */
|
|
|
#ifdef vms
|
#ifdef vms
|
descrip.dsc$w_length = strlen("tt:");
|
descrip.dsc$w_length = strlen("tt:");
|
descrip.dsc$b_dtype = DSC$K_DTYPE_T;
|
descrip.dsc$b_dtype = DSC$K_DTYPE_T;
|
descrip.dsc$b_class = DSC$K_CLASS_S;
|
descrip.dsc$b_class = DSC$K_CLASS_S;
|
descrip.dsc$a_pointer = "tt:";
|
descrip.dsc$a_pointer = "tt:";
|
(void)sys$assign(&descrip,&chan,0,0);
|
(void)sys$assign(&descrip,&chan,0,0);
|
(void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0);
|
(void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0);
|
setbuff[1] |= TT$M_NOECHO;
|
setbuff[1] |= TT$M_NOECHO;
|
(void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
|
(void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
|
#endif /* vms */
|
#endif /* vms */
|
}
|
}
|
|
|
static void
|
static void
|
gl_char_cleanup() /* undo effects of gl_char_init */
|
gl_char_cleanup() /* undo effects of gl_char_init */
|
{
|
{
|
#ifdef __unix__
|
#ifdef __unix__
|
#ifdef POSIX
|
#ifdef POSIX
|
tcsetattr(0, TCSANOW, &old_termios);
|
tcsetattr(0, TCSANOW, &old_termios);
|
#else /* not POSIX */
|
#else /* not POSIX */
|
#ifdef TIOCSETN /* BSD */
|
#ifdef TIOCSETN /* BSD */
|
ioctl(0, TIOCSETN, &old_tty);
|
ioctl(0, TIOCSETN, &old_tty);
|
#else /* SYSV */
|
#else /* SYSV */
|
ioctl(0, TCSETA, &old_termio);
|
ioctl(0, TCSETA, &old_termio);
|
#endif /* TIOCSETN */
|
#endif /* TIOCSETN */
|
#endif /* POSIX */
|
#endif /* POSIX */
|
#endif /* __unix__ */
|
#endif /* __unix__ */
|
|
|
#ifdef vms
|
#ifdef vms
|
setbuff[1] &= ~TT$M_NOECHO;
|
setbuff[1] &= ~TT$M_NOECHO;
|
(void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
|
(void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
|
sys$dassgn(chan);
|
sys$dassgn(chan);
|
chan = -1;
|
chan = -1;
|
#endif
|
#endif
|
}
|
}
|
|
|
#if MSDOS || __EMX__ || __GO32__
|
#if MSDOS || __EMX__ || __GO32__
|
int pc_keymap(c)
|
int pc_keymap(c)
|
int c;
|
int c;
|
{
|
{
|
switch (c) {
|
switch (c) {
|
case 72: c = 16; /* up -> ^P */
|
case 72: c = 16; /* up -> ^P */
|
break;
|
break;
|
case 80: c = 14; /* down -> ^N */
|
case 80: c = 14; /* down -> ^N */
|
break;
|
break;
|
case 75: c = 2; /* left -> ^B */
|
case 75: c = 2; /* left -> ^B */
|
break;
|
break;
|
case 77: c = 6; /* right -> ^F */
|
case 77: c = 6; /* right -> ^F */
|
break;
|
break;
|
default: c = 0; /* make it garbage */
|
default: c = 0; /* make it garbage */
|
}
|
}
|
return c;
|
return c;
|
}
|
}
|
#endif /* MSDOS || __EMX__ || __GO32__ */
|
#endif /* MSDOS || __EMX__ || __GO32__ */
|
|
|
static int
|
static int
|
gl_getc()
|
gl_getc()
|
/* get a character without echoing it to screen */
|
/* get a character without echoing it to screen */
|
{
|
{
|
int c;
|
int c;
|
#ifdef __unix__
|
#ifdef __unix__
|
char ch;
|
char ch;
|
#endif
|
#endif
|
|
|
#ifdef __unix__
|
#ifdef __unix__
|
while ((c = read(0, &ch, 1)) == -1) {
|
while ((c = read(0, &ch, 1)) == -1) {
|
if (errno != EINTR)
|
if (errno != EINTR)
|
break;
|
break;
|
}
|
}
|
c = (ch <= 0)? -1 : ch;
|
c = (ch <= 0)? -1 : ch;
|
#endif /* __unix__ */
|
#endif /* __unix__ */
|
#ifdef MSDOS
|
#ifdef MSDOS
|
c = _bios_keybrd(_NKEYBRD_READ);
|
c = _bios_keybrd(_NKEYBRD_READ);
|
#endif /* MSDOS */
|
#endif /* MSDOS */
|
#ifdef __GO32__
|
#ifdef __GO32__
|
c = getkey () ;
|
c = getkey () ;
|
if (c > 255) c = pc_keymap(c & 0377);
|
if (c > 255) c = pc_keymap(c & 0377);
|
#endif /* __GO32__ */
|
#endif /* __GO32__ */
|
#ifdef __TURBOC__
|
#ifdef __TURBOC__
|
while(!bioskey(1))
|
while(!bioskey(1))
|
;
|
;
|
c = bioskey(0);
|
c = bioskey(0);
|
#endif
|
#endif
|
#if MSDOS || __TURBOC__
|
#if MSDOS || __TURBOC__
|
if ((c & 0377) == 224) {
|
if ((c & 0377) == 224) {
|
c = pc_keymap((c >> 8) & 0377);
|
c = pc_keymap((c >> 8) & 0377);
|
} else {
|
} else {
|
c &= 0377;
|
c &= 0377;
|
}
|
}
|
#endif /* MSDOS || __TURBOC__ */
|
#endif /* MSDOS || __TURBOC__ */
|
#ifdef __EMX__
|
#ifdef __EMX__
|
c = _read_kbd(0, 1, 0);
|
c = _read_kbd(0, 1, 0);
|
if (c == 224 || c == 0) {
|
if (c == 224 || c == 0) {
|
c = pc_keymap(_read_kbd(0, 1, 0));
|
c = pc_keymap(_read_kbd(0, 1, 0));
|
} else {
|
} else {
|
c &= 0377;
|
c &= 0377;
|
}
|
}
|
#endif
|
#endif
|
#ifdef vms
|
#ifdef vms
|
if(chan < 0) {
|
if(chan < 0) {
|
c='\0';
|
c='\0';
|
}
|
}
|
(void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0);
|
(void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0);
|
c &= 0177; /* get a char */
|
c &= 0177; /* get a char */
|
#endif
|
#endif
|
return c;
|
return c;
|
}
|
}
|
|
|
static void
|
static void
|
gl_putc(c)
|
gl_putc(c)
|
int c;
|
int c;
|
{
|
{
|
char ch = c;
|
char ch = c;
|
|
|
write(1, &ch, 1);
|
write(1, &ch, 1);
|
if (ch == '\n') {
|
if (ch == '\n') {
|
ch = '\r';
|
ch = '\r';
|
write(1, &ch, 1); /* RAW mode needs '\r', does not hurt */
|
write(1, &ch, 1); /* RAW mode needs '\r', does not hurt */
|
}
|
}
|
}
|
}
|
|
|
/******************** fairly portable part *********************************/
|
/******************** fairly portable part *********************************/
|
|
|
static void
|
static void
|
gl_puts(buf)
|
gl_puts(buf)
|
char *buf;
|
char *buf;
|
{
|
{
|
int len;
|
int len;
|
|
|
if (buf) {
|
if (buf) {
|
len = strlen(buf);
|
len = strlen(buf);
|
write(1, buf, len);
|
write(1, buf, len);
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
gl_error(buf)
|
gl_error(buf)
|
char *buf;
|
char *buf;
|
{
|
{
|
int len = strlen(buf);
|
int len = strlen(buf);
|
|
|
gl_cleanup();
|
gl_cleanup();
|
write(2, buf, len);
|
write(2, buf, len);
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
static void
|
static void
|
gl_init()
|
gl_init()
|
/* set up variables and terminal */
|
/* set up variables and terminal */
|
{
|
{
|
if (gl_init_done < 0) { /* -1 only on startup */
|
if (gl_init_done < 0) { /* -1 only on startup */
|
hist_init();
|
hist_init();
|
}
|
}
|
if (isatty(0) == 0 || isatty(1) == 0)
|
if (isatty(0) == 0 || isatty(1) == 0)
|
gl_error("\n*** Error: getline(): not interactive, use stdio.\n");
|
gl_error("\n*** Error: getline(): not interactive, use stdio.\n");
|
gl_char_init();
|
gl_char_init();
|
gl_init_done = 1;
|
gl_init_done = 1;
|
}
|
}
|
|
|
static void
|
static void
|
gl_cleanup()
|
gl_cleanup()
|
/* undo effects of gl_init, as necessary */
|
/* undo effects of gl_init, as necessary */
|
{
|
{
|
if (gl_init_done > 0)
|
if (gl_init_done > 0)
|
gl_char_cleanup();
|
gl_char_cleanup();
|
gl_init_done = 0;
|
gl_init_done = 0;
|
}
|
}
|
|
|
void
|
void
|
gl_setwidth(w)
|
gl_setwidth(w)
|
int w;
|
int w;
|
{
|
{
|
if (w > 20) {
|
if (w > 20) {
|
gl_termw = w;
|
gl_termw = w;
|
gl_scroll = w / 3;
|
gl_scroll = w / 3;
|
} else {
|
} else {
|
gl_error("\n*** Error: minimum screen width is 21\n");
|
gl_error("\n*** Error: minimum screen width is 21\n");
|
}
|
}
|
}
|
}
|
|
|
char *
|
char *
|
gl_getline(prompt)
|
gl_getline(prompt)
|
char *prompt;
|
char *prompt;
|
{
|
{
|
int c, loc, tmp;
|
int c, loc, tmp;
|
|
|
#ifdef __unix__
|
#ifdef __unix__
|
int sig;
|
int sig;
|
#endif
|
#endif
|
|
|
gl_init();
|
gl_init();
|
gl_prompt = (prompt)? prompt : "";
|
gl_prompt = (prompt)? prompt : "";
|
gl_buf[0] = 0;
|
gl_buf[0] = 0;
|
if (gl_in_hook)
|
if (gl_in_hook)
|
gl_in_hook(gl_buf);
|
gl_in_hook(gl_buf);
|
gl_fixup(gl_prompt, -2, BUF_SIZE);
|
gl_fixup(gl_prompt, -2, BUF_SIZE);
|
while ((c = gl_getc()) >= 0) {
|
while ((c = gl_getc()) >= 0) {
|
gl_extent = 0; /* reset to full extent */
|
gl_extent = 0; /* reset to full extent */
|
if (isprint(c)) {
|
if (isprint(c)) {
|
if (gl_search_mode)
|
if (gl_search_mode)
|
search_addchar(c);
|
search_addchar(c);
|
else
|
else
|
gl_addchar(c);
|
gl_addchar(c);
|
} else {
|
} else {
|
if (gl_search_mode) {
|
if (gl_search_mode) {
|
if (c == '\033' || c == '\016' || c == '\020') {
|
if (c == '\033' || c == '\016' || c == '\020') {
|
search_term();
|
search_term();
|
c = 0; /* ignore the character */
|
c = 0; /* ignore the character */
|
} else if (c == '\010' || c == '\177') {
|
} else if (c == '\010' || c == '\177') {
|
search_addchar(-1); /* unwind search string */
|
search_addchar(-1); /* unwind search string */
|
c = 0;
|
c = 0;
|
} else if (c != '\022' && c != '\023') {
|
} else if (c != '\022' && c != '\023') {
|
search_term(); /* terminate and handle char */
|
search_term(); /* terminate and handle char */
|
}
|
}
|
}
|
}
|
switch (c) {
|
switch (c) {
|
case '\n': case '\r': /* newline */
|
case '\n': case '\r': /* newline */
|
gl_newline();
|
gl_newline();
|
gl_cleanup();
|
gl_cleanup();
|
return gl_buf;
|
return gl_buf;
|
/*NOTREACHED*/
|
/*NOTREACHED*/
|
break;
|
break;
|
case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */
|
case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */
|
break;
|
break;
|
case '\002': gl_fixup(gl_prompt, -1, gl_pos-1); /* ^B */
|
case '\002': gl_fixup(gl_prompt, -1, gl_pos-1); /* ^B */
|
break;
|
break;
|
case '\004': /* ^D */
|
case '\004': /* ^D */
|
if (gl_cnt == 0) {
|
if (gl_cnt == 0) {
|
gl_buf[0] = 0;
|
gl_buf[0] = 0;
|
gl_cleanup();
|
gl_cleanup();
|
gl_putc('\n');
|
gl_putc('\n');
|
return gl_buf;
|
return gl_buf;
|
} else {
|
} else {
|
gl_del(0);
|
gl_del(0);
|
}
|
}
|
break;
|
break;
|
case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */
|
case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */
|
break;
|
break;
|
case '\006': gl_fixup(gl_prompt, -1, gl_pos+1); /* ^F */
|
case '\006': gl_fixup(gl_prompt, -1, gl_pos+1); /* ^F */
|
break;
|
break;
|
case '\010': case '\177': gl_del(-1); /* ^H and DEL */
|
case '\010': case '\177': gl_del(-1); /* ^H and DEL */
|
break;
|
break;
|
case '\t': /* TAB */
|
case '\t': /* TAB */
|
if (gl_tab_hook) {
|
if (gl_tab_hook) {
|
tmp = gl_pos;
|
tmp = gl_pos;
|
loc = gl_tab_hook(gl_buf, gl_strlen(gl_prompt), &tmp);
|
loc = gl_tab_hook(gl_buf, gl_strlen(gl_prompt), &tmp);
|
if (loc >= 0 || tmp != gl_pos)
|
if (loc >= 0 || tmp != gl_pos)
|
gl_fixup(gl_prompt, loc, tmp);
|
gl_fixup(gl_prompt, loc, tmp);
|
}
|
}
|
break;
|
break;
|
case '\013': gl_kill(gl_pos); /* ^K */
|
case '\013': gl_kill(gl_pos); /* ^K */
|
break;
|
break;
|
case '\014': gl_redraw(); /* ^L */
|
case '\014': gl_redraw(); /* ^L */
|
break;
|
break;
|
case '\016': /* ^N */
|
case '\016': /* ^N */
|
strcpy(gl_buf, hist_next());
|
strcpy(gl_buf, hist_next());
|
if (gl_in_hook)
|
if (gl_in_hook)
|
gl_in_hook(gl_buf);
|
gl_in_hook(gl_buf);
|
gl_fixup(gl_prompt, 0, BUF_SIZE);
|
gl_fixup(gl_prompt, 0, BUF_SIZE);
|
break;
|
break;
|
case '\017': gl_overwrite = !gl_overwrite; /* ^O */
|
case '\017': gl_overwrite = !gl_overwrite; /* ^O */
|
break;
|
break;
|
case '\020': /* ^P */
|
case '\020': /* ^P */
|
strcpy(gl_buf, hist_prev());
|
strcpy(gl_buf, hist_prev());
|
if (gl_in_hook)
|
if (gl_in_hook)
|
gl_in_hook(gl_buf);
|
gl_in_hook(gl_buf);
|
gl_fixup(gl_prompt, 0, BUF_SIZE);
|
gl_fixup(gl_prompt, 0, BUF_SIZE);
|
break;
|
break;
|
case '\022': search_back(1); /* ^R */
|
case '\022': search_back(1); /* ^R */
|
break;
|
break;
|
case '\023': search_forw(1); /* ^S */
|
case '\023': search_forw(1); /* ^S */
|
break;
|
break;
|
case '\024': gl_transpose(); /* ^T */
|
case '\024': gl_transpose(); /* ^T */
|
break;
|
break;
|
case '\025': gl_kill(0); /* ^U */
|
case '\025': gl_kill(0); /* ^U */
|
break;
|
break;
|
case '\031': gl_yank(); /* ^Y */
|
case '\031': gl_yank(); /* ^Y */
|
break;
|
break;
|
case '\033': /* ansi arrow keys */
|
case '\033': /* ansi arrow keys */
|
c = gl_getc();
|
c = gl_getc();
|
if (c == '[') {
|
if (c == '[') {
|
switch(c = gl_getc()) {
|
switch(c = gl_getc()) {
|
case 'A': /* up */
|
case 'A': /* up */
|
strcpy(gl_buf, hist_prev());
|
strcpy(gl_buf, hist_prev());
|
if (gl_in_hook)
|
if (gl_in_hook)
|
gl_in_hook(gl_buf);
|
gl_in_hook(gl_buf);
|
gl_fixup(gl_prompt, 0, BUF_SIZE);
|
gl_fixup(gl_prompt, 0, BUF_SIZE);
|
break;
|
break;
|
case 'B': /* down */
|
case 'B': /* down */
|
strcpy(gl_buf, hist_next());
|
strcpy(gl_buf, hist_next());
|
if (gl_in_hook)
|
if (gl_in_hook)
|
gl_in_hook(gl_buf);
|
gl_in_hook(gl_buf);
|
gl_fixup(gl_prompt, 0, BUF_SIZE);
|
gl_fixup(gl_prompt, 0, BUF_SIZE);
|
break;
|
break;
|
case 'C': gl_fixup(gl_prompt, -1, gl_pos+1); /* right */
|
case 'C': gl_fixup(gl_prompt, -1, gl_pos+1); /* right */
|
break;
|
break;
|
case 'D': gl_fixup(gl_prompt, -1, gl_pos-1); /* left */
|
case 'D': gl_fixup(gl_prompt, -1, gl_pos-1); /* left */
|
break;
|
break;
|
default: gl_putc('\007'); /* who knows */
|
default: gl_putc('\007'); /* who knows */
|
break;
|
break;
|
}
|
}
|
} else if (c == 'f' || c == 'F') {
|
} else if (c == 'f' || c == 'F') {
|
gl_word(1);
|
gl_word(1);
|
} else if (c == 'b' || c == 'B') {
|
} else if (c == 'b' || c == 'B') {
|
gl_word(-1);
|
gl_word(-1);
|
} else
|
} else
|
gl_putc('\007');
|
gl_putc('\007');
|
break;
|
break;
|
default: /* check for a terminal signal */
|
default: /* check for a terminal signal */
|
#ifdef __unix__
|
#ifdef __unix__
|
if (c > 0) { /* ignore 0 (reset above) */
|
if (c > 0) { /* ignore 0 (reset above) */
|
sig = 0;
|
sig = 0;
|
#ifdef SIGINT
|
#ifdef SIGINT
|
if (c == gl_intrc)
|
if (c == gl_intrc)
|
sig = SIGINT;
|
sig = SIGINT;
|
#endif
|
#endif
|
#ifdef SIGQUIT
|
#ifdef SIGQUIT
|
if (c == gl_quitc)
|
if (c == gl_quitc)
|
sig = SIGQUIT;
|
sig = SIGQUIT;
|
#endif
|
#endif
|
#ifdef SIGTSTP
|
#ifdef SIGTSTP
|
if (c == gl_suspc || c == gl_dsuspc)
|
if (c == gl_suspc || c == gl_dsuspc)
|
sig = SIGTSTP;
|
sig = SIGTSTP;
|
#endif
|
#endif
|
if (sig != 0) {
|
if (sig != 0) {
|
gl_cleanup();
|
gl_cleanup();
|
kill(0, sig);
|
kill(0, sig);
|
gl_init();
|
gl_init();
|
gl_redraw();
|
gl_redraw();
|
c = 0;
|
c = 0;
|
}
|
}
|
}
|
}
|
#endif /* __unix__ */
|
#endif /* __unix__ */
|
if (c > 0)
|
if (c > 0)
|
gl_putc('\007');
|
gl_putc('\007');
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
gl_cleanup();
|
gl_cleanup();
|
gl_buf[0] = 0;
|
gl_buf[0] = 0;
|
return gl_buf;
|
return gl_buf;
|
}
|
}
|
|
|
static void
|
static void
|
gl_addchar(c)
|
gl_addchar(c)
|
int c;
|
int c;
|
/* adds the character c to the input buffer at current location */
|
/* adds the character c to the input buffer at current location */
|
{
|
{
|
int i;
|
int i;
|
|
|
if (gl_cnt >= BUF_SIZE - 1)
|
if (gl_cnt >= BUF_SIZE - 1)
|
gl_error("\n*** Error: getline(): input buffer overflow\n");
|
gl_error("\n*** Error: getline(): input buffer overflow\n");
|
if (gl_overwrite == 0 || gl_pos == gl_cnt) {
|
if (gl_overwrite == 0 || gl_pos == gl_cnt) {
|
for (i=gl_cnt; i >= gl_pos; i--)
|
for (i=gl_cnt; i >= gl_pos; i--)
|
gl_buf[i+1] = gl_buf[i];
|
gl_buf[i+1] = gl_buf[i];
|
gl_buf[gl_pos] = c;
|
gl_buf[gl_pos] = c;
|
gl_fixup(gl_prompt, gl_pos, gl_pos+1);
|
gl_fixup(gl_prompt, gl_pos, gl_pos+1);
|
} else {
|
} else {
|
gl_buf[gl_pos] = c;
|
gl_buf[gl_pos] = c;
|
gl_extent = 1;
|
gl_extent = 1;
|
gl_fixup(gl_prompt, gl_pos, gl_pos+1);
|
gl_fixup(gl_prompt, gl_pos, gl_pos+1);
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
gl_yank()
|
gl_yank()
|
/* adds the kill buffer to the input buffer at current location */
|
/* adds the kill buffer to the input buffer at current location */
|
{
|
{
|
int i, len;
|
int i, len;
|
|
|
len = strlen(gl_killbuf);
|
len = strlen(gl_killbuf);
|
if (len > 0) {
|
if (len > 0) {
|
if (gl_overwrite == 0) {
|
if (gl_overwrite == 0) {
|
if (gl_cnt + len >= BUF_SIZE - 1)
|
if (gl_cnt + len >= BUF_SIZE - 1)
|
gl_error("\n*** Error: getline(): input buffer overflow\n");
|
gl_error("\n*** Error: getline(): input buffer overflow\n");
|
for (i=gl_cnt; i >= gl_pos; i--)
|
for (i=gl_cnt; i >= gl_pos; i--)
|
gl_buf[i+len] = gl_buf[i];
|
gl_buf[i+len] = gl_buf[i];
|
for (i=0; i < len; i++)
|
for (i=0; i < len; i++)
|
gl_buf[gl_pos+i] = gl_killbuf[i];
|
gl_buf[gl_pos+i] = gl_killbuf[i];
|
gl_fixup(gl_prompt, gl_pos, gl_pos+len);
|
gl_fixup(gl_prompt, gl_pos, gl_pos+len);
|
} else {
|
} else {
|
if (gl_pos + len > gl_cnt) {
|
if (gl_pos + len > gl_cnt) {
|
if (gl_pos + len >= BUF_SIZE - 1)
|
if (gl_pos + len >= BUF_SIZE - 1)
|
gl_error("\n*** Error: getline(): input buffer overflow\n");
|
gl_error("\n*** Error: getline(): input buffer overflow\n");
|
gl_buf[gl_pos + len] = 0;
|
gl_buf[gl_pos + len] = 0;
|
}
|
}
|
for (i=0; i < len; i++)
|
for (i=0; i < len; i++)
|
gl_buf[gl_pos+i] = gl_killbuf[i];
|
gl_buf[gl_pos+i] = gl_killbuf[i];
|
gl_extent = len;
|
gl_extent = len;
|
gl_fixup(gl_prompt, gl_pos, gl_pos+len);
|
gl_fixup(gl_prompt, gl_pos, gl_pos+len);
|
}
|
}
|
} else
|
} else
|
gl_putc('\007');
|
gl_putc('\007');
|
}
|
}
|
|
|
static void
|
static void
|
gl_transpose()
|
gl_transpose()
|
/* switch character under cursor and to left of cursor */
|
/* switch character under cursor and to left of cursor */
|
{
|
{
|
int c;
|
int c;
|
|
|
if (gl_pos > 0 && gl_cnt > gl_pos) {
|
if (gl_pos > 0 && gl_cnt > gl_pos) {
|
c = gl_buf[gl_pos-1];
|
c = gl_buf[gl_pos-1];
|
gl_buf[gl_pos-1] = gl_buf[gl_pos];
|
gl_buf[gl_pos-1] = gl_buf[gl_pos];
|
gl_buf[gl_pos] = c;
|
gl_buf[gl_pos] = c;
|
gl_extent = 2;
|
gl_extent = 2;
|
gl_fixup(gl_prompt, gl_pos-1, gl_pos);
|
gl_fixup(gl_prompt, gl_pos-1, gl_pos);
|
} else
|
} else
|
gl_putc('\007');
|
gl_putc('\007');
|
}
|
}
|
|
|
static void
|
static void
|
gl_newline()
|
gl_newline()
|
/*
|
/*
|
* Cleans up entire line before returning to caller. A \n is appended.
|
* Cleans up entire line before returning to caller. A \n is appended.
|
* If line longer than screen, we redraw starting at beginning
|
* If line longer than screen, we redraw starting at beginning
|
*/
|
*/
|
{
|
{
|
int change = gl_cnt;
|
int change = gl_cnt;
|
int len = gl_cnt;
|
int len = gl_cnt;
|
int loc = gl_width - 5; /* shifts line back to start position */
|
int loc = gl_width - 5; /* shifts line back to start position */
|
|
|
if (gl_cnt >= BUF_SIZE - 1)
|
if (gl_cnt >= BUF_SIZE - 1)
|
gl_error("\n*** Error: getline(): input buffer overflow\n");
|
gl_error("\n*** Error: getline(): input buffer overflow\n");
|
if (gl_out_hook) {
|
if (gl_out_hook) {
|
change = gl_out_hook(gl_buf);
|
change = gl_out_hook(gl_buf);
|
len = strlen(gl_buf);
|
len = strlen(gl_buf);
|
}
|
}
|
if (loc > len)
|
if (loc > len)
|
loc = len;
|
loc = len;
|
gl_fixup(gl_prompt, change, loc); /* must do this before appending \n */
|
gl_fixup(gl_prompt, change, loc); /* must do this before appending \n */
|
gl_buf[len] = '\n';
|
gl_buf[len] = '\n';
|
gl_buf[len+1] = '\0';
|
gl_buf[len+1] = '\0';
|
gl_putc('\n');
|
gl_putc('\n');
|
}
|
}
|
|
|
static void
|
static void
|
gl_del(loc)
|
gl_del(loc)
|
int loc;
|
int loc;
|
/*
|
/*
|
* Delete a character. The loc variable can be:
|
* Delete a character. The loc variable can be:
|
* -1 : delete character to left of cursor
|
* -1 : delete character to left of cursor
|
* 0 : delete character under cursor
|
* 0 : delete character under cursor
|
*/
|
*/
|
{
|
{
|
int i;
|
int i;
|
|
|
if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
|
if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
|
for (i=gl_pos+loc; i < gl_cnt; i++)
|
for (i=gl_pos+loc; i < gl_cnt; i++)
|
gl_buf[i] = gl_buf[i+1];
|
gl_buf[i] = gl_buf[i+1];
|
gl_fixup(gl_prompt, gl_pos+loc, gl_pos+loc);
|
gl_fixup(gl_prompt, gl_pos+loc, gl_pos+loc);
|
} else
|
} else
|
gl_putc('\007');
|
gl_putc('\007');
|
}
|
}
|
|
|
static void
|
static void
|
gl_kill(pos)
|
gl_kill(pos)
|
int pos;
|
int pos;
|
/* delete from pos to the end of line */
|
/* delete from pos to the end of line */
|
{
|
{
|
if (pos < gl_cnt) {
|
if (pos < gl_cnt) {
|
strcpy(gl_killbuf, gl_buf + pos);
|
strcpy(gl_killbuf, gl_buf + pos);
|
gl_buf[pos] = '\0';
|
gl_buf[pos] = '\0';
|
gl_fixup(gl_prompt, pos, pos);
|
gl_fixup(gl_prompt, pos, pos);
|
} else
|
} else
|
gl_putc('\007');
|
gl_putc('\007');
|
}
|
}
|
|
|
static void
|
static void
|
gl_word(direction)
|
gl_word(direction)
|
int direction;
|
int direction;
|
/* move forward or backword one word */
|
/* move forward or backword one word */
|
{
|
{
|
int pos = gl_pos;
|
int pos = gl_pos;
|
|
|
if (direction > 0) { /* forward */
|
if (direction > 0) { /* forward */
|
while (!isspace(gl_buf[pos]) && pos < gl_cnt)
|
while (!isspace(gl_buf[pos]) && pos < gl_cnt)
|
pos++;
|
pos++;
|
while (isspace(gl_buf[pos]) && pos < gl_cnt)
|
while (isspace(gl_buf[pos]) && pos < gl_cnt)
|
pos++;
|
pos++;
|
} else { /* backword */
|
} else { /* backword */
|
if (pos > 0)
|
if (pos > 0)
|
pos--;
|
pos--;
|
while (isspace(gl_buf[pos]) && pos > 0)
|
while (isspace(gl_buf[pos]) && pos > 0)
|
pos--;
|
pos--;
|
while (!isspace(gl_buf[pos]) && pos > 0)
|
while (!isspace(gl_buf[pos]) && pos > 0)
|
pos--;
|
pos--;
|
if (pos < gl_cnt && isspace(gl_buf[pos])) /* move onto word */
|
if (pos < gl_cnt && isspace(gl_buf[pos])) /* move onto word */
|
pos++;
|
pos++;
|
}
|
}
|
gl_fixup(gl_prompt, -1, pos);
|
gl_fixup(gl_prompt, -1, pos);
|
}
|
}
|
|
|
static void
|
static void
|
gl_redraw()
|
gl_redraw()
|
/* emit a newline, reset and redraw prompt and current input line */
|
/* emit a newline, reset and redraw prompt and current input line */
|
{
|
{
|
if (gl_init_done > 0) {
|
if (gl_init_done > 0) {
|
gl_putc('\n');
|
gl_putc('\n');
|
gl_fixup(gl_prompt, -2, gl_pos);
|
gl_fixup(gl_prompt, -2, gl_pos);
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
gl_fixup(prompt, change, cursor)
|
gl_fixup(prompt, change, cursor)
|
char *prompt;
|
char *prompt;
|
int change, cursor;
|
int change, cursor;
|
/*
|
/*
|
* This function is used both for redrawing when input changes or for
|
* This function is used both for redrawing when input changes or for
|
* moving within the input line. The parameters are:
|
* moving within the input line. The parameters are:
|
* prompt: compared to last_prompt[] for changes;
|
* prompt: compared to last_prompt[] for changes;
|
* change : the index of the start of changes in the input buffer,
|
* change : the index of the start of changes in the input buffer,
|
* with -1 indicating no changes, -2 indicating we're on
|
* with -1 indicating no changes, -2 indicating we're on
|
* a new line, redraw everything.
|
* a new line, redraw everything.
|
* cursor : the desired location of the cursor after the call.
|
* cursor : the desired location of the cursor after the call.
|
* A value of BUF_SIZE can be used to indicate the cursor should
|
* A value of BUF_SIZE can be used to indicate the cursor should
|
* move just past the end of the input line.
|
* move just past the end of the input line.
|
*/
|
*/
|
{
|
{
|
static int gl_shift; /* index of first on screen character */
|
static int gl_shift; /* index of first on screen character */
|
static int off_right; /* true if more text right of screen */
|
static int off_right; /* true if more text right of screen */
|
static int off_left; /* true if more text left of screen */
|
static int off_left; /* true if more text left of screen */
|
static char last_prompt[80] = "";
|
static char last_prompt[80] = "";
|
int left = 0, right = -1; /* bounds for redraw */
|
int left = 0, right = -1; /* bounds for redraw */
|
int pad; /* how much to erase at end of line */
|
int pad; /* how much to erase at end of line */
|
int backup; /* how far to backup before fixing */
|
int backup; /* how far to backup before fixing */
|
int new_shift; /* value of shift based on cursor */
|
int new_shift; /* value of shift based on cursor */
|
int extra; /* adjusts when shift (scroll) happens */
|
int extra; /* adjusts when shift (scroll) happens */
|
int i;
|
int i;
|
int new_right = -1; /* alternate right bound, using gl_extent */
|
int new_right = -1; /* alternate right bound, using gl_extent */
|
int l1, l2;
|
int l1, l2;
|
|
|
if (change == -2) { /* reset */
|
if (change == -2) { /* reset */
|
gl_pos = gl_cnt = gl_shift = off_right = off_left = 0;
|
gl_pos = gl_cnt = gl_shift = off_right = off_left = 0;
|
gl_putc('\r');
|
gl_putc('\r');
|
gl_puts(prompt);
|
gl_puts(prompt);
|
strcpy(last_prompt, prompt);
|
strcpy(last_prompt, prompt);
|
change = 0;
|
change = 0;
|
gl_width = gl_termw - gl_strlen(prompt);
|
gl_width = gl_termw - gl_strlen(prompt);
|
} else if (strcmp(prompt, last_prompt) != 0) {
|
} else if (strcmp(prompt, last_prompt) != 0) {
|
l1 = gl_strlen(last_prompt);
|
l1 = gl_strlen(last_prompt);
|
l2 = gl_strlen(prompt);
|
l2 = gl_strlen(prompt);
|
gl_cnt = gl_cnt + l1 - l2;
|
gl_cnt = gl_cnt + l1 - l2;
|
strcpy(last_prompt, prompt);
|
strcpy(last_prompt, prompt);
|
gl_putc('\r');
|
gl_putc('\r');
|
gl_puts(prompt);
|
gl_puts(prompt);
|
gl_pos = gl_shift;
|
gl_pos = gl_shift;
|
gl_width = gl_termw - l2;
|
gl_width = gl_termw - l2;
|
change = 0;
|
change = 0;
|
}
|
}
|
pad = (off_right)? gl_width - 1 : gl_cnt - gl_shift; /* old length */
|
pad = (off_right)? gl_width - 1 : gl_cnt - gl_shift; /* old length */
|
backup = gl_pos - gl_shift;
|
backup = gl_pos - gl_shift;
|
if (change >= 0) {
|
if (change >= 0) {
|
gl_cnt = strlen(gl_buf);
|
gl_cnt = strlen(gl_buf);
|
if (change > gl_cnt)
|
if (change > gl_cnt)
|
change = gl_cnt;
|
change = gl_cnt;
|
}
|
}
|
if (cursor > gl_cnt) {
|
if (cursor > gl_cnt) {
|
if (cursor != BUF_SIZE) /* BUF_SIZE means end of line */
|
if (cursor != BUF_SIZE) /* BUF_SIZE means end of line */
|
gl_putc('\007');
|
gl_putc('\007');
|
cursor = gl_cnt;
|
cursor = gl_cnt;
|
}
|
}
|
if (cursor < 0) {
|
if (cursor < 0) {
|
gl_putc('\007');
|
gl_putc('\007');
|
cursor = 0;
|
cursor = 0;
|
}
|
}
|
if (off_right || (off_left && cursor < gl_shift + gl_width - gl_scroll / 2))
|
if (off_right || (off_left && cursor < gl_shift + gl_width - gl_scroll / 2))
|
extra = 2; /* shift the scrolling boundary */
|
extra = 2; /* shift the scrolling boundary */
|
else
|
else
|
extra = 0;
|
extra = 0;
|
new_shift = cursor + extra + gl_scroll - gl_width;
|
new_shift = cursor + extra + gl_scroll - gl_width;
|
if (new_shift > 0) {
|
if (new_shift > 0) {
|
new_shift /= gl_scroll;
|
new_shift /= gl_scroll;
|
new_shift *= gl_scroll;
|
new_shift *= gl_scroll;
|
} else
|
} else
|
new_shift = 0;
|
new_shift = 0;
|
if (new_shift != gl_shift) { /* scroll occurs */
|
if (new_shift != gl_shift) { /* scroll occurs */
|
gl_shift = new_shift;
|
gl_shift = new_shift;
|
off_left = (gl_shift)? 1 : 0;
|
off_left = (gl_shift)? 1 : 0;
|
off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
|
off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
|
left = gl_shift;
|
left = gl_shift;
|
new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
|
new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
|
} else if (change >= 0) { /* no scroll, but text changed */
|
} else if (change >= 0) { /* no scroll, but text changed */
|
if (change < gl_shift + off_left) {
|
if (change < gl_shift + off_left) {
|
left = gl_shift;
|
left = gl_shift;
|
} else {
|
} else {
|
left = change;
|
left = change;
|
backup = gl_pos - change;
|
backup = gl_pos - change;
|
}
|
}
|
off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
|
off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
|
right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
|
right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
|
new_right = (gl_extent && (right > left + gl_extent))?
|
new_right = (gl_extent && (right > left + gl_extent))?
|
left + gl_extent : right;
|
left + gl_extent : right;
|
}
|
}
|
pad -= (off_right)? gl_width - 1 : gl_cnt - gl_shift;
|
pad -= (off_right)? gl_width - 1 : gl_cnt - gl_shift;
|
pad = (pad < 0)? 0 : pad;
|
pad = (pad < 0)? 0 : pad;
|
if (left <= right) { /* clean up screen */
|
if (left <= right) { /* clean up screen */
|
for (i=0; i < backup; i++)
|
for (i=0; i < backup; i++)
|
gl_putc('\b');
|
gl_putc('\b');
|
if (left == gl_shift && off_left) {
|
if (left == gl_shift && off_left) {
|
gl_putc('$');
|
gl_putc('$');
|
left++;
|
left++;
|
}
|
}
|
for (i=left; i < new_right; i++)
|
for (i=left; i < new_right; i++)
|
gl_putc(gl_buf[i]);
|
gl_putc(gl_buf[i]);
|
gl_pos = new_right;
|
gl_pos = new_right;
|
if (off_right && new_right == right) {
|
if (off_right && new_right == right) {
|
gl_putc('$');
|
gl_putc('$');
|
gl_pos++;
|
gl_pos++;
|
} else {
|
} else {
|
for (i=0; i < pad; i++) /* erase remains of prev line */
|
for (i=0; i < pad; i++) /* erase remains of prev line */
|
gl_putc(' ');
|
gl_putc(' ');
|
gl_pos += pad;
|
gl_pos += pad;
|
}
|
}
|
}
|
}
|
i = gl_pos - cursor; /* move to final cursor location */
|
i = gl_pos - cursor; /* move to final cursor location */
|
if (i > 0) {
|
if (i > 0) {
|
while (i--)
|
while (i--)
|
gl_putc('\b');
|
gl_putc('\b');
|
} else {
|
} else {
|
for (i=gl_pos; i < cursor; i++)
|
for (i=gl_pos; i < cursor; i++)
|
gl_putc(gl_buf[i]);
|
gl_putc(gl_buf[i]);
|
}
|
}
|
gl_pos = cursor;
|
gl_pos = cursor;
|
}
|
}
|
|
|
static int
|
static int
|
gl_tab(buf, offset, loc)
|
gl_tab(buf, offset, loc)
|
char *buf;
|
char *buf;
|
int offset;
|
int offset;
|
int *loc;
|
int *loc;
|
/* default tab handler, acts like tabstops every 8 cols */
|
/* default tab handler, acts like tabstops every 8 cols */
|
{
|
{
|
int i, count, len;
|
int i, count, len;
|
|
|
len = strlen(buf);
|
len = strlen(buf);
|
count = 8 - (offset + *loc) % 8;
|
count = 8 - (offset + *loc) % 8;
|
for (i=len; i >= *loc; i--)
|
for (i=len; i >= *loc; i--)
|
buf[i+count] = buf[i];
|
buf[i+count] = buf[i];
|
for (i=0; i < count; i++)
|
for (i=0; i < count; i++)
|
buf[*loc+i] = ' ';
|
buf[*loc+i] = ' ';
|
i = *loc;
|
i = *loc;
|
*loc = i + count;
|
*loc = i + count;
|
return i;
|
return i;
|
}
|
}
|
|
|
/******************* strlen stuff **************************************/
|
/******************* strlen stuff **************************************/
|
|
|
void gl_strwidth(func)
|
void gl_strwidth(func)
|
size_t (*func)();
|
size_t (*func)();
|
{
|
{
|
if (func != 0) {
|
if (func != 0) {
|
gl_strlen = func;
|
gl_strlen = func;
|
}
|
}
|
}
|
}
|
|
|
/******************* History stuff **************************************/
|
/******************* History stuff **************************************/
|
|
|
#ifndef HIST_SIZE
|
#ifndef HIST_SIZE
|
#define HIST_SIZE 100
|
#define HIST_SIZE 100
|
#endif
|
#endif
|
|
|
static int hist_pos = 0, hist_last = 0;
|
static int hist_pos = 0, hist_last = 0;
|
static char *hist_buf[HIST_SIZE];
|
static char *hist_buf[HIST_SIZE];
|
|
|
static void
|
static void
|
hist_init()
|
hist_init()
|
{
|
{
|
int i;
|
int i;
|
|
|
hist_buf[0] = "";
|
hist_buf[0] = "";
|
for (i=1; i < HIST_SIZE; i++)
|
for (i=1; i < HIST_SIZE; i++)
|
hist_buf[i] = (char *)0;
|
hist_buf[i] = (char *)0;
|
}
|
}
|
|
|
void
|
void
|
gl_histadd(buf)
|
gl_histadd(buf)
|
char *buf;
|
char *buf;
|
{
|
{
|
static char *prev = 0;
|
static char *prev = 0;
|
char *p = buf;
|
char *p = buf;
|
int len;
|
int len;
|
|
|
/* in case we call gl_histadd() before we call gl_getline() */
|
/* in case we call gl_histadd() before we call gl_getline() */
|
if (gl_init_done < 0) { /* -1 only on startup */
|
if (gl_init_done < 0) { /* -1 only on startup */
|
hist_init();
|
hist_init();
|
gl_init_done = 0;
|
gl_init_done = 0;
|
}
|
}
|
while (*p == ' ' || *p == '\t' || *p == '\n')
|
while (*p == ' ' || *p == '\t' || *p == '\n')
|
p++;
|
p++;
|
if (*p) {
|
if (*p) {
|
len = strlen(buf);
|
len = strlen(buf);
|
if (strchr(p, '\n')) /* previously line already has NL stripped */
|
if (strchr(p, '\n')) /* previously line already has NL stripped */
|
len--;
|
len--;
|
if (prev == 0 || strlen(prev) != len ||
|
if (prev == 0 || strlen(prev) != len ||
|
strncmp(prev, buf, len) != 0) {
|
strncmp(prev, buf, len) != 0) {
|
hist_buf[hist_last] = hist_save(buf);
|
hist_buf[hist_last] = hist_save(buf);
|
prev = hist_buf[hist_last];
|
prev = hist_buf[hist_last];
|
hist_last = (hist_last + 1) % HIST_SIZE;
|
hist_last = (hist_last + 1) % HIST_SIZE;
|
if (hist_buf[hist_last] && *hist_buf[hist_last]) {
|
if (hist_buf[hist_last] && *hist_buf[hist_last]) {
|
free(hist_buf[hist_last]);
|
free(hist_buf[hist_last]);
|
}
|
}
|
hist_buf[hist_last] = "";
|
hist_buf[hist_last] = "";
|
}
|
}
|
}
|
}
|
hist_pos = hist_last;
|
hist_pos = hist_last;
|
}
|
}
|
|
|
static char *
|
static char *
|
hist_prev()
|
hist_prev()
|
/* loads previous hist entry into input buffer, sticks on first */
|
/* loads previous hist entry into input buffer, sticks on first */
|
{
|
{
|
char *p = 0;
|
char *p = 0;
|
int next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
|
int next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
|
|
|
if (hist_buf[hist_pos] != 0 && next != hist_last) {
|
if (hist_buf[hist_pos] != 0 && next != hist_last) {
|
hist_pos = next;
|
hist_pos = next;
|
p = hist_buf[hist_pos];
|
p = hist_buf[hist_pos];
|
}
|
}
|
if (p == 0) {
|
if (p == 0) {
|
p = "";
|
p = "";
|
gl_putc('\007');
|
gl_putc('\007');
|
}
|
}
|
return p;
|
return p;
|
}
|
}
|
|
|
static char *
|
static char *
|
hist_next()
|
hist_next()
|
/* loads next hist entry into input buffer, clears on last */
|
/* loads next hist entry into input buffer, clears on last */
|
{
|
{
|
char *p = 0;
|
char *p = 0;
|
|
|
if (hist_pos != hist_last) {
|
if (hist_pos != hist_last) {
|
hist_pos = (hist_pos+1) % HIST_SIZE;
|
hist_pos = (hist_pos+1) % HIST_SIZE;
|
p = hist_buf[hist_pos];
|
p = hist_buf[hist_pos];
|
}
|
}
|
if (p == 0) {
|
if (p == 0) {
|
p = "";
|
p = "";
|
gl_putc('\007');
|
gl_putc('\007');
|
}
|
}
|
return p;
|
return p;
|
}
|
}
|
|
|
static char *
|
static char *
|
hist_save(p)
|
hist_save(p)
|
char *p;
|
char *p;
|
/* makes a copy of the string */
|
/* makes a copy of the string */
|
{
|
{
|
char *s = 0;
|
char *s = 0;
|
int len = strlen(p);
|
int len = strlen(p);
|
char *nl = strchr(p, '\n');
|
char *nl = strchr(p, '\n');
|
|
|
if (nl) {
|
if (nl) {
|
if ((s = malloc(len)) != 0) {
|
if ((s = malloc(len)) != 0) {
|
strncpy(s, p, len-1);
|
strncpy(s, p, len-1);
|
s[len-1] = 0;
|
s[len-1] = 0;
|
}
|
}
|
} else {
|
} else {
|
if ((s = malloc(len+1)) != 0) {
|
if ((s = malloc(len+1)) != 0) {
|
strcpy(s, p);
|
strcpy(s, p);
|
}
|
}
|
}
|
}
|
if (s == 0)
|
if (s == 0)
|
gl_error("\n*** Error: hist_save() failed on malloc\n");
|
gl_error("\n*** Error: hist_save() failed on malloc\n");
|
return s;
|
return s;
|
}
|
}
|
|
|
/******************* Search stuff **************************************/
|
/******************* Search stuff **************************************/
|
|
|
static char search_prompt[101]; /* prompt includes search string */
|
static char search_prompt[101]; /* prompt includes search string */
|
static char search_string[100];
|
static char search_string[100];
|
static int search_pos = 0; /* current location in search_string */
|
static int search_pos = 0; /* current location in search_string */
|
static int search_forw_flg = 0; /* search direction flag */
|
static int search_forw_flg = 0; /* search direction flag */
|
static int search_last = 0; /* last match found */
|
static int search_last = 0; /* last match found */
|
|
|
static void
|
static void
|
search_update(c)
|
search_update(c)
|
int c;
|
int c;
|
{
|
{
|
if (c == 0) {
|
if (c == 0) {
|
search_pos = 0;
|
search_pos = 0;
|
search_string[0] = 0;
|
search_string[0] = 0;
|
search_prompt[0] = '?';
|
search_prompt[0] = '?';
|
search_prompt[1] = ' ';
|
search_prompt[1] = ' ';
|
search_prompt[2] = 0;
|
search_prompt[2] = 0;
|
} else if (c > 0) {
|
} else if (c > 0) {
|
search_string[search_pos] = c;
|
search_string[search_pos] = c;
|
search_string[search_pos+1] = 0;
|
search_string[search_pos+1] = 0;
|
search_prompt[search_pos] = c;
|
search_prompt[search_pos] = c;
|
search_prompt[search_pos+1] = '?';
|
search_prompt[search_pos+1] = '?';
|
search_prompt[search_pos+2] = ' ';
|
search_prompt[search_pos+2] = ' ';
|
search_prompt[search_pos+3] = 0;
|
search_prompt[search_pos+3] = 0;
|
search_pos++;
|
search_pos++;
|
} else {
|
} else {
|
if (search_pos > 0) {
|
if (search_pos > 0) {
|
search_pos--;
|
search_pos--;
|
search_string[search_pos] = 0;
|
search_string[search_pos] = 0;
|
search_prompt[search_pos] = '?';
|
search_prompt[search_pos] = '?';
|
search_prompt[search_pos+1] = ' ';
|
search_prompt[search_pos+1] = ' ';
|
search_prompt[search_pos+2] = 0;
|
search_prompt[search_pos+2] = 0;
|
} else {
|
} else {
|
gl_putc('\007');
|
gl_putc('\007');
|
hist_pos = hist_last;
|
hist_pos = hist_last;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
search_addchar(c)
|
search_addchar(c)
|
int c;
|
int c;
|
{
|
{
|
char *loc;
|
char *loc;
|
|
|
search_update(c);
|
search_update(c);
|
if (c < 0) {
|
if (c < 0) {
|
if (search_pos > 0) {
|
if (search_pos > 0) {
|
hist_pos = search_last;
|
hist_pos = search_last;
|
} else {
|
} else {
|
gl_buf[0] = 0;
|
gl_buf[0] = 0;
|
hist_pos = hist_last;
|
hist_pos = hist_last;
|
}
|
}
|
strcpy(gl_buf, hist_buf[hist_pos]);
|
strcpy(gl_buf, hist_buf[hist_pos]);
|
}
|
}
|
if ((loc = strstr(gl_buf, search_string)) != 0) {
|
if ((loc = strstr(gl_buf, search_string)) != 0) {
|
gl_fixup(search_prompt, 0, loc - gl_buf);
|
gl_fixup(search_prompt, 0, loc - gl_buf);
|
} else if (search_pos > 0) {
|
} else if (search_pos > 0) {
|
if (search_forw_flg) {
|
if (search_forw_flg) {
|
search_forw(0);
|
search_forw(0);
|
} else {
|
} else {
|
search_back(0);
|
search_back(0);
|
}
|
}
|
} else {
|
} else {
|
gl_fixup(search_prompt, 0, 0);
|
gl_fixup(search_prompt, 0, 0);
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
search_term()
|
search_term()
|
{
|
{
|
gl_search_mode = 0;
|
gl_search_mode = 0;
|
if (gl_buf[0] == 0) /* not found, reset hist list */
|
if (gl_buf[0] == 0) /* not found, reset hist list */
|
hist_pos = hist_last;
|
hist_pos = hist_last;
|
if (gl_in_hook)
|
if (gl_in_hook)
|
gl_in_hook(gl_buf);
|
gl_in_hook(gl_buf);
|
gl_fixup(gl_prompt, 0, gl_pos);
|
gl_fixup(gl_prompt, 0, gl_pos);
|
}
|
}
|
|
|
static void
|
static void
|
search_back(new_search)
|
search_back(new_search)
|
int new_search;
|
int new_search;
|
{
|
{
|
int found = 0;
|
int found = 0;
|
char *p, *loc;
|
char *p, *loc;
|
|
|
search_forw_flg = 0;
|
search_forw_flg = 0;
|
if (gl_search_mode == 0) {
|
if (gl_search_mode == 0) {
|
search_last = hist_pos = hist_last;
|
search_last = hist_pos = hist_last;
|
search_update(0);
|
search_update(0);
|
gl_search_mode = 1;
|
gl_search_mode = 1;
|
gl_buf[0] = 0;
|
gl_buf[0] = 0;
|
gl_fixup(search_prompt, 0, 0);
|
gl_fixup(search_prompt, 0, 0);
|
} else if (search_pos > 0) {
|
} else if (search_pos > 0) {
|
while (!found) {
|
while (!found) {
|
p = hist_prev();
|
p = hist_prev();
|
if (*p == 0) { /* not found, done looking */
|
if (*p == 0) { /* not found, done looking */
|
gl_buf[0] = 0;
|
gl_buf[0] = 0;
|
gl_fixup(search_prompt, 0, 0);
|
gl_fixup(search_prompt, 0, 0);
|
found = 1;
|
found = 1;
|
} else if ((loc = strstr(p, search_string)) != 0) {
|
} else if ((loc = strstr(p, search_string)) != 0) {
|
strcpy(gl_buf, p);
|
strcpy(gl_buf, p);
|
gl_fixup(search_prompt, 0, loc - p);
|
gl_fixup(search_prompt, 0, loc - p);
|
if (new_search)
|
if (new_search)
|
search_last = hist_pos;
|
search_last = hist_pos;
|
found = 1;
|
found = 1;
|
}
|
}
|
}
|
}
|
} else {
|
} else {
|
gl_putc('\007');
|
gl_putc('\007');
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
search_forw(new_search)
|
search_forw(new_search)
|
int new_search;
|
int new_search;
|
{
|
{
|
int found = 0;
|
int found = 0;
|
char *p, *loc;
|
char *p, *loc;
|
|
|
search_forw_flg = 1;
|
search_forw_flg = 1;
|
if (gl_search_mode == 0) {
|
if (gl_search_mode == 0) {
|
search_last = hist_pos = hist_last;
|
search_last = hist_pos = hist_last;
|
search_update(0);
|
search_update(0);
|
gl_search_mode = 1;
|
gl_search_mode = 1;
|
gl_buf[0] = 0;
|
gl_buf[0] = 0;
|
gl_fixup(search_prompt, 0, 0);
|
gl_fixup(search_prompt, 0, 0);
|
} else if (search_pos > 0) {
|
} else if (search_pos > 0) {
|
while (!found) {
|
while (!found) {
|
p = hist_next();
|
p = hist_next();
|
if (*p == 0) { /* not found, done looking */
|
if (*p == 0) { /* not found, done looking */
|
gl_buf[0] = 0;
|
gl_buf[0] = 0;
|
gl_fixup(search_prompt, 0, 0);
|
gl_fixup(search_prompt, 0, 0);
|
found = 1;
|
found = 1;
|
} else if ((loc = strstr(p, search_string)) != 0) {
|
} else if ((loc = strstr(p, search_string)) != 0) {
|
strcpy(gl_buf, p);
|
strcpy(gl_buf, p);
|
gl_fixup(search_prompt, 0, loc - p);
|
gl_fixup(search_prompt, 0, loc - p);
|
if (new_search)
|
if (new_search)
|
search_last = hist_pos;
|
search_last = hist_pos;
|
found = 1;
|
found = 1;
|
}
|
}
|
}
|
}
|
} else {
|
} else {
|
gl_putc('\007');
|
gl_putc('\007');
|
}
|
}
|
}
|
}
|
|
|