#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
#include <regexpr.h>
#ifndef PRESUNEUC
#include <wctype.h>
#ifdef putchar
#undef putchar
#endif
#ifdef getchar
#undef getchar
#endif
#endif
#ifdef PRESUNEUC
#define blank() isspace(wcursor[0])
#endif
#define forbid(a) if (a) goto errlab;
unsigned char vscandir[2] = { '/', 0 };
static int get_addr();
void
operate(int c, int cnt)
{
wchar_t i;
int (*moveop)(), (*deleteop)();
int (*opf)();
bool subop = 0;
unsigned char *oglobp, *ocurs;
line *addr;
line *odot;
int oc;
static unsigned char lastFKND;
static wchar_t lastFCHR;
short d;
int mouse_x;
int mouse_y;
int oline;
moveop = vmove, deleteop = (int (*)())vdelete;
wcursor = cursor;
wdot = NOLINE;
notecnt = 0;
dir = 1;
switch (c) {
case 'd':
moveop = (int (*)())vdelete;
deleteop = beep;
break;
case 's':
ungetkey(' ');
subop++;
case 'c':
if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S')
subop++;
moveop = (int (*)())vchange;
deleteop = beep;
break;
case '!':
moveop = vfilter;
deleteop = beep;
break;
case 'y':
moveop = vyankit;
deleteop = beep;
break;
case '=':
forbid(!value(vi_LISP));
case '<':
case '>':
moveop = vshftop;
deleteop = beep;
break;
case 'r':
vmacchng(1);
vrep(cnt);
return;
default:
goto nocount;
}
vmacchng(1);
if (isdigit(peekkey()) && peekkey() != '0') {
cnt *= vgetcnt();
Xcnt = cnt;
forbid(cnt <= 0);
}
c = map(getesc(), arrows, 0);
if (c == 0)
return;
if (!subop)
*lastcp++ = c;
nocount:
opf = moveop;
switch (c) {
case CTRL('X'):
c = getkey();
if ((c != CTRL('_')) && (c != (CTRL(']'))))
break;
getkey();
mouse_x = get_addr() + 1;
mouse_y = get_addr() + 1;
if (mouse_y < WTOP)
break;
if (Pline == numbline)
mouse_x -= 8;
if (mouse_x < 0)
mouse_x = 0;
if (mouse_x > WCOLS)
break;
for (i = 0; i <= WECHO; i++) {
if (vlinfo[i].vliny >= mouse_y)
break;
}
if (i > WECHO)
break;
if (i) {
if (vlinfo[i - 1].vdepth > 1) {
mouse_x += WCOLS * (mouse_y -
(vlinfo[i].vliny -
(vlinfo[i - 1].vdepth - 1)));
}
}
else
{
mouse_x += WCOLS * (mouse_y - 1);
}
vsave();
ocurs = cursor;
odot = dot;
oline = vcline;
operate('H', i);
getDOT();
if (Pline == numbline)
mouse_x += 8;
vmovcol = mouse_x;
vmoving = 1;
wcursor = vfindcol(mouse_x);
wdot = (odot - oline) + i - 1;
cursor = ocurs;
vcline = oline;
dot = odot;
getDOT();
break;
case 'b':
case 'B':
dir = -1;
case 'W':
case 'w':
wdkind = c & ' ';
forbid(lfind(2, cnt, opf, (line *)0) < 0);
vmoving = 0;
break;
case 'E':
wdkind = 0;
goto ein;
case 'e':
wdkind = 1;
ein:
forbid(lfind(3, cnt - 1, opf, (line *)0) < 0);
vmoving = 0;
break;
case '(':
dir = -1;
case ')':
forbid(lfind(0, cnt, opf, (line *) 0) < 0);
markDOT();
break;
case '{':
dir = -1;
case '}':
forbid(lfind(1, cnt, opf, (line *) 0) < 0);
markDOT();
break;
case '%':
vsave();
ocurs = cursor;
odot = wdot = dot;
oglobp = globp;
CATCH
i = lmatchp((line *) 0);
ONERR
globp = oglobp;
dot = wdot = odot;
cursor = ocurs;
splitw = 0;
vclean();
vjumpto(dot, ocurs, 0);
return;
ENDCATCH
#ifdef TRACE
if (trace)
fprintf(trace, "after lmatchp in %, dot=%d, wdot=%d, "
"dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
#endif
getDOT();
forbid(!i);
if (opf != vmove)
if (dir > 0)
wcursor++;
else
cursor++;
else
markDOT();
vmoving = 0;
break;
case '[':
dir = -1;
case ']':
if (!vglobp)
forbid(getkey() != c);
#ifndef XPG4
forbid(Xhadcnt);
#endif
vsave();
#ifdef XPG4
if (cnt > 1) {
while (cnt-- > 1) {
i = lbrack(c, opf);
getDOT();
forbid(!i);
markDOT();
if (ospeed > B300)
hold |= HOLDWIG;
(*opf)(c);
}
}
#endif
i = lbrack(c, opf);
getDOT();
forbid(!i);
markDOT();
if (ospeed > B300)
hold |= HOLDWIG;
break;
case ',':
forbid(lastFKND == 0);
c = isupper(lastFKND) ? tolower(lastFKND) : toupper(lastFKND);
i = lastFCHR;
if (vglobp == 0)
vglobp = (unsigned char *)"";
subop++;
goto nocount;
case '0':
wcursor = linebuf;
vmoving = 0;
break;
case ';':
forbid(lastFKND == 0);
c = lastFKND;
i = lastFCHR;
subop++;
goto nocount;
case 'F':
case 'T':
dir = -1;
case 'f':
case 't':
if (!subop) {
int length;
wchar_t wchar;
length = _mbftowc(lastcp, &wchar, getesc, &Peekkey);
if (length <= 0 || wchar == 0) {
(void) beep();
return;
}
i = wchar;
lastcp += length;
}
if (vglobp == 0)
lastFKND = c, lastFCHR = i;
for (; cnt > 0; cnt--)
forbid(find(i) == 0);
vmoving = 0;
switch (c) {
case 'T':
wcursor = nextchr(wcursor);
break;
case 't':
wcursor = lastchr(linebuf, wcursor);
case 'f':
fixup:
if (moveop != vmove)
wcursor = nextchr(wcursor);
break;
}
break;
case '|':
if (Pline == numbline)
cnt += 8;
vmovcol = cnt;
vmoving = 1;
wcursor = vfindcol(cnt);
break;
case '^':
wcursor = vskipwh(linebuf);
vmoving = 0;
break;
case '$':
if (opf == vmove) {
vmoving = 1;
vmovcol = 20000;
} else
vmoving = 0;
if (cnt > 1) {
if (opf == vmove) {
wcursor = 0;
cnt--;
} else
wcursor = linebuf;
wdot = dot + cnt;
break;
}
if (linebuf[0]) {
wcursor = strend(linebuf);
wcursor = lastchr(linebuf, wcursor);
goto fixup;
}
wcursor = linebuf;
break;
case 'h':
case CTRL('h'):
dir = -1;
case 'l':
case ' ':
forbid(margin() || opf == vmove && edge());
while (cnt > 0 && !margin()) {
if (dir == 1)
wcursor = nextchr(wcursor);
else
wcursor = lastchr(linebuf, wcursor);
cnt--;
}
if (margin() && opf == vmove || wcursor < linebuf) {
if (dir == 1)
wcursor = lastchr(linebuf, wcursor);
else
wcursor = linebuf;
}
vmoving = 0;
break;
case 'D':
cnt = INF;
goto deleteit;
case 'X':
dir = -1;
deleteit:
case 'x':
if (margin())
goto errlab;
vmacchng(1);
while (cnt > 0 && !margin()) {
if (dir == 1)
wcursor = nextchr(wcursor);
else
wcursor = lastchr(linebuf, wcursor);
cnt--;
}
opf = deleteop;
vmoving = 0;
break;
default:
if (opf == vmove || c != workcmd[0]) {
errlab:
(void) beep();
vmacp = 0;
return;
}
case '_':
wdot = dot + cnt - 1;
vmoving = 0;
wcursor = 0;
break;
case 'H':
wdot = (dot - vcline) + cnt - 1;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
case '-':
wdot = dot - cnt;
vmoving = 0;
wcursor = 0;
break;
case 'k':
case CTRL('p'):
wdot = dot - cnt;
if (vmoving == 0)
vmoving = 1, vmovcol = column(cursor);
wcursor = 0;
break;
case 'L':
wdot = dot + vcnt - vcline - cnt;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
case 'M':
wdot = dot + ((vcnt + 1) / 2) - vcline - 1;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
case '+':
case CR:
wdot = dot + cnt;
vmoving = 0;
wcursor = 0;
break;
case CTRL('n'):
case 'j':
case NL:
wdot = dot + cnt;
if (vmoving == 0)
vmoving = 1, vmovcol = column(cursor);
wcursor = 0;
break;
case 'n':
vglobp = vscandir;
c = *vglobp++;
goto nocount;
case 'N':
vglobp = vscandir[0] == '/' ? (unsigned char *)"?" :
(unsigned char *)"/";
c = *vglobp++;
goto nocount;
case '\'':
case '`':
d = c;
c = getesc();
if (c == 0)
return;
c = markreg(c);
forbid(c == 0);
wdot = getmark(c);
forbid(wdot == NOLINE);
forbid(Xhadcnt);
vmoving = 0;
wcursor = d == '`' ? ncols[c - 'a'] : 0;
if (opf == vmove && (wdot != dot ||
(d == '`' && wcursor != cursor)))
markDOT();
if (wcursor) {
vsave();
getaline(*wdot);
if (wcursor > strend(linebuf))
wcursor = 0;
else {
cnt = wcursor - linebuf;
for (wcursor = linebuf; wcursor - linebuf < cnt; )
wcursor = nextchr(wcursor);
if (wcursor - linebuf > cnt)
wcursor = lastchr(linebuf, wcursor);
}
getDOT();
}
if (ospeed > B300)
hold |= HOLDWIG;
break;
case 'G':
if (!Xhadcnt)
cnt = lineDOL();
wdot = zero + cnt;
forbid(wdot < one || wdot > dol);
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
case '/':
case '?':
forbid(Xhadcnt);
vsave();
oc = c;
ocurs = cursor;
odot = dot;
wcursor = 0;
if (readecho(c))
return;
if (!vglobp)
vscandir[0] = genbuf[0];
oglobp = globp; CP(vutmp, genbuf); globp = vutmp;
d = peekc;
fromsemi:
ungetchar(0);
fixech();
CATCH
#ifndef CBREAK
vcook();
#endif
addr = address(cursor);
#ifndef CBREAK
vraw();
#endif
ONERR
#ifndef CBREAK
vraw();
#endif
slerr:
globp = oglobp;
dot = odot;
cursor = ocurs;
ungetchar(d);
splitw = 0;
vclean();
vjumpto(dot, ocurs, 0);
return;
ENDCATCH
if (globp == 0)
globp = (unsigned char *)"";
else if (peekc)
--globp;
if (*globp == ';') {
globp++;
dot = addr;
cursor = (unsigned char *)loc1;
goto fromsemi;
}
dot = odot;
ungetchar(d);
c = 0;
if (*globp == 'z')
globp++, c = '\n';
if (any(*globp, "^+-."))
c = *globp++;
i = 0;
while (isdigit(*globp))
i = i * 10 + *globp++ - '0';
if (any(*globp, "^+-."))
c = *globp++;
if (*globp) {
(void) beep();
goto slerr;
}
globp = oglobp;
splitw = 0;
vmoving = 0;
wcursor = (unsigned char *)loc1;
if (i != 0)
vsetsiz(i);
if (opf == vmove) {
if (state == ONEOPEN || state == HARDOPEN)
outline = destline = WBOT;
if (addr != dot || (unsigned char *)loc1 != cursor)
markDOT();
if (loc1 > (char *)linebuf && *loc1 == 0)
loc1 = (char *)lastchr(linebuf, loc1);
if (c)
vjumpto(addr, (unsigned char *)loc1, c);
else {
vmoving = 0;
if (loc1) {
vmoving++;
vmovcol = column(loc1);
}
getDOT();
if (state == CRTOPEN && addr != dot)
vup1();
vupdown(addr - dot, NOSTR);
}
if (oc == '/') {
if (dot < odot ||
(dot == odot && cursor <= ocurs))
warnf(value(vi_TERSE) ?
gettext("Search wrapped BOTTOM") :
gettext("Search wrapped around BOTTOM of buffer"));
} else {
if (dot > odot ||
(dot == odot && cursor >= ocurs))
warnf(value(vi_TERSE) ?
gettext("Search wrapped TOP") :
gettext("Search wrapped around TOP of buffer"));
}
return;
}
lastcp[-1] = 'n';
getDOT();
wdot = addr;
break;
}
if (vreg && wdot == 0)
wdot = dot;
(*opf)(c);
wdot = NOLINE;
}
static void
lfixol()
{
unsigned char *savevglobp;
int savesplit;
if (Outchar == vputchar)
return;
putnl();
if (inopen > 0 && clr_eol)
vclreol();
if (enter_standout_mode && exit_bold)
putpad((unsigned char *)enter_standout_mode);
lprintf(gettext("[Hit return to continue] "), 0);
if (enter_standout_mode && exit_bold)
putpad((unsigned char *)exit_bold);
savevglobp = vglobp;
vglobp = 0;
getkey();
vglobp = savevglobp;
Outchar = vputchar;
savesplit = splitw;
splitw = 0;
vclear();
vdirty(0, WLINES);
vredraw(WTOP);
splitw = savesplit;
}
void
warnf(char *str, char *cp)
{
int saveline, savecol, savesplit;
saveline = outline;
savecol = outcol;
savesplit = splitw;
splitw = 1;
vgoto(WECHO, 0);
if (!enter_standout_mode || !exit_bold)
dingdong();
if (clr_eol)
vclreol();
if (enter_standout_mode && exit_bold)
putpad((unsigned char *)enter_standout_mode);
lprintf(str, cp);
if (enter_standout_mode && exit_bold)
putpad((unsigned char *)exit_bold);
lfixol();
vgoto(saveline, savecol);
splitw = savesplit;
}
static int
get_addr()
{
short c;
short next;
c = getkey();
next = 0;
switch (c) {
case CTRL('A'):
next = 96;
c = getkey();
break;
case CTRL('B'):
next = 192;
c = getkey();
break;
}
if (c < ' ')
return (-1);
return (next + c - ' ');
}
int
find(wchar_t c)
{
wchar_t wchar;
int length;
for (;;) {
if (edge())
return (0);
if (dir == 1)
wcursor = nextchr(wcursor);
else
wcursor = lastchr(linebuf, wcursor);
if ((length = mbtowc(&wchar, (char *)wcursor,
MULTI_BYTE_MAX)) > 0 && wchar == c)
return (1);
}
}
int
word(int (*op)(), int cnt)
{
int which;
unsigned char *iwc;
line *iwdot = wdot;
wchar_t wchar;
int length;
if (dir == 1) {
iwc = wcursor;
which = wordch(wcursor);
while (wordof(which, wcursor)) {
length = mbtowc(&wchar, (char *)wcursor,
MULTI_BYTE_MAX);
if (length <= 0)
length = 1;
if (cnt == 1 && op != vmove && wcursor[length] == 0) {
wcursor += length;
break;
}
if (!lnext())
return (0);
if (wcursor == linebuf)
break;
}
if (op != (int (*)())vchange || cnt > 1)
while (!margin() && blank()) {
if (!lnext())
return (0);
}
else
if (wcursor == iwc && iwdot == wdot && *iwc)
wcursor = nextchr(wcursor);
if (op == vmove && margin()) {
wcursor = lastchr(linebuf, wcursor);
#ifdef XPG4
if (wcursor < linebuf) {
wcursor = linebuf;
}
#endif
}
} else {
if (!lnext())
return (0);
while (blank())
if (!lnext())
return (0);
if (!margin()) {
which = wordch(wcursor);
while (!margin() && wordof(which, wcursor))
wcursor = lastchr(linebuf, wcursor);
}
#ifdef PRESUNEUC
if (wcursor < linebuf || !wordof(which, wcursor))
wcursor = nextchr(wcursor);
#else
if (wcursor < linebuf)
wcursor++;
else if (!wordof(which, wcursor))
wcursor = nextchr(wcursor);
#endif
}
return (1);
}
int
eend(int (*op)())
{
int which;
if (!lnext())
return (0);
while (blank())
if (!lnext())
return (0);
which = wordch(wcursor);
while (wordof(which, wcursor)) {
if (wcursor[1] == 0) {
wcursor = nextchr(wcursor);
break;
}
if (!lnext())
return (0);
}
if (op == vyankit)
wcursor = lastchr(linebuf, wcursor) + 1;
else if (op != (int (*)())vchange && op != (int (*)())vdelete &&
wcursor > linebuf)
wcursor = lastchr(linebuf, wcursor);
return (1);
}
int
wordof(unsigned char which, unsigned char *wc)
{
#ifdef PRESUNEUC
if (isspace(*wc))
#else
wchar_t z;
(void) mbtowc(&z, (char *)wc, MB_LEN_MAX);
if (iswspace(z))
#endif
return (0);
return (!wdkind || wordch(wc) == which);
}
#ifdef PRESUNEUC
#define SS2 0216
#define SS3 0217
#endif
int
wordch(unsigned char *wc)
{
int length;
wchar_t c;
length = mbtowc(&c, (char *)wc, MULTI_BYTE_MAX);
if (length <= 0)
return (0);
if (length > 1)
#ifndef PRESUNEUC
if (wdwc)
return (*wdwc)(c);
else
#endif
return (length);
#ifndef PRESUNEUC
return (isalpha(*wc) || isdigit(*wc) || *wc == '_');
#else
return (isalpha(c) || isdigit(c) || c == '_');
#endif
}
int
edge(void)
{
if (linebuf[0] == 0)
return (1);
if (dir == 1)
return (*(nextchr(wcursor)) == 0);
else
return (wcursor == linebuf);
}
int
margin(void)
{
return (wcursor < linebuf || wcursor[0] == 0);
}
#ifndef PRESUNEUC
int
blank(void)
{
wchar_t z;
(void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX);
return (iswspace((int)z));
}
#endif