page@swan.ulowell.edu (Bob Page) (03/15/89)
Submitted-by: grwalter@watcgl.waterloo.edu (Fred Walter) Posting-number: Volume 89, Issue 40 Archive-name: editors/stevie35a.1 # 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: # MAKE_TAGS # Makefile # README # TODO # amiga.h # ascii.h # bsd.c # bsd.h # dec.c # dos.c # dos.h # env.h # inc.c # keymap.h # linefunc.c # macros.h # makefile.amiga.lattice # makefile.bsd # makefile.dos # makefile.mwc # makefile.os2 # makefile.tos # makefile.usg # mark.c # mk.c # os2.h # param.c # param.h # porting.doc # raw.c # regexp.h # regmagic.h # regsub.c # sendpacket.c # source.doc # tos.h # unix.c # unix.h # updateNs.c # updateRs.c # This archive created: Tue Mar 14 14:40:09 1989 cat << \SHAR_EOF > MAKE_TAGS /ctags/ctags -t alloc.c charset.c cmdline.c dec.c edit.c /ctags/ctags -t -a fileio.c help.c inc.c linefunc.c main.c mark.c /ctags/ctags -t -a misccmds.c normal.c param.c raw.c screen.c /ctags/ctags -t -a search.c sendpacket.c updateNs.c /ctags/ctags -t -a updateRs.c ascii.h keymap.h /ctags/ctags -t -a macros.h param.h stevie.h term.h mk.c /ctags/ctags -t -a amiga.h amiga.c SHAR_EOF cat << \SHAR_EOF > Makefile # # Makefile for Lattice C 5.0 on Amiga # .c.o: lc $(CFLAGS) $< CFLAGS = -cu -ma -O LINKFLAGS = NODEBUG LIBS = lib:lc.lib MACH= amiga.o raw.o sendpacket.o OBJ1= main.o edit.o linefunc.o normal.o cmdline.o charset.o OBJ2= updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o OBJ3= mk.o regexp.o regsub.o version.o OBJ4= updateNs.o mark.o screen.o fileio.o param.o OBJ= $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(MACH) all: stevie say "done all" stevie: $(OBJ) BLINK TO stevie FROM lib:cres.o $(OBJ) LIBRARY $(LIBS) $(LINKFLAGS) clean: delete $(OBJ1) delete $(OBJ2) delete $(OBJ3) delete $(OBJ4) delete $(MACH) delete stevie SHAR_EOF cat << \SHAR_EOF > README STEVIE Source Release This is a source release of the STEVIE editor, a public domain clone of the UNIX editor 'vi'. The program was originally developed for the Atari ST, but has been ported to UNIX, OS/2, BSD 4.3 and the Amiga as well. There are currently two divergent versions of STEVIE. This version is the one that was ported to the Amiga and then worked on by me (G. R. Walter). The other one Tony Andrews continued to work on. My version is faster in some respects then his version, and his version does a couple of things mine doesn't. The files included in this release are: README This file. stevie.doc Reference manual for STEVIE. Assumes familiarity with vi. source.doc Quick overview of the major data structures used. porting.doc Tips for porting STEVIE to other systems. makefile.dos makefile.os2 makefile.usg makefile.tos makefile.bsd makefile.amiga.lattice Makefiles for MS DOS, OS/2, UNIX System V, Atari ST, BSD 4.3 UNIX and the Amiga respectively. raw.c sendpacket.c amiga.c amiga.h bsd.c bsd.h dos.c dos.h os2.c os2.h unix.c unix.h tos.c tos.h System-dependent routines for the same. alloc.c ascii.h cmdline.c edit.c fileio.c help.c charset.c keymap.h linefunc.c main.c mark.c misccmds.c normal.c param.c regexp.c regsub.c version.c regexp.h regmagic.h param.h ptrfunc.c screen.c search.c stevie.h term.h macros.h C source and header files for STEVIE. To compile STEVIE for one of the provided systems: 1. Compile the regular expression library and install as appropriate for your system. 2. Edit the file 'env.h' to set the system defines as needed. 3. Check the makefile for your system, and modify as needed. 4. Compile. NOTE: implicit in the design is the assumption that char's are unsigned. Thus if your compiler assumes different by default, change the default or you may have to change the source. Good Luck... Tony Andrews March 12, 1988 G. R. (Fred) Walter August 14, 1988 SHAR_EOF cat << \SHAR_EOF > TODO To Do ----- - Change the static buffers for insert/undo/redo/undoundo/etc to dynamic buffers. - Add #'d and named buffers. - Add 'R' and 'U'. - Add 'set sw' option. - In cmdline.c make get_range() give the appropriate error messages when it gets a bad line range. - Add & (do last search and replace on current line) and :[range]& (do last search and replace on the range of lines). - change the screen code so that number of columns is always a multiple of four. Then add assembler routines for copying (to be used in updateNextscreen()) that copy longs (4 bytes at a time). This will speed up things even more. SHAR_EOF cat << \SHAR_EOF > amiga.h /* * Amiga Machine-dependent routines. */ extern FILE *raw_io; extern int new_window; int inchar(); void flushbuf(); void outchar(); void outstr(); void beep(); void windinit(), windexit(), windgoto(); void delay(); void sleep(); SHAR_EOF cat << \SHAR_EOF > ascii.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 */ /* * Definitions of various common control characters */ #define NUL '\000' #define BS '\010' #define BS_STR "\010" #define TAB '\011' #define NL '\012' #define NL_STR "\012" #define CR '\015' #define ESC '\033' #define ESC_STR "\033" #define UNDO_SHIFTJ '\333' #define UNDO_SHIFTJ_STR "\333" #define ENABLE_REDRAWING '\334' #define ENABLE_REDRAWING_STR "\334" #define CTRL(x) ((x) & 0x1f) SHAR_EOF cat << \SHAR_EOF > bsd.c /* * System-dependent routines for BSD 4.3 UNIX */ #include "stevie.h" #include <sgtty.h> /* * inchar() - get a character from the keyboard */ int inchar() { int c; fflush(stdout); /* flush any pending output */ c = getchar(); return c; } void outstr(s) char *s; { while (*s) outchar(*s++); } void beep() { if (RedrawingDisabled) return; outchar('\007'); } void delay() { sleep(1); } static struct sgttyb ostate; void windinit() { char *getenv(); char *term; struct sgttyb nstate; term = getenv("TERM"); if (!term) { fprintf(stderr, "Invalid terminal type '%s'\n", term); exit(1); } if ((strncmp(term, "vt", 2) != 0) && (strncmp(term, "kd", 2) != 0)) { fprintf(stderr, "Invalid terminal type '%s'\n", term); exit(1); } Columns = 80; P(P_LI) = Rows = 24; /* * Go into cbreak mode */ ioctl(1, (long) TIOCGETP, (char *) &ostate); nstate = ostate; nstate.sg_flags = nstate.sg_flags & ~(ECHO | CRMOD) | CBREAK; ioctl(1, (long) TIOCSETP, (char *) &nstate); } void windexit(r) int r; { fflush(stdout); ioctl(0, (long) TIOCSETP, (char *) &ostate); exit(r); } void windgoto(r, c) int c; int r; { r++; c++; outstr("\033["); if (r >= 10) outchar((char) (r / 10 + '0')); outchar((char) (r % 10 + '0')); outchar(';'); if (c >= 10) outchar((char) (c / 10 + '0')); outchar((char) (c % 10 + '0')); outchar('H'); } FILE * fopenb(fname, mode) char *fname; char *mode; { return fopen(fname, mode); } SHAR_EOF cat << \SHAR_EOF > bsd.h /* * BSD 4.3 Machine-dependent routines. */ int inchar(); #define outchar(c) putchar(c) void outstr(), beep(); #define remove(path) unlink(path) int rename(); void windinit(), windexit(), windgoto(); void delay(); SHAR_EOF cat << \SHAR_EOF > dec.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" /* * dec(p) * * Decrement the line pointer 'p' crossing line boundaries as necessary. Return * 1 when crossing a line, -1 when at start of file, 0 otherwise. */ int dec(lp) register LPtr *lp; { if (lp->index > 0) { /* still within line */ lp->index--; return 0; } if (lp->linep->prev != Filetop->linep) { /* there is a prior line */ lp->linep = lp->linep->prev; lp->index = strlen(lp->linep->s); return 1; } lp->index = 0; /* stick at first char */ return -1; /* at start of file */ } SHAR_EOF cat << \SHAR_EOF > dos.c static char RCSid[] = "$Header: dos.c,v 1.1 88/05/03 14:22:16 tony Exp $"; /* * DOS System-dependent routines. * * System-specific code for MS-DOS. This has been tested with * MSDOS 3.3 on an AT. Also, the console driver "nansi.sys" is * required. * * $Log: dos.c,v $ * Revision 1.1 88/05/03 14:22:16 tony * Initial revision * * */ #include "stevie.h" /* * inchar() - get a character from the keyboard */ int inchar() { int c; for (;; beep()) { /* loop until we get a valid character */ flushbuf(); /* flush any pending output */ switch (c = getch()) { case 0x1e: return K_CGRAVE; case 0: /* special key */ if (State != NORMAL) { c = getch(); /* throw away next char */ continue; /* and loop for another char */ } switch (c = getch()) { case 0x50: return K_DARROW; case 0x48: return K_UARROW; case 0x4b: return K_LARROW; case 0x4d: return K_RARROW; case 0x52: return K_INSERT; case 0x47: stuffReadbuff("1G"); return -1; case 0x4f: stuffReadbuff("G"); return -1; case 0x51: stuffReadbuff(mkstr(CTRL('F'))); return -1; case 0x49: stuffReadbuff(mkstr(CTRL('B'))); return -1; /* * Hard-code some useful function key macros. */ case 0x3b: /* F1 */ stuffReadbuff(":p\n"); return -1; case 0x54: /* SF1 */ stuffReadbuff(":p!\n"); return -1; case 0x3c: /* F2 */ stuffReadbuff(":n\n"); return -1; case 0x55: /* SF2 */ stuffReadbuff(":n!\n"); return -1; case 0x3d: /* F3 */ stuffReadbuff(":e #\n"); return -1; case 0x3e: /* F4 */ stuffReadbuff(":rew\n"); return -1; case 0x57: /* SF4 */ stuffReadbuff(":rew!\n"); return -1; case 0x3f: /* F5 */ stuffReadbuff("[["); return -1; case 0x40: /* F6 */ stuffReadbuff("]]"); return -1; case 0x41: /* F7 */ stuffReadbuff("<<"); return -1; case 0x42: /* F8 */ stuffReadbuff(">>"); return -1; case 0x43: /* F9 */ stuffReadbuff(":x\n"); return -1; case 0x44: /* F10 */ stuffReadbuff(":help\n"); return -1; default: break; } break; default: return c; } } } #define BSIZE 2048 static char outbuf[BSIZE]; static int bpos = 0; flushbuf() { if (bpos != 0) write(1, outbuf, bpos); bpos = 0; } /* * Macro to output a character. Used within this file for speed. */ #define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() /* * Function version for use outside this file. */ void outchar(c) register char c; { outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf(); } static char cell[2] = {0, 7}; /* * outstr(s) - write a string to the console */ void outstr(s) register char *s; { while (*s) { outone(*s++); } } void beep() { if (RedrawingDisabled) return; outone('\007'); } void sleep(n) int n; { /* * Should do something reasonable here. */ } void delay() { long l; flushbuf(); /* * Should do something better here... */ for (l = 0; l < 5000; l++); } void windinit() { Columns = 80; P(P_LI) = Rows = 25; } void windexit(r) int r; { flushbuf(); exit(r); } void windgoto(r, c) register int r, c; { r += 1; c += 1; /* * Check for overflow once, to save time. */ if (bpos + 8 >= BSIZE) flushbuf(); outbuf[bpos++] = '\033'; outbuf[bpos++] = '['; if (r >= 10) outbuf[bpos++] = r / 10 + '0'; outbuf[bpos++] = r % 10 + '0'; outbuf[bpos++] = ';'; if (c >= 10) outbuf[bpos++] = c / 10 + '0'; outbuf[bpos++] = c % 10 + '0'; outbuf[bpos++] = 'H'; } FILE * fopenb(fname, mode) char *fname; char *mode; { FILE *fopen(); char modestr[16]; sprintf(modestr, "%sb", mode); return fopen(fname, modestr); } SHAR_EOF cat << \SHAR_EOF > dos.h /* * MS DOS Machine-dependent routines. */ int inchar(); void outchar(); void outstr(); void beep(); void windinit(); void windexit(); void windgoto(); void delay(); void sleep(); SHAR_EOF cat << \SHAR_EOF > env.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 */ /* * The defines in this file establish the environment we're compiling * in. Set these appropriately before compiling the editor. */ /* * One (and only 1) of the following defines should be uncommented. Most of * the code is pretty machine-independent. Machine dependent code goes in a * file like tos.c or unix.c. The only other place where machine dependent * code goes is term.h for escape sequences. */ #ifndef AMIGA #define ATARI Atari ST */ /* #define UNIX System V */ /* #define BSD BSD 4.3 */ /* #define OS2 Microsoft OS/2 */ /* #define DOS MS DOS 3.3 */ /* #define AMIGA Amiga */ #endif /* * If ATARI is defined, one of the following compilers must be selected. */ #ifdef ATARI #define MWC Mark William's C 3.0.9 */ /* #define MEGAMAX Megamax Compiler */ /* #define ALCYON Alcyon C compiler */ # ifdef MWC # define AppendNumberToUndoUndobuff XX1 # define AppendPositionToUndoUndobuff XX2 # define FOPENB # endif # ifdef MEGAMAX # define FOPENB # endif #endif /* * If HELP is defined, the :help command shows a vi command summary. */ #define HELP /* enable help command */ /* * STRCSPN should be defined if the target system doesn't have the * routine strcspn() available. See regexp.c for details. */ #ifdef ATARI #define STRCSPN #endif SHAR_EOF cat << \SHAR_EOF > inc.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" /* * inc(p) * * Increment the line pointer 'p' crossing line boundaries as necessary. Return * 1 when crossing a line, -1 when at end of file, 0 otherwise. */ int inc(lp) register LPtr *lp; { register char *p = &(lp->linep->s[lp->index]); if (*p != NUL) { /* still within line */ lp->index++; return ((p[1] != NUL) ? 0 : 1); } if (lp->linep->next != Fileend->linep) { /* there is a next line */ lp->index = 0; lp->linep = lp->linep->next; return 1; } return -1; } SHAR_EOF 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 != Filetop->linep) { 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 > makefile.amiga.lattice # # Makefile for Lattice C 5.0 on Amiga # .c.o: lc $(CFLAGS) $< CFLAGS = -cu -ma -O LINKFLAGS = NODEBUG LIBS = lib:lc.lib MACH= amiga.o raw.o sendpacket.o OBJ1= main.o edit.o linefunc.o normal.o cmdline.o charset.o OBJ2= updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o OBJ3= mk.o regexp.o regsub.o version.o OBJ4= updateNs.o mark.o screen.o fileio.o param.o OBJ= $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(MACH) all: stevie say "done all" stevie: $(OBJ) BLINK TO stevie FROM lib:cres.o $(OBJ) LIBRARY $(LIBS) $(LINKFLAGS) clean: delete $(OBJ1) delete $(OBJ2) delete $(OBJ3) delete $(OBJ4) delete $(MACH) delete stevie SHAR_EOF cat << \SHAR_EOF > makefile.bsd # # Makefile for BSD 4.3 UNIX # CFLAGS = -pg -g LINTFLAGS = MACHOBJ= bsd.o MACHSRC= bsd.c SRC= main.c edit.c linefunc.c normal.c cmdline.c charset.c \ updateRs.c misccmds.c help.c dec.c inc.c search.c alloc.c \ mk.c regexp.c regsub.c version.c \ updateNs.c mark.c screen.c fileio.c param.c $(MACHSRC) OBJ= main.o edit.o linefunc.o normal.o cmdline.o charset.o \ updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o \ mk.o regexp.o regsub.o version.o \ updateNs.o mark.o screen.o fileio.o param.o $(MACHOBJ) all : stevie stevie : $(OBJ) $(CC) $(OBJ) $(CFLAGS) -o stevie lint: lint $(LINTFLAGS) $(SRC) clean : rm -f *.out *.o core stevie *.BAK SHAR_EOF cat << \SHAR_EOF > makefile.dos # # Makefile for DOS # # This makefile is set up for Microsoft C 5.1 # # # Compact model lets us edit large files, but keep small model code # MODEL= /AC CFLAGS = $(MODEL) MACH= dos.obj OBJ= main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \ mk.obj updateRs.obj regexp.obj regsub.obj version.obj \ misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \ updateNs.obj mark.obj screen.obj fileio.obj param.obj $(MACH) all: stevie.exe main.obj: main.c cl -c $(CFLAGS) main.c updateRs.obj: updateRs.c cl -c $(CFLAGS) updateRs.c mk.obj: mk.c cl -c $(CFLAGS) mk.c regexp.obj: regexp.c cl -c $(CFLAGS) regexp.c regsub.obj: regsub.c cl -c $(CFLAGS) regsub.c version.obj: version.c cl -c $(CFLAGS) version.c alloc.obj : alloc.c cl -c $(CFLAGS) alloc.c edit.obj : edit.c cl -c $(CFLAGS) edit.c updateNs.obj : updateNs.c cl -c $(CFLAGS) updateNs.c linefunc.obj : linefunc.c cl -c $(CFLAGS) linefunc.c normal.obj : normal.c cl -c $(CFLAGS) normal.c cmdline.obj : cmdline.c cl -c $(CFLAGS) cmdline.c charset.obj : charset.c cl -c $(CFLAGS) charset.c misccmds.obj : misccmds.c cl -c $(CFLAGS) misccmds.c help.obj : help.c cl -c $(CFLAGS) help.c dec.obj : dec.c cl -c $(CFLAGS) dec.c inc.obj : inc.c cl -c $(CFLAGS) inc.c search.obj : search.c cl -c $(CFLAGS) search.c mark.obj : mark.c cl -c $(CFLAGS) mark.c screen.obj : screen.c cl -c $(CFLAGS) screen.c fileio.obj : fileio.c cl -c $(CFLAGS) fileio.c param.obj : param.c cl -c $(CFLAGS) param.c os2.obj : os2.c cl -c $(CFLAGS) os2.c stevie.exe : $(OBJ) cl $(MODEL) *.obj c:\lib\setargv.obj -o stevie.exe /F 6000 -link /NOE SHAR_EOF cat << \SHAR_EOF > makefile.mwc # # # # Makefile for Mark Williams C # CFLAGS = -O -VPEEP LDFLAGS = -s -x -v LINKER=ld OBJ1= main.o edit.o linefunc.o normal.o cmdline.o charset.o \ updatere.o misccmds.o help.o dec.o inc.o OBJ2= alloc.o search.o mk.o regexp.o regsub.o version.o updatene.o \ mark.o screen.o fileio.o param.o tos.o SRC= main.c edit.c linefunc.c normal.c cmdline.c charset.c \ updatere.c misccmds.c help.c dec.c inc.c search.c alloc.c \ mk.c regexp.c regsub.c version.c \ updatene.c mark.c screen.c fileio.c param.c \ tos.c all : stevie.ttp stevie.a: $(OBJ1) $(OBJ2) ar rv stevie.a $(OBJ1) ar rv stevie.a $(OBJ2) stevie.ttp: stevie.a cc stevie.a $(LIBS) -o stevie.ttp SHAR_EOF cat << \SHAR_EOF > makefile.os2 # # Makefile for OS/2 # # The make command with OS/2 is really stupid. # # # Compact model lets us edit large files, but keep small model code # MODEL= -AC CFLAGS = $(MODEL) -I..\regexp -J MACH= os2.obj OBJ= main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \ mk.obj updateRs.obj regexp.obj regsub.obj version.obj \ misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \ updateNs.obj mark.obj screen.obj fileio.obj param.obj $(MACH) all: stevie.exe main.obj: main.c cl -c $(CFLAGS) main.c updateRs.obj: updateRs.c cl -c $(CFLAGS) updateRs.c mk.obj: mk.c cl -c $(CFLAGS) mk.c regexp.obj: regexp.c cl -c $(CFLAGS) regexp.c regsub.obj: regsub.c cl -c $(CFLAGS) regsub.c version.obj: version.c cl -c $(CFLAGS) version.c alloc.obj : alloc.c cl -c $(CFLAGS) alloc.c edit.obj : edit.c cl -c $(CFLAGS) edit.c updateNs.obj : updateNs.c cl -c $(CFLAGS) updateNs.c linefunc.obj : linefunc.c cl -c $(CFLAGS) linefunc.c normal.obj : normal.c cl -c $(CFLAGS) normal.c cmdline.obj : cmdline.c cl -c $(CFLAGS) cmdline.c charset.obj : charset.c cl -c $(CFLAGS) charset.c misccmds.obj : misccmds.c cl -c $(CFLAGS) misccmds.c help.obj : help.c cl -c $(CFLAGS) help.c dec.obj : dec.c cl -c $(CFLAGS) dec.c inc.obj : inc.c cl -c $(CFLAGS) inc.c search.obj : search.c cl -c $(CFLAGS) search.c mark.obj : mark.c cl -c $(CFLAGS) mark.c screen.obj : screen.c cl -c $(CFLAGS) screen.c fileio.obj : fileio.c cl -c $(CFLAGS) fileio.c param.obj : param.c cl -c $(CFLAGS) param.c os2.obj : os2.c cl -c $(CFLAGS) os2.c stevie.exe : $(OBJ) cl $(MODEL) *.obj $(LIBS) -o stevie.exe copy stevie.exe rstevie.exe bind rstevie.exe \lib\api.lib \lib\doscalls.lib SHAR_EOF cat << \SHAR_EOF > makefile.tos # # Makefile for the Atari ST - Megamax C compiler # CFLAGS = -DMEGAMAX # Megamax rule .c.o: mmcc $(CFLAGS) $< mmimp $*.o mmlib rv vi.lib $*.o MACH= tos.o OBJ= main.o edit.o linefunc.o normal.o cmdline.o charset.o \ updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o \ mk.o regexp.o regsub.o version.o \ updateNs.o mark.o screen.o fileio.o param.o $(MACH) all : stevie.ttp stevie.ttp : $(OBJ) $(LINKER) vi.lib $(LIBS) -o stevie.ttp clean : $(RM) $(OBJ) vi.lib SHAR_EOF cat << \SHAR_EOF > makefile.usg # # Makefile for UNIX (System V) # CFLAGS = -O MACH= unix.o OBJ= main.o edit.o linefunc.o normal.o cmdline.o charset.o \ updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o \ mk.o regexp.o regsub.o version.o \ updateNs.o mark.o screen.o fileio.o param.o $(MACH) all : stevie stevie : $(OBJ) $(CC) $(OBJ) $(LIBS) -o stevie clean : rm $(OBJ) 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 > mk.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" char * mkline(n) int n; { static char lbuf[9]; int i = 6; strcpy(lbuf, " "); lbuf[i--] = (char) ((n % 10) + '0'); n /= 10; if (n != 0) { lbuf[i--] = (char) ((n % 10) + '0'); n /= 10; } if (n != 0) { lbuf[i--] = (char) ((n % 10) + '0'); n /= 10; } if (n != 0) { lbuf[i--] = (char) ((n % 10) + '0'); n /= 10; } if (n != 0) { lbuf[i--] = (char) ((n % 10) + '0'); n /= 10; } return lbuf; } char * mkstr(c) char c; { static char s[2]; s[0] = c; s[1] = NUL; return s; } SHAR_EOF cat << \SHAR_EOF > os2.h /* * OS2 Machine-dependent routines. */ int inchar(); void outchar(); void outstr(), beep(); void windinit(), windexit(), windgoto(); void delay(); void sleep(); 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}, {"ignorecase", "ic", FALSE, P_BOOL}, {"autoindent", "ai", FALSE, P_BOOL}, {"number", "nu", 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(NOT_VALID); if (did_lines) { Rows = P(P_LI); screenalloc(); /* allocate new screen buffers */ screenclear(); updateNextscreen(NOT_VALID); } /* * 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_IC 12 /* ignore case in searches */ #define P_AI 13 /* auto-indent */ #define P_NU 14 /* number lines on the screen */ /* * Macro to get the value of a parameter */ #define P(n) (params[n].value) SHAR_EOF cat << \SHAR_EOF > porting.doc Release Notes for STEVIE - Version 3.31B Porting Tony Andrews - March 6, 1988 G. R. Walter - January 6, 1988 Porting the editor is a relatively simple task. Most of the code is pretty machine-independent. For each environment, there is a file of routines that perform various low-level operations that tend to vary a lot from one machine to another. Another file contains the escape sequences to be used for each machine. The machine-dependent files currently used are: tos.c: Atari ST - ifdef for either Megamax or Alcyon tos.h unix.c: UNIX System V unix.h os2.c: Microsoft OS/2 os2.h dos.c: MS DOS dos.h amiga.c: Amiga amiga.h bsd.c: BSD 4.3 UNIX bsd.h Each of these files are around 150 lines long and deal with low-level issues like character I/O to the terminal, terminal initialization, cursor addressing, and so on. There are different tradeoffs to be made depending on the environment. For example, the UNIX version buffers terminal output because of the relatively high overhead of system calls. A quick look at the files will make it clear what needs to be done in a new environment. Terminal escape sequences are in the file "term.h". These are defined statically, for the time being. There is some discussion in term.h regarding which sequences are optional and which are not. The editor is somewhat flexible in dealing with a lack of terminal capabilities. The character set is in the file "charset.c". Because not all C compilers support command line macro definitions, the #define's for system-specific macros are placed in the file "env.h". If you port to a new system, add another line there to define the macro you choose for your port. The basic process for doing a new port is: 1. Come up with a macro name to use when ifdef'ing your system- specific changes. Add a line to 'env.h' to define the macro name you've chosen. 2. Look at amiga.c, bsd.c, unix.c, tos.c, dos.c and os2.c and copy the one that comes closest to working on your system. Then modify your new file as needed. 3. Look at term.h and edit the file appropriately adding a new set of escape sequence definitions for your system. 4. Compiling and debug the editor. 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 <proto/exec.h> #include <proto/dos.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 cat << \SHAR_EOF > regexp.h /* * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE * * This is NOT the original regular expression code as written by * Henry Spencer. This code has been modified specifically for use * with the STEVIE editor, and should not be used apart from compiling * STEVIE. If you want a good regular expression library, get the * original code. The copyright notice that follows is from the * original. * * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE * * Definitions etc. for regexp(3) routines. * * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], * not the System V one. */ #define NSUBEXP 10 typedef struct regexp { char *startp[NSUBEXP]; char *endp[NSUBEXP]; char regstart; /* Internal use only. */ char reganch; /* Internal use only. */ char *regmust; /* Internal use only. */ int regmlen; /* Internal use only. */ char program[1]; /* Unwarranted chumminess with compiler. */ } regexp; extern regexp *regcomp(); extern int regexec(); extern void regsub(); extern void regerror(); #ifndef ORIGINAL extern int reg_ic; /* set non-zero to ignore case in searches */ #endif SHAR_EOF cat << \SHAR_EOF > regmagic.h /* * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE * * This is NOT the original regular expression code as written by * Henry Spencer. This code has been modified specifically for use * with the STEVIE editor, and should not be used apart from compiling * STEVIE. If you want a good regular expression library, get the * original code. The copyright notice that follows is from the * original. * * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE * * The first byte of the regexp internal "program" is actually this magic * number; the start node begins in the second byte. */ #define MAGIC 0234 SHAR_EOF cat << \SHAR_EOF > regsub.c /* * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE * * This is NOT the original regular expression code as written by * Henry Spencer. This code has been modified specifically for use * with the STEVIE editor, and should not be used apart from compiling * STEVIE. If you want a good regular expression library, get the * original code. The copyright notice that follows is from the * original. * * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE * * regsub * * Copyright (c) 1986 by University of Toronto. * Written by Henry Spencer. Not derived from licensed software. * * Permission is granted to anyone to use this software for any * purpose on any computer system, and to redistribute it freely, * subject to the following restrictions: * * 1. The author is not responsible for the consequences of use of * this software, no matter how awful, even if they arise * from defects in it. * * 2. The origin of this software must not be misrepresented, either * by explicit claim or by omission. * * 3. Altered versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * $Log: regsub.c,v $ * Revision 1.2 88/04/28 08:11:25 tony * First modification of the regexp library. Added an external variable * 'reg_ic' which can be set to indicate that case should be ignored. * Added a new parameter to regexec() to indicate that the given string * comes from the beginning of a line and is thus eligible to match * 'beginning-of-line'. * */ #include "env.h" #ifdef MEGAMAX overlay "regexp" #endif #include <stdio.h> #include "regexp.h" #include "regmagic.h" #ifndef CHARBITS #define UCHARAT(p) ((int)*(unsigned char *)(p)) #else #define UCHARAT(p) ((int)*(p)&CHARBITS) #endif /* - regsub - perform substitutions after a regexp match */ void regsub(prog, source, dest) regexp *prog; char *source; char *dest; { register char *src; register char *dst; register char c; register int no; register int len; extern char *strncpy(); if (prog == NULL || source == NULL || dest == NULL) { regerror("NULL parm to regsub"); return; } if (UCHARAT(prog->program) != MAGIC) { regerror("damaged regexp fed to regsub"); return; } src = source; dst = dest; while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '\\' && '0' <= *src && *src <= '9') no = *src++ - '0'; else no = -1; if (no < 0) { /* Ordinary character. */ if (c == '\\' && (*src == '\\' || *src == '&')) c = *src++; *dst++ = c; } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { len = prog->endp[no] - prog->startp[no]; (void) strncpy(dst, prog->startp[no], len); dst += len; if (len != 0 && *(dst - 1) == '\0') { /* strncpy hit NUL. */ regerror("damaged match string"); return; } } } *dst++ = '\0'; } SHAR_EOF cat << \SHAR_EOF > sendpacket.c /* * Sendpacket.c * * An invaluable addition to your Amiga.lib file. This code sends a packet the * given message port. This makes working around DOS lots easier. * * Note, I didn't write this, those wonderful folks at CBM did. I do suggest * however that you may wish to add it to Amiga.Lib, to do so, compile it and * say 'oml lib:amiga.lib -r sendpacket.o' */ #include <proto/exec.h> /* #include <exec/ports.h> */ #include <exec/memory.h> #include <proto/dos.h> /* * Function - SendPacket written by Phil Lindsay, Carolyn Scheppner, and Andy * Finkel. This function will send a packet of the given type to the Message * Port supplied. */ long SendPacket(pid, action, args, nargs) struct MsgPort *pid; /* process indentifier ... (handlers message * port ) */ long action, /* packet type ... (what you want handler to * do ) */ args[], /* a pointer to a argument list */ nargs; /* number of arguments in list */ { struct MsgPort *replyport; struct StandardPacket *packet; long count, *pargs, res1; replyport = (struct MsgPort *) CreatePort(NULL, 0); if (!replyport) return (0); /* Allocate space for a packet, make it public and clear it */ packet = (struct StandardPacket *) AllocMem((long) sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR); if (!packet) { DeletePort(replyport); return (0); } packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt); packet->sp_Pkt.dp_Link = &(packet->sp_Msg); packet->sp_Pkt.dp_Port = replyport; packet->sp_Pkt.dp_Type = action; /* copy the args into the packet */ pargs = &(packet->sp_Pkt.dp_Arg1); /* address of first argument */ for (count = 0; count < nargs; count++) pargs[count] = args[count]; PutMsg(pid, packet); /* send packet */ WaitPort(replyport); GetMsg(replyport); res1 = packet->sp_Pkt.dp_Res1; FreeMem(packet, (long) sizeof(struct StandardPacket)); DeletePort(replyport); return (res1); } SHAR_EOF cat << \SHAR_EOF > source.doc Release Notes for STEVIE - Version 3.10a Source Notes Tony Andrews - March 6, 1988 Overview -------- This file provides a brief description of the source code for Stevie. The data structures are described later as well. For information specific to porting the editor, see the file 'porting.doc'. This document is more relevant to people who want to hack on the editor apart from doing a simple port. Most of this document was written some time ago so a lot of the discussion centers on problems related to the Atari ST environment and compilers. Most of this can be ignored for other systems. Things You Need - ATARI ----------------------- Stevie has been compiled with both the Alcyon (4.14A) and the Megamax C compilers. For the posted binary, Megamax was used because it's less buggy and provides a reasonable malloc(). Ports to other compilers should be pretty simple. The current ifdef's for ALCYON and MEGAMAX should point to the potential trouble areas. (See 'porting.doc' for more information.) The search code depends on Henry Spencer's regular expression code. I used a version I got from the net recently (as part of a 'grep' posting) and had absolutely no trouble compiling it on the ST. Thanks, Henry! The file 'getenv.c' contains a getenv routine that may or may not be needed with your compiler. My version works with Alcyon and Megamax, under either the Beckemeyer or Gulam shells. Lastly, you need a decent malloc. Lots of stuff in stevie is allocated dynamically. The malloc with Alcyon is problematic because it allocates from the heap between the end of data and the top of stack. If you make the stack big enough to edit large files, you wind up wasting space when working with small files. Mallocs that get their memory from GEMDOS (in fairly large chunks) are much better. Things You Need - AMIGA ----------------------- Lattice C version 5.0 or later. Data Structures --------------- A brief discussion of the evolution of the data structures will do much to clarify the code, and explain some of the strangeness you may see. In the original version, the file was maintained in memory as a simple contiguous buffer. References to positions in the file were simply character pointers. Due to the obvious performance problems inherent in this approach, the following changes were made. The file is now represented by a doubly linked list of 'line' structures defined as follows: struct line { struct line *next; /* next line */ struct line *prev; /* previous line */ char *s; /* text for this line */ int size; /* actual size of space at 's' */ unsigned long num; /* line "number" */ }; The members of the line structure are described more completely here: prev - pointer to the structure for the prior line, or NULL for the first line of the file next - like 'prev' but points to the next line s - points to the contents of the line (null terminated) size - contains the size of the chunk of space pointed to by s. This is used so we know when we can add text to a line without getting more space. When we DO need more space, we always get a little extra so we don't make so many calls to malloc. num - This is a pseudo line number that makes it easy to compare positions within the file. Otherwise, we'd have to traverse all the links to tell which line came first. Since character pointers served to mark file positions in the original, a similar data object was needed for the new data structures. This purpose is served by the 'lptr' structure which is defined as: struct lptr { struct line *linep; /* line we're referencing */ int index; /* position within that line */ }; The member 'linep' points to the 'line' structure for the line containing the location of interest. The integer 'index' is the offset into the line data (member 's') of the character to be referenced. The following typedef's are more commonly used: typedef struct line LINE; typedef struct lptr LPtr; Many operations that were trivial with character pointers had to be implemented by functions or macros to manipulate LPtr's. Most of these are in the files 'ptrfunc.c' and 'macros.h'. There you'll find functions to increment, decrement, and compare LPtr's. SHAR_EOF cat << \SHAR_EOF > tos.h /* * Atari Machine-dependent routines. */ int inchar(); void outchar(); void outstr(), beep(); void remove(), rename(); void windinit(), windexit(), windgoto(); void delay(); void sleep(); SHAR_EOF cat << \SHAR_EOF > unix.c /* * System-dependent routines for UNIX System V Release 3. */ #include "stevie.h" /* #include <termio.h> /* System V */ #include <curses.h> /* BSD */ /* * inchar() - get a character from the keyboard */ int inchar() { char c; flushbuf(); /* flush any pending output */ while (read(0, &c, 1) != 1); return (int) c; } #define BSIZE 2048 static char outbuf[BSIZE]; static int bpos = 0; flushbuf() { if (bpos != 0) write(1, outbuf, bpos); bpos = 0; } /* * Macro to output a character. Used within this file for speed. */ #define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() /* * Function version for use outside this file. */ void outchar(c) char c; { outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf(); } void outstr(s) char *s; { while (*s) { outone(*s++); } } void beep() { if (RedrawingDisabled) return; outone('\007'); } /* * remove(file) - remove a file */ void remove(file) char *file; { unlink(file); } /* * rename(of, nf) - rename existing file 'of' to 'nf' */ void rename(of, nf) char *of, *nf; { unlink(nf); link(of, nf); unlink(of); } void delay() { /* not implemented */ } static struct termio ostate; void windinit() { char *getenv(); char *term; struct termio nstate; if ((term = getenv("TERM")) == NULL || strcmp(term, "vt100") != 0) { fprintf(stderr, "Invalid terminal type '%s'\n", term); exit(1); } Columns = 80; P(P_LI) = Rows = 24; /* * Go into cbreak mode */ ioctl(0, TCGETA, &ostate); nstate = ostate; nstate.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL); nstate.c_cc[VMIN] = 1; nstate.c_cc[VTIME] = 0; ioctl(0, TCSETAW, &nstate); } void windexit(r) int r; { /* * Restore terminal modes */ ioctl(0, TCSETAW, &ostate); exit(r); } #define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() void windgoto(r, c) int r, c; { r += 1; c += 1; /* * Check for overflow once, to save time. */ if (bpos + 8 >= BSIZE) flushbuf(); outbuf[bpos++] = '\033'; outbuf[bpos++] = '['; if (r >= 10) outbuf[bpos++] = r / 10 + '0'; outbuf[bpos++] = r % 10 + '0'; outbuf[bpos++] = ';'; if (c >= 10) outbuf[bpos++] = c / 10 + '0'; outbuf[bpos++] = c % 10 + '0'; outbuf[bpos++] = 'H'; } FILE * fopenb(fname, mode) char *fname; char *mode; { return fopen(fname, mode); } SHAR_EOF cat << \SHAR_EOF > unix.h /* * Unix Machine-dependent routines. */ int inchar(); void outchar(); void outstr(), beep(); void remove(), rename(); void windinit(), windexit(), windgoto(); void delay(); SHAR_EOF cat << \SHAR_EOF > updateNs.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" /* * updateNextscreen() * * Based on the current value of Topchar, transfer a screenfull of stuff from * Filemem to Nextscreen, and update Botchar. */ void updateNextscreen(type) int type; { register char *ptr; register char c; register int row; register int col; register char *screenp; register char *endscreen; register char *nextrow; LPtr start; LINE *memp; LINE *save; /* save pos. in case line won't fit */ char extra[16]; char *p_extra; int n_extra; bool_t done; /* if TRUE, we hit the end of the file */ bool_t didline; /* if TRUE, we finished the last line */ int srow; /* starting row of the current line */ int lno; /* number of the line we're doing */ int coff; /* column offset */ int idx; int i; int j; char lines; if (NumLineSizes == 0) type = NOT_VALID; MustRedrawLine = FALSE; MustRedrawScreen = TRUE; idx = 0; row = 0; start.linep = Topchar->linep; screenp = Nextscreen; /* The number of rows shown is Rows-1. */ /* The last line is the status/command line. */ endscreen = Nextscreen + (Rows - 1) * Columns; if ((type == VALID) || (type == VALID_TO_CURSCHAR)) { j = -1; for (i = 0; i < NumLineSizes; i++) { if (LinePointers[i] == Topchar->linep) { j = i; break; } row += LineSizes[i]; } if (j == -1) { /* Are we off the top of the screen by one line ? */ if (Topchar->linep->next == LinePointers[0]) { i = plines(Topchar); if (i < (Rows - 1)) { screenp = endscreen - (i * Columns); while (screenp > Nextscreen) *(--endscreen) = *(--screenp); endscreen = Nextscreen + (i * Columns); for(idx = NumLineSizes; idx > 0; idx--) { LinePointers[idx] = LinePointers[idx - 1]; LineSizes[idx] = LineSizes[idx - 1]; } LineSizes[idx] = i; } } row = 0; } else if (j == 0 && type == VALID) { return; } else { nextrow = Nextscreen + row * Columns; row = 0; for (;;) { LineSizes[idx] = LineSizes[j]; LinePointers[idx] = LinePointers[j]; if (type == VALID_TO_CURSCHAR) { if (LinePointers[idx]->next == Curschar->linep) { break; } } j++; if (j >= NumLineSizes) break; row += LineSizes[idx]; idx++; } start.linep = LinePointers[idx]; endscreen = nextrow + row * Columns; while (nextrow < endscreen) *screenp++ = *nextrow++; endscreen = Nextscreen + (Rows - 1) * Columns; } } srow = row; save = memp = start.linep; coff = P(P_NU) ? 8 : 0; if (P(P_NU)) lno = cntllines(Filemem, &start); done = didline = FALSE; col = 0; lines = 1; LinePointers[idx] = memp; p_extra = NULL; n_extra = 0; if (P(P_NU)) { strcpy(extra, mkline(lno++)); p_extra = extra; n_extra = 8; } ptr = memp->s; /* * We go one past the end of the screen so we can find out if the last * line fit on the screen or not. */ while (screenp <= endscreen) { /* Get the next character to put on the screen. */ /* * The 'extra' array contains the extra stuff that is inserted to * represent special characters (tabs, and other non-printable stuff. */ if (n_extra > 0) { c = *p_extra++; n_extra--; } else { c = *ptr++; if (c < 32 || c > 127) { if (c == NUL) { srow = ++row; /* * Save this position in case the next line won't fit on the * screen completely. */ save = memp; if (memp->next != Fileend->linep) { memp = memp->next; ptr = memp->s; } else { done = TRUE; } if (P(P_LS)) { *screenp++ = '$'; if (screenp > endscreen) break; col++; if (col >= Columns) { row++; lines++; } } LineSizes[idx++] = lines; lines = 1; LinePointers[idx] = memp; if (P(P_NU)) { strcpy(extra, mkline(lno++)); p_extra = extra; n_extra = 8; } /* blank out the rest of this row */ nextrow = Nextscreen + (row * Columns); while (screenp < nextrow) *screenp++ = ' '; if (done) break; if (screenp == endscreen) { didline = TRUE; break; } else if (screenp > endscreen) { idx--; break; } col = 0; continue; } else if (c == TAB) { if (!P(P_LS)) { strcpy(extra, " "); p_extra = extra; /* tab amount depends on current column */ n_extra = ((P(P_TS) - 1) - (col - coff) % P(P_TS)); c = ' '; } } else if ((n_extra = chars[c].ch_size - 1) > 0) { p_extra = chars[c].ch_str; c = *p_extra++; } } } if (col >= Columns) { lines++; row++; col = 0; } /* store the character in Nextscreen */ *screenp++ = c; col++; } /* Do we have to do off the top of the screen processing ? */ if (endscreen != (Nextscreen + (Rows - 1) * Columns)) { endscreen = Nextscreen + (Rows - 1) * Columns; row = 0; for(idx = 0; idx <= NumLineSizes && row < (Rows - 1); idx++) row += LineSizes[idx]; if (row < (Rows - 1)) { screenp = Nextscreen + (row * Columns); done = TRUE; } else if (row > (Rows - 1)) { /* Need to blank out the last line */ idx--; save = LinePointers[idx]; srow = row - LineSizes[idx]; didline = FALSE; } else { memp = LinePointers[idx]; screenp = Nextscreen + (row * Columns); didline = TRUE; } } /* * If we didn't hit the end of the file, and we didn't finish the last * line we were working on, then the line didn't fit. */ if (!done && !didline) { /* * Clear the rest of the screen and mark the unused lines. */ screenp = Nextscreen + (srow * Columns); while (screenp < endscreen) *screenp++ = ' '; for (; srow < (Rows - 1); srow++) Nextscreen[srow * Columns] = '@'; Botchar->linep = save; } else { /* make sure the rest of the screen is blank */ while (screenp < endscreen) *screenp++ = ' '; /* put '~'s on rows that aren't part of the file. */ if (col != 0) row++; while (row < Rows) { Nextscreen[row * Columns] = '~'; row++; } if (done) /* we hit the end of the file */ *Botchar = *Fileend; else Botchar->linep = memp; /* FIX - prev? */ } NumLineSizes = idx; } SHAR_EOF cat << \SHAR_EOF > updateRs.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" /* * updateRealscreen * * Transfer the contents of Nextscreen to the screen, using Realscreen to avoid * unnecessary output. */ void updateRealscreen() { register char *np = Nextscreen; register char *rp = Realscreen; register char *endscreen; register int row = 0, col = 0; int gorow = -1, gocol = -1; if (RedrawingDisabled) return; if (!MustRedrawScreen && !MustRedrawLine) return; if (MustRedrawLine) { msg("internal error: updateRealscreen called when MustRedrawLine set"); sleep(5); } endscreen = &np[(Rows - 1) * Columns]; outstr(T_CI); /* disable cursor */ for (; np < endscreen; np++, rp++) { /* If desired screen (contents of Nextscreen) does not */ /* match what's really there, put it there. */ if (*np != *rp) { /* if we are positioned at the right place, */ /* we don't have to use windgoto(). */ if (gocol != col || gorow != row) { /* * If we're just off by one, don't send an entire esc. seq. * (this happens a lot!) */ if (gorow == row && gocol + 1 == col) { outchar(*(np - 1)); gocol++; } else windgoto(gorow = row, gocol = col); } outchar(*rp = *np); gocol++; } if (++col >= Columns) { col = 0; row++; } } outstr(T_CV); /* enable cursor again */ MustRedrawLine = FALSE; MustRedrawScreen = FALSE; } 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.