home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.misc
- From: thewalt@canuck.CE.Berkeley.EDU (Chris Thewalt)
- Subject: v26i092: input-edit - C input functions for line editing with history, Patch01
- Message-ID: <1991Nov30.210948.4573@sparky.imd.sterling.com>
- X-Md4-Signature: b8bf2ca4014f08c3651aba5c21908e83
- Date: Sat, 30 Nov 1991 21:09:48 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: thewalt@canuck.CE.Berkeley.EDU (Chris Thewalt)
- Posting-number: Volume 26, Issue 92
- Archive-name: input-edit/patch01
- Environment: UNIX, MS-DOS
- Patch-To: input-edit: Volume 25, Issue 56
-
- The patch to getline.c was larger than a repost of the file, so this
- version replaces the original getline.c posted in Volume 25, Issue 56.
-
- The changes since the first version are:
-
- 1) removed stdio calls to decrease executable size
- (thanks to Scott Schwartz, schwartz@groucho.cs.psu.edu)
- 2) added VMS support
- (thanks to Christoph Keller, keller@bernina.ethz.ch)
- 3) added some new key bindings and functionality:
- ^T: transpose current and previous character
- arrow keys: motion for ANSI and MSDOS arrow keys
- ^G: toggles replace (overwrite) mode. Initially
- in insert mode.
-
- What is input-edit?
-
- environment: ANSI C, UNIX (sysv or bsd), MSDOS with MSC, VMS
- (Converting to K&R C should be fairly simple)
-
- tested on: DECstation 5000, Ultrix 4.2 with gcc
- Sun Sparc II, SunOS 4.1.1, gcc
- SGI Iris, IRIX System V.3, cc
- PC, DR DOS 5.0, MSC 6.0
-
- description: Getline can be used in programs that want to provide
- an emacs style line editing cabability with history.
- Getline allows the user to edit the current line
- and move through the history list of lines previously
- typed and returns the buffer to the caller when RETURN
- is entered. Long lines are handled by horizontal
- scrolling. Does NOT use termcap, uses only \b to move around.
-
- The actual editing capabilites are a very small subset
- of emacs commands, but then the package is very small
- and quite portable. Get GNU readline if you need more
- powerful editing.
-
- #!/bin/sh
- # This is a shell archive (produced by shar 3.49)
- # To extract the files from this archive, save it to a file, remove
- # everything above the "!/bin/sh" line above, and type "sh file_name".
- #
- # made 11/25/1991 16:03 UTC by thewalt@canuck.CE.Berkeley.EDU
- # Source directory /usr/users/thewalt/et
- #
- # existing files WILL be overwritten
- #
- # This shar contains:
- # length mode name
- # ------ ---------- ------------------------------------------
- # 20798 -rw-r--r-- getline.c
- #
- # ============= getline.c ==============
- echo 'x - extracting getline.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'getline.c' &&
- #ifndef lint
- static char rcsid[] =
- "$Id: getline.c,v 2.1 1991/11/25 15:58:19 thewalt Exp thewalt $";
- #endif
- X
- /*
- X * Fairly portable (ANSI C), emacs style line editing input package.
- X * This package uses \b to move, and \007 to ring the bell.
- X * It uses a fixed screen width, as initialized in the gl_init() call,
- X * and does not draw in the last location to avoid line wraps.
- X * The only non-portable part is how to turn off character echoing.
- X * This code works for *NIX of BSD or SYSV flavor, as well as MSDOS (MSC6.0).
- X * No TERMCAP features are used, so long lines are scrolled on one line
- X * rather than extending over several lines. The function getline
- X * returns a pointer to a static buffer area which holds the input string,
- X * including the newline. On EOF the first character is set equal to '\0'.
- X * The caller supplies a desired prompt, as shown in the prototype:
- X *
- X * char *getline(char *prompt)
- X *
- X * Getline is different from GNU readline in that:
- X * - getline has much more limited editing capabilities, but it
- X * is also much smaller and doesn't need termcap.
- X * - you don't free the buffer when done, since it is static
- X * (make a copy yourself if you want one)
- X * - the newline is appended to the buffer
- X * - you don't add lines to history, it is done automatically.
- X *
- X * The function gl_init(int screen_width) should be called before
- X * calling getline(char *prompt), and gl_cleanup(void) should be
- X * called before before exiting. The function gl_redraw(void) may also
- X * be called to redraw the screen (as is done when ^L is read).
- X * The function gl_replace() is also user callable and toggles getline
- X * between insert and replace (overwrite) mode. Getline begins in insert
- X * mode.
- X *
- X * The editing keys are:
- X * ^A, ^E - move to beginnning or end of line, respectively.
- X * ^F, ^B - nondestructive move forward or back one location, respectively.
- X * ^D - delete the character currently under the cursor, or
- X * send EOF if no characters in the buffer.
- X * ^G - toggle replace (overwrite) mode, initally in insert mode.
- X * ^H, DEL - delete character left of the cursor.
- X * ^K - delete from cursor to end of line.
- X * ^L - redraw the current line.
- X * ^P, ^N - move through history, previous and next, respectively.
- X * ^T - transpose chars under and to left of cursor
- X * TAB - call user defined function if bound, or insert spaces
- X * to get to next TAB stop (just past every 8th column).
- X * NL, CR - places line on history list if nonblank, calls output
- X * cleanup function if bound, appends newline and returns
- X * to the caller.
- X * arrow keys - appropriate motion
- X *
- X * In addition, the caller can modify the buffer in certain ways, which
- X * may be useful for things like auto-indent modes. There are three
- X * function pointers which can be bound to user functions.
- X * Each of these functions must return the index of the first location
- X * at which the buffer was modified, or -1 if the buffer wasn't modified.
- X * Each of the functions receive the current input buffer as the first
- X * argument. The screen is automatically cleaned up if the buffer is changed.
- X * The user is responsible for not writing beyond the end of the static
- X * buffer. The function pointer prototypes are:
- X *
- X * int (*gl_in_hook)(char *buf)
- X * - called on entry to getline, and each time a new history
- X * string is loaded, from a ^P or ^N. Initally NULL.
- X * int (*gl_out_hook)(char *buf)
- X * - called when a \n or \r is read, before appending \n and
- X * returning to caller. Initally NULL.
- X * int (*gl_tab_hook)(char *buf, int offset, int *loc)
- X * - called whenever a TAB is read. The second argument is
- X * the current line offset due to the width of the prompt.
- X * The third argument is a pointer to the variable holding the
- X * current location in the buffer. The location may be reset
- X * by the user to move the cursor when the call returns.
- X * Initially a built in tabbing function is bound.
- X *
- X * Please send bug reports, fixes and enhancements to Chris Thewalt,
- X * thewalt@ce.berkeley.edu
- X */
- X
- static char *copyright = "Copyright (C) 1991, Chris Thewalt";
- /*
- X * Copyright (C) 1991 by Chris Thewalt
- X *
- X * Permission to use, copy, modify, and distribute this software
- X * for any purpose and without fee is hereby granted, provided
- X * that the above copyright notices appear in all copies and that both the
- X * copyright notice and this permission notice appear in supporting
- X * documentation. This software is provided "as is" without express or
- X * implied warranty.
- X */
- X
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- X
- extern int isatty();
- X
- #define BUF_SIZE 1024
- #define SCROLL 30
- X
- static int gl_init_done = 0; /* -1 is terminal, 1 is batch */
- static int gl_screen = 80; /* screen width */
- 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_overwrite = 0; /* overwrite mode */
- static int gl_pos, gl_cnt = 0; /* position and size of input */
- static char gl_buf[BUF_SIZE]; /* input buffer */
- static char *gl_prompt; /* to save the prompt string */
- X
- void gl_init(int);
- void gl_cleanup(void); /* to undo gl_init */
- void gl_redraw(void); /* issue \n and redraw all */
- void gl_replace(void); /* toggle replace/insert mode */
- static void gl_char_init(void); /* get ready for no echo input */
- static void gl_char_cleanup(void); /* undo gl_char_init */
- static int gl_getc(void); /* read one char from terminal */
- static void gl_putc(int); /* write one char to terminal */
- static void gl_gets(char *, int); /* get a line from terminal */
- static void gl_puts(char *); /* write a line to terminal */
- static void gl_addchar(int); /* install specified char */
- static void gl_transpose(void); /* transpose two chars */
- static void gl_newline(void); /* handle \n or \r */
- static void gl_fixup(int, int); /* fixup state variables and screen */
- static void gl_del(int); /* del, either left (-1) or cur (0) */
- static void gl_kill(void); /* delete to EOL */
- static int gl_tab(char *, int, int *); /* default TAB handler */
- X
- static void hist_add(void); /* adds nonblank entries to hist */
- static void hist_init(void); /* initializes hist pointers */
- static void hist_next(void); /* copies next entry to input buf */
- static void hist_prev(void); /* copies prev entry to input buf */
- static char *hist_save(char *); /* makes copy of a string */
- X
- int (*gl_in_hook)(char *) = 0;
- int (*gl_out_hook)(char *) = 0;
- int (*gl_tab_hook)(char *, int, int *) = gl_tab;
- X
- /************************ nonportable part *********************************/
- extern int write();
- extern void _exit();
- X
- #ifdef MSDOS
- #include <bios.h>
- #endif
- X
- #ifdef unix
- extern int read();
- #include <sys/ioctl.h>
- #ifndef TIOCGETP
- #include <termio.h>
- struct termio tty, old_tty;
- #else
- #include <sgtty.h>
- struct sgttyb tty, old_tty;
- #endif /* TIOCGETP */
- extern int ioctl();
- #endif /* unix */
- X
- #ifdef vms
- #include <descrip.h>
- #include <ttdef.h>
- #include <iodef.h>
- #include unixio
- X
- static int setbuff[2]; /* buffer to set terminal attributes */
- static short chan = -1; /* channel to terminal */
- struct dsc$descriptor_s descrip; /* VMS descriptor */
- #endif
- X
- static void
- gl_char_init()
- /* turn off input echo */
- {
- #ifdef unix
- #ifdef TIOCGETP
- X ioctl(0, TIOCGETP, &old_tty);
- X tty = old_tty;
- X tty.sg_flags |= CBREAK;
- X tty.sg_flags &= ~ECHO;
- X ioctl(0, TIOCSETP, &tty);
- #else
- X ioctl(0, TCGETA, &old_tty);
- X tty = old_tty;
- X tty.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
- X tty.c_cc[VMIN] = 1;
- X tty.c_cc[VTIME] = 0;
- X ioctl(0, TCSETA, &tty);
- #endif
- #endif /* unix */
- #ifdef vms
- X descrip.dsc$w_length = strlen("tt:");
- X descrip.dsc$b_dtype = DSC$K_DTYPE_T;
- X descrip.dsc$b_class = DSC$K_CLASS_S;
- X descrip.dsc$a_pointer = "tt:";
- X (void)sys$assign(&descrip,&chan,0,0);
- X (void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0);
- X setbuff[1] |= TT$M_NOECHO;
- X (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
- #endif /* vms */
- }
- X
- static void
- gl_char_cleanup()
- /* undo effects of gl_char_init, as necessary */
- {
- #ifdef unix
- #ifdef TIOCSETP
- X ioctl(0, TIOCSETP, &old_tty);
- #else
- X ioctl(0, TCSETA, &old_tty);
- #endif
- #endif /* unix */
- X
- #ifdef vms
- X setbuff[1] &= ~TT$M_NOECHO;
- X (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
- X sys$dassgn(chan);
- X chan = -1;
- #endif
- }
- X
- static int
- gl_getc()
- /* get a character without echoing it to screen */
- {
- X int c;
- X char ch;
- X
- #ifdef unix
- X c = (read(0, &ch, 1) > 0)? ch : -1;
- #endif
- #ifdef MSDOS
- X c = _bios_keybrd(_NKEYBRD_READ);
- X if ((c & 0377) == 224) {
- X switch (c = (c >> 8) & 0377) {
- X case 72: c = 16; /* up -> ^P */
- X break;
- X case 80: c = 14; /* down -> ^N */
- X break;
- X case 75: c = 2; /* left -> ^B */
- X break;
- X case 77: c = 6; /* right -> ^F */
- X break;
- X default: c = 254; /* make it garbage */
- X }
- X } else {
- X c = c & 0377;
- X }
- #endif
- #ifdef vms
- X if(chan < 0) {
- X c='\0';
- X }
- X (void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0);
- X c &= 0177; /* get a char */
- #endif
- X return c;
- }
- X
- static void
- gl_putc(int c)
- {
- X char ch = c;
- X
- X write(1, &ch, 1);
- }
- X
- /******************** fairly portable part *********************************/
- X
- static void
- gl_gets(char *buf, int size) /* slow, only used in batch mode */
- {
- X char *p = buf;
- X int c;
- X
- X size -= 1;
- X while (buf + size > p && (c = gl_getc()) > 0) {
- X *p++ = c;
- X if (c == '\n')
- X break;
- X }
- X *p = 0;
- }
- X
- static void
- gl_puts(char *buf)
- {
- X while (*buf)
- X gl_putc(*buf++);
- }
- X
- void
- gl_init(int scrn_wdth)
- /* set up variables and terminal */
- {
- X gl_screen = scrn_wdth;
- X if (gl_init_done == 0) {
- X hist_init();
- X if (isatty(0)) {
- X gl_char_init();
- X gl_init_done = -1; /* -1 means terminal */
- X } else {
- X gl_init_done = 1; /* 1 means batch */
- X }
- X }
- X gl_pos = gl_cnt = 0;
- }
- X
- void
- gl_cleanup()
- /* undo effects of gl_init, as necessary */
- {
- X if (gl_init_done == -1)
- X gl_char_cleanup();
- X gl_init_done = 0;
- }
- X
- char *
- getline(char *prompt)
- {
- X int c, loc, tmp;
- X
- X if (!gl_init_done)
- X gl_init(80);
- X gl_buf[0] = 0; /* used as end of input indicator */
- X if (gl_init_done == 1) { /* no input editing, and no prompt output */
- X gl_gets(gl_buf, BUF_SIZE);
- X return gl_buf;
- X }
- X gl_fixup(-1, 0); /* this resets gl_fixup */
- X gl_width = gl_screen - strlen(prompt);
- X if (prompt == 0)
- X prompt = "";
- X gl_prompt = prompt;
- X gl_pos = gl_cnt = 0;
- X gl_puts(prompt);
- X if (gl_in_hook) {
- X loc = gl_in_hook(gl_buf);
- X if (loc >= 0)
- X gl_fixup(0, BUF_SIZE);
- X }
- X while ((c = gl_getc()) >= 0) {
- X gl_extent = 0;
- X if (isprint(c)) {
- X gl_addchar(c);
- X } else {
- X switch (c) {
- X case '\n': case '\r': /* newline */
- X gl_newline();
- X return gl_buf;
- X break;
- X case '\001': gl_fixup(-1, 0); /* ^A */
- X break;
- X case '\002': gl_fixup(-1, gl_pos-1); /* ^B */
- X break;
- X case '\004': /* ^D */
- X if (gl_cnt == 0) {
- X gl_buf[0] = 0;
- X gl_cleanup();
- X gl_putc('\n');
- X return gl_buf;
- X } else {
- X gl_del(0);
- X }
- X break;
- X case '\005': gl_fixup(-1, gl_cnt); /* ^E */
- X break;
- X case '\006': gl_fixup(-1, gl_pos+1); /* ^F */
- X break;
- X case '\007': gl_replace(); /* ^G */
- X break;
- X case '\010': case '\177': gl_del(-1); /* ^H and DEL */
- X break;
- X case '\t': /* TAB */
- X if (gl_tab_hook) {
- X tmp = gl_pos;
- X loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp);
- X if (loc >= 0 || tmp != gl_pos)
- X gl_fixup(loc, tmp);
- X }
- X break;
- X case '\013': gl_kill(); /* ^K */
- X break;
- X case '\014': gl_redraw(); /* ^L */
- X break;
- X case '\016': hist_next(); /* ^N */
- X break;
- X case '\020': hist_prev(); /* ^P */
- X break;
- X case '\024': gl_transpose(); /* ^T */
- X break;
- X case '\033': /* ansi arrow keys */
- X c = gl_getc();
- X if (c == '[') {
- X switch(c = gl_getc()) {
- X case 'A': hist_prev(); /* up */
- X break;
- X case 'B': hist_next(); /* down */
- X break;
- X case 'C': gl_fixup(-1, gl_pos+1); /* right */
- X break;
- X case 'D': gl_fixup(-1, gl_pos-1); /* left */
- X break;
- X default: gl_putc('\007'); /* who knows */
- X break;
- X }
- X } else
- X gl_putc('\007');
- X break;
- X default:
- X gl_putc('\007');
- X break;
- X }
- X }
- X }
- X gl_cleanup();
- X return gl_buf;
- }
- X
- static void
- gl_addchar(int c)
- /* adds the character c to the input buffer at current location */
- {
- X int i;
- X
- X if (gl_cnt >= BUF_SIZE - 1) {
- X gl_puts("getline: input buffer overflow\n");
- X _exit(1);
- X }
- X if (gl_overwrite == 0 || gl_pos == gl_cnt) {
- X for (i=gl_cnt; i >= gl_pos; i--)
- X gl_buf[i+1] = gl_buf[i];
- X gl_buf[gl_pos] = c;
- X gl_fixup(gl_pos, gl_pos+1);
- X } else {
- X gl_buf[gl_pos] = c;
- X gl_extent = 1;
- X gl_fixup(gl_pos, gl_pos+1);
- X }
- }
- X
- static void
- gl_transpose(void)
- /* switch character under cursor and to left of cursor */
- {
- X int c;
- X
- X if (gl_pos > 0 && gl_cnt > gl_pos) {
- X c = gl_buf[gl_pos-1];
- X gl_buf[gl_pos-1] = gl_buf[gl_pos];
- X gl_buf[gl_pos] = c;
- X gl_extent = 2;
- X gl_fixup(gl_pos-1, gl_pos);
- X } else
- X gl_putc('\007');
- }
- X
- void
- gl_replace()
- {
- X gl_overwrite = !gl_overwrite;
- }
- X
- static void
- gl_newline()
- /*
- X * Cleans up entire line before returning to caller. A \n is appended.
- X * If line longer than screen, we redraw starting at beginning
- X */
- {
- X int change = gl_cnt;
- X int len = gl_cnt;
- X int loc = gl_width - 5; /* shifts line back to start position */
- X
- X if (gl_cnt >= BUF_SIZE - 1) {
- X gl_puts("getline: input buffer overflow\n");
- X _exit(1);
- X }
- X hist_add(); /* only adds if nonblank */
- X if (gl_out_hook) {
- X change = gl_out_hook(gl_buf);
- X len = strlen(gl_buf);
- X }
- X if (loc > len)
- X loc = len;
- X gl_fixup(change, loc); /* must do this before appending \n */
- X gl_buf[len] = '\n';
- X gl_buf[len+1] = '\0';
- X gl_putc('\n');
- }
- X
- static void
- gl_del(int loc)
- /*
- X * Delete a character. The loc variable can be:
- X * -1 : delete character to left of cursor
- X * 0 : delete character under cursor
- X */
- {
- X int i;
- X
- X if (loc == -1 && gl_pos > 0 || loc == 0 && gl_pos < gl_cnt) {
- X for (i=gl_pos+loc; i < gl_cnt; i++)
- X gl_buf[i] = gl_buf[i+1];
- X gl_fixup(gl_pos+loc, gl_pos+loc);
- X } else
- X gl_putc('\007');
- }
- X
- static void
- gl_kill()
- /* delete from current position to the end of line */
- {
- X if (gl_pos < gl_cnt) {
- X gl_buf[gl_pos] = '\0';
- X gl_fixup(gl_pos, gl_pos);
- X } else
- X gl_putc('\007');
- }
- X
- void
- gl_redraw()
- /* emit a newline, reset and redraw prompt and current input line */
- {
- X if (gl_init_done == -1) {
- X gl_putc('\n');
- X gl_puts(gl_prompt);
- X gl_pos = 0;
- X gl_fixup(0, BUF_SIZE);
- X }
- }
- X
- static void
- gl_fixup(int change, int cursor)
- /*
- X * This function is used both for redrawing when input changes or for
- X * moving within the input line. The parameters are:
- X * change : the index of the start of changes in the input buffer,
- X * with -1 indicating no changes.
- X * cursor : the desired location of the cursor after the call.
- X * A value of BUF_SIZE can be used to indicate the cursor should
- X * move just past the end of the input line.
- X */
- {
- X static int gl_shift; /* index of first on screen character */
- X static int off_right; /* true if more text right of screen */
- X static int off_left; /* true if more text left of screen */
- X int left = 0, right = -1; /* bounds for redraw */
- X int pad; /* how much to erase at end of line */
- X int backup; /* how far to backup before fixing */
- X int new_shift; /* value of shift based on cursor */
- X int extra; /* adjusts when shift (scroll) happens */
- X int i;
- X int new_right; /* alternate right bound, using gl_extent */
- X
- X if (change == -1 && cursor == 0 && gl_buf[0] == 0) { /* reset */
- X gl_shift = off_right = off_left = 0;
- X return;
- X }
- X pad = (off_right)? gl_width - 1 : gl_cnt - gl_shift; /* old length */
- X backup = gl_pos - gl_shift;
- X if (change >= 0) {
- X gl_cnt = strlen(gl_buf);
- X if (change > gl_cnt)
- X change = gl_cnt;
- X }
- X if (cursor > gl_cnt) {
- X if (cursor != BUF_SIZE) /* BUF_SIZE means end of line */
- X gl_putc('\007');
- X cursor = gl_cnt;
- X }
- X if (cursor < 0) {
- X gl_putc('\007');
- X cursor = 0;
- X }
- X if (off_right || off_left && cursor < gl_shift + gl_width - SCROLL / 2)
- X extra = 2; /* shift the scrolling boundary */
- X else
- X extra = 0;
- X new_shift = cursor + extra + SCROLL - gl_width;
- X if (new_shift > 0) {
- X new_shift /= SCROLL;
- X new_shift *= SCROLL;
- X } else
- X new_shift = 0;
- X if (new_shift != gl_shift) { /* scroll occurs */
- X gl_shift = new_shift;
- X off_left = (gl_shift)? 1 : 0;
- X off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
- X left = gl_shift;
- X new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
- X } else if (change >= 0) { /* no scroll, but text changed */
- X if (change < gl_shift + off_left) {
- X left = gl_shift;
- X } else {
- X left = change;
- X backup = gl_pos - change;
- X }
- X off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
- X right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
- X new_right = (gl_extent && (right > left + gl_extent))?
- X left + gl_extent : right;
- X }
- X pad -= (off_right)? gl_width - 1 : gl_cnt - gl_shift;
- X pad = (pad < 0)? 0 : pad;
- X if (left <= right) { /* clean up screen */
- X for (i=0; i < backup; i++)
- X gl_putc('\b');
- X if (left == gl_shift && off_left) {
- X gl_putc('$');
- X left++;
- X }
- X for (i=left; i < new_right; i++)
- X gl_putc(gl_buf[i]);
- X gl_pos = new_right;
- X if (off_right && new_right == right) {
- X gl_putc('$');
- X gl_pos++;
- X } else {
- X for (i=0; i < pad; i++) /* erase remains of prev line */
- X gl_putc(' ');
- X gl_pos += pad;
- X }
- X }
- X i = gl_pos - cursor; /* move to final cursor location */
- X if (i > 0) {
- X while (i--)
- X gl_putc('\b');
- X } else {
- X for (i=gl_pos; i < cursor; i++)
- X gl_putc(gl_buf[i]);
- X }
- X gl_pos = cursor;
- }
- X
- static int
- gl_tab(char *buf, int offset, int *loc)
- /* default tab handler, acts like tabstops every 8 cols */
- {
- X int i, count, len;
- X
- X len = strlen(buf);
- X count = 8 - (offset + *loc) % 8;
- X for (i=len; i >= *loc; i--)
- X buf[i+count] = buf[i];
- X for (i=0; i < count; i++)
- X buf[*loc+i] = ' ';
- X i = *loc;
- X *loc = i + count;
- X return i;
- }
- X
- /******************* History stuff **************************************/
- X
- #ifndef HIST_SIZE
- #define HIST_SIZE 100
- #endif
- X
- int hist_pos, hist_last;
- char *hist_buf[HIST_SIZE];
- X
- static void
- hist_init()
- {
- X int i;
- X
- X for (i=0; i < HIST_SIZE; i++)
- X hist_buf[i] = (char *)0;
- }
- X
- static void
- hist_add()
- {
- X char *p = gl_buf;
- X
- X while (*p == ' ' || *p == '\t') /* only save nonblank line */
- X p++;
- X if (*p) {
- X hist_buf[hist_last] = hist_save(gl_buf);
- X hist_last = (hist_last + 1) % HIST_SIZE;
- X if (hist_buf[hist_last]) { /* erase next location */
- X free(hist_buf[hist_last]);
- X hist_buf[hist_last] = 0;
- X }
- X }
- X hist_pos = hist_last;
- }
- X
- static void
- hist_prev()
- /* loads previous hist entry into input buffer, sticks on first */
- {
- X int next;
- X
- X next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
- X if (next != hist_last) {
- X if (hist_buf[next]) {
- X hist_pos = next;
- X strcpy(gl_buf, hist_buf[hist_pos]);
- X } else
- X gl_putc('\007');
- X } else
- X gl_putc('\007');
- X if (gl_in_hook)
- X gl_in_hook(gl_buf);
- X gl_fixup(0, BUF_SIZE);
- }
- X
- static void
- hist_next()
- /* loads next hist entry into input buffer, clears on last */
- {
- X if (hist_pos != hist_last) {
- X hist_pos = (hist_pos + 1) % HIST_SIZE;
- X if (hist_buf[hist_pos]) {
- X strcpy(gl_buf, hist_buf[hist_pos]);
- X } else {
- X gl_buf[0] = 0;
- X }
- X } else
- X gl_putc('\007');
- X if (gl_in_hook)
- X gl_in_hook(gl_buf);
- X gl_fixup(0, BUF_SIZE);
- }
- X
- static char *
- hist_save(char *p)
- /* makes a copy of the string */
- {
- X char *s = 0;
- X
- X if (p && ((s = malloc(strlen(p)+1)) != 0)) {
- X strcpy(s, p);
- X }
- X return s;
- }
- SHAR_EOF
- chmod 0644 getline.c ||
- echo 'restore of getline.c failed'
- Wc_c="`wc -c < 'getline.c'`"
- test 20798 -eq "$Wc_c" ||
- echo 'getline.c: original size 20798, current size' "$Wc_c"
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-