1BSD/ex-1.1/ex_cmds.c
#include "ex.h"
#include "ex_glob.h"
#include "ex_tty.h"
/*
* Ex - a text editor
* Bill Joy UCB June-October 1977
*/
char version[];
char CHANGE[] "change";
char PRINT[] "print";
char RECOVER[] "recover";
char PRESERVE[] "preserve";
char READ[] "read";
static char pflag, nflag, kflag;
static int poffset;
int xpand(), tabulate();
commands(noprompt, exitoneof)
int noprompt;
char exitoneof;
{
register int *addr;
register c;
register char *p;
int lchngflag, cnt;
char hadpr;
resetflav();
lchngflag = chngflag;
if (noprompt == -1) {
noprompt = 0;
c = 'e';
if (recov) {
recov = 0;
goto dorecover;
}
goto doecmd;
/* magic! */
}
for (;;) {
shudclob = 0;
if (pflag || lchngflag != chngflag && value(AUTOPRINT) &&
!inglobal && endline) {
pflag = 0;
lchngflag = chngflag;
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;
}
}
if (value(STICKY) == 0)
resetflav();
lchngflag = chngflag;
if (inglobal == 0) {
flush();
if (value(HUSH) == 0 && value(PROMPT) && globp == 0 &&
noprompt == 0 && intty && endline) {
putchar(':');
hadpr = 1;
flush();
}
TSYNC();
}
addr2 = 0;
do {
addr1 = addr2;
addr = address();
c = getchar();
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;
tailspec(c);
switch (c) {
case 'a':
if (peekchar() == 'r') {
tail("args");
setnoaddr();
c = 0;
if (!exclam())
c = xargc0 - xargc;
newline();
for (; c < xargc0; c++)
printf("%6d %s\n", c - (xargc0 - xargc) + 1, xargv0[c]);
continue;
}
tail("append");
setdot();
setai(exclam());
newline();
deletenone();
append(gettty, setin(addr2));
lchngflag = chngflag;
continue;
case 'c':
switch (peekchar()) {
case 'o':
getchar();
if (peekchar() == 'm') {
tail2of("comment");
do
c = getchar();
while (c == '|' || !endcmd(c));
continue;
}
tail2of("Copy");
move();
continue;
case 'd':
tail("cd");
goto changdir;
case 'h':
getchar();
if (peekchar() == 'd') {
tail2of("chdir");
changdir:
#ifdef UNIMP
if (savedfile[0] == '/')
exclam();
else
quickly();
#endif
skipwh();
if (endcmd(peekchar())) {
newline();
p = home;
} else
getone(), p = file;
if (chdir(p) < 0)
filioerr(p);
if (file[0] != '/')
value(EDITED) = 0;
continue;
}
tail2of(CHANGE);
break;
default:
tail(CHANGE);
}
setai(exclam());
setCNL();
setin(addr1);
delete();
append(gettty, addr1 - 1);
lchngflag = chngflag;
continue;
case 'd':
tail("delete");
setCNL();
delete();
appendnone();
continue;
case 'e':
switch (peekchar()) {
case 'x':
getchar();
if (peekchar() == 'p') {
tail2of("expand");
setCNL();
xop(&xpand);
continue;
}
tail2of("ex");
break;
case 'c':
tail("echo");
skipwh();
do {
c = getchar();
switch (c) {
case '|':
putnl();
break;
case '\\':
c = getchar();
default:
putchar(c);
}
} while (!endcmd(c));
continue;
default:
tail("edit");
}
if (!exclam() && chngflag)
c = 'E';
doecmd:
filename(c);
if (c == 'E') {
ungetchar(lastchar());
quickly();
}
setnoaddr();
init();
addr2 = zero;
laste++;
sync();
rop(c);
lchngflag = chngflag;
continue;
case 'f':
tail("file");
setnoaddr();
filename(c);
putnl();
continue;
case 'g':
tail("global");
global(!exclam());
lchngflag = chngflag;
continue;
case 'i':
tail("insert");
setdot();
nonzero();
setai(exclam());
newline();
deletenone();
setin(addr2);
append(gettty, addr2 - 1);
if (dot == zero && dol > zero)
dot = one;
lchngflag = chngflag;
continue;
case 'j':
tail("join");
c = exclam();
setcount();
nonzero();
newline();
if (addr1 == addr2) {
if (addr1 == dol) {
if (dol != one)
error("Illegal $ in join|$join not allowed unless only one line in buffer");
} else
addr2++;
}
join(c);
continue;
case 'k':
casek:
skipwh();
c = getchar();
if (endcmd(c))
error("Mark what?|%s requires following letter", Command);
newline();
if (c != letter(c))
error("Bad mark|Mark must specify a letter");
setdot();
nonzero();
names[c - 'a'] = *addr2 &~ 01;
continue;
case 'm':
if (peekchar() == 'a') {
tail("mark");
goto casek;
}
tail("Move");
move();
continue;
case 'o':
tail("open");
oop();
pflag = 0;
lchngflag = chngflag;
continue;
case '|':
endline = 0;
goto caseline;
case '\n':
endline = 1;
caseline:
notempty();
if (addr2 == 0) {
if (dot == dol)
error("At EOF|At end-of-file");
if (UPLINE && c == '\n' && !inglobal)
c = '\013';
addr2 = dot + 1;
}
addr1 = addr2;
setdot();
nonzero();
getline(*addr1);
if (c == '\013') {
putchar('\013' | QUOTE); /* prototype UPLINE */
if (hadpr)
shudclob = 1;
}
plines(addr1, addr2, 1);
continue;
case 'l':
tail("list");
setCNL();
setlist();
pflag = 0;
goto print;
case ':':
setCNL();
kflag = 1;
setflav();
pflag = 0;
goto print;
case '#':
numberit:
setCNL();
setnumb();
pflag = 0;
goto print;
case 'p':
switch (peekchar()) {
case 'u':
tail("put");
setdot();
eol();
PUT();
continue;
case 'r':
getchar();
if (peekchar() == 'e') {
tail2of(PRESERVE);
eol();
preserve();
continue;
}
tail2of(PRINT);
break;
default:
tail(PRINT);
break;
}
setCNL();
pflag = 0;
print:
nonzero();
if (CLEAR && addr2 - addr1 >= LINES)
putchar('\032' | QUOTE); /* proto */
plines(addr1, addr2, 1);
continue;
case 'n':
if (peekchar() == 'u') {
tail("number");
goto numberit;
}
tail("next");
setnoaddr();
quickly();
if (getargs() == 0) {
ungetchar(lastchar());
return (1);
}
glob(genbuf, G);
xargc0 = gargc;
xargv0 = &G->Ava[0];
rewind();
return (2);
case 'q':
tail("quit");
setnoaddr();
c = quickly();
eol();
if (c)
argc = 0;
return (0);
case 'r':
if (peekchar() == 'e') {
getchar();
switch (peekchar()) {
case 'w':
tail2of("rewind");
setnoaddr();
quickly();
newline();
rewind();
return (2);
case 's':
tail2of("reset");
setNAEOL();
REset();
continue;
case 'c':
tail2of(RECOVER);
setnoaddr();
c = 'e';
if (!exclam() && chngflag)
c = 'E';
dorecover:
filename(c);
if (c == 'E') {
ungetchar(lastchar());
quickly();
}
init();
addr2 = zero;
laste++;
sync();
recover();
rop2();
revocer();
if (status == 0)
rop3(c);
if (dol != zero)
change();
lchngflag = chngflag;
continue;
}
tail2of(READ);
} else
tail(READ);
if (savedfile[0] == 0 && dol == zero)
c = 'e';
filename(c);
rop(c);
lchngflag = chngflag;
continue;
case 's':
switch (peekchar()) {
case 'e':
tail("set");
setnoaddr();
set(skipwh());
continue;
case 'h':
tail("shell");
setNAEOL();
unix2("-i", 0, NIL);
continue;
case 'o':
tail("source");
setnoaddr();
getone();
source(file, 0);
continue;
case 'y':
tail("sync");
setNAEOL();
synctmp();
continue;
}
case '&':
case '~':
Command = "substitute";
if (c == 's')
tail(Command);
if (!substitute(c))
pflag = 0;
continue;
case 't':
if (peekchar() == 'a') {
tail("tabulate");
c = exclam();
setCNL();
xop(&tabulate, c);
continue;
}
tail("Transcribe");
move();
continue;
case 'u':
tail("undo");
setnoaddr();
markDOT();
c = exclam();
newline();
undo(c);
continue;
case 'v':
switch (peekchar()) {
case 'e':
tail("version");
setNAEOL();
printf("%s\n", version);
flush();
continue;
case 'i':
tail("visual");
vop();
pflag = 0;
lchngflag = chngflag;
continue;
}
tail("v");
global(0);
lchngflag = chngflag;
continue;
case 'w':
tail("write");
setall();
wop();
lchngflag = chngflag;
continue;
case 'x':
tail("xpand");
setCNL();
xop(&xpand);
continue;
case 'y':
tail("yank");
setcount();
eol();
yank();
continue;
case 'z':
zop();
pflag = 0;
continue;
case '=':
newline();
setall();
printf("%d\n", addr2 - zero);
continue;
case '!':
unix();
continue;
case '<':
case '>':
for (cnt = 1; peekchar() == c; cnt++)
getchar();
setCNL();
shift(c, cnt);
continue;
case EOF:
/* onhup for chtty !?! */
if (exitoneof || gTTY(0) == -1)
return (0);
if (dol == zero) {
putnl();
notempty();
}
ungetchar(EOF);
zop(hadpr);
continue;
case 'h':
tail("help");
setnoaddr();
helpthem();
continue;
default:
if (!letter(c))
break;
ungetchar(c);
tailof("", 0);
}
error("What?|Unknown command character '%c'", c);
}
}
quickly()
{
if (exclam())
return (1);
if (chngflag) {
chngflag = 0;
xchngflag = 0;
error("No write@since last change");
}
return (0);
}
change()
{
tchngflag++;
chngflag = tchngflag;
}
sync()
{
chngflag = 0;
tchngflag = 0;
xchngflag = 0;
}
plines(adr1, adr2, movedot)
int *adr1;
register int *adr2;
char movedot;
{
register int *addr;
for (addr = adr1; addr <= adr2; addr++) {
getline(*addr);
pline(addr - zero);
if (movedot)
dot = addr;
}
}
int normline();
newline()
{
register c;
resetflav();
for (;;) {
c = getchar();
switch (c) {
case '^':
case '-':
poffset--;
break;
case '+':
poffset++;
break;
case 'l':
listf++;
break;
case ':':
kflag++;
break;
case '#':
nflag++;
break;
case 'p':
listf = 0;
break;
case ' ':
case '\t':
continue;
default:
if (!endcmd(c))
error("Extra chars|Extra characters at end of \"%s\" command", Command);
if (c == EOF)
ungetchar(c);
setflav();
return;
}
pflag++;
}
}
eol()
{
skipwh();
if (!endcmd(getchar()))
error("Extra chars|Extra characters at end of command");
}
resetflav()
{
listf = 0;
kflag = 0;
nflag = 0;
pflag = 0;
poffset = 0;
setflav();
}
int (*Pline)(), normline(), numbline();
setflav()
{
if (nflag || kflag == 0 && value(NUMBER))
setnumb();
else
/* setnonumb(); */
Pline = &normline;
if (listf || kflag == 0 && value(LIST))
setlist();
else
setnorm();
setoutt();
}
endcmd(ch)
{
switch (ch) {
case '\n':
case EOF:
endline = 1;
return (1);
case '|':
endline = 0;
return (1);
}
return (0);
}
tailspec(c)
char c;
{
static char foocmd[2];
foocmd[0] = c;
Command = foocmd;
}
tail(comm)
char *comm;
{
tailof(comm, 1);
return (comm);
}
tail2of(comm)
char *comm;
{
return (tailof(comm, 2));
}
tailof(comm, i)
register char *comm;
int i;
{
register char *cp;
register int c;
char command[20];
Command = comm;
for (cp = command; i > 0; i--)
*cp++ = *comm++;
while (*comm && peekchar() == *comm)
*cp++ = getchar(), comm++;
c = peekchar();
if (letter(c) && c != 'l' && c != 'p') {
do
*cp++ = getchar();
while (cp < &command[19] && letter(peekchar()));
*cp = 0;
error("What?|%s: Not an editor command", command);
}
}
exclam()
{
skipwh();
if (peekchar() == '!') {
getchar();
return (1);
}
return (0);
}