v11i010: Stevie 3.69a - 2/6
Dave Tutelman
dmt at pegasus.ATT.COM
Sun Mar 11 05:41:29 AEST 1990
Posting-number: Volume 11, Issue 10
Submitted-by: dmt at pegasus.ATT.COM (Dave Tutelman)
Archive-name: stevie3.69a/part02
: This is a shar archive. Extract with sh, not csh.
: The rest of this file will extract:
: alloc.c cmdline.c edit.c enveval.c fileio.c help.c hexchars.c env.h keymap.h ops.h param.h regexp.h regmagic.h
echo extracting - alloc.c
sed 's/^X//' > alloc.c << '!EOR!'
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
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 if (!Realscreen || !Nextscreen)
X return (-1);
X else return (0);
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 if (l->s == NULL) return (LINE *) NULL;
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}
!EOR!
echo extracting - cmdline.c
sed 's/^X//' > cmdline.c << '!EOR!'
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 void 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 ESC: /* abandon command */
X msg("");
X return NULL;
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 EnvEval (arg, CMDSZ); /* expand environment vars */
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,"untag", 5) == 0) {
X if (P(P_TG))
X dountag(cmd[5]);
X else
X emsg("Tag stacking not enabled");
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
Xvoid
Xbadcmd()
X{
X emsg("Unrecognized command");
X}
X
Xbool_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 CLEOL; /* 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}
!EOR!
echo extracting - edit.c
sed 's/^X//' > edit.c << '!EOR!'
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 if (State == REPLACE) /* DMT added, 12/89 */
X delchar(FALSE);
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}
!EOR!
echo extracting - enveval.c
sed 's/^X//' > enveval.c << '!EOR!'
X/*
X * Evaluate a string, expanding environment variables
X * where encountered.
X * We'll use the UNIX convention for representing environment
X * variables: $xxx, where xxx is the shortest string that
X * matches some environment variable.
X */
X
X#include <stdio.h>
X#include <string.h>
X
Xchar *getenv();
X
Xint
XEnvEval (s, len)
X char *s;
X int len;
X/*------------------------------------------------------------------
X * s= Pointer to buffer, currently containing string. It will be
X * expanded in-place in the buffer.
X * len=Maximum allowable length of the buffer. (In this version, we
X * use a static buffer of 256 bytes internally.)
X *
X * RETURNS:
X * 0 on success.
X * -1 on failure. In this case, s may contain a partially
X * converted string, but it won't contain a partial
X * string. It will be the FULL string, with as
X * many substitutions as we could find.
X */
X
X{
X#define LEN 256
X char buf [LEN];
X char *s1, *s2;
X char *b1;
X int done=0;
X
X if (len > LEN)
X return (-1);
X
X s1 = s;
X
X /* Check for '$', and expand when we find one. */
X while (!done) {
X if ((s1 = strchr (s1, '$')) == NULL)
X done = 1;
X else {
X /*
X * Here's where the real work gets done.
X * We'll find the env.var., and convert
X * it into buf, then copy back into s
X * and continue.
X */
X char c;
X int need, got;
X
X /* Test successively longer strings, to see
X * if they're env.vars.
X */
X for (s2=++s1+1; ; s2++) {
X c = *s2; /* save it */
X *s2 = '\0';
X b1 = getenv (s1);
X *s2 = c; /* restore it */
X if (b1) /* found it */
X break;
X if (!*s2) /* nothing to try */
X goto Failed;
X }
X --s1; /* Back to the '$' */
X
X /* OK, we've found one (between s1 & s2,
X * non-inclusive). Its value is in b1.
X * Do the substitution into bufp,
X * and copy back into s.
X */
X need = strlen(b1) + strlen(s2) + 1;
X got = len - (s1-s);
X if (need > got)
X goto Failed;
X strcpy (buf, b1);
X strcat (buf, s2);
X strcpy (s1, buf);
X }
X }
X
X /* If we get here, the converted value is in s */
X return (0);
X
X Failed:
X return (-1);
X}
X
X
X/* #define SAMPLE */
X#ifdef SAMPLE /***************************************************/
X
Xmain (int argc, char **argv)
X{
X int i, ret;
X
X for (i=1; i<argc; i++) {
X printf ("Convert %s to", argv [i]);
X ret = EnvEval (argv [i], 80);
X printf (" %s", argv [i]);
X if (ret)
X printf (" - Failed");
X putchar ('\n');
X }
X}
X
X#endif
!EOR!
echo extracting - fileio.c
sed 's/^X//' > fileio.c << '!EOR!'
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 <sys/types.h> /* For stat() and chmod() */
X#include <sys/stat.h> /* Ditto */
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)
X/*-------------------------------------------------
X * Note that this will try to expand the file name using environment
X * variables. For this reason, we copy it into an 80-byte buffer,
X * so that there's room to expand it.
X *
X * It uses the environment-variable convention of UNIX, even
X * under systems with other conventions. That is, your home directory
X * would be called $HOME (even in DOS, where you might want to say %HOME%)
X *-----------------------------------------------------*/
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 char namebuf[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 strncpy (namebuf, fname, 80);
X EnvEval (namebuf, 80);
X
X if ( ! nochangename )
X Filename = strsave(namebuf);
X
X if ( (f=fopen(fixname(namebuf),"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", namebuf);
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", namebuf);
X return FALSE;
X }
X
X sprintf(buff, "\"%s\" %s%d line%s, %ld character%s",
X namebuf,
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 struct stat statbuf;
X int statres;
X
X smsg("\"%s\"", fname);
X
X /* Expand any environment variables left in the name.
X * fname better be in a variable big enough to handle the
X * expansion (80 bytes).
X */
X EnvEval (fname, 80);
X
X /* If the file already exists, get what we need to know
X * (like current mode).
X */
X statres = stat (fname, &statbuf);
X
X /*
X * Form the backup file name - change foo.* to foo.bak
X */
X backup = alloc((unsigned) (strlen(fname) + 5));
X if (backup == NULL) {
X emsg("Can't open file for writing!");
X return FALSE;
X }
X
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 /*
X * Set the mode of the new file to agree with the old.
X */
X if (statres==0)
X chmod (fname, statbuf.st_mode);
X
X return TRUE;
X}
!EOR!
echo extracting - help.c
sed 's/^X//' > help.c << '!EOR!'
X/* $Header: /nw/tony/src/stevie/src/RCS/help.c,v 1.9 89/08/06 09:50:09 tony Exp $
X *
X * Routine to display a command summary.
X * (Dave Tutelman note:
X * I added the ability to page backwards and forwards through help.
X * In order to minimize the abuse to the existing code, I used
X * "goto"s and labeled each screen. It's not the way I would have
X * done help from scratch, but it's not TOO ugly.
X * )
X */
X
X#include <ctype.h>
X#include "stevie.h"
X#include "ascii.h"
X#include "keymap.h"
X
X/* Macro to show help screen 'n'.
X * If C supported label types, it'd be cleaner to do it that way. */
X#define SHOWHELP( n ) switch(n) { \
X case 0: goto Screen0; \
X case 1: goto Screen1; \
X case 2: goto Screen2; \
X case 3: goto Screen3; \
X case 4: goto Screen4; \
X case 5: goto Screen5; \
X case 6: goto Screen6; \
X case 7: goto Screen7; \
X case 8: goto Screen8; \
X default: return (TRUE); }
X
Xextern char *Version;
X
Xstatic int helprow;
Xstatic int lastscreen = 0; /* return to help in previous screen */
X
X#ifdef HELP
X
Xstatic void longline();
X
Xbool_t
Xhelp()
X{
X int k;
X
X SHOWHELP( lastscreen ); /* where did we quit help last ? */
X
X/***********************************************************************
X * Zeroth Screen : Index to the help screens.
X ***********************************************************************/
X
XScreen0:
X CLS;
X windgoto(helprow = 0, 0);
X
Xlongline("\
X Index to HELP Screens\n\
X =====================\n\n");
Xlongline("\
X 0 Help index (this screen)\n\
X 1 Positioning within file, adjusting the screen\n\
X 2 Character positioning\n\
X 3 Line positioning, marking & returning, undo & redo\n");
Xlongline("\
X 4 Insert & replace, words, sentences, paragraphs\n\
X 5 Operators, miscellaneous operations, yank & put\n\
X 6 \"Ex\" command line operations\n\
X 7 Set parameters\n\
X 8 System-specific features\n");
X
X windgoto(0, 52);
X longline(Version);
X
X SHOWHELP( helpkey (0) );
X
X
X/***********************************************************************
X * First Screen: Positioning within file, Adjusting the Screen
X ***********************************************************************/
X
XScreen1:
X CLS;
X windgoto(helprow = 0, 0);
X
Xlongline("\
X Positioning within file\n\
X =======================\n\
X ^F Forward screenfull\n\
X ^B Backward screenfull\n");
Xlongline("\
X ^D scroll down half screen\n\
X ^U scroll up half screen\n");
Xlongline("\
X G Goto line (end default)\n\
X ]] next function\n\
X [[ previous function\n\
X /re next occurence of regular expression 're'\n");
Xlongline("\
X ?re prior occurence of regular expression 're'\n\
X n repeat last / or ?\n\
X N reverse last / or ?\n\
X % find matching (, ), {, }, [, or ]\n");
Xlongline("\
X\n\
X Adjusting the screen\n\
X ====================\n\
X ^L Redraw the screen\n\
X ^E scroll window down 1 line\n\
X ^Y scroll window up 1 line\n");
Xlongline("\
X z<RETURN> redraw, current line at top\n\
X z- ... at bottom\n\
X z. ... at center\n");
X
X SHOWHELP( helpkey (1) );
X
X
X/***********************************************************************
X * Second Screen: Character positioning
X ***********************************************************************/
X
XScreen2:
X CLS;
X windgoto(helprow = 0, 0);
X
Xlongline("\
X Character Positioning\n\
X =====================\n\
X ^ first non-white\n\
X 0 beginning of line\n\
X $ end of line\n\
X h backward\n");
Xlongline("\
X l forward\n\
X ^H same as h\n\
X space same as l\n\
X fx find 'x' forward\n");
Xlongline("\
X Fx find 'x' backward\n\
X tx upto 'x' forward\n\
X Tx upto 'x' backward\n\
X ; Repeat last f, F, t, or T\n");
Xlongline("\
X , inverse of ;\n\
X | to specified column\n\
X % find matching (, ), {, }, [, or ]\n");
X
X SHOWHELP( helpkey (2) );
X
X
X/***********************************************************************
X * Third Screen: Line Positioning, Marking and Returning
X ***********************************************************************/
X
XScreen3:
X CLS;
X windgoto(helprow = 0, 0);
X
Xlongline("\
X Line Positioning\n\
X ================\n\
X H home window line\n\
X L last window line\n\
X M middle window line\n");
Xlongline("\
X + next line, at first non-white\n\
X - previous line, at first non-white\n\
X CR return, same as +\n\
X j next line, same column\n\
X k previous line, same column\n");
X
Xlongline("\
X\n\
X Marking and Returning\n\
X =====================\n\
X `` previous context\n\
X '' ... at first non-white in line\n");
Xlongline("\
X mx mark position with letter 'x'\n\
X `x to mark 'x'\n\
X 'x ... at first non-white in line\n");
X
Xlongline("\n\
X Undo & Redo\n\
X =============\n\
X u undo last change\n\
X U restore current line\n\
X . repeat last change\n");
X
X SHOWHELP( helpkey (3) );
X
X
X/***********************************************************************
X * Fourth Screen: Insert & Replace,
X ***********************************************************************/
X
XScreen4:
X CLS;
X windgoto(helprow = 0, 0);
X
Xlongline("\
X Insert and Replace\n\
X ==================\n\
X a append after cursor\n\
X i insert before cursor\n\
X A append at end of line\n\
X I insert before first non-blank\n");
Xlongline("\
X o open line below\n\
X O open line above\n\
X rx replace single char with 'x'\n\
X R replace characters\n");
Xif (! P(P_TO))
Xlongline("\
X ~ change case (upper/lower) of single char\n");
X
Xlongline("\
X\n\
X Words, sentences, paragraphs\n\
X ============================\n\
X w word forward\n\
X b back word\n\
X e end of word\n\
X ) to next sentence\n\
X } to next paragraph\n");
Xlongline("\
X ( back sentence\n\
X { back paragraph\n\
X W blank delimited word\n\
X B back W\n\
X E to end of W\n");
X
X SHOWHELP( helpkey (4) );
X
X
X/***********************************************************************
X * Fifth Screen: Operators, Misc. operations, Yank & Put
X ***********************************************************************/
X
XScreen5:
X CLS;
X windgoto(helprow = 0, 0);
X
Xlongline("\
X Operators (double to affect lines)\n\
X ==================================\n\
X d delete\n\
X c change\n");
Xlongline("\
X < left shift\n\
X > right shift\n\
X y yank to buffer\n\
X ! filter lines (command name follows)\n");
Xif (P(P_TO))
Xlongline("\
X ~ reverse case (upper/lower)\n");
X
Xlongline("\n\
X Miscellaneous operations\n\
X ========================\n\
X C change rest of line\n\
X D delete rest of line\n\
X s substitute chars\n");
Xlongline("\
X S substitute lines (not yet)\n\
X J join lines\n\
X x delete characters\n\
X X ... before cursor\n");
X
Xlongline("\n\
X Yank and Put\n\
X ============\n\
X p put back text\n\
X P put before\n\
X Y yank lines");
X
X SHOWHELP( helpkey (5) );
X
X
X/***********************************************************************
X * Sixth Screen: Command-line operations
X ***********************************************************************/
X
XScreen
More information about the Comp.sources.misc
mailing list