page@swan.ulowell.edu (Bob Page) (12/02/88)
Submitted-by: grwalter@watcgl.waterloo.edu Posting-number: Volume 2, Issue 82 Archive-name: editors/stevie.2 # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # keymap.h # linefunc.c # macros.h # main.c # mark.c # misccmds.c # param.c # param.h # raw.c # This archive created: Thu Dec 1 20:37:28 1988 cat << \SHAR_EOF > keymap.h /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ /* * Keycode definitions for special keys * * On systems that have any of these keys, the routine 'inchar' in the * machine-dependent code should return one of the codes here. */ #define K_CGRAVE 0x1e /* control grave accent */ #define K_HELP 0x80 #define K_UNDO 0x81 #define K_INSERT 0x82 #define K_HOME 0x83 #define K_UARROW 0x84 #define K_DARROW 0x85 #define K_LARROW 0x86 #define K_RARROW 0x87 #define K_SUARROW 0x88 #define K_SDARROW 0x89 #define K_SLARROW 0x8a #define K_SRARROW 0x8b #define K_F1 0x8c /* function keys */ #define K_F2 0x8d #define K_F3 0x8e #define K_F4 0x8f #define K_F5 0x90 #define K_F6 0x91 #define K_F7 0x92 #define K_F8 0x93 #define K_F9 0x94 #define K_F10 0x95 #define K_SF1 0x96 /* shifted function keys */ #define K_SF2 0x97 #define K_SF3 0x98 #define K_SF4 0x99 #define K_SF5 0x9a #define K_SF6 0x9b #define K_SF7 0x9c #define K_SF8 0x9d #define K_SF9 0x9e #define K_SF10 0x9f SHAR_EOF cat << \SHAR_EOF > linefunc.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" /* * nextline(curr) * * Return a pointer to the beginning of the next line after the one referenced * by 'curr'. Return NULL if there is no next line (at EOF). */ LPTR * nextline(curr) LPTR *curr; { static LPTR next; if (curr != NULL) { if (curr->linep->next != Fileend->linep) { next.index = 0; next.linep = curr->linep->next; return &next; } } return (LPTR *) NULL; } /* * prevline(curr) * * Return a pointer to the beginning of the line before the one referenced by * 'curr'. Return NULL if there is no prior line. */ LPTR * prevline(curr) LPTR *curr; { static LPTR prev; if (curr != NULL) { if (curr->linep->prev != NULL) { prev.index = 0; prev.linep = curr->linep->prev; return &prev; } } return (LPTR *) NULL; } /* * coladvance(p,col) * * Try to advance to the specified column, starting at p. */ LPTR * coladvance(p, col) LPTR *p; int col; { static LPTR lp; int c, in; lp.linep = p->linep; lp.index = p->index; /* If we're on a blank ('\n' only) line, we can't do anything */ if (lp.linep->s[lp.index] == '\0') return &lp; /* try to advance to the specified column */ for (c = 0; col-- > 0; c++) { /* Count a tab for what it's worth (if list mode not on) */ if (gchar(&lp) == TAB && !P(P_LS)) { in = ((P(P_TS) - 1) - c % P(P_TS)); col -= in; c += in; } /* Don't go past the end of */ /* the file or the line. */ if (inc(&lp)) { dec(&lp); break; } } return &lp; } SHAR_EOF cat << \SHAR_EOF > macros.h /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ /* * gchar(lp) - get the character at position "lp" */ #define gchar(lp) ((lp)->linep->s[(lp)->index]) /* * pchar(lp, c) - put character 'c' at position 'lp' */ #define pchar(lp, c) ((lp)->linep->s[(lp)->index] = (c)) /* * pswap(a, b) - swap two position pointers */ #define pswap(a, b) { LPTR pswaptmp; pswaptmp = a; a = b; b = pswaptmp; } /* * Position comparisons */ #define lt(a, b) ((LINEOF(a) != LINEOF(b)) \ ? (LINEOF(a) < LINEOF(b)) : ((a)->index < (b)->index)) #define ltoreq(a, b) ((LINEOF(a) != LINEOF(b)) \ ? (LINEOF(a) < LINEOF(b)) : ((a)->index <= (b)->index)) #define gt(a, b) ((LINEOF(a) != LINEOF(b)) \ ? (LINEOF(a) > LINEOF(b)) : ((a)->index > (b)->index)) #define gtoreq(a, b) ((LINEOF(a) != LINEOF(b)) \ ? (LINEOF(a) > LINEOF(b)) : ((a)->index >= (b)->index)) #define equal(a, b) (((a)->linep == (b)->linep) && ((a)->index == (b)->index)) /* * anyinput * * Return non-zero if input is pending. */ #define anyinput() (Readbuffptr != NULL) /* * buf1line() - return TRUE if there is only one line in file buffer */ #define buf1line() (Filemem->linep->next == Fileend->linep) /* * bufempty() - return TRUE if the file buffer is empty */ #define bufempty() (buf1line() && Filemem->linep->s[0] == NUL) /* * lineempty() - return TRUE if the line is empty */ #define lineempty(p) ((p)->linep->s[0] == NUL) /* * startofline() - return TRUE if the given position is at start of line */ #define startofline(p) ((p)->index == 0) /* * endofline() - return TRUE if the given position is at end of line * * This routine will probably never be called with a position resting on the NUL * byte, but handle it correctly in case it happens. */ #define endofline(p) \ ((p)->linep->s[(p)->index] == NUL || (p)->linep->s[(p)->index + 1] == NUL) /* * RowNumber() - return the row number (if no UndoInProgress) */ #define RowNumber(p) (UndoInProgress ? 0 : cntllines(Filemem, (p))) SHAR_EOF cat << \SHAR_EOF > main.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" int Rows; /* Number of Rows and Columns */ int Columns; /* in the current window. */ char *Realscreen = NULL; /* What's currently on the screen, a * single array of size Rows*Columns. */ char *Nextscreen = NULL; /* What's to be put on the screen. */ char *Filename = NULL;/* Current file name */ LPTR *Filemem; /* The contents of the file, as a single * array. */ LPTR *Fileend; /* Pointer to the end of the file in Filemem. * (It points to the byte AFTER the last * byte.) */ LPTR *Topchar; /* Pointer to the byte in Filemem which is in * the upper left corner of the screen. */ LPTR *Botchar; /* Pointer to the byte in Filemem which is * just off the bottom of the screen. */ LPTR *Curschar; /* Pointer to byte in Filemem at which the * cursor is currently placed. */ int Curscol; /* Current position of cursor (column) */ int Cursrow; /* Current position of cursor (row) */ int Cursvcol; /* Current virtual column, the column number * of the file's actual line, as opposed to * the column number we're at on the screen. * This makes a difference on lines that span * more than one screen line. */ int Curswant = 0; /* The column we'd like to be at. This is * used try to stay in the same column * through up/down cursor motions. */ bool_t set_want_col; /* If set, then update Curswant the next time * through cursupdate() to the current * virtual column. */ int State = NORMAL; /* This is the current state of the command * interpreter. */ int Prenum = 0; /* The (optional) number before a command. */ LPTR *Insstart; /* This is where the latest insert/append * mode started. */ bool_t Changed = FALSE;/* Set to TRUE if something in the file has * been changed and not written out. */ char *IObuff; /* file reads are done, one line at a time, * into this buffer; as well as sprintf's */ char *Insbuffptr = NULL; char *Insbuff; /* Each insertion gets stuffed into this * buffer. */ char *Readbuffptr = NULL; char *Readbuff; /* Having this buffer allows STEVIE to easily * make itself do commands */ char *Redobuffptr = NULL; char *Redobuff; /* Each command should stuff characters into * this buffer that will re-execute itself. */ bool_t UndoInProgress = FALSE; /* Set to TRUE if undo'ing */ char *Undobuffptr = NULL; char *Undobuff; /* Each command should stuff characters into * this buffer that will undo its effects. */ char *UndoUndobuffptr = NULL; char *UndoUndobuff; /* Each command should stuff characters into * this buffer that will undo its undo. */ char *Yankbuffptr = NULL; char *Yankbuff; /* Yank buffer */ char last_command = NUL; /* last command */ char last_command_char = NUL; /* character needed to undo * last command */ bool_t RedrawingDisabled = FALSE; /* Set to TRUE if undo'ing or * put'ing */ bool_t MustRedrawLine = FALSE; /* Set to TRUE if we must redraw the * current line */ bool_t MustRedrawScreen = TRUE; /* Set to TRUE if we must * redraw the screen */ char **files; /* list of input files */ int numfiles; /* number of input files */ int curfile; /* number of the current file */ static void usage() { fprintf(stderr, "usage: stevie [file ...]\n"); fprintf(stderr, " stevie -t tag\n"); fprintf(stderr, " stevie +[num] file\n"); fprintf(stderr, " stevie +/pat file\n"); exit(1); } #ifdef AMIGA void #else int #endif main(argc, argv) int argc; char **argv; { char *initstr, *getenv(); /* init string from the environment */ char *tag = NULL; /* tag from command line */ char *pat = NULL; /* pattern from command line */ int line = -1; /* line number from command line */ int atoi(); #ifdef AMIGA /* * This won't be needed if you have a version of Lattice 4.01 without broken * break signal handling. */ (void) signal(SIGINT, SIG_IGN); #endif /* * Process the command line arguments. */ if (argc > 1) { switch (argv[1][0]) { case '-': /* -t tag */ if (argv[1][1] != 't') usage(); if (argv[2] == NULL) usage(); Filename = NULL; tag = argv[2]; numfiles = 1; break; case '+': /* +n or +/pat */ if (argv[1][1] == '/') { if (argv[2] == NULL) usage(); Filename = strsave(argv[2]); pat = &(argv[1][1]); numfiles = 1; } else if (isdigit(argv[1][1]) || argv[1][1] == NUL) { if (argv[2] == NULL) usage(); Filename = strsave(argv[2]); numfiles = 1; line = (isdigit(argv[1][1])) ? atoi(&(argv[1][1])) : 0; } else usage(); break; default: /* must be a file name */ Filename = strsave(argv[1]); files = &(argv[1]); numfiles = argc - 1; break; } } else { Filename = NULL; numfiles = 1; } curfile = 0; windinit(); /* * Allocate LPTR structures for all the various position pointers */ if ((Filemem = (LPTR *) malloc((unsigned) sizeof(LPTR))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Fileend = (LPTR *) malloc((unsigned) sizeof(LPTR))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Topchar = (LPTR *) malloc((unsigned) sizeof(LPTR))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Botchar = (LPTR *) malloc((unsigned) sizeof(LPTR))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Curschar = (LPTR *) malloc((unsigned) sizeof(LPTR))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Insstart = (LPTR *) malloc((unsigned) sizeof(LPTR))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } /* * Allocate space for the many buffers */ if ((IObuff = malloc(IOSIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Insbuff = malloc(INSERT_SIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Readbuff = malloc(READSIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Redobuff = malloc(REDO_UNDO_SIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Undobuff = malloc(REDO_UNDO_SIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((UndoUndobuff = malloc(REDO_UNDO_SIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Yankbuff = malloc(YANKSIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } screenalloc(); filealloc(); /* Initialize Filemem & Fileend */ screenclear(); if ((initstr = getenv("EXINIT")) != NULL) { char *lp, buf[128]; if ((lp = getenv("LINES")) != NULL) { sprintf(buf, "%s lines=%s", initstr, lp); readcmdline(':', buf); } else readcmdline(':', initstr); } if (Filename != NULL) { if (readfile(Filename, Filemem, FALSE)) filemess("[New File]"); } else msg("Empty Buffer"); setpcmark(); updateNextscreen(); if (tag) { stuffReadbuff(":ta "); stuffReadbuff(tag); stuffReadbuff("\n"); } else if (pat) { stuffReadbuff(pat); stuffReadbuff("\n"); } else if (line >= 0) { if (line > 0) stuffnumReadbuff(line); stuffReadbuff("G"); } edit(); windexit(0); } void stuffReadbuff(s) char *s; { if (strlen(s) == 0) return; if (Readbuffptr == NULL) { if ((strlen(s) + 1) < READSIZE) { strcpy(Readbuff, s); Readbuffptr = Readbuff; } else emsg("Couldn't stuffReadbuff() - should never happen"); } else if ((strlen(Readbuff) + (strlen(s) + 1)) < READSIZE) strcat(Readbuff, s); else emsg("Couldn't stuffReadbuff() - should never happen"); } void stuffnumReadbuff(n) int n; { char buf[32]; sprintf(buf, "%d", n); stuffReadbuff(buf); } /* OPTRESULT */ char vgetc() { if (Readbuffptr != NULL) { char nextc = *Readbuffptr++; if (*Readbuffptr == NUL) { *Readbuff = NUL; Readbuffptr = NULL; } return (nextc); } return (inchar()); } char vpeekc() { if (Readbuffptr != NULL) return (*Readbuffptr); return (NUL); } SHAR_EOF cat << \SHAR_EOF > mark.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" #ifdef MEGAMAX overlay "mark" #endif /* * This file contains routines to maintain and manipulate marks. */ #define NMARKS 10 /* max. # of marks that can be saved */ struct mark { char name; LPTR pos; }; static struct mark mlist[NMARKS]; static struct mark pcmark; /* previous context mark */ static bool_t pcvalid = FALSE;/* true if pcmark is valid */ /* * setmark(c) - set mark 'c' at current cursor position * * Returns TRUE on success, FALSE if no room for mark or bad name given. */ bool_t setmark(c) char c; { int i; if (!isalpha(c)) return FALSE; /* * If there is already a mark of this name, then just use the existing * mark entry. */ for (i = 0; i < NMARKS; i++) { if (mlist[i].name == c) { mlist[i].pos = *Curschar; return TRUE; } } /* * There wasn't a mark of the given name, so find a free slot */ for (i = 0; i < NMARKS; i++) { if (mlist[i].name == NUL) { /* got a free one */ mlist[i].name = c; mlist[i].pos = *Curschar; return TRUE; } } return FALSE; } /* * setpcmark() - set the previous context mark to the current position */ void setpcmark() { pcmark.pos = *Curschar; pcvalid = TRUE; } /* * getmark(c) - find mark for char 'c' * * Return pointer to LPTR or NULL if no such mark. */ LPTR * getmark(c) char c; { int i; if (c == '\'' || c == '`') /* previous context mark */ return pcvalid ? &(pcmark.pos) : (LPTR *) NULL; for (i = 0; i < NMARKS; i++) { if (mlist[i].name == c) return &(mlist[i].pos); } return (LPTR *) NULL; } /* * clrall() - clear all marks * * Used mainly when trashing the entire buffer during ":e" type commands */ void clrall() { int i; for (i = 0; i < NMARKS; i++) mlist[i].name = NUL; pcvalid = FALSE; } /* * clrmark(line) - clear any marks for 'line' * * Used any time a line is deleted so we don't have marks pointing to * non-existent lines. */ void clrmark(line) LINE *line; { int i; for (i = 0; i < NMARKS; i++) { if (mlist[i].pos.linep == line) mlist[i].name = NUL; } if (pcvalid && (pcmark.pos.linep == line)) pcvalid = FALSE; } SHAR_EOF cat << \SHAR_EOF > misccmds.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" static bool_t openfwd(), openbwd(); extern int did_ai; /* * opencmd * * Add a blank line above or below the current line. */ bool_t opencmd(dir, can_ai) int dir; int can_ai; /* if true, consider auto-indent */ { if (dir == FORWARD) return (openfwd(can_ai)); else return (openbwd(can_ai)); } static bool_t openfwd(can_ai) int can_ai; { LINE *l; LPTR *next; char *s; /* string to be moved to new line, if any */ /* * If we're in insert mode, we need to move the remainder of the current * line onto the new line. Otherwise the new line is left blank. */ if (State == INSERT) s = &Curschar->linep->s[Curschar->index]; else s = ""; if ((next = nextline(Curschar)) == NULL) /* open on last line */ next = Fileend; /* * By asking for as much space as the prior line had we make sure that * we'll have enough space for any auto-indenting. */ if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) { emsg("out of memory"); beep(); sleep(2); return (FALSE); } if (*s != NUL) strcpy(l->s, s); /* copy string to new line */ #ifdef AUTO_INDENT else if (can_ai && P(P_AI)) { /* * Auto-indent removed due to buggy implementation... */ did_ai = TRUE; } #endif if (State == INSERT) /* truncate current line at cursor */ *s = NUL; Curschar->linep->next = l; /* link neighbors to new line */ next->linep->prev = l; l->prev = Curschar->linep; /* link new line to neighbors */ l->next = next->linep; if (next == Fileend) /* new line at end */ l->num = Curschar->linep->num + LINEINC; else if ((l->prev->num) + 1 == l->next->num) /* no gap, renumber */ renum(); else { /* stick it in the middle */ long lnum; lnum = (l->prev->num + l->next->num) / 2; l->num = lnum; } *Curschar = *nextline(Curschar); /* cursor moves down */ Curschar->index = 0; s_ins(Cursrow + 1, 1); /* insert a physical line */ updateNextscreen(); /* because Botchar is now invalid */ cursupdate(); /* update Cursrow before insert */ return (TRUE); } static bool_t openbwd(can_ai) int can_ai; { LINE *l; LPTR *prev; prev = prevline(Curschar); if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) { emsg("out of memory"); beep(); sleep(2); return (FALSE); } Curschar->linep->prev = l; /* link neighbors to new line */ if (prev != NULL) prev->linep->next = l; l->next = Curschar->linep; /* link new line to neighbors */ if (prev != NULL) l->prev = prev->linep; #ifdef AUTO_INDENT if (can_ai && P(P_AI)) { /* * Auto-indent removed due to buggy implementation... */ did_ai = TRUE; } #endif *Curschar = *prevline(Curschar); /* cursor moves up */ Curschar->index = 0; if (prev == NULL) /* new start of file */ Filemem->linep = l; renum(); /* keep it simple - we don't do this often */ cursupdate(); /* update Cursrow before insert */ if (Cursrow != 0) s_ins(Cursrow, 1); /* insert a physical line */ updateNextscreen(); return (TRUE); } int cntllines(pbegin, pend) LPTR *pbegin, *pend; { register LINE *lp; register int lnum = 1; for (lp = pbegin->linep; lp != pend->linep; lp = lp->next) lnum++; return (lnum); } /* * plines(p) - return the number of physical screen lines taken by line 'p' */ int plines(p) LPTR *p; { int col; char *s; if (p == NULL) { fprintf(stderr, "plines(p) : p == NULL ????"); return (0); } s = p->linep->s; if (*s == NUL) /* empty line */ return 1; /* * If list mode is on, then the '$' at the end of the line takes up one * extra column. */ col = P(P_LS) ? 1 : 0; for (; *s != NUL; s++) { if (*s == TAB && !P(P_LS)) col += P(P_TS) - (col % P(P_TS)); else col += chars[*s].ch_size; } return ((col + (Columns - 1)) / Columns); } void fileinfo() { long l1, l2; char buf[MAX_COLUMNS + 1]; if (bufempty()) { msg("Buffer Empty"); return; } l1 = cntllines(Filemem, Curschar); l2 = cntllines(Filemem, Fileend) - 1; sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --", (Filename != NULL) ? Filename : "No File", Changed ? " [Modified]" : "", l1, l2, (l1 * 100) / l2); msg(buf); } /* * gotoline(n) - return a pointer to line 'n' * * Returns a pointer to the last line of the file if n is zero, or beyond the * end of the file. */ LPTR * gotoline(n) int n; { static LPTR l; l.index = 0; if (n == 0) l = *prevline(Fileend); else { LPTR *p; for (l = *Filemem; --n > 0; l = *p) if ((p = nextline(&l)) == NULL) break; } return &l; } void inschar(c) char c; { char *p; char *pend; /* make room for the new char. */ if (!canincrease(1)) return; p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1]; pend = &Curschar->linep->s[Curschar->index]; for (; p > pend; p--) *p = *(p - 1); *p = c; if (RedrawingDisabled) { inc(Curschar); return; } /* * If we're in insert mode and showmatch mode is set, then check for * right parens and braces. If there isn't a match, then beep. If there * is a match AND it's on the screen, then flash to it briefly. If it * isn't on the screen, don't do anything. */ if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) { LPTR *lpos, csave; if ((lpos = showmatch()) == NULL) /* no match, so beep */ beep(); else if (LINEOF(lpos) >= LINEOF(Topchar)) { updateNextscreen(); /* show the new char first */ updateRealscreen(); csave = *Curschar; *Curschar = *lpos; /* move to matching char */ cursupdate(); windgoto(Cursrow, Curscol); delay(); /* brief pause */ *Curschar = csave; /* restore cursor position */ cursupdate(); } } inc(Curschar); } void insstr(s) char *s; { char *p, *endp; int k, n = strlen(s); /* Move everything in the file over to make */ /* room for the new string. */ if (!canincrease(n)) return; endp = &Curschar->linep->s[Curschar->index]; p = Curschar->linep->s + strlen(Curschar->linep->s) + 1 + n; for (; p > endp; p--) *p = *(p - n); p = &Curschar->linep->s[Curschar->index]; for (k = 0; k < n; k++) { *p++ = *s++; inc(Curschar); } } bool_t delchar(fixpos, undo) bool_t fixpos; /* if TRUE fix the cursor position when done */ bool_t undo; /* if TRUE put char deleted into Undo buffer */ { int i; /* Check for degenerate case; there's nothing in the file. */ if (bufempty()) return FALSE; if (lineempty(Curschar)) /* can't do anything */ return FALSE; if (undo) AppendToUndobuff(mkstr(gchar(Curschar))); /* Delete the char. at Curschar by shifting everything in the line down. */ for (i = Curschar->index + 1; i < Curschar->linep->size; i++) Curschar->linep->s[i - 1] = Curschar->linep->s[i]; /* * If we just took off the last character of a non-blank line, we don't * want to end up positioned at the newline. */ if (fixpos) { if (gchar(Curschar) == NUL && Curschar->index > 0 && State != INSERT) Curschar->index--; } return TRUE; } void delline(nlines) { LINE *p, *q; int doscreen = TRUE; /* if true, update the screen */ /* * There's no point in keeping the screen updated if we're deleting more * than a screen's worth of lines. */ if (nlines > (Rows - 1)) { doscreen = FALSE; s_del(Cursrow, Rows - 1); /* flaky way to clear rest of screen */ } while (nlines-- > 0) { if (bufempty()) /* nothing to delete */ break; if (buf1line()) { /* just clear the line */ Curschar->linep->s[0] = NUL; Curschar->index = 0; break; } p = Curschar->linep->prev; q = Curschar->linep->next; if (p == NULL) { /* first line of file so... */ Filemem->linep = q; /* adjust start of file */ Topchar->linep = q; /* and screen */ } else p->next = q; q->prev = p; clrmark(Curschar->linep); /* clear marks for the line */ /* * Delete the correct number of physical lines on the screen */ if (doscreen) s_del(Cursrow, plines(Curschar)); /* * If deleting the top line on the screen, adjust Topchar */ if (Topchar->linep == Curschar->linep) Topchar->linep = q; free(Curschar->linep->s); free((char *) (Curschar->linep)); Curschar->linep = q; Curschar->index = 0; /* is this right? */ /* If we delete the last line in the file, back up */ if (Curschar->linep == Fileend->linep) { Curschar->linep = Curschar->linep->prev; /* and don't try to delete any more lines */ break; } } } SHAR_EOF cat << \SHAR_EOF > param.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ /* * Code to handle user-settable parameters. This is all pretty much table- * driven. To add a new parameter, put it in the params array, and add a * macro for it in param.h. If it's a numeric parameter, add any necessary * bounds checks to doset(). String parameters aren't currently supported. */ #include "stevie.h" struct param params[] = { {"tabstop", "ts", 8, P_NUM}, {"scroll", "scroll", 12, P_NUM}, {"report", "report", 5, P_NUM}, {"lines", "lines", 25, P_NUM}, {"vbell", "vb", TRUE, P_BOOL}, {"showmatch", "sm", FALSE, P_BOOL}, {"wrapscan", "ws", TRUE, P_BOOL}, {"errorbells", "eb", FALSE, P_BOOL}, {"showmode", "mo", FALSE, P_BOOL}, {"backup", "bk", FALSE, P_BOOL}, {"return", "cr", TRUE, P_BOOL}, {"list", "list", FALSE, P_BOOL}, {"autoindent", "ai", FALSE, P_BOOL}, {"", "", 0, 0,} /* end marker */ }; static void showparms(); void doset(arg, inter) char *arg; /* parameter string */ bool_t inter; /* TRUE if called interactively */ { int i; char *s; bool_t did_lines = FALSE; bool_t state = TRUE; /* new state of boolean parms. */ if (arg == NULL) { showparms(FALSE); return; } if (strncmp(arg, "all", 3) == 0) { showparms(TRUE); return; } if (strncmp(arg, "no", 2) == 0) { state = FALSE; arg += 2; } for (i = 0; params[i].fullname[0] != NUL; i++) { s = params[i].fullname; if (strncmp(arg, s, strlen(s)) == 0) /* matched full name */ break; s = params[i].shortname; if (strncmp(arg, s, strlen(s)) == 0) /* matched short name */ break; } if (params[i].fullname[0] != NUL) { /* found a match */ if (params[i].flags & P_NUM) { did_lines = (i == P_LI); if (inter && (arg[strlen(s)] != '=' || state == FALSE)) emsg("Invalid set of numeric parameter"); else { params[i].value = atoi(arg + strlen(s) + 1); params[i].flags |= P_CHANGED; } } else { /* boolean */ if (inter && (arg[strlen(s)] == '=')) emsg("Invalid set of boolean parameter"); else { params[i].value = state; params[i].flags |= P_CHANGED; } } } else { if (inter) emsg("Unrecognized 'set' option"); } /* * Update the screen in case we changed something like "tabstop" or * "list" that will change its appearance. */ if (inter) updateNextscreen(); if (did_lines) { Rows = P(P_LI); screenalloc(); /* allocate new screen buffers */ screenclear(); updateNextscreen(); } /* * Check the bounds for numeric parameters here */ if (P(P_TS) <= 0 || P(P_TS) > 32) { if (inter) emsg("Invalid tab size specified"); P(P_TS) = 8; return; } if (P(P_SS) <= 0 || P(P_SS) > Rows) { if (inter) emsg("Invalid scroll size specified"); P(P_SS) = 12; return; } /* * Check for another argument, and call doset() recursively, if found. If * any argument results in an error, no further parameters are processed. */ while (*arg != ' ' && *arg != '\t') { /* skip to next white space */ if (*arg == NUL) return; /* end of parameter list */ arg++; } while (*arg == ' ' || *arg == '\t') /* skip to next non-white */ arg++; if (*arg) doset(arg, TRUE); /* recurse on next parameter, if present */ } static void showparms(all) bool_t all; /* show ALL parameters */ { struct param *p; char buf[64]; gotocmdline(YES, NUL); outstr("Parameters:\r\n"); for (p = ¶ms[0]; p->fullname[0] != NUL; p++) { if (!all && ((p->flags & P_CHANGED) == 0)) continue; if (p->flags & P_BOOL) sprintf(buf, "\t%s%s\r\n", (p->value ? "" : "no"), p->fullname); else sprintf(buf, "\t%s=%d\r\n", p->fullname, p->value); outstr(buf); } wait_return(); } SHAR_EOF cat << \SHAR_EOF > param.h /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ /* * Settable parameters */ struct param { char *fullname; /* full parameter name */ char *shortname; /* permissible abbreviation */ int value; /* parameter value */ int flags; }; extern struct param params[]; /* * Flags */ #define P_BOOL 0x01 /* the parameter is boolean */ #define P_NUM 0x02 /* the parameter is numeric */ #define P_CHANGED 0x04 /* the parameter has been changed */ /* * The following are the indices in the params array for each parameter */ /* * Numeric parameters */ #define P_TS 0 /* tab size */ #define P_SS 1 /* scroll size */ #define P_RP 2 /* report */ #define P_LI 3 /* lines */ /* * Boolean parameters */ #define P_VB 4 /* visual bell */ #define P_SM 5 /* showmatch */ #define P_WS 6 /* wrap scan */ #define P_EB 7 /* error bells */ #define P_MO 8 /* show mode */ #define P_BK 9 /* make backups when writing out files */ #define P_CR 10 /* use cr-lf to terminate lines on writes */ #define P_LS 11 /* show tabs and newlines graphically */ #define P_AI 12 /* auto-indent */ /* * Macro to get the value of a parameter */ #define P(n) (params[n].value) SHAR_EOF cat << \SHAR_EOF > raw.c /* * raw.c * * This is a routine for setting a given stream to raw or cooked mode on the * Amiga . This is useful when you are using Lattice C to produce programs * that want to read single characters with the "getch()" or "fgetc" call. * * Written : 18-Jun-87 By Chuck McManis. */ #include <exec/types.h> #include <libraries/dos.h> #include <libraries/dosextens.h> #include <stdio.h> #include <ios1.h> #include <error.h> extern int errno; /* The error variable */ /* * Function raw() - Convert the specified file pointer to 'raw' mode. This * only works on TTY's and essentially keeps DOS from translating keys for * you, also (BIG WIN) it means getch() will return immediately rather than * wait for a return. You lose editing features though. */ long raw(fp) FILE *fp; { struct MsgPort *mp; /* The File Handle message port */ struct FileHandle *afh; struct UFB *ufb; long Arg[1], res; ufb = (struct UFB *) chkufb(fileno(fp)); /* Step one, get the file * handle */ afh = (struct FileHandle *) (ufb->ufbfh); if (!IsInteractive(afh)) { /* Step two, check to see if it's a console */ errno = ENOTTY; return (-1); } /* Step three, get it's message port. */ mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type; Arg[0] = -1L; res = SendPacket(mp, ACTION_SCREEN_MODE, Arg, 1); /* Put it in RAW: mode */ if (res == 0) { errno = ENXIO; return (-1); } return (0); } /* * Function - cooked() this function returns the designate file pointer to * it's normal, wait for a <CR> mode. This is exactly like raw() except that * it sends a 0 to the console to make it back into a CON: from a RAW: */ long cooked(fp) FILE *fp; { struct MsgPort *mp; /* The File Handle message port */ struct FileHandle *afh; struct UFB *ufb; long Arg[1], res; ufb = (struct UFB *) chkufb(fileno(fp)); afh = (struct FileHandle *) (ufb->ufbfh); if (!IsInteractive(afh)) { errno = ENOTTY; return (-1); } mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type; Arg[0] = 0; res = SendPacket(mp, ACTION_SCREEN_MODE, Arg, 1); if (res == 0) { errno = ENXIO; return (-1); } return (0); } SHAR_EOF # End of shell archive exit 0 -- Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page Have five nice days.