Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 7u83 1
/*
2
 * This code contains changes by
3
 *      Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4
 *
5
 * Conditions 1, 2, and 4 and the no-warranty notice below apply
6
 * to these changes.
7
 *
8
 *
9
 * Copyright (c) 1980, 1993
10
 * 	The Regents of the University of California.  All rights reserved.
11
 *
12
 * Redistribution and use in source and binary forms, with or without
13
 * modification, are permitted provided that the following conditions
14
 * are met:
15
 * 1. Redistributions of source code must retain the above copyright
16
 *    notice, this list of conditions and the following disclaimer.
17
 * 2. Redistributions in binary form must reproduce the above copyright
18
 *    notice, this list of conditions and the following disclaimer in the
19
 *    documentation and/or other materials provided with the distribution.
20
 * 3. All advertising materials mentioning features or use of this software
21
 *    must display the following acknowledgement:
22
 * 	This product includes software developed by the University of
23
 * 	California, Berkeley and its contributors.
24
 * 4. Neither the name of the University nor the names of its contributors
25
 *    may be used to endorse or promote products derived from this software
26
 *    without specific prior written permission.
27
 *
28
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
 * SUCH DAMAGE.
39
 *
40
 *
41
 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42
 *
43
 * Redistribution and use in source and binary forms, with or without
44
 * modification, are permitted provided that the following conditions
45
 * are met:
46
 *   Redistributions of source code and documentation must retain the
47
 *    above copyright notice, this list of conditions and the following
48
 *    disclaimer.
49
 *   Redistributions in binary form must reproduce the above copyright
50
 *    notice, this list of conditions and the following disclaimer in the
51
 *    documentation and/or other materials provided with the distribution.
52
 *   All advertising materials mentioning features or use of this software
53
 *    must display the following acknowledgement:
54
 *      This product includes software developed or owned by Caldera
55
 *      International, Inc.
56
 *   Neither the name of Caldera International, Inc. nor the names of
57
 *    other contributors may be used to endorse or promote products
58
 *    derived from this software without specific prior written permission.
59
 *
60
 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61
 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64
 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65
 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72
 */
73
 
74
#ifndef	lint
75
#ifdef	DOSCCS
76
static char sccsid[] = "@(#)ex_vops3.c	1.19 (gritter) 1/2/05";
77
#endif
78
#endif
79
 
80
/* from ex_vops3.c	7.3 (Berkeley) 6/7/85 */
81
 
82
#include "ex.h"
83
#include "ex_tty.h"
84
#include "ex_vis.h"
85
 
86
/*
87
 * Routines to handle structure.
88
 * Operations supported are:
89
 *	( ) { } [ ]
90
 *
91
 * These cover:		LISP		TEXT
92
 *	( )		s-exprs		sentences
93
 *	{ }		list at same	paragraphs
94
 *	[ ]		defuns		sections
95
 *
96
 * { and } for C used to attempt to do something with matching {}'s, but
97
 * I couldn't find definitions which worked intuitively very well, so I
98
 * scrapped this.
99
 *
100
 * The code here is very hard to understand.
101
 */
102
line	*llimit;
103
void	(*lf)(int);
104
 
105
bool	wasend;
106
 
107
/*
108
 * Find over structure, repeated count times.
109
 * Don't go past line limit.  F is the operation to
110
 * be performed eventually.  If pastatom then the user said {}
111
 * rather than (), implying past atoms in a list (or a paragraph
112
 * rather than a sentence.
113
 */
114
int
115
llfind(bool pastatom, int cnt, void (*f)(int), line *limit)
116
{
117
#ifdef	LISPCODE
118
	register int c;
119
#endif
120
	register int rc = 0;
121
	char save[LBSIZE];
122
 
123
	/*
124
	 * Initialize, saving the current line buffer state
125
	 * and computing the limit; a 0 argument means
126
	 * directional end of file.
127
	 */
128
	wasend = 0;
129
	lf = f;
130
	strcpy(save, linebuf);
131
	if (limit == 0)
132
		limit = dir < 0 ? one : dol;
133
	llimit = limit;
134
	wdot = dot;
135
	wcursor = cursor;
136
 
137
	if (pastatom >= 2) {
138
		while (cnt > 0 && word(f, cnt))
139
			cnt--;
140
		if (pastatom == 3)
141
			eend(f);
142
		if (dot == wdot) {
143
			wdot = 0;
144
			if (cursor == wcursor)
145
				rc = -1;
146
		}
147
	}
148
#ifdef LISPCODE
149
	else if (!value(LISP)) {
150
#else
151
	else {
152
#endif
153
		char *icurs;
154
		line *idot;
155
 
156
		if (linebuf[0] == 0) {
157
			do
158
				if (!lnext())
159
					goto ret;
160
			while (linebuf[0] == 0);
161
			if (dir > 0) {
162
				wdot--;
163
				linebuf[0] = 0;
164
				wcursor = linebuf;
165
				/*
166
				 * If looking for sentence, next line
167
				 * starts one.
168
				 */
169
				if (!pastatom) {
170
					icurs = wcursor;
171
					idot = wdot;
172
					goto begin;
173
				}
174
			}
175
		}
176
		icurs = wcursor;
177
		idot = wdot;
178
 
179
		/*
180
		 * Advance so as to not find same thing again.
181
		 */
182
		if (dir > 0) {
183
			if (!lnext()) {
184
				rc = -1;
185
				goto ret;
186
			}
187
		} else
188
			ignore(lskipa1(""));
189
 
190
		/*
191
		 * Count times find end of sentence/paragraph.
192
		 */
193
begin:
194
		for (;;) {
195
			while (!endsent(pastatom))
196
				if (!lnext())
197
					goto ret;
198
			if (!pastatom || wcursor == linebuf && endPS())
199
				if (--cnt <= 0)
200
					break;
201
			if (linebuf[0] == 0) {
202
				do
203
					if (!lnext())
204
						goto ret;
205
				while (linebuf[0] == 0);
206
			} else
207
				if (!lnext())
208
					goto ret;
209
		}
210
 
211
		/*
212
		 * If going backwards, and didn't hit the end of the buffer,
213
		 * then reverse direction.
214
		 */
215
		if (dir < 0 && (wdot != llimit || wcursor != linebuf)) {
216
			dir = 1;
217
			llimit = dot;
218
			/*
219
			 * Empty line needs special treatement.
220
			 * If moved to it from other than begining of next line,
221
			 * then a sentence starts on next line.
222
			 */
223
			if (linebuf[0] == 0 && !pastatom && 
224
			   (wdot != dot - 1 || cursor != linebuf)) {
225
				lnext();
226
				goto ret;
227
			}
228
		}
229
 
230
		/*
231
		 * If we are not at a section/paragraph division,
232
		 * advance to next.
233
		 */
234
		if (wcursor == icurs && wdot == idot || wcursor != linebuf || !endPS())
235
			ignore(lskipa1(""));
236
	}
237
#ifdef LISPCODE
238
	else {
239
		c = *wcursor;
240
		/*
241
		 * Startup by skipping if at a ( going left or a ) going
242
		 * right to keep from getting stuck immediately.
243
		 */
244
		if (dir < 0 && c == '(' || dir > 0 && c == ')') {
245
			if (!lnext()) {
246
				rc = -1;
247
				goto ret;
248
			}
249
		}
250
		/*
251
		 * Now chew up repitition count.  Each time around
252
		 * if at the beginning of an s-exp (going forwards)
253
		 * or the end of an s-exp (going backwards)
254
		 * skip the s-exp.  If not at beg/end resp, then stop
255
		 * if we hit a higher level paren, else skip an atom,
256
		 * counting it unless pastatom.
257
		 */
258
		while (cnt > 0) {
259
			c = *wcursor;
260
			if (dir < 0 && c == ')' || dir > 0 && c == '(') {
261
				if (!lskipbal("()"))
262
					goto ret;
263
				/*
264
 				 * Unless this is the last time going
265
				 * backwards, skip past the matching paren
266
				 * so we don't think it is a higher level paren.
267
				 */
268
				if (dir < 0 && cnt == 1)
269
					goto ret;
270
				if (!lnext() || !ltosolid())
271
					goto ret;
272
				--cnt;
273
			} else if (dir < 0 && c == '(' || dir > 0 && c == ')')
274
				/* Found a higher level paren */
275
				goto ret;
276
			else {
277
				if (!lskipatom())
278
					goto ret;
279
				if (!pastatom)
280
					--cnt;
281
			}
282
		}
283
	}
284
#endif
285
ret:
286
	strcLIN(save);
287
	return (rc);
288
}
289
 
290
/*
291
 * Is this the end of a sentence?
292
 */
293
int
294
endsent(bool pastatom)
295
{
296
	register char *cp = wcursor;
297
	register int c, d;
298
 
299
	/*
300
	 * If this is the beginning of a line, then
301
	 * check for the end of a paragraph or section.
302
	 */
303
	if (cp == linebuf)
304
		return (endPS());
305
 
306
	/*
307
	 * Sentences end with . ! ? not at the beginning
308
	 * of the line, and must be either at the end of the line,
309
	 * or followed by 2 spaces.  Any number of intervening ) ] ' "
310
	 * characters are allowed.
311
	 */
312
	if (!any(c = *cp, ".!?"))
313
		goto tryps;
314
	do
315
		if ((d = *++cp) == 0)
316
			return (1);
317
	while (any(d, ")]'"));
318
	if (*cp == 0 || *cp++ == ' ' && *cp == ' ')
319
		return (1);
320
tryps:
321
	if (cp[1] == 0)
322
		return (endPS());
323
	return (0);
324
}
325
 
326
/*
327
 * End of paragraphs/sections are respective
328
 * macros as well as blank lines and form feeds.
329
 */
330
int
331
endPS(void)
332
{
333
 
334
	return (linebuf[0] == 0 ||
335
		isa(svalue(PARAGRAPHS)) || isa(svalue(SECTIONS)));
336
 
337
}
338
 
339
#ifdef LISPCODE
340
int
341
lindent(line *addr)
342
{
343
	register int i;
344
	char *swcurs = wcursor;
345
	line *swdot = wdot;
346
 
347
again:
348
	if (addr > one) {
349
		register char *cp;
350
		register int cnt = 0;
351
 
352
		addr--;
353
		getline(*addr);
354
		for (cp = linebuf; *cp; cp++)
355
			if (*cp == '(')
356
				cnt++;
357
			else if (*cp == ')')
358
				cnt--;
359
		cp = vpastwh(linebuf);
360
		if (*cp == 0)
361
			goto again;
362
		if (cnt == 0)
363
			return (whitecnt(linebuf));
364
		addr++;
365
	}
366
	wcursor = linebuf;
367
	linebuf[0] = 0;
368
	wdot = addr;
369
	dir = -1;
370
	llimit = one;
371
	lf = (void (*)(int))lindent;
372
	if (!lskipbal("()"))
373
		i = 0;
374
	else if (wcursor == linebuf)
375
		i = 2;
376
	else {
377
		register char *wp = wcursor;
378
 
379
		dir = 1;
380
		llimit = wdot;
381
		if (!lnext() || !ltosolid() || !lskipatom()) {
382
			wcursor = wp;
383
			i = 1;
384
		} else
385
			i = 0;
386
		i += column(wcursor) - 1;
387
		if (!inopen)
388
			i--;
389
	}
390
	wdot = swdot;
391
	wcursor = swcurs;
392
	return (i);
393
}
394
#endif
395
 
396
int
397
lmatchp(line *addr)
398
{
399
	register int i;
400
	register char *parens, *cp;
401
 
402
	for (cp = cursor; !any(*cp, "({[)}]");)
403
		if (*cp++ == 0)
404
			return (0);
405
	lf = 0;
406
	parens = any(*cp, "()") ? "()" : any(*cp, "[]") ? "[]" : "{}";
407
	if (*cp == parens[1]) {
408
		dir = -1;
409
		llimit = one;
410
	} else {
411
		dir = 1;
412
		llimit = dol;
413
	}
414
	if (addr)
415
		llimit = addr;
416
	if (splitw)
417
		llimit = dot;
418
	wcursor = cp;
419
	wdot = dot;
420
	i = lskipbal(parens);
421
	return (i);
422
}
423
 
424
void
425
lsmatch(char *cp)
426
{
427
	char save[LBSIZE];
428
	register char *sp = save;
429
	register char *scurs = cursor;
430
 
431
	wcursor = cp;
432
	strcpy(sp, linebuf);
433
	*wcursor = 0;
434
	strcpy(cursor, genbuf);
435
	cursor = strend(linebuf) - 1;
436
	if (lmatchp(dot - vcline)) {
437
		register int i = insmode;
438
		register int c = outcol;
439
		register int l = outline;
440
 
441
		if (!MI)
442
			endim();
443
		vgoto(splitw ? WECHO : LINE(wdot - llimit), column(wcursor) - 1);
444
		flush();
445
		sleep(1);
446
		vgoto(l, c);
447
		if (i)
448
			goim();
449
	}
450
	else {
451
		strcLIN(sp);
452
		strcpy(scurs, genbuf);
453
		if (!lmatchp((line *) 0))
454
			beep();
455
	}
456
	strcLIN(sp);
457
	wdot = 0;
458
	wcursor = 0;
459
	cursor = scurs;
460
}
461
 
462
int
463
ltosolid(void)
464
{
465
 
466
	return (ltosol1("()"));
467
}
468
 
469
int
470
ltosol1(register char *parens)
471
{
472
	register char *cp;
473
 
474
	if (*parens && !*wcursor && !lnext())
475
		return (0);
476
	while (isspace(*wcursor&0377) || (*wcursor == 0 && *parens))
477
		if (!lnext())
478
			return (0);
479
	if (any(*wcursor, parens) || dir > 0)
480
		return (1);
481
	for (cp = wcursor; cp > linebuf; cp--)
482
		if (isspace(cp[-1]&0377) || any(cp[-1], parens))
483
			break;
484
	wcursor = cp;
485
	return (1);
486
}
487
 
488
int
489
lskipbal(register char *parens)
490
{
491
	register int level = dir;
492
	register int c;
493
 
494
	do {
495
		if (!lnext()) {
496
			wdot = NOLINE;
497
			return (0);
498
		}
499
		c = *wcursor;
500
		if (c == parens[1])
501
			level--;
502
		else if (c == parens[0])
503
			level++;
504
	} while (level);
505
	return (1);
506
}
507
 
508
int
509
lskipatom(void)
510
{
511
 
512
	return (lskipa1("()"));
513
}
514
 
515
int
516
lskipa1(register char *parens)
517
{
518
	register int c;
519
 
520
	for (;;) {
521
		if (dir < 0 && wcursor == linebuf) {
522
			if (!lnext())
523
				return (0);
524
			break;
525
		}
526
		c = *wcursor;
527
		if (c && (isspace(c) || any(c, parens)))
528
			break;
529
		if (!lnext())
530
			return (0);
531
		if (dir > 0 && wcursor == linebuf)
532
			break;
533
	}
534
	return (ltosol1(parens));
535
}
536
 
537
int
538
lnext(void)
539
{
540
 
541
	if (dir > 0) {
542
		if (*wcursor)
543
			wcursor += skipright(linebuf, wcursor);
544
		if (*wcursor)
545
			return (1);
546
		if (wdot >= llimit) {
547
			if (lf == vmove && wcursor > linebuf)
548
				wcursor += skipleft(linebuf, wcursor);
549
			return (0);
550
		}
551
		wdot++;
552
		getline(*wdot);
553
		wcursor = linebuf;
554
		return (1);
555
	} else {
556
		wcursor += skipleft(linebuf, wcursor);
557
		if (wcursor >= linebuf)
558
			return (1);
559
#ifdef LISPCODE
560
		if (lf == (void (*)(int))lindent && linebuf[0] == '(')
561
			llimit = wdot;
562
#endif
563
		if (wdot <= llimit) {
564
			wcursor = linebuf;
565
			return (0);
566
		}
567
		wdot--;
568
		getline(*wdot);
569
		wcursor = linebuf[0] == 0 ? linebuf : strend(linebuf) - 1;
570
		return (1);
571
	}
572
}
573
 
574
int
575
lbrack(register int c, void (*f)(int))
576
{
577
	register line *addr;
578
 
579
	addr = dot;
580
	for (;;) {
581
		addr += dir;
582
		if (addr < one || addr > dol) {
583
			addr -= dir;
584
			break;
585
		}
586
		getline(*addr);
587
		if (linebuf[0] == '{' ||
588
#ifdef LISPCODE
589
		    value(LISP) && linebuf[0] == '(' ||
590
#endif
591
		    isa(svalue(SECTIONS))) {
592
			if (c == ']' && f != vmove) {
593
				addr--;
594
				getline(*addr);
595
			}
596
			break;
597
		}
598
		if (c == ']' && f != vmove && linebuf[0] == '}')
599
			break;
600
	}
601
	if (addr == dot)
602
		return (0);
603
	if (f != vmove)
604
		wcursor = c == ']' ? strend(linebuf) : linebuf;
605
	else
606
		wcursor = 0;
607
	wdot = addr;
608
	vmoving = 0;
609
	return (1);
610
}
611
 
612
int
613
isa(register char *cp)
614
{
615
 
616
	if (linebuf[0] != '.')
617
		return (0);
618
	for (; cp[0] && cp[1]; cp += 2)
619
		if (linebuf[1] == cp[0]) {
620
			if (linebuf[2] == cp[1])
621
				return (1);
622
			if (linebuf[2] == 0 && cp[1] == ' ')
623
				return (1);
624
		}
625
	return (0);
626
}
627
 
628
static void
629
cswitch(char *dst, int *dn, const char *src, int *sn)
630
{
631
	int	c;
632
 
633
#ifdef	MB
634
	if (mb_cur_max > 1) {
635
		nextc(c, src, *sn);
636
		if (c & INVBIT) {
637
			*dst = *src;
638
			*dn = *sn = 1;
639
		} else {
640
			if (iswupper(c))
641
				c = towlower(c);
642
			else if (iswlower(c))
643
				c = towupper(c);
644
			if ((*dn = wctomb(dst, c)) > *sn) {
645
				*dst = *src;
646
				*dn = *sn = 1;
647
			}
648
		}
649
	} else
650
#endif	/* MB */
651
	{
652
		c = *src & 0377;
653
		if (isupper(c))
654
			*dst = tolower(c);
655
		else if (islower(c))
656
			*dst = toupper(c);
657
		else
658
			*dst = c;
659
		*dn = *sn = 1;
660
	}
661
}
662
 
663
void
664
vswitch(int cnt)
665
{
666
	if (cnt <= 1) {
667
		char mbuf[MB_LEN_MAX+4];
668
		int	n0, n1;
669
		setLAST();
670
		mbuf[0] = 'r';
671
		cswitch(&mbuf[1], &n1, cursor, &n0);
672
		if (cursor[n1] != '\0')
673
			mbuf[1+n1++] = ' ';
674
		mbuf[1+n1] = '\0';
675
		macpush(mbuf, 1);
676
	} else {	/* cnt > 1 */
677
		char *mbuf = malloc(MAXDIGS + cnt*(mb_cur_max+1) + 5);
678
		register char *p = &mbuf[MAXDIGS + 1];
679
		int num, n0, n1, m;
680
 
681
		setLAST();
682
		*p++ = 's';
683
		for (num = 0, m = 0; num < cnt && cursor[m] != '\0'; num++) {
684
			*p++ = CTRL('v');
685
			cswitch(p, &n1, &cursor[m], &n0);
686
			p += n1;
687
			m += n0;
688
		}
689
		*p++ = ESCAPE;
690
		if (cursor[m])
691
			*p++ = ' ';
692
		*p++ = '\0';
693
		macpush(p_dconv((long)num, mbuf), 1);
694
		lastvgk = 0;
695
		free(mbuf);
696
	}
697
}
698
 
699
#ifdef	MB
700
int
701
wskipleft(char *lp, char *pos)
702
{
703
	int	c, n;
704
 
705
	do {
706
		nextc(c, lp, n);
707
		lp += n;
708
	} while (lp < pos);
709
	return -n;
710
}
711
 
712
int
713
wskipright(char *line, char *pos)
714
{
715
	int	c, n;
716
 
717
	nextc(c, pos, n);
718
	return n;
719
}
720
 
721
int
722
wsamechar(char *cp, int d)
723
{
724
	int	c;
725
 
726
	if (mbtowi(&c, cp, mb_cur_max) >= 0 && c == d)
727
		return 1;
728
	return 0;
729
}
730
#endif	/* MB */