page%swap@Sun.COM (Bob Page) (05/12/89)
Submitted-by: grwalter@watmath.waterloo.edu (Fred Walter) Posting-number: Volume 89, Issue 131 Archive-name: editors/stevie36.2 # This is a shell archive. # Remove anything above and including the cut line. # Then run the rest of the file through 'sh'. # Unpacked files will be owned by you and have default permissions. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: SHell ARchive # Run the following text through 'sh' to create: # cmdline.c # dec.c # dos.c # dos.h # edit.c # env.h # fileio.c # format_l.c # help.c # inc.c # keymap.h # linefunc.c # macros.h # main.c # This is archive 2 of a 6-part kit. # This archive created: Thu May 11 19:41:25 1989 echo "extracting cmdline.c" sed 's/^X//' << \SHAR_EOF > cmdline.c X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#include "stevie.h" X Xstatic char *altfile = NULL; /* alternate file */ Xstatic int altline; /* line # in alternate file */ X Xstatic char *nowrtmsg = "No write since last change (use ! to override)"; X Xextern char **files; /* used for "n" and "rew" */ Xextern int curfile; Xextern int numfiles; X X/* X * The next two variables contain the bounds of any range given in a command. X * If no range was given, both contain null line pointers. If only a single X * line was given, u_pos will contain a null line pointer. X */ Xstatic LPtr l_pos, u_pos; X Xstatic bool_t interactive; /* TRUE if we're reading a real command line */ X Xstatic bool_t doecmd(); Xstatic void Xbadcmd(), doshell(), get_range(); Xstatic LPtr *get_line(); X X#ifdef MEGAMAX Xoverlay "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 in X * main() to handle initialization commands in the environment variable X * "EXINIT". X */ Xvoid Xreadcmdline(firstc, cmdline) X char firstc; /* either ':', '/', or '?' */ X char *cmdline; /* optional command string */ X{ X char c; X char buff[CMDBUFFSIZE]; X char cmdbuf[CMDBUFFSIZE]; X char argbuf[CMDBUFFSIZE]; X char *p, *q, *cmd, *arg; X bool_t literal_next_flag = FALSE; X X /* X * Clear the range variables. X */ X l_pos.linep = (LINE *) NULL; X u_pos.linep = (LINE *) NULL; X X interactive = (cmdline == NULL); X X if (interactive) X gotocmdline(YES, 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 == CTRL('V') && !literal_next_flag) { X literal_next_flag = TRUE; X outchar('^'); X continue; X } X if (c == '\n' || ((c == '\r' || c == ESC) && (!literal_next_flag))) X break; X if ((c == '\b') && (!literal_next_flag)) { X if (p > buff + (firstc != ':')) { X p--; X /* X * this is gross, but it relies only on 'gotocmdline' X */ X gotocmdline(YES, firstc == ':' ? ':' : NUL); X for (q = buff; q < p; q++) X outstr(chars[*q].ch_str); X } else { X msg(""); X return; /* back to cmd mode */ X } X continue; X } X if ((c == '@') && (!literal_next_flag)) { X p = buff; X gotocmdline(YES, firstc); X continue; X } X if (literal_next_flag) { X literal_next_flag = FALSE; X outchar('\b'); X } X outstr(chars[c].ch_str); X *p++ = c; X } X *p = '\0'; X } else { X if (strlen(cmdline) > CMDBUFFSIZE - 2) /* should really do something X * better here... */ X return; X strcpy(p, cmdline); X } X X /* skip any initial white space */ X for (cmd = buff; *cmd != NUL && isspace(*cmd); cmd++); X X /* search commands */ X c = *cmd; X if (c == '/' || c == '?') { X cmd++; X /* was the command was '//' or '??' (I.E. repeat last search) */ X if ((*cmd == c) || (*cmd == NUL)) { X if (c == '/') X searchagain(FORWARD); X else X searchagain(BACKWARD); 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 * Parse a range, if present (and update the cmd pointer). X */ X get_range(&cmd); X if (l_pos.linep != NULL) { X if (LINEOF(&l_pos) > LINEOF(&u_pos)) { X emsg("Invalid range"); X return; X } X } X strcpy(cmdbuf, cmd); /* save the unmodified command */ X X /* isolate the command and find any argument */ X for (p = cmd; *p != NUL && !isspace(*p); p++); X if (*p == NUL) X arg = NULL; X else { X *p = NUL; X for (p++; *p != NUL && isspace(*p); p++); X if (*p == NUL) { X arg = NULL; X } else { X strcpy(argbuf, p); X arg = argbuf; X } X } X X if (strcmp(cmd, "q!") == 0) { X getout(0); X } X if (strcmp(cmd, "q") == 0) { X if (Changed) { X emsg(nowrtmsg); X } else { X getout(0); X } X return; X } X if (strcmp(cmd, "w") == 0) { X if (arg == NULL) { X if (Filename != NULL) { X if (!writeit(Filename, &l_pos, &u_pos)) { X emsg("Problems occured while writing output file"); X } X } else { X emsg("No output file"); X } X } else { X (void) writeit(arg, &l_pos, &u_pos); X } X return; X } X if (strcmp(cmd, "wq") == 0) { X if (Filename != NULL) { X if (writeit(Filename, (LPtr *) NULL, (LPtr *) NULL)) { X getout(0); X } X } else { X emsg("No output file"); X } X return; X } X if (strcmp(cmd, "x") == 0) { X if (Changed) { X if (Filename != NULL) { X if (!writeit(Filename, (LPtr *) NULL, (LPtr *) NULL)) { X emsg("Problems occured while writing output file"); X return; X } X } else { X emsg("No output file"); X return; X } X } X getout(0); 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 stuffReadbuff(":e"); X if (cmd[1] == '!') X stuffReadbuff("!"); X stuffReadbuff(" "); X stuffReadbuff(files[++curfile]); X stuffReadbuff("\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 stuffReadbuff(":e"); X if (cmd[1] == '!') X stuffReadbuff("!"); X stuffReadbuff(" "); X stuffReadbuff(files[--curfile]); X stuffReadbuff("\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 stuffReadbuff(":e"); X if (cmd[3] == '!') X stuffReadbuff("!"); X stuffReadbuff(" "); X stuffReadbuff(files[0]); X stuffReadbuff("\n"); X return; X } X if (strcmp(cmd, "e") == 0) { X if (Changed) X emsg(nowrtmsg); X else X (void) doecmd(arg); X return; X } X if (strcmp(cmd, "e!") == 0) { X (void) doecmd(arg); 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 CHANGED; X return; X } X if (strcmp(cmd, ".=") == 0) { X smsg("line %d", cntllines(Filemem, Curschar)); X return; X } X if (strcmp(cmd, "$=") == 0) { X smsg("%d", cntllines(Filemem, Fileend) - 1); 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 s_clear(); 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 if (strncmp(cmd, "d", 1) == 0) { X LINE *cp; X int n; X X if (l_pos.linep == NULL) X l_pos = *Curschar; X if (u_pos.linep == NULL) X u_pos = l_pos; X X ResetBuffers(); X n = RowNumber(&l_pos); X AppendPositionToUndoUndobuff(0, n); X AppendPositionToUndobuff(0, n); X if ((Filetop->linep->next == l_pos.linep) && X (u_pos.linep->next == Fileend->linep)) X AppendToUndobuff("a"); X else if (u_pos.linep->next == Fileend->linep) X AppendToUndobuff("o"); X else X AppendToUndobuff("O"); X X n = 0; X cp = l_pos.linep; X for (; cp != NULL && cp != Fileend->linep; cp = cp->next) { X AppendToUndobuff(cp->s); X n++; X if (cp == u_pos.linep) X break; X AppendToUndobuff(NL_STR); X } X AppendToUndobuff(ESC_STR); X X if (n > 1) X AppendNumberToUndoUndobuff(n); X AppendToUndoUndobuff("dd"); X X *Curschar = l_pos; X delline(n); X S_NOT_VALID; X return; X } X if (strncmp(cmd, "s/", 2) == 0) { X dosub(&l_pos, &u_pos, cmdbuf + 1); X return; X } X if (strncmp(cmd, "g/", 2) == 0) { X doglob(&l_pos, &u_pos, cmdbuf + 1); 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 if (u_pos.linep != NULL) X *Curschar = u_pos; X else X *Curschar = l_pos; X X S_CHECK_TOPCHAR_AND_BOTCHAR; X X return; 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 * % (entire file) 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 the X * range spec. If an initial address is found, but no second, the upper bound X * is equal to the lower. X */ Xstatic void Xget_range(cp) X char **cp; X{ X LPtr *l; X char *p; X X if (**cp == '%') { X l_pos.index = 0; X l_pos.linep = Filetop->linep->next; X u_pos.index = 0; X u_pos.linep = Fileend->linep->prev; X (*cp)++; X return; 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 *cp = p; X X if (*p != ',') { /* is there another line spec ? */ X u_pos = l_pos; X return; X } X *cp = ++p; X X if ((l = get_line(cp)) == NULL) { X u_pos = l_pos; X return; X } X u_pos = *l; X} X Xstatic LPtr * Xget_line(cp) X 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': X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X for (lnum = c - '0'; isdigit(*p); p++) X lnum = (lnum * 10) + (*p - '0'); X X if (lnum == 0) X lnum = 1; 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 *cp = p; X return &pos; X} X Xstatic void Xbadcmd() X{ X if (interactive) X emsg("Unrecognized command"); X} X X/* X * dotag(tag, force) - goto tag X */ Xvoid Xdotag(tag, force) X char *tag; X 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 while (fgets(lbuf, LSIZE, tp) != NULL) { 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 (!force && Changed) { X emsg(nowrtmsg); X return; X } X if (doecmd(fname)) { X stuffReadbuff(str); /* str has \n at end */ X stuffReadbuff("\007"); /* CTRL('G') */ X fclose(tp); X return; X } X } X } X emsg("tag not found"); X fclose(tp); X} X Xstatic bool_t Xdoecmd(arg) X char *arg; X{ X int line = 1; /* line # to go to in new file */ X X if (arg != NULL) { X /* X * First detect a ":e" on the current file. This is mainly for ":ta" X * commands where the destination is within the current file. X */ X if (Filename != NULL) { X if (strcmp(arg, Filename) == 0) { X if (!Changed) { X return TRUE; X } X } 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 /* clear mem and read file */ X freeall(); X filealloc(); X UNCHANGED; X X if (readfile(Filename, Filemem, 0)) { X emsg("Can't open file"); X return FALSE; X } X *Topchar = *Curschar; X if (line != 1) { X stuffnumReadbuff(line); X stuffReadbuff("G"); X } X setpcmark(); X X return TRUE; X} X Xstatic void Xdoshell() X{ X char *sh, *getenv(); X X sh = getenv("SHELL"); X if (sh == NULL) { X emsg("Shell variable not set"); X return; X } X gotocmdline(YES, NUL); X X if (system(sh) < 0) { X emsg("Exec failed"); X return; X } X wait_return(); X} X Xvoid Xgotocmdline(clr, firstc) X bool_t clr; X char firstc; 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 */ Xvoid Xmsg(s) X char *s; X{ X gotocmdline(YES, NUL); X outstr(s); X#ifdef AMIGA X flushbuf(); X#endif X#ifdef BSD X flushbuf(); X#endif X} X X/* VARARGS */ Xvoid Xsmsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9) X char *s; X int a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X char sbuf[MAX_COLUMNS + 1]; 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 */ Xvoid Xemsg(s) X char *s; X{ X UndoInProgress = FALSE; X RedrawingDisabled = FALSE; X X if (P(P_EB)) X beep(); X outstr(T_TI); X msg(s); X outstr(T_TP); X#ifdef AMIGA X flushbuf(); X#endif X#ifdef BSD X flushbuf(); X#endif X} X Xvoid Xwait_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 s_clear(); X} SHAR_EOF echo "extracting dec.c" sed 's/^X//' << \SHAR_EOF > dec.c X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#include "stevie.h" X X/* X * dec(p) X * X * Decrement the line pointer 'p' crossing line boundaries as necessary. Return X * 1 when crossing a line, -1 when at start of file, 0 otherwise. X */ Xint Xdec(lp) X register LPtr *lp; X{ X if (lp->index > 0) { /* still within line */ X lp->index--; X return 0; X } X if (lp->linep->prev != Filetop->linep) { /* there is a prior line */ X lp->linep = lp->linep->prev; X lp->index = strlen(lp->linep->s); X return 1; X } X lp->index = 0; /* stick at first char */ X return -1; /* at start of file */ X} SHAR_EOF echo "extracting dos.c" sed 's/^X//' << \SHAR_EOF > dos.c X/* X * DOS System-dependent routines. X * X * System-specific code for MS-DOS. This has been tested with X * MSDOS 3.3 on an AT. Also, the console driver "nansi.sys" is X * required. X * X */ X X#include <dos.h> X#include "stevie.h" X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X int c; X X for (;; beep()) { /* loop until we get a valid character */ X X flushbuf(); /* flush any pending output */ X X switch (c = getch()) { X case 0x1e: X return K_CGRAVE; X case 0: /* special key */ X if (State != NORMAL) { X c = getch(); /* throw away next char */ X continue; /* and loop for another char */ X } X switch (c = getch()) { X case 0x50: X return K_DARROW; X case 0x48: X return K_UARROW; X case 0x4b: X return K_LARROW; X case 0x4d: X return K_RARROW; X case 0x52: X return K_INSERT; X case 0x47: X stuffReadbuff("1G"); X return -1; X case 0x4f: X stuffReadbuff("G"); X return -1; X case 0x51: X stuffReadbuff(mkstr(CTRL('F'))); X return -1; X case 0x49: X stuffReadbuff(mkstr(CTRL('B'))); X return -1; X /* X * Hard-code some useful function key macros. X */ X case 0x3b: /* F1 */ X stuffReadbuff(":p\n"); X return -1; X case 0x54: /* SF1 */ X stuffReadbuff(":p!\n"); X return -1; X case 0x3c: /* F2 */ X stuffReadbuff(":n\n"); X return -1; X case 0x55: /* SF2 */ X stuffReadbuff(":n!\n"); X return -1; X case 0x3d: /* F3 */ X stuffReadbuff(":e #\n"); X return -1; X case 0x3e: /* F4 */ X stuffReadbuff(":rew\n"); X return -1; X case 0x57: /* SF4 */ X stuffReadbuff(":rew!\n"); X return -1; X case 0x3f: /* F5 */ X stuffReadbuff("[["); X return -1; X case 0x40: /* F6 */ X stuffReadbuff("]]"); X return -1; X case 0x41: /* F7 */ X stuffReadbuff("<<"); X return -1; X case 0x42: /* F8 */ X stuffReadbuff(">>"); X return -1; X case 0x43: /* F9 */ X stuffReadbuff(":x\n"); X return -1; X case 0x44: /* F10 */ X stuffReadbuff(":help\n"); X return -1; X default: X break; X } X break; X X default: X return c; X } X } X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X Xflushbuf() X{ X if (bpos != 0) X write(1, outbuf, bpos); X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) X register char c; X{ X outbuf[bpos++] = c; X if (bpos >= BSIZE) X flushbuf(); X} X Xstatic char cell[2] = {0, 7}; X X/* X * outstr(s) - write a string to the console X */ Xvoid Xoutstr(s) X register char *s; X{ X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X if (RedrawingDisabled) X return; X X outone('\007'); X} X Xvoid Xsleep(n) X int n; X{ X /* X * Should do something reasonable here. X */ X} X Xvoid Xdelay() X{ X long l; X X flushbuf(); X /* X * Should do something better here... X */ X for (l = 0; l < 5000; l++); X} X Xvoid Xwindinit() X{ X Columns = 80; X P(P_LI) = Rows = 25; X} X Xvoid Xwindexit(r) X int r; X{ X flushbuf(); X exit(r); X} X Xvoid Xwindgoto(r, c) X register int r, c; X{ X union REGS rr; X X flushbuf(); X rr.h.dh = r; X rr.h.dl = c; X rr.x.bx = 0; X rr.x.ax = 0x0200; X int86(0x10, &rr, &rr); X} X XFILE * Xfopenb(fname, mode) X char *fname; X char *mode; X{ X FILE *fopen(); X char modestr[16]; X X sprintf(modestr, "%sb", mode); X return fopen(fname, modestr); X} SHAR_EOF echo "extracting dos.h" sed 's/^X//' << \SHAR_EOF > dos.h X/* X * MS DOS Machine-dependent routines. X */ X Xint inchar(); Xvoid outchar(); Xvoid outstr(); Xvoid beep(); Xvoid windinit(); Xvoid windexit(); Xvoid windgoto(); Xvoid delay(); Xvoid sleep(); SHAR_EOF echo "extracting edit.c" sed 's/^X//' << \SHAR_EOF > edit.c X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#include "stevie.h" X X/* X * This flag is used to make auto-indent work right on lines where only a X * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and X * reset when any other editting is done on the line. If an <ESC> or <RETURN> X * is received, and did_ai is TRUE, the line is truncated. X */ Xbool_t did_ai = FALSE; X Xvoid Xedit() X{ X char c; X bool_t literal_next_flag = FALSE; 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 s_refresh(NOT_VALID); X X for (;;) { X X if (!RedrawingDisabled) { X /* Figure out where the cursor is based on Curschar. */ X cursupdate(UPDATE_CURSOR); X windgoto(Cursrow, Curscol); X } X c = vgetc(); X X if (State == NORMAL) { X /* We're in the normal (non-insert) mode. */ X X /* Pick up any leading digits and compute 'Prenum' */ X if (isascii(c)) { /* must disallow special chars from "ascii.h" */ X if ((Prenum > 0 && isdigit(c)) || (isdigit(c) && c != '0')) { X Prenum = Prenum * 10 + (c - '0'); X continue; X } X } X /* execute the command */ X normal(c); X Prenum = 0; X X } else { X if (c == CTRL('V') && !literal_next_flag) { X literal_next_flag = TRUE; X outchar('^'); X continue; X } X if (literal_next_flag) { X literal_next_flag = FALSE; X outchar('\b'); X if (c != NL) { X did_ai = FALSE; X insertchar(c); X continue; X } X } X switch (c) { /* We're in insert mode */ X X case ESC: /* an escape ends input mode */ X doESCkey: X /* X * If we just did an auto-indent, truncate the line, and put X * the cursor back. X */ X if (did_ai) { X Curschar->linep->s[0] = NUL; X Curschar->index = 0; X did_ai = FALSE; X } X set_want_col = TRUE; X X /* X * The cursor should end up on the last inserted character. X * This is an attempt to match the real 'vi', but it may not X * be quite right yet. X */ X if (Curschar->index != 0) { X if (gchar(Curschar) == NUL) X dec(Curschar); X else if (Insbuffptr != NULL) X dec(Curschar); X } X State = NORMAL; X msg(""); X X if (!UndoInProgress) { X int n; X char *p; X X if (last_command == 'o') X AppendToUndobuff(UNDO_SHIFTJ_STR); X X if (Insbuffptr != NULL) { X if (last_command == 'O') X AppendToUndobuff("0"); X AppendToRedobuff(Insbuff); X AppendToUndoUndobuff(Insbuff); X n = 0; X for (p = Insbuff; *p != NUL; p++) { X if (*p == NL) { X if (n) { X AppendNumberToUndobuff(n); X AppendToUndobuff("dl"); X n = 0; X } X AppendToUndobuff(UNDO_SHIFTJ_STR); X } else X n++; X } X if (n) { X AppendNumberToUndobuff(n); X AppendToUndobuff("dl"); X } X } X if (last_command == 'c') { X AppendToUndobuff(mkstr(last_command_char)); X AppendToUndobuff(Yankbuff); X AppendToUndobuff(ESC_STR); X } X AppendToRedobuff(ESC_STR); X AppendToUndoUndobuff(ESC_STR); X if (last_command == 'O') X AppendToUndobuff(UNDO_SHIFTJ_STR); X } X break; X X case CTRL('D'): X /* X * Control-D is treated as a backspace in insert mode to make X * auto-indent easier. This isn't completely compatible with X * vi, but it's a lot easier than doing it exactly right, and X * the 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 /* can't backup to a previous line */ X if (Curschar->linep != Insstart->linep && X Curschar->index <= 0) { X beep(); X break; X } X did_ai = FALSE; X dec(Curschar); X delchar(TRUE, FALSE); X /* X * It's a little strange to put backspaces into the redo X * buffer, but it makes auto-indent a lot easier to deal X * with. X */ X AppendToInsbuff(BS_STR); X if (!RedrawingDisabled) /* screen will be fixed later */ X S_LINE_NOT_VALID; X break; X X case CR: X case NL: X AppendToInsbuff(NL_STR); X if (!OpenForward(!RedrawingDisabled)) X goto doESCkey; /* out of memory */ 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 by X * the "redo", "undo" or "put" commands, so it needs to know when it should X * stop and defer processing to the "normal" mechanism. X */ X#define ISSPECIAL(c) ((c) == BS || (c) == NL || (c) == CR || (c) == ESC) X Xvoid Xinsertchar(c) X char c; X{ X if (anyinput()) { /* If there's any pending input, grab up to X * MAX_COLUMNS at once. */ X char p[MAX_COLUMNS + 1]; X int i; X X p[0] = c; X i = 1; X c = vpeekc(); X while (!ISSPECIAL(c) && anyinput() && (i < MAX_COLUMNS)) { X p[i++] = vgetc(); X c = vpeekc(); X } X p[i] = '\0'; X insstr(p); X AppendToInsbuff(p); X } else { X inschar(c); X AppendToInsbuff(mkstr(c)); X } X X if (!RedrawingDisabled) /* screen will be fixed later */ X S_LINE_NOT_VALID; X} X Xvoid Xgetout(r) X int r; X{ X windgoto(Rows - 1, 0); X outchar('\r'); X outchar('\n'); X windexit(r); X} X Xvoid Xscrolldown(nlines) X int nlines; X{ X register LPtr *p; X X S_MUST_UPDATE_BOTCHAR; X S_CHECK_TOPCHAR_AND_BOTCHAR; X X /* Scroll up 'nlines' lines. */ X while (nlines--) { X p = prevline(Topchar); X if (p == NULL) X break; X Topchar->linep = p->linep; X } X /* X * The calling routine must make sure that Curschar is in the correct X * place with relation to Botchar. X */ X} X Xvoid Xscrollup(nlines) X int nlines; X{ X register LPtr *p; X X S_MUST_UPDATE_BOTCHAR; X S_CHECK_TOPCHAR_AND_BOTCHAR; X X /* Scroll down 'nlines' lines. */ X while (nlines--) { X p = nextline(Topchar); X if (p == NULL) X break; X Topchar->linep = p->linep; X } X /* X * The calling routine must make sure that Curschar is in the correct X * place with relation to Topchar. X */ X} X X/* X * oneright oneleft onedown oneup X * X * Move one char {right,left,down,up}. Return TRUE when sucessful, FALSE when X * we hit a boundary (of a line, or the file). X */ X Xbool_t Xoneright() 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 /* FALLTHROUGH */ X case -1: X return FALSE; X } X X return FALSE; /* PARANOIA: should never reach here */ X} X Xbool_t Xoneleft() 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 /* FALLTHROUGH */ X case -1: X return FALSE; X } X X return FALSE; /* PARANOIA: should never reach here */ X} X Xvoid Xbeginline(flag) X bool_t flag; X{ X while (oneleft()); X if (flag) { X while (isspace(gchar(Curschar)) && oneright()); X } X set_want_col = TRUE; X} X Xbool_t Xoneup(n) X register int n; X{ X register int k; X X S_CHECK_TOPCHAR_AND_BOTCHAR; X X for (k = 0; k < n; k++) { X if (Curschar->linep->prev == Filetop->linep) { X if (k > 0) X break; X else X return FALSE; X } X Curschar->linep = Curschar->linep->prev; X } X X /* try to advance to the column we want to be at */ X Curschar->index = 0; X coladvance(Curschar, Curswant); X return TRUE; X} X Xbool_t Xonedown(n) X register int n; X{ X register int k; X X S_CHECK_TOPCHAR_AND_BOTCHAR; X X for (k = 0; k < n; k++) { X if (Curschar->linep->next == Fileend->linep) { X if (k > 0) X break; X else X return FALSE; X } X Curschar->linep = Curschar->linep->next; X } X X /* try to advance to the column we want to be at */ X Curschar->index = 0; X coladvance(Curschar, Curswant); X return TRUE; X} SHAR_EOF echo "extracting env.h" sed 's/^X//' << \SHAR_EOF > env.h X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X/* X * The defines in this file establish the environment we're compiling X * in. Set these appropriately before compiling the editor. X */ X X/* X * One (and only 1) of the following defines should be uncommented. Most of X * the code is pretty machine-independent. Machine dependent code goes in a X * file like tos.c or unix.c. The only other place where machine dependent X * code goes is term.h for escape sequences. X */ X X#ifndef AMIGA X# ifndef BSD X# ifndef UNIX X/* Defined in makefile : AMIGA Amiga */ X/* Defined in makefile : BSD BSD 4.3 */ X/* Defined in makefile : UNIX System V */ X/* #define ATARI Atari ST */ X/* #define OS2 Microsoft OS/2 */ X/* #define DOS MS DOS 3.3 */ X# endif X# endif X#endif X X/* X * If ATARI is defined, one of the following compilers must be selected. X */ X#ifdef ATARI X#define MWC Mark William's C 3.0.9 */ X/* #define MEGAMAX Megamax Compiler */ X/* #define ALCYON Alcyon C compiler */ X X# ifdef MWC X# define AppendNumberToUndoUndobuff XX1 X# define AppendPositionToUndoUndobuff XX2 X# define FOPENB X# endif X X# ifdef MEGAMAX X# define FOPENB X# endif X#endif X X/* X * If HELP is defined, the :help command shows a vi command summary. X */ X#define HELP /* enable help command */ X X/* X * STRCSPN should be defined if the target system doesn't have the X * routine strcspn() available. See regexp.c for details. X */ X X#ifdef ATARI X#define STRCSPN X#endif SHAR_EOF echo "extracting fileio.c" sed 's/^X//' << \SHAR_EOF > fileio.c X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#include "stevie.h" X Xvoid Xfilemess(s) X char *s; X{ X sprintf(IObuff, "\"%s\" %s", ((Filename == NULL) ? "" : Filename), s); X msg(IObuff); X} X Xvoid Xrenum() X{ X LPtr *p; X unsigned long l = 0; X X for (p = Filemem; p != NULL; p = nextline(p), l += LINEINC) X p->linep->num = l; X X Fileend->linep->num = 0xffffffffL; X} X X#ifdef MEGAMAX Xoverlay "fileio" X#endif X Xbool_t Xreadfile(fname, fromp, nochangename) X char *fname; X LPtr *fromp; X bool_t nochangename; /* if TRUE, don't change the Filename */ X{ X FILE *f, *fopen(); X LINE *curr; X char buf2[80]; X int c; X int IObuffsize = 0; X long nchars = 0; X int linecnt = 0; X bool_t wasempty = bufempty(); X int nonascii = 0; /* count garbage characters */ X int nulls = 0; /* count nulls */ X bool_t incomplete = FALSE; /* was the last line incomplete? */ X bool_t toolong = FALSE; /* a line was too long */ X X curr = fromp->linep; X X if (!nochangename) X Filename = strsave(fname); X X f = fopen(fname, "r"); X if (f == NULL) X return TRUE; X X S_NOT_VALID; X X filemess(""); X X do { X c = getc(f); X X if (c == EOF) { X if (IObuffsize == 0)/* normal loop termination */ X break; X X /* X * If we get EOF in the middle of a line, note the fact and X * complete the line ourselves. X */ X incomplete = TRUE; X c = NL; X } X if (c >= 0x80) { X c -= 0x80; X nonascii++; X } X /* X * If we reached the end of the line, OR we ran out of space for it, X * then process the complete line. X */ X if (c == NL || IObuffsize == (IOSIZE - 1)) { X LINE *lp; X X if (c != NL) X toolong = TRUE; X X IObuff[IObuffsize++] = NUL; X lp = newline(IObuffsize); X if (lp == NULL) { X fprintf(stderr, "not enough memory - should never happen"); X getout(1); X } X strcpy(lp->s, IObuff); X X curr->next->prev = lp; /* new line to next one */ X lp->next = curr->next; X X curr->next = lp; /* new line to prior one */ X lp->prev = curr; X X curr = lp; /* new line becomes current */ X IObuffsize = 0; X linecnt++; X } else if (c == NUL) { X nulls++; /* count and ignore nulls */ X } else { X IObuff[IObuffsize++] = (char) c; /* normal character */ X } X X nchars++; X } while (!incomplete && !toolong); X X fclose(f); X X /* X * If the buffer was empty when we started, we have to go back and remove X * the "dummy" line at Filemem and patch up the ptrs. X */ X if (wasempty && linecnt != 0) { X LINE *dummy = Filemem->linep; /* dummy line ptr */ X X Filemem->linep = Filemem->linep->next; X Filemem->linep->prev = Filetop->linep; X Filetop->linep->next = Filemem->linep; X X Curschar->linep = Filemem->linep; X Topchar->linep = Filemem->linep; X X free(dummy->s); /* free string space */ X free((char *) dummy); /* free LINE struct */ X } X renum(); X X if (toolong) { X sprintf(IObuff, "\"%s\" Line too long", fname); X msg(IObuff); X return FALSE; X } X sprintf(IObuff, "\"%s\" %s%d line%s, %ld character%s", X fname, X incomplete ? "[Incomplete last line] " : "", X linecnt, (linecnt > 1) ? "s" : "", X nchars, (nchars > 1) ? "s" : ""); X X buf2[0] = NUL; X X if (nonascii || nulls) { X if (nonascii) { X if (nulls) X sprintf(buf2, " (%d null, %d non-ASCII)", X nulls, nonascii); X else X sprintf(buf2, " (%d non-ASCII)", nonascii); X } else X sprintf(buf2, " (%d null)", nulls); X } X strcat(IObuff, buf2); X msg(IObuff); X X return FALSE; X} X X/* X * writeit - write to file 'fname' lines 'start' through 'end' X * X * If either 'start' or 'end' contain null line pointers, the default is to use X * the start or end of the file respectively. X */ Xbool_t Xwriteit(fname, start, end) X char *fname; X LPtr *start, *end; X{ X FILE *f; X FILE *fopen(); X FILE *fopenb(); /* open in binary mode, where needed */ X char *s; X long nchars; X int lines; X LPtr *p; X X sprintf(IObuff, "\"%s\"", fname); X msg(IObuff); X X /* X * Form the backup file name - change foo.* to foo.bak - use IObuff to X * hold the backup file name X */ X strcpy(IObuff, fname); X for (s = IObuff; *s && *s != '.'; s++); X *s = NUL; X strcat(IObuff, ".bak"); X X /* X * Delete any existing backup and move the current version to the backup. X * For safety, we don't remove the backup until the write has finished X * successfully. And if the 'backup' option is set, leave it around. X */ X rename(fname, IObuff); X X f = P(P_CR) ? fopen(fname, "w") : fopenb(fname, "w"); X if (f == NULL) { X emsg("Can't open file for writing!"); X return FALSE; X } X /* X * If we were given a bound, start there. Otherwise just start at the X * beginning of the file. X */ X if (start == NULL || start->linep == NULL) X p = Filemem; X else X p = start; X X lines = 0; X nchars = 0; X do { X fprintf(f, "%s\n", p->linep->s); X nchars += strlen(p->linep->s) + 1; X lines++; X X /* X * If we were given an upper bound, and we just did that line, then X * bag it now. X */ X if (end != NULL && end->linep != NULL) { X if (end->linep == p->linep) X break; X } X } while ((p = nextline(p)) != NULL); X X fclose(f); X X /* X * Remove the backup unless they want it left around X */ X if (!P(P_BK)) X remove(IObuff); X X sprintf(IObuff, "\"%s\" %d line%s, %ld character%s", fname, X lines, (lines > 1) ? "s" : "", X nchars, (nchars > 1) ? "s" : ""); X msg(IObuff); X UNCHANGED; X X return TRUE; X} SHAR_EOF echo "extracting format_l.c" sed 's/^X//' << \SHAR_EOF > format_l.c X/* X * format_line() X * X * Return a pointer to a string buffer containing a formated screen line. X * X * By G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#include "stevie.h" X Xchar *tab_expand = " "; X Xchar * Xformat_line(ptr, len) X register char *ptr; X int *len; X{ X register char *dest; X register char c; X register int col; X char *p_extra; X int n_extra; X int coff; /* column offset */ X X dest = IObuff; X col = 0; X X coff = P(P_NU) ? 8 : 0; X X n_extra = 0; X p_extra = NULL; X X for (;;) { X if (n_extra > 0) { X c = *p_extra++; X n_extra--; X } else { X c = *ptr++; X while (c >= 32 && c < 127) { X *dest++ = c; X col++; X if (col >= IOSIZE) X goto DONE_FORMAT_LINE; X c = *ptr++; X } X if (c == TAB) { X if (!P(P_LS)) { X /* tab amount depends on current column */ X p_extra = tab_expand; X n_extra = (P(P_TS) - 1) - (col - coff) % P(P_TS); X c = ' '; X } X } else if ((n_extra = chars[c].ch_size - 1) > 0) { X p_extra = chars[c].ch_str; X c = *p_extra++; X } else if (c == NUL) { X if (P(P_NU)) { X *dest++ = '$'; X col++; X } X break; X } X } X *dest++ = c; X col++; X if (col >= IOSIZE) X break; X } XDONE_FORMAT_LINE: X if (col >= IOSIZE) { X dest--; X col--; X } X *dest = NUL; X X if (len != NULL) X *len = col; X X return (IObuff); X} SHAR_EOF echo "extracting help.c" sed 's/^X//' << \SHAR_EOF > help.c X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#include "stevie.h" X Xextern char *Version; X Xstatic int helprow; X X#ifdef HELP X X#ifdef MEGAMAX Xoverlay "help" X#endif X Xstatic void longline(); X Xbool_t Xhelp() X{ X outstr(T_ED); X windgoto(helprow = 0, 0); X X longline("\ XPositioning within file\n\ X=======================\n\ X^F\t\tForward screenfull Worked on by:\n\ X^B\t\tBackward screenfull Tim Thompson\n"); X longline("\ X^D\t\tscroll down half screen Tony Andrews\n\ X^U\t\tscroll up half screen G.R. (Fred) Walter\n"); X longline("\ XG\t\tGoto line (end default)\n\ X]]\t\tnext function\n\ X[[\t\tprevious function\n\ X/re\t\tnext occurence of regular expression 're'\n"); X longline("\ X?re\t\tprior occurence of regular expression 're'\n\ Xn\t\trepeat last / or ?\n\ XN\t\treverse last / or ?\n\ X%\t\tfind matching (, ), {, }, [, or ]\n"); X longline("\ X\n\ XAdjusting the screen\n\ X====================\n\ X^L\t\tRedraw the screen\n\ X^E\t\tscroll window down 1 line\n\ X^Y\t\tscroll window up 1 line\n"); X longline("\ Xz<RETURN>\tredraw, current line at top\n\ Xz-\t\t... at bottom\n\ Xz.\t\t... at center\n"); X X windgoto(0, 32); X longline(Version); X#ifdef AMIGA X longline(" "); X longline(__DATE__); X longline(" "); X longline(__TIME__); X#endif 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 outstr(T_ED); X windgoto(helprow = 0, 0); X X longline("\ XCharacter Positioning\n\ X=====================\n\ X^\t\tfirst non-white\n\ X0\t\tbeginning of line\n\ X$\t\tend of line\n\ Xh\t\tbackward\n"); X longline("\ Xl\t\tforward\n\ X^H\t\tsame as h\n\ Xspace\t\tsame as l\n\ Xfx\t\tfind 'x' forward\n"); X longline("\ XFx\t\tfind 'x' backward\n\ Xtx\t\tupto 'x' forward\n\ XTx\t\tupto 'x' backward\n\ X;\t\tRepeat last f, F, t, or T\n"); X longline("\ X,\t\tinverse of ;\n\ X|\t\tto specified column\n\ X%\t\tfind 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 outstr(T_ED); X windgoto(helprow = 0, 0); X X longline("\ XLine Positioning\n\ X================\n\ XH\t\thome window line\n\ XL\t\tlast window line\n\ XM\t\tmiddle window line\n"); X longline("\ X+\t\tnext line, at first non-white\n\ X-\t\tprevious line, at first non-white\n\ XCR\t\treturn, same as +\n\ Xj\t\tnext line, same column\n\ Xk\t\tprevious line, same column\n"); X X longline("\ X\n\ XMarking and Returning\n\ X=====================\n\ X``\t\tprevious context\n\ X''\t\t... at first non-white in line\n"); X longline("\ Xmx\t\tmark position with letter 'x'\n\ X`x\t\tto mark 'x'\n\ X'x\t\t... 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 outstr(T_ED); X windgoto(helprow = 0, 0); X X longline("\ XInsert and Replace\n\ X==================\n\ Xa\t\tappend after cursor\n\ Xi\t\tinsert before cursor\n\ XA\t\tappend at end of line\n\ XI\t\tinsert before first non-blank\n"); X longline("\ Xo\t\topen line below\n\ XO\t\topen line above\n\ Xrx\t\treplace single char with 'x'\n\ XR\t\treplace characters (not yet)\n\ X~\t\treplace character under cursor with other case\n"); X X longline("\ X\n\ XWords, sentences, paragraphs\n\ X============================\n\ Xw\t\tword forward\n\ Xb\t\tback word\n\ Xe\t\tend of word\n\ X)\t\tto next sentence (not yet)\n\ X}\t\tto next paragraph (not yet)\n"); X longline("\ X(\t\tback sentence (not yet)\n\ X{\t\tback paragraph (not yet)\n\ XW\t\tblank delimited word\n\ XB\t\tback W\n\ XE\t\tto end of W"); 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 outstr(T_ED); X windgoto(helprow = 0, 0); X X longline("\ XUndo & Redo\n\ X=============\n\ Xu\t\tundo last change\n\ XU\t\trestore current line (not yet)\n\ X.\t\trepeat last change\n"); X X longline("\ X\n\ XFile manipulation\n\ X=================\n"); X longline("\ X:w\t\twrite back changes\n\ X:wq\t\twrite and quit\n\ X:x\t\twrite if modified, and quit\n\ X:q\t\tquit\n\ X:q!\t\tquit, discard changes\n\ X:e name\t\tedit file 'name'\n"); X longline("\ X:e!\t\tre-edit, discard changes\n\ X:e #\t\tedit alternate file\n\ X:w name\t\twrite file 'name'\n"); X longline("\ X:n\t\tedit next file in arglist\n\ X:n args\t\tspecify new arglist (not yet)\n\ X:rew\t\trewind arglist\n\ X:f\t\thow current file and lines\n"); X longline("\ X:f file\t\tchange current file name\n\ X:ta tag\t\tto tag file entry 'tag'\n\ X^]\t\t:ta, current word is tag"); 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 outstr(T_ED); X windgoto(helprow = 0, 0); X X longline("\ XOperators (double to affect lines)\n\ X==================================\n\ Xd\t\tdelete\n\ Xc\t\tchange\n"); X longline("\ X<\t\tleft shift\n\ X>\t\tright shift\n\ Xy\t\tyank to buffer\n"); X X longline("\n\ XYank and Put\n\ X============\n\ Xp\t\tput back text\n\ XP\t\tput before\n\ XY\t\tyank lines"); 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 outstr(T_ED); X windgoto(helprow = 0, 0); X X longline("\n\ XMiscellaneous operations\n\ X========================\n\ XC\t\tchange rest of line\n\ XD\t\tdelete rest of line\n\ Xs\t\tsubstitute chars\n"); X longline("\ XS\t\tsubstitute lines (not yet)\n\ XJ\t\tjoin lines\n\ Xx\t\tdelete characters\n\ XX\t\t... before cursor\n\ X:[range]s/search/replace/[g]\n\ X:[range]g/search[/p|/d]\n\ X:[range]d\tdelete range of lines\n"); X X windgoto(helprow = Rows - 1, 47); X longline("<Press any key>"); X X vgetc(); X X return TRUE; X} X Xstatic void Xlongline(p) X char *p; X{ X# ifdef AMIGA X outstr(p); X# else 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# endif X} X#else X Xbool_t Xhelp() X{ X msg("Sorry, help not configured"); X return FALSE; X} X#endif SHAR_EOF echo "extracting inc.c" sed 's/^X//' << \SHAR_EOF > inc.c X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#include "stevie.h" X X/* X * inc(p) X * X * Increment the line pointer 'p' crossing line boundaries as necessary. Return X * 1 when crossing a line, -1 when at end of file, 0 otherwise. X */ Xint Xinc(lp) X register LPtr *lp; X{ X register char *p = &(lp->linep->s[lp->index]); X X if (*p != NUL) { /* still within line */ X lp->index++; X return ((p[1] != NUL) ? 0 : 1); X } X if (lp->linep->next != Fileend->linep) { /* there is a next line */ X lp->index = 0; X lp->linep = lp->linep->next; X return 1; X } X return -1; X} SHAR_EOF echo "extracting keymap.h" sed 's/^X//' << \SHAR_EOF > keymap.h X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X/* X * Keycode definitions for special keys X * X * On systems that have any of these keys, the routine 'inchar' in the X * machine-dependent code should return one of the codes here. X */ X X#define K_CGRAVE 0x1e /* control grave accent */ X X#define K_HELP 0x80 X#define K_UNDO 0x81 X#define K_INSERT 0x82 X#define K_HOME 0x83 X#define K_UARROW 0x84 X#define K_DARROW 0x85 X#define K_LARROW 0x86 X#define K_RARROW 0x87 X#define K_SUARROW 0x88 X#define K_SDARROW 0x89 X#define K_SLARROW 0x8a X#define K_SRARROW 0x8b X X#define K_F1 0x8c /* function keys */ X#define K_F2 0x8d X#define K_F3 0x8e X#define K_F4 0x8f X#define K_F5 0x90 X#define K_F6 0x91 X#define K_F7 0x92 X#define K_F8 0x93 X#define K_F9 0x94 X#define K_F10 0x95 X X#define K_SF1 0x96 /* shifted function keys */ X#define K_SF2 0x97 X#define K_SF3 0x98 X#define K_SF4 0x99 X#define K_SF5 0x9a X#define K_SF6 0x9b X#define K_SF7 0x9c X#define K_SF8 0x9d X#define K_SF9 0x9e X#define K_SF10 0x9f SHAR_EOF echo "extracting linefunc.c" sed 's/^X//' << \SHAR_EOF > linefunc.c X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#include "stevie.h" X X/* X * nextline(curr) X * X * Return a pointer to the beginning of the next line after the one referenced X * by 'curr'. Return NULL if there is no next line (at EOF). X */ X XLPtr * Xnextline(curr) X LPtr *curr; X{ X static LPtr next; X X if (curr != NULL) { X if (curr->linep->next != Fileend->linep) { X next.index = 0; X next.linep = curr->linep->next; X return &next; X } X } X return (LPtr *) NULL; X} X X/* X * prevline(curr) X * X * Return a pointer to the beginning of the line before the one referenced by X * 'curr'. Return NULL if there is no prior line. X */ X XLPtr * Xprevline(curr) X LPtr *curr; X{ X static LPtr prev; X X if (curr != NULL) { X if (curr->linep->prev != Filetop->linep) { X prev.index = 0; X prev.linep = curr->linep->prev; X return &prev; X } X } X return (LPtr *) NULL; X} X X/* X * coladvance(p,col) X * X * Try to advance to the specified column, starting at p. X */ X Xvoid Xcoladvance(p, want_col) X register LPtr *p; X register int want_col; X{ X register char c; X register int col; X register int incr; X X if (gchar(p) != NUL) { /* already at the end of line */ X for (col = 0; want_col > 0;) { X c = gchar(p); X if (c == TAB && !P(P_LS)) X incr = (P(P_TS) - col % P(P_TS)); X else X incr = chars[c].ch_size; X want_col -= incr; X col += incr; X X /* Don't go past the end of the file or the line. */ X if (inc(p)) { X dec(p); X break; X } X } X } X} SHAR_EOF echo "extracting macros.h" sed 's/^X//' << \SHAR_EOF > macros.h X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X/* X * gchar(lp) - get the character at position "lp" X */ X#define gchar(lp) ((lp)->linep->s[(lp)->index]) X X/* X * pchar(lp, c) - put character 'c' at position 'lp' X */ X#define pchar(lp, c) ((lp)->linep->s[(lp)->index] = (c)) X X/* X * pswap(a, b) - swap two position pointers X */ X#define pswap(a, b) { LPtr pswaptmp; pswaptmp = a; a = b; b = pswaptmp; } X X/* X * Position comparisons X */ X#define lt(a, b) ((LINEOF(a) != LINEOF(b)) \ X ? (LINEOF(a) < LINEOF(b)) : ((a)->index < (b)->index)) X X#define ltoreq(a, b) ((LINEOF(a) != LINEOF(b)) \ X ? (LINEOF(a) < LINEOF(b)) : ((a)->index <= (b)->index)) X X#define gt(a, b) ((LINEOF(a) != LINEOF(b)) \ X ? (LINEOF(a) > LINEOF(b)) : ((a)->index > (b)->index)) X X#define gtoreq(a, b) ((LINEOF(a) != LINEOF(b)) \ X ? (LINEOF(a) > LINEOF(b)) : ((a)->index >= (b)->index)) X X#define equal(a, b) (((a)->linep == (b)->linep) && ((a)->index == (b)->index)) X X/* X * anyinput X * X * Return non-zero if input is pending. X */ X#define anyinput() (Readbuffptr != NULL) X X/* X * buf1line() - return TRUE if there is only one line in file buffer X */ X#define buf1line() (Filemem->linep->next == Fileend->linep) X X/* X * bufempty() - return TRUE if the file buffer is empty X */ X#define bufempty() (buf1line() && Filemem->linep->s[0] == NUL) X X/* X * lineempty() - return TRUE if the line is empty X */ X#define lineempty(p) ((p)->linep->s[0] == NUL) X X/* X * startofline() - return TRUE if the given position is at start of line X */ X#define startofline(p) ((p)->index == 0) X X/* X * endofline() - return TRUE if the given position is at end of line X * X * This routine will probably never be called with a position resting on the NUL X * byte, but handle it correctly in case it happens. X */ X#define endofline(p) \ X ((p)->linep->s[(p)->index] == NUL || (p)->linep->s[(p)->index + 1] == NUL) X X/* X * RowNumber() - return the row number (if no UndoInProgress) X */ X#define RowNumber(p) (UndoInProgress ? 0 : cntllines(Filemem, (p))) SHAR_EOF echo "extracting main.c" sed 's/^X//' << \SHAR_EOF > main.c X/* X * STEVIE - Simply Try this Editor for VI Enthusiasts X * X * Code Contributions By : Tim Thompson twitch!tjt X * Tony Andrews onecom!wldrdg!tony X * G. R. (Fred) Walter watmath!watcgl!grwalter X */ X X#ifdef AMIGA X# include <proto/exec.h> X#endif X X#include "stevie.h" X Xint Rows; /* Number of Rows and Columns */ Xint Columns; /* in the current window. */ X Xint CheckTopcharAndBotchar = FALSE; Xint MustUpdateBotchar = FALSE; Xint ValidToCurschar = FALSE; Xint LineNotValid = FALSE; X Xint NumLineSizes = -1; /* # of active LineSizes */ XLINE **LinePointers = NULL; /* Pointer to the line for LineSizes */ Xchar *LineSizes = NULL; /* Size of a line (pline output) */ X Xchar *Filename = NULL;/* Current file name */ X XLPtr *Filemem; /* The contents of the file, as a single X * array. */ XLPtr *Filetop; /* Line 'above' the start of the file */ X XLPtr *Fileend; /* Pointer to the end of the file in Filemem. X * (It points to the byte AFTER the last X * byte.) */ X XLPtr *Topchar; /* Pointer to the byte in Filemem which is in X * the upper left corner of the screen. */ X XLPtr *Botchar; /* Pointer to the byte in Filemem which is X * just off the bottom of the screen. */ X XLPtr *Curschar; /* Pointer to byte in Filemem at which the X * cursor is currently placed. */ X Xint Curscol; /* Current position of cursor (column) */ Xint Cursrow; /* Current position of cursor (row) */ X Xint Cursvcol; /* Current virtual column, the column number X * of the file's actual line, as opposed to X * the column number we're at on the screen. X * This makes a difference on lines that span X * more than one screen line. */ X Xint Curswant = 0; /* The column we'd like to be at. This is X * used try to stay in the same column X * through up/down cursor motions. */ X Xbool_t set_want_col; /* If set, then update Curswant the next time X * through cursupdate() to the current X * virtual column. */ X Xint State = NORMAL; /* This is the current state of the command X * interpreter. */ X Xint Prenum = 0; /* The (optional) number before a command. */ X XLPtr *Insstart; /* This is where the latest insert/append X * mode started. */ X Xbool_t Changed = FALSE;/* Set to TRUE if something in the file has X * been changed and not written out. */ X Xchar *IObuff; /* file reads are done, one line at a time, X * into this buffer; as well as sprintf's */ X Xchar *Insbuffptr = NULL; Xchar *Insbuff; /* Each insertion gets stuffed into this X * buffer. */ X Xchar *Readbuffptr = NULL; Xchar *Readbuff; /* Having this buffer allows STEVIE to easily X * make itself do commands */ X Xchar *Redobuffptr = NULL; Xchar *Redobuff; /* Each command should stuff characters into X * this buffer that will re-execute itself. */ X Xbool_t UndoInProgress = FALSE; /* Set to TRUE if undo'ing */ Xchar *Undobuffptr = NULL; Xchar *Undobuff; /* Each command should stuff characters into X * this buffer that will undo its effects. */ X Xchar *UndoUndobuffptr = NULL; Xchar *UndoUndobuff; /* Each command should stuff characters into X * this buffer that will undo its undo. */ X Xchar *Yankbuffptr = NULL; Xchar *Yankbuff; /* Yank buffer */ X Xchar last_command = NUL; /* last command */ Xchar last_command_char = NUL; /* character needed to undo X * last command */ X Xbool_t RedrawingDisabled = FALSE; /* Set to TRUE if undo'ing or X * put'ing */ X Xchar **files; /* list of input files */ Xint numfiles; /* number of input files */ Xint curfile; /* number of the current file */ X Xstatic void Xusage() 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 X#ifdef AMIGA Xvoid X#else Xint X#endif Xmain(argc, argv) X int argc; X char **argv; X{ X char *initstr; /* 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 int atoi(); X char *getenv(); X X#ifdef AMIGA X { X struct Library *DosBase;/* Used for checking version */ X X DosBase = OpenLibrary("dos.library", 33); X if (!DosBase) { X fprintf(stderr, X "\nSTEVIE requires Version 33 or later of dos.library.\n"); X exit(2); X } else { X CloseLibrary(DosBase); X } X X/* X * I don't think STEVIE should be exited with a break. X */ X (void) signal(SIGINT, SIG_IGN); X } X#endif 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 and for X * the many buffers. X */ X Filetop = (LPtr *) alloc((unsigned) sizeof(LPtr)); X Filemem = (LPtr *) alloc((unsigned) sizeof(LPtr)); X Fileend = (LPtr *) alloc((unsigned) sizeof(LPtr)); X Topchar = (LPtr *) alloc((unsigned) sizeof(LPtr)); X Curschar = (LPtr *) alloc((unsigned) sizeof(LPtr)); X Botchar = (LPtr *) alloc((unsigned) sizeof(LPtr)); X Insstart = (LPtr *) alloc((unsigned) sizeof(LPtr)); X IObuff = alloc(IOSIZE); X Insbuff = alloc(INSERT_SIZE); X Readbuff = alloc(READSIZE); X Redobuff = alloc(REDO_UNDO_SIZE); X Undobuff = alloc(REDO_UNDO_SIZE); X UndoUndobuff = alloc(REDO_UNDO_SIZE); X Yankbuff = alloc(YANKSIZE); X if (Filetop == NULL || X Filemem == NULL || X Fileend == NULL || X Topchar == NULL || X Curschar == NULL || X Botchar == NULL || X Insstart == NULL || X IObuff == NULL || X Insbuff == NULL || X Readbuff == NULL || X Redobuff == NULL || X Undobuff == NULL || X UndoUndobuff == NULL || X Yankbuff == NULL) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X screenalloc(); X filealloc(); /* Initialize Filemem, Filetop & Fileend */ X X s_clear(); X X initstr = getenv("EXINIT"); X if (initstr != NULL) { X char *lp, buf[128]; X X lp = getenv("LINES"); X if (lp != NULL) { X sprintf(buf, "%s lines=%s", initstr, lp); X readcmdline(':', buf); X } else X readcmdline(':', initstr); 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 if (tag) { X stuffReadbuff(":ta "); X stuffReadbuff(tag); X stuffReadbuff("\n"); X } else if (pat) { X stuffReadbuff(pat); X stuffReadbuff("\n"); X } else if (line >= 0) { X if (line > 0) X stuffnumReadbuff(line); X stuffReadbuff("G"); X } X edit(); X /* NOTREACHED */ X /* windexit(0); */ X} X Xvoid XstuffReadbuff(s) X char *s; X{ X if (Readbuffptr == NULL) { X if ((strlen(s) + 1) < READSIZE) { X strcpy(Readbuff, s); X Readbuffptr = Readbuff; X return; X } X } else if ((strlen(Readbuff) + (strlen(s) + 1)) < READSIZE) { X strcat(Readbuff, s); X return; X } X emsg("Couldn't stuffReadbuff() - clearing Readbuff\n"); X *Readbuff = NUL; X Readbuffptr = NULL; X} X Xvoid XstuffnumReadbuff(n) X int n; X{ X char buf[32]; X X sprintf(buf, "%d", n); X stuffReadbuff(buf); X} X X/* OPTRESULT */ Xchar Xvgetc() X{ X int c; X X /* X * inchar() may map special keys by using stuffReadbuff(). If it does so, X * it returns -1 so we know to loop here to get a real char. X */ X do { X if (Readbuffptr != NULL) { X char nextc = *Readbuffptr++; X X if (*Readbuffptr == NUL) { X *Readbuff = NUL; X Readbuffptr = NULL; X } X return (nextc); X } X c = inchar(); X } while (c == -1); X X return (char) c; X} X Xchar Xvpeekc() X{ X if (Readbuffptr != NULL) X return (*Readbuffptr); X return (NUL); X} SHAR_EOF echo "End of archive 2 (of 6)" # if you want to concatenate archives, remove anything after this line exit