#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'stevie/cmdline.c' <<'END_OF_FILE' 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 (vi_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} END_OF_FILE if test 11790 -ne `wc -c <'stevie/cmdline.c'`; then echo shar: \"'stevie/cmdline.c'\" unpacked with wrong size! fi # end of 'stevie/cmdline.c' fi if test -f 'stevie/misccmds.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stevie/misccmds.c'\" else echo shar: Extracting \"'stevie/misccmds.c'\" \(9492 characters\) sed "s/^X//" >'stevie/misccmds.c' <<'END_OF_FILE' X/* $Header: /nw/tony/src/stevie/src/RCS/misccmds.c,v 1.14 89/08/06 09:50:17 tony Exp $ X * X * Various routines to perform specific editing operations or return X * useful information about the file. X */ X X#include "stevie.h" X Xstatic void openfwd(), openbwd(); X Xextern bool_t did_ai; X X/* X * opencmd X * X * Add a blank line above or below the current line. X */ X Xvoid Xopencmd(dir, can_ai) Xint dir; Xint can_ai; /* if true, consider auto-indent */ X{ X if (dir == FORWARD) X openfwd(can_ai); X else X openbwd(can_ai); X} X Xstatic void Xopenfwd(can_ai) Xint can_ai; X{ X register LINE *l; X LPTR *next; X register char *s; /* string to be moved to new line, if any */ X int newindex = 0; /* index of the cursor on the new line */ X X /* X * If we're in insert mode, we need to move the remainder of the X * current line onto the new line. Otherwise the new line is left X * blank. X */ X if (State == INSERT || State == REPLACE) X s = &Curschar->linep->s[Curschar->index]; X else X s = ""; X X if ((next = nextline(Curschar)) == NULL) /* open on last line */ X next = Fileend; X X /* X * By asking for as much space as the prior line had we make sure X * that we'll have enough space for any auto-indenting. X */ X if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) X return; X X if (*s != NUL) X strcpy(l->s, s); /* copy string to new line */ X X else if (can_ai && P(P_AI) && !anyinput()) { X char *p; X X /* X * Copy prior line, and truncate after white space X */ X strcpy(l->s, Curschar->linep->s); X X for (p = l->s; *p == ' ' || *p == TAB ;p++) X ; X *p = NUL; X newindex = p - l->s; X X /* X * If we just did an auto-indent, then we didn't type X * anything on the prior line, and it should be truncated. X */ X if (did_ai) X Curschar->linep->s[0] = NUL; X X did_ai = TRUE; X } X X /* truncate current line at cursor */ X if (State == INSERT || State == REPLACE) X *s = NUL; X X X Curschar->linep->next = l; /* link neighbors to new line */ X next->linep->prev = l; X X l->prev = Curschar->linep; /* link new line to neighbors */ X l->next = next->linep; X X if (next == Fileend) /* new line at end */ X l->num = Curschar->linep->num + LINEINC; X X else if ((l->prev->num) + 1 == l->next->num) /* no gap, renumber */ X renum(); X X else { /* stick it in the middle */ X unsigned long lnum; X lnum = ((long)l->prev->num + (long)l->next->num) / 2; X l->num = lnum; X } X X /* X * Get the cursor to the start of the line, so that 'Cursrow' X * gets set to the right physical line number for the stuff X * that follows... X */ X Curschar->index = 0; X cursupdate(); X X /* X * If we're doing an open on the last logical line, then X * go ahead and scroll the screen up. Otherwise, just insert X * a blank line at the right place. We use calls to plines() X * in case the cursor is resting on a long line. X */ X if (Cursrow + plines(Curschar) == (Rows - 1)) X scrollup(1); X else X s_ins(Cursrow+plines(Curschar), 1); X X *Curschar = *nextline(Curschar); /* cursor moves down */ X Curschar->index = newindex; X X updatescreen(); /* because Botchar is now invalid... */ X X cursupdate(); /* update Cursrow before insert */ X} X Xstatic void Xopenbwd(can_ai) Xint can_ai; X{ X register LINE *l; X LINE *prev; X int newindex = 0; X X prev = Curschar->linep->prev; X X if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) X return; X X Curschar->linep->prev = l; /* link neighbors to new line */ X prev->next = l; X X l->next = Curschar->linep; /* link new line to neighbors */ X l->prev = prev; X X if (can_ai && P(P_AI) && !anyinput()) { X char *p; X X /* X * Copy current line, and truncate after white space X */ X strcpy(l->s, Curschar->linep->s); X X for (p = l->s; *p == ' ' || *p == TAB ;p++) X ; X *p = NUL; X newindex = p - l->s; X X did_ai = TRUE; X } X X Curschar->linep = Curschar->linep->prev; X Curschar->index = newindex; X X if (prev == Filetop->linep) /* new start of file */ X Filemem->linep = l; X X renum(); /* keep it simple - we don't do this often */ X X cursupdate(); /* update Cursrow before insert */ X if (Cursrow != 0) X s_ins(Cursrow, 1); /* insert a physical line */ X X updatescreen(); X} X Xint Xcntllines(pbegin,pend) Xregister LPTR *pbegin, *pend; X{ X register LINE *lp; X int lnum = 1; X X for (lp = pbegin->linep; lp != pend->linep ;lp = lp->next) X lnum++; X X return(lnum); X} X X/* X * plines(p) - return the number of physical screen lines taken by line 'p' X */ Xint Xplines(p) XLPTR *p; X{ X register int col = 0; X register char *s; X X s = p->linep->s; X X if (*s == NUL) /* empty line */ X return 1; X X for (; *s != NUL ;s++) { X if ( *s == TAB && !P(P_LS)) X col += P(P_TS) - (col % P(P_TS)); X else X col += chars[(unsigned)(*s & 0xff)].ch_size; X } X X /* X * If list mode is on, then the '$' at the end of X * the line takes up one extra column. X */ X if (P(P_LS)) X col += 1; X /* X * If 'number' mode is on, add another 8. X */ X if (P(P_NU)) X col += 8; X X return ((col + (Columns-1)) / Columns); X} X Xvoid Xfileinfo() X{ X extern int numfiles, curfile; X register long l1, l2; X X if (bufempty()) { X l1 = 0; X l2 = 1; /* don't div by zero */ X } else { X l1 = cntllines(Filemem, Curschar); X l2 = cntllines(Filemem, Fileend) - 1; X } X X if (numfiles > 1) X smsg("\"%s\"%s line %ld of %ld -- %ld %% -- (file %d of %d)", X (Filename != NULL) ? Filename : "No File", X Changed ? " [Modified]" : "", X l1, l2, (l1 * 100)/l2, X curfile+1, numfiles); X else X smsg("\"%s\"%s line %ld of %ld -- %ld %% --", X (Filename != NULL) ? Filename : "No File", X Changed ? " [Modified]" : "", X l1, l2, (l1 * 100)/l2); X} X X/* X * gotoline(n) - return a pointer to line 'n' X * X * Returns a pointer to the last line of the file if n is zero, or X * beyond the end of the file. X */ XLPTR * Xgotoline(n) Xregister int n; X{ X static LPTR l; X X l.index = 0; X X if ( n == 0 ) X l = *prevline(Fileend); X else { X LPTR *p; X X for (l = *Filemem; --n > 0 ;l = *p) X if ((p = nextline(&l)) == NULL) X break; X } X return &l; X} X Xvoid Xinschar(c) Xint c; X{ X register char *p, *pend; X X /* make room for the new char. */ X if ( ! canincrease(1) ) X return; X X if (State != REPLACE) { X p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1]; X pend = &Curschar->linep->s[Curschar->index]; X X for (; p > pend ;p--) X *p = *(p-1); X X *p = c; X X } else { /* replace mode */ X /* X * Once we reach the end of the line, we are effectively X * inserting new text, so make sure the string terminator X * stays out there. X */ X if (gchar(Curschar) == NUL) X Curschar->linep->s[Curschar->index+1] = NUL; X pchar(Curschar, c); X } X X /* X * If we're in insert mode and showmatch mode is set, then X * check for right parens and braces. If there isn't a match, X * then beep. If there is a match AND it's on the screen, then X * flash to it briefly. If it isn't on the screen, don't do anything. X */ X if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) { X LPTR *lpos, csave; X X if ((lpos = showmatch()) == NULL) /* no match, so beep */ X beep(); X else if (LINEOF(lpos) >= LINEOF(Topchar)) { X updatescreen(); /* show the new char first */ X csave = *Curschar; X *Curschar = *lpos; /* move to matching char */ X cursupdate(); X windgoto(Cursrow, Curscol); X pause(); /* brief pause */ X *Curschar = csave; /* restore cursor position */ X cursupdate(); X } X } X X inc(Curschar); X CHANGED; X} X Xbool_t Xdelchar(fixpos) Xbool_t fixpos; /* if TRUE, fix the cursor position when done */ X{ X register int i; X X /* Check for degenerate case; there's nothing in the file. */ X if (bufempty()) X return FALSE; X X if (lineempty()) /* can't do anything */ X return FALSE; X X /* Delete the char. at Curschar by shifting everything */ X /* in the line down. */ X for ( i=Curschar->index+1; i < Curschar->linep->size ;i++) X Curschar->linep->s[i-1] = Curschar->linep->s[i]; X X /* If we just took off the last character of a non-blank line, */ X /* we don't want to end up positioned at the newline. */ X if (fixpos) { X if (gchar(Curschar)==NUL && Curschar->index>0 && State!=INSERT) X Curschar->index--; X } X CHANGED; X X return TRUE; X} X X Xvoid Xdelline(nlines, can_update) Xint nlines; Xbool_t can_update; X{ X register LINE *p, *q; X int doscreen; /* if true, update the screen */ X X doscreen = can_update; X /* X * There's no point in keeping the screen updated if we're X * deleting more than a screen's worth of lines. X */ X if (nlines > (Rows - 1) && can_update) { X doscreen = FALSE; X s_del(Cursrow, Rows-1); /* flaky way to clear rest of screen */ X } X X while ( nlines-- > 0 ) { X X if (bufempty()) /* nothing to delete */ X break; X X if (buf1line()) { /* just clear the line */ X Curschar->linep->s[0] = NUL; X Curschar->index = 0; X break; X } X X p = Curschar->linep->prev; X q = Curschar->linep->next; X X if (p == Filetop->linep) { /* first line of file so... */ X Filemem->linep = q; /* adjust start of file */ X Topchar->linep = q; /* and screen */ X } X p->next = q; X q->prev = p; X X clrmark(Curschar->linep); /* clear marks for the line */ X X /* X * Delete the correct number of physical lines on the screen X */ X if (doscreen) X s_del(Cursrow, plines(Curschar)); X X /* X * If deleting the top line on the screen, adjust Topchar X */ X if (Topchar->linep == Curschar->linep) X Topchar->linep = q; X X free(Curschar->linep->s); X free((char *) Curschar->linep); X X Curschar->linep = q; X Curschar->index = 0; /* is this right? */ X CHANGED; X X /* If we delete the last line in the file, back up */ X if ( Curschar->linep == Fileend->linep) { X Curschar->linep = Curschar->linep->prev; X /* and don't try to delete any more lines */ X break; X } X } X} END_OF_FILE if test 9492 -ne `wc -c <'stevie/misccmds.c'`; then echo shar: \"'stevie/misccmds.c'\" unpacked with wrong size! fi # end of 'stevie/misccmds.c' fi if test -f 'stevie/unix.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stevie/unix.c'\" else echo shar: Extracting \"'stevie/unix.c'\" \(12229 characters\) sed "s/^X//" >'stevie/unix.c' <<'END_OF_FILE' X/* $Header: /nw/tony/src/stevie/src/RCS/unix.c,v 1.8 89/08/06 09:51:13 tony Exp $ X * X * System-dependent routines for UNIX System V or Berkeley (BSD). X * Also VxWorks 4.0.2 real-time system. X */ X X#include "stevie.h" X#include "term.h" X X#ifdef VxWorks X# include X# include X#else X# ifdef BSD X# include X# else X# include X# endif X# include X#endif X X#include X X#ifdef TERMCAP Xshort ospeed = 9600; /* baud rate for tputs (termlib) */ Xchar PC = NULL; /* padding character for tputs */ X#endif X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X#ifdef VxWorks X# define TIMEOUT 30 /* number of 1/60ths of a second to wait for cursor X code completion */ X#else X# define TIMEOUT 5 /* number of 1/10ths of a second to wait for cursor X code completion */ X#endif X X int j; /* loop index */ X char c; /* input character */ X char keystr[9]; /* escape sequences/key names */ X int kl; /* escape sequence length */ X int esc_code; /* decoded escape sequence code */ X bool_t part_escape; /* flag: partial escape sequences match */ X char* kn; /* pointer to T_Kx */ X int timeout; /* timeout for waiting for cursor code completion */ X X X got_int = FALSE; X X flushbuf(); /* flush any pending output */ X#ifdef TERMCAP X fflush(stdout); /* tputs uses stdout, so make sure flushed */ X#endif X X do { X while (read(0, &c, 1) != 1) X ; X } while (c == NUL); X X if (c==DEL) { X c=BS; /* always map DEL to backspace */ X } X else if (c=='' && State==NORMAL) { X /* this is control-^ or control-6 on some terminals. It is the same X as :e # */ X stuffin(":e #\n"); X return -1; X } X else if (c==T_KU[0]) { X /* Decode cursor keys T_KU, T_KD, T_KR, T_KL. Assumes they all X start with the same code, typically escape. */ X X keystr[0]=c; X keystr[1]=NULL; X X kl=1; X esc_code=-1; X while (esc_code==-1 && kl<8) { X X timeout=0; X do { X#ifdef VxWorks X while (!kbhit()) { X usleep(16667); /* wait for 1/60th of a second */ X#endif X if (++timeout>TIMEOUT) { X stuffin(keystr); X return -1; X } X#ifdef VxWorks X } X#endif X if (read(0, &c, 1) != 1) X c=NUL; X } while (c == NUL); X X keystr[kl++]=c; X keystr[kl]=NULL; X X part_escape=FALSE; X X for (j=0; j<4; j++) { /* enumerate cursor keys */ X X switch (j) { X case 0: kn=T_KU; break; X case 1: kn=T_KD; break; X case 2: kn=T_KR; break; X case 3: kn=T_KL; break; X default: assert(FALSE); X } X X /* check for match/partial match */ X if (kn[0]!=NULL && strncmp(keystr,kn,kl)==0) { X part_escape=TRUE; X if (strlen(kn)==kl) { X /* complete match */ X esc_code=j; X break; X } X } X } X X if (!part_escape) { X /* no more possibilities for match, so quit */ X break; X } X } X X if (esc_code!=-1) { X /* got valid special key */ X if (State != NORMAL) { X c=ESC; /* not in command mode, so enter it */ X } X else { X switch (esc_code) { X case 0: c=K_UARROW; break; X case 1: c=K_DARROW; break; X case 2: c=K_RARROW; break; X case 3: c=K_LARROW; break; X default: assert(FALSE); X } X } X } X else { X stuffin(keystr); X return -1; X } X } X X return c & 0xff; /* mask because returning an int! */ X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X X#ifdef TERMCAP X/* X * Function to output a character, to be passed to termlib routine tputs(). X */ Xstatic int X_putchar(c) Xchar c; X{ X return (putchar(c)); X} X Xvoid Xflushbuf_pad() X/* X * Uses tputs so that padding specs in termcap get expanded. X * This should be used to output control string sequences extracted from X * termcap, such as cursor motion. X * Important: The padding spec is expanded only if at the beginning of outbuf, X * therefore calling routine must call flushbuf() immediately _before_ X * outputting the termcap control string and flushbuf_pad() immediately after. X * Note that _putchar() uses stdio-buffered I/O, so flushbuf() must as well. X */ X{ X if (bpos > 0) { X outbuf[bpos]=NULL; /* null-terminate */ X tputs(outbuf, 0, _putchar); X } X bpos = 0; X} X#endif X Xvoid Xflushbuf() X{ X if (bpos > 0) { X#ifdef TERMCAP X /* use stdio-buffered I/O because flushbuf_pad() does */ X fwrite(outbuf, 1, bpos, stdout); X#else X write(1, outbuf, bpos); X#endif X } X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = (c) & 0xff; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) Xchar c; X{ X outone(c); X} X Xvoid Xoutstr(s) Xregister char *s; X{ X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X if ( P(P_VB) ) X vbeep (); X else X outone('\007'); X} X X/* X * remove(file) - remove a file X */ Xvoid Xremove(file) Xchar *file; X{ X if (file==NULL || file[0]==NULL) X return; X#ifdef VxWorks X delete(file); X#else X unlink(file); X#endif X} X X/* X * rename(of, nf) - rename existing file 'of' to 'nf' X * This doesn't really care if it succeeds(!) X */ X#ifdef VxWorks Xvoid X_rename(of, nf) Xchar *of, *nf; X{ X STATUS st; X int fd; X X if (of == NULL || of[0]==NULL || nf == NULL || nf[0]==NULL) X return; X X /* try to open 'of' */ X if ((fd = open (of, READ, 0)) < OK) { X /* printf ("can't open: %s\n", of); */ X return; X } X X /* delete any file with same name as 'nf' */ X st=delete(nf); X X /* rename it */ X if (ioctl (fd, FIORENAME, nf) != OK) { X /* printf ("unable to rename file %s to %s\n", of,nf); */ X st = ERROR; X } X else { X st = OK; X } X X close (fd); X return /*(st)*/; X} X X#else /* not VxWorks */ X Xvoid Xrename(of, nf) Xchar *of, *nf; X{ X unlink(nf); X link(of, nf); X unlink(of); X} X X#endif /* VxWorks */ X Xvoid Xpause() X{ X sleep (1); X} X X#ifdef VxWorks Xstatic int ostate = 0; X#else X# ifdef BSD Xstatic struct sgttyb ostate; X# else Xstatic struct termio ostate; X# endif X#endif X X/* X * Go into cbreak mode X */ Xvoid Xset_tty() X{ X#ifdef VxWorks X ostate=ioctl(0,FIOGETOPTIONS,0); X ioctl(0,FIOSETOPTIONS,OPT_CRMOD | OPT_TANDEM | OPT_7_BIT); /* set raw */ X ospeed=13; /* this is the termio/gtty code for 9600 baud, X used by tputs() in the termlib library */ X#else X# ifdef BSD X struct sgttyb nstate; X X ioctl(0, TIOCGETP, &ostate); X ospeed=ostate.ospeed; /* determine baud rate */ X nstate = ostate; X nstate.sg_flags &= ~(XTABS|CRMOD|ECHO); X nstate.sg_flags |= CBREAK; X ioctl(0, TIOCSETN, &nstate); X# else X struct termio nstate; X X ioctl(0, TCGETA, &ostate); X ospeed=ostate.c_cflag & CBAUD; /* determine baud rate */ X nstate = ostate; X nstate.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); X nstate.c_cc[VMIN] = 0; X nstate.c_cc[VTIME] = 1; /* reads time out after 100 ms */ X ioctl(0, TCSETAW, &nstate); X# endif /* BSD */ X#endif /* VxWorks */ X} X X/* X * Restore original terminal modes X */ Xvoid Xreset_tty() X{ X#ifdef VxWorks X ioctl(0,FIOSETOPTIONS,ostate); /* restore */ X#else X# ifdef BSD X ioctl(0, TIOCSETP, &ostate); X# else X ioctl(0, TCSETAW, &ostate); X# endif /* BSD */ X#endif /* VxWorks */ X} X X#ifdef VxWorks XFUNCPTR Xsignal(type, func) Xint type; XFUNCPTR func; X{ X STATUS st; X SIGVEC sv; X SIGVEC svold; X X sv.sv_handler=func; X sv.sv_mask=0; X sv.sv_flags=0; X X st=sigvec(type, &sv, &svold); X if (st==VX_ERROR) X return((FUNCPTR)-1); X X return(svold.sv_handler); X} X#endif X X Xvoid Xsig() X{ X signal(SIGINT, sig); X signal(SIGQUIT, sig); X X got_int = TRUE; X} X Xvoid Xwindinit() X{ X#ifdef TERMCAP X if (t_init() != 1) { X exit(1); X } X#else X Columns = 80; X P(P_LI) = Rows = 24; X#endif X X /* X * The code here makes sure that there isn't a window during which X * we could get interrupted and exit with the tty in a weird state. X */ X signal(SIGINT, sig); X signal(SIGQUIT, sig); X X set_tty(); X X if (got_int) X windexit(0); X} X Xvoid Xwindexit(r) Xint r; X{ X reset_tty(); X exit(r); X} X Xvoid Xwindgoto(r, c) Xregister int r, c; X{ X#ifdef TERMCAP X char *tgoto(); X#else X r += 1; X c += 1; X#endif X X /* X * Check for overflow once, to save time. X */ X if (bpos + 8 >= BSIZE) X flushbuf(); X X#ifdef TERMCAP X flushbuf(); X outstr(tgoto(T_CM, c, r)); X flushbuf_pad(); X#else X outbuf[bpos++] = '\033'; X outbuf[bpos++] = '['; X if (r >= 10) X outbuf[bpos++] = r/10 + '0'; X outbuf[bpos++] = r%10 + '0'; X outbuf[bpos++] = ';'; X if (c >= 10) X outbuf[bpos++] = c/10 + '0'; X outbuf[bpos++] = c%10 + '0'; X outbuf[bpos++] = 'H'; X#endif X} X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X return fopen(fname, mode); X} X Xchar * Xfixname(s) Xchar *s; X{ X return s; X} X X/* X * doshell() - run a command or an interactive shell X */ Xvoid Xdoshell(cmd) Xchar *cmd; X{ X char *getenv(); X char cline[128]; X X#ifdef VxWorks X emsg("Shell access not supported under VxWorks"); X return; X#else X outstr("\r\n"); X flushbuf(); X X if (cmd == NULL) { X if ((cmd = getenv("SHELL")) == NULL) X cmd = "/bin/sh"; X sprintf(cline, "%s -i", cmd); X cmd = cline; X } X X reset_tty(); X system(cmd); X set_tty(); X X wait_return(); X#endif X} X X#ifdef VxWorks X/* X * The strchr() function is identical to index() except it uses int instead X * of char for 'c'. strchr() comes from system V. X */ Xchar* strchr (s,c) Xchar* s; Xint c; X{ X char *index(); X X return index(s,(char)c); X} X#endif X X X/* X * FILL IT IN, FOR YOUR SYSTEM, AND SHARE IT! X * X * The next couple of functions do system-specific stuff. X * They currently do nothing; I'm not familiar enough with X * system-specific programming on this system. X * If you fill it in for your system, please post the results X * and share with the rest of us. X */ X X Xsetcolor (c) X/* X * Set the color to c, using the local system convention for numbering X * colors or video attributes. X * X * If you implement this, remember to note the original color in X * windinit(), before you do any setcolor() commands, and X * do a setcolor() back to the original as part of windexit(). X */ X int c; X{ X /* Dummy routine, just return 0 */ X return (0); X} X X Xsetrows (r) X/* X * Set the number of lines to r, if possible. Otherwise X * "do the right thing". Return the number of lines actually set. X * X * If you implement this, remember to note the original number of rows X * in windinit(), before you do any setrows() commands, and X * do a setrows() back to the original as part of windexit(). X */ X int r; X{ X /* Since we do nothing, just return the current number of lines */ X return ( P(P_LI) ); X} X X Xvbeep () X/* X * Do a "visual bell". This generally consists of flashing the screen X * once in inverse video. X */ X{ X int color, revco; X X color = P( P_CO ); /* get current color */ X revco = reverse_color (color); /* system-specific */ X setcolor (revco); X flushbuf (); X pause (); X setcolor (color); X windgoto (Cursrow, Curscol); X flushbuf (); X} X Xreverse_color (co) X/* X * Returns the inverse video attribute or color of co. X * The existing code below is VERY simple-minded. X * Replace it with proper code for your system. X */ X int co; X{ X if (co) return (0); X else return (1); X} X X X/********** End of do-it-yourself kit **********************/ END_OF_FILE echo shar: 1 control character may be missing from \"'stevie/unix.c'\" if test 12229 -ne `wc -c <'stevie/unix.c'`; then echo shar: \"'stevie/unix.c'\" unpacked with wrong size! fi # end of 'stevie/unix.c' fi echo shar: End of archive 6 \(of 13\). cp /dev/null ark6isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 13 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0