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