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
* 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>
#ifdef putchar
#endif
#ifdef getchar
#endif
#endif /* PRESUNEUC */
#ifdef PRESUNEUC
#endif /* PRESUNEUC */
/*
* 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
{
wchar_t i;
int (*opf)();
bool subop = 0;
int oc;
static unsigned char lastFKND;
short d;
/* #ifdef PTR_ADDRESSES */
int mouse_x;
int mouse_y;
int oline;
static int get_addr();
/* #endif PTR_ADDRESSES */
notecnt = 0;
dir = 1;
switch (c) {
/*
* d delete operator.
*/
case 'd':
break;
/*
* s substitute characters, like c\040, i.e. change space.
*/
case 's':
ungetkey(' ');
subop++;
/* fall into ... */
/*
* c Change operator.
*/
case 'c':
subop++;
break;
/*
* ! Filter through a UNIX command.
*/
case '!':
break;
/*
* y Yank operator. Place specified text so that it
* can be put back with p/P. Also yanks to named buffers.
*/
case 'y':
break;
/*
* = Reformat operator (for LISP).
*/
case '=':
/* fall into ... */
/*
* > Right shift operator.
* < Left shift operator.
*/
case '<':
case '>':
break;
/*
* r Replace character under cursor with single following
* character.
*/
case 'r':
vmacchng(1);
return;
default:
goto nocount;
}
vmacchng(1);
/*
* Had an operator, so accept another count.
* Multiply counts together.
*/
}
/*
* Get next character, mapping it and saving as
* part of command for repeat.
*/
if (c == 0)
return;
if (!subop)
*lastcp++ = c;
switch (c) {
/* #ifdef PTR_ADDRESSES */
/*
* ^X^_ Netty Mouse positioning hack
* ^X^]
*/
case CTRL('X'):
/*
* Read in mouse stuff
*/
c = getkey(); /* ^_ or ^] */
break;
getkey(); /* mouse button */
break;
mouse_x -= 8;
if (mouse_x < 0)
mouse_x = 0;
break;
/*
* Find the line on the screen
*/
for (i = 0; i <= WECHO; i++)
{
break;
}
if (i > WECHO)
break;
/*
* Look for lines longer than one line - note odd case at zero
*/
if (i)
{
{
}
}
else
{
}
/*
* Set the line
*/
vsave();
operate('H', i);
/*
* Set the column
*/
getDOT();
mouse_x += 8;
vmoving = 1;
/*
* Reset everything so that stuff like delete and change work
*/
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 & ' ';
vmoving = 0;
break;
/*
*/
case 'E':
wdkind = 0;
goto ein;
/*
* e To end of following word.
*/
case 'e':
wdkind = 1;
ein:
vmoving = 0;
break;
/*
* ( Back an s-expression.
*/
case '(':
dir = -1;
/* fall into... */
/*
* ) Forward an s-expression.
*/
case ')':
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 '}':
markDOT();
break;
/*
* % To matching () or {}. If not at ( or { scan for
* first such after cursor on this line.
*/
case '%':
vsave();
splitw = 0;
vclean();
return;
#ifdef TRACE
if (trace)
#endif
getDOT();
forbid(!i);
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)
#ifndef XPG4
#endif
vsave();
#ifdef XPG4
if (cnt > 1) {
while (cnt-- > 1) {
getDOT();
forbid(!i);
markDOT();
(*opf)(c);
}
}
#endif /* XPG4 */
getDOT();
forbid(!i);
markDOT();
break;
/*
* , Invert last find with f F t or T, like inverse
* of ;.
*/
case ',':
i = lastFCHR;
if (vglobp == 0)
vglobp = (unsigned char *)"";
subop++;
goto nocount;
/*
* 0 To beginning of real line.
*/
case '0':
vmoving = 0;
break;
/*
* ; Repeat last find with f F t or T.
*/
case ';':
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;
(void) beep();
return;
}
i = wchar;
}
if (vglobp == 0)
vmoving = 0;
switch (c) {
case 'T':
break;
case 't':
case 'f':
break;
}
break;
/*
* | Find specified print column in current line.
*/
case '|':
cnt += 8;
vmoving = 1;
break;
/*
* ^ To beginning of non-white space on line.
*/
case '^':
vmoving = 0;
break;
/*
* $ To end of line.
*/
case '$':
vmoving = 1;
vmovcol = 20000;
} else
vmoving = 0;
if (cnt > 1) {
wcursor = 0;
cnt--;
} else
/* This is wrong at EOF */
break;
}
if (linebuf[0]) {
goto fixup;
}
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 ' ':
if (dir == 1)
else
cnt--;
}
if (dir == 1)
else
}
vmoving = 0;
break;
/*
* D Delete to end of line, short for d$.
*/
case 'D':
goto deleteit;
/*
* X Delete character before cursor.
*/
case 'X':
dir = -1;
/* fall into ... */
/*
* x Delete character at cursor, leaving cursor where it is.
*/
case 'x':
if (margin())
goto errlab;
vmacchng(1);
if (dir == 1)
else
cnt--;
}
vmoving = 0;
break;
default:
/*
* Stuttered operators are equivalent to the operator on
* a line, thus turn dd into d_.
*/
(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 '_':
vmoving = 0;
wcursor = 0;
break;
/*
* H To first, home line on screen.
* Count is for count'th line rather than first.
*/
case 'H':
vmoving = 0;
wcursor = 0;
break;
/*
* - Backwards lines, to first non-white character.
*/
case '-':
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'):
if (vmoving == 0)
wcursor = 0;
break;
/*
* L To last line on screen, or count'th line from the
* bottom.
*/
case 'L':
vmoving = 0;
wcursor = 0;
break;
/*
* M To the middle of the screen.
*/
case 'M':
vmoving = 0;
wcursor = 0;
break;
/*
* + Forward line, to first non-white.
*
* CR Convenient synonym for +.
*/
case '+':
case CR:
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:
if (vmoving == 0)
wcursor = 0;
break;
/*
* n Search to next match of current pattern.
*/
case 'n':
c = *vglobp++;
goto nocount;
/*
* N Like n but in reverse direction.
*/
case 'N':
(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);
vmoving = 0;
markDOT();
if (wcursor) {
vsave();
wcursor = 0;
else {
/*CSTYLED*/
}
getDOT();
}
break;
/*
* G Goto count'th line, or last line if no count
* given.
*/
case 'G':
if (!Xhadcnt)
vmoving = 0;
wcursor = 0;
break;
/*
* / Scan forward for following re.
* ? Scan backward for following re.
*/
case '/':
case '?':
vsave();
oc = c;
wcursor = 0;
if (readecho(c))
return;
if (!vglobp)
d = peekc;
ungetchar(0);
fixech();
#ifndef CBREAK
/*
* Lose typeahead (ick).
*/
vcook();
#endif
#ifndef CBREAK
vraw();
#endif
#ifndef CBREAK
vraw();
#endif
ungetchar(d);
splitw = 0;
vclean();
return;
if (globp == 0)
globp = (unsigned char *)"";
else if (peekc)
--globp;
if (*globp == ';') {
/* /foo/;/bar/ */
globp++;
goto fromsemi;
}
ungetchar(d);
c = 0;
if (*globp == 'z')
globp++, c = '\n';
c = *globp++;
i = 0;
c = *globp++;
if (*globp) {
/* random junk after the pattern */
(void) beep();
goto slerr;
}
splitw = 0;
vmoving = 0;
if (i != 0)
vsetsiz(i);
markDOT();
if (c)
else {
vmoving = 0;
if (loc1) {
vmoving++;
}
getDOT();
vup1();
}
gettext("Search wrapped BOTTOM") :
gettext("Search wrapped around BOTTOM of buffer"));
} else { /* backward search */
gettext("Search wrapped TOP") :
gettext("Search wrapped around TOP of buffer"));
}
return;
}
getDOT();
break;
}
/*
* Apply.
*/
(*opf)(c);
}
static void
lfixol()
{
unsigned char *savevglobp;
int savesplit;
return;
/* Show messages */
putnl();
vclreol();
if (enter_standout_mode && exit_bold)
putpad((unsigned char *)enter_standout_mode);
if (enter_standout_mode && exit_bold)
/* Get key input for confirmation */
savevglobp = vglobp;
vglobp = 0; /* force typed input */
getkey();
vglobp = savevglobp;
/* reset output function */
/* Clean up screen */
splitw = 0;
vclear();
}
void
{
splitw = 1;
if (!enter_standout_mode || !exit_bold)
dingdong();
if (clr_eol)
vclreol();
if (enter_standout_mode && exit_bold)
putpad((unsigned char *)enter_standout_mode);
if (enter_standout_mode && exit_bold)
lfixol();
}
/* #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
{
int length;
for (;;) {
if (edge())
return (0);
if (dir == 1)
else
MULTI_BYTE_MAX)) > 0 && wchar == c)
return (1);
}
}
/*
* Do a word motion with operator op, and cnt more words
* to go after this.
*/
int
{
int which;
unsigned char *iwc;
int length;
if (dir == 1) {
if (length <= 0)
length = 1;
break;
}
if (!lnext())
return (0);
break;
}
/* Unless last segment of a change skip blanks */
if (!lnext())
return (0);
}
else
#ifdef XPG4
}
#endif /* XPG4 */
}
} else {
if (!lnext())
return (0);
while (blank())
if (!lnext())
return (0);
if (!margin()) {
}
#ifdef PRESUNEUC
#else
wcursor++;
#endif /* PRESUNEUC */
}
return (1);
}
/*
* To end of word, with operator op and cnt more motions
* remaining after this.
*/
int
{
int which;
if (!lnext())
return (0);
while (blank())
if (!lnext())
return (0);
if (wcursor[1] == 0) {
break;
}
if (!lnext())
return (0);
}
return (1);
}
/*
* Wordof tells whether the character at *wc is in a word of
*/
int
{
#ifdef PRESUNEUC
#else
wchar_t z;
if (iswspace(z))
#endif /* PRESUNEUC */
return (0);
}
/*
* 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
{
int length;
wchar_t c;
if (length <= 0)
return (0);
if (length > 1)
#ifndef PRESUNEUC
if (wdwc)
return (*wdwc)(c);
else
#endif /* PRESUNEUC */
return (length);
#ifndef PRESUNEUC
#else
#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)
else
}
/*
* Margin tells us when we have fallen off the end of the line.
*/
int
margin(void)
{
}
#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;
return (iswspace((int)z));
}
#endif /* PRESUNEUC */