ex_voper.c revision f6db9f272f0061301cfaa1c0001b7d636eae31f4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1981 Regents of the University of California
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
#include <regexpr.h>
#ifndef PRESUNEUC
#include <wctype.h>
/* Undef putchar/getchar if they're defined. */
#ifdef putchar
#undef putchar
#endif
#ifdef getchar
#undef getchar
#endif
#endif /* PRESUNEUC */
#ifdef PRESUNEUC
#define blank() isspace(wcursor[0])
#endif /* PRESUNEUC */
#define forbid(a) if (a) goto errlab;
unsigned char vscandir[2] = { '/', 0 };
/*
* Decode an operator/operand type command.
* Eventually we switch to an operator subroutine in ex_vops.c.
* The work here is setting up a function variable to point
* to the routine we want, and manipulation of the variables
* wcursor and wdot, which mark the other end of the affected
* area. If wdot is zero, then the current line is the other end,
* and if wcursor is zero, then the first non-blank location of the
* other line is implied.
*/
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;
/* #ifdef PTR_ADDRESSES */
int mouse_x;
int mouse_y;
int oline;
static int get_addr();
/* #endif PTR_ADDRESSES */
moveop = vmove, deleteop = (int (*)())vdelete;
wcursor = cursor;
wdot = NOLINE;
notecnt = 0;
dir = 1;
switch (c) {
/*
* d delete operator.
*/
case 'd':
moveop = (int (*)())vdelete;
deleteop = beep;
break;
/*
* s substitute characters, like c\040, i.e. change space.
*/
case 's':
ungetkey(' ');
subop++;
/* fall into ... */
/*
* c Change operator.
*/
case 'c':
if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S')
subop++;
moveop = (int (*)())vchange;
deleteop = beep;
break;
/*
* ! Filter through a UNIX command.
*/
case '!':
moveop = vfilter;
deleteop = beep;
break;
/*
* y Yank operator. Place specified text so that it
* can be put back with p/P. Also yanks to named buffers.
*/
case 'y':
moveop = vyankit;
deleteop = beep;
break;
/*
* = Reformat operator (for LISP).
*/
case '=':
forbid(!value(vi_LISP));
/* fall into ... */
/*
* > Right shift operator.
* < Left shift operator.
*/
case '<':
case '>':
moveop = vshftop;
deleteop = beep;
break;
/*
* r Replace character under cursor with single following
* character.
*/
case 'r':
vmacchng(1);
vrep(cnt);
return;
default:
goto nocount;
}
vmacchng(1);
/*
* Had an operator, so accept another count.
* Multiply counts together.
*/
if (isdigit(peekkey()) && peekkey() != '0') {
cnt *= vgetcnt();
Xcnt = cnt;
forbid(cnt <= 0);
}
/*
* Get next character, mapping it and saving as
* part of command for repeat.
*/
c = map(getesc(), arrows, 0);
if (c == 0)
return;
if (!subop)
*lastcp++ = c;
nocount:
opf = moveop;
switch (c) {
/* #ifdef PTR_ADDRESSES */
/*
* ^X^_ Netty Mouse positioning hack
* ^X^]
*/
case CTRL('X'):
/*
* Read in mouse stuff
*/
c = getkey(); /* ^_ or ^] */
if ((c != CTRL('_')) && (c != (CTRL(']'))))
break;
getkey(); /* mouse button */
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;
/*
* Find the line on the screen
*/
for (i = 0; i <= WECHO; i++)
{
if (vlinfo[i].vliny >= mouse_y)
break;
}
if (i > WECHO)
break;
/*
* Look for lines longer than one line - note odd case at zero
*/
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);
}
/*
* Set the line
*/
vsave();
ocurs = cursor;
odot = dot;
oline = vcline;
operate('H', i);
/*
* Set the column
*/
getDOT();
if (Pline == numbline)
mouse_x += 8;
vmovcol = mouse_x;
vmoving = 1;
wcursor = vfindcol(mouse_x);
/*
* Reset everything so that stuff like delete and change work
*/
wdot = (odot - oline) + i - 1;
cursor = ocurs;
vcline = oline;
dot = odot;
getDOT();
break;
/* #endif PTR_ADDRESSES */
/*
* b Back up a word.
* B Back up a word, liberal definition.
*/
case 'b':
case 'B':
dir = -1;
/* fall into ... */
/*
* w Forward a word.
* W Forward a word, liberal definition.
*/
case 'W':
case 'w':
wdkind = c & ' ';
forbid(lfind(2, cnt, opf, (line *)0) < 0);
vmoving = 0;
break;
/*
* E to end of following blank/nonblank word
*/
case 'E':
wdkind = 0;
goto ein;
/*
* e To end of following word.
*/
case 'e':
wdkind = 1;
ein:
forbid(lfind(3, cnt - 1, opf, (line *)0) < 0);
vmoving = 0;
break;
/*
* ( Back an s-expression.
*/
case '(':
dir = -1;
/* fall into... */
/*
* ) Forward an s-expression.
*/
case ')':
forbid(lfind(0, cnt, opf, (line *) 0) < 0);
markDOT();
break;
/*
* { Back an s-expression, but don't stop on atoms.
* In text mode, a paragraph. For C, a balanced set
* of {}'s.
*/
case '{':
dir = -1;
/* fall into... */
/*
* } Forward an s-expression, but don't stop on atoms.
* In text mode, back paragraph. For C, back a balanced
* set of {}'s.
*/
case '}':
forbid(lfind(1, cnt, opf, (line *) 0) < 0);
markDOT();
break;
/*
* % To matching () or {}. If not at ( or { scan for
* first such after cursor on this line.
*/
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;
/*
* [ Back to beginning of defun, i.e. an ( in column 1.
* For text, back to a section macro.
* For C, back to a { in column 1 (~~ beg of function.)
*/
case '[':
dir = -1;
/* fall into ... */
/*
* ] Forward to next defun, i.e. a ( in column 1.
* For text, forward section.
* For C, forward to a } in column 1 (if delete or such)
* or if a move to a { in column 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 /* XPG4 */
i = lbrack(c, opf);
getDOT();
forbid(!i);
markDOT();
if (ospeed > B300)
hold |= HOLDWIG;
break;
/*
* , Invert last find with f F t or T, like inverse
* of ;.
*/
case ',':
forbid(lastFKND == 0);
c = isupper(lastFKND) ? tolower(lastFKND) : toupper(lastFKND);
i = lastFCHR;
if (vglobp == 0)
vglobp = (unsigned char *)"";
subop++;
goto nocount;
/*
* 0 To beginning of real line.
*/
case '0':
wcursor = linebuf;
vmoving = 0;
break;
/*
* ; Repeat last find with f F t or T.
*/
case ';':
forbid(lastFKND == 0);
c = lastFKND;
i = lastFCHR;
subop++;
goto nocount;
/*
* F Find single character before cursor in current line.
* T Like F, but stops before character.
*/
case 'F': /* inverted find */
case 'T':
dir = -1;
/* fall into ... */
/*
* f Find single character following cursor in current line.
* t Like f, but stope before character.
*/
case 'f': /* find */
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;
/*
* | Find specified print column in current line.
*/
case '|':
if (Pline == numbline)
cnt += 8;
vmovcol = cnt;
vmoving = 1;
wcursor = vfindcol(cnt);
break;
/*
* ^ To beginning of non-white space on line.
*/
case '^':
wcursor = vskipwh(linebuf);
vmoving = 0;
break;
/*
* $ To end of line.
*/
case '$':
if (opf == vmove) {
vmoving = 1;
vmovcol = 20000;
} else
vmoving = 0;
if (cnt > 1) {
if (opf == vmove) {
wcursor = 0;
cnt--;
} else
wcursor = linebuf;
/* This is wrong at EOF */
wdot = dot + cnt;
break;
}
if (linebuf[0]) {
wcursor = strend(linebuf);
wcursor = lastchr(linebuf, wcursor);
goto fixup;
}
wcursor = linebuf;
break;
/*
* h Back a character.
* ^H Back a character.
*/
case 'h':
case CTRL('h'):
dir = -1;
/* fall into ... */
/*
* space Forward a character.
*/
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;
/*
* D Delete to end of line, short for d$.
*/
case 'D':
cnt = INF;
goto deleteit;
/*
* X Delete character before cursor.
*/
case 'X':
dir = -1;
/* fall into ... */
deleteit:
/*
* x Delete character at cursor, leaving cursor where it is.
*/
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:
/*
* Stuttered operators are equivalent to the operator on
* a line, thus turn dd into d_.
*/
if (opf == vmove || c != workcmd[0]) {
errlab:
(void) beep();
vmacp = 0;
return;
}
/* fall into ... */
/*
* _ Target for a line or group of lines.
* Stuttering is more convenient; this is mostly
* for aesthetics.
*/
case '_':
wdot = dot + cnt - 1;
vmoving = 0;
wcursor = 0;
break;
/*
* H To first, home line on screen.
* Count is for count'th line rather than first.
*/
case 'H':
wdot = (dot - vcline) + cnt - 1;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
/*
* - Backwards lines, to first non-white character.
*/
case '-':
wdot = dot - cnt;
vmoving = 0;
wcursor = 0;
break;
/*
* ^P To previous line same column. Ridiculous on the
* console of the VAX since it puts console in LSI mode.
*/
case 'k':
case CTRL('p'):
wdot = dot - cnt;
if (vmoving == 0)
vmoving = 1, vmovcol = column(cursor);
wcursor = 0;
break;
/*
* L To last line on screen, or count'th line from the
* bottom.
*/
case 'L':
wdot = dot + vcnt - vcline - cnt;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
/*
* M To the middle of the screen.
*/
case 'M':
wdot = dot + ((vcnt + 1) / 2) - vcline - 1;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
/*
* + Forward line, to first non-white.
*
* CR Convenient synonym for +.
*/
case '+':
case CR:
wdot = dot + cnt;
vmoving = 0;
wcursor = 0;
break;
/*
* ^N To next line, same column if possible.
*
* LF Linefeed is a convenient synonym for ^N.
*/
case CTRL('n'):
case 'j':
case NL:
wdot = dot + cnt;
if (vmoving == 0)
vmoving = 1, vmovcol = column(cursor);
wcursor = 0;
break;
/*
* n Search to next match of current pattern.
*/
case 'n':
vglobp = vscandir;
c = *vglobp++;
goto nocount;
/*
* N Like n but in reverse direction.
*/
case 'N':
vglobp = vscandir[0] == '/' ? (unsigned char *)"?" :
(unsigned char *)"/";
c = *vglobp++;
goto nocount;
/*
* ' Return to line specified by following mark,
* first white position on line.
*
* ` Return to marked line at remembered column.
*/
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();
getline(*wdot);
if (wcursor > strend(linebuf))
wcursor = 0;
else {
cnt = wcursor - linebuf;
/*CSTYLED*/
for (wcursor = linebuf; wcursor - linebuf < cnt; )
wcursor = nextchr(wcursor);
if (wcursor - linebuf > cnt)
wcursor = lastchr(linebuf, wcursor);
}
getDOT();
}
if (ospeed > B300)
hold |= HOLDWIG;
break;
/*
* G Goto count'th line, or last line if no count
* given.
*/
case 'G':
if (!Xhadcnt)
cnt = lineDOL();
wdot = zero + cnt;
forbid(wdot < one || wdot > dol);
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
/*
* / Scan forward for following re.
* ? Scan backward for following re.
*/
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
/*
* Lose typeahead (ick).
*/
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 == ';') {
/* /foo/;/bar/ */
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) {
/* random junk after the pattern */
(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 == '/') { /* forward search */
if (dot < odot ||
(dot == odot && cursor <= ocurs))
warnf(value(vi_TERSE) ?
gettext("Search wrapped BOTTOM") :
gettext("Search wrapped around BOTTOM of buffer"));
} else { /* backward search */
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;
}
/*
* Apply.
*/
if (vreg && wdot == 0)
wdot = dot;
(*opf)(c);
wdot = NOLINE;
}
static void
lfixol()
{
unsigned char *savevglobp;
int savesplit;
if (Outchar == vputchar)
return;
/* Show messages */
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);
/* Get key input for confirmation */
savevglobp = vglobp;
vglobp = 0; /* force typed input */
getkey();
vglobp = savevglobp;
/* reset output function */
Outchar = vputchar;
/* Clean up screen */
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;
}
/* #ifdef PTR_ADDRESSES */
/*
* read in a row or column address
*
*/
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 - ' ');
}
/* #endif PTR_ADDRESSES */
/*
* Find single character c, in direction dir from cursor.
*/
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);
}
}
/*
* Do a word motion with operator op, and cnt more words
* to go after this.
*/
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;
}
/* Unless last segment of a change skip blanks */
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 /* XPG4 */
}
} 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 /* PRESUNEUC */
}
return (1);
}
/*
* To end of word, with operator op and cnt more motions
* remaining after this.
*/
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);
}
/*
* Wordof tells whether the character at *wc is in a word of
* kind which (blank/nonblank words are 0, conservative words 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 /* PRESUNEUC */
return (0);
return (!wdkind || wordch(wc) == which);
}
/*
* Wordch tells whether character at *wc is a word character
* i.e. an alfa, digit, or underscore.
*/
#ifdef PRESUNEUC
#define SS2 0216
#define SS3 0217
#endif /* PRESUNEUC */
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 /* PRESUNEUC */
return (length);
#ifndef PRESUNEUC
return (isalpha(*wc) || isdigit(*wc) || *wc == '_');
#else
return (isalpha(c) || isdigit(c) || c == '_');
#endif /* PRESUNEUC */
}
/*
* Edge tells when we hit the last character in the current line.
*/
int
edge(void)
{
if (linebuf[0] == 0)
return (1);
if (dir == 1)
return (*(nextchr(wcursor)) == 0);
else
return (wcursor == linebuf);
}
/*
* Margin tells us when we have fallen off the end of the line.
*/
int
margin(void)
{
return (wcursor < linebuf || wcursor[0] == 0);
}
#ifndef PRESUNEUC
/*
* Blank tells if the cursor is currently on a TAB, RETURN,
* NEWLINE, FORMFEED, bertical tab, or SPACE character from EUC
* primary and supplementary codesets.
*/
int
blank(void)
{
wchar_t z;
(void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX);
return (iswspace((int)z));
}
#endif /* PRESUNEUC */