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