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_re.c	1.56 (gritter) 3/25/05";
77
#endif
78
#endif
79
 
80
/* from ex_re.c	7.5 (Berkeley) 6/7/85 */
81
 
82
#include "ex.h"
83
#include "ex_re.h"
84
 
85
#ifdef	UXRE
86
 
87
#include <regex.h>
88
 
89
char	*braslist[NBRA];
90
char	*braelist[NBRA];
91
char	*loc1;
92
char	*loc2;
93
 
94
#else	/* !UXRE */
95
static int	regerrno;
96
 
97
#define	INIT			register char *sp = instring;
98
#define	GETC()			(*sp++)
99
#define	PEEKC()			(*sp)
100
#define	UNGETC(c)		(--sp)
101
#define	RETURN(c)		return(ep);
102
#define	ERROR(c)		{ regerrno = c; return 0; }
103
 
104
#define	compile(a, b, c, d)	_compile(a, b, c, d)
105
#define	regexp_h_static		static
106
 
107
#ifndef	NO_BE_BACKSLASH
108
#define	REGEXP_H_VI_BACKSLASH
109
#endif	/* !NO_BE_BACKSLASH */
110
 
111
#ifdef	MB
112
#define	REGEXP_H_WCHARS
113
#endif	/* MB */
114
 
115
#define	REGEXP_H_USED_FROM_VI
116
 
117
#include "regexp.h"
118
 
119
#ifndef	REG_ICASE
120
#define	REG_ICASE	1
121
#endif
122
 
123
static size_t
124
loconv(register char *dst, register const char *src)
125
{
126
	char	*odst = dst;
127
 
128
#ifdef	MB
129
	if (mb_cur_max > 1) {
130
		char	mb[MB_LEN_MAX];
131
		wchar_t wc;
132
		int len, i, nlen;
133
 
134
		for (;;) {
135
			if ((*src & 0200) == 0) {
136
				*dst++ = tolower(*src);
137
				if (*src++ == '\0')
138
					break;
139
			} else if ((len = mbtowc(&wc, src, mb_cur_max)) <= 0) {
140
				*dst++ = *src++;
141
			} else {
142
				wc = towlower(wc);
143
				if (len >= mb_cur_max) {
144
					if ((nlen = wctomb(dst, wc)) <= len) {
145
						dst += nlen;
146
						src += len;
147
					} else {
148
						*dst++ = *src++;
149
					}
150
				} else {
151
					if ((nlen = wctomb(mb, wc)) <= len) {
152
						src += len;
153
						for (i = 0; i < nlen; i++)
154
							*dst++ = mb[i];
155
					} else {
156
						*dst++ = *src++;
157
					}
158
				}
159
			}
160
		}
161
	} else
162
#endif	/* MB */
163
	{
164
		do
165
			*dst++ = tolower(*src & 0377);
166
		while (*src++);
167
	}
168
	return dst - odst;
169
}
170
 
171
#undef	compile
172
 
173
#endif	/* !UXRE */
174
 
175
/*
176
 * Global, substitute and regular expressions.
177
 * Very similar to ed, with some re extensions and
178
 * confirmed substitute.
179
 */
180
void 
181
global(int k)
182
{
183
	register char *gp;
184
	register int c, i;
185
	register line *a1;
186
	char	mb[MB_LEN_MAX+1];
187
	char globuf[GBSIZE], *Cwas;
188
	int lines = lineDOL();
189
	int oinglobal = inglobal;
190
	char *oglobp = globp;
191
 
192
	Cwas = Command;
193
	/*
194
	 * States of inglobal:
195
	 *  0: ordinary - not in a global command.
196
	 *  1: text coming from some buffer, not tty.
197
	 *  2: like 1, but the source of the buffer is a global command.
198
	 * Hence you're only in a global command if inglobal==2. This
199
	 * strange sounding convention is historically derived from
200
	 * everybody simulating a global command.
201
	 */
202
	if (inglobal==2)
203
		error(catgets(catd, 1, 121,
204
				"Global within global@not allowed"));
205
	markDOT();
206
	setall();
207
	nonzero();
208
	if (skipend())
209
		error(catgets(catd, 1, 122,
210
		"Global needs re|Missing regular expression for global"));
211
	c = GETWC(mb);
212
	ignore(compile(c, 1));
213
	savere(&scanre);
214
	gp = globuf;
215
	while ((c = GETWC(mb)) != '\n') {
216
		switch (c) {
217
 
218
		case EOF:
219
			c = '\n';
220
			goto brkwh;
221
 
222
		case '\\':
223
			c = GETWC(mb);
224
			switch (c) {
225
 
226
			case '\\':
227
				ungetchar(c);
228
				break;
229
 
230
			case '\n':
231
				break;
232
 
233
			default:
234
				*gp++ = '\\';
235
				break;
236
			}
237
			break;
238
		}
239
		for (i = 0; mb[i]; i++) {
240
			*gp++ = mb[i];
241
			if (gp >= &globuf[GBSIZE - 2])
242
				error(catgets(catd, 1, 123,
243
						"Global command too long"));
244
		}
245
	}
246
brkwh:
247
	ungetchar(c);
248
/* out: */
249
	newline();
250
	*gp++ = c;
251
	*gp++ = 0;
252
	saveall();
253
	inglobal = 2;
254
	for (a1 = one; a1 <= dol; a1++) {
255
		*a1 &= ~01;
256
		if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
257
			*a1 |= 01;
258
	}
259
#ifdef notdef
260
/*
261
 * This code is commented out for now.  The problem is that we don't
262
 * fix up the undo area the way we should.  Basically, I think what has
263
 * to be done is to copy the undo area down (since we shrunk everything)
264
 * and move the various pointers into it down too.  I will do this later
265
 * when I have time. (Mark, 10-20-80)
266
 */
267
	/*
268
	 * Special case: g/.../d (avoid n^2 algorithm)
269
	 */
270
	if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
271
		gdelete();
272
		return;
273
	}
274
#endif
275
	if (inopen)
276
		inopen = -1;
277
	/*
278
	 * Now for each marked line, set dot there and do the commands.
279
	 * Note the n^2 behavior here for lots of lines matching.
280
	 * This is really needed: in some cases you could delete lines,
281
	 * causing a marked line to be moved before a1 and missed if
282
	 * we didn't restart at zero each time.
283
	 */
284
	for (a1 = one; a1 <= dol; a1++) {
285
		if (*a1 & 01) {
286
			*a1 &= ~01;
287
			dot = a1;
288
			globp = globuf;
289
			commands(1, 1);
290
			a1 = zero;
291
		}
292
	}
293
	globp = oglobp;
294
	inglobal = oinglobal;
295
	endline = 1;
296
	Command = Cwas;
297
	netchHAD(lines);
298
	setlastchar(EOF);
299
	if (inopen) {
300
		ungetchar(EOF);
301
		inopen = 1;
302
	}
303
}
304
 
305
/*
306
 * gdelete: delete inside a global command. Handles the
307
 * special case g/r.e./d. All lines to be deleted have
308
 * already been marked. Squeeze the remaining lines together.
309
 * Note that other cases such as g/r.e./p, g/r.e./s/r.e.2/rhs/,
310
 * and g/r.e./.,/r.e.2/d are not treated specially.  There is no
311
 * good reason for this except the question: where to you draw the line?
312
 */
313
void 
314
gdelete(void)
315
{
316
	register line *a1, *a2, *a3;
317
 
318
	a3 = dol;
319
	/* find first marked line. can skip all before it */
320
	for (a1=zero; (*a1&01)==0; a1++)
321
		if (a1>=a3)
322
			return;
323
	/* copy down unmarked lines, compacting as we go. */
324
	for (a2=a1+1; a2<=a3;) {
325
		if (*a2&01) {
326
			a2++;		/* line is marked, skip it */
327
			dot = a1;	/* dot left after line deletion */
328
		} else
329
			*a1++ = *a2++;	/* unmarked, copy it */
330
	}
331
	dol = a1-1;
332
	if (dot>dol)
333
		dot = dol;
334
	change();
335
}
336
 
337
bool	cflag;
338
int	scount, slines, stotal;
339
 
340
int 
341
substitute(int c)
342
{
343
	register line *addr;
344
	register int n;
345
	int gsubf, hopcount;
346
 
347
	gsubf = compsub(c);
348
	if(FIXUNDO)
349
		save12(), undkind = UNDCHANGE;
350
	stotal = 0;
351
	slines = 0;
352
	for (addr = addr1; addr <= addr2; addr++) {
353
		scount = hopcount = 0;
354
		if (dosubcon(0, addr) == 0)
355
			continue;
356
		if (gsubf) {
357
			/*
358
			 * The loop can happen from s/\</&/g
359
			 * but we don't want to break other, reasonable cases.
360
			 */
361
			while (*loc2) {
362
				if (++hopcount > sizeof linebuf)
363
					error(catgets(catd, 1, 124,
364
							"substitution loop"));
365
				if (dosubcon(1, addr) == 0)
366
					break;
367
			}
368
		}
369
		if (scount) {
370
			stotal += scount;
371
			slines++;
372
			putmark(addr);
373
			n = append(getsub, addr);
374
			addr += n;
375
			addr2 += n;
376
		}
377
	}
378
	if (stotal == 0 && !inglobal && !cflag)
379
		error(catgets(catd, 1, 125,
380
				"Fail|Substitute pattern match failed"));
381
	snote(stotal, slines);
382
	return (stotal);
383
}
384
 
385
int 
386
compsub(int ch)
387
{
388
	register int seof, c, uselastre;
389
	char	mb[MB_LEN_MAX+1];
390
	static int gsubf;
391
 
392
	if (!value(EDCOMPATIBLE))
393
		gsubf = cflag = 0;
394
	uselastre = 0;
395
	switch (ch) {
396
 
397
	case 's':
398
		ignore(skipwh());
399
		seof = GETWC(mb);
400
		if (endcmd(seof) || any(seof, "gcr")) {
401
			ungetchar(seof);
402
			goto redo;
403
		}
404
		if (xisalnum(seof))
405
			error(catgets(catd, 1, 126,
406
	"Substitute needs re|Missing regular expression for substitute"));
407
		seof = compile(seof, 1);
408
		uselastre = 1;
409
		comprhs(seof);
410
		gsubf = 0;
411
		cflag = 0;
412
		break;
413
 
414
	case '~':
415
		uselastre = 1;
416
		/* fall into ... */
417
	case '&':
418
	redo:
419
		if (re.Patbuf[0] == 0)
420
			error(catgets(catd, 1, 127,
421
			"No previous re|No previous regular expression"));
422
		if (subre.Patbuf[0] == 0)
423
			error(catgets(catd, 1, 128,
424
	"No previous substitute re|No previous substitute to repeat"));
425
		break;
426
	}
427
	for (;;) {
428
		c = getchar();
429
		switch (c) {
430
 
431
		case 'g':
432
			gsubf = !gsubf;
433
			continue;
434
 
435
		case 'c':
436
			cflag = !cflag;
437
			continue;
438
 
439
		case 'r':
440
			uselastre = 1;
441
			continue;
442
 
443
		default:
444
			ungetchar(c);
445
			setcount();
446
			newline();
447
			if (uselastre)
448
				savere(&subre);
449
			else
450
				resre(&subre);
451
			return (gsubf);
452
		}
453
	}
454
}
455
 
456
void
457
comprhs(int seof)
458
{
459
	register char *rp, *orp;
460
	char	mb[MB_LEN_MAX+1];
461
#ifdef	BIT8
462
	char *qp, *oqp;
463
#endif
464
	register int c, i;
465
#ifdef	BIT8
466
	int q;
467
#endif
468
	char orhsbuf[RHSSIZE];
469
#ifdef	BIT8
470
	char orhsquo[RHSSIZE];
471
#endif
472
	int	hashflag = 0;
473
 
474
	rp = rhsbuf;
475
#ifdef	BIT8
476
	qp = rhsquo;
477
#endif
478
	CP(orhsbuf, rp);
479
#ifdef	BIT8
480
	copy(orhsquo, qp, (size_t) strlen(rp));
481
#endif
482
	for (;;) {
483
		c = GETWC(mb);
484
#ifdef	BIT8
485
		q = 0;
486
#endif
487
		if (c == seof)
488
			break;
489
		switch (c) {
490
 
491
		case '%':
492
			if (rp == rhsbuf)
493
				hashflag = 1;
494
			break;
495
 
496
		case '\\':
497
			c = GETWC(mb);
498
			if (c == EOF) {
499
				ungetchar(c);
500
				break;
501
			}
502
			if (value(MAGIC)) {
503
				/*
504
				 * When "magic", \& turns into a plain &,
505
				 * and all other chars work fine quoted.
506
				 */
507
				if (c != '&')
508
#ifndef	BIT8
509
					c |= QUOTE;
510
#else
511
					q = 1;
512
#endif
513
				break;
514
			}
515
magic:
516
			if (c == '~') {
517
hash:
518
#ifndef	BIT8
519
				for (orp = orhsbuf; *orp; *rp++ = *orp++) {
520
#else
521
				for (orp = orhsbuf, oqp = orhsquo;
522
						*orp; *rp++ = *orp++) {
523
					*qp++ = *oqp++;
524
#endif
525
					if (rp >= &rhsbuf[RHSSIZE - 1])
526
						goto toobig;
527
				}
528
				if (hashflag & 2)
529
					goto endrhs;
530
				continue;
531
			}
532
#ifndef	BIT8
533
			c |= QUOTE;
534
#else
535
			q = 1;
536
#endif
537
			break;
538
 
539
		case '\n':
540
		case EOF:
541
			if (!(globp && globp[0])) {
542
				ungetchar(c);
543
				goto endrhs;
544
			}
545
 
546
		case '~':
547
		case '&':
548
			if (value(MAGIC))
549
				goto magic;
550
			break;
551
		}
552
		if (rp >= &rhsbuf[RHSSIZE - 1]) {
553
toobig:
554
			*rp = 0;
555
			error(catgets(catd, 1, 129,
556
		"Replacement pattern too long@- limit 256 characters"));
557
		}
558
		for (i = 0; mb[i]; i++) {
559
			*rp++ = mb[i];
560
#ifdef	BIT8
561
			*qp++ = q;
562
#endif
563
		}
564
	}
565
endrhs:
566
	if (hashflag == 1 && rhsbuf[0] == '%' && rp == &rhsbuf[1]) {
567
		rp = rhsbuf;
568
		hashflag |= 2;
569
		goto hash;
570
	}
571
	*rp++ = 0;
572
}
573
 
574
int
575
getsub(void)
576
{
577
	register char *p;
578
 
579
	if ((p = linebp) == 0)
580
		return (EOF);
581
	strcLIN(p);
582
	linebp = 0;
583
	return (0);
584
}
585
 
586
int
587
dosubcon(bool f, line *a)
588
{
589
 
590
	if (execute(f, a) == 0)
591
		return (0);
592
	if (confirmed(a)) {
593
		dosub();
594
		scount++;
595
	}
596
	return (1);
597
}
598
 
599
int
600
confirmed(line *a)
601
{
602
	register int c;
603
	char *yesstr = catgets(catd, 1, 249, "y");
604
	int okay = -1;
605
 
606
	if (cflag == 0)
607
		return (1);
608
	pofix();
609
	pline(lineno(a));
610
	if (inopen)
611
		putchar('\n' | QUOTE);
612
	c = column(loc1 - 1);
613
	ugo(c - 1 + (inopen ? 1 : 0), ' ');
614
	ugo(column(loc2 - 1) - c, '^');
615
	flush();
616
	c = getkey();
617
again:
618
	if (c == '\r')
619
		c = '\n';
620
	if (inopen)
621
		putchar(c), flush();
622
	if (c != '\n' && c != EOF) {
623
		if (okay && *yesstr) {
624
			if (c == (*yesstr++ & 0377))
625
				okay = 1;
626
			else
627
				okay = 0;
628
		}
629
		c = getkey();
630
		goto again;
631
	}
632
	noteinp();
633
	return (okay > 0);
634
}
635
 
636
#ifdef	notdef
637
int
638
ex_getch(void)
639
{
640
	char c;
641
 
642
	if (read(2, &c, 1) != 1)
643
		return (EOF);
644
#ifndef	BIT8
645
	return (c & TRIM);
646
#else
647
	return c;
648
#endif
649
}
650
#endif	/* notdef */
651
 
652
void
653
ugo(int cnt, int with)
654
{
655
 
656
	if (cnt > 0)
657
		do
658
			putchar(with);
659
		while (--cnt > 0);
660
}
661
 
662
int	casecnt;
663
bool	destuc;
664
 
665
void
666
dosub(void)
667
{
668
	register char *lp, *sp, *rp;
669
	int c, n;
670
#ifdef	BIT8
671
	register char *qp;
672
	int q;
673
#endif
674
 
675
	lp = linebuf;
676
	sp = genbuf;
677
	rp = rhsbuf;
678
#ifdef	BIT8
679
	qp = rhsquo;
680
#endif
681
	while (lp < loc1)
682
		*sp++ = *lp++;
683
	casecnt = 0;
684
	while (*rp) {
685
		nextc(c, rp, n);
686
		rp += n;
687
#ifdef	BIT8
688
		c &= TRIM;
689
		q = *qp;
690
		qp += n;
691
#endif
692
		/* ^V <return> from vi to split lines */
693
		if (c == '\r')
694
			c = '\n';
695
 
696
#ifndef	BIT8
697
		if (c & QUOTE)
698
			switch (c & TRIM) {
699
#else
700
		if (q)
701
			switch (c) {
702
#endif
703
 
704
			case '&':
705
				sp = place(sp, loc1, loc2);
706
				if (sp == 0)
707
					goto ovflo;
708
				continue;
709
 
710
			case 'l':
711
				casecnt = 1;
712
				destuc = 0;
713
				continue;
714
 
715
			case 'L':
716
				casecnt = LBSIZE;
717
				destuc = 0;
718
				continue;
719
 
720
			case 'u':
721
				casecnt = 1;
722
				destuc = 1;
723
				continue;
724
 
725
			case 'U':
726
				casecnt = LBSIZE;
727
				destuc = 1;
728
				continue;
729
 
730
			case 'E':
731
			case 'e':
732
				casecnt = 0;
733
				continue;
734
			}
735
#ifndef	BIT8
736
		if (c < 0 && (c &= TRIM) >= '1' && c < re.Nbra + '1') {
737
#else
738
		if (q && c >= '1' && c < re.Nbra + '1') {
739
#endif
740
			sp = place(sp, braslist[c - '1'], braelist[c - '1']);
741
			if (sp == 0)
742
				goto ovflo;
743
			continue;
744
		}
745
#ifdef	MB
746
		if (mb_cur_max > 1) {
747
			char	mb[MB_LEN_MAX+1];
748
			int	i, m;
749
			if (casecnt)
750
				c = fixcase(c & TRIM);
751
			if (c & INVBIT || (m = wctomb(mb, c)) <= 0) {
752
				mb[0] = rp[-n];
753
				m = 1;
754
			}
755
			for (i = 0; i < m; i++) {
756
				*sp++ = mb[i];
757
				if (sp >= &genbuf[LBSIZE])
758
					goto ovflo;
759
			}
760
		} else
761
#endif	/* MB */
762
		{
763
			if (casecnt)
764
				*sp++ = fixcase(c & TRIM);
765
			else
766
				*sp++ = c & TRIM;
767
		}
768
		if (sp >= &genbuf[LBSIZE])
769
ovflo:
770
			error(catgets(catd, 1, 130,
771
					"Line overflow@in substitute"));
772
	}
773
	lp = loc2;
774
	loc2 = sp + (linebuf - genbuf);
775
#ifdef	UXRE
776
	if (loc1 == lp) {
777
		nextc(c, loc2, n);
778
		loc2 += n;
779
	}
780
#endif	/* UXRE */
781
	while (*sp++ = *lp++)
782
		if (sp >= &genbuf[LBSIZE])
783
			goto ovflo;
784
	strcLIN(genbuf);
785
}
786
 
787
int
788
fixcase(register int c)
789
{
790
 
791
	if (casecnt == 0)
792
		return (c);
793
	casecnt--;
794
#ifdef	MB
795
	if (c & INVBIT)
796
		return (c);
797
	if (mb_cur_max > 1) {
798
		if (destuc) {
799
			if (iswlower(c))
800
				c = towupper(c);
801
		} else
802
			if (iswupper(c))
803
				c = towlower(c);
804
	} else
805
#endif	/* MB */
806
	{
807
		if (destuc) {
808
			if (islower(c))
809
				c = toupper(c);
810
		} else
811
			if (isupper(c))
812
				c = tolower(c);
813
	}
814
	return (c);
815
}
816
 
817
char *
818
place(register char *sp, register char *l1, register char *l2)
819
{
820
	while (l1 < l2) {
821
#ifdef	MB
822
		if (mb_cur_max > 1) {
823
			char	mb[MB_LEN_MAX+1];
824
			int	c, i, m, n;
825
 
826
			nextc(c, l1, m);
827
			if (c & INVBIT) {
828
				m = n = 1;
829
				*mb = *l1;
830
			} else {
831
				c = fixcase(c);
832
				if ((n = wctomb(mb, c)) <= 0) {
833
					n = 1;
834
					*mb = *l1;
835
				}
836
			}
837
			l1 += m;
838
			for (i = 0; i < n; i++) {
839
				*sp++ = mb[i];
840
				if (sp >= &genbuf[LBSIZE])
841
					return (0);
842
			}
843
		} else
844
#endif	/* MB */
845
		{
846
			*sp++ = fixcase(*l1++);
847
			if (sp >= &genbuf[LBSIZE])
848
				return (0);
849
		}
850
	}
851
	return (sp);
852
}
853
 
854
void
855
snote(register int total, register int lines)
856
{
857
 
858
	if (!notable(total))
859
		return;
860
	printf(mesg(catgets(catd, 1, 131, "%d subs|%d substitutions")), total);
861
	if (lines != 1 && lines != total)
862
		printf(catgets(catd, 1, 132, " on %d lines"), lines);
863
	noonl();
864
	flush();
865
}
866
 
867
void
868
cerror(char *s)
869
{
870
	re.Patbuf[0] = '\0';
871
	error(s);
872
}
873
 
874
void
875
refree(struct regexp *rp)
876
{
877
	struct regexp *r1 = NULL, *r2 = NULL;
878
 
879
	if (rp->Expbuf == 0)
880
		return;
881
	if (rp == &re) {
882
		r1 = &scanre;
883
		r2 = &subre;
884
	} else if (rp == &scanre) {
885
		r1 = &re;
886
		r2 = &subre;
887
	} else if (rp == &subre) {
888
		r1 = &re;
889
		r2 = &scanre;
890
	}
891
	if ((r1->Expbuf == 0 || rp->Re_ident != r1->Re_ident) &&
892
			(r2->Expbuf == 0 || rp->Re_ident != r2->Re_ident)) {
893
#ifdef	UXRE
894
		regfree(rp->Expbuf);
895
#endif	/* UXRE */
896
		free(rp->Expbuf);
897
	}
898
	rp->Expbuf = 0;
899
}
900
 
901
struct regexp *
902
savere(struct regexp *store)
903
{
904
	refree(store);
905
	copy(store, &re, sizeof re);
906
	return store;
907
}
908
 
909
struct regexp *
910
resre(struct regexp *store)
911
{
912
	refree(&re);
913
	copy(&re, store, sizeof re);
914
	return store;
915
}
916
 
917
static void
918
compile1(void)
919
{
920
#ifdef	UXRE
921
	int	n;
922
#else	/* !UXRE */
923
	char	*r;
924
	char	*p;
925
#endif	/* !UXRE */
926
 
927
	refree(&re);
928
	re.Flags = value(IGNORECASE) ? REG_ICASE : 0;
929
#ifdef	UXRE
930
	re.Flags |= REG_ANGLES;
931
#ifndef	NO_BE_BACKSLASH
932
	re.Flags |= REG_BKTESCAPE | REG_BADRANGE;
933
#endif	/* !NO_BE_BACKSLASH */
934
	if (re.Expbuf == NULL)
935
		re.Expbuf = calloc(1, sizeof (regex_t));
936
	if ((n = regcomp(re.Expbuf, re.Patbuf, re.Flags)) != 0) {
937
		switch (n) {
938
		case REG_EBRACK:
939
			free(re.Expbuf);
940
			re.Expbuf = 0;
941
			cerror(catgets(catd, 1, 154, "Missing ]"));
942
			/*NOTREACHED*/
943
			break;
944
		default:
945
			regerror(n, re.Expbuf, &re.Patbuf[1],
946
					sizeof re.Patbuf - 1);
947
			free(re.Expbuf);
948
			re.Expbuf = 0;
949
			cerror(&re.Patbuf[1]);
950
		}
951
	}
952
	if ((re.Nbra = ((regex_t *)re.Expbuf)->re_nsub) > NBRA)
953
		re.Nbra = NBRA;
954
#else	/* !UXRE */
955
	if ((re.Expbuf = malloc(re.Length)) == NULL)
956
		cerror("Re too complex|Regular expression too complicated");
957
	if (re.Flags & REG_ICASE) {
958
		p = malloc(strlen(re.Patbuf) + 1);
959
		loconv(p, re.Patbuf);
960
	} else
961
		p = re.Patbuf;
962
	r = _compile(p, re.Expbuf, &((char *)re.Expbuf)[re.Length], '\0');
963
	if (p != re.Patbuf)
964
		free(p);
965
	if (r == 0) {
966
		char	*cp;
967
		free(re.Expbuf);
968
		re.Expbuf = 0;
969
		switch (regerrno) {
970
		case 11:
971
			cp = "Range endpoint too large|Range endpoint "
972
					"too large in regular expression";
973
			break;
974
		case 16:
975
			cp = "Bad number|Bad number in regular expression";
976
			break;
977
		case 25:
978
			cp = "\"\\digit\" out of range";
979
			break;
980
		case 36:
981
			cp = "Badly formed re|Missing closing delimiter "
982
				"for regular expression";
983
			break;
984
		case 42:
985
			cp = "\\( \\) Imbalance";
986
			break;
987
		case 43:
988
			cp = "Awash in \\('s!|Too many \\('d subexressions "
989
				"in a regular expression";
990
			break;
991
		case 44:
992
			cp = "More than 2 numbers given in \\{~\\}";
993
			break;
994
		case 45:
995
			cp = "} expected after \\";
996
			break;
997
		case 46:
998
			cp = "First number exceeds second in \\{~\\}";
999
			break;
1000
		case 49:
1001
			cp = "Missing ]";
1002
			break;
1003
		case 67:
1004
			cp = "Illegal byte sequence|Regular expression "
1005
				"has illegal byte sequence";
1006
			break;
1007
		default:
1008
			cp = "Unknown regexp error code!!";
1009
		}
1010
		cerror(cp);
1011
	}
1012
	re.Circfl = circf;
1013
	re.Nbra = nbra;
1014
#endif	/* !UXRE */
1015
	re.Re_ident++;
1016
}
1017
 
1018
int
1019
compile(int eof, int oknl)
1020
{
1021
	int c, d, i, n = 0;
1022
	char	mb[MB_LEN_MAX+1];
1023
	char *p = re.Patbuf, *end = re.Patbuf + sizeof re.Patbuf;
1024
	int nomagic = value(MAGIC) ? 0 : 1, esc, rcnt = 0;
1025
	char *rhsp;
1026
#ifdef	BIT8
1027
	char *rhsq;
1028
#endif
1029
 
1030
	if (isalpha(eof) || isdigit(eof))
1031
		error(catgets(catd, 1, 133,
1032
	"Regular expressions cannot be delimited by letters or digits"));
1033
	c = GETWC(mb);
1034
	if (eof == '\\') {
1035
		switch (c) {
1036
		case '/':
1037
		case '?':
1038
			if (scanre.Patbuf[0] == 0)
1039
				error(catgets(catd, 1, 134,
1040
	"No previous scan re|No previous scanning regular expression"));
1041
			resre(&scanre);
1042
			return c;
1043
		case '&':
1044
			if (subre.Patbuf[0] == 0)
1045
				error(catgets(catd, 1, 135,
1046
	"No previous substitute re|No previous substitute regular expression"));
1047
			resre(&subre);
1048
			return c;
1049
		default:
1050
			error(catgets(catd, 1, 136,
1051
	"Badly formed re|Regular expression \\ must be followed by / or ?"));
1052
		}
1053
	}
1054
	if (c == eof || c == '\n' || c == EOF) {
1055
		if (c == '\n' && oknl == 0)
1056
			error(catgets(catd, 1, 138,
1057
			"Missing closing delimiter@for regular expression"));
1058
		if (c != eof)
1059
			ungetchar(c);
1060
		if (re.Expbuf == 0)
1061
			error(catgets(catd, 1, 137,
1062
			"No previous re|No previous regular expression"));
1063
		return eof;
1064
	}
1065
	re.Nbra = re.Circfl = 0;
1066
	if (c == '^')
1067
		re.Circfl++;
1068
	esc = 0;
1069
	goto havec;
1070
	/*
1071
	 * Fetch the search pattern. This is quite a mess since we have
1072
	 * to handle nomagic and ~.
1073
	 */
1074
	for (;;) {
1075
		esc = 0;
1076
		c = GETWC(mb);
1077
	havec:	if (c == eof || c == EOF) {
1078
			if (c == EOF)
1079
				ungetchar(c);
1080
			break;
1081
		} else if (c == '\n') {
1082
			if (!oknl)
1083
				cerror(catgets(catd, 1, 157,
1084
	"Badly formed re|Missing closing delimiter for regular expression"));
1085
			ungetchar(c);
1086
			break;
1087
		} else if (nomagic) {
1088
			switch (c) {
1089
			case '.':
1090
			case '*':
1091
			case '[':
1092
			case '~':
1093
				*p++ = '\\';
1094
				esc = 1;
1095
				break;
1096
			case '\\':
1097
				c = GETWC(mb);
1098
				if (c != '.' && c != '*' && c != '[' &&
1099
						c != '~') {
1100
					*p++ = '\\';
1101
					esc = 1;
1102
				}
1103
			}
1104
		} else if (c == '\\') {
1105
			c = GETWC(mb);
1106
			if (c != '~')
1107
				*p++ = '\\';
1108
			esc = 1;
1109
		}
1110
		if (c == EOF) {
1111
			ungetchar(c);
1112
			break;
1113
		}
1114
		if (!esc && c == '~') {
1115
			rhsp = rhsbuf;
1116
#ifdef	BIT8
1117
			rhsq = rhsquo;
1118
#endif
1119
			while (*rhsp) {
1120
#ifndef	BIT8
1121
				if (*rhsp & QUOTE) {
1122
					nextc(c, rhsp, n);
1123
					c &= TRIM;
1124
#else	/* BIT8 */
1125
				if (*rhsq) {
1126
					nextc(c, rhsp, n);
1127
#endif	/* BIT8 */
1128
					if (c == '&')
1129
						error(catgets(catd, 1, 149,
1130
			"Replacement pattern contains &@- cannot use in re"));
1131
					if (c >= '1' && c <= '9')
1132
						error(catgets(catd, 1, 150,
1133
			"Replacement pattern contains \\d@- cannot use in re"));
1134
				}
1135
				if (p >= end - 3)
1136
					goto complex;
1137
				if (*rhsp == '\\' || *rhsp == '[' ||
1138
						*rhsp == '.' ||
1139
						*rhsp == '^' ||
1140
						*rhsp == '*' ||
1141
						*rhsp == '$')
1142
					*p++ = '\\';
1143
#ifdef	BIT8
1144
				nextc(c, rhsp, n);
1145
				for (i = 0; i < n; i++) {
1146
					*p++ = *rhsp++;
1147
					rhsq++;
1148
				}
1149
#else
1150
				*p++ = *rhsp++ & TRIM;
1151
#endif
1152
			}
1153
		} else if (!esc && c == '[') {
1154
			rcnt++;
1155
			/*
1156
			 * Search for the end of the bracket expression
1157
			 * since '~' may not be recognized inside.
1158
			 */
1159
			*p++ = (char)c;
1160
			if (p >= end)
1161
				goto complex;
1162
			d = EOF;
1163
			do {
1164
				c = GETWC(mb);
1165
				if (c == '\n' || c == EOF)
1166
					cerror("Missing ]");
1167
				for (i = 0; mb[i]; i++) {
1168
					*p++ = mb[i];
1169
					if (p >= end)
1170
						goto complex;
1171
				}
1172
#ifdef	UXRE
1173
				if (d == '[' && (c == ':' || c == '.' ||
1174
							c == '=')) {
1175
					d = c;
1176
					do {
1177
						c = GETWC(mb);
1178
						if (c == '\n' || c == EOF)
1179
							cerror("Missing ]");
1180
						for (i = 0; mb[i]; i++) {
1181
							*p++ = mb[i];
1182
							if (p >= end)
1183
								goto complex;
1184
						}
1185
					} while (c != d || peekchar() != ']');
1186
					c = GETWC(mb);
1187
					for (i = 0; mb[i]; i++) {
1188
						*p++ = mb[i];
1189
						if (p >= end)
1190
							goto complex;
1191
					}
1192
					c = EOF; /* -> reset d and continue */
1193
				}
1194
#endif	/* UXRE */
1195
				d = c;
1196
			} while (c != ']');
1197
		} else if (esc && c == '{') {
1198
			/*
1199
			 * Search for the end of the interval expression
1200
			 * since '~' may not be recognized inside.
1201
			 */
1202
			for (i = 0; mb[i]; i++) {
1203
				*p++ = mb[i];
1204
				if (p >= end)
1205
					goto complex;
1206
			}
1207
			do {
1208
				c = GETWC(mb);
1209
				if (c == '\n' || c == EOF)
1210
					cerror(catgets(catd, 1, 143,
1211
			"Bad number|Bad number in regular expression"));
1212
				for (i = 0; mb[i]; i++) {
1213
					*p++ = mb[i];
1214
					if (p >= end)
1215
						goto complex;
1216
				}
1217
			} while (c != '\\');
1218
			c = GETWC(mb);
1219
			if (c != '}')
1220
				cerror(catgets(catd, 1, 146,
1221
					"} expected after \\"));
1222
			*p++ = (char)c;
1223
		} else {
1224
			for (i = 0; mb[i]; i++) {
1225
				*p++ = mb[i];
1226
				if (p >= end)
1227
					goto complex;
1228
			}
1229
		}
1230
		if (p >= end)
1231
complex:		cerror(catgets(catd, 1, 139,
1232
			"Re too complex|Regular expression too complicated"));
1233
	}
1234
	if (p == re.Patbuf)
1235
		*p++ = '.';	/* approximate historical behavior */
1236
	*p = '\0';
1237
	re.Length = rcnt*32 + 2*(p-re.Patbuf) + 5;
1238
	compile1();
1239
	return eof;
1240
}
1241
 
1242
#ifdef	UXRE
1243
int
1244
execute(int gf, line *addr)
1245
{
1246
	char *p;
1247
	int c;
1248
	int eflags = 0, nsub;
1249
	regmatch_t bralist[NBRA + 1];
1250
 
1251
	if (gf) {
1252
		if (re.Circfl)
1253
			return 0;
1254
		eflags |= REG_NOTBOL;
1255
		p = loc2;
1256
	} else {
1257
		if (addr == zero)
1258
			return 0;
1259
		if ((value(IGNORECASE) ? 1:0) ^ (re.Flags & REG_ICASE ? 1:0))
1260
			compile1();
1261
		p = linebuf;
1262
		getline(*addr);
1263
	}
1264
	/*
1265
	 * Need subexpression matches only for substitute command,
1266
	 * so don't fetch them otherwise (enables use of DFA).
1267
	 */
1268
	nsub = (re.Re_ident == subre.Re_ident ? NBRA : 0);
1269
	switch (regexec(re.Expbuf, p, nsub + 1, bralist, eflags)) {
1270
	case 0:
1271
		break;
1272
	case REG_NOMATCH:
1273
		return 0;
1274
	default:
1275
		cerror(catgets(catd, 1, 139,
1276
			"Re too complex|Regular expression too complicated"));
1277
	}
1278
	loc1 = p + bralist[0].rm_so;
1279
	loc2 = p + bralist[0].rm_eo;
1280
	for (c = 0; c < nsub; c++) {
1281
		if (bralist[c + 1].rm_so != -1) {
1282
			braslist[c] = p + bralist[c + 1].rm_so;
1283
			braelist[c] = p + bralist[c + 1].rm_eo;
1284
		} else
1285
			braslist[c] = braelist[c] = NULL;
1286
	}
1287
	return 1;
1288
}
1289
#else	/* !UXRE */
1290
int
1291
execute(int gf, line *addr)
1292
{
1293
	char *p;
1294
 
1295
	if (gf) {
1296
		if (re.Circfl)
1297
			return 0;
1298
		p = locs = loc2;
1299
	} else {
1300
		if (addr == zero)
1301
			return 0;
1302
		p = linebuf;
1303
		getline(*addr);
1304
		if ((value(IGNORECASE) ? 1:0) ^ (re.Flags & REG_ICASE ? 1:0))
1305
			compile1();
1306
		if (value(IGNORECASE))
1307
			loconv(linebuf, linebuf);
1308
		locs = 0;
1309
	}
1310
	circf = re.Circfl;
1311
	return step(p, re.Expbuf);
1312
}
1313
#endif	/* !UXRE */