BSD 2 development
[unix-history] / .ref-BSD-1 / ex-1.1 / ex_vmain.c
#include "ex.h"
#ifdef VISUAL
#include "ex_tty.h"
#include "ex_vis.h"
#include "ex_re.h"
/*
* Ex - a text editor
* Bill Joy UCB September 1977
*/
vmain(ic)
char *ic;
{
register int i;
i = Vmain(ic);
flusho();
return (i);
}
int delete(), join(), vshift();
char vscandir[3] "/\n";
static char op;
Vmain(ic)
char *ic;
{
register int c, cnt, i;
char hadcnt, first, *oglobp;
extern char Peekkey, *genindent();
int (*OP)(), ind, vmunddot, *addr;
extern char *loc1;
if (nextic) {
ic = nextic;
nextic = 0;
}
first = 1;
vnline:
if (vundkind != VMANY)
vundkind = VNONE;
getDOT();
vmunddot = *dot;
vmark:
if (vmoving)
wcursor = vfindcol(vmovcol);
else if (first) {
wcursor = ic;
first = 0;
} else
wcursor = vskipwh(ic);
ic = linebuf;
vmove();
for (;;) {
TSYNC();
killglob();
if (digit(peekkey()) && peekkey() != '0') {
hadcnt = 1;
cnt = vgetcnt();
if (cnt <= 0) {
beep();
continue;
}
} else {
Xhadcnt = hadcnt = 0;
Xcnt = cnt = 1;
}
vagain:
op = c = getkey();
if (HSTR && HSTR[0] == c && HSTR[1] == 0)
goto home;
if (UPLINE && UPLINE[0] == c && UPLINE[1] == 0)
goto upline;
switch (c) {
case CTRL(z): /* sync */
if (!visual)
vsync(LINES - 1);
else
vredraw(ZERO);
vfixcurs();
continue;
case CTRL(s):
vsave();
synctmp();
continue;
case ESCAPE: /* cancel command */
beep();
continue;
case '.': /* repeat change */
if (lastcmd[0] == 0) {
beep();
continue;
}
if (hadcnt)
lastcnt = cnt;
cnt = lastcnt;
hadcnt = lasthad;
vglobp = lastcmd;
goto vagain;
#ifdef UNIMP
case 'N':
vglobp = vscandir[0] == '/' ? "?" : "/";
goto vagain;
#endif
case 'n': /* next line matching */
vglobp = vscandir;
goto vagain;
case 'H': /* home cursor */
if (hadcnt) {
beep();
continue;
}
markDOT();
if (vcline == 0) {
c = '^';
break;
}
home:
cnt = vcline;
case '-': /* back up (to first white) */
vmoving = 0;
goto vup;
case 'k': /* up line same column */
upline:
if (vmoving == 0) {
vmoving = 1;
vmovcol = column(cursor);
}
vup:
vsave();
if (cnt > dot - one)
cnt = dot - one;
if (cnt == 0) {
beep();
continue;
}
dot =- cnt;
if (cnt > vcline || !visual) {
vch = '.';
return (1);
}
vcline =- cnt;
goto vnline;
case '\'':
c = getesc();
if (c == 0)
continue;
if (c == '\'')
c = 'a' + 26;
else if (c != letter(c)) {
beep();
continue;
}
for (addr = one; addr <= dol; addr++)
if (names[c-'a'] == (*addr &~ 01))
break;
if (addr > dol) {
beep();
continue;
}
markDOT();
gogo:
vsave();
vch = -1;
getline(*addr);
loc1 = vskipwh(linebuf);
goto it;
case 'G':
if (!hadcnt)
cnt = dol - zero;
if (cnt < 1 || cnt > dol - zero) {
beep();
continue;
}
addr = zero + cnt;
markDOT();
goto gogo;
case 'K':
c = getesc();
if (c == 0)
continue;
if (c != letter(c)) {
beep();
continue;
}
vsave();
names[c-'a'] = (*dot &~ 01);
continue;
case 'L':
cnt = vcnt - vcline - 1;
if (cnt == 0) {
c = '^';
break;
}
markDOT();
goto vdown;
case CTRL(d): /* scroll half-screen */
if (hadcnt)
vSCROLL = cnt;
cnt = vSCROLL;
if (visual) {
ind = vcnt - vcline - 1;
cnt =+ ind;
}
case '+': /* next line, first non-white */
case CR:
vmoving = 0;
goto vdown;
case 'j': /* down line respecting position */
case NL:
if (vmoving == 0) {
vmoving = 1;
vmovcol = column(cursor);
}
vdown:
if (dot == dol) {
beep();
continue;
}
vsave();
if (cnt > dol - dot) {
ind =- cnt - (dol - dot);
if (ind < 0)
ind = 0;
cnt = dol - dot;
}
i = vcnt - vcline - 1;
if (c != CTRL(d) && cnt <= i) {
vcline =+ cnt;
dot =+ cnt;
goto vnline;
}
cnt =- i;
dot =+ i;
vcline =+ i;
if (c != CTRL(d)) {
if (!visual || vfit(cnt, dot) > LINES) {
vch = '.';
dot =+ cnt;
return (1);
}
}
vroll(cnt);
if (c == CTRL(d) && VLINES != LINES) {
vcline =- ind;
dot =- ind;
if (vcline < 0) {
dot =- vcline;
vcline = 0;
}
}
goto vnline;
case 'A':
if (hadcnt) {
beep();
continue;
}
ungetkey('a');
xtrey(c);
c = '$';
break;
case 'I':
if (hadcnt) {
beep();
continue;
}
ungetkey('i');
xtrey(c);
c = '^';
break;
case 'C':
if (hadcnt) {
beep();
continue;
}
xtrey(c);
setwork();
if (*cursor == 0) {
ungetkey('a');
continue;
}
ungetkey('$');
c = 'c';
break;
case 'z': /* context */
case 'v':
if (!visual) {
if (hadcnt) {
beep();
continue;
}
vsave();
ostop();
setoutt();
inopen = 0;
addr2 = dot;
zeq(vlast - 1);
inopen++;
termreset();
Outchar = &vputchar;
ostart();
vholdmove = 1;
vch = '.';
return (1);
}
vsave();
c = getesc();
if (c == 0)
continue;
if (hadcnt) {
markDOT();
addr = zero + cnt;
if (addr < one)
addr = one;
if (addr > dol)
addr = dol;
} else
addr = dot;
switch (c) {
case '.':
case '-':
break;
case '^':
if (addr == one) {
beep();
continue;
}
break;
case '+':
if (addr == dol) {
beep();
continue;
}
c = 0;
break;
case CR:
case NL:
vch = 0;
break;
default:
beep();
continue;
}
vmoving = 0;
vch = c;
dot = addr;
return (1);
case 'Y':
if (!visual && cnt <= TUBELINES)
goto yok;
if (cnt > vcnt - vcline) {
beep();
continue;
}
yok:
vsave();
vyank(cnt);
continue;
}
vmoving = 0;
setwork(c);
switch (c) {
case '\\': /* delete line */
if (vglobp == 0) {
c = getesc();
if (c == 0)
continue;
if (c != '\\') {
beep();
continue;
}
}
if (cnt > vcnt - vcline) {
beep();
continue;
}
vsave();
setLAST();
c = vliny[vcline];
addr = dot;
for (i = 0; i < cnt; i++)
vulines[i] = dot[i];
vyank(cnt);
vresaddr = dot;
vrescnt = cnt;
vdelcnt = 0;
vundkind = VMANY;
vrescurs = cursor;
vremote(cnt, delete);
velide(cnt, vcline);
if (addr > dol)
vcline--;
if (vcnt == 0) {
if (dol == zero)
error("No lines in buffer");
if (!visual) {
vgoto(c, 0);
vputchar('@');
}
vch = '.';
return (1);
}
getDOT();
vscrap();
c = vcline ? vliny[vcline - 1] : ZERO;
if (vcline == vcnt)
vredraw(c);
else
vsync(c);
goto vmark;
case 'J': /* join lines */
if (cnt > TUBELINES || dot == dol ||
hadcnt && cnt == 1) {
beep();
continue;
}
vsave();
setLAST();
if (cnt == 1)
cnt = 2;
if (cnt > dol - dot + 1)
cnt = dol - dot + 1;
vrescnt = cnt;
copy(vulines, dot, cnt * sizeof vulines[0]);
vdelcnt = 1;
vresaddr = dot;
vrescurs = cursor;
vundkind = VMANY;
cursor = strend(linebuf);
vremote(cnt, join);
vsave();
velide(cnt - 1, vcline + 1);
vsyncCL();
if (!*cursor && cursor > linebuf)
cursor--;
vfixcurs();
continue;
#ifdef UNIMP
case '<':
case '>':
if (cnt > vcnt - vcline) {
beep();
continue;
}
vsave();
setLAST();
vrescnt = cnt;
copy(vulines, dot, cnt * sizeof vulines[0]);
vdelcnt = cnt;
vresaddr = dot;
vrescurs = cursor;
vundkind = VMANY;
vremote(cnt, vshift);
dot = vresaddr;
getDOT();
vsyncCL();
vmoving = 0;
goto vmark;
#endif
case 'S': /* replace lines */
if (cnt > vcnt - vcline) {
beep();
continue;
}
vsave();
setLAST();
ind = whitecnt(linebuf);
c = vliny[vcline];
addr = dot;
for (i = 0; i < cnt; i++)
vulines[i] = dot[i];
vyank(cnt);
vresaddr = dot;
vrescnt = cnt;
vundkind = VMANY;
vremote(cnt, delete);
velide(cnt, vcline);
vcline--;
if (addr <= dol)
dot--;
*genindent(ind) = 0;
vdoappend(genbuf);
if (!visual) {
holdat = 1;
vclrlin(c);
holdat = 0;
voinit();
} else {
vcline++;
vopen(dot, c);
vsyncCL();
}
vrescurs = cursor;
vdelcnt = 1;
cursor = linebuf;
linebuf[0] = 0;
vfixcurs();
vappend('o', 1, ind);
continue;
case 'O': /* open new lines above */
case 'o': /* open new lines below */
vsave();
setLAST();
ind = whitecnt(linebuf);
if (c == 'O') {
vcline--;
dot--;
if (dot > zero)
getDOT();
}
if (!visual) {
c = LINES - CA;
vup1();
} else {
c = vcline < 0 ? ZERO : vliny[vcline] + vdepth();
i = vliny[vcline + 1] - c;
if (i < cnt)
vopenup(cnt - i);
}
*genindent(ind) = 0;
vdoappend(genbuf);
if (!visual)
voinit();
else {
vcline++;
vopen(dot, c);
vsyncCL();
}
vrescurs = cursor;
vresaddr = dot;
vrescnt = 0;
vdelcnt = 1;
vundkind = VMANY;
cursor = linebuf;
linebuf[0] = 0;
vappend('o', 1, ind);
continue;
case 'a': /* append */
setLAST();
if (*cursor) {
vgotoCL(column(cursor));
cursor++;
}
vappend(c, cnt, 0);
continue;
case 'R':
case 'i': /* insert */
setLAST();
if (*cursor == '\t')
vgotoCL(column(cursor - 1));
oglobp = cursor;
vappend(c, cnt, 0);
/*
cursor = oglobp;
vmove();
*/
continue;
case DELETE:
beep();
if (peekkey() != DELETE)
continue;
case FS: /* quit gets you out like a q */
if (inglobal)
onintr();
case 'q': /* quit */
vch = 'q';
vsave();
return (-1);
/*
case 'U':
strcpy(genbuf, linebuf);
putmk1(dot, vmunddot);
getDOT();
ic = vundcurs();
first = 1;
c = vreopen(vliny[vcline], dot - zero);
vsync(vliny[vcline] + c);
goto vmark;
*/
case 'P':
case 'p':
if (vyancnt == 0) {
if (DEL[0] == OVERBUF) {
beep();
continue;
}
vglobp = DEL;
ungetkey(c == 'p' ? 'a' : 'i');
goto vagain;
}
setLAST();
addr = dot - vcline;
vsave();
if (c == 'P') {
dot--;
vcline--;
c = 'p';
}
vdelcnt = vyancnt;
vresaddr = dot + 1;
vrescurs = 0;
copy(vulines, vylines, vyancnt * sizeof vylines[0]);
vresCNT = 0;
vrescnt = vyancnt;
append(vrestore, dot);
vrescnt = 0;
dot = vresaddr;
vundkind = VMANY;
goto putem;
case 'u': /* undo */
switch (vundkind) {
case VMANY:
if (vdelcnt > TUBELINES)
goto fonfon;
vsave();
addr = dot - vcline;
if (vrescnt > 0) {
vresCNT = 0;
append(vrestore, vresaddr - 1);
}
if (vdelcnt > 0) {
dot = vresaddr + vrescnt;
copy(vulines, dot, vdelcnt * sizeof vulines[0]);
vremote(vdelcnt, delete);
}
c = vrescnt;
vrescnt = vdelcnt;
vdelcnt = c;
dot = vresaddr;
if (dot > dol)
dot--;
/* buffer can't be empty */
putem:
cnt = dot - addr;
if (!visual || cnt < 0 || cnt > vcnt) {
vch = '.';
nextic = vrescurs;
return (1);
}
dot--;
vcnt = cnt;
vcline = cnt - 1;
if (vcline >= 0) {
getDOT();
vlast = vliny[vcline] + vdepth();
} else
vlast = ZERO;
vroll(1);
vredraw(vliny[vcline]);
if (vrescurs) {
ic = vrescurs;
vrescurs = 0;
first = 1;
}
goto vnline;
case VNONE:
fonfon:
beep();
continue;
case VCHNG:
strcpy(genbuf, linebuf);
strcLIN(vutmp);
strcpy(vutmp, genbuf);
goto vundoit;
default:
error("Internal error: vmain undo@- please tell someone");
}
/*
case 'U':
strcpy(genbuf, linebuf);
putmk1(dot, vmunddot);
getDOT();
*/
vundoit:
ic = vundcurs();
first = 1;
c = vreopen(vliny[vcline], dot - zero);
vsync(vliny[vcline] + c);
goto vmark;
case '/':
case '?':
if (hadcnt) {
beep();
continue;
}
splitw++;
ic = cursor;
vsave();
if (!visual && !CA)
vup1();
vgoto(LINES - 1, 0);
putchar(c);
if (CA) {
vclreol();
vgoto(LINES - 1, 1);
}
cursor = linebuf;
linebuf[0] = 0;
genbuf[0] = c;
OP = Pline;
Pline = &normline;
c = vcline;
i = LINES - 1 - vliny[vcnt];
vliny[vcnt] = LINES - 1;
vcline = vcnt;
if (peekbr()) {
if (!INS[0] || INS[0] == OVERBUF) {
Peekkey = DELETE;
goto back;
}
vglobp = INS;
}
vgetline(0, genbuf + 1, &hadcnt);
back:
vcline = c;
vliny[vcnt] =- i;
Pline = OP;
splitw = 0;
if (genbuf[0] == 0 || Peekkey == DELETE ||
Peekkey == FS) {
if (Peekkey == DELETE)
Peekkey = 0;
oops:
if (!CA) {
nextic = ic;
vch = '.';
return (1);
}
getDOT();
vsetcurs(ic);
continue;
}
/*
if (genbuf[0] != '/' && genbuf[0] != '?')
error("Search delimiter must be / or ?");
*/
if (!vglobp)
vscandir[0] = genbuf[0];
oglobp = globp;
globp = genbuf + 1;
compile(genbuf[0], 1);
savere(&scanre);
vch = -1;
if (globp && *globp) {
c = *globp++;
if (!visual || c != 'v' && c != 'z')
xtra:
error("Extra chars|Extra characters after search pattern");
vch = *globp++;
switch (vch) {
case 0:
vch = 0;
break;
case '^':
case '-':
case '+':
case '.':
if (*globp == 0)
break;
default:
goto xtra;
}
}
splitw = 1;
globp = oglobp;
vgoto(LINES - 1, 0);
flusho();
splitw = 0;
addr = scanfor(genbuf[0]);
if (addr == NIL) {
putchar('F');
beep();
vraw();
goto oops;
}
markDOT();
it:
c = vcline + (addr - dot);
if (vch == -1 && CA && c >= 0 && c < vcnt) {
ic = loc1;
first = 1;
vmoving = 0;
vcline = c;
dot = addr;
goto vnline;
}
if (CA && !visual)
vup1();
nextic = loc1;
dot = addr;
if (vch == -1)
vch = '.';
return (1);
default:
operate(c, cnt);
continue;
}
}
}
vyank(cnt)
int cnt;
{
DEL[0] = OVERBUF;
vyancnt = cnt;
copy(vylines, dot, cnt * sizeof vylines[0]);
}
vgetcnt()
{
register int c, cnt;
cnt = 0;
for (;;) {
c = getkey();
if (!digit(c))
break;
cnt =* 10, cnt =+ c - '0';
}
ungetkey(c);
Xhadcnt = 1;
Xcnt = cnt;
return(cnt);
}
vremote(cnt, f)
int cnt, (*f)();
{
addr1 = dot;
addr2 = dot + cnt - 1;
inglobal++;
(*f)(0);
inglobal--;
}
vfindcol(i)
int i;
{
register char *cp;
qcolumn(linebuf - 1, 0);
for (cp = linebuf; *cp && vcntcol < i; cp++)
qcount(*cp);
if (cp != linebuf)
cp--;
return (cp);
}
vsave()
{
char genbuf[LBSIZE];
strcpy(genbuf, linebuf);
getDOT();
if (strcmp(linebuf, genbuf) == 0)
return (0);
strcLIN(genbuf);
putmark(dot);
return (1);
}
vundcurs()
{
register char *lp, *gp;
for (lp = linebuf, gp = genbuf; *lp && *gp && *lp == *gp; lp++, gp++)
continue;
if (*lp)
return (lp);
if (*gp)
return (lp > linebuf ? lp - 1 : lp);
return (vskipwh(linebuf));
}
vrestor()
{
if (vresCNT == vrescnt)
return (EOF);
getline(vulines[vresCNT]);
vresCNT++;
return (0);
}
vsyncCL()
{
vsync(vliny[vcline]);
}
getDOT()
{
getline(*dot);
}
vshift()
{
shift(op, 1);
}
#endif