xref: /plan9/sys/src/ape/cmd/sed/sed0.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include "sed.h"
5 
6 struct label	*labtab = ltab;
7 char	CGMES[]	= "sed: Command garbled: %s\n";
8 char	TMMES[]	= "sed: Too much text: %s\n";
9 char	LTL[]	= "sed: Label too long: %s\n";
10 char	AD0MES[]	= "sed: No addresses allowed: %s\n";
11 char	AD1MES[]	= "sed: Only one address allowed: %s\n";
12 uchar	bittab[]  = {
13 		1,
14 		2,
15 		4,
16 		8,
17 		16,
18 		32,
19 		64,
20 		128
21 	};
22 
23 main(int argc, char **argv)
24 {
25 
26 	eargc = argc;
27 	eargv = (uchar**)argv;
28 
29 	badp = &bad;
30 	aptr = abuf;
31 	hspend = holdsp;
32 	lab = labtab + 1;	/* 0 reserved for end-pointer */
33 	rep = ptrspace;
34 	rep->r1.ad1 = respace;
35 	lbend = &linebuf[LBSIZE];
36 	hend = &holdsp[LBSIZE];
37 	lcomend = &genbuf[64];
38 	ptrend = &ptrspace[PTRSIZE];
39 	reend = &respace[RESIZE];
40 	labend = &labtab[LABSIZE];
41 	lnum = 0;
42 	pending = 0;
43 	depth = 0;
44 	spend = linebuf;
45 	hspend = holdsp;
46 	fcode[0] = stdout;
47 	nfiles = 1;
48 	lastre = NULL;
49 
50 	if(eargc == 1)
51 		exit(0);
52 
53 
54 	while (--eargc > 0 && (++eargv)[0][0] == '-')
55 		switch (eargv[0][1]) {
56 
57 		case 'n':
58 			nflag++;
59 			continue;
60 
61 		case 'f':
62 			if(eargc-- <= 0)	exit(2);
63 
64 			if((fin = fopen((char*)(*++eargv), "r")) == NULL) {
65 				fprintf(stderr, "sed: Cannot open pattern-file: %s\n", *eargv);
66 				exit(2);
67 			}
68 
69 			fcomp();
70 			fclose(fin);
71 			continue;
72 
73 		case 'e':
74 			eflag++;
75 			fcomp();
76 			eflag = 0;
77 			continue;
78 
79 		case 'g':
80 			gflag++;
81 			continue;
82 
83 		default:
84 			fprintf(stderr, "sed: Unknown flag: %c\n", eargv[0][1]);
85 			continue;
86 		}
87 
88 
89 	if(compfl == 0) {
90 		eargv--;
91 		eargc++;
92 		eflag++;
93 		fcomp();
94 		eargv++;
95 		eargc--;
96 		eflag = 0;
97 	}
98 
99 	if(depth) {
100 		fprintf(stderr, "sed: Too many {'s\n");
101 		exit(2);
102 	}
103 
104 	labtab->address = rep;
105 
106 	dechain();
107 
108 /*	abort();	/*DEBUG*/
109 
110 	if(eargc <= 0)
111 		execute((uchar *)NULL);
112 	else while(--eargc >= 0) {
113 		execute(*eargv++);
114 	}
115 	fclose(stdout);
116 	exit(0);
117 }
118 void
119 fcomp(void)
120 {
121 
122 	uchar	*p, *op, *tp;
123     uchar *address(uchar*);
124 	union reptr	*pt, *pt1;
125 	int	i;
126 	struct label	*lpt;
127 
128 	compfl = 1;
129 	op = lastre;
130 
131 	if(rline(linebuf) < 0) {
132 		lastre = op;
133 		return;
134 	}
135 	if(*linebuf == '#') {
136 		if(linebuf[1] == 'n')
137 			nflag = 1;
138 	}
139 	else {
140 		cp = linebuf;
141 		goto comploop;
142 	}
143 
144 	for(;;) {
145 		if(rline(linebuf) < 0)	break;
146 
147 		cp = linebuf;
148 
149 comploop:
150 /*	fprintf(stdout, "cp: %s\n", cp);	/*DEBUG*/
151 		while(*cp == ' ' || *cp == '\t')	cp++;
152 		if(*cp == '\0' || *cp == '#')		continue;
153 		if(*cp == ';') {
154 			cp++;
155 			goto comploop;
156 		}
157 
158 		p = address(rep->r1.ad1);
159 		if(p == badp) {
160 			fprintf(stderr, CGMES, linebuf);
161 			exit(2);
162 		}
163 
164 		if(p == 0) {
165 			p = rep->r1.ad1;
166 			rep->r1.ad1 = 0;
167 		} else {
168 			if(p == rep->r1.ad1) {
169 				if(op)
170 					rep->r1.ad1 = op;
171 				else {
172 					fprintf(stderr, "sed: First RE may not be null\n");
173 					exit(2);
174 				}
175 			}
176 			if(*rep->r1.ad1 != CLNUM && *rep->r1.ad1 != CEND)
177 				op = rep->r1.ad1;
178 			if(*cp == ',' || *cp == ';') {
179 				cp++;
180 				if((rep->r1.ad2 = p) > reend) {
181 					fprintf(stderr, TMMES, linebuf);
182 					exit(2);
183 				}
184 				p = address(rep->r1.ad2);
185 				if(p == badp || p == 0) {
186 					fprintf(stderr, CGMES, linebuf);
187 					exit(2);
188 				}
189 				if(p == rep->r1.ad2)
190 					rep->r1.ad2 = op;
191 				else{
192 				if(*rep->r1.ad2 != CLNUM && *rep->r1.ad2 != CEND)
193 					op = rep->r1.ad2;
194 				}
195 
196 			} else
197 				rep->r1.ad2 = 0;
198 		}
199 
200 		if(p > reend) {
201 			fprintf(stderr, "sed: Too much text: %s\n", linebuf);
202 			exit(2);
203 		}
204 
205 		while(*cp == ' ' || *cp == '\t')	cp++;
206 
207 swit:
208 		switch(*cp++) {
209 
210 			default:
211 /*fprintf(stderr, "cp = %d; *cp = %o\n", cp - linebuf, *cp);*/
212 				fprintf(stderr, "sed: Unrecognized command: %s\n", linebuf);
213 				exit(2);
214 
215 			case '!':
216 				rep->r1.negfl = 1;
217 				goto swit;
218 
219 			case '{':
220 				rep->r1.command = BCOM;
221 				rep->r1.negfl = !(rep->r1.negfl);
222 				cmpend[depth++] = &rep->r2.lb1;
223 				if(++rep >= ptrend) {
224 					fprintf(stderr, "sed: Too many commands: %s\n", linebuf);
225 					exit(2);
226 				}
227 				rep->r1.ad1 = p;
228 				if(*cp == '\0')	continue;
229 
230 				goto comploop;
231 
232 			case '}':
233 				if(rep->r1.ad1) {
234 					fprintf(stderr, AD0MES, linebuf);
235 					exit(2);
236 				}
237 
238 				if(--depth < 0) {
239 					fprintf(stderr, "sed: Too many }'s\n");
240 					exit(2);
241 				}
242 				*cmpend[depth] = rep;
243 
244 				rep->r1.ad1 = p;
245 				if(*cp == 0)	continue;
246 				goto comploop;
247 
248 			case '=':
249 				rep->r1.command = EQCOM;
250 				if(rep->r1.ad2) {
251 					fprintf(stderr, AD1MES, linebuf);
252 					exit(2);
253 				}
254 				break;
255 
256 			case ':':
257 				if(rep->r1.ad1) {
258 					fprintf(stderr, AD0MES, linebuf);
259 					exit(2);
260 				}
261 
262 				while(*cp++ == ' ');
263 				cp--;
264 
265 
266 				tp = lab->asc;
267 				while((*tp = *cp++) && *tp != ';')
268 					if(++tp >= &(lab->asc[8])) {
269 						fprintf(stderr, LTL, linebuf);
270 						exit(2);
271 					}
272 				*tp = '\0';
273 				if(*lab->asc == 0) {
274 					fprintf(stderr, CGMES, linebuf);
275 					exit(2);
276 				}
277 
278 				if(lpt = search(lab)) {
279 					if(lpt->address) {
280 						fprintf(stderr, "sed: Duplicate labels: %s\n", linebuf);
281 						exit(2);
282 					}
283 				} else {
284 					lab->chain = 0;
285 					lpt = lab;
286 					if(++lab >= labend) {
287 						fprintf(stderr, "sed: Too many labels: %s\n", linebuf);
288 						exit(2);
289 					}
290 				}
291 				lpt->address = rep;
292 				rep->r1.ad1 = p;
293 
294 				continue;
295 
296 			case 'a':
297 				rep->r1.command = ACOM;
298 				if(rep->r1.ad2) {
299 					fprintf(stderr, AD1MES, linebuf);
300 					exit(2);
301 				}
302 				if(*cp == '\\')	cp++;
303 				if(*cp++ != '\n') {
304 					fprintf(stderr, CGMES, linebuf);
305 					exit(2);
306 				}
307 				rep->r1.re1 = p;
308 				p = text(rep->r1.re1);
309 				break;
310 			case 'c':
311 				rep->r1.command = CCOM;
312 				if(*cp == '\\')	cp++;
313 				if(*cp++ != ('\n')) {
314 					fprintf(stderr, CGMES, linebuf);
315 					exit(2);
316 				}
317 				rep->r1.re1 = p;
318 				p = text(rep->r1.re1);
319 				break;
320 			case 'i':
321 				rep->r1.command = ICOM;
322 				if(rep->r1.ad2) {
323 					fprintf(stderr, AD1MES, linebuf);
324 					exit(2);
325 				}
326 				if(*cp == '\\')	cp++;
327 				if(*cp++ != ('\n')) {
328 					fprintf(stderr, CGMES, linebuf);
329 					exit(2);
330 				}
331 				rep->r1.re1 = p;
332 				p = text(rep->r1.re1);
333 				break;
334 
335 			case 'g':
336 				rep->r1.command = GCOM;
337 				break;
338 
339 			case 'G':
340 				rep->r1.command = CGCOM;
341 				break;
342 
343 			case 'h':
344 				rep->r1.command = HCOM;
345 				break;
346 
347 			case 'H':
348 				rep->r1.command = CHCOM;
349 				break;
350 
351 			case 't':
352 				rep->r1.command = TCOM;
353 				goto jtcommon;
354 
355 			case 'b':
356 				rep->r1.command = BCOM;
357 jtcommon:
358 				while(*cp++ == ' ');
359 				cp--;
360 
361 				if(*cp == '\0') {
362 					if(pt = labtab->chain) {
363 						while(pt1 = pt->r2.lb1)
364 							pt = pt1;
365 						pt->r2.lb1 = rep;
366 					} else
367 						labtab->chain = rep;
368 					break;
369 				}
370 				tp = lab->asc;
371 				while((*tp = *cp++) && *tp != ';')
372 					if(++tp >= &(lab->asc[8])) {
373 						fprintf(stderr, LTL, linebuf);
374 						exit(2);
375 					}
376 				cp--;
377 				*tp = '\0';
378 				if(*lab->asc == 0) {
379 					fprintf(stderr, CGMES, linebuf);
380 					exit(2);
381 				}
382 
383 				if(lpt = search(lab)) {
384 					if(lpt->address) {
385 						rep->r2.lb1 = lpt->address;
386 					} else {
387 						pt = lpt->chain;
388 						while(pt1 = pt->r2.lb1)
389 							pt = pt1;
390 						pt->r2.lb1 = rep;
391 					}
392 				} else {
393 					lab->chain = rep;
394 					lab->address = 0;
395 					if(++lab >= labend) {
396 						fprintf(stderr, "sed: Too many labels: %s\n", linebuf);
397 						exit(2);
398 					}
399 				}
400 				break;
401 
402 			case 'n':
403 				rep->r1.command = NCOM;
404 				break;
405 
406 			case 'N':
407 				rep->r1.command = CNCOM;
408 				break;
409 
410 			case 'p':
411 				rep->r1.command = PCOM;
412 				break;
413 
414 			case 'P':
415 				rep->r1.command = CPCOM;
416 				break;
417 
418 			case 'r':
419 				rep->r1.command = RCOM;
420 				if(rep->r1.ad2) {
421 					fprintf(stderr, AD1MES, linebuf);
422 					exit(2);
423 				}
424 				if(*cp++ != ' ') {
425 					fprintf(stderr, CGMES, linebuf);
426 					exit(2);
427 				}
428 				rep->r1.re1 = p;
429 				p = text(rep->r1.re1);
430 				break;
431 
432 			case 'd':
433 				rep->r1.command = DCOM;
434 				break;
435 
436 			case 'D':
437 				rep->r1.command = CDCOM;
438 				rep->r2.lb1 = ptrspace;
439 				break;
440 
441 			case 'q':
442 				rep->r1.command = QCOM;
443 				if(rep->r1.ad2) {
444 					fprintf(stderr, AD1MES, linebuf);
445 					exit(2);
446 				}
447 				break;
448 
449 			case 'l':
450 				rep->r1.command = LCOM;
451 				break;
452 
453 			case 's':
454 				rep->r1.command = SCOM;
455 				seof = *cp++;
456 				rep->r1.re1 = p;
457 				p = compile(rep->r1.re1);
458 				if(p == badp) {
459 					fprintf(stderr, CGMES, linebuf);
460 					exit(2);
461 				}
462 				if(p == rep->r1.re1) {
463 					if(op == NULL) {
464 						fprintf(stderr, "sed: First RE may not be null.\n");
465 						exit(2);
466 					}
467 					rep->r1.re1 = op;
468 				} else {
469 					op = rep->r1.re1;
470 				}
471 
472 				if((rep->r1.rhs = p) > reend) {
473 					fprintf(stderr, TMMES, linebuf);
474 					exit(2);
475 				}
476 
477 				if((p = compsub(rep->r1.rhs)) == badp) {
478 					fprintf(stderr, CGMES, linebuf);
479 					exit(2);
480 				}
481 				if(*cp == 'g') {
482 					cp++;
483 					rep->r1.gfl++;
484 				} else if(gflag)
485 					rep->r1.gfl++;
486 
487 				if(*cp == 'p') {
488 					cp++;
489 					rep->r1.pfl = 1;
490 				}
491 
492 				if(*cp == 'P') {
493 					cp++;
494 					rep->r1.pfl = 2;
495 				}
496 
497 				if(*cp == 'w') {
498 					cp++;
499 					if(*cp++ !=  ' ') {
500 						fprintf(stderr, CGMES, linebuf);
501 						exit(2);
502 					}
503 					if(nfiles >= MAXFILES) {
504 						fprintf(stderr, "sed: Too many files in w commands 1 \n");
505 						exit(2);
506 					}
507 
508 					text((uchar*)fname[nfiles]);
509 					for(i = nfiles - 1; i >= 0; i--)
510 						if(cmp((uchar*)fname[nfiles],(uchar*)fname[i]) == 0) {
511 							rep->r1.fcode = fcode[i];
512 							goto done;
513 						}
514 					if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
515 						fprintf(stderr, "sed: Cannot open %s\n", fname[nfiles]);
516 						exit(2);
517 					}
518 					fcode[nfiles++] = rep->r1.fcode;
519 				}
520 				break;
521 
522 			case 'w':
523 				rep->r1.command = WCOM;
524 				if(*cp++ != ' ') {
525 					fprintf(stderr, CGMES, linebuf);
526 					exit(2);
527 				}
528 				if(nfiles >= MAXFILES){
529 					fprintf(stderr, "sed: Too many files in w commands 2 \n");
530 					fprintf(stderr, "nfiles = %d; MAXF = %d\n", nfiles, MAXFILES);
531 					exit(2);
532 				}
533 
534 				text((uchar*)fname[nfiles]);
535 				for(i = nfiles - 1; i >= 0; i--)
536 					if(cmp((uchar*)fname[nfiles], (uchar*)fname[i]) == 0) {
537 						rep->r1.fcode = fcode[i];
538 						goto done;
539 					}
540 
541 				if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
542 					fprintf(stderr, "sed: Cannot create %s\n", fname[nfiles]);
543 					exit(2);
544 				}
545 				fcode[nfiles++] = rep->r1.fcode;
546 				break;
547 
548 			case 'x':
549 				rep->r1.command = XCOM;
550 				break;
551 
552 			case 'y':
553 				rep->r1.command = YCOM;
554 				seof = *cp++;
555 				rep->r1.re1 = p;
556 				p = ycomp(rep->r1.re1);
557 				if(p == badp) {
558 					fprintf(stderr, CGMES, linebuf);
559 					exit(2);
560 				}
561 				if(p > reend) {
562 					fprintf(stderr, TMMES, linebuf);
563 					exit(2);
564 				}
565 				break;
566 
567 		}
568 done:
569 		if(++rep >= ptrend) {
570 			fprintf(stderr, "sed: Too many commands, last: %s\n", linebuf);
571 			exit(2);
572 		}
573 
574 		rep->r1.ad1 = p;
575 
576 		if(*cp++ != '\0') {
577 			if(cp[-1] == ';')
578 				goto comploop;
579 			fprintf(stderr, CGMES, linebuf);
580 			exit(2);
581 		}
582 
583 	}
584 }
585 
586 uchar	*
587 compsub(uchar *rhsbuf)
588 {
589 	uchar	*p, *q, *r;
590 	p = rhsbuf;
591 	q = cp;
592 	for(;;) {
593 		if((*p = *q++) == '\\') {
594 			*++p = *q++;
595 			if(*p >= '1' && *p <= '9' && *p > numbra + '0')
596 				return(badp);
597 			if(*p == 'n')
598 				*--p = '\n';
599 		} else if(*p == seof) {
600 			*p++ = '\0';
601 			cp = q;
602 			return(p);
603 		}
604 		if(*p++ == '\0') {
605 			return(badp);
606 		}
607 
608 	}
609 }
610 
611 uchar *
612 compile(uchar *expbuf)
613 {
614 	int c;
615 	uchar *ep, *sp;
616 	uchar	neg;
617 	uchar *lastep, *cstart;
618 	int cclcnt;
619 	int	closed;
620 	uchar	bracket[NBRA], *bracketp;
621 
622 	if(*cp == seof) {
623 		cp++;
624 		return(expbuf);
625 	}
626 
627 	ep = expbuf;
628 	lastep = 0;
629 	bracketp = bracket;
630 	closed = numbra = 0;
631 	sp = cp;
632 	if (*sp == '^') {
633 		*ep++ = 1;
634 		sp++;
635 	} else {
636 		*ep++ = 0;
637 	}
638 	for (;;) {
639 		if (ep >= reend) {
640 			cp = sp;
641 			return(badp);
642 		}
643 		if((c = *sp++) == seof) {
644 			if(bracketp != bracket) {
645 				cp = sp;
646 				return(badp);
647 			}
648 			cp = sp;
649 			*ep++ = CEOF;
650 			return(ep);
651 		}
652 		if(c != '*')
653 			lastep = ep;
654 		switch (c) {
655 
656 		case '\\':
657 			if((c = *sp++) == '(') {
658 				if(numbra >= NBRA) {
659 					cp = sp;
660 					return(badp);
661 				}
662 				*bracketp++ = numbra;
663 				*ep++ = CBRA;
664 				*ep++ = numbra++;
665 				continue;
666 			}
667 			if(c == ')') {
668 				if(bracketp <= bracket) {
669 					cp = sp;
670 					return(badp);
671 				}
672 				*ep++ = CKET;
673 				*ep++ = *--bracketp;
674 				closed++;
675 				continue;
676 			}
677 
678 			if(c >= '1' && c <= '9') {
679 				if((c -= '1') >= closed)
680 					return(badp);
681 
682 				*ep++ = CBACK;
683 				*ep++ = c;
684 				continue;
685 			}
686 			if(c == '\n') {
687 				cp = sp;
688 				return(badp);
689 			}
690 			if(c == 'n') {
691 				c = '\n';
692 			}
693 			goto defchar;
694 
695 		case '\0':
696 		case '\n':
697 			cp = sp;
698 			return(badp);
699 
700 		case '.':
701 			*ep++ = CDOT;
702 			continue;
703 
704 		case '*':
705 			if (lastep == 0)
706 				goto defchar;
707 			if(*lastep == CKET) {
708 				cp = sp;
709 				return(badp);
710 			}
711 			*lastep |= STAR;
712 			continue;
713 
714 		case '$':
715 			if (*sp != seof)
716 				goto defchar;
717 			*ep++ = CDOL;
718 			continue;
719 
720 		case '[':
721 			if(&ep[33] >= reend) {
722 				fprintf(stderr, "sed: RE too long: %s\n", linebuf);
723 				exit(2);
724 			}
725 
726 			*ep++ = CCL;
727 
728 			neg = 0;
729 			if((c = *sp++) == '^') {
730 				neg = 1;
731 				c = *sp++;
732 			}
733 
734 			cstart = sp;
735 			do {
736 				if(c == '\0') {
737 					fprintf(stderr, CGMES, linebuf);
738 					exit(2);
739 				}
740 				if (c=='-' && sp>cstart && *sp!=']') {
741 					for (c = sp[-2]; c<*sp; c++)
742 						ep[c>>3] |= bittab[c&07];
743 				}
744 				if(c == '\\') {
745 					switch(c = *sp++) {
746 						case 'n':
747 							c = '\n';
748 							break;
749 					}
750 				}
751 
752 				ep[c >> 3] |= bittab[c & 07];
753 			} while((c = *sp++) != ']');
754 
755 			if(neg)
756 				for(cclcnt = 0; cclcnt < 32; cclcnt++)
757 					ep[cclcnt] ^= -1;
758 			ep[0] &= 0376;
759 
760 			ep += 32;
761 
762 			continue;
763 
764 		defchar:
765 		default:
766 			*ep++ = CCHR;
767 			*ep++ = c;
768 		}
769 	}
770 }
771 int
772 rline(uchar *lbuf)
773 {
774 	uchar	*p, *q;
775 	int	t;
776 	static uchar	*saveq;
777 
778 	p = lbuf - 1;
779 
780 	if(eflag) {
781 		if(eflag > 0) {
782 			eflag = -1;
783 			if(eargc-- <= 0)
784 				exit(2);
785 			q = *++eargv;
786 			while(*++p = *q++) {
787 				if(*p == '\\') {
788 					if((*++p = *q++) == '\0') {
789 						saveq = 0;
790 						return(-1);
791 					} else
792 						continue;
793 				}
794 				if(*p == '\n') {
795 					*p = '\0';
796 					saveq = q;
797 					return(1);
798 				}
799 			}
800 			saveq = 0;
801 			return(1);
802 		}
803 		if((q = saveq) == 0)	return(-1);
804 
805 		while(*++p = *q++) {
806 			if(*p == '\\') {
807 				if((*++p = *q++) == '0') {
808 					saveq = 0;
809 					return(-1);
810 				} else
811 					continue;
812 			}
813 			if(*p == '\n') {
814 				*p = '\0';
815 				saveq = q;
816 				return(1);
817 			}
818 		}
819 		saveq = 0;
820 		return(1);
821 	}
822 
823 	while((t = getc(fin)) != EOF) {
824 		*++p = t;
825 		if(*p == '\\') {
826 			t = getc(fin);
827 			*++p = t;
828 		}
829 		else if(*p == '\n') {
830 			*p = '\0';
831 			return(1);
832 		}
833 	}
834 	*++p = '\0';
835 	return(-1);
836 }
837 
838 uchar *
839 address(uchar *expbuf)
840 {
841 	uchar	*rcp;
842 	long	lno;
843 
844 	if(*cp == '$') {
845 		cp++;
846 		*expbuf++ = CEND;
847 		*expbuf++ = CEOF;
848 		return(expbuf);
849 	}
850 
851 	if(*cp == '/') {
852 		seof = '/';
853 		cp++;
854 		return(compile(expbuf));
855 	}
856 
857 	rcp = cp;
858 	lno = 0;
859 
860 	while(*rcp >= '0' && *rcp <= '9')
861 		lno = lno*10 + *rcp++ - '0';
862 
863 	if(rcp > cp) {
864 		if(!lno){
865 			fprintf(stderr, "sed: line number 0 is illegal\n");
866 			exit(2);
867 		}
868 		*expbuf++ = CLNUM;
869 		*expbuf++ = lno;
870 		*expbuf++ = lno >> 8;
871 		*expbuf++ = lno >> 16;
872 		*expbuf++ = lno >> 24;
873 		*expbuf++ = CEOF;
874 		cp = rcp;
875 		return(expbuf);
876 	}
877 	return(0);
878 }
879 int
880 cmp(uchar *a, uchar *b)
881 {
882 	uchar	*ra, *rb;
883 
884 	ra = a - 1;
885 	rb = b - 1;
886 
887 	while(*++ra == *++rb)
888 		if(*ra == '\0')	return(0);
889 	return(1);
890 }
891 
892 uchar *
893 text(uchar *textbuf)
894 {
895 	uchar	*p, *q;
896 
897 	p = textbuf;
898 	q = cp;
899 	while(*q == '\t' || *q == ' ')	q++;
900 	for(;;) {
901 
902 		if((*p = *q++) == '\\')
903 			*p = *q++;
904 		if(*p == '\0') {
905 			cp = --q;
906 			return(++p);
907 		}
908 		if(*p == '\n') {
909 			while(*q == '\t' || *q == ' ')	q++;
910 		}
911 		p++;
912 	}
913 }
914 
915 
916 struct label *
917 search(struct label *ptr)
918 {
919 	struct label	*rp;
920 
921 	rp = labtab;
922 	while(rp < ptr) {
923 		if(cmp(rp->asc, ptr->asc) == 0)
924 			return(rp);
925 		rp++;
926 	}
927 
928 	return(0);
929 }
930 
931 void
932 dechain(void)
933 {
934 	struct label	*lptr;
935 	union reptr	*rptr, *trptr;
936 
937 	for(lptr = labtab; lptr < lab; lptr++) {
938 
939 		if(lptr->address == 0) {
940 			fprintf(stderr, "sed: Undefined label: %s\n", lptr->asc);
941 			exit(2);
942 		}
943 
944 		if(lptr->chain) {
945 			rptr = lptr->chain;
946 			while(trptr = rptr->r2.lb1) {
947 				rptr->r2.lb1 = lptr->address;
948 				rptr = trptr;
949 			}
950 			rptr->r2.lb1 = lptr->address;
951 		}
952 	}
953 }
954 
955 uchar *
956 ycomp(uchar *expbuf)
957 {
958 	uchar *ep, *tsp;
959 	int c;
960 	uchar	*sp;
961 
962 	ep = expbuf;
963 	sp = cp;
964 	for(tsp = cp; *tsp != seof; tsp++) {
965 		if(*tsp == '\\')
966 			tsp++;
967 		if(*tsp == '\n' || *tsp == '\0')
968 			return(badp);
969 	}
970 	tsp++;
971 
972 	while((c = *sp++) != seof) {
973 		if(c == '\\' && *sp == 'n') {
974 			sp++;
975 			c = '\n';
976 		}
977 		if((ep[c] = *tsp++) == '\\' && *tsp == 'n') {
978 			ep[c] = '\n';
979 			tsp++;
980 		}
981 		if(ep[c] == seof || ep[c] == '\0')
982 			return(badp);
983 	}
984 	if(*tsp != seof)
985 		return(badp);
986 	cp = ++tsp;
987 
988 	for(c = 0; c<0400; c++)
989 		if(ep[c] == 0)
990 			ep[c] = c;
991 
992 	return(ep + 0400);
993 }
994 
995