allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (08/20/89)
Posting-number: Volume 8, Issue 3 Submitted-by: tony@cs.utexas.edu@wldrdg.UUCP (Tony Andrews) Archive-name: stevie3.68/part01 [STevie is a vi-clone, originally developed for the Atari ST but since ported to MS-DOS and Minix (PC and ST versions), and probably to a few other systems as well. ++bsa] #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # alloc.c # ascii.h # cmdline.c # ctags.c # edit.c # env.h # fileio.c # This archive created: Sun Aug 13 11:45:54 1989 export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(1787 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'README' XSTEVIE Source Release - 3.68 X XThis is a source release of the STEVIE editor, a public domain clone Xof the UNIX editor 'vi'. The program was originally developed for the XAtari ST, but has been ported to UNIX, OS/2, DOS, and Minix-ST as well. XPorts done by others, but not directly supported by this release, include XMinix-PC, Amiga, and a Data General system of some sort. X XThe good news about stevie is that it is extremely portable. It supports Xsystems with virtually all combinations of integer size, pointer size, Xand byte order. The only major issue remaining, for some environments, Xis that the file is kept in memory. For most environments, this isn't a Xproblem, but for Minix-PC it is particularly annoying. X XThe files included in this release are: X XREADME X This file. X Xstevie.mm Xstevie.doc X Reference manual for STEVIE. Assumes familiarity with vi. X Xsource.doc X Quick overview of the major data structures used. X Xporting.doc X Tips for porting STEVIE to other systems. X Xos2.mk Xunix.mk Xdos.mk Xtos.mk Xminix.mk X Makefiles for OS/2, UNIX, DOS, and the Atari ST (TOS and Minix). X Xos2.c Xunix.c Xdos.c Xtos.c Xminix.c Xterm.h Xenv.h X System-dependent code for the same. X Xalloc.c ascii.h cmdline.c edit.c fileio.c help.c hexchars.c Xkeymap.h linefunc.c main.c mark.c misccmds.c normal.c ops.c ops.h Xparam.c param.h ptrfunc.c regexp.c regexp.h regmagic.h regsub.c Xscreen.c search.c stevie.h term.c undo.c version.c X X C source and header files for STEVIE. X Xctags.doc X Documentation for the accompanying program 'ctags'. X Xctags.c X Source code for the program 'ctags'. X X XTo compile STEVIE for one of the provided systems: X X 1. Edit the file 'env.h' to set the system defines as needed. X X 2. Check the makefile for your system, and modify as needed. X X 3. Compile. X XGood Luck... X XTony Andrews X8/6/89 HE_HATES_THESE_CANS if test 1787 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 1787 characters)' fi fi # end of overwriting check echo shar: extracting "'alloc.c'" '(4487 characters)' if test -f 'alloc.c' then echo shar: will not over-write existing file "'alloc.c'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'alloc.c' X/* $Header: /nw/tony/src/stevie/src/RCS/alloc.c,v 1.5 89/08/06 09:49:22 tony Exp $ X * X * Various allocation routines and routines returning information about X * allocated objects. X */ X X#include "stevie.h" X Xchar * Xalloc(size) Xunsigned size; X{ X char *p; /* pointer to new storage space */ X X p = malloc(size); X if ( p == (char *)NULL ) { /* if there is no more room... */ X emsg("alloc() is unable to find memory!"); X } X return(p); X} X Xchar * Xstrsave(string) Xchar *string; X{ X return(strcpy(alloc((unsigned)(strlen(string)+1)),string)); X} X Xvoid Xscreenalloc() X{ X /* X * If we're changing the size of the screen, free the old arrays X */ X if (Realscreen != NULL) X free(Realscreen); X if (Nextscreen != NULL) X free(Nextscreen); X X Realscreen = malloc((unsigned)(Rows*Columns)); X Nextscreen = malloc((unsigned)(Rows*Columns)); X} X X/* X * Allocate and initialize a new line structure with room for X * 'nchars'+1 characters. We add one to nchars here to allow for X * null termination because all the callers would just do it otherwise. X */ XLINE * Xnewline(nchars) Xint nchars; X{ X register LINE *l; X X if ((l = (LINE *) alloc(sizeof(LINE))) == NULL) X return (LINE *) NULL; X X l->s = alloc((unsigned) (nchars+1)); /* the line is empty */ X l->s[0] = NUL; X l->size = nchars + 1; X X l->prev = (LINE *) NULL; /* should be initialized by caller */ X l->next = (LINE *) NULL; X X return l; X} X X/* X * filealloc() - construct an initial empty file buffer X */ Xvoid Xfilealloc() X{ X if ((Filemem->linep = newline(0)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X if ((Filetop->linep = newline(0)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X if ((Fileend->linep = newline(0)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X Filemem->index = 0; X Filetop->index = 0; X Fileend->index = 0; X X Filetop->linep->next = Filemem->linep; /* connect Filetop to Filemem */ X Filemem->linep->prev = Filetop->linep; X X Filemem->linep->next = Fileend->linep; /* connect Filemem to Fileend */ X Fileend->linep->prev = Filemem->linep; X X *Curschar = *Filemem; X *Topchar = *Filemem; X X Filemem->linep->num = 0; X Fileend->linep->num = 0xffff; X X clrall(); /* clear all marks */ X u_clear(); /* clear the undo buffer */ X} X X/* X * freeall() - free the current buffer X * X * Free all lines in the current buffer. X */ Xvoid Xfreeall() X{ X register LINE *lp, *xlp; X X for (lp = Filetop->linep; lp != NULL ;lp = xlp) { X if (lp->s != NULL) X free(lp->s); X xlp = lp->next; X free((char *)lp); X } X X Curschar->linep = NULL; /* clear pointers */ X Filetop->linep = NULL; X Filemem->linep = NULL; X Fileend->linep = NULL; X X u_clear(); X} X X/* X * bufempty() - return TRUE if the buffer is empty X */ Xbool_t Xbufempty() X{ X return (buf1line() && Filemem->linep->s[0] == NUL); X} X X/* X * buf1line() - return TRUE if there is only one line X */ Xbool_t Xbuf1line() X{ X return (Filemem->linep->next == Fileend->linep); X} X X/* X * lineempty() - return TRUE if the current line is empty X */ Xbool_t Xlineempty() X{ X return (Curschar->linep->s[0] == NUL); X} 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 X * on the NUL byte, but handle it correctly in case it happens. X */ Xbool_t Xendofline(p) Xregister LPTR *p; X{ X return (p->linep->s[p->index] == NUL || p->linep->s[p->index+1] == NUL); X} X/* X * canincrease(n) - returns TRUE if the current line can be increased 'n' bytes X * X * This routine returns immediately if the requested space is available. X * If not, it attempts to allocate the space and adjust the data structures X * accordingly. If everything fails it returns FALSE. X */ Xbool_t Xcanincrease(n) Xregister int n; X{ X register int nsize; X register char *s; /* pointer to new space */ X X nsize = strlen(Curschar->linep->s) + 1 + n; /* size required */ X X if (nsize <= Curschar->linep->size) X return TRUE; X X /* X * Need to allocate more space for the string. Allow some extra X * space on the assumption that we may need it soon. This avoids X * excessive numbers of calls to malloc while entering new text. X */ X if ((s = alloc((unsigned) (nsize + SLOP))) == NULL) { X emsg("Can't add anything, file is too big!"); X State = NORMAL; X return FALSE; X } X X Curschar->linep->size = nsize + SLOP; X strcpy(s, Curschar->linep->s); X free(Curschar->linep->s); X Curschar->linep->s = s; X X return TRUE; X} X Xchar * Xmkstr(c) Xchar c; X{ X static char s[2]; X X s[0] = c; X s[1] = NUL; X X return s; X} HE_HATES_THESE_CANS if test 4487 -ne "`wc -c < 'alloc.c'`" then echo shar: error transmitting "'alloc.c'" '(should have been 4487 characters)' fi fi # end of overwriting check echo shar: extracting "'ascii.h'" '(282 characters)' if test -f 'ascii.h' then echo shar: will not over-write existing file "'ascii.h'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'ascii.h' X/* $Header: /nw/tony/src/stevie/src/RCS/ascii.h,v 1.2 89/03/11 22:42:03 tony Exp $ X * X * Definitions of various common control characters X */ X X#define NUL '\0' X#define BS '\010' X#define TAB '\011' X#define NL '\012' X#define CR '\015' X#define ESC '\033' X X#define CTRL(x) ((x) & 0x1f) HE_HATES_THESE_CANS if test 282 -ne "`wc -c < 'ascii.h'`" then echo shar: error transmitting "'ascii.h'" '(should have been 282 characters)' fi fi # end of overwriting check echo shar: extracting "'cmdline.c'" '(13370 characters)' if test -f 'cmdline.c' then echo shar: will not over-write existing file "'cmdline.c'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'cmdline.c' X/* $Header: /nw/tony/src/stevie/src/RCS/cmdline.c,v 1.20 89/08/13 11:41:23 tony Exp $ X * X * Routines to parse and execute "command line" commands, such as searches X * or colon commands. 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)"; Xstatic char *nooutfile = "No output file"; Xstatic char *morefiles = "more files to edit"; X Xextern char **files; /* used for "n" and "rew" */ Xextern int numfiles, curfile; X X#define CMDSZ 100 /* size of the command buffer */ X Xstatic bool_t doecmd(); Xstatic void badcmd(), get_range(); Xstatic LPTR *get_line(); X X/* X * getcmdln() - read a command line from the terminal X * X * Reads a command line started by typing '/', '?', '!', or ':'. Returns a X * pointer to the string that was read. For searches, an optional trailing X * '/' or '?' is removed. X */ Xchar * Xgetcmdln(firstc) Xchar firstc; X{ X static char buff[CMDSZ]; X register char *p = buff; X register int c; X register char *q; X X gotocmd(TRUE, firstc); X X /* collect the command string, handling '\b' and @ */ X do { X switch (c = vgetc()) { X X default: /* a normal character */ X outchar(c); X *p++ = c; X break; X X case BS: X if (p > buff) { X /* X * this is gross, but it relies X * only on 'gotocmd' X */ X p--; X gotocmd(TRUE, firstc); X for (q = buff; q < p ;q++) X outchar(*q); X } else { X msg(""); X return NULL; /* back to cmd mode */ X } X break; X X case '@': /* line kill */ X p = buff; X gotocmd(TRUE, firstc); X break; X X case NL: /* done reading the line */ X case CR: X break; X } X } while (c != NL && c != CR); X X *p = '\0'; X X if (firstc == '/' || firstc == '?') { /* did we do a search? */ X /* X * Look for a terminating '/' or '?'. This will be the first X * one that isn't quoted. Truncate the search string there. X */ X for (p = buff; *p ;) { X if (*p == firstc) { /* we're done */ X *p = '\0'; X break; X } else if (*p == '\\') /* next char quoted */ X p += 2; X else X p++; /* normal char */ X } X } X return buff; X} X X/* X * docmdln() - handle a colon command X * X * Handles a colon command received interactively by getcmdln() or from X * the environment variable "EXINIT" (or eventually .virc). X */ Xvoid Xdocmdln(cmdline) Xchar *cmdline; X{ X char buff[CMDSZ]; X char cmdbuf[CMDSZ]; X char argbuf[CMDSZ]; X char *cmd, *arg; X register char *p; X /* X * The next two variables contain the bounds of any range given in a X * command. If no range was given, both contain null line pointers. X * If only a single line was given, u_pos will contain a null line X * pointer. X */ X LPTR l_pos, u_pos; X X X /* X * Clear the range variables. X */ X l_pos.linep = (struct line *) NULL; X u_pos.linep = (struct line *) NULL; X X if (cmdline == NULL) X return; X X if (strlen(cmdline) > CMDSZ-2) { X msg("Error: command line too long"); X return; X } X strcpy(buff, cmdline); X X /* skip any initial white space */ X for (cmd = buff; *cmd != NUL && isspace(*cmd) ;cmd++) X ; X X if (*cmd == '%') { /* change '%' to "1,$" */ X strcpy(cmdbuf, "1,$"); /* kind of gross... */ X strcat(cmdbuf, cmd+1); X strcpy(cmd, cmdbuf); X } X X while ((p=strchr(cmd, '%')) != NULL && *(p-1) != '\\') { X /* change '%' to Filename */ X if (Filename == NULL) { X emsg("No filename"); X return; X } X *p= NUL; X strcpy (cmdbuf, cmd); X strcat (cmdbuf, Filename); X strcat (cmdbuf, p+1); X strcpy(cmd, cmdbuf); X msg(cmd); /*repeat */ X } X X while ((p=strchr(cmd, '#')) != NULL && *(p-1) != '\\') { X /* change '#' to Altname */ X if (altfile == NULL) { X emsg("No alternate file"); X return; X } X *p= NUL; X strcpy (cmdbuf, cmd); X strcat (cmdbuf, altfile); X strcat (cmdbuf, p+1); X strcpy(cmd, cmdbuf); X msg(cmd); /*repeat */ X } X X /* X * Parse a range, if present (and update the cmd pointer). X */ X get_range(&cmd, &l_pos, &u_pos); X X if (l_pos.linep != NULL) { X if (LINEOF(&l_pos) > LINEOF(&u_pos)) { X emsg("Invalid range"); X return; X } 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 ; X if ( *p == NUL ) X arg = NULL; X else { X *p = NUL; X for (p++; *p != NUL && isspace(*p) ;p++) X ; X if (*p == NUL) X arg = NULL; X else { X strcpy(argbuf, p); X arg = argbuf; X } X } X if (strcmp(cmd,"q!") == 0) X getout(); X if (strcmp(cmd,"q") == 0) { X if (Changed) X emsg(nowrtmsg); X else { X if ((curfile + 1) < numfiles) X emsg(morefiles); X else X getout(); X } X return; X } X if (strcmp(cmd,"w") == 0) { X if (arg == NULL) { X if (Filename != NULL) { X writeit(Filename, &l_pos, &u_pos); X } else X emsg(nooutfile); X } X else X writeit(arg, &l_pos, &u_pos); X return; X } X if (strcmp(cmd,"wq") == 0) { X if (Filename != NULL) { X if (writeit(Filename, (LPTR *)NULL, (LPTR *)NULL)) X getout(); X } else X emsg(nooutfile); X return; X } X if (strcmp(cmd, "x") == 0) { X doxit(); X return; X } X X if (strcmp(cmd,"f") == 0 && arg == NULL) { X fileinfo(); X return; X } X if (*cmd == 'n') { X if ((curfile + 1) < numfiles) { X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[1] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[++curfile]); X stuffin("\n"); X } else X emsg("No more files!"); X return; X } X if (*cmd == 'N') { X if (curfile > 0) { X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[1] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[--curfile]); X stuffin("\n"); X } else X emsg("No more files!"); X return; X } X if (strncmp(cmd, "rew", 3) == 0) { X if (numfiles <= 1) /* nothing to rewind */ X return; X curfile = 0; X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[3] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[0]); X stuffin("\n"); X return; X } X if (strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0) { X (void) doecmd(arg, cmd[1] == '!'); X return; X } X /* X * The command ":e#" gets expanded to something like ":efile", so X * detect that case here. X */ X if (*cmd == 'e' && arg == NULL) { X if (cmd[1] == '!') X (void) doecmd(&cmd[2], TRUE); X else X (void) doecmd(&cmd[1], FALSE); X return; X } X if (strcmp(cmd,"f") == 0) { X Filename = strsave(arg); X filemess(""); X return; X } X if (strcmp(cmd,"r") == 0) { X if (arg == NULL) { X badcmd(); X return; X } X if (readfile(arg, Curschar, 1)) { X emsg("Can't open file"); X return; X } X updatescreen(); X CHANGED; X return; X } X if (strcmp(cmd,"=") == 0) { X smsg("%d", cntllines(Filemem, &l_pos)); X return; X } X if (strncmp(cmd,"ta", 2) == 0) { X dotag(arg, cmd[2] == '!'); X return; X } X if (strncmp(cmd,"set", 2) == 0) { X doset(arg); X return; X } X if (strcmp(cmd,"help") == 0) { X if (help()) { X screenclear(); X updatescreen(); X } X return; X } X if (strncmp(cmd, "ve", 2) == 0) { X extern char *Version; X X msg(Version); X return; X } X if (strcmp(cmd, "sh") == 0) { X doshell(NULL); X return; X } X if (*cmd == '!') { X doshell(cmdbuf+1); 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 *Curschar = l_pos; X return; X } X X badcmd(); X} X X Xdoxit() X{ X if (Changed) { X if (Filename != NULL) { X if (!writeit(Filename, (LPTR *)NULL, (LPTR *)NULL)) X return; X } else { X emsg(nooutfile); X return; X } X } X if ((curfile + 1) < numfiles) X emsg(morefiles); X else X getout(); X} X X/* X * get_range - parse a range specifier X * X * Ranges are of the form: X * X * addr[,addr] X * X * where 'addr' is: X * X * $ [+- NUM] X * 'x [+- NUM] (where x denotes a currently defined mark) X * . [+- NUM] X * NUM X * X * The pointer *cp is updated to point to the first character following X * the range spec. If an initial address is found, but no second, the X * upper bound is equal to the lower. X */ Xstatic void Xget_range(cp, lower, upper) Xregister char **cp; XLPTR *lower, *upper; X{ X register LPTR *l; X register char *p; X X if ((l = get_line(cp)) == NULL) X return; X X *lower = *l; X X for (p = *cp; *p != NUL && isspace(*p) ;p++) X ; X X *cp = p; X X if (*p != ',') { /* is there another line spec ? */ X *upper = *lower; X return; X } X X *cp = ++p; X X if ((l = get_line(cp)) == NULL) { X *upper = *lower; X return; X } X X *upper = *l; X} X Xstatic LPTR * Xget_line(cp) Xchar **cp; X{ X static LPTR pos; X LPTR *lp; X register char *p, c; X register int lnum; X X pos.index = 0; /* shouldn't matter... check back later */ X X p = *cp; X /* X * Determine the basic form, if present. X */ X switch (c = *p++) { X X case '$': X pos.linep = Fileend->linep->prev; X break; X X case '.': X pos.linep = Curschar->linep; X break; X X case '\'': X if ((lp = getmark(*p++)) == NULL) { X emsg("Unknown mark"); X return (LPTR *) NULL; X } X pos = *lp; X break; X X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X for (lnum = c - '0'; isdigit(*p) ;p++) X lnum = (lnum * 10) + (*p - '0'); X X pos = *gotoline(lnum); X break; X X default: X return (LPTR *) NULL; X } X X while (*p != NUL && isspace(*p)) X p++; X X if (*p == '-' || *p == '+') { X bool_t neg = (*p++ == '-'); X X for (lnum = 0; isdigit(*p) ;p++) X lnum = (lnum * 10) + (*p - '0'); X X if (neg) X lnum = -lnum; X X pos = *gotoline( cntllines(Filemem, &pos) + lnum ); X } X X *cp = p; X return &pos; X} X Xstatic void Xbadcmd() X{ X emsg("Unrecognized command"); X} X X#define LSIZE 256 /* max. size of a line in the tags file */ X X/* X * dotag(tag, force) - goto tag X */ Xvoid Xdotag(tag, force) Xchar *tag; Xbool_t force; X{ X FILE *tp, *fopen(); X char lbuf[LSIZE]; /* line buffer */ X char pbuf[LSIZE]; /* search pattern buffer */ X register char *fname, *str; X register char *p; X X if ((tp = fopen("tags", "r")) == NULL) { X emsg("Can't open tags file"); X return; X } X X while (fgets(lbuf, LSIZE, tp) != NULL) { X X if ((fname = strchr(lbuf, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *fname++ = '\0'; X if ((str = strchr(fname, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *str++ = '\0'; X X if (strcmp(lbuf, tag) == 0) { X X /* X * Scan through the search string. If we see a magic X * char, we have to quote it. This lets us use "real" X * implementations of ctags. X */ X p = pbuf; X *p++ = *str++; /* copy the '/' or '?' */ X *p++ = *str++; /* copy the '^' */ X X for (; *str != NUL ;str++) { X if (*str == '\\') { X *p++ = *str++; X *p++ = *str; X } else if (strchr("/?", *str) != NULL) { X if (str[1] != '\n') { X *p++ = '\\'; X *p++ = *str; X } else X *p++ = *str; X } else if (strchr("^()*.", *str) != NULL) { X *p++ = '\\'; X *p++ = *str; X } else X *p++ = *str; X } X *p = NUL; X X /* X * This looks out of order, but by calling stuffin() X * before doecmd() we keep an extra screen update X * from occuring. This stuffins() have no effect X * until we get back to the main loop, anyway. X */ X stuffin(pbuf); /* str has \n at end */ X stuffin("\007"); /* CTRL('g') */ X X if (doecmd(fname, force)) { X fclose(tp); X return; X } else X stuffin(NULL); /* clear the input */ X } X } X emsg("tag not found"); X fclose(tp); X} X Xstatic bool_t Xdoecmd(arg, force) Xchar *arg; Xbool_t force; X{ X int line = 1; /* line # to go to in new file */ X X if (!force && Changed) { X emsg(nowrtmsg); X if (altfile) X free(altfile); X altfile = strsave(arg); X return FALSE; X } X if (arg != NULL) { X /* X * First detect a ":e" on the current file. This is mainly X * for ":ta" commands where the destination is within the X * current file. X */ X if (Filename != NULL && strcmp(arg, Filename) == 0) { X if (!Changed || (Changed && !force)) X return TRUE; X } X if (altfile) { X if (strcmp (arg, altfile) == 0) X line = altline; X free(altfile); X } X altfile = Filename; X altline = cntllines(Filemem, Curschar); X Filename = strsave(arg); X } X if (Filename == NULL) { X emsg("No filename"); X return FALSE; X } X X /* clear mem and read file */ X freeall(); X filealloc(); X UNCHANGED; X X if (readfile(Filename, Filemem, 0)) X filemess("[New File]"); X X *Topchar = *Curschar; X if (line != 1) { X stuffnum(line); X stuffin("G"); X } X do_mlines(); X setpcmark(); X updatescreen(); X return TRUE; X} X Xvoid Xgotocmd(clr, firstc) Xbool_t clr; Xchar 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) Xchar *s; X{ X gotocmd(TRUE, 0); X outstr(s); X flushbuf(); X} X X/*VARARGS1*/ Xvoid Xsmsg(s, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) Xchar *s; Xint a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16; X{ X char sbuf[80]; X X sprintf(sbuf, s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16); 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) Xchar *s; X{ X if (P(P_EB)) X beep(); X msg(s); X} X Xvoid Xwait_return() X{ X register char c; X X if (got_int) X outstr("Interrupt: "); X X outstr("Press RETURN to continue"); X do { X c = vgetc(); X } while (c != CR && c != NL && c != ' ' && c != ':'); X X if (c == ':') { X outchar(NL); X docmdln(getcmdln(c)); X } else X screenclear(); X X updatescreen(); X} HE_HATES_THESE_CANS if test 13370 -ne "`wc -c < 'cmdline.c'`" then echo shar: error transmitting "'cmdline.c'" '(should have been 13370 characters)' fi fi # end of overwriting check echo shar: extracting "'ctags.c'" '(2893 characters)' if test -f 'ctags.c' then echo shar: will not over-write existing file "'ctags.c'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'ctags.c' X/* X * ctags - first cut at a UNIX ctags re-implementation X */ X X/* X * Caveats: X * X * Only simple function declarations are recognized, as in: X * X * type X * fname(...) X * X * where "fname" is the name of the function and must come at the beginning X * of a line. This is the form I always use, so the limitation doesn't X * bother me. X * X * Macros (with or without parameters) of the following form are also detected: X * X * "#" [white space] "define" [white space] NAME X * X * No sorting or detection of duplicate functions is done. X * X * If there are no arguments, a list of filenames to be searched is read X * from the standard input. Otherwise, all arguments are assumed to be X * file names. X * X * Tony Andrews X * August 1987 X */ X X#include <stdio.h> X#include <ctype.h> X#include <string.h> X Xint ac; Xchar **av; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X char *fname, *nextfile(); X FILE *tp, *fopen(); X X ac = argc; X av = argv; X X if ((tp = fopen("tags", "w")) == NULL) { X fprintf(stderr, "Can't create tags file\n"); X exit(1); X } X X while ((fname = nextfile()) != NULL) X dofile(fname, tp); X X fclose(tp); X exit(0); X} X Xchar * Xnextfile() /* returns ptr to next file to be searched, null at end */ X{ X static char buf[128]; X static int ap = 1; X char *gets(); X X if (ac <= 1) { /* read from stdin */ X if (feof(stdin)) X return (char *) NULL; X return (gets(buf)); X } else { X if (ap < ac) X return av[ap++]; X else X return (char *) NULL; X } X} X X#define LSIZE 512 /* max. size of a line */ X X#define BEGID(c) (isalpha(c) || (c) == '_') X#define MIDID(c) (isalpha(c) || isdigit(c) || (c) == '_') X Xdofile(fn, tp) Xchar *fn; XFILE *tp; X{ X FILE *fp, *fopen(); X char *cp, *strchr(); X char lbuf[LSIZE]; X char func[LSIZE]; X int i, j; X X if ((fp = fopen(fn, "r")) == NULL) { X fprintf(stderr, "Can't open file '%s' - skipping\n", fn); X return; X } X X while (fgets(lbuf, LSIZE, fp) != NULL) { X X lbuf[strlen(lbuf)-1] = '\0'; /* bag the newline */ X X if (BEGID(lbuf[0])) { /* could be a function */ X for (i=0; MIDID(lbuf[i]) ;i++) /* grab the name */ X func[i] = lbuf[i]; X X func[i] = '\0'; /* null terminate the name */ X X /* X * We've skipped to the end of what may be a function X * name. Check to see if the next char is a paren, X * and make sure the closing paren is here too. X */ X if (lbuf[i]=='(' && (((cp = strchr(lbuf,')'))!=NULL))) { X *++cp = '\0'; X fprintf(tp, "%s\t%s\t/^%s$/\n", func,fn,lbuf); X } X X } else if (lbuf[0] == '#') { /* could be a define */ X for (i=1; isspace(lbuf[i]) ;i++) X ; X if (strncmp(&lbuf[i], "define", 6) != 0) X continue; X X i += 6; /* skip "define" */ X X for (; isspace(lbuf[i]) ;i++) X ; X X if (!BEGID(lbuf[i])) X continue; X X for (j=0; MIDID(lbuf[i]) ;i++, j++) X func[j] = lbuf[i]; X X func[j] = '\0'; /* null terminate the name */ X lbuf[i] = '\0'; X fprintf(tp, "%s\t%s\t/^%s/\n", func, fn, lbuf); X } X } X fclose(fp); X} HE_HATES_THESE_CANS if test 2893 -ne "`wc -c < 'ctags.c'`" then echo shar: error transmitting "'ctags.c'" '(should have been 2893 characters)' fi fi # end of overwriting check echo shar: extracting "'edit.c'" '(6488 characters)' if test -f 'edit.c' then echo shar: will not over-write existing file "'edit.c'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'edit.c' X/* $Header: /nw/tony/src/stevie/src/RCS/edit.c,v 1.11 89/08/02 19:57:12 tony Exp $ X * X * The main edit loop as well as some other simple cursor movement routines. X */ X X#include "stevie.h" X X/* X * This flag is used to make auto-indent work right on lines where only X * a <RETURN> or <ESC> is typed. It is set when an auto-indent is done, X * and reset when any other editting is done on the line. If an <ESC> X * or <RETURN> is received, and did_ai is TRUE, the line is truncated. X */ Xbool_t did_ai = FALSE; X Xvoid Xedit() X{ X extern bool_t need_redraw; X int c; X register char *p, *q; X X Prenum = 0; X X /* position the display and the cursor at the top of the file. */ X *Topchar = *Filemem; X *Curschar = *Filemem; X Cursrow = Curscol = 0; X X do_mlines(); /* check for mode lines before starting */ X X updatescreen(); X X for ( ;; ) { X X /* Figure out where the cursor is based on Curschar. */ X cursupdate(); X X if (need_redraw && !anyinput()) { X updatescreen(); X need_redraw = FALSE; X } X X if (!anyinput()) X windgoto(Cursrow,Curscol); X X X c = vgetc(); X X if (State == NORMAL) { X X /* We're in the normal (non-insert) mode. */ X X /* Pick up any leading digits and compute 'Prenum' */ X if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){ X Prenum = Prenum*10 + (c-'0'); X continue; X } X /* execute the command */ X normal(c); X Prenum = 0; X X } else { X X /* X * Insert or Replace mode. X */ X switch (c) { X X case ESC: /* an escape ends input mode */ X X /* X * If we just did an auto-indent, truncate the X * line, and put the cursor back. X */ X if (did_ai) { X Curschar->linep->s[0] = NUL; X Curschar->index = 0; X did_ai = FALSE; X } X X set_want_col = TRUE; X X /* Don't end up on a '\n' if you can help it. */ X if (gchar(Curschar) == NUL && Curschar->index != 0) X dec(Curschar); X X /* X * The cursor should end up on the last inserted X * character. This is an attempt to match the real X * 'vi', but it may not be quite right yet. X */ X if (Curschar->index != 0 && !endofline(Curschar)) X dec(Curschar); X X State = NORMAL; X msg(""); X X /* construct the Redo buffer */ X p=Redobuff; X q=Insbuff; X while ( q < Insptr ) X *p++ = *q++; X *p++ = ESC; X *p = NUL; X updatescreen(); X break; X X case CTRL('D'): X /* X * Control-D is treated as a backspace in insert X * mode to make auto-indent easier. This isn't X * completely compatible with vi, but it's a lot X * easier than doing it exactly right, and the X * difference isn't very noticeable. X */ X case BS: X /* can't backup past starting point */ X if (Curschar->linep == Insstart->linep && X Curschar->index <= Insstart->index) { X beep(); X break; X } X X /* can't backup to a previous line */ X if (Curschar->linep != Insstart->linep && X Curschar->index <= 0) { X beep(); X break; X } X X did_ai = FALSE; X dec(Curschar); X if (State == INSERT) X delchar(TRUE); X /* X * It's a little strange to put backspaces into X * the redo buffer, but it makes auto-indent a X * lot easier to deal with. X */ X *Insptr++ = BS; X Ninsert++; X cursupdate(); X updateline(); X break; X X case CR: X case NL: X *Insptr++ = NL; X Ninsert++; X opencmd(FORWARD, TRUE); /* open a new line */ X break; X X default: X did_ai = FALSE; X insertchar(c); X break; X } X } X } X} X Xvoid Xinsertchar(c) Xint c; X{ X inschar(c); X *Insptr++ = c; X Ninsert++; X /* X * The following kludge avoids overflowing the statically X * allocated insert buffer. Just dump the user back into X * command mode, and print a message. X */ X if (Insptr+10 >= &Insbuff[1024]) { X stuffin(mkstr(ESC)); X emsg("No buffer space - returning to command mode"); X sleep(2); X } X updateline(); X} X Xvoid Xgetout() X{ X windgoto(Rows-1,0); X putchar('\r'); X putchar('\n'); X windexit(0); X} X Xvoid Xscrolldown(nlines) Xint nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X X /* Scroll up 'nlines' lines. */ X while (nlines--) { X if ((p = prevline(Topchar)) == NULL) X break; X done += plines(p); X *Topchar = *p; X /* X * If the cursor is on the bottom line, we need to X * make sure it gets moved up the appropriate number X * of lines so it stays on the screen. X */ X if (Curschar->linep == Botchar->linep->prev) { X int i = 0; X while (i < done) { X i += plines(Curschar); X *Curschar = *prevline(Curschar); X } X } X } X s_ins(0, done); X} X Xvoid Xscrollup(nlines) Xint nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X register int pl; /* # of plines for the current line */ X X /* Scroll down 'nlines' lines. */ X while (nlines--) { X pl = plines(Topchar); X if ((p = nextline(Topchar)) == NULL) X break; X done += pl; X if (Curschar->linep == Topchar->linep) X *Curschar = *p; X *Topchar = *p; X X } X s_del(0, done); X} X X/* X * oneright X * oneleft X * onedown X * oneup X * X * Move one char {right,left,down,up}. Return TRUE when X * sucessful, FALSE when we hit a boundary (of a line, or the file). X */ X 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 /* fall through */ X case -1: X return FALSE; X } X /*NOTREACHED*/ 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 /* fall through */ X case -1: X return FALSE; X } X /*NOTREACHED*/ X} X Xvoid Xbeginline(flag) Xbool_t flag; X{ X while ( oneleft() ) X ; X if (flag) { X while (isspace(gchar(Curschar)) && oneright()) X ; X } X set_want_col = TRUE; X} X Xbool_t Xoneup(n) Xint n; X{ X LPTR p, *np; X register int k; X X p = *Curschar; X for ( k=0; k<n; k++ ) { X /* Look for the previous line */ X if ( (np=prevline(&p)) == NULL ) { X /* If we've at least backed up a little .. */ X if ( k > 0 ) X break; /* to update the cursor, etc. */ X else X return FALSE; X } X p = *np; X } X *Curschar = p; X /* This makes sure Topchar gets updated so the complete line */ X /* is one the screen. */ X cursupdate(); X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} X Xbool_t Xonedown(n) Xint n; X{ X LPTR p, *np; X register int k; X X p = *Curschar; X for ( k=0; k<n; k++ ) { X /* Look for the next line */ X if ( (np=nextline(&p)) == NULL ) { X if ( k > 0 ) X break; X else X return FALSE; X } X p = *np; X } X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} HE_HATES_THESE_CANS if test 6488 -ne "`wc -c < 'edit.c'`" then echo shar: error transmitting "'edit.c'" '(should have been 6488 characters)' fi fi # end of overwriting check echo shar: extracting "'env.h'" '(2323 characters)' if test -f 'env.h' then echo shar: will not over-write existing file "'env.h'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'env.h' 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. X * Most of the code is pretty machine-independent. Machine dependent X * code goes in a file like tos.c or unix.c. The only other place X * where machine dependent code goes is term.h for escape sequences. X */ X X/* #define ATARI /* For the Atari ST */ X#define UNIX /* System V or BSD */ X/* #define OS2 /* Microsoft OS/2 1.1 */ X/* #define DOS /* MSDOS 3.3 (on AT) */ X X/* X * If UNIX is defined above, then BSD may be defined. X */ X#ifdef UNIX X/* #define BSD /* Berkeley UNIX */ X#endif X X/* X * If ATARI is defined, MINIX may be defined. Otherwise, the editor X * is set up to compile using the Sozobon C compiler under TOS. X */ X#ifdef ATARI X#define MINIX /* Minix for the Atari ST */ X#endif X X/* X * The yank buffer is still static, but its size can be specified X * here to override the default of 4K. X */ X/* #define YBSIZE 8192 /* yank buffer size */ 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 X#ifdef MINIX X#define STRCSPN X#endif X X#endif X X/* X * The following defines control the inclusion of "optional" features. As X * the code size of the editor grows, it will probably be useful to be able X * to tailor the editor to get the features you most want in environments X * with code size limits. X * X * TILDEOP X * Normally the '~' command works on a single character. This define X * turns on code that allows it to work like an operator. This is X * then enabled at runtime with the "tildeop" parameter. X * X * HELP X * If defined, a series of help screens may be views with the ":help" X * command. This eats a fair amount of data space. X * X * TERMCAP X * Where termcap support is provided, it is generally optional. If X * not enabled, you generally get hard-coded escape sequences for X * some "reasonable" terminal. In Minix, this means the console. For X * UNIX, this means an ANSI standard terminal. See the file "term.h" X * for details about specific environments. X * X */ X#define TILDEOP /* enable tilde to be an operator */ X#define HELP /* enable help command */ X#define TERMCAP /* enable termcap support */ HE_HATES_THESE_CANS if test 2323 -ne "`wc -c < 'env.h'`" then echo shar: error transmitting "'env.h'" '(should have been 2323 characters)' fi fi # end of overwriting check echo shar: extracting "'fileio.c'" '(5409 characters)' if test -f 'fileio.c' then echo shar: will not over-write existing file "'fileio.c'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'fileio.c' X/* $Header: /nw/tony/src/stevie/src/RCS/fileio.c,v 1.12 89/08/06 09:50:01 tony Exp $ X * X * Basic file I/O routines. X */ X X#include "stevie.h" X Xvoid Xfilemess(s) Xchar *s; X{ X smsg("\"%s\" %s", (Filename == NULL) ? "" : Filename, s); X flushbuf(); 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 = 0xffffffff; X} X X#define MAXLINE 256 /* maximum size of a line */ X Xbool_t Xreadfile(fname,fromp,nochangename) Xchar *fname; XLPTR *fromp; Xbool_t nochangename; /* if TRUE, don't change the Filename */ X{ X FILE *f, *fopen(); X register LINE *curr; X char buff[MAXLINE], buf2[80]; X register int i, c; X register 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 if ( (f=fopen(fixname(fname),"r")) == NULL ) X return TRUE; X X filemess(""); X X i = 0; X do { X c = getc(f); X X if (c == EOF) { X if (i == 0) /* normal loop termination */ X break; X X /* X * If we get EOF in the middle of a line, note the X * fact and complete the line ourselves. X */ X incomplete = TRUE; X c = NL; X } X X /* X * Abort if we get an interrupt, but finished reading the X * current line first. X */ X if (got_int && i == 0) X break; X X if (c >= 0x80) { X c -= 0x80; X nonascii++; X } X X /* X * If we reached the end of the line, OR we ran out of X * space for it, then process the complete line. X */ X if (c == NL || i == (MAXLINE-1)) { X LINE *lp; X X if (c != NL) X toolong = TRUE; X X buff[i] = '\0'; X if ((lp = newline(strlen(buff))) == NULL) X exit(1); X X strcpy(lp->s, buff); 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 i = 0; X linecnt++; X X } else if (c == NUL) X nulls++; /* count and ignore nulls */ X else { X buff[i++] = c; /* normal character */ X } X X nchars++; X X } while (!incomplete && !toolong); X X fclose(f); X X /* X * If the buffer was empty when we started, we have to go back X * and remove the "dummy" line at Filemem and patch up the ptrs. X */ X if (wasempty && nchars != 0) { X LINE *dummy = Filemem->linep; /* dummy line ptr */ X X free(dummy->s); /* free string space */ X Filemem->linep = Filemem->linep->next; X free((char *)dummy); /* free LINE struct */ 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 X renum(); X X if (got_int) { X smsg("\"%s\" Interrupt", fname); X got_int = FALSE; X return FALSE; /* an interrupt isn't really an error */ X } X X if (toolong) { X smsg("\"%s\" Line too long", fname); X return FALSE; X } X X sprintf(buff, "\"%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(buff, buf2); X msg(buff); X X return FALSE; X} 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 X * is to use the start or end of the file respectively. X */ Xbool_t Xwriteit(fname, start, end) Xchar *fname; XLPTR *start, *end; X{ X FILE *f, *fopen(); X FILE *fopenb(); /* open in binary mode, where needed */ X char *backup; X register char *s; X register long nchars; X register int lines; X register LPTR *p; X X smsg("\"%s\"", fname); X X /* X * Form the backup file name - change foo.* to foo.bak X */ X backup = alloc((unsigned) (strlen(fname) + 5)); X strcpy(backup, fname); X for (s = backup; *s && *s != '.' ;s++) X ; X *s = NUL; X strcat(backup, ".bak"); X X /* X * Delete any existing backup and move the current version X * to the backup. For safety, we don't remove the backup X * until the write has finished successfully. And if the X * 'backup' option is set, leave it around. X */ X rename(fname, backup); X X X f = P(P_CR) ? fopen(fixname(fname), "w") : fopenb(fixname(fname), "w"); X X if (f == NULL) { X emsg("Can't open file for writing!"); X free(backup); X return FALSE; X } X X /* X * If we were given a bound, start there. Otherwise just X * start at the beginning of the file. X */ X if (start == NULL || start->linep == NULL) X p = Filemem; X else X p = start; X X lines = 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 X * line, then bag it now. X */ X if (end != NULL && end->linep != NULL) { X if (end->linep == p->linep) X break; X } X X } while ((p = nextline(p)) != NULL); X X fclose(f); X smsg("\"%s\" %d line%s, %ld character%s", fname, X lines, (lines > 1) ? "s" : "", X nchars, (nchars > 1) ? "s" : ""); X X UNCHANGED; X X /* X * Remove the backup unless they want it left around X */ X if (!P(P_BK)) X remove(backup); X X free(backup); X X return TRUE; X} HE_HATES_THESE_CANS if test 5409 -ne "`wc -c < 'fileio.c'`" then echo shar: error transmitting "'fileio.c'" '(should have been 5409 characters)' fi fi # end of overwriting check # End of shell archive exit 0 --