* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)v_paragraph.c 9.1 (Berkeley) 11/9/94";
if (len == 0 || v_isempty(p, len)) { \
* Historic documentation (USD:15-11, 4.2) said that formfeed \
* characters (^L) in the first column delimited paragraphs. \
* The historic vi code mentions formfeed characters, but never \
* implements them. It seems reasonable, do it. \
if (p[0] != '.' || len < 2) \
for (lp = VIP(sp)->ps; *lp != '\0'; lp += 2) \
(lp[1] == ' ' && len == 2 || lp[1] == p[2]) && \
* v_paragraphf -- [count]}
* Move forward count paragraphs.
* Paragraphs are empty lines after text, formfeed characters, or values
* from the paragraph or section options.
enum { P_INTEXT
, P_INBLANK
} pstate
;
recno_t cnt
, lastlno
, lno
;
* If the starting cursor position is at or before any non-blank
* characters in the line, i.e. the movement is cutting all of the
* line's text, the buffer is in line mode. It's a lot easier to
* check here, because we know that the end is going to be the start
* This was historical practice in vi, with a single exception. If
* the paragraph movement was from the start of the last line to EOF,
* then all the characters were deleted from the last line, but the
* line itself remained. If somebody complains, don't pause, don't
* hesitate, just hit them.
if (vp
->m_start
.cno
== 0)
vp
->m_stop
= vp
->m_start
;
if (nonblank(sp
, vp
->m_stop
.lno
, &vp
->m_stop
.cno
))
if (vp
->m_start
.cno
<= vp
->m_stop
.cno
)
/* Figure out what state we're currently in. */
if ((p
= file_gline(sp
, lno
, &len
)) == NULL
)
* If we start in text, we want to switch states
* (2 * N - 1) times, in non-text, (2 * N) times.
cnt
= F_ISSET(vp
, VC_C1SET
) ? vp
->count
: 1;
if (len
== 0 || v_isempty(p
, len
))
if ((p
= file_gline(sp
, ++lno
, &len
)) == NULL
)
if (len
== 0 || v_isempty(p
, len
))
* Non-motion commands move to the end of the range,
* delete and yank stay at the start. Ignore others.
* Adjust the end of the range for motion commands;
* historically, a motion component was to the end of
* the previous line, whereas the movement command was
* to the start of the new "paragraph".
found
: if (ISMOTION(vp
)) {
vp
->m_stop
.lno
= lastlno
;
vp
->m_stop
.cno
= lastlen
? lastlen
- 1 : 0;
vp
->m_final
= vp
->m_start
;
vp
->m_final
= vp
->m_stop
;
* Adjust end of the range for motion commands; EOF is a movement
* sink. The } command historically moved to the end of the last
* line, not the beginning, from any position before the end of the
* last line. It also historically worked on empty files, so we
eof
: if (vp
->m_start
.lno
== lno
|| vp
->m_start
.lno
== lno
- 1) {
if (file_gline(sp
, vp
->m_start
.lno
, &len
) == NULL
) {
if (file_lline(sp
, &lno
))
if (vp
->m_start
.lno
!= 1 || lno
!= 0) {
GETLINE_ERR(sp
, vp
->m_start
.lno
);
if (vp
->m_start
.cno
== (len
? len
- 1 : 0)) {
* Non-motion commands move to the end of the range, delete
* and yank stay at the start. Ignore others.
* If deleting the line (which happens if deleting to EOF), then
* cursor movement is to the first nonblank.
if (ISMOTION(vp
) && ISCMD(vp
->rkp
, 'd')) {
F_SET(vp
, VM_RCM_SETFNB
);
vp
->m_stop
.lno
= lno
- 1;
vp
->m_stop
.cno
= len
? len
- 1 : 0;
vp
->m_final
= ISMOTION(vp
) ? vp
->m_start
: vp
->m_stop
;
* v_paragraphb -- [count]{
* Move backward count paragraphs.
enum { P_INTEXT
, P_INBLANK
} pstate
;
* Check for SOF. The historic vi didn't complain if users hit SOF
* repeatedly, unless it was part of a motion command. There is no
* question but that Emerson's editor of choice was vi.
* The { command historically moved to the beginning of the first
* line if invoked on the first line.
* If the starting cursor position is in the first column (backward
* paragraph movements did NOT historically pay attention to non-blank
* characters) i.e. the movement is cutting the entire line, the buffer
* is in line mode. Cuts from the beginning of the line also did not
* cut the current line, but started at the previous EOL.
* Correct for a left motion component while we're thinking about it.
if (vp
->m_start
.cno
== 0) {
if (vp
->m_start
.lno
== 1) {
if (vp
->m_start
.lno
<= 1)
/* Figure out what state we're currently in. */
if ((p
= file_gline(sp
, lno
, &len
)) == NULL
)
* If we start in text, we want to switch states
* (2 * N - 1) times, in non-text, (2 * N) times.
cnt
= F_ISSET(vp
, VC_C1SET
) ? vp
->count
: 1;
if (len
== 0 || v_isempty(p
, len
))
* If the starting cursor is past the first column,
* the current line is checked for a paragraph.
if ((p
= file_gline(sp
, --lno
, &len
)) == NULL
)
if (len
!= 0 && !v_isempty(p
, len
)) {
/* SOF is a movement sink. */
found
: vp
->m_stop
.lno
= lno
;
* All commands move to the end of the range. (We already
* adjusted the start of the range for motion commands).
vp
->m_final
= vp
->m_stop
;
* Build the paragraph command search pattern.
* The vi paragraph command searches for either a paragraph or
p_len
= (p_p
= O_STR(sp
, O_PARAGRAPHS
)) == NULL
? 0 : strlen(p_p
);
s_len
= (s_p
= O_STR(sp
, O_SECTIONS
)) == NULL
? 0 : strlen(s_p
);
if (p_len
== 0 && s_len
== 0)
MALLOC_RET(sp
, p
, char *, p_len
+ s_len
+ 1);
memmove(p
, p_p
, p_len
+ 1);
memmove(p
+ p_len
, s_p
, s_len
+ 1);