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