#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
#ifndef PRESUNEUC
#include <wctype.h>
#ifdef putchar
# undef putchar
#endif
#ifdef getchar
# undef getchar
#endif
#endif
extern size_t strlcpy(char *, const char *, size_t);
extern unsigned char *vUA1, *vUA2;
extern unsigned char *vUD1, *vUD2;
#ifdef XPG6
extern int redisplay;
#endif
int vmaxrep(unsigned char, int);
static void imultlinerep(int, line *, int, int);
static void omultlinerep(int, line *, int);
#ifdef XPG6
static void rmultlinerep(int, int);
#endif
void fixdisplay(void);
void
bleep(int i, unsigned char *cp)
{
i -= lcolumn(nextchr(cp));
do
putchar('\\' | QUOTE);
while (--i >= 0);
rubble = 1;
}
int
vdcMID(void)
{
unsigned char *cp;
squish();
setLAST();
if (FIXUNDO)
vundkind = VCHNG, CP(vutmp, linebuf);
if (wcursor < cursor)
cp = wcursor, wcursor = cursor, cursor = cp;
vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
fixundo();
return (lcolumn(wcursor));
}
void
takeout(unsigned char *BUF)
{
unsigned char *cp;
if (wcursor < linebuf)
wcursor = linebuf;
if (cursor == wcursor) {
(void) beep();
return;
}
if (wcursor < cursor) {
cp = wcursor;
wcursor = cursor;
cursor = cp;
}
setBUF(BUF);
if ((unsigned char)BUF[128] == 0200)
(void) beep();
}
int
ateopr(void)
{
wchar_t i, c;
wchar_t *cp = vtube[destline] + destcol;
for (i = WCOLS - destcol; i > 0; i--) {
c = *cp++;
if (c == 0) {
if (destline == WECHO && destcol < WCOLS-11 && vtube[WECHO][WCOLS-20])
return 0;
return (1);
}
if (c != ' ' && (c & QUOTE) == 0)
return (0);
}
return (1);
}
bool vaifirst;
bool gobbled;
unsigned char *ogcursor;
static int INSCDCNT;
static int inscdcnt;
void
vappend(int ch, int cnt, int indent)
{
int i;
unsigned char *gcursor;
bool escape;
int repcnt, savedoomed;
short oldhold = hold;
int savecnt = cnt;
line *startsrcline;
int startsrccol, endsrccol;
int gotNL = 0;
int imultlinecnt = 0;
int omultlinecnt = 0;
if ((savecnt > 1) && (ch == 'o' || ch == 'O')) {
omultlinecnt = 1;
}
#ifdef XPG6
if ((savecnt > 1) && (ch == 'a' || ch == 'A' || ch == 'i' || ch == 'I'))
imultlinecnt = 1;
#endif
if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
rubble = 1;
gcursor = cursor;
i = *gcursor;
*gcursor = ' ';
wcursor = gcursor;
(void) vmove();
*gcursor = i;
}
vaifirst = indent == 0;
if (ch == 'r')
repcnt = 2;
else
repcnt = 0;
if (value(vi_AUTOINDENT) && indent != 0) {
unsigned char x;
gcursor = genindent(indent);
*gcursor = 0;
vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
} else {
gcursor = genbuf;
*gcursor = 0;
if (ch == 'o')
vfixcurs();
}
vUA1 = vUA2 = cursor;
switch (ch) {
case 'r':
break;
case 'a':
if (value(vi_TERSE)) {
vshowmode(gettext("A"));
} else {
vshowmode(gettext("APPEND MODE"));
}
break;
case 's':
if (value(vi_TERSE)) {
vshowmode(gettext("S"));
} else {
vshowmode(gettext("SUBSTITUTE MODE"));
}
break;
case 'c':
if (value(vi_TERSE)) {
vshowmode(gettext("C"));
} else {
vshowmode(gettext("CHANGE MODE"));
}
break;
case 'R':
if (value(vi_TERSE)) {
vshowmode(gettext("R"));
} else {
vshowmode(gettext("REPLACE MODE"));
}
break;
case 'o':
if (value(vi_TERSE)) {
vshowmode(gettext("O"));
} else {
vshowmode(gettext("OPEN MODE"));
}
break;
case 'i':
if (value(vi_TERSE)) {
vshowmode(gettext("I"));
} else {
vshowmode(gettext("INSERT MODE"));
}
break;
default:
if (value(vi_TERSE)) {
vshowmode(gettext("I"));
} else {
vshowmode(gettext("INPUT MODE"));
}
}
ixlatctl(1);
if ((vglobp && *vglobp == 0) || peekbr()) {
if (INS[128] == 0200) {
(void) beep();
if (!splitw)
ungetkey('u');
doomed = 0;
hold = oldhold;
return;
}
vglobp = INS;
inscdcnt = INSCDCNT;
hold |= HOLDQIK;
} else if (vglobp == 0) {
INS[0] = 0;
INS[128] = 0;
INSCDCNT = 0;
}
gobblebl = 0;
startsrcline = dot;
startsrccol = cursor - linebuf;
if (*cursor == 0 || state == CRTOPEN)
hold |= HOLDROL;
for (;;) {
if (ch == 'r' && repcnt == 0)
escape = 0;
else {
ixlatctl(1);
gcursor = vgetline(repcnt, gcursor, &escape, ch);
if (escape == '\n') {
gotNL = 1;
#ifdef XPG6
if (ch == 'r') {
endsrccol = gcursor - genbuf - 1;
}
#endif
} else {
endsrccol = gcursor - genbuf - 1;
}
ixlatctl(0);
if (HADUP)
addtext("^");
else if (HADZERO)
addtext("0");
if(!vglobp)
INSCDCNT = CDCNT;
while (CDCNT > 0) {
addtext("\004");
CDCNT--;
}
if (gobbled)
addtext(" ");
addtext(ogcursor);
}
repcnt = 0;
if (!vaifirst && value(vi_AUTOINDENT)) {
i = fixindent(indent);
if (!HADUP)
indent = i;
gcursor = strend(genbuf);
}
if ((imultlinecnt && gotNL) || omultlinecnt) {
cnt = 1;
}
cnt = vmaxrep(ch, cnt);
CP(gcursor + 1, cursor);
do {
CP(cursor, genbuf);
if (cnt > 1) {
int oldhold = hold;
Outchar = vinschar;
hold |= HOLDQIK;
viprintf("%s", genbuf);
hold = oldhold;
Outchar = vputchar;
}
cursor += gcursor - genbuf;
} while (--cnt > 0);
endim();
vUA2 = cursor;
if (escape != '\n')
CP(cursor, gcursor + 1);
if (state != HARDOPEN) {
DEPTH(vcline) = 0;
savedoomed = doomed;
if (doomed > 0) {
int cind = cindent();
physdc(cind, cind + doomed);
doomed = 0;
}
if(MB_CUR_MAX > 1)
rewrite = _ON;
i = vreopen(LINE(vcline), lineDOT(), vcline);
if(MB_CUR_MAX > 1)
rewrite = _OFF;
#ifdef TRACE
if (trace)
fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
#endif
if (ch == 'R')
doomed = savedoomed;
}
if (escape != '\n') {
vshowmode("");
break;
}
killU();
addtext(gobblebl ? " " : "\n");
vsave();
cnt = 1;
if (value(vi_AUTOINDENT)) {
if (value(vi_LISP))
indent = lindent(dot + 1);
else
if (!HADUP && vaifirst)
indent = whitecnt(linebuf);
vaifirst = 0;
strcLIN(vpastwh(gcursor + 1));
gcursor = genindent(indent);
*gcursor = 0;
if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
gcursor = genbuf;
CP(gcursor, linebuf);
} else {
CP(genbuf, gcursor + 1);
gcursor = genbuf;
}
if (FIXUNDO && vundkind == VCHNG) {
vremote(1, yank, 0);
undap1--;
}
vdoappend(genbuf);
vundkind = VMANYINS;
vcline++;
if (state != VISUAL)
vshow(dot, NOLINE);
else {
i += LINE(vcline - 1);
vopen(dot, i);
if (value(vi_SLOWOPEN))
vscrap();
else
vsync1(LINE(vcline));
}
switch (ch) {
case 'r':
break;
case 'a':
if (value(vi_TERSE)) {
vshowmode(gettext("A"));
} else {
vshowmode(gettext("APPEND MODE"));
}
break;
case 's':
if (value(vi_TERSE)) {
vshowmode(gettext("S"));
} else {
vshowmode(gettext("SUBSTITUTE MODE"));
}
break;
case 'c':
if (value(vi_TERSE)) {
vshowmode(gettext("C"));
} else {
vshowmode(gettext("CHANGE MODE"));
}
break;
case 'R':
if (value(vi_TERSE)) {
vshowmode(gettext("R"));
} else {
vshowmode(gettext("REPLACE MODE"));
}
break;
case 'i':
if (value(vi_TERSE)) {
vshowmode(gettext("I"));
} else {
vshowmode(gettext("INSERT MODE"));
}
break;
case 'o':
if (value(vi_TERSE)) {
vshowmode(gettext("O"));
} else {
vshowmode(gettext("OPEN MODE"));
}
break;
default:
if (value(vi_TERSE)) {
vshowmode(gettext("I"));
} else {
vshowmode(gettext("INPUT MODE"));
}
}
strcLIN(gcursor);
*gcursor = 0;
cursor = linebuf;
vgotoCL(nqcolumn(cursor - 1, genbuf));
}
if (imultlinecnt && gotNL) {
imultlinerep(savecnt, startsrcline, startsrccol, endsrccol);
} else if (omultlinecnt) {
omultlinerep(savecnt, startsrcline, endsrccol);
#ifdef XPG6
} else if (savecnt > 1 && ch == 'r' && gotNL) {
endsrccol = gcursor - genbuf - 1;
rmultlinerep(savecnt, endsrccol);
#endif
}
hold = oldhold;
if ((imultlinecnt && gotNL) || omultlinecnt) {
fixdisplay();
#ifdef XPG6
} else if (savecnt > 1 && ch == 'r' && gotNL) {
fixdisplay();
redisplay = 1;
#endif
} else if (cursor > linebuf) {
cursor = lastchr(linebuf, cursor);
#ifdef XPG6
if (ch == 'r' && gotNL && isblank((int)*cursor))
++cursor;
#endif
}
if (state != HARDOPEN)
vsyncCL();
else if (cursor > linebuf)
back1();
doomed = 0;
wcursor = cursor;
(void) vmove();
}
static void
imultlinerep(int savecnt, line *startsrcline, int startsrccol, int endsrccol)
{
int tmpcnt = 2;
line *srcline, *endsrcline;
size_t destsize = LBSIZE - endsrccol - 1;
endsrcline = dot;
vsave();
--dot;
--vcline;
(void) strlcpy((char *)genbuf, (char *)linebuf, sizeof (genbuf));
getaline(*startsrcline);
if (strlcpy((char *)(genbuf + endsrccol + 1),
(char *)(linebuf + startsrccol), destsize) >= destsize) {
error(gettext("Line too long"));
}
vdoappend(genbuf);
vcline++;
++startsrcline;
while (tmpcnt <= savecnt) {
for (srcline = startsrcline; srcline <= endsrcline;
++srcline) {
if ((tmpcnt == savecnt) &&
(srcline == endsrcline)) {
vcline++;
dot++;
getDOT();
cursor = linebuf + endsrccol;
} else {
getaline(*srcline);
vdoappend(linebuf);
vcline++;
}
}
++tmpcnt;
}
}
static void
omultlinerep(int savecnt, line *startsrcline, int endsrccol)
{
int tmpcnt = 2;
line *srcline, *endsrcline;
endsrcline = dot;
vsave();
while (tmpcnt <= savecnt) {
for (srcline = startsrcline; srcline <= endsrcline; ++srcline) {
getaline(*srcline);
vdoappend(linebuf);
vcline++;
}
++tmpcnt;
}
cursor = linebuf + endsrccol;
}
#ifdef XPG6
static void
rmultlinerep(int savecnt, int endsrccol)
{
int tmpcnt = 2;
vsave();
--dot;
--vcline;
while (tmpcnt <= savecnt) {
linebuf[0] = '\0';
vdoappend(linebuf);
vcline++;
++tmpcnt;
}
++dot;
++vcline;
vcursaft(linebuf + endsrccol);
}
#endif
void
fixdisplay(void)
{
vclear();
vdirty(0, vcnt);
if (state != VISUAL) {
vclean();
vcnt = 0;
vmoveto(dot, cursor, 0);
} else {
vredraw(WTOP);
vrepaint(cursor);
vfixcurs();
}
}
void
back1(void)
{
vgoto(destline - 1, WCOLS + destcol - 1);
}
unsigned char *
vgetline(cnt, gcursor, aescaped, commch)
int cnt;
unsigned char *gcursor;
bool *aescaped;
unsigned char commch;
{
int c, ch;
unsigned char *cp, *pcp;
int x, y, iwhite, backsl=0;
unsigned char *iglobp;
int (*OO)() = Outchar;
int length, width;
unsigned char multic[MULTI_BYTE_MAX+1];
wchar_t wchar = 0;
unsigned char *p;
int len;
*aescaped = 0;
ogcursor = gcursor;
flusho();
CDCNT = 0;
HADUP = 0;
HADZERO = 0;
gobbled = 0;
iwhite = whitecnt(genbuf);
iglobp = vglobp;
abbrepcnt = 0;
if (splitw)
Outchar = vputchar;
else {
Outchar = vinschar;
vprepins();
}
for (;;) {
length = 0;
backsl = 0;
if (gobblebl)
gobblebl--;
if (cnt != 0) {
cnt--;
if (cnt == 0)
goto vadone;
}
c = getkey();
if (c != ATTN)
c &= 0377;
ch = c;
maphopcnt = 0;
if (vglobp == 0 && Peekkey == 0 && commch != 'r')
while ((ch = map(c, immacs, commch)) != c) {
c = ch;
if (!value(vi_REMAP))
break;
if (++maphopcnt > 256)
error(gettext("Infinite macro loop"));
}
if (!iglobp) {
if (c == tty.c_cc[VERASE])
c = CTRL('h');
else if (c == tty.c_cc[VKILL])
c = -1;
switch (c) {
case ATTN:
case QUIT:
ungetkey(c);
goto vadone;
case CTRL('h'):
bakchar:
cp = lastchr(ogcursor, gcursor);
if (cp < ogcursor) {
if (splitw) {
ungetkey(c);
goto vadone;
}
(void) beep();
continue;
}
goto vbackup;
case CTRL('w'):
wdkind = 1;
for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
continue;
pcp = lastchr(ogcursor, cp);
for (c = wordch(pcp);
cp > ogcursor && wordof(c, pcp); cp = pcp, pcp = lastchr(ogcursor, cp))
continue;
goto vbackup;
case -1:
cp = ogcursor;
vbackup:
if (cp == gcursor) {
(void) beep();
continue;
}
endim();
*cp = 0;
c = cindent();
vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
if (doomed >= 0)
doomed += c - cindent();
gcursor = cp;
continue;
case '\\':
x = destcol, y = destline;
putchar('\\');
vcsync();
c = getkey();
if (c == tty.c_cc[VERASE]
|| c == tty.c_cc[VKILL])
{
vgoto(y, x);
if (doomed >= 0)
doomed++;
multic[0] = wchar = c;
length = 1;
goto def;
}
ungetkey(c), c = '\\';
backsl = 1;
break;
case CTRL('q'):
case CTRL('v'):
x = destcol, y = destline;
putchar('^');
vgoto(y, x);
c = getkey();
#ifdef USG
if (c == ATTN)
c = tty.c_cc[VINTR];
#endif
if (c != NL) {
if (doomed >= 0)
doomed++;
multic[0] = wchar = c;
length = 1;
goto def;
}
break;
}
}
if(!backsl) {
ungetkey(c);
if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
(void) beep();
continue;
}
} else {
length = 1;
multic[0] = '\\';
}
if (c != NL && !splitw) {
if (c == ' ' && gobblebl) {
gobbled = 1;
continue;
}
if ((width = wcwidth(wchar)) <= 0)
width = (wchar <= 0177 ? 1 : 4);
if (value(vi_WRAPMARGIN) &&
(outcol + width - 1 >= OCOLUMNS - value(vi_WRAPMARGIN) ||
backsl && outcol==0) &&
commch != 'r') {
unsigned char *wp;
int bytelength;
#ifndef PRESUNEUC
unsigned char *tgcursor;
wchar_t wc1, wc2;
tgcursor = gcursor;
#endif
wdkind = 1;
strncpy(gcursor, multic, length);
gcursor += length;
if (backsl) {
#ifdef PRESUNEUC
if((length = mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
#else
if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
#endif
(void) beep();
continue;
}
strncpy(gcursor, multic, length);
gcursor += length;
}
*gcursor = 0;
for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
;
#ifdef PRESUNEUC
width = 0;
for(wp = cp; *wp; )
#else
width = 0;
for(wp = tgcursor; wp < cp;)
#endif
if((bytelength = mbtowc(&wchar, (char *)wp, MULTI_BYTE_MAX)) < 0) {
width+=4;
wp++;
} else {
int curwidth = wcwidth(wchar);
if(curwidth <= 0)
width += (*wp < 0200 ? 2 : 4);
else
width += curwidth;
wp += bytelength;
}
#ifdef PRESUNEUC
if (outcol+(backsl?OCOLUMNS:0) - width >= OCOLUMNS - value(vi_WRAPMARGIN)) {
#else
if (outcol+(backsl?OCOLUMNS:0) + width -1 >= OCOLUMNS - value(vi_WRAPMARGIN)) {
#endif
#ifdef PRESUNEUC
for (; cp>ogcursor && !isspace(cp[-1]); cp--)
;
#else
wc1 = wc2 = 0;
while (cp>ogcursor) {
if (isspace(cp[-1])) {
break;
}
if (!multibyte) {
cp--;
continue;
}
wp = (unsigned char *)(cp -
MB_CUR_MAX);
if (wp < ogcursor)
wp = ogcursor;
while (cp > wp) {
if (wc2) {
if ((bytelength = mbtowc(&wc1, (char *)wp, cp-wp)) != cp-wp) {
wp++;
wc1 = 0;
continue;
}
} else {
if ((bytelength = mbtowc(&wc2, (char *)wp, cp-wp)) != cp-wp) {
wp++;
wc2 = 0;
continue;
}
}
if (wc1) {
if (wdbdg && (!iswascii(wc1) || !iswascii(wc2))) {
if ((*wdbdg)(wc1, wc2, 2) < 5) {
goto ws;
}
}
wc2 = wc1;
wc1 = 0;
cp -= bytelength - 1;
break;
} else {
cp -= bytelength - 1;
break;
}
}
cp--;
}
ws:
#endif
if (cp <= ogcursor) {
gcursor -= length;
c = *gcursor;
*gcursor = 0;
(void) beep();
goto dontbreak;
}
macpush(cp, 0);
#ifdef PRESUNEUC
cp--;
#endif
}
macpush("\n", 0);
while (cp > ogcursor && isspace(cp[-1]))
cp--;
gobblebl = 3;
goto vbackup;
}
dontbreak:;
}
if (anyabbrs && gcursor > ogcursor && !wordch(multic) && wordch(lastchr(ogcursor, gcursor))) {
int wdtype, abno;
multic[length] = 0;
wdkind = 1;
cp = lastchr(ogcursor, gcursor);
pcp = lastchr(ogcursor, cp);
for (wdtype = wordch(pcp);
cp > ogcursor && wordof(wdtype, pcp); cp = pcp, pcp = lastchr(ogcursor, pcp))
;
*gcursor = 0;
for (abno=0; abbrevs[abno].mapto; abno++) {
if (eq(cp, abbrevs[abno].cap)) {
if(abbrepcnt == 0) {
if(reccnt(abbrevs[abno].cap, abbrevs[abno].mapto))
abbrepcnt = 1;
macpush(multic, 0);
macpush(abbrevs[abno].mapto);
goto vbackup;
} else
abbrepcnt = 0;
}
}
}
switch (c) {
case CR:
if (vglobp) {
multic[0] = wchar = c;
length = 1;
goto def;
}
c = '\n';
case NL:
*aescaped = c;
goto vadone;
case ESCAPE:
if (lastvgk) {
multic[0] = wchar = c;
length = 1;
goto def;
}
goto vadone;
case CTRL('t'):
if (vglobp) {
multic[0] = wchar = c;
length = 1;
goto def;
}
*gcursor = 0;
cp = vpastwh(genbuf);
c = whitecnt(genbuf);
if (ch == CTRL('t')) {
if (cp != gcursor)
continue;
cp = genindent(iwhite = backtab(c + value(vi_SHIFTWIDTH) + 1));
ogcursor = cp;
goto vbackup;
}
case CTRL('d'):
if(vglobp && inscdcnt <= 0) {
multic[0] = wchar = c;
length = 1;
goto def;
}
if(vglobp)
inscdcnt--;
*gcursor = 0;
cp = vpastwh(genbuf);
c = whitecnt(genbuf);
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')) {
HADZERO = *cp == '0';
ogcursor = cp = genbuf;
HADUP = 1 - HADZERO;
CDCNT = 1;
endim();
back1();
(void) vputchar(' ');
goto vbackup;
}
if (vglobp && vglobp - iglobp >= 2) {
if ((p = vglobp - MB_CUR_MAX) < iglobp)
p = iglobp;
for ( ; p < &vglobp[-2]; p += len) {
if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0)
len = 1;
}
if ((p == &vglobp[-2]) &&
(*p == '^' || *p == '0') &&
gcursor == ogcursor + 1)
goto bakchar;
}
continue;
default:
if (!vglobp && junk(c)) {
(void) beep();
continue;
}
def:
if (!backsl) {
putchar(wchar);
flush();
}
if (gcursor + length - 1 > &genbuf[LBSIZE - 2])
error(gettext("Line too long"));
(void)strncpy(gcursor, multic, length);
gcursor += length;
vcsync();
if (value(vi_SHOWMATCH) && !iglobp)
if (c == ')' || c == '}')
lsmatch(gcursor);
continue;
}
}
vadone:
*gcursor = 0;
if (Outchar != termchar)
Outchar = OO;
endim();
return (gcursor);
}
int vgetsplit();
unsigned char *vsplitpt;
void
vdoappend(unsigned char *lp)
{
int oing = inglobal;
vsplitpt = lp;
inglobal = 1;
(void)append(vgetsplit, dot);
inglobal = oing;
}
int
vgetsplit(void)
{
if (vsplitpt == 0)
return (EOF);
strcLIN(vsplitpt);
vsplitpt = 0;
return (0);
}
int
vmaxrep(unsigned char ch, int cnt)
{
int len;
unsigned char *cp;
int repcnt, oldcnt, replen;
if (cnt > LBSIZE - 2)
cnt = LBSIZE - 2;
if (ch == 'R') {
len = strlen(cursor);
oldcnt = 0;
for(cp = cursor; *cp; ) {
oldcnt++;
cp = nextchr(cp);
}
repcnt = 0;
for(cp = genbuf; *cp; ) {
repcnt++;
cp = nextchr(cp);
}
if(repcnt < oldcnt) {
for(cp = cursor; repcnt > 0; repcnt--)
cp = nextchr(cp);
len = cp - cursor;
}
CP(cursor, cursor + len);
vUD2 += len;
}
len = strlen(linebuf);
replen = strlen(genbuf);
if (len + cnt * replen <= LBSIZE - 2)
return (cnt);
cnt = (LBSIZE - 2 - len) / replen;
if (cnt == 0) {
vsave();
error(gettext("Line too long"));
}
return (cnt);
}
int
reccnt(unsigned char *cap, unsigned char *mapto)
{
int i, cnt, final;
cnt = 0;
final = strlen(mapto) - strlen(cap);
for (i=0; i <= final; i++)
if ((strncmp(cap, mapto+i, strlen(cap)) == 0)
&& (i == 0 || !wordch(&mapto[i-1]))
&& (i == final || !wordch(&mapto[i+strlen(cap)])))
cnt++;
return (cnt);
}