--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/vi/port/ex_voper.c Tue Jun 14 00:00:00 2005 -0700
@@ -0,0 +1,1216 @@
+/*
+ * 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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1981 Regents of the University of California
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#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.
+ */
+operate(c, cnt)
+ register int c, cnt;
+{
+ register wchar_t i;
+ int (*moveop)(), (*deleteop)();
+ register int (*opf)();
+ bool subop = 0;
+ unsigned char *oglobp, *ocurs;
+ register 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 = vdelete;
+ wcursor = cursor;
+ wdot = NOLINE;
+ notecnt = 0;
+ dir = 1;
+ switch (c) {
+
+ /*
+ * d delete operator.
+ */
+ case 'd':
+ moveop = 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 = 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) {
+ 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:
+ 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 */
+ 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, 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(enter_standout_mode);
+ lprintf(gettext("[Hit return to continue] "), 0);
+ if (enter_standout_mode && exit_bold)
+ putpad(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;
+}
+
+warnf(str, cp)
+ char *str, *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(enter_standout_mode);
+ lprintf(str, cp);
+ if (enter_standout_mode && exit_bold)
+ putpad(exit_bold);
+ lfixol();
+ vgoto(saveline, savecol);
+ splitw = savesplit;
+}
+
+/* #ifdef PTR_ADDRESSES */
+/*
+ * read in a row or column address
+ *
+ */
+static int
+get_addr()
+{
+ register short c;
+ register 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.
+ */
+find(c)
+ 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.
+ */
+word(op, cnt)
+ register int (*op)();
+ int cnt;
+{
+ register int which;
+ register unsigned char *iwc;
+ register 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 != 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.
+ */
+eend(op)
+ register int (*op)();
+{
+ register 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 != vchange && op != 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).
+ */
+wordof(which, wc)
+ unsigned char which;
+ register 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 */
+
+wordch(wc)
+ unsigned char *wc;
+{
+ register 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.
+ */
+edge()
+{
+
+ 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.
+ */
+margin()
+{
+
+ 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.
+ */
+blank()
+{
+ wchar_t z;
+
+ (void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX);
+ return (iswspace((int)z));
+}
+#endif /* PRESUNEUC */