xref: /illumos-gate/usr/src/ucbcmd/sed/sed0.c (revision e86372a01d2d16a5dd4a64e144ed978ba17fe7dd)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <sys/param.h>
32 #include "sed.h"
33 
34 #define	NWFILES		11	/* 10 plus one for standard output */
35 FILE	*fin;
36 FILE    *fcode[NWFILES];
37 char    *lastre;
38 char    sseof;
39 union reptr     *ptrend;
40 int     eflag;
41 extern	int	nbra;
42 char    linebuf[LBSIZE+1];
43 int     gflag;
44 int     nlno;
45 char    *fname[NWFILES];
46 int     nfiles;
47 union reptr ptrspace[PTRSIZE];
48 union reptr *rep;
49 char    *cp;
50 char    respace[RESIZE];
51 struct label ltab[LABSIZE];
52 struct label    *lab;
53 struct label    *labend;
54 int     depth;
55 int     eargc;
56 char    **eargv;
57 union reptr     **cmpend[DEPTH];
58 
59 #define CCEOF	22
60 
61 struct label    *labtab = ltab;
62 
63 char	ETMES[]		= "Extra text at end of command: %s";
64 char	SMMES[]		= "Space missing before filename: %s";
65 char    TMMES[]		= "Too much command text: %s";
66 char    LTL[]  		= "Label too long: %s";
67 char    AD0MES[]	= "No addresses allowed: %s";
68 char    AD1MES[]	= "Only one address allowed: %s";
69 char	TOOBIG[]	= "Suffix too large - 512 max: %s";
70 
71 extern int sed;	  /* IMPORTANT flag !!! */
72 extern char *comple();
73 
74 static void dechain(void);
75 static void fcomp(void);
76 
77 int
78 main(int argc, char *argv[])
79 {
80 	int flag_found = 0;
81 
82 	sed = 1;
83 	eargc = argc;
84 	eargv = argv;
85 
86 	aptr = abuf;
87 	lab = labtab + 1;       /* 0 reserved for end-pointer */
88 	rep = ptrspace;
89 	rep->r1.ad1 = respace;
90 	lcomend = &genbuf[71];
91 	ptrend = &ptrspace[PTRSIZE];
92 	labend = &labtab[LABSIZE];
93 	lnum = 0;
94 	pending = 0;
95 	depth = 0;
96 	spend = linebuf;
97 	hspend = holdsp;	/* Avoid "bus error" under "H" cmd. */
98 	fcode[0] = stdout;
99 	fname[0] = "";
100 	nfiles = 1;
101 
102 	if(eargc == 1)
103 		exit(0);
104 
105 
106 	setlocale(LC_ALL, "");		/* get locale environment */
107 
108 	while (--eargc > 0 && (++eargv)[0][0] == '-')
109 		switch (eargv[0][1]) {
110 
111 		case 'n':
112 			nflag++;
113 			continue;
114 
115 		case 'f':
116 			flag_found = 1;
117 			if(eargc-- <= 0)	exit(2);
118 
119 			if((fin = fopen(*++eargv, "r")) == NULL) {
120 				(void) fprintf(stderr, "sed: ");
121 				perror(*eargv);
122 				exit(2);
123 			}
124 
125 			fcomp();
126 			(void) fclose(fin);
127 			continue;
128 
129 		case 'e':
130 			flag_found = 1;
131 			eflag++;
132 			fcomp();
133 			eflag = 0;
134 			continue;
135 
136 		case 'g':
137 			gflag++;
138 			continue;
139 
140 		default:
141 			(void) fprintf(stderr, "sed: Unknown flag: %c\n", eargv[0][1]);
142 			exit(2);
143 		}
144 
145 
146 	if(rep == ptrspace && !flag_found) {
147 		eargv--;
148 		eargc++;
149 		eflag++;
150 		fcomp();
151 		eargv++;
152 		eargc--;
153 		eflag = 0;
154 	}
155 
156 	if(depth)
157 		comperr("Too many {'s");
158 
159 	labtab->address = rep;
160 
161 	dechain();
162 
163 	if(eargc <= 0)
164 		execute((char *)NULL);
165 	else while(--eargc >= 0) {
166 		execute(*eargv++);
167 	}
168 	(void) fclose(stdout);
169 	return (0);
170 }
171 
172 static void
173 fcomp(void)
174 {
175 
176 	char   *p, *op, *tp;
177 	char    *address();
178 	union reptr     *pt, *pt1;
179 	int     i, ii;
180 	struct label    *lpt;
181 	char fnamebuf[MAXPATHLEN];
182 
183 	op = lastre;
184 
185 	if(rline(linebuf, &linebuf[LBSIZE+1]) < 0)  return;
186 	if(*linebuf == '#') {
187 		if(linebuf[1] == 'n')
188 			nflag = 1;
189 	}
190 	else {
191 		cp = linebuf;
192 		goto comploop;
193 	}
194 
195 	for(;;) {
196 		if(rline(linebuf, &linebuf[LBSIZE+1]) < 0)  break;
197 
198 		cp = linebuf;
199 
200 comploop:
201 /*		(void) fprintf(stderr, "cp: %s\n", cp); DEBUG */
202 		while(*cp == ' ' || *cp == '\t')	cp++;
203 		if(*cp == '\0' || *cp == '#')	 continue;
204 		if(*cp == ';') {
205 			cp++;
206 			goto comploop;
207 		}
208 
209 		p = address(rep->r1.ad1);
210 
211 		if(p == rep->r1.ad1) {
212 			if(op)
213 				rep->r1.ad1 = op;
214 			else
215 				comperr("First RE may not be null: %s");
216 		} else if(p == 0) {
217 			p = rep->r1.ad1;
218 			rep->r1.ad1 = 0;
219 		} else {
220 			op = rep->r1.ad1;
221 			if(*cp == ',' || *cp == ';') {
222 				cp++;
223 				rep->r1.ad2 = p;
224 				p = address(rep->r1.ad2);
225 				if(p == 0)
226 					comperr("Illegal line number: %s");
227 				if(p == rep->r1.ad2)
228 					rep->r1.ad2 = op;
229 				else
230 					op = rep->r1.ad2;
231 
232 			} else
233 				rep->r1.ad2 = 0;
234 		}
235 
236 		if(p > &respace[RESIZE-1])
237 			comperr(TMMES);
238 
239 		while(*cp == ' ' || *cp == '\t')	cp++;
240 
241 swit:
242 		switch(*cp++) {
243 
244 			default:
245 				comperr("Unrecognized command: %s");
246 
247 			case '!':
248 				rep->r1.negfl = 1;
249 				goto swit;
250 
251 			case '{':
252 				rep->r1.command = BCOM;
253 				rep->r1.negfl = !(rep->r1.negfl);
254 				cmpend[depth++] = &rep->r2.lb1;
255 				if(++rep >= ptrend)
256 					comperr("Too many commands: %s");
257 				rep->r1.ad1 = p;
258 				if(*cp == '\0') continue;
259 
260 				goto comploop;
261 
262 			case '}':
263 				if(rep->r1.ad1)
264 					comperr(AD0MES);
265 
266 				if(--depth < 0)
267 					comperr("Too many }'s");
268 				*cmpend[depth] = rep;
269 
270 				rep->r1.ad1 = p;
271 				continue;
272 
273 			case '=':
274 				rep->r1.command = EQCOM;
275 				if(rep->r1.ad2)
276 					comperr(AD1MES);
277 				break;
278 
279 			case ':':
280 				if(rep->r1.ad1)
281 					comperr(AD0MES);
282 
283 				while(*cp++ == ' ');
284 				cp--;
285 
286 
287 				tp = lab->asc;
288 				while((*tp++ = *cp++))
289 					if(tp >= &(lab->asc[9]))
290 						comperr(LTL);
291 				*--tp = '\0';
292 
293 				if(lpt = search(lab)) {
294 					if(lpt->address)
295 						comperr("Duplicate labels: %s");
296 				} else {
297 					lab->chain = 0;
298 					lpt = lab;
299 					if(++lab >= labend)
300 						comperr("Too many labels: %s");
301 				}
302 				lpt->address = rep;
303 				rep->r1.ad1 = p;
304 
305 				continue;
306 
307 			case 'a':
308 				rep->r1.command = ACOM;
309 				if(rep->r1.ad2)
310 					comperr(AD1MES);
311 				if(*cp == '\\') cp++;
312 				if(*cp++ != '\n')
313 					comperr(ETMES);
314 				rep->r1.re1 = p;
315 				if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL)
316 					comperr(TMMES);
317 				break;
318 			case 'c':
319 				rep->r1.command = CCOM;
320 				if(*cp == '\\') cp++;
321 				if(*cp++ != ('\n'))
322 					comperr(ETMES);
323 				rep->r1.re1 = p;
324 				if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL)
325 					comperr(TMMES);
326 				break;
327 			case 'i':
328 				rep->r1.command = ICOM;
329 				if(rep->r1.ad2)
330 					comperr(AD1MES);
331 				if(*cp == '\\') cp++;
332 				if(*cp++ != ('\n'))
333 					comperr(ETMES);
334 				rep->r1.re1 = p;
335 				if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL)
336 					comperr(TMMES);
337 				break;
338 
339 			case 'g':
340 				rep->r1.command = GCOM;
341 				break;
342 
343 			case 'G':
344 				rep->r1.command = CGCOM;
345 				break;
346 
347 			case 'h':
348 				rep->r1.command = HCOM;
349 				break;
350 
351 			case 'H':
352 				rep->r1.command = CHCOM;
353 				break;
354 
355 			case 't':
356 				rep->r1.command = TCOM;
357 				goto jtcommon;
358 
359 			case 'b':
360 				rep->r1.command = BCOM;
361 jtcommon:
362 				while(*cp++ == ' ');
363 				cp--;
364 
365 				if(*cp == '\0') {
366 					if(pt = labtab->chain) {
367 						while(pt1 = pt->r2.lb1)
368 							pt = pt1;
369 						pt->r2.lb1 = rep;
370 					} else
371 						labtab->chain = rep;
372 					break;
373 				}
374 				tp = lab->asc;
375 				while((*tp++ = *cp++))
376 					if(tp >= &(lab->asc[9]))
377 						comperr(LTL);
378 				cp--;
379 				*--tp = '\0';
380 
381 				if(lpt = search(lab)) {
382 					if(lpt->address) {
383 						rep->r2.lb1 = lpt->address;
384 					} else {
385 						pt = lpt->chain;
386 						while(pt1 = pt->r2.lb1)
387 							pt = pt1;
388 						pt->r2.lb1 = rep;
389 					}
390 				} else {
391 					lab->chain = rep;
392 					lab->address = 0;
393 					if(++lab >= labend)
394 						comperr("Too many labels: %s");
395 				}
396 				break;
397 
398 			case 'n':
399 				rep->r1.command = NCOM;
400 				break;
401 
402 			case 'N':
403 				rep->r1.command = CNCOM;
404 				break;
405 
406 			case 'p':
407 				rep->r1.command = PCOM;
408 				break;
409 
410 			case 'P':
411 				rep->r1.command = CPCOM;
412 				break;
413 
414 			case 'r':
415 				rep->r1.command = RCOM;
416 				if(rep->r1.ad2)
417 					comperr(AD1MES);
418 				if(*cp++ != ' ')
419 					comperr(SMMES);
420 				rep->r1.re1 = p;
421 				if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL)
422 					comperr(TMMES);
423 				break;
424 
425 			case 'd':
426 				rep->r1.command = DCOM;
427 				break;
428 
429 			case 'D':
430 				rep->r1.command = CDCOM;
431 				rep->r2.lb1 = ptrspace;
432 				break;
433 
434 			case 'q':
435 				rep->r1.command = QCOM;
436 				if(rep->r1.ad2)
437 					comperr(AD1MES);
438 				break;
439 
440 			case 'l':
441 				rep->r1.command = LCOM;
442 				break;
443 
444 			case 's':
445 				rep->r1.command = SCOM;
446 				sseof = *cp++;
447 				rep->r1.re1 = p;
448 				p = comple((char *) 0, rep->r1.re1, &respace[RESIZE-1], sseof);
449 				if(p == rep->r1.re1) {
450 					if(op)
451 						rep->r1.re1 = op;
452 					else
453 						comperr("First RE may not be null: %s");
454 				} else
455 					op = rep->r1.re1;
456 				rep->r1.rhs = p;
457 
458 				p = compsub(rep->r1.rhs);
459 
460 				if(*cp == 'g') {
461 					cp++;
462 					rep->r1.gfl = 999;
463 				} else if(gflag)
464 					rep->r1.gfl = 999;
465 
466 				if(*cp >= '1' && *cp <= '9')
467 					{i = *cp - '0';
468 					cp++;
469 					while(1)
470 						{ii = *cp;
471 						if(ii < '0' || ii > '9') break;
472 						i = i*10 + ii - '0';
473 						if(i > 512)
474 							comperr(TOOBIG);
475 						cp++;
476 						}
477 					rep->r1.gfl = i;
478 					}
479 
480 				if(*cp == 'p') {
481 					cp++;
482 					rep->r1.pfl = 1;
483 				}
484 
485 				if(*cp == 'P') {
486 					cp++;
487 					rep->r1.pfl = 2;
488 				}
489 
490 				if(*cp == 'w') {
491 					cp++;
492 					if(*cp++ !=  ' ')
493 						comperr(SMMES);
494 					if (text(fnamebuf, &fnamebuf[MAXPATHLEN]) == NULL)
495 						comperr("File name too long: %s");
496 					for(i = nfiles - 1; i >= 0; i--)
497 						if(strcmp(fnamebuf,fname[i]) == 0) {
498 							rep->r1.fcode = fcode[i];
499 							goto done;
500 						}
501 					if(nfiles >= NWFILES)
502 						comperr("Too many files in w commands: %s");
503 
504 					i = strlen(fnamebuf) + 1;
505 					if ((fname[nfiles] = malloc((unsigned)i)) == NULL) {
506 						(void) fprintf(stderr, "sed: Out of memory\n");
507 						exit(2);
508 					}
509 					(void) strcpy(fname[nfiles], fnamebuf);
510 					if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
511 						(void) fprintf(stderr, "sed: Cannot open ");
512 						perror(fname[nfiles]);
513 						exit(2);
514 					}
515 					fcode[nfiles++] = rep->r1.fcode;
516 				}
517 				break;
518 
519 			case 'w':
520 				rep->r1.command = WCOM;
521 				if(*cp++ != ' ')
522 					comperr(SMMES);
523 				if (text(fnamebuf, &fnamebuf[MAXPATHLEN]) == NULL)
524 					comperr("File name too long: %s");
525 				for(i = nfiles - 1; i >= 0; i--)
526 					if(strcmp(fnamebuf, fname[i]) == 0) {
527 						rep->r1.fcode = fcode[i];
528 						goto done;
529 					}
530 				if(nfiles >= NWFILES)
531 					comperr("Too many files in w commands: %s");
532 
533 				i = strlen(fnamebuf) + 1;
534 				if ((fname[nfiles] = malloc((unsigned)i)) == NULL) {
535 					(void) fprintf(stderr, "sed: Out of memory\n");
536 					exit(2);
537 				}
538 				(void) strcpy(fname[nfiles], fnamebuf);
539 				if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
540 					(void) fprintf(stderr, "sed: Cannot create ");
541 					perror(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 				sseof = *cp++;
554 				rep->r1.re1 = p;
555 				p = ycomp(rep->r1.re1);
556 				break;
557 
558 		}
559 done:
560 		if(++rep >= ptrend)
561 			comperr("Too many commands, last: %s");
562 
563 		rep->r1.ad1 = p;
564 
565 		if(*cp++ != '\0') {
566 			if(cp[-1] == ';')
567 				goto comploop;
568 			comperr(ETMES);
569 		}
570 	}
571 	rep->r1.command = 0;
572 	lastre = op;
573 }
574 
575 char    *compsub(rhsbuf)
576 char    *rhsbuf;
577 {
578 	char   *p, *q;
579 
580 	p = rhsbuf;
581 	q = cp;
582 	for(;;) {
583 		if(p > &respace[RESIZE-1])
584 			comperr(TMMES);
585 		if((*p = *q++) == '\\') {
586 			p++;
587 			if(p > &respace[RESIZE-1])
588 				comperr(TMMES);
589 			*p = *q++;
590 			if(*p > nbra + '0' && *p <= '9')
591 				comperr("``\\digit'' out of range: %s");
592 			p++;
593 			continue;
594 		}
595 		if(*p == sseof) {
596 			*p++ = '\0';
597 			cp = q;
598 			return(p);
599 		}
600   		if(*p++ == '\0')
601 			comperr("Ending delimiter missing on substitution: %s");
602 
603 	}
604 }
605 
606 int
607 rline(lbuf, lbend)
608 char    *lbuf;
609 char	*lbend;
610 {
611 	char   *p, *q;
612 	int	t;
613 	static char     *saveq;
614 
615 	p = lbuf;
616 
617 	if(eflag) {
618 		if(eflag > 0) {
619 			eflag = -1;
620 			if(--eargc <= 0)
621 				exit(2);
622 			q = *++eargv;
623 			while((t = *q++) != '\0') {
624 				if(t == '\n') {
625 					saveq = q;
626 					goto out1;
627 				}
628 				if (p < lbend)
629 					*p++ = t;
630 				if(t == '\\') {
631 					if((t = *q++) == '\0') {
632 						saveq = 0;
633 						return(-1);
634 					}
635 					if (p < lbend)
636 						*p++ = t;
637 				}
638 			}
639 			saveq = 0;
640 
641 		out1:
642 			if (p == lbend)
643 				comperr("Command line too long");
644 			*p = '\0';
645 			return(1);
646 		}
647 		if((q = saveq) == 0)    return(-1);
648 
649 		while((t = *q++) != '\0') {
650 			if(t == '\n') {
651 				saveq = q;
652 				goto out2;
653 			}
654 			if(p < lbend)
655 				*p++ = t;
656 			if(t == '\\') {
657 				if((t = *q++) == '\0') {
658 					saveq = 0;
659 					return(-1);
660 				}
661 				if (p < lbend)
662 					*p++ = t;
663 			}
664 		}
665 		saveq = 0;
666 
667 	out2:
668 		if (p == lbend)
669 			comperr("Command line too long");
670 		*p = '\0';
671 		return(1);
672 	}
673 
674 	while((t = getc(fin)) != EOF) {
675 		if(t == '\n') {
676 			if (p == lbend)
677 				comperr("Command line too long");
678 			*p = '\0';
679 			return(1);
680 		}
681 		if (p < lbend)
682 			*p++ = t;
683 		if(t == '\\') {
684 			if((t = getc(fin)) == EOF)
685 				break;
686 			if(p < lbend)
687 				*p++ = t;
688 		}
689 	}
690 	if(ferror(fin)) {
691 		perror("sed: Error reading pattern file");
692 		exit(2);
693 	}
694 	return(-1);
695 }
696 
697 char    *address(expbuf)
698 char    *expbuf;
699 {
700 	char   *rcp;
701 	long long	lno;
702 
703 	if(*cp == '$') {
704 		if (expbuf > &respace[RESIZE-2])
705 			comperr(TMMES);
706 		cp++;
707 		*expbuf++ = CEND;
708 		*expbuf++ = CCEOF;
709 		return(expbuf);
710 	}
711 	if (*cp == '/' || *cp == '\\' ) {
712 		if ( *cp == '\\' )
713 			cp++;
714 		sseof = *cp++;
715 		return(comple((char *) 0, expbuf, &respace[RESIZE-1], sseof));
716 	}
717 
718 	rcp = cp;
719 	lno = 0;
720 
721 	while(*rcp >= '0' && *rcp <= '9')
722 		lno = lno*10 + *rcp++ - '0';
723 
724 	if(rcp > cp) {
725 		if (expbuf > &respace[RESIZE-3])
726 			comperr(TMMES);
727 		*expbuf++ = CLNUM;
728 		*expbuf++ = nlno;
729 		tlno[nlno++] = lno;
730 		if(nlno >= NLINES)
731 			comperr("Too many line numbers: %s");
732 		*expbuf++ = CCEOF;
733 		cp = rcp;
734 		return(expbuf);
735 	}
736 	return(0);
737 }
738 
739 char    *text(textbuf, tbend)
740 char    *textbuf;
741 char	*tbend;
742 {
743 	char   *p, *q;
744 
745 	p = textbuf;
746 	q = cp;
747 #ifndef S5EMUL
748 	/*
749 	 * Strip off indentation from text to be inserted.
750 	 */
751 	while(*q == '\t' || *q == ' ')	q++;
752 #endif
753 	for(;;) {
754 
755 		if(p > tbend)
756 			return(NULL);	/* overflowed the buffer */
757 		if((*p = *q++) == '\\')
758 			*p = *q++;
759 		if(*p == '\0') {
760 			cp = --q;
761 			return(++p);
762 		}
763 #ifndef S5EMUL
764 		/*
765 		 * Strip off indentation from text to be inserted.
766 		 */
767 		if(*p == '\n') {
768 			while(*q == '\t' || *q == ' ')	q++;
769 		}
770 #endif
771 		p++;
772 	}
773 }
774 
775 
776 struct label    *search(ptr)
777 struct label    *ptr;
778 {
779 	struct label    *rp;
780 
781 	rp = labtab;
782 	while(rp < ptr) {
783 		if(strcmp(rp->asc, ptr->asc) == 0)
784 			return(rp);
785 		rp++;
786 	}
787 
788 	return(0);
789 }
790 
791 
792 static void
793 dechain(void)
794 {
795 	struct label    *lptr;
796 	union reptr     *rptr, *trptr;
797 
798 	for(lptr = labtab; lptr < lab; lptr++) {
799 
800 		if(lptr->address == 0) {
801 			(void) fprintf(stderr, "sed: Undefined label: %s\n", lptr->asc);
802 			exit(2);
803 		}
804 
805 		if(lptr->chain) {
806 			rptr = lptr->chain;
807 			while(trptr = rptr->r2.lb1) {
808 				rptr->r2.lb1 = lptr->address;
809 				rptr = trptr;
810 			}
811 			rptr->r2.lb1 = lptr->address;
812 		}
813 	}
814 }
815 
816 char *ycomp(expbuf)
817 char    *expbuf;
818 {
819 	char	c;
820 	char *ep, *tsp;
821 	int i;
822 	char    *sp;
823 
824 	ep = expbuf;
825 	if(ep + 0377 > &respace[RESIZE-1])
826 		comperr(TMMES);
827 	sp = cp;
828 	for(tsp = cp; (c = *tsp) != sseof; tsp++) {
829 		if(c == '\\')
830 			tsp++;
831 		if(c == '\0' || c == '\n')
832 			comperr("Ending delimiter missing on string: %s");
833 	}
834 	tsp++;
835 
836 	while((c = *sp++) != sseof) {
837 		c &= 0377;
838 		if(c == '\\' && *sp == 'n') {
839 			sp++;
840 			c = '\n';
841 		}
842 		if((ep[c] = *tsp++) == '\\' && *tsp == 'n') {
843 			ep[c] = '\n';
844 			tsp++;
845 		}
846 		if(ep[c] == sseof || ep[c] == '\0')
847 			comperr("Transform strings not the same size: %s");
848 	}
849 	if(*tsp != sseof) {
850 		if(*tsp == '\0')
851 			comperr("Ending delimiter missing on string: %s");
852 		else
853 			comperr("Transform strings not the same size: %s");
854 	}
855 	cp = ++tsp;
856 
857 	for(i = 0; i < 0400; i++)
858 		if(ep[i] == 0)
859 			ep[i] = i;
860 
861 	return(ep + 0400);
862 }
863 
864 void
865 comperr(char *msg)
866 {
867 	(void) fprintf(stderr, "sed: ");
868 	(void) fprintf(stderr, msg, linebuf);
869 	(void) putc('\n', stderr);
870 	exit(2);
871 }
872