home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * *
- * edit.c *
- * *
- ******************************************************************************/
-
- /*-------------------------- INITIAL CODING DATE -----------------------------
- Tue Sep 12 09:09:54 EDT 1989 by George M. Bogatko
-
- -------------------------------- HEADER FILES -----------------------------*/
- #include <stdio.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/termio.h>
- #include <setjmp.h>
- #include <ctype.h>
-
- /*------------------ TYPEDEF'S, DEFINES, STRUCTURE DEF'S ------------------*/
- #define ESC 27
- #define BELL write(1, &bell, 1)
- #define CURBACK write(1, &curback, 1)
- #define SPACE write(1, &space, 1)
- #define PROMPT write(1, prompt, strlen(prompt))
-
- #ifdef NOSIGSET
- #define sigset signal
- #endif
-
- /*---------------- IMPORTED GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/
-
- /*---------------- EXPORTED GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/
- extern int edit();
-
- /*---------------- INTERNAL GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/
- #ident "%W% %G% - George M. Bogatko -"
-
- /* static */ extern void sig_handle();
- static jmp_buf jumpbuf;
- static int lastlen; /* length of the last edited buffer, for blanking out */
-
- #ifdef NOSIGSET
- static int (*oldintsig)();
- static int (*oldquitsig)();
- #else
- static void (*oldintsig)();
- static void (*oldquitsig)();
- #endif
-
- static char *spaces=
- " ";
- static char *backspaces="\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
-
-
- /*-----------------------------------------------------------------------------
-
- SYNOPSIS:
- int edit(char *buf, char *prompt)
-
- DESCRIPTION:
-
- EDIT is the workhorse of the 'edline' command line editor. It
- takes a buffer of characters, and applies the following editing
- commands to it:
-
- ACCEPT LINE <return>
- APPEND a
- DELETE A CHAR x
- REPLACE A CHAR r
- END INSERT/APPEND MODE ESC
- ERASE LINE AND START AGAIN BREAK(break key) or QUIT(ctrl-\)
- INSERT i
- MOVE BACKWARD A WORD b
- MOVE DOWN A LINE j
- MOVE FORWARD A WORD w
- MOVE LEFT A CHAR h
- MOVE RIGHT A CHAR l
- MOVE TO BEGINNING OF LINE 0
- MOVE TO END OF LINE $
- MOVE UP A LINE k
-
- The function does NOT rely on any TERM setting, but does everything
- with writes and backspaces.
-
- ioctl is used to set the terminal in RAW mode. SIGINT and SIGQUIT are
- trapped to restore the previous settings.
-
- The function returns the last character hit, or 255 if SIGINT or
- SIGQUIT are caught.
-
-
- CAVEATS:
- Certain perverse combinations of commands given in a very fast
- sequence will produce strange characters.
-
- This is usually called from 'edline()'
-
- The maximum line length is 78 - strlen(prompt)
-
- =============================================================================*/
- int edit(buf, prompt)
- char *buf;
- char *prompt;
- {
- unsigned char
- *ps=0, /* start of buffer */
- *pe=0, /* end of buffer */
- *pc=0, /* current place in buffer */
- *cp=0, /* a 'current pointer' used in manipulations */
- bell = '\007', /* BEEEEP!! */
- c = 0, /* a temporary character holder */
- curback='\b', /* backspace */
- gotofront = '\r', /* plain return */
- newline = '\n', /* plain newline */
- space = ' '; /* space */
-
- enum {first, next} time = next; /* for first time only things */
-
- int
- char_count = 0,
- eof = 0,
- erase_char = 0,
- fieldlen = 0,
- jmpret,
- maxlen = 78 - strlen(prompt);
-
- struct termio no_canon, canon;
-
- /*
- * flush standard in and out so that any 'printf' or previous stdin
- * requests are cleared out
- */
- fflush(stdin);
- fflush(stdout);
- /*
- * set terminal for prompt input
- */
- ioctl(0, TCGETA, &canon);
- no_canon = canon;
-
- erase_char = canon.c_cc[2];
- eof = canon.c_cc[4];
-
- no_canon.c_lflag &= ~(ICANON|ECHO|ECHOE);
- no_canon.c_cc[4] = 1;
- no_canon.c_cc[5] = 0;
-
- ioctl(0, TCSETAW, &no_canon);
- /*
- * handle sigint sigquit
- */
- oldintsig = sigset(SIGINT, sig_handle);
- oldquitsig = sigset(SIGQUIT, sig_handle);
-
- if( (jmpret = setjmp(jumpbuf)) != 0 )
- {
- if(jmpret == SIGINT)
- c = 255;
- if(jmpret == SIGQUIT)
- c = 254;
- goto abort;
- }
- /*
- * edit buffer
- */
-
- /* DISPLAY BUFFER */
-
- PROMPT;
- if( *buf )
- {
- fieldlen = char_count = strlen(buf);
- write(1,buf,char_count);
- if( lastlen > fieldlen )
- write(1,spaces,lastlen-fieldlen);
- write(1,&gotofront,1);
- PROMPT;
- if( *buf == ' ' )
- {
- *buf = '\0';
- char_count = 0;
- time = first;
- }
- }
- else
- time = first;
- /*
- * set pointers
- */
- pc = ps = (unsigned char *)buf;
- pe = ps + strlen(buf);
-
-
- for(;;)
- {
- /*
- * prime the pump by forcing 'insert' mode if this is the first time
- * in the editor.
- */
- if( time == first )
- {
- c = 'i';
- time = next;
- }
- else
- read(0, &c, 1);
-
- switch(c)
- {
- /* EXIT EDITING */
- case '\n':
- goto abort;
- break;
-
- /* END OF LINE */
- case '$':
- fieldlen = pe-(pc+1);
- write(1,pc,fieldlen);
- pc+=fieldlen;
- break;
-
- /* BEGINNING OF LINE */
- case '0':
- write(1, &gotofront, 1);
- PROMPT;
- pc = ps;
- break;
-
- /* MOVE LEFT */
- case 'h':
- if( pc>ps )
- {
- CURBACK;
- pc--;
- }
- else
- BELL;
- break;
-
- /* INSERT MODE */
- /*
- * yes, there's some yank and put code here. shoot me
- */
- case 'a':
- if(*ps != '\0')
- write(1, pc++, 1);
-
- /* NO BREAK HERE -- FALL THRU */
-
- case 'i':
- for(;;)
- {
- read(0, &c, 1);
-
- /* END INSERT MODE */
- if( c == ESC )
- {
- if( pc > ps)
- {
- pc--;
- CURBACK;
- }
- break;
- }
- /* DELETE CHARACTER WITHIN INSERT MODE */
- else if( c == erase_char )
- {
- if( *ps == '\0' || pc <= ps )
- {
- pc = ps;
- BELL;
- continue;
- }
- else
- {
- pc--;
- CURBACK;
- }
-
- for(cp = pc; *cp != '\0'; cp++)
- {
- *cp = *(cp+1);
- }
-
- fieldlen=pe-pc;
- if(fieldlen)
- write(1,pc,fieldlen-1);
- SPACE;
- write(1,backspaces,fieldlen);
-
- pe--;
- char_count--;
- }
- /* EXIT EDITING FROM INSERT MODE */
- else if ( c == '\n' )
- goto abort;
- /* GATHER CHARS IN INSERT MODE */
- else if( isalnum(c) || ispunct(c) || c == ' ' )
- {
- if( ++char_count >= maxlen )
- {
- BELL;
- char_count--;
- continue;
- }
- for(cp = pe; cp >= pc; cp--)
- {
- *(cp+1) = *cp;
- }
- *pc = c;
-
- fieldlen=(pe-pc);
- write(1,pc,fieldlen+1);
- pc++;
- write(1,backspaces,fieldlen);
-
- pe++;
- }
- }
- break;
-
- /* UP, DOWN A LINE -- command character returned to 'edline()' */
- case 'j':
- case 'k':
- goto abort;
- break;
-
- /* MOVE RIGHT */
- case 'l':
- case ' ':
-
- if( *(pc+1) == '\0' )
- BELL;
- else
- {
- write(1, pc, 1);
- pc++;
- }
- break;
-
- /* FORWARD A WORD */
- case 'w':
- if( (pc+1) == pe )
- break;
- else
- {
- do
- write(1, pc++, 1);
- while( isalnum(*pc) && *(pc+1) != '\0' );
- if( *(pc+1) != '\0' )
- write(1, pc++, 1);
- }
- break;
-
- /* BACKWARD A WORD */
- case 'b':
- if( pc <= ps )
- {
- pc = ps;
- break;
- }
- else
- {
- do
- {
- CURBACK;
- pc--;
- }
- while( isalnum(*pc) && pc > ps );
- if( pc > ps )
- {
- CURBACK;
- pc--;
- }
- }
- break;
-
- /* DELETE A CHAR */
- case 'x':
- if( *ps == '\0' || pc < ps )
- {
- pc = ps;
- BELL;
- break;
- }
-
- for(cp = pc; *cp != '\0'; cp++)
- {
- *cp = *(cp+1);
- }
-
-
-
- fieldlen=pe-pc;
- if(fieldlen)
- write(1,pc,fieldlen-1);
- SPACE;
- write(1,backspaces,fieldlen);
-
- pe--;
- char_count--;
-
- if( pc >= pe )
- {
- pc--;
- if( pc >= ps )
- CURBACK;
- }
-
- break;
-
- /* REPLACE A CHAR */
- case 'r':
- read(0, &c, 1);
- if( c != ESC )
- {
- *pc = c;
- write(1, pc, 1);
- write(1,backspaces,1);
- }
- break;
-
- /* ERROR */
- default:
- BELL;
- break;
- }
- }
- abort:
- /*
- * clean up and return
- */
- write(1, &gotofront, 1);
- ioctl(0, TCSETAW, &canon);
- sigset(SIGINT, oldintsig);
- sigset(SIGQUIT, oldquitsig);
-
- lastlen=strlen(buf);
- return c;
- }
-
- static void sig_handle(sig)
- {
- longjmp(jumpbuf, sig);
- }
-