BSD 2 development
[unix-history] / .ref-BSD-1 / ex-1.1 / ex_vops.c
#include "ex.h"
#ifdef VISUAL
#include "ex_tty.h"
#include "ex_vis.h"
/*
* Ex - a text editor
* Bill Joy UCB September 1977
*/
vdelete(c)
char c;
{
register char *cp;
register int i;
if (c == '#')
cursor++, wcursor++;
if (wcursor < linebuf)
wcursor = linebuf;
if (cursor == wcursor) {
beep();
return;
}
vdcMID();
setDEL();
cp = cursor;
strcpy(cp, wcursor);
if (cp > linebuf && (cp[0] == 0 || c == '#'))
cp--;
i = vliny[vcline];
i =+ vreopen(i, dot - zero);
while (i < vliny[vcline + 1]) {
vclrlin(i, dot + 1);
i++;
}
vsetcurs(cp);
}
vdcMID()
{
register char *cp;
setLAST();
vundkind = VCHNG;
strcpy(vutmp, linebuf);
if (wcursor < cursor) {
cp = wcursor;
wcursor = cursor;
cursor = cp;
}
}
vgrabit()
{
takeout(INS);
}
vyankit()
{
takeout(DEL);
}
takeout(BUF)
char *BUF;
{
register char *cp;
if (wcursor < linebuf)
wcursor = linebuf;
if (cursor == wcursor) {
beep();
return;
}
if (wcursor < cursor) {
cp = wcursor;
wcursor = cursor;
cursor = cp;
}
setBUF(BUF);
if (BUF[0] == OVERBUF)
beep();
}
vchange()
{
register char *cp;
register int i;
if (wcursor < linebuf)
wcursor = linebuf;
if (cursor == wcursor) {
beep();
return;
}
vdcMID();
vfixcurs();
cp = cursor;
vsetcurs(wcursor - 1);
putchar('$');
cursor = cp;
setDEL();
strcpy(cursor, wcursor);
if (*cursor == 0)
vgotoCL(column(cursor));
else if (*cursor == '\t')
vgotoCL(column(cursor - 1));
else
vfixcurs();
vappend('c', 1, 0);
}
char vaifirst;
vappend(ch, cnt, indent)
char ch;
int cnt, indent;
{
register int i;
register char *gcursor;
char escape, *ic;
int repcnt;
if (!visual && !CA)
vsave();
vaifirst = indent == 0;
if (ch == 'r')
repcnt = 2;
else
repcnt = 0;
ic = cursor;
switch (ch) {
case 'c':
case 'r':
case 'o':
/* roll your own */
break;
default:
vundkind = VCHNG;
strcpy(vutmp, linebuf);
break;
}
if (value(AUTOINDENT) && indent != 0) {
gcursor = genindent(indent);
*gcursor = 0;
vgotoCL(qcolumn(cursor - 1, genbuf));
} else {
gcursor = genbuf;
*gcursor = 0;
if (ch == 'o')
vfixcurs();
}
if ((vglobp && *vglobp == 0) || peekbr()) {
if (!INS[0] || INS[0] == OVERBUF) {
beep();
return;
}
vglobp = INS;
} else if (vglobp == 0)
INS[0] = 0;
/*
* At the beginning of the following loop which gathers appended
* lines, gcursor points to the beginning of the place for the
* appended text. Linebuf contains the line in which the operation
* is taking place, the appended text is placed starting at the
* position indicated by cursor.
*/
for (;;) {
/*
* Get a line into genbuf. Gcursor indicates that we
* have possibly generated some input (e.g. autoindent).
* If the line is terminated with a newline character
* then escape will be set to the newline. The repcnt
* limits the number of characters appended, e.g. it is
* 2 to get exactly one character (i.e. for a replace)
* or 0 to get an arbitrary number of characters.
*/
if (ch == 'r' && repcnt == 0)
escape = 0;
else {
gcursor = vgetline(repcnt, gcursor, &escape);
#ifdef UNIMP
if (HADUP)
addtext(HADZERO ? "0" : "^");
while (CDCNT > 0) {
addtext("\04");
CDCNT--;
}
#endif
addtext(ogcursor);
}
repcnt = 0;
if (!vaifirst && value(AUTOINDENT)) {
/*
* Fix up the autoindent. Fixindent gathers white
* space from the beginning of the line and turns
* it into tabs and spaces as appropriate.
* We reset the cursor to be the end of the line
* as it was when it was returned from vgetline.
*/
i = fixindent(indent);
if (!hadup)
indent = i;
gcursor = strend(genbuf);
}
/*
* Have to cut down the count if the specified count
* would make a line which is too long.
*/
cnt = vmaxrep(ch, cnt);
/*
* We save the rest of the line after the end of the
* appended material (at gcursor + 1).
* This frees up linebuf for use in saving lines, etc.
*/
strcpy(gcursor + 1, cursor);
/*
* Catenate cnt copies of the inserted text after
* the material which precedes this insert.
*/
do {
strcpy(cursor, genbuf);
cursor =+ gcursor - genbuf;
} while (--cnt > 0);
/*
* If the insert didnt terminate with a new line character
* then we want to put the whole line back together.
*/
if (escape != '\n')
strcpy(cursor, gcursor + 1);
/*
* Clean up the line image on the screen.
* I is the first line after this lines image for use
* in making a new next line.
*/
i = vreopen(vliny[vcline], dot - zero);
if (escape != '\n')
break;
addtext("\n");
vsave();
if (vundkind != VMANY) {
vundkind = VMANY;
vrescurs = ic;
strcLIN(vutmp);
vulines[0] = putline();
vrescnt = 1;
vdelcnt = 1;
vresaddr = dot;
getDOT();
}
vdelcnt++;
cnt = 1;
/*
* We wish to place the text we are "pushing ahead"
* in front of the append in linebuf, cursor pointing
* to the beginning of linebuf. We also wish to leave
* in genbuf the white space implied by an autoindent
* or if not ai then just start the new line at the
* beginning of genbuf.
*/
if (value(AUTOINDENT)) {
if (!hadup && vaifirst)
indent = whitecnt(linebuf);
vaifirst = 0;
/*
* If we are generating an indent, then we
* don't want the white space of the pushed ahead
* line, preferring to generate our own. Discard
* the white space of the pushed ahead material
* and copy the remainder back to linebuf.
*/
strcLIN(vpastwh(gcursor + 1));
/*
* Generate indent white space and leave the
* cursor pointing just after it.
* Note that genindent doesn't make the generated
* white space into a string so we must do that
* ourselves.
*/
gcursor = genindent(indent);
*gcursor = 0;
/*
* If the line is too long when the generated white
* space is added, then just pretend ai isn't set.
*/
if (gcursor + strlen(linebuf) > &genbuf[510])
gcursor = genbuf;
/*
* Paste the first image of the line together.
*/
strcpy(gcursor, linebuf);
} else {
/*
* Without ai the first image of the new line
* is just the pushed ahead material, and there
* are no pre-inserted characters.
*/
strcpy(genbuf, gcursor + 1);
gcursor = genbuf;
}
/*
* Make a new line after dot with the material in genbuf.
* Note that this call increments dot as a side effect,
* so that dot now references the new line.
*/
vdoappend(genbuf);
/*
* Now open up the new line on the screen after
* the current line
*/
vcline++;
if (!visual) {
vup1();
voinit();
} else {
i =+ vliny[vcline - 1];
vopen(dot, i);
}
/*
* Put the stuff we are pushing into linebuf
* and set the cursor to indicate that no stuff
* will preceded the inserted material on the new line.
*/
strcLIN(gcursor);
*gcursor = 0;
cursor = linebuf;
vgotoCL(qcolumn(cursor - 1, genbuf));
}
/*
* We ended an append with a non-newline.
* At this point the new image of the line is in linebuf
* and the cursor points at the desired cursor position.
* We have already shown this line, but must clean up the
* remainder of the screen. Note that the cursor should
* also be set to the last character appended, so
* it needs to be backed up if there was such a character.
*/
if (cursor > linebuf)
cursor--;
vfixopen(i);
vfixcurs();
}
#endif
genindent(indent)
register int indent;
{
register char *cp;
for (cp = genbuf; indent >= 8; indent =- 8)
*cp++ = '\t';
for (; indent > 0; indent--)
*cp++ = ' ';
return (cp);
}
#ifdef VISUAL
fixindent(indent)
int indent;
{
register int i;
register char *cp;
i = whitecnt(genbuf);
cp = vpastwh(genbuf);
if (*cp == 0 && i == indent && linebuf[0] == 0) {
genbuf[0] = 0;
return (i);
}
strcpy(genindent(i), cp);
return (i);
}
#endif
vpastwh(cp)
register char *cp;
{
while (white(*cp))
cp++;
return (cp);
}
whitecnt(cp)
register char *cp;
{
register int i;
i = 0;
for (;;)
switch (*cp++) {
case '\t':
i =+ 8;
i =& ~7;
break;
case ' ':
i++;
break;
default:
return (i);
}
}
#ifdef VISUAL
vgetline(cnt, gcursor, aescaped)
int cnt;
register char *gcursor;
char *aescaped;
{
register int c;
register char *cp;
int x, y, iwhite;
char *iglobp, ch;
*aescaped = 0;
ogcursor = gcursor;
flusho();
#ifdef UNIMP
CDCNT = 0;
HADUP = 0;
HADZERO = 0;
#endif
hadup = 0;
iwhite = whitecnt(genbuf);
iglobp = vglobp;
for (;;) {
if (cnt != 0) {
cnt--;
if (cnt == 0)
goto vadone;
}
ch = c = getkey();
switch (c) {
case DELETE: /* interrupt */
case FS: /* quit */
ungetkey(c);
goto vadone;
case CTRL(d):
case CTRL(t):
*gcursor = 0;
cp = vpastwh(genbuf);
c = whitecnt(genbuf);
if (ch == CTRL(t)) {
if (cp != gcursor)
continue;
cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1));
ogcursor = cp;
goto vbackup;
}
#ifdef UNIMP
if (c == iwhite && c != 0)
if (cp == gcursor) {
iwhite = backtab(c);
CDCNT++;
ogcursor = cp = genindent(iwhite);
goto vbackup;
} else if (cp + 1 == gcursor &&
(*cp == '^' || *cp == '0')) {
hadup = *cp == '^';
ogcursor = cp = genbuf;
HADUP = 1;
CDCNT = 1;
goto vbackup;
}
if (vglobp && vglobp - iglobp >= 2 &&
(vglobp[-2] == '^' || vglobp[-2] == '0')
&& gcursor == ogcursor + 1)
goto bakchar;
#endif
continue;
case CTRL(h): /* back character */
bakchar:
cp = gcursor - 1;
if (cp < ogcursor) {
beep();
continue;
}
goto vbackup;
case CTRL(w): /* back word */
wdkind = 0;
for (cp = gcursor; cp > ogcursor &&
white(cp[-1]); cp--)
continue;
for (c = wordch(cp - 1); cp > ogcursor &&
wordof(c, cp - 1); cp--)
continue;
goto vbackup;
case '@':
case CTRL(x):
cp = ogcursor;
vbackup:
if (cp == gcursor) {
beep();
continue;
}
while (gcursor < cp) putchar(*gcursor++);
*cp = 0;
vgotoCL(qcolumn(cursor - 1, genbuf));
gcursor = cp;
continue;
case CR:
c = '\n';
case NL:
*aescaped = c;
goto vadone;
case ESCAPE:
goto vadone;
case '\\':
x = destcol;
y = destline;
putchar('\\');
vcsync();
c = getkey();
switch (c) {
case DELETE:
case FS:
case CTRL(d):
case CTRL(h):
case CTRL(t):
case CTRL(w):
case '@':
case CTRL(x):
vgoto(y, x);
break;
default:
ungetkey(c);
c = '\\';
goto noput;
}
default:
putchar(c);
noput:
if (gcursor > &genbuf[510])
error("Line too long");
*gcursor++ = c;
vcsync();
continue;
}
}
vadone:
*gcursor = 0;
return (gcursor);
}
int vgetsplit();
char *vsplitpt;
vdoappend(lp)
char *lp;
{
vsplitpt = lp;
inglobal++;
append(vgetsplit, dot);
inglobal--;
}
vgetsplit()
{
if (vsplitpt == 0)
return (EOF);
strcLIN(vsplitpt);
vsplitpt = 0;
return(0);
}
vmaxrep(ch, cnt)
char ch;
register int cnt;
{
register int len, replen;
if (cnt > 510)
cnt = 510;
replen = strlen(genbuf);
if (ch == 'R') {
len = strlen(cursor);
strcpy(cursor, cursor + (replen > len ? len : replen));
}
len = strlen(linebuf);
if (len + cnt * replen <= 510)
return (cnt);
cnt = (510 - len) / replen;
if (cnt == 0) {
vsave();
error("Line too long");
}
return (cnt);
}
vmove()
{
vsetcurs(wcursor);
}
#endif