rsalz@uunet.uu.net (Rich Salz) (06/06/88)
Submitted-by: onecom!wldrdg!tony (Tony Andrews) Posting-number: Volume 15, Issue 38 Archive-name: stevie/part02 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 2 (of 4)." # Contents: cmdline.c edit.c help.c main.c misccmds.c # Wrapped by rsalz@fig.bbn.com on Sun Jun 5 11:45:43 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'cmdline.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cmdline.c'\" else echo shar: Extracting \"'cmdline.c'\" \(11004 characters\) sed "s/^X//" >'cmdline.c' <<'END_OF_FILE' X/* X * STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt... X * X * Extensive modifications by: Tony Andrews onecom!wldrdg!tony X * X */ X X#include "stevie.h" X static char *altfile = NULL; /* alternate file */ static int altline; /* line # in alternate file */ X static char *nowrtmsg = "No write since last change (use ! to override)"; X extern char **files; /* used for "n" and "rew" */ extern int numfiles, curfile; X X/* X * The next two variables contain the bounds of any range given in a X * command. If no range was given, both contain null line pointers. X * If only a single line was given, u_pos will contain a null line X * pointer. X */ static LPTR l_pos, u_pos; X static bool_t interactive; /* TRUE if we're reading a real command line */ X X#define CMDSZ 100 /* size of the command buffer */ X static bool_t doecmd(); static void badcmd(), doshell(), get_range(); static LPTR *get_line(); X X#ifdef MEGAMAX overlay "cmdline" X#endif X X/* X * readcmdline() - accept a command line starting with ':', '/', or '?' X * X * readcmdline() accepts and processes colon commands and searches. If X * 'cmdline' is null, the command line is read here. Otherwise, cmdline X * points to a complete command line that should be used. This is used X * in main() to handle initialization commands in the environment variable X * "EXINIT". X */ void readcmdline(firstc, cmdline) int firstc; /* either ':', '/', or '?' */ char *cmdline; /* optional command string */ X{ X int c; X char buff[CMDSZ]; X char *p, *q, *cmd, *arg; X X /* X * Clear the range variables. X */ X l_pos.linep = (struct line *) NULL; X u_pos.linep = (struct line *) NULL; X X interactive = (cmdline == NULL); X X if (interactive) X gotocmd(1,1,firstc); X p = buff; X if ( firstc != ':' ) X *p++ = firstc; X X if (interactive) { X /* collect the command string, handling '\b' and @ */ X for ( ; ; ) { X c = vgetc(); X if ( c=='\n'||c=='\r'||c==EOF ) X break; X if ( c=='\b' ) { X if ( p > buff ) { X p--; X /* this is gross, but it relies X * only on 'gotocmd' X */ X gotocmd(1,0,firstc==':'?':':0); X for ( q=buff; q<p; q++ ) X outchar(*q); X } else { X msg(""); X return; /* back to cmd mode */ X } X continue; X } X if ( c=='@' ) { X p = buff; X gotocmd(1,1,firstc); X continue; X } X outchar(c); X *p++ = c; X } X *p = '\0'; X } else { X if (strlen(cmdline) > CMDSZ-2) /* should really do something */ X return; /* better here... */ X strcpy(p, cmdline); X } X X /* skip any initial white space */ X for ( cmd = buff; *cmd != NUL && isspace(*cmd); cmd++ ) X ; X X /* search commands */ X c = *cmd; X if ( c == '/' || c == '?' ) { X cmd++; X if ( *cmd == c ) { X /* the command was '//' or '??' */ X repsearch(); X return; X } X /* If there is a matching '/' or '?' at the end, toss it */ X p = strchr(cmd, NUL); X if ( *(p-1) == c && *(p-2) != '\\' ) X *(p-1) = NUL; X dosearch((c == '/') ? FORWARD : BACKWARD, cmd); X return; X } X X /* X * Parse a range, if present (and update the cmd pointer). X */ X get_range(&cmd); X X /* isolate the command and find any argument */ X for ( p=cmd; *p != NUL && ! isspace(*p); p++ ) X ; X if ( *p == NUL ) X arg = NULL; X else { X *p = NUL; X for (p++; *p != NUL && isspace(*p) ;p++) X ; X arg = p; X if ( *arg == '\0' ) X arg = NULL; X } X if ( strcmp(cmd,"q!")==0 ) X getout(); X if ( strcmp(cmd,"q")==0 ) { X if ( Changed ) X emsg(nowrtmsg); X else X getout(); X return; X } X if ( strcmp(cmd,"w")==0 ) { X if ( arg == NULL ) { X if (Filename != NULL) { X writeit(Filename, &l_pos, &u_pos); X UNCHANGED; X } else X emsg("No output file"); X } X else X writeit(arg, &l_pos, &u_pos); X return; X } X if ( strcmp(cmd,"wq")==0 ) { X if (Filename != NULL) { X if ( writeit(Filename, NULL, NULL) ) X getout(); X } else X emsg("No output file"); X return; X } X if ( strcmp(cmd, "x") == 0 ) { X if (Changed) { X if (Filename != NULL) { X if (!writeit(Filename, NULL, NULL)) X return; X } else { X emsg("No output file"); X return; X } X } X getout(); X } X if ( strcmp(cmd,"f")==0 && arg==NULL ) { X fileinfo(); X return; X } X if ( *cmd == 'n' ) { X if ( (curfile + 1) < numfiles ) { X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[1] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[++curfile]); X stuffin("\n"); X } else X emsg("No more files!"); X return; X } X if ( *cmd == 'p' ) { X if ( curfile > 0 ) { X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[1] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[--curfile]); X stuffin("\n"); X } else X emsg("No more files!"); X return; X } X if ( strncmp(cmd, "rew", 3) == 0) { X if (numfiles <= 1) /* nothing to rewind */ X return; X curfile = 0; X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[3] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[0]); X stuffin("\n"); X return; X } X if ( strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0 ) { X doecmd(arg, cmd[1] == '!'); X return; X } X if ( strcmp(cmd,"f") == 0 ) { X Filename = strsave(arg); X filemess(""); X return; X } X if ( strcmp(cmd,"r") == 0 || strcmp(cmd,".r") == 0 ) { X if ( arg == NULL ) { X badcmd(); X return; X } X if (readfile(arg, Curschar, 1)) { X emsg("Can't open file"); X return; X } X updatescreen(); X CHANGED; X return; X } X if ( strcmp(cmd,".=")==0 ) { X char messbuff[80]; X sprintf(messbuff,"line %d", cntllines(Filemem,Curschar)); X msg(messbuff); X return; X } X if ( strcmp(cmd,"$=")==0 ) { X char messbuff[8]; X sprintf(messbuff, "%d", cntllines(Filemem, Fileend)-1); X msg(messbuff); X return; X } X if ( strncmp(cmd,"ta", 2) == 0 ) { X dotag(arg, cmd[2] == '!'); X return; X } X if ( strcmp(cmd,"set")==0 ) { X doset(arg, interactive); X return; X } X if ( strcmp(cmd,"help")==0 ) { X if (help()) { X screenclear(); X updatescreen(); X } X return; X } X if ( strcmp(cmd, "version") == 0) { X extern char *Version; X X msg(Version); X return; X } X if ( strcmp(cmd, "sh") == 0) { X doshell(); X return; X } X /* X * If we got a line, but no command, then go to the line. X */ X if (*cmd == NUL && l_pos.linep != NULL) { X *Curschar = l_pos; X cursupdate(); X return; X } X X badcmd(); X} X X/* X * get_range - parse a range specifier X * X * Ranges are of the form: X * X * addr[,addr] X * X * where 'addr' is: X * X * $ [+- NUM] X * 'x [+- NUM] (where x denotes a currently defined mark) X * . [+- NUM] X * NUM X * X * The pointer *cp is updated to point to the first character following X * the range spec. If an initial address is found, but no second, the X * upper bound is equal to the lower. X */ static void get_range(cp) char **cp; X{ X LPTR *l; X char *p; X X if ((l = get_line(cp)) == NULL) X return; X X l_pos = *l; X X for (p = *cp; *p != NUL && isspace(*p) ;p++) X ; X X *cp = p; X X if (*p != ',') { /* is there another line spec ? */ X u_pos = l_pos; X return; X } X X *cp = ++p; X X if ((l = get_line(cp)) == NULL) { X u_pos = l_pos; X return; X } X X u_pos = *l; X} X static LPTR * get_line(cp) char **cp; X{ X static LPTR pos; X LPTR *lp; X char *p, c; X int lnum; X X pos.index = 0; /* shouldn't matter... check back later */ X X p = *cp; X /* X * Determine the basic form, if present. X */ X switch (c = *p++) { X X case '$': X pos.linep = Fileend->linep->prev; X break; X X case '.': X pos.linep = Curschar->linep; X break; X X case '\'': X if ((lp = getmark(*p++)) == NULL) { X emsg("Unknown mark"); X return (LPTR *) NULL; X } X pos = *lp; X break; X X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X for (lnum = c - '0'; isdigit(*p) ;p++) X lnum = (lnum * 10) + (*p - '0'); X X pos = *gotoline(lnum); X break; X X default: X return (LPTR *) NULL; X } X X while (*p != NUL && isspace(*p)) X p++; X X if (*p == '-' || *p == '+') { X bool_t neg = (*p++ == '-'); X X for (lnum = 0; isdigit(*p) ;p++) X lnum = (lnum * 10) + (*p - '0'); X X if (neg) X lnum = -lnum; X X pos = *gotoline( cntllines(Filemem, &pos) + lnum ); X } X X *cp = p; X return &pos; X} X static void badcmd() X{ X if (interactive) X emsg("Unrecognized command"); X} X X#define LSIZE 512 /* max. size of a line in the tags file */ X X/* X * dotag(tag, force) - goto tag X */ void dotag(tag, force) char *tag; bool_t force; X{ X FILE *tp, *fopen(); X char lbuf[LSIZE]; X char *fname, *str; X X if ((tp = fopen("tags", "r")) == NULL) { X emsg("Can't open tags file"); X return; X } X X while (fgets(lbuf, LSIZE, tp) != NULL) { X X if ((fname = strchr(lbuf, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *fname++ = '\0'; X if ((str = strchr(fname, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *str++ = '\0'; X X if (strcmp(lbuf, tag) == 0) { X if (doecmd(fname, force)) { X stuffin(str); /* str has \n at end */ X stuffin("\007"); /* CTRL('G') */ X fclose(tp); X return; X } X } X } X emsg("tag not found"); X fclose(tp); X} X static bool_t doecmd(arg, force) char *arg; bool_t force; X{ X int line = 1; /* line # to go to in new file */ X X if (!force && Changed) { X emsg(nowrtmsg); X return FALSE; X } X if ( arg != NULL ) { X /* X * First detect a ":e" on the current file. This is mainly X * for ":ta" commands where the destination is within the X * current file. X */ X if (Filename != NULL && strcmp(arg, Filename) == 0) { X if (!Changed || (Changed && !force)) X return TRUE; X } X if (strcmp(arg, "#") == 0) { /* alternate */ X char *s = Filename; X X if (altfile == NULL) { X emsg("No alternate file"); X return FALSE; X } X Filename = altfile; X altfile = s; X line = altline; X altline = cntllines(Filemem, Curschar); X } else { X altfile = Filename; X altline = cntllines(Filemem, Curschar); X Filename = strsave(arg); X } X } X if (Filename == NULL) { X emsg("No filename"); X return FALSE; X } X X /* clear mem and read file */ X freeall(); X filealloc(); X UNCHANGED; X X readfile(Filename, Filemem, 0); X *Topchar = *Curschar; X if (line != 1) { X stuffnum(line); X stuffin("G"); X } X setpcmark(); X updatescreen(); X return TRUE; X} X static void doshell() X{ X char *sh, *getenv(); X X if ((sh = getenv("SHELL")) == NULL) { X emsg("Shell variable not set"); X return; X } X gotocmd(TRUE, FALSE, 0); X X if (system(sh) < 0) { X emsg("Exec failed"); X return; X } X X wait_return(); X} X void gotocmd(clr, fresh, firstc) bool_t clr, fresh; char firstc; X{ X int n; X X windgoto(Rows-1,0); X if ( clr ) X outstr(T_EL); /* clear the bottom line */ X if ( firstc ) X outchar(firstc); X} X X/* X * msg(s) - displays the string 's' on the status line X */ void msg(s) char *s; X{ X gotocmd(TRUE, TRUE, 0); X outstr(s); X} X void smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9) char *s; int a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X char sbuf[80]; X X sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9); X msg(sbuf); X} X X/* X * emsg() - display an error message X * X * Rings the bell, if appropriate, and calls message() to do the real work X */ void emsg(s) char *s; X{ X if (P(P_EB)) X beep(); X msg(s); X} X void wait_return() X{ X char c; X X outstr("Press RETURN to continue"); X do { X c = vgetc(); X } while (c != '\r' && c != '\n'); X X screenclear(); X updatescreen(); X} END_OF_FILE if test 11004 -ne `wc -c <'cmdline.c'`; then echo shar: \"'cmdline.c'\" unpacked with wrong size! fi # end of 'cmdline.c' fi if test -f 'edit.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'edit.c'\" else echo shar: Extracting \"'edit.c'\" \(6480 characters\) sed "s/^X//" >'edit.c' <<'END_OF_FILE' X/* X * STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt... X * X * Extensive modifications by: Tony Andrews onecom!wldrdg!tony X * X */ X X#include "stevie.h" X X/* X * This flag is used to make auto-indent work right on lines where only X * a <RETURN> or <ESC> is typed. It is set when an auto-indent is done, X * and reset when any other editting is done on the line. If an <ESC> X * or <RETURN> is received, and did_ai is TRUE, the line is truncated. X */ bool_t did_ai = FALSE; X void edit() X{ X int c; X char *p, *q; X X Prenum = 0; X X /* position the display and the cursor at the top of the file. */ X *Topchar = *Filemem; X *Curschar = *Filemem; X Cursrow = Curscol = 0; X X for ( ;; ) { X X /* Figure out where the cursor is based on Curschar. */ X cursupdate(); X X windgoto(Cursrow,Curscol); X X c = vgetc(); X X if (State == NORMAL) { X X /* We're in the normal (non-insert) mode. */ X X /* Pick up any leading digits and compute 'Prenum' */ X if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){ X Prenum = Prenum*10 + (c-'0'); X continue; X } X /* execute the command */ X normal(c); X Prenum = 0; X X } else { X X switch (c) { /* We're in insert mode */ X X case ESC: /* an escape ends input mode */ X X set_want_col = TRUE; X X /* Don't end up on a '\n' if you can help it. */ X if (gchar(Curschar) == NUL && Curschar->index != 0) X dec(Curschar); X X /* X * The cursor should end up on the last inserted X * character. This is an attempt to match the real X * 'vi', but it may not be quite right yet. X */ X if (Curschar->index != 0 && !endofline(Curschar)) X dec(Curschar); X X State = NORMAL; X msg(""); X *Uncurschar = *Insstart; X Undelchars = Ninsert; X /* Undobuff[0] = '\0'; */ X /* construct the Redo buffer */ X p=Redobuff; X q=Insbuff; X while ( q < Insptr ) X *p++ = *q++; X *p++ = ESC; X *p = NUL; X updatescreen(); X break; X X case CTRL('D'): X /* X * Control-D is treated as a backspace in insert X * mode to make auto-indent easier. This isn't X * completely compatible with vi, but it's a lot X * easier than doing it exactly right, and the X * difference isn't very noticeable. X */ X case BS: X /* can't backup past starting point */ X if (Curschar->linep == Insstart->linep && X Curschar->index <= Insstart->index) { X beep(); X break; X } X X /* can't backup to a previous line */ X if (Curschar->linep != Insstart->linep && X Curschar->index <= 0) { X beep(); X break; X } X X did_ai = FALSE; X dec(Curschar); X delchar(TRUE); X Insptr--; X Ninsert--; X cursupdate(); X updateline(); X break; X X case CR: X case NL: X *Insptr++ = NL; X Ninsert++; X opencmd(FORWARD, TRUE); /* open a new line */ X cursupdate(); X updatescreen(); X break; X X default: X did_ai = FALSE; X insertchar(c); X break; X } X } X } X} X X/* X * Special characters in this context are those that need processing other X * than the simple insertion that can be performed here. This includes ESC X * which terminates the insert, and CR/NL which need special processing to X * open up a new line. This routine tries to optimize insertions performed X * by the "redo" command, so it needs to know when it should stop and defer X * processing to the "normal" mechanism. X */ X#define ISSPECIAL(c) ((c) == NL || (c) == CR || (c) == ESC) X void insertchar(c) int c; X{ X char *p; X X if ( ! anyinput() ) { X inschar(c); X *Insptr++ = c; X Ninsert++; X /* X * The following kludge avoids overflowing the statically X * allocated insert buffer. Just dump the user back into X * command mode, and print a message. X */ X if (Insptr+10 >= &Insbuff[1024]) { X stuffin(mkstr(ESC)); X emsg("No buffer space - returning to command mode"); X sleep(2); X } X } X else { X /* If there's any pending input, grab it all at once. */ X p = Insptr; X *Insptr++ = c; X Ninsert++; X for (c = vpeekc(); !ISSPECIAL(c) ;c = vpeekc()) { X c = vgetc(); X *Insptr++ = c; X Ninsert++; X } X *Insptr = '\0'; X insstr(p); X } X updateline(); X} X void getout() X{ X windgoto(Rows-1,0); X putchar('\r'); X putchar('\n'); X windexit(0); X} X void scrolldown(nlines) int nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X X /* Scroll up 'nlines' lines. */ X while (nlines--) { X if ((p = prevline(Topchar)) == NULL) X break; X done += plines(p); X *Topchar = *p; X if (Curschar->linep == Botchar->linep->prev) X *Curschar = *prevline(Curschar); X } X s_ins(0, done); X} X void scrollup(nlines) int nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X register int pl; /* # of plines for the current line */ X X /* Scroll down 'nlines' lines. */ X while (nlines--) { X pl = plines(Topchar); X if ((p = nextline(Topchar)) == NULL) X break; X done += pl; X if (Curschar->linep == Topchar->linep) X *Curschar = *p; X *Topchar = *p; X X } X s_del(0, done); X} X X/* X * oneright X * oneleft X * onedown X * oneup X * X * Move one char {right,left,down,up}. Return TRUE when X * sucessful, FALSE when we hit a boundary (of a line, or the file). X */ X bool_t oneright() X{ X set_want_col = TRUE; X X switch (inc(Curschar)) { X X case 0: X return TRUE; X X case 1: X dec(Curschar); /* crossed a line, so back up */ X /* fall through */ X case -1: X return FALSE; X } X} X bool_t oneleft() X{ X set_want_col = TRUE; X X switch (dec(Curschar)) { X X case 0: X return TRUE; X X case 1: X inc(Curschar); /* crossed a line, so back up */ X /* fall through */ X case -1: X return FALSE; X } X} X void beginline(flag) bool_t flag; X{ X while ( oneleft() ) X ; X if (flag) { X while (isspace(gchar(Curschar)) && oneright()) X ; X } X set_want_col = TRUE; X} X bool_t oneup(n) X{ X LPTR p, *np; X int k; X X p = *Curschar; X for ( k=0; k<n; k++ ) { X /* Look for the previous line */ X if ( (np=prevline(&p)) == NULL ) { X /* If we've at least backed up a little .. */ X if ( k > 0 ) X break; /* to update the cursor, etc. */ X else X return FALSE; X } X p = *np; X } X *Curschar = p; X /* This makes sure Topchar gets updated so the complete line */ X /* is one the screen. */ X cursupdate(); X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} X bool_t onedown(n) X{ X LPTR p, *np; X int k; X X p = *Curschar; X for ( k=0; k<n; k++ ) { X /* Look for the next line */ X if ( (np=nextline(&p)) == NULL ) { X if ( k > 0 ) X break; X else X return FALSE; X } X p = *np; X } X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} END_OF_FILE if test 6480 -ne `wc -c <'edit.c'`; then echo shar: \"'edit.c'\" unpacked with wrong size! fi # end of 'edit.c' fi if test -f 'help.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'help.c'\" else echo shar: Extracting \"'help.c'\" \(8348 characters\) sed "s/^X//" >'help.c' <<'END_OF_FILE' X/* X * STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt... X * X * Extensive modifications by: Tony Andrews onecom!wldrdg!tony X * X */ X X#include "stevie.h" X char *Version = "STEVIE - Version 3.10"; X static int helprow; X X#ifdef HELP X X#ifdef MEGAMAX overlay "help" X#endif X static void longline(); X bool_t help() X{ X X/*********************************************************************** X * First Screen: Positioning within file, Adjusting the Screen X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X longline("\ X Positioning within file\n\ X =======================\n\ X ^F Forward screenfull Original version by:\n\ X ^B Backward screenfull Tim Thompson\n"); longline("\ X ^D scroll down half screen\n\ X ^U scroll up half screen Extensive hacks by:\n"); longline("\ X G Goto line (end default) Tony Andrews\n\ X ]] next function\n\ X [[ previous function\n\ X /re next occurence of regular expression 're'\n"); longline("\ X ?re prior occurence of regular expression 're'\n\ X n repeat last / or ?\n\ X N reverse last / or ?\n\ X % find matching (, ), {, }, [, or ]\n"); longline("\ X\n\ X Adjusting the screen\n\ X ====================\n\ X ^L Redraw the screen\n\ X ^E scroll window down 1 line\n\ X ^Y scroll window up 1 line\n"); longline("\ X z<RETURN> redraw, current line at top\n\ X z- ... at bottom\n\ X z. ... at center\n"); X X windgoto(0, 52); X longline(Version); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Second Screen: Character positioning X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X longline("\ X Character Positioning\n\ X =====================\n\ X ^ first non-white\n\ X 0 beginning of line\n\ X $ end of line\n\ X h backward\n"); longline("\ X l forward\n\ X ^H same as h\n\ X space same as l\n\ X fx find 'x' forward\n"); longline("\ X Fx find 'x' backward\n\ X tx upto 'x' forward\n\ X Tx upto 'x' backward\n\ X ; Repeat last f, F, t, or T\n"); longline("\ X , inverse of ;\n\ X | to specified column\n\ X % find matching (, ), {, }, [, or ]\n"); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Third Screen: Line Positioning, Marking and Returning X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X longline("\ X Line Positioning\n\ X =====================\n\ X H home window line\n\ X L last window line\n\ X M middle window line\n"); longline("\ X + next line, at first non-white\n\ X - previous line, at first non-white\n\ X CR return, same as +\n\ X j next line, same column\n\ X k previous line, same column\n"); X longline("\ X\n\ X Marking and Returning\n\ X =====================\n\ X `` previous context\n\ X '' ... at first non-white in line\n"); longline("\ X mx mark position with letter 'x'\n\ X `x to mark 'x'\n\ X 'x ... at first non-white in line\n"); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X/*********************************************************************** X * Fourth Screen: Insert & Replace, X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X longline("\ X Insert and Replace\n\ X ==================\n\ X a append after cursor\n\ X i insert before cursor\n\ X A append at end of line\n\ X I insert before first non-blank\n"); longline("\ X o open line below\n\ X O open line above\n\ X rx replace single char with 'x'\n\ X R replace characters (not yet)\n"); X longline("\ X\n\ X Words, sentences, paragraphs\n\ X ============================\n\ X w word forward\n\ X b back word\n\ X e end of word\n\ X ) to next sentence (not yet)\n\ X } to next paragraph (not yet)\n"); longline("\ X ( back sentence (not yet)\n\ X { back paragraph (not yet)\n\ X W blank delimited word\n\ X B back W\n\ X E to end of W\n"); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Fifth Screen: Misc. operations, X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X longline("\ X Undo & Redo\n\ X =============\n\ X u undo last change (partially done)\n\ X U restore current line (not yet)\n\ X . repeat last change\n"); X longline("\ X\n\ X File manipulation\n\ X =================\n"); longline("\ X :w write back changes\n\ X :wq write and quit\n\ X :x write if modified, and quit\n\ X :q quit\n\ X :q! quit, discard changes\n\ X :e name edit file 'name'\n"); longline("\ X :e! reedit, discard changes\n\ X :e # edit alternate file\n\ X :w name write file 'name'\n"); longline("\ X :n edit next file in arglist\n\ X :n args specify new arglist (not yet)\n\ X :rew rewind arglist\n\ X :f show current file and lines\n"); longline("\ X :f file change current file name\n\ X :ta tag to tag file entry 'tag'\n\ X ^] :ta, current word is tag\n"); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Sixth Screen: Operators, Misc. operations, Yank & Put X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X longline("\ X Operators (double to affect lines)\n\ X ==================================\n\ X d delete\n\ X c change\n"); longline("\ X < left shift\n\ X > right shift\n\ X y yank to buffer\n"); X longline("\n\ X Miscellaneous operations\n\ X ========================\n\ X C change rest of line\n\ X D delete rest of line\n\ X s substitute chars\n"); longline("\ X S substitute lines (not yet)\n\ X J join lines\n\ X x delete characters\n\ X X ... before cursor\n"); X longline("\n\ X Yank and Put\n\ X ============\n\ X p put back text\n\ X P put before\n\ X Y yank lines"); X X windgoto(helprow = Rows-1, 47); X longline("<Press any key>"); X X vgetc(); X X return TRUE; X} X static void longline(p) char *p; X{ X char *s; X X for ( s = p; *s ;s++ ) { X if ( *s == '\n' ) X windgoto(++helprow, 0); X else X outchar(*s); X } X} X#else X bool_t help() X{ X msg("Sorry, help not configured"); X return FALSE; X} X#endif END_OF_FILE if test 8348 -ne `wc -c <'help.c'`; then echo shar: \"'help.c'\" unpacked with wrong size! fi # end of 'help.c' fi if test -f 'main.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'main.c'\" else echo shar: Extracting \"'main.c'\" \(6750 characters\) sed "s/^X//" >'main.c' <<'END_OF_FILE' X/* X * STEVIE - ST Editor for VI Enthusiasts ...Tim Thompson...twitch!tjt... X * X * Extensive modifications by: Tony Andrews onecom!wldrdg!tony X * X */ X X#include "stevie.h" X int Rows; /* Number of Rows and Columns */ int Columns; /* in the current window. */ X char *Realscreen = NULL; /* What's currently on the screen, a single */ X /* array of size Rows*Columns. */ char *Nextscreen = NULL; /* What's to be put on the screen. */ X char *Filename = NULL; /* Current file name */ X LPTR *Filemem; /* The contents of the file, as a single array. */ X LPTR *Fileend; /* Pointer to the end of the file in Filemem. */ X /* (It points to the byte AFTER the last byte.) */ X LPTR *Topchar; /* Pointer to the byte in Filemem which is */ X /* in the upper left corner of the screen. */ X LPTR *Botchar; /* Pointer to the byte in Filemem which is */ X /* just off the bottom of the screen. */ X LPTR *Curschar; /* Pointer to byte in Filemem at which the */ X /* cursor is currently placed. */ X int Cursrow, Curscol; /* Current position of cursor */ X int Cursvcol; /* Current virtual column, the column number of */ X /* the file's actual line, as opposed to the */ X /* column number we're at on the screen. This */ X /* makes a difference on lines that span more */ X /* than one screen line. */ X int Curswant = 0; /* The column we'd like to be at. This is used */ X /* try to stay in the same column through up/down */ X /* cursor motions. */ X bool_t set_want_col; /* If set, then update Curswant the next time */ X /* through cursupdate() to the current virtual */ X /* column. */ X int State = NORMAL; /* This is the current state of the command */ X /* interpreter. */ X int Prenum = 0; /* The (optional) number before a command. */ X LPTR *Insstart; /* This is where the latest insert/append */ X /* mode started. */ X bool_t Changed = 0; /* Set to 1 if something in the file has been */ X /* changed and not written out. */ X bool_t Debug = 0; X char Redobuff[1024]; /* Each command should stuff characters into this */ X /* buffer that will re-execute itself. */ X char Undobuff[1024]; /* Each command should stuff characters into this */ X /* buffer that will undo its effects. */ X char Insbuff[1024]; /* Each insertion gets stuffed into this buffer. */ X LPTR *Uncurschar; /* Curschar is restored to this before undoing. */ X int Ninsert = 0; /* Number of characters in the current insertion. */ int Undelchars = 0; /* Number of characters to delete, when undoing. */ char *Insptr = NULL; X char **files; /* list of input files */ int numfiles; /* number of input files */ int curfile; /* number of the current file */ X static void usage() X{ X fprintf(stderr, "usage: stevie [file ...]\n"); X fprintf(stderr, " stevie -t tag\n"); X fprintf(stderr, " stevie +[num] file\n"); X fprintf(stderr, " stevie +/pat file\n"); X exit(1); X} X main(argc,argv) int argc; char *argv[]; X{ X char *initstr, *getenv(); /* init string from the environment */ X char *tag = NULL; /* tag from command line */ X char *pat = NULL; /* pattern from command line */ X int line = -1; /* line number from command line */ X X /* X * Process the command line arguments. X */ X if (argc > 1) { X switch (argv[1][0]) { X X case '-': /* -t tag */ X if (argv[1][1] != 't') X usage(); X X if (argv[2] == NULL) X usage(); X X Filename = NULL; X tag = argv[2]; X numfiles = 1; X break; X X case '+': /* +n or +/pat */ X if (argv[1][1] == '/') { X if (argv[2] == NULL) X usage(); X Filename = strsave(argv[2]); X pat = &(argv[1][1]); X numfiles = 1; X X } else if (isdigit(argv[1][1]) || argv[1][1] == NUL) { X if (argv[2] == NULL) X usage(); X Filename = strsave(argv[2]); X numfiles = 1; X X line = (isdigit(argv[1][1])) ? X atoi(&(argv[1][1])) : 0; X } else X usage(); X X break; X X default: /* must be a file name */ X Filename = strsave(argv[1]); X files = &(argv[1]); X numfiles = argc - 1; X break; X } X } else { X Filename = NULL; X numfiles = 1; X } X curfile = 0; X X windinit(); X X /* X * Allocate LPTR structures for all the various position pointers X */ X if ((Filemem = (LPTR *) malloc(sizeof(LPTR))) == NULL) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X if ((Fileend = (LPTR *) malloc(sizeof(LPTR))) == NULL) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X if ((Topchar = (LPTR *) malloc(sizeof(LPTR))) == NULL) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X if ((Botchar = (LPTR *) malloc(sizeof(LPTR))) == NULL) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X if ((Curschar = (LPTR *) malloc(sizeof(LPTR))) == NULL) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X if ((Insstart = (LPTR *) malloc(sizeof(LPTR))) == NULL) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X if ((Uncurschar = (LPTR *) malloc(sizeof(LPTR))) == NULL) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X X screenalloc(); X filealloc(); /* Initialize Filemem & Fileend */ X X screenclear(); X X if ((initstr = getenv("EXINIT")) != NULL) { X char *lp, buf[128]; X X if ((lp = getenv("LINES")) != NULL) { X sprintf(buf, "%s lines=%s", initstr, lp); X readcmdline(':', buf); X } else X readcmdline(':', initstr); X } X X if (Filename != NULL) { X if (readfile(Filename, Filemem, FALSE)) X filemess("[New File]"); X } else X msg("Empty Buffer"); X X setpcmark(); X X updatescreen(); X X if (tag) { X stuffin(":ta "); X stuffin(tag); X stuffin("\n"); X X } else if (pat) { X stuffin(pat); X stuffin("\n"); X X } else if (line >= 0) { X if (line > 0) X stuffnum(line); X stuffin("G"); X } X X edit(); X X windexit(0); X} X X#define RBSIZE 1280 /* should be a little bigger than YBSIZE */ static char getcbuff[RBSIZE]; static char *getcnext = NULL; X void stuffin(s) char *s; X{ X if ( getcnext == NULL ) { X strcpy(getcbuff,s); X getcnext = getcbuff; X } else X strcat(getcbuff,s); X} X void stuffnum(n) int n; X{ X char buf[32]; X X sprintf(buf, "%d", n); X stuffin(buf); X} X void addtobuff(s,c1,c2,c3,c4,c5,c6) char *s; char c1, c2, c3, c4, c5, c6; X{ X char *p = s; X if ( (*p++ = c1) == NUL ) X return; X if ( (*p++ = c2) == NUL ) X return; X if ( (*p++ = c3) == NUL ) X return; X if ( (*p++ = c4) == NUL ) X return; X if ( (*p++ = c5) == NUL ) X return; X if ( (*p++ = c6) == NUL ) X return; X} X int vgetc() X{ X if ( getcnext != NULL ) { X int nextc = *getcnext++; X if ( *getcnext == NUL ) { X *getcbuff = NUL; X getcnext = NULL; X } X return(nextc); X } X return(inchar()); X} X int vpeekc() X{ X if ( getcnext != NULL ) X return(*getcnext); X return(-1); X} X X/* X * anyinput X * X * Return non-zero if input is pending. X */ X bool_t anyinput() X{ X return (getcnext != NULL); X} END_OF_FILE if test 6750 -ne `wc -c <'main.c'`; then echo shar: \"'main.c'\" unpacked with wrong size! fi # end of 'main.c' fi if test -f 'misccmds.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'misccmds.c'\" else echo shar: Extracting \"'misccmds.c'\" \(8039 characters\) sed "s/^X//" >'misccmds.c' <<'END_OF_FILE' X/* X * STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt... X * X * Extensive modifications by: Tony Andrews onecom!wldrdg!tony X * X */ X X#include "stevie.h" X static void openfwd(), openbwd(); X extern int did_ai; X X/* X * opencmd X * X * Add a blank line above or below the current line. X */ X void opencmd(dir, can_ai) int dir; int can_ai; /* if true, consider auto-indent */ X{ X if (dir == FORWARD) X openfwd(can_ai); X else X openbwd(can_ai); X} X static void openfwd(can_ai) int can_ai; X{ X LINE *l; X LPTR *next; X char *s; /* string to be moved to new line, if any */ X X /* X * If we're in insert mode, we need to move the remainder of the X * current line onto the new line. Otherwise the new line is left X * blank. X */ X if (State == INSERT) X s = &Curschar->linep->s[Curschar->index]; X else X s = ""; X X if ((next = nextline(Curschar)) == NULL) /* open on last line */ X next = Fileend; X X /* X * By asking for as much space as the prior line had we make sure X * that we'll have enough space for any auto-indenting. X */ X if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) X return; X X if (*s != NUL) X strcpy(l->s, s); /* copy string to new line */ X#if 0 X else if (can_ai && P(P_AI)) { X /* X * Auto-indent removed due to buggy implementation... X */ X did_ai = TRUE; X } X#endif X X if (State == INSERT) /* truncate current line at cursor */ X *s = NUL; X X X Curschar->linep->next = l; /* link neighbors to new line */ X next->linep->prev = l; X X l->prev = Curschar->linep; /* link new line to neighbors */ X l->next = next->linep; X X if (next == Fileend) /* new line at end */ X l->num = Curschar->linep->num + LINEINC; X X else if ((l->prev->num) + 1 == l->next->num) /* no gap, renumber */ X renum(); X X else { /* stick it in the middle */ X unsigned long lnum; X lnum = ((long)l->prev->num + (long)l->next->num) / 2; X l->num = lnum; X } X X *Curschar = *nextline(Curschar); /* cursor moves down */ X Curschar->index = 0; X X s_ins(Cursrow+1, 1); /* insert a physical line */ X X updatescreen(); /* because Botchar is now invalid... */ X X cursupdate(); /* update Cursrow before insert */ X} X static void openbwd(can_ai) int can_ai; X{ X LINE *l; X LPTR *prev; X X prev = prevline(Curschar); X X if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) X return; X X Curschar->linep->prev = l; /* link neighbors to new line */ X if (prev != NULL) X prev->linep->next = l; X X l->next = Curschar->linep; /* link new line to neighbors */ X if (prev != NULL) X l->prev = prev->linep; X X#if 0 X if (can_ai && P(P_AI)) { X did_ai = TRUE; X } X#endif X X *Curschar = *prevline(Curschar); /* cursor moves up */ X Curschar->index = 0; X X if (prev == NULL) /* new start of file */ X Filemem->linep = l; X X renum(); /* keep it simple - we don't do this often */ X X cursupdate(); /* update Cursrow before insert */ X if (Cursrow != 0) X s_ins(Cursrow, 1); /* insert a physical line */ X X updatescreen(); X} X int cntllines(pbegin,pend) LPTR *pbegin, *pend; X{ X LINE *lp; X int lnum = 1; X X for (lp = pbegin->linep; lp != pend->linep ;lp = lp->next) X lnum++; X X return(lnum); X} X X/* X * plines(p) - return the number of physical screen lines taken by line 'p' X */ int plines(p) LPTR *p; X{ X register int col; X register char *s; X X s = p->linep->s; X X if (*s == NUL) /* empty line */ X return 1; X X /* X * If list mode is on, then the '$' at the end of X * the line takes up one extra column. X */ X col = P(P_LS) ? 1 : 0; X X for (; *s != NUL ;s++) { X if ( *s == TAB && !P(P_LS)) X col += P(P_TS) - (col % P(P_TS)); X else X col += chars[(unsigned)(*s & 0xff)].ch_size; X } X return ((col + (Columns-1)) / Columns); X} X void fileinfo() X{ X long l1, l2; X char buf[80]; X X if (bufempty()) { X msg("Buffer Empty"); X return; X } X X l1 = cntllines(Filemem, Curschar); X l2 = cntllines(Filemem, Fileend) - 1; X sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --", X (Filename != NULL) ? Filename : "No File", X Changed ? " [Modified]" : "", X l1, l2, (l1 * 100)/l2); X msg(buf); X} X X/* X * gotoline(n) - return a pointer to line 'n' X * X * Returns a pointer to the last line of the file if n is zero, or X * beyond the end of the file. X */ LPTR * gotoline(n) int n; X{ X static LPTR l; X X l.index = 0; X X if ( n == 0 ) X l = *prevline(Fileend); X else { X LPTR *p; X X for (l = *Filemem; --n > 0 ;l = *p) X if ((p = nextline(&l)) == NULL) X break; X } X return &l; X} X void inschar(c) int c; X{ X register char *p, *pend; X X /* make room for the new char. */ X if ( ! canincrease(1) ) X return; X X p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1]; X pend = &Curschar->linep->s[Curschar->index]; X X for (; p > pend ;p--) X *p = *(p-1); X X *p = c; X X /* X * If we're in insert mode and showmatch mode is set, then X * check for right parens and braces. If there isn't a match, X * then beep. If there is a match AND it's on the screen, then X * flash to it briefly. If it isn't on the screen, don't do anything. X */ X if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) { X LPTR *lpos, csave; X X if ((lpos = showmatch()) == NULL) /* no match, so beep */ X beep(); X else if (LINEOF(lpos) >= LINEOF(Topchar)) { X updatescreen(); /* show the new char first */ X csave = *Curschar; X *Curschar = *lpos; /* move to matching char */ X cursupdate(); X windgoto(Cursrow, Curscol); X delay(); /* brief pause */ X *Curschar = csave; /* restore cursor position */ X cursupdate(); X } X } X X inc(Curschar); X CHANGED; X} X void insstr(s) register char *s; X{ X register char *p, *endp; X register int k, n = strlen(s); X X /* Move everything in the file over to make */ X /* room for the new string. */ X if (!canincrease(n)) X return; X X endp = &Curschar->linep->s[Curschar->index]; X p = Curschar->linep->s + strlen(Curschar->linep->s) + 1 + n; X X for (; p>endp ;p--) X *p = *(p-n); X X p = &Curschar->linep->s[Curschar->index]; X for ( k=0; k<n; k++ ) { X *p++ = *s++; X inc(Curschar); X } X CHANGED; X} X bool_t delchar(fixpos) bool_t fixpos; /* if TRUE, fix the cursor position when done */ X{ X register int i; X X /* Check for degenerate case; there's nothing in the file. */ X if (bufempty()) X return FALSE; X X if (lineempty()) /* can't do anything */ X return FALSE; X X /* Delete the char. at Curschar by shifting everything */ X /* in the line down. */ X for ( i=Curschar->index+1; i < Curschar->linep->size ;i++) X Curschar->linep->s[i-1] = Curschar->linep->s[i]; X X /* If we just took off the last character of a non-blank line, */ X /* we don't want to end up positioned at the newline. */ X if (fixpos) { X if (gchar(Curschar)==NUL && Curschar->index>0 && State!=INSERT) X Curschar->index--; X } X CHANGED; X X return TRUE; X} X X void delline(nlines) X{ X register LINE *p, *q; X int doscreen = TRUE; /* if true, update the screen */ X X /* X * There's no point in keeping the screen updated if we're X * deleting more than a screen's worth of lines. X */ X if (nlines > (Rows - 1)) { X doscreen = FALSE; X s_del(Cursrow, Rows-1); /* flaky way to clear rest of screen */ X } X X while ( nlines-- > 0 ) { X X if (bufempty()) /* nothing to delete */ X break; X X if (buf1line()) { /* just clear the line */ X Curschar->linep->s[0] = NUL; X Curschar->index = 0; X break; X } X X p = Curschar->linep->prev; X q = Curschar->linep->next; X X if (p == NULL) { /* first line of file so... */ X Filemem->linep = q; /* adjust start of file */ X Topchar->linep = q; /* and screen */ X } else X p->next = q; X q->prev = p; X X clrmark(Curschar->linep); /* clear marks for the line */ X X /* X * Delete the correct number of physical lines on the screen X */ X if (doscreen) X s_del(Cursrow, plines(Curschar)); X X /* X * If deleting the top line on the screen, adjust Topchar X */ X if (Topchar->linep == Curschar->linep) X Topchar->linep = q; X X free(Curschar->linep->s); X free(Curschar->linep); X X Curschar->linep = q; X Curschar->index = 0; /* is this right? */ X CHANGED; X X /* If we delete the last line in the file, back up */ X if ( Curschar->linep == Fileend->linep) { X Curschar->linep = Curschar->linep->prev; X /* and don't try to delete any more lines */ X break; X } X } X} END_OF_FILE if test 8039 -ne `wc -c <'misccmds.c'`; then echo shar: \"'misccmds.c'\" unpacked with wrong size! fi # end of 'misccmds.c' fi echo shar: End of archive 2 \(of 4\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 4 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 4 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.