/* Copyright (c) 1981 Regents of the University of California */
static char *sccsid
= "@(#)ex_voper.c 7.2 %G%";
#define blank() isspace(wcursor[0])
#define forbid(a) if (a) goto errlab;
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
int (*moveop
)(), (*deleteop
)();
static char lastFKND
, lastFCHR
;
moveop
= vmove
, deleteop
= vdelete
;
* s substitute characters, like c\040, i.e. change space.
if (c
== 'c' && workcmd
[0] == 'C' || workcmd
[0] == 'S')
* ! Filter through a UNIX command.
* y Yank operator. Place specified text so that it
* can be put back with p/P. Also yanks to named buffers.
* = Reformat operator (for LISP).
* > Right shift operator.
* r Replace character under cursor with single following
* Had an operator, so accept another count.
* Multiply counts together.
if (isdigit(peekkey()) && peekkey() != '0') {
* Get next character, mapping it and saving as
* part of command for repeat.
c
= map(getesc(),arrows
);
* B Back up a word, liberal definition.
* W Forward a word, liberal definition.
forbid(lfind(2, cnt
, opf
, 0) < 0);
* E to end of following blank/nonblank word
* e To end of following word.
forbid(lfind(3, cnt
- 1, opf
, 0) < 0);
* ( Back an s-expression.
* ) Forward an s-expression.
forbid(lfind(0, cnt
, opf
, (line
*) 0) < 0);
* { Back an s-expression, but don't stop on atoms.
* In text mode, a paragraph. For C, a balanced set
* } Forward an s-expression, but don't stop on atoms.
* In text mode, back paragraph. For C, back a balanced
forbid(lfind(1, cnt
, opf
, (line
*) 0) < 0);
* % To matching () or {}. If not at ( or { scan for
* first such after cursor on this line.
fprintf(trace
, "after lmatchp in %, dot=%d, wdot=%d, dol=%d\n", lineno(dot
), lineno(wdot
), lineno(dol
));
* [ 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.)
* ] 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.
* , Invert last find with f F t or T, like inverse
c
= isupper(lastFKND
) ? tolower(lastFKND
) : toupper(lastFKND
);
* 0 To beginning of real line.
* ; Repeat last find with f F t or T.
* F Find single character before cursor in current line.
* T Like F, but stops before character.
case 'F': /* inverted find */
* f Find single character following cursor in current line.
* t Like f, but stope before character.
lastFKND
= c
, lastFCHR
= i
;
* | Find specified print column in current line.
* ^ To beginning of non-white space on line.
wcursor
= vskipwh(linebuf
);
/* This is wrong at EOF */
wcursor
= strend(linebuf
) - 1;
* space Forward a character.
forbid (margin() || opf
== vmove
&& edge());
while (cnt
> 0 && !margin())
if (margin() && opf
== vmove
|| wcursor
< linebuf
)
* D Delete to end of line, short for d$.
* X Delete character before cursor.
* x Delete character at cursor, leaving cursor where it is.
while (cnt
> 0 && !margin())
* Stuttered operators are equivalent to the operator on
* a line, thus turn dd into d_.
if (opf
== vmove
|| c
!= workcmd
[0]) {
* _ Target for a line or group of lines.
* Stuttering is more convenient; this is mostly
* H To first, home line on screen.
* Count is for count'th line rather than first.
wdot
= (dot
- vcline
) + cnt
- 1;
* - Backwards lines, to first non-white character.
* ^P To previous line same column. Ridiculous on the
* console of the VAX since it puts console in LSI mode.
vmoving
= 1, vmovcol
= column(cursor
);
* L To last line on screen, or count'th line from the
wdot
= dot
+ vcnt
- vcline
- cnt
;
* M To the middle of the screen.
wdot
= dot
+ ((vcnt
+ 1) / 2) - vcline
- 1;
* + Forward line, to first non-white.
* CR Convenient synonym for +.
* ^N To next line, same column if possible.
* LF Linefeed is a convenient synonym for ^N.
vmoving
= 1, vmovcol
= column(cursor
);
* n Search to next match of current pattern.
* N Like n but in reverse direction.
vglobp
= vscandir
[0] == '/' ? "?" : "/";
* ' Return to line specified by following mark,
* first white position on line.
* ` Return to marked line at remembered column.
wcursor
= d
== '`' ? ncols
[c
- 'a'] : 0;
if (opf
== vmove
&& (wdot
!= dot
|| (d
== '`' && wcursor
!= cursor
)))
if (wcursor
> strend(linebuf
))
* G Goto count'th line, or last line if no count
forbid (wdot
< one
|| wdot
> dol
);
* / Scan forward for following re.
* ? Scan backward for following re.
oglobp
= globp
; CP(vutmp
, genbuf
); globp
= vutmp
;
i
= i
* 10 + *globp
++ - '0';
/* random junk after the pattern */
if (state
== ONEOPEN
|| state
== HARDOPEN
)
outline
= destline
= WBOT
;
if (addr
!= dot
|| loc1
!= cursor
)
if (loc1
> linebuf
&& *loc1
== 0)
if (state
== CRTOPEN
&& addr
!= dot
)
vupdown(addr
- dot
, NOSTR
);
* Find single character c, in direction dir from cursor.
* Do a word motion with operator op, and cnt more words
register line
*iwdot
= wdot
;
while (wordof(which
, wcursor
)) {
if (cnt
== 1 && op
!= vmove
&& wcursor
[1] == 0) {
/* Unless last segment of a change skip blanks */
if (op
!= vchange
|| cnt
> 1)
while (!margin() && blank())
if (wcursor
== iwc
&& iwdot
== wdot
&& *iwc
)
if (op
== vmove
&& margin())
while (!margin() && wordof(which
, wcursor
))
if (wcursor
< linebuf
|| !wordof(which
, wcursor
))
* To end of word, with operator op and cnt more motions
while (wordof(which
, wcursor
)) {
if (op
!= vchange
&& op
!= vdelete
&& wcursor
> linebuf
)
* Wordof tells whether the character at *wc is in a word of
* kind which (blank/nonblank words are 0, conservative words 1).
return (!wdkind
|| wordch(wc
) == which
);
* Wordch tells whether character at *wc is a word character
* i.e. an alfa, digit, or underscore.
return (isalpha(c
) || isdigit(c
) || c
== '_');
* Edge tells when we hit the last character in the current line.
return (wcursor
[1] == 0);
return (wcursor
== linebuf
);
* Margin tells us when we have fallen off the end of the line.
return (wcursor
< linebuf
|| wcursor
[0] == 0);