#include "ex.h"
#include "ex_argv.h"
#include "ex_temp.h"
#include "ex_tty.h"
#include "ex_vis.h"
#ifdef STDIO
#include <stdio.h>
#undef getchar
#undef putchar
#endif
bool endline = 1;
line *tad1;
static int jnoop(void);
static void splitit(void);
int putchar(), getchar();
int tags_flag;
int
append(int (*f)(), line *a)
{
line *a1, *a2, *rdot;
int nline;
nline = 0;
dot = a;
if(FIXUNDO && !inopen && f!=getsub) {
undap1 = undap2 = dot + 1;
undkind = UNDCHANGE;
}
while ((*f)() == 0) {
if (truedol >= endcore) {
if (morelines() < 0) {
if (FIXUNDO && f == getsub) {
undap1 = addr1;
undap2 = addr2 + 1;
}
error(value(vi_TERSE) ? gettext("Out of memory") :
gettext("Out of memory- too many lines in file"));
}
}
nline++;
a1 = truedol + 1;
a2 = a1 + 1;
dot++;
undap2++;
dol++;
unddol++;
truedol++;
for (rdot = dot; a1 > rdot;)
*--a2 = *--a1;
*rdot = 0;
putmark(rdot);
if (f == gettty) {
dirtcnt++;
TSYNC();
}
}
return (nline);
}
void
appendnone(void)
{
if(FIXUNDO) {
undkind = UNDCHANGE;
undap1 = undap2 = addr1;
}
}
void
pargs(void)
{
unsigned char **av = argv0, *as = args0;
int ac;
for (ac = 0; ac < argc0; ac++) {
if (ac != 0)
putchar(' ');
if (ac + argc == argc0 - 1)
viprintf("[");
lprintf("%s", as);
if (ac + argc == argc0 - 1)
viprintf("]");
as = av ? *++av : strend(as) + 1;
}
noonl();
}
int
delete(bool hush)
{
line *a1, *a2;
nonzero();
if(FIXUNDO) {
void (*dsavint)();
#ifdef UNDOTRACE
if (trace)
vudump("before delete");
#endif
change();
dsavint = signal(SIGINT, SIG_IGN);
undkind = UNDCHANGE;
a1 = addr1;
squish();
a2 = addr2;
if (a2++ != dol) {
reverse(a1, a2);
reverse(a2, dol + 1);
reverse(a1, dol + 1);
}
dol -= a2 - a1;
unddel = a1 - 1;
if (a1 > dol)
a1 = dol;
dot = a1;
pkill[0] = pkill[1] = 0;
signal(SIGINT, dsavint);
#ifdef UNDOTRACE
if (trace)
vudump("after delete");
#endif
} else {
line *a3;
int i;
change();
a1 = addr1;
a2 = addr2 + 1;
a3 = truedol;
i = a2 - a1;
unddol -= i;
undap2 -= i;
dol -= i;
truedol -= i;
do
*a1++ = *a2++;
while (a2 <= a3);
a1 = addr1;
if (a1 > dol)
a1 = dol;
dot = a1;
}
if (!hush)
killed();
return (0);
}
void
deletenone(void)
{
if(FIXUNDO) {
undkind = UNDCHANGE;
squish();
unddel = addr1;
}
}
void
squish(void)
{
line *a1 = dol + 1, *a2 = unddol + 1, *a3 = truedol + 1;
if(FIXUNDO) {
if (inopen == -1)
return;
if (a1 < a2 && a2 < a3)
do
*a1++ = *a2++;
while (a2 < a3);
truedol -= unddol - dol;
unddol = dol;
}
}
static int jcount;
int
join(int c)
{
line *a1;
unsigned char *cp, *cp1;
#ifndef PRESUNEUC
unsigned char *pcp;
wchar_t *delim;
wchar_t wc1, wc2;
int n;
#endif
cp = genbuf;
*cp = 0;
for (a1 = addr1; a1 <= addr2; a1++) {
getaline(*a1);
cp1 = linebuf;
if (a1 != addr1 && c == 0) {
while (*cp1 == ' ' || *cp1 == '\t')
cp1++;
if (*cp1 && cp > genbuf && cp[-1] != ' ' && cp[-1] != '\t') {
#ifndef PRESUNEUC
if (wddlm && *cp1 != ')' && cp[-1] != '.') {
if ((pcp = cp - MB_CUR_MAX) < genbuf)
pcp = genbuf;;
for ( ; pcp <= cp-1; pcp++) {
if ((n = mbtowc(&wc1,
(char *)pcp, cp - pcp)) ==
cp - pcp)
goto gotprev;
}
goto mberror;
gotprev:
if (!isascii(wc2 = *cp1)) {
if (mbtowc(&wc2, (char *) cp1,
MB_CUR_MAX) <= 0)
goto mberror;
}
delim = (*wddlm)(wc1,wc2,2);
while (*delim)
cp += wctomb((char *)cp,
*delim++);
*cp = 0;
} else
mberror:
#endif
if (*cp1 != ')') {
*cp++ = ' ';
if (cp[-2] == '.')
*cp++ = ' ';
}
}
}
while (*cp++ = *cp1++)
if (cp > &genbuf[LBSIZE-2])
error(value(vi_TERSE) ? gettext("Line overflow") :
gettext("Result line of join would be too long"));
cp--;
}
strcLIN(genbuf);
(void) delete(0);
jcount = 1;
if (FIXUNDO)
undap1 = undap2 = addr1;
(void)append(jnoop, --addr1);
if (FIXUNDO)
vundkind = VMANY;
return (0);
}
static int
jnoop(void)
{
return(--jcount);
}
int getcopy();
void
vi_move(void)
{
line *adt;
bool iscopy = 0;
if (Command[0] == 'm') {
setdot1();
markpr(addr2 == dot ? addr1 - 1 : addr2 + 1);
} else {
iscopy++;
setdot();
}
nonzero();
adt = address((char*)0);
if (adt == 0)
serror(value(vi_TERSE) ?
(unsigned char *)gettext("%s where?") :
(unsigned char *)gettext("%s requires a trailing address"),
Command);
donewline();
move1(iscopy, adt);
killed();
}
void
move1(int cflag, line *addrt)
{
line *adt, *ad1, *ad2;
int nlines;
adt = addrt;
nlines = (addr2 - addr1) + 1;
if (cflag) {
tad1 = addr1;
ad1 = dol;
(void)append(getcopy, ad1++);
ad2 = dol;
} else {
ad2 = addr2;
for (ad1 = addr1; ad1 <= ad2;)
*ad1++ &= ~01;
ad1 = addr1;
}
ad2++;
if (adt < ad1) {
if (adt + 1 == ad1 && !cflag && !inglobal)
error(gettext("That move would do nothing!"));
dot = adt + (ad2 - ad1);
if (++adt != ad1) {
reverse(adt, ad1);
reverse(ad1, ad2);
reverse(adt, ad2);
}
} else if (adt >= ad2) {
dot = adt++;
reverse(ad1, ad2);
reverse(ad2, adt);
reverse(ad1, adt);
} else
error(gettext("Move to a moved line"));
change();
if (!inglobal)
if(FIXUNDO) {
if (cflag) {
undap1 = addrt + 1;
undap2 = undap1 + nlines;
deletenone();
} else {
undkind = UNDMOVE;
undap1 = addr1;
undap2 = addr2;
unddel = addrt;
squish();
}
}
}
int
getcopy(void)
{
if (tad1 > addr2)
return (EOF);
getaline(*tad1++);
return (0);
}
int
getput(void)
{
if (tad1 > unddol)
return (EOF);
getaline(*tad1++);
tad1++;
return (0);
}
int
put(void)
{
int cnt;
if (!FIXUNDO)
error(gettext("Cannot put inside global/macro"));
cnt = unddol - dol;
if (cnt && inopen && pkill[0] && pkill[1]) {
pragged(1);
return (0);
}
tad1 = dol + 1;
(void)append(getput, addr2);
undkind = UNDPUT;
notecnt = cnt;
netchange(cnt);
return (0);
}
void
pragged(bool kill)
{
extern unsigned char *cursor;
#ifdef XPG4
extern int P_cursor_offset;
#endif
unsigned char *gp = &genbuf[cursor - linebuf];
if (!kill)
getDOT();
strcpy(genbuf, linebuf);
getaline(*unddol);
if (kill)
*pkill[1] = 0;
strcat(linebuf, gp);
#ifdef XPG4
P_cursor_offset = strlen(linebuf) - strlen(gp) - 1;
#endif
putmark(unddol);
getaline(dol[1]);
if (kill)
strcLIN(pkill[0]);
strcpy(gp, linebuf);
strcLIN(genbuf);
putmark(dol+1);
undkind = UNDCHANGE;
undap1 = dot;
undap2 = dot + 1;
unddel = dot - 1;
undo(1);
}
void
shift(int c, int cnt)
{
line *addr;
unsigned char *cp;
unsigned char *dp;
int i;
if(FIXUNDO)
save12(), undkind = UNDCHANGE;
cnt *= value(vi_SHIFTWIDTH);
for (addr = addr1; addr <= addr2; addr++) {
dot = addr;
if (c == '=' && addr == addr1 && addr != addr2)
continue;
getDOT();
i = whitecnt(linebuf);
switch (c) {
case '>':
if (linebuf[0] == 0)
continue;
cp = genindent(i + cnt);
break;
case '<':
if (i == 0)
continue;
i -= cnt;
cp = i > 0 ? genindent(i) : genbuf;
break;
default:
i = lindent(addr);
getDOT();
cp = genindent(i);
break;
}
if (cp + strlen(dp = vpastwh(linebuf)) >= &genbuf[LBSIZE - 2])
error(value(vi_TERSE) ? gettext("Line too long") :
gettext("Result line after shift would be too long"));
CP(cp, dp);
strcLIN(genbuf);
putmark(addr);
}
killed();
}
void
tagfind(quick)
bool quick;
{
unsigned char cmdbuf[BUFSIZE];
unsigned char filebuf[FNSIZE];
unsigned char tagfbuf[BUFSIZE];
int c, d;
bool samef = 1;
int tfcount = 0;
int omagic, tl;
unsigned char *fn, *fne;
#ifdef STDIO
FILE *iof;
unsigned char iofbuf[BUFSIZE];
off64_t mid;
off64_t top, bot;
struct stat64 sbuf;
#endif
omagic = value(vi_MAGIC);
tl = value(vi_TAGLENGTH);
if (!skipend()) {
unsigned char *lp = lasttag;
while (!iswhite(peekchar()) && !endcmd(peekchar()))
if (lp < &lasttag[sizeof lasttag - 2])
*lp++ = getchar();
else
ignchar();
*lp++ = 0;
if (!endcmd(peekchar()))
badtag:
error(value(vi_TERSE) ? gettext("Bad tag") :
gettext("Give one tag per line"));
} else if (lasttag[0] == 0)
error(gettext("No previous tag"));
c = getchar();
if (!endcmd(c))
goto badtag;
if (c == EOF)
ungetchar(c);
clrstats();
CP(tagfbuf, svalue(vi_TAGS));
fne = tagfbuf - 1;
while (fne) {
fn = ++fne;
while (*fne && *fne != ' ')
fne++;
if (*fne == 0)
fne = 0;
else
*fne = 0;
#ifdef STDIO
iof = fopen((char *)fn, "r");
if (iof == NULL)
continue;
tfcount++;
setbuf(iof, (char *)iofbuf);
fstat64(fileno(iof), &sbuf);
top = sbuf.st_size;
if (top == 0L || iof == NULL)
top = -1L;
bot = 0L;
while (top >= bot) {
unsigned char *cp = linebuf;
unsigned char *lp = lasttag;
unsigned char *oglobp;
mid = (top + bot) / 2;
fseeko64(iof, mid, 0);
if (mid > 0)
if(fgets((char *)linebuf, sizeof linebuf, iof)==NULL)
goto goleft;
if(fgets((char *)linebuf, sizeof linebuf, iof)==NULL)
goto goleft;
linebuf[strlen(linebuf)-1] = 0;
while (*cp && *lp == *cp)
cp++, lp++;
if ( *lp == 0 && (iswhite(*cp) || tl > 511 || tl > 0 && lp-lasttag >= tl) ) {
if ( mid == bot && mid == top ) {
;
}
else {
top = mid;
continue;
}
}
else {
if ((int)*lp > (int)*cp)
bot = mid + 1;
else
goleft:
top = mid - 1;
continue;
}
fclose(iof);
while (!iswhite(*cp))
cp++;
while (*cp && iswhite(*cp))
cp++;
if (!*cp)
badtags:
serror((unsigned char *)
gettext("%s: Bad tags file entry"),
lasttag);
lp = filebuf;
while (*cp && *cp != ' ' && *cp != '\t') {
if (lp < &filebuf[sizeof filebuf - 2])
*lp++ = *cp;
cp++;
}
*lp++ = 0;
if (*cp == 0)
goto badtags;
if (dol != zero) {
names['t'-'a'] = *dot &~ 01;
if (inopen) {
extern unsigned char *ncols['z'-'a'+2];
extern unsigned char *cursor;
ncols['t'-'a'] = cursor;
}
}
#ifdef TAG_STACK
if (*savedfile) {
savetag((char *)savedfile);
}
#endif
strcpy(cmdbuf, cp);
if (strcmp(filebuf, savedfile) || !edited) {
unsigned char cmdbuf2[sizeof filebuf + 10];
if (!quick) {
ckaw();
if (chng && dol > zero) {
#ifdef TAG_STACK
unsavetag();
#endif
error(value(vi_TERSE) ?
gettext("No write") : gettext("No write since last change (:tag! overrides)"));
}
}
oglobp = globp;
strcpy(cmdbuf2, "e! ");
strcat(cmdbuf2, filebuf);
globp = cmdbuf2;
d = peekc; ungetchar(0);
commands(1, 1);
peekc = d;
globp = oglobp;
value(vi_MAGIC) = omagic;
samef = 0;
}
oglobp = globp;
globp = cmdbuf;
d = peekc; ungetchar(0);
if (samef)
markpr(dot);
value(vi_MAGIC) = 0;
commands(1, 1);
peekc = d;
globp = oglobp;
value(vi_MAGIC) = omagic;
return;
}
#endif
if (tags_flag == 0)
continue;
io = open(fn, 0);
if (io < 0)
continue;
while (getfile() == 0) {
unsigned char *cp = linebuf;
unsigned char *lp = lasttag;
unsigned char *oglobp;
while (*cp && *lp == *cp)
cp++, lp++;
if ( *lp == 0 && (iswhite(*cp) || tl > 511 || tl > 0 && lp-lasttag >= tl) ) {
;
}
else {
continue;
}
close(io);
while (!iswhite(*cp))
cp++;
while (*cp && iswhite(*cp))
cp++;
if (!*cp)
badtags2:
serror((unsigned char *)
gettext("%s: Bad tags file entry"),
lasttag);
lp = filebuf;
while (*cp && *cp != ' ' && *cp != '\t') {
if (lp < &filebuf[sizeof filebuf - 2])
*lp++ = *cp;
cp++;
}
*lp++ = 0;
if (*cp == 0)
goto badtags2;
if (dol != zero) {
names['t'-'a'] = *dot &~ 01;
if (inopen) {
extern unsigned char *ncols['z'-'a'+2];
extern unsigned char *cursor;
ncols['t'-'a'] = cursor;
}
}
#ifdef TAG_STACK
if (*savedfile) {
savetag((char *)savedfile);
}
#endif
strcpy(cmdbuf, cp);
if (strcmp(filebuf, savedfile) || !edited) {
unsigned char cmdbuf2[sizeof filebuf + 10];
if (!quick) {
ckaw();
if (chng && dol > zero) {
#ifdef TAG_STACK
unsavetag();
#endif
error(value(vi_TERSE) ?
gettext("No write") : gettext("No write since last change (:tag! overrides)"));
}
}
oglobp = globp;
strcpy(cmdbuf2, "e! ");
strcat(cmdbuf2, filebuf);
globp = cmdbuf2;
d = peekc; ungetchar(0);
commands(1, 1);
peekc = d;
globp = oglobp;
value(vi_MAGIC) = omagic;
samef = 0;
}
oglobp = globp;
globp = cmdbuf;
d = peekc; ungetchar(0);
if (samef)
markpr(dot);
value(vi_MAGIC) = 0;
commands(1, 1);
peekc = d;
globp = oglobp;
value(vi_MAGIC) = omagic;
return;
}
#ifdef STDIO
fclose(iof);
#else
close(io);
#endif
}
if (tfcount <= 0)
error(gettext("No tags file"));
else
serror(value(vi_TERSE) ?
(unsigned char *)gettext("%s: No such tag") :
(unsigned char *)gettext("%s: No such tag in tags file"),
lasttag);
}
int
yank(void)
{
if (!FIXUNDO)
error(gettext("Can't yank inside global/macro"));
save12();
undkind = UNDNONE;
killcnt(addr2 - addr1 + 1);
return (0);
}
bool zhadpr;
bool znoclear;
short zweight;
void
zop(int hadpr)
{
int c, nlines, op;
bool excl;
zhadpr = hadpr;
notempty();
znoclear = 0;
zweight = 0;
excl = exclam();
switch (c = op = getchar()) {
case '^':
zweight = 1;
case '-':
case '+':
while (peekchar() == op) {
ignchar();
zweight++;
}
case '=':
case '.':
c = getchar();
break;
case EOF:
znoclear++;
break;
default:
op = 0;
break;
}
if (isdigit(c)) {
nlines = c - '0';
for(;;) {
c = getchar();
if (!isdigit(c))
break;
nlines *= 10;
nlines += c - '0';
}
if (nlines < lines)
znoclear++;
value(vi_WINDOW) = nlines;
if (op == '=')
nlines += 2;
}
else {
nlines = op == EOF ? value(vi_SCROLL) :
excl ? lines - 1 : value(vi_WINDOW);
}
if (inopen || c != EOF) {
ungetchar(c);
donewline();
}
addr1 = addr2;
if (addr2 == 0 && dot < dol && op == 0)
addr1 = addr2 = dot+1;
setdot();
zop2(nlines, op);
}
void
zop2(int nlines, int op)
{
line *split;
split = NULL;
switch (op) {
case EOF:
if (addr2 == dol)
error(gettext("\nAt EOF"));
case '+':
if (addr2 == dol)
error(gettext("At EOF"));
addr2 += nlines * zweight;
if (addr2 > dol)
error(gettext("Hit BOTTOM"));
addr2++;
default:
addr1 = addr2;
addr2 += nlines-1;
dot = addr2;
break;
case '=':
case '.':
znoclear = 0;
nlines--;
nlines >>= 1;
if (op == '=')
nlines--;
addr1 = addr2 - nlines;
if (op == '=')
dot = split = addr2;
addr2 += nlines;
if (op == '.') {
markDOT();
dot = addr2;
}
break;
case '^':
case '-':
addr2 -= nlines * zweight;
if (addr2 < one)
error(gettext("Hit TOP"));
nlines--;
addr1 = addr2 - nlines;
dot = addr2;
break;
}
if (addr1 <= zero)
addr1 = one;
if (addr2 > dol)
addr2 = dol;
if (dot > dol)
dot = dol;
if (addr1 > addr2)
return;
if (op == EOF && zhadpr) {
getaline(*addr1);
putchar((int)('\r' | QUOTE));
shudclob = 1;
} else if (znoclear == 0 && clear_screen != NOSTR && !inopen) {
flush1();
vclear();
}
if (addr2 - addr1 > 1)
pstart();
if (split) {
plines(addr1, split - 1, 0);
splitit();
plines(split, split, 0);
splitit();
addr1 = split + 1;
}
plines(addr1, addr2, 0);
}
static void
splitit(void)
{
int l;
for (l = columns > 80 ? 40 : columns / 2; l > 0; l--)
putchar('-');
putnl();
}
void
plines(line *adr1, line *adr2, bool movedot)
{
line *addr;
pofix();
for (addr = adr1; addr <= adr2; addr++) {
getaline(*addr);
pline(lineno(addr));
if (inopen)
putchar((int)('\n' | QUOTE));
if (movedot)
dot = addr;
}
}
void
pofix(void)
{
if (inopen && Outchar != termchar) {
vnfl();
setoutt();
}
}
void
undo(bool c)
{
int i, k;
line *jp, *kp, *j;
line *dolp1, *newdol, *newadot;
#ifdef UNDOTRACE
if (trace)
vudump("before undo");
#endif
if (inglobal && inopen <= 0)
error(value(vi_TERSE) ? gettext("Can't undo in global") :
gettext("Can't undo in global commands"));
if (!c)
somechange();
pkill[0] = pkill[1] = 0;
change();
if (undkind == UNDMOVE) {
if ((i = (jp = unddel) - undap2) > 0) {
addr2 = jp;
addr1 = (jp = undap1) + i;
unddel = jp-1;
} else {
addr1 = ++jp;
addr2 = jp + ((unddel = undap2) - undap1);
}
kp = undap1;
move1(0, unddel);
dot = kp;
Command = (unsigned char *)"move";
killed();
} else {
int cnt;
newadot = dot;
cnt = lineDOL();
newdol = dol;
dolp1 = dol + 1;
if ((i = (kp = undap2) - (jp = undap1)) > 0) {
if (kp != dolp1) {
reverse(jp, kp);
reverse(kp, dolp1);
reverse(jp, dolp1);
}
if (unddel >= jp)
unddel -= i;
newdol -= i;
dot = jp-1;
}
if (undkind == UNDPUT) {
unddel = undap1 - 1;
squish();
}
jp = unddel + 1;
if ((i = (kp = unddol) - dol) > 0) {
if (jp != dolp1) {
reverse(jp, dolp1);
reverse(dolp1, ++kp);
reverse(jp, kp);
}
if (undap1 >= jp)
undap1 += i;
dot = jp;
newdol += i;
}
unddel = undap1 - 1;
undap1 = jp;
undap2 = jp + i;
dol = newdol;
netchHAD(cnt);
if (undkind == UNDALL) {
dot = undadot;
undadot = newadot;
} else
undkind = UNDCHANGE;
for (j=unddol; j> dol; j--)
for (k=0; k<=25; k++)
if (names[k] == *(j))
names[k]= *((undap1+(j-dolp1)) );
}
if ((dot <= zero || dot > dol) && dot != dol)
dot = one;
#ifdef UNDOTRACE
if (trace)
vudump("after undo");
#endif
}
void
somechange(void)
{
line *ip, *jp;
switch (undkind) {
case UNDMOVE:
return;
case UNDCHANGE:
if (undap1 == undap2 && dol == unddol)
break;
return;
case UNDPUT:
if (undap1 != undap2)
return;
break;
case UNDALL:
if (unddol - dol != lineDOL())
return;
for (ip = one, jp = dol + 1; ip <= dol; ip++, jp++)
if ((*ip &~ 01) != (*jp &~ 01))
return;
break;
case UNDNONE:
error(gettext("Nothing to undo"));
}
error(value(vi_TERSE) ? gettext("Nothing changed") :
gettext("Last undoable command didn't change anything"));
}
void
mapcmd(int un, int ab)
{
unsigned char lhs[100], rhs[100];
unsigned char *p;
int c;
unsigned char *dname;
struct maps *mp;
unsigned char funkey[3];
mp = ab ? abbrevs : exclam() ? immacs : arrows;
if (skipend()) {
int i;
if (peekchar() != EOF)
ignchar();
if (un)
error(gettext("Missing lhs"));
if (inopen)
pofix();
for (i=0; i< MAXNOMACS && mp[i].mapto; i++)
if (mp[i].cap) {
lprintf("%s", mp[i].descr);
putchar('\t');
lprintf("%s", mp[i].cap);
putchar('\t');
lprintf("%s", mp[i].mapto);
putNFL();
}
return;
}
(void)skipwh();
for (p=lhs; ; ) {
c = getchar();
if (c == CTRL('v')) {
c = getchar();
} else if (!un && any(c, " \t")) {
break;
} else if (endcmd(c) && c!='"') {
ungetchar(c);
if (un) {
donewline();
*p = 0;
addmac(lhs, (unsigned char *)NOSTR,
(unsigned char *)NOSTR, mp);
return;
} else
error(gettext("Missing rhs"));
}
*p++ = c;
}
*p = 0;
if (skipend())
error(gettext("Missing rhs"));
for (p=rhs; ; ) {
c = getchar();
if (c == CTRL('v')) {
c = getchar();
} else if (endcmd(c) && c!='"') {
ungetchar(c);
break;
}
*p++ = c;
}
*p = 0;
donewline();
if (lhs[0] == '#') {
unsigned char *fnkey;
unsigned char *fkey();
fnkey = fkey(lhs[1] - '0');
funkey[0] = 'f'; funkey[1] = lhs[1]; funkey[2] = 0;
if (fnkey)
strcpy(lhs, fnkey);
dname = funkey;
} else {
dname = lhs;
}
addmac(lhs,rhs,dname,mp);
}
void
addmac(unsigned char *src, unsigned char *dest, unsigned char *dname,
struct maps *mp)
{
int slot, zer;
#ifdef UNDOTRACE
if (trace)
fprintf(trace, "addmac(src='%s', dest='%s', dname='%s', mp=%x\n", src, dest, dname, mp);
#endif
if (dest && mp==arrows) {
if (src[1] == 0 && src[0] == dest[strlen(dest)-1])
error(gettext("No tail recursion"));
if (isalpha(src[0]) && isascii(src[0]) && src[1] || any(src[0],":"))
error(gettext("Too dangerous to map that"));
}
else if (dest) {
if (eq(src, dest+strlen(dest)-strlen(src)))
error(gettext("No tail recursion"));
}
if (src == (unsigned char *)NOSTR || src[0] == 0)
error(gettext("Missing lhs"));
zer = -1;
for (slot=0; slot < MAXNOMACS && mp[slot].mapto; slot++) {
if (mp[slot].cap) {
if (eq(src, mp[slot].cap) || eq(src, mp[slot].mapto))
break;
} else {
zer = slot;
}
}
if (slot >= MAXNOMACS)
error(gettext("Too many macros"));
if (dest == (unsigned char *)NOSTR) {
if (mp[slot].cap) {
mp[slot].cap = (unsigned char *)NOSTR;
mp[slot].descr = (unsigned char *)NOSTR;
} else {
error(value(vi_TERSE) ? gettext("Not mapped") :
gettext("That macro wasn't mapped"));
}
return;
}
if (zer >= 0 && mp[slot].mapto == 0)
slot = zer;
if (msnext == 0)
msnext = mapspace;
if (msnext - mapspace + strlen(dest) + strlen(src) + strlen(dname) + 3 > MAXCHARMACS)
error(gettext("Too much macro text"));
CP(msnext, src);
mp[slot].cap = msnext;
msnext += strlen(src) + 1;
CP(msnext, dest);
mp[slot].mapto = msnext;
msnext += strlen(dest) + 1;
if (dname) {
CP(msnext, dname);
mp[slot].descr = msnext;
msnext += strlen(dname) + 1;
} else {
mp[slot].descr = src;
}
}
void
cmdmac(c)
unsigned char c;
{
unsigned char macbuf[BUFSIZE];
line *ad, *a1, *a2;
unsigned char *oglobp;
short pk;
bool oinglobal;
lastmac = c;
oglobp = globp;
oinglobal = inglobal;
pk = peekc; peekc = 0;
if (inglobal < 2)
inglobal = 1;
regbuf(c, macbuf, sizeof(macbuf));
a1 = addr1; a2 = addr2;
for (ad=a1; ad<=a2; ad++) {
globp = macbuf;
dot = ad;
commands(1,1);
}
globp = oglobp;
inglobal = oinglobal;
peekc = pk;
}
unsigned char *
vgetpass(prompt)
char *prompt;
{
unsigned char *p;
int c;
static unsigned char pbuf[9];
if (!inopen)
return (unsigned char *)getpass(prompt);
viprintf("%s", prompt); flush();
for (p=pbuf; (c = getkey())!='\n' && c!=EOF && c!='\r';) {
if (p < &pbuf[8])
*p++ = c;
}
*p = '\0';
return(pbuf);
}
#ifdef TAG_STACK
#define TSTACKSIZE 20
struct tagstack {
line *tag_line;
char *tag_file;
} tagstack[TSTACKSIZE];
static int tag_depth = 0;
static char tag_buf[ 1024 ];
static char *tag_end = tag_buf;
void
savetag(char *name)
{
if( !value(vi_TAGSTACK) )
return;
if(tag_depth >= TSTACKSIZE) {
error(gettext("Tagstack too deep."));
}
if( strlen( name ) + 1 + tag_end >= &tag_buf[1024]) {
error(gettext("Too many tags."));
}
tagstack[tag_depth].tag_line = dot;
tagstack[tag_depth++].tag_file = tag_end;
while(*tag_end++ = *name++)
;
}
void
unsavetag(void)
{
if (!value(vi_TAGSTACK))
return;
if (tag_depth > 0)
tag_end = tagstack[--tag_depth].tag_file;
}
void
poptag(quick)
bool quick;
{
unsigned char cmdbuf[100];
unsigned char *oglobp;
int d;
if (!value(vi_TAGSTACK)) {
tag_end = tag_buf;
d = tag_depth;
tag_depth = 0;
if (d == 0)
error(gettext("Tagstack not enabled."));
else
return;
}
if (!tag_depth)
error(gettext("Tagstack empty."));
if (strcmp(tagstack[tag_depth-1].tag_file, savedfile) ) {
if (!quick) {
ckaw();
if (chng && dol > zero)
error(value(vi_TERSE) ?
gettext("No write") : gettext("No write since last change (:pop! overrides)"));
}
oglobp = globp;
strcpy(cmdbuf, "e! ");
strcat(cmdbuf, tagstack[tag_depth-1].tag_file);
globp = cmdbuf;
d = peekc; ungetchar(0);
commands(1, 1);
peekc = d;
globp = oglobp;
}
markpr(dot);
dot = tagstack[--tag_depth].tag_line;
tag_end = tagstack[tag_depth].tag_file;
}
#endif