4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 /* Copyright (c) 1981 Regents of the University of California */
37 * Routines to handle structure.
38 * Operations supported are:
41 * These cover: LISP TEXT
42 * ( ) s-exprs sentences
43 * { } list at same paragraphs
46 * { and } for C used to attempt to do something with matching {}'s, but
47 * I couldn't find definitions which worked intuitively very well, so I
50 * The code here is very hard to understand.
62 * Find over structure, repeated count times.
63 * Don't go past line limit. F is the operation to
64 * be performed eventually. If pastatom then the user said {}
65 * rather than (), implying past atoms in a list (or a paragraph
66 * rather than a sentence.
69 lfind(pastatom
, cnt
, f
, limit
)
76 unsigned char save
[LBSIZE
];
79 * Initialize, saving the current line buffer state
80 * and computing the limit; a 0 argument means
81 * directional end of file.
85 strcpy(save
, linebuf
);
87 limit
= dir
< 0 ? one
: dol
;
95 while(eend(f
) && cnt
-- > 0) {
99 while (cnt
> 0 && word(f
, cnt
))
105 if (cursor
== wcursor
)
109 else if (!value(vi_LISP
)) {
110 unsigned char *icurs
;
113 if (linebuf
[0] == 0) {
117 while (linebuf
[0] == 0);
123 * If looking for sentence, next line
137 * Advance so as to not find same thing again.
158 * Count times find end of sentence/paragraph.
162 while (!endsent(pastatom
))
165 if (!pastatom
|| wcursor
== linebuf
&& endPS())
168 if (linebuf
[0] == 0) {
172 while (linebuf
[0] == 0);
179 * If going backwards, and didn't hit the end of the buffer,
180 * then reverse direction.
182 if (dir
< 0 && (wdot
!= llimit
|| wcursor
!= linebuf
)) {
186 * Empty line needs special treatement.
187 * If moved to it from other than beginning of next line,
188 * then a sentence starts on next line.
190 if (linebuf
[0] == 0 && !pastatom
&&
191 (wdot
!= dot
- 1 || cursor
!= linebuf
)) {
198 * If we are not at a section/paragraph division,
201 if (wcursor
== icurs
&& wdot
== idot
|| wcursor
!= linebuf
|| !endPS())
207 * Startup by skipping if at a ( going left or a ) going
208 * right to keep from getting stuck immediately.
210 if (dir
< 0 && c
== '(' || dir
> 0 && c
== ')') {
217 * Now chew up repetition count. Each time around
218 * if at the beginning of an s-exp (going forwards)
219 * or the end of an s-exp (going backwards)
220 * skip the s-exp. If not at beg/end resp, then stop
221 * if we hit a higher level paren, else skip an atom,
222 * counting it unless pastatom.
226 if (dir
< 0 && c
== ')' || dir
> 0 && c
== '(') {
230 * Unless this is the last time going
231 * backwards, skip past the matching paren
232 * so we don't think it is a higher level paren.
234 if (dir
< 0 && cnt
== 1)
236 if (!lnext() || !ltosolid())
239 } else if (dir
< 0 && c
== '(' || dir
> 0 && c
== ')')
240 /* Found a higher level paren */
256 * Is this the end of a sentence?
259 endsent(bool pastatom
)
261 unsigned char *cp
= wcursor
;
266 * If this is the beginning of a line, then
267 * check for the end of a paragraph or section.
273 * Sentences end with . ! ? not at the beginning
274 * of the line, and must be either at the end of the line,
275 * or followed by 2 spaces. Any number of intervening ) ] ' "
276 * characters are allowed.
278 if (!any(c
= *cp
, ".!?"))
282 if ((len
= mblen((char *)cp
, MB_CUR_MAX
)) <= 0)
288 } while (any(d
, ")]'\""));
290 } while (any(d
, ")]'"));
292 if (*cp
== 0 || *cp
++ == ' ' && *cp
== ' ')
301 * End of paragraphs/sections are respective
302 * macros as well as blank lines and form feeds.
308 return (linebuf
[0] == 0 ||
310 /* POSIX 1003.2 Section 5.35.7.1: control-L, "{" */
312 linebuf
[0] == CTRL('L') ||
314 isa(svalue(vi_PARAGRAPHS
)) || isa(svalue(vi_SECTIONS
)));
322 unsigned char *swcurs
= wcursor
;
332 for (cp
= linebuf
; *cp
; cp
++)
337 cp
= vpastwh(linebuf
);
341 return (whitecnt(linebuf
));
352 else if (wcursor
== linebuf
)
355 unsigned char *wp
= wcursor
;
359 if (!lnext() || !ltosolid() || !lskipatom()) {
364 i
+= column(wcursor
) - 1;
377 unsigned char *parens
, *cp
;
379 for (cp
= cursor
; !any(*cp
, "({[)}]");) {
382 if ((i
= mblen((char *)cp
, MB_CUR_MAX
)) <= 0)
388 parens
= any(*cp
, "()") ? (unsigned char *)"()" : any(*cp
, "[]") ? (unsigned char *)"[]" : (unsigned char *)"{}";
389 if (*cp
== parens
[1]) {
402 i
= lskipbal(parens
);
407 lsmatch(unsigned char *cp
)
409 unsigned char save
[LBSIZE
];
410 unsigned char *sp
= save
;
411 unsigned char *scurs
= cursor
;
416 strcpy(cursor
, genbuf
);
417 cursor
= strend(linebuf
);
418 cursor
= lastchr(linebuf
, cursor
);
419 if (lmatchp(dot
- vcline
)) {
424 if (!move_insert_mode
)
426 vgoto(splitw
? WECHO
: LINE(wdot
- llimit
), column(wcursor
) - 1);
435 strcpy(scurs
, genbuf
);
436 if (!lmatchp((line
*) 0))
449 return (ltosol1("()"));
453 ltosol1(unsigned char *parens
)
459 if (*parens
&& !*wcursor
&& !lnext())
462 while (isspace(*wcursor
) || (*wcursor
== 0 && *parens
))
465 if (any(*wcursor
, parens
) || dir
> 0)
469 for (cp
= linebuf
; cp
< wcursor
; cp
+= len
) {
472 if (isspace(*cp
) || any(*cp
, parens
))
476 if ((len
= mblen((char *)cp
, MB_CUR_MAX
)) <= 0)
484 lskipbal(unsigned char *parens
)
497 else if (c
== parens
[0])
507 return (lskipa1("()"));
511 lskipa1(unsigned char *parens
)
516 if (dir
< 0 && wcursor
== linebuf
) {
522 if (c
&& (isspace(c
) || any(c
, parens
)))
527 if (dir
> 0 && wcursor
== linebuf
)
530 return (ltosol1(parens
));
539 wcursor
= nextchr(wcursor
);
542 if (wdot
>= llimit
) {
543 if (lf
== vmove
&& wcursor
> linebuf
)
544 wcursor
= lastchr(linebuf
, wcursor
);
552 wcursor
= lastchr(linebuf
, wcursor
);
553 if (wcursor
>= linebuf
)
555 if (lf
== lindent
&& linebuf
[0] == '(')
557 if (wdot
<= llimit
) {
566 wcursor
= strend(linebuf
);
567 wcursor
= lastchr(linebuf
, wcursor
);
574 lbrack(int c
, int (*f
)())
581 if (addr
< one
|| addr
> dol
) {
586 if (linebuf
[0] == '{' ||
588 /* POSIX 1003.2 Section 5.35.7.1: control-L */
589 linebuf
[0] == CTRL('L') ||
591 value(vi_LISP
) && linebuf
[0] == '(' ||
592 isa(svalue(vi_SECTIONS
))) {
593 if (c
== ']' && f
!= vmove
) {
599 if (c
== ']' && f
!= vmove
&& linebuf
[0] == '}')
605 wcursor
= c
== ']' ? strend(linebuf
) : linebuf
;
614 isa(unsigned char *cp
)
617 if (linebuf
[0] != '.')
619 for (; cp
[0] && cp
[1]; cp
+= 2)
620 if (linebuf
[1] == cp
[0]) {
621 if (linebuf
[2] == cp
[1])
623 if (linebuf
[2] == 0 && cp
[1] == ' ')