From 9a067bbc530b5cc223c3931492ac7dd29e6e351d Mon Sep 17 00:00:00 2001 From: Bill Joy Date: Tue, 8 May 1979 23:18:22 -0800 Subject: [PATCH] BSD 2 development Work on file src/ex/ex_cmds.c Work on file src/ex/ex_cmds2.c Synthesized-from: 2bsd --- src/ex/ex_cmds.c | 716 ++++++++++++++++++++++++++++++++++++++++++++++ src/ex/ex_cmds2.c | 491 +++++++++++++++++++++++++++++++ 2 files changed, 1207 insertions(+) create mode 100644 src/ex/ex_cmds.c create mode 100644 src/ex/ex_cmds2.c diff --git a/src/ex/ex_cmds.c b/src/ex/ex_cmds.c new file mode 100644 index 0000000000..ec9665eed0 --- /dev/null +++ b/src/ex/ex_cmds.c @@ -0,0 +1,716 @@ +/* Copyright (c) 1979 Regents of the University of California */ +#include "ex.h" +#include "ex_argv.h" +#include "ex_temp.h" +#include "ex_tty.h" + +bool pflag, nflag; +int poffset; + +#define nochng() lchng = chng + +/* + * Main loop for command mode command decoding. + * A few commands are executed here, but main function + * is to strip command addresses, do a little address oriented + * processing and call command routines to do the real work. + */ +commands(noprompt, exitoneof) + bool noprompt, exitoneof; +{ + register line *addr; + register int c; + register int lchng; + int cnt; + bool hadpr; + + resetflav(); + nochng(); + for (;;) { + /* + * If dot at last command + * ended up at zero, advance to one if there is a such. + */ + if (dot <= zero) { + dot = zero; + if (dol > zero) + dot = one; + } + shudclob = 0; + + /* + * If autoprint or trailing print flags, + * print the line at the specified offset + * before the next command. + */ + if (pflag || lchng != chng && value(AUTOPRINT) && !inglobal && !inopen && endline) { + pflag = 0; + nochng(); + if (dol != zero) { + addr1 = addr2 = dot + poffset; + if (addr1 < one || addr1 > dol) + error("Offset out-of-bounds|Offset after command too large"); + setdot1(); + goto print; + } + } + nochng(); + + /* + * Print prompt if appropriate. + * If not in global flush output first to prevent + * going into pfast mode unreasonably. + */ + if (inglobal == 0) { + flush(); + if (hush == 0 && value(PROMPT) && globp == 0 && noprompt == 0 && intty && endline) { + putchar(':'); + hadpr = 1; + } + TSYNC(); + } + + /* + * Gobble up the address. + * Degenerate addresses yield ".". + */ + addr2 = 0; + do { + addr1 = addr2; + addr = address(); + c = getcd(); + if (addr == 0) + if (c == ',') + addr = dot; + else if (addr1 != 0) { + addr2 = dot; + break; + } else + break; + addr2 = addr; + if (c == ';') { + c = ','; + dot = addr; + } + } while (c == ','); + if (addr1 == 0) + addr1 = addr2; + if (c == ':') + c = getchar(); + + /* + * Set command name for special character commands. + */ + tailspec(c); + + /* + * If called via : escape from open or visual, limit + * the set of available commands here to save work below. + */ + if (inopen) { + if (c=='\n' || c=='\r' || c==CTRL(d) || c==EOF) { + if (addr2) + dot = addr2; + if (c == EOF) + return; + continue; + } + if (any(c, "o")) +notinvis: + tailprim(Command, 1, 1); + } + switch (c) { + + case 'a': + + if (peekchar() == 'r') { +/* args */ + tail("args"); + setnoaddr(); + eol(); + pargs(); + continue; + } + +/* append */ + if (inopen) + goto notinvis; + tail("append"); + setdot(); + aiflag = exclam(); + newline(); + deletenone(); + setin(addr2); + ignore(append(gettty, addr2)); + nochng(); + continue; + + case 'c': + switch (peekchar()) { + +/* copy */ + case 'o': + if (inopen) + goto notinvis; + tail("copy"); + move(); + continue; + +#ifdef CHDIR +/* cd */ + case 'd': + tail("cd"); + goto changdir; + +/* chdir */ + case 'h': + ignchar(); + if (peekchar() == 'd') { + register char *p; + tail2of("chdir"); +changdir: + if (savedfile[0] == '/' || !value(WARN)) + ignore(exclam()); + else + ignore(quickly()); + if (skipend()) { + p = getenv("HOME"); + if (p == NULL) + error("Home directory unknown"); + } else + getone(), p = file; + eol(); + if (chdir(p) < 0) + filioerr(p); + if (savedfile[0] != '/') + edited = 0; + continue; + } + if (inopen) + tailprim("change", 2, 1); + tail2of("change"); + break; + +#endif + default: + if (inopen) + goto notinvis; + tail("change"); + break; + } +/* change */ + aiflag = exclam(); + setCNL(); + setin(addr1); + delete(0); + ignore(append(gettty, addr1 - 1)); + nochng(); + continue; + +/* delete */ + case 'd': + tail("delete"); + c = cmdreg(); + setCNL(); + if (c) + YANKreg(c); + delete(0); + appendnone(); + continue; + +/* edit */ +/* ex */ + case 'e': + tail(peekchar() == 'x' ? "ex" : "edit"); + if (!exclam() && chng) + c = 'E'; + filename(c); + if (c == 'E') { + ungetchar(lastchar()); + ignore(quickly()); + } + setnoaddr(); +doecmd: + init(); + addr2 = zero; + laste++; + sync(); + rop(c); + nochng(); + continue; + +/* file */ + case 'f': + tail("file"); + setnoaddr(); + filename(c); + noonl(); + synctmp(); + continue; + +/* global */ + case 'g': + tail("global"); + global(!exclam()); + nochng(); + continue; + +/* insert */ + case 'i': + if (inopen) + goto notinvis; + tail("insert"); + setdot(); + nonzero(); + aiflag = exclam(); + newline(); + deletenone(); + setin(addr2); + ignore(append(gettty, addr2 - 1)); + if (dot == zero && dol > zero) + dot = one; + nochng(); + continue; + +/* join */ + case 'j': + tail("join"); + c = exclam(); + setcount(); + nonzero(); + newline(); + if (addr1 == addr2 && addr2 != dol) + addr2++; + join(c); + continue; + +/* k */ + case 'k': +casek: + pastwh(); + c = getchar(); + if (endcmd(c)) + serror("Mark what?|%s requires following letter", Command); + newline(); + if (!islower(c)) + error("Bad mark|Mark must specify a letter"); + setdot(); + nonzero(); + names[c - 'a'] = *addr2 &~ 01; + anymarks = 1; + continue; + +/* list */ + case 'l': + tail("list"); + setCNL(); + ignorf(setlist(1)); + pflag = 0; + goto print; + + case 'm': + if (peekchar() == 'a') { +/* mark */ + tail("mark"); + goto casek; + } +/* move */ + tail("move"); + move(); + continue; + + case 'n': + if (peekchar() == 'u') { + tail("number"); + goto numberit; + } +/* next */ + tail("next"); + setnoaddr(); + ignore(quickly()); + if (getargs()) + makargs(); + next(); + c = 'e'; + filename(c); + goto doecmd; + +/* open */ + case 'o': + tail("open"); + oop(); + pflag = 0; + nochng(); + continue; + + case 'p': + switch (peekchar()) { + +/* put */ + case 'u': + tail("put"); + setdot(); + c = cmdreg(); + eol(); + if (c) + putreg(c); + else + put(); + continue; + + case 'r': + ignchar(); + if (peekchar() == 'e') { +/* preserve */ + tail2of("preserve"); + eol(); + if (preserve() == 0) + error("Preserve failed!"); + else + error("File preserved."); + } + tail2of("print"); + break; + + default: + tail("print"); + break; + } +/* print */ + setCNL(); + pflag = 0; +print: + nonzero(); + if (CL && span() > LINES) { + flush1(); + vclear(); + } + plines(addr1, addr2, 1); + continue; + +/* quit */ + case 'q': + tail("quit"); + setnoaddr(); + c = quickly(); + eol(); + if (!c) +quit: + nomore(); + if (inopen) { + vgoto(WECHO, 0); + if (!ateopr()) + vnfl(); + flush(); + setty(normf); + } + cleanup(1); + exit(0); + + case 'r': + if (peekchar() == 'e') { + ignchar(); + switch (peekchar()) { + +/* rewind */ + case 'w': + tail2of("rewind"); + setnoaddr(); + ignore(quickly()); + eol(); + erewind(); + next(); + c = 'e'; + ungetchar(lastchar()); + filename(c); + goto doecmd; + +/* recover */ + case 'c': + tail2of("recover"); + setnoaddr(); + c = 'e'; + if (!exclam() && chng) + c = 'E'; + filename(c); + if (c == 'E') { + ungetchar(lastchar()); + ignore(quickly()); + } + init(); + addr2 = zero; + laste++; + sync(); + recover(); + rop2(); + revocer(); + if (status == 0) + rop3(c); + if (dol != zero) + change(); + nochng(); + continue; + } + tail2of("read"); + } else + tail("read"); +/* read */ + if (savedfile[0] == 0 && dol == zero) + c = 'e'; + pastwh(); + if (peekchar() == '!') { + setdot(); + ignchar(); + unix0(0); + filter(0); + continue; + } + filename(c); + rop(c); + nochng(); + if (inopen && endline && addr1 > zero && addr1 < dol) + dot = addr1 + 1; + continue; + + case 's': + switch (peekchar()) { + +/* set */ + case 'e': + tail("set"); + setnoaddr(); + set(); + continue; + +/* shell */ + case 'h': + tail("shell"); + setNAEOL(); + vnfl(); + unixwt(1, unixex("-i", (char *) 0, 0, 0)); + vcontin(0); + continue; + +/* source */ + case 'o': + if (inopen) + goto notinvis; + tail("source"); + setnoaddr(); + getone(); + eol(); + source(file, 0); + continue; + } + /* fall into ... */ + +/* & */ +/* ~ */ +/* substitute */ + case '&': + case '~': + Command = "substitute"; + if (c == 's') + tail(Command); + if (!substitute(c)) + pflag = 0; + continue; + +/* t */ + case 't': + if (peekchar() == 'a') { + tail("tag"); + tagfind(exclam()); + if (!inopen) + lchng = chng - 1; + else + nochng(); + continue; + } + tail("t"); + move(); + continue; + +/* undo */ + case 'u': + tail("undo"); + setnoaddr(); + markDOT(); + c = exclam(); + newline(); + undo(c); + continue; + + case 'v': + switch (peekchar()) { + + case 'e': +/* version */ + tail("version"); + setNAEOL(); + /* should use SCCS subst here */ + printf("Version 2.2, May 6, 1979"); + noonl(); + continue; + +/* visual */ + case 'i': + tail("visual"); + vop(); + pflag = 0; + nochng(); + continue; + } +/* v */ + tail("v"); + global(0); + nochng(); + continue; + +/* write */ + case 'w': + c = peekchar(); + tail(c == 'q' ? "wq" : "write"); + if (skipwh() && peekchar() == '!') { + ignchar(); + setall(); + unix0(0); + filter(1); + } else { + setall(); + wop(); + nochng(); + } + if (c == 'q') + goto quit; + continue; + +/* yank */ + case 'y': + tail("yank"); + c = cmdreg(); + setcount(); + eol(); + if (c) + YANKreg(c); + else + yank(); + continue; + +/* z */ + case 'z': + zop(0); + pflag = 0; + continue; + +/* | */ + case '|': + endline = 0; + goto caseline; + +/* \n */ + case '\n': + endline = 1; +caseline: + notempty(); + if (addr2 == 0) { + if (dot == dol) + error("At EOF|At end-of-file"); + if (UP != NOSTR && c == '\n' && !inglobal) + c = CTRL(k); + addr2 = dot + 1; + } + addr1 = addr2; + setdot(); + nonzero(); + getline(*addr1); + if (c == CTRL(k)) { + flush1(); + destline--; + if (hadpr) + shudclob = 1; + } + plines(addr1, addr2, 1); + continue; + +/* # */ + case '#': +numberit: + setCNL(); + ignorf(setnumb(1)); + pflag = 0; + goto print; + +/* = */ + case '=': + newline(); + setall(); + printf("%d", lineno(addr2)); + noonl(); + continue; + +/* ! */ + case '!': + if (addr2 != 0) { + unix0(0); + setdot(); + filter(2); + } else { + unix0(1); + vnfl(); + unixwt(1, unixex("-c", uxb, 0, 0)); + vcontin(1); + } + continue; + +/* < */ +/* > */ + case '<': + case '>': + for (cnt = 1; peekchar() == c; cnt++) + ignchar(); + setCNL(); + shift(c, cnt); + continue; + +/* ^D */ +/* EOF */ + case CTRL(d): + case EOF: + if (exitoneof) { + if (addr2 != 0) + dot = addr2; + return; + } + if (!isatty(0)) { + if (intty) + /* + * Chtty sys call at UCB may cause a + * input which was a tty to suddenly be + * turned into /dev/null. + */ + onhup(); + return; + } + if (addr2 != 0) { + setlastchar('\n'); + putnl(); + } + if (dol == zero) { + if (addr2 == 0) + putnl(); + notempty(); + } + ungetchar(EOF); + zop(hadpr); + continue; + + default: + if (!isalpha(c)) + break; + ungetchar(c); + tailprim("", 0, 0); + } + error("What?|Unknown command character '%c'", c); + } +} diff --git a/src/ex/ex_cmds2.c b/src/ex/ex_cmds2.c new file mode 100644 index 0000000000..c290244cb0 --- /dev/null +++ b/src/ex/ex_cmds2.c @@ -0,0 +1,491 @@ +/* Copyright (c) 1979 Regents of the University of California */ +#include "ex.h" +#include "ex_argv.h" +#include "ex_temp.h" +#include "ex_tty.h" +#include "ex_vis.h" + +bool pflag, nflag; +int poffset; + +/* + * Subroutines for major command loop. + */ + +/* + * Is there a single letter indicating a named buffer next? + */ +cmdreg() +{ + register int c = 0; + + pastwh(); + if (isalpha(peekchar())) + c = getchar(); + return (c); +} + +/* + * Tell whether the character ends a command + */ +endcmd(ch) + int ch; +{ + switch (ch) { + + case '\n': + case EOF: + endline = 1; + return (1); + + case '|': + endline = 0; + return (1); + } + return (0); +} + +/* + * Insist on the end of the command. + */ +eol() +{ + + if (!skipend()) + error("Extra chars|Extra characters at end of command"); + ignnEOF(); +} + +/* + * Print out the message in the error message file at str, + * with i an integer argument to printf. + */ +/*VARARGS2*/ +error(str, i) +#ifdef lint + register char *str; +#else + register int str; +#endif + int i; +{ + + error0(); + merror(str, i); + error1(str); +} + +/* + * Rewind the argument list. + */ +erewind() +{ + + argc = argc0; + argv = argv0; + args = args0; + if (argc > 1 && !hush) { + printf(mesg("%d files@to edit"), argc); + if (inopen) + putchar(' '); + else + putNFL(); + } +} + +/* + * Guts of the pre-printing error processing. + * If in visual and catching errors, then we dont mung up the internals, + * just fixing up the echo area for the print. + * Otherwise we reset a number of externals, and discard unused input. + */ +error0() +{ + + intag = 0; + if (vcatch) { + if (splitw == 0) + fixech(); + if (!SO || !SE) + dingdong(); + return; + } + if (input) { + input = strend(input) - 1; + if (*input == '\n') + setlastchar('\n'); + input = 0; + } + setoutt(); + flush(); + resetflav(); + if (laste) { + laste = 0; + sync(); + } + if (!SO || !SE) + dingdong(); + if (inopen) { + /* + * We are coming out of open/visual ungracefully. + * Restore COLUMNS, undo, and fix tty mode. + */ + COLUMNS = OCOLUMNS; + undvis(); + ostop(normf); + putpad(VE); + putnl(); + } + inopen = 0; + holdcm = 0; +} + +/* + * Post error printing processing. + * Close the i/o file if left open. + * If catching in visual then throw to the visual catch, + * else if a child after a fork, then exit. + * Otherwise, in the normal command mode error case, + * finish state reset, and throw to top. + */ +error1(str) + char *str; +{ + + if (io > 0) { + close(io); + io = -1; + } + if (vcatch && !die) { + inglobal = 0; + inopen = 1; + vcatch = 0; + fixol(); + longjmp(vreslab); + } + if (str) + putNFL(); + if (die) + exit(1); + lseek(0, 0L, 2); + if (inglobal) + setlastchar('\n'); + inglobal = 0; + globp = 0; + while (lastchar() != '\n' && lastchar() != EOF) + ignchar(); + ungetchar(0); + endline = 1; + reset(); +} + +fixol() +{ + if (Outchar != vputchar) { + flush(); + if (state == ONEOPEN || state == HARDOPEN) + outline = destline = 0; + Outchar = vputchar; + vcontin(1); + } else { + if (destcol) + vclreol(); + vclean(); + } +} + +/* + * Does an ! character follow in the command stream? + */ +exclam() +{ + + if (peekchar() == '!') { + ignchar(); + return (1); + } + return (0); +} + +/* + * Make an argument list for e.g. next. + */ +makargs() +{ + + glob(&frob); + argc0 = frob.argc0; + argv0 = frob.argv; + args0 = argv0[0]; + erewind(); +} + +/* + * Advance to next file in argument list. + */ +next() +{ + + if (argc == 0) + error("No more files@to edit"); + morargc = argc; + if (savedfile[0]) + CP(altfile, savedfile); + CP(savedfile, args); + argc--; + args = argv ? *++argv : strend(args) + 1; +} + +/* + * Eat trailing flags and offsets after a command, + * saving for possible later post-command prints. + */ +newline() +{ + register int c; + + resetflav(); + for (;;) { + c = getchar(); + switch (c) { + + case '^': + case '-': + poffset--; + break; + + case '+': + poffset++; + break; + + case 'l': + listf++; + break; + + case '#': + nflag++; + break; + + case 'p': + listf = 0; + break; + + case ' ': + case '\t': + continue; + + default: + if (!endcmd(c)) + serror("Extra chars|Extra characters at end of \"%s\" command", Command); + if (c == EOF) + ungetchar(c); + setflav(); + return; + } + pflag++; + } +} + +/* + * Before quit or respec of arg list, check that there are + * no more files in the arg list. + */ +nomore() +{ + + if (argc == 0 || morargc == argc) + return; + morargc = argc; + merror("%d more file", argc); + serror("%s@to edit", plural((long) argc)); +} + +/* + * Before edit of new file check that either an ! follows + * or the file has not been changed. + */ +quickly() +{ + + if (exclam()) + return (1); + if (chng) { +/* + chng = 0; +*/ + xchng = 0; + error("No write@since last change (%s! overrides)", Command); + } + return (0); +} + +/* + * Reset the flavor of the output to print mode with no numbering. + */ +resetflav() +{ + + if (inopen) + return; + listf = 0; + nflag = 0; + pflag = 0; + poffset = 0; + setflav(); +} + +/* + * Print an error message with a %s type argument to printf. + * Message text comes from error message file. + */ +serror(str, cp) +#ifdef lint + register char *str; +#else + register int str; +#endif + char *cp; +{ + + error0(); + smerror(str, cp); + error1(str); +} + +/* + * Set the flavor of the output based on the flags given + * and the number and list options to either number or not number lines + * and either use normally decoded (ARPAnet standard) characters or list mode, + * where end of lines are marked and tabs print as ^I. + */ +setflav() +{ + + if (inopen) + return; + setnumb(nflag || value(NUMBER)); + setlist(listf || value(LIST)); + setoutt(); +} + +/* + * Skip white space and tell whether command ends then. + */ +skipend() +{ + + pastwh(); + return (endcmd(peekchar())); +} + +/* + * Set the command name for non-word commands. + */ +tailspec(c) + int c; +{ + static char foocmd[2]; + + foocmd[0] = c; + Command = foocmd; +} + +/* + * Try to read off the rest of the command word. + * If alphabetics follow, then this is not the command we seek. + */ +tail(comm) + char *comm; +{ + + tailprim(comm, 1, 0); +} + +tail2of(comm) + char *comm; +{ + + tailprim(comm, 2, 0); +} + +char tcommand[20]; + +tailprim(comm, i, notinvis) + register char *comm; + int i; + bool notinvis; +{ + register char *cp; + register int c; + + Command = comm; + for (cp = tcommand; i > 0; i--) + *cp++ = *comm++; + while (*comm && peekchar() == *comm) + *cp++ = getchar(), comm++; + c = peekchar(); + if (notinvis || isalpha(c)) { + /* + * Of the trailing lp funny buisness, only dl and dp + * survive the move from ed to ex. + */ + if (tcommand[0] == 'd' && any(c, "lp")) + goto ret; + while (cp < &tcommand[19] && isalpha(peekchar())) + *cp++ = getchar(); + *cp = 0; + if (notinvis) + serror("What?|%s: No such command from open/visual", tcommand); + else + serror("What?|%s: Not an editor command", tcommand); + } +ret: + *cp = 0; +} + +/* + * Continue after a shell escape from open/visual. + */ +vcontin(ask) + bool ask; +{ + + if (vcnt > 0) + vcnt = -vcnt; + if (inopen) { + if (state != VISUAL) { +/* + vtube[WECHO][0] = '*'; + vnfl(); +*/ + return; + } + if (ask) { + merror("[Hit return to continue] "); + flush(); + } +#ifdef V6 + vraw(); +#endif + if (ask && getkey() == ':') + ungetkey(':'); + } +} + +/* + * Put out a newline (before a shell escape) + * if in open/visual. + */ +vnfl() +{ + + if (inopen) { + if (state != VISUAL && state != CRTOPEN && destline <= WECHO) + vclean(); + else + vmoveitup(1); + vgoto(WECHO, 0); + vclrbyte(vtube[WECHO], WCOLS); + flush(); + } +} -- 2.20.1