xref: /illumos-gate/usr/src/ucbcmd/sed/sed1.c (revision 7c478bd9)
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 /*	Copyright (c) 1984 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright (c) 1996, by Sun Microsystems, Inc.
28  * All rights reserved.
29  */
30 
31 #ident	"%Z%%M%	%I%	%E% SMI"	/* from S5R3.1 1.7 */
32 
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include "sed.h"
38 #include <regexp.h>
39 
40 union reptr     *abuf[ABUFSIZE+1];
41 union reptr **aptr;
42 char    ibuf[BUFSIZ];
43 char    *cbp;
44 char    *ebp;
45 char    genbuf[LBSIZE+1];
46 char	*lcomend;
47 int     dolflag;
48 int     sflag;
49 int     jflag;
50 int     delflag;
51 long long lnum;
52 char    holdsp[LBSIZE+1];
53 char    *spend;
54 char    *hspend;
55 int     nflag;
56 long long tlno[NLINES];
57 int     f;
58 char	*ifname;
59 int	numpass;
60 union reptr     *pending;
61 char	*trans[040]  = {
62 	"\\01",
63 	"\\02",
64 	"\\03",
65 	"\\04",
66 	"\\05",
67 	"\\06",
68 	"\\07",
69 	"-<",
70 	"->",
71 	"\n",
72 	"\\13",
73 	"\\14",
74 	"\\15",
75 	"\\16",
76 	"\\17",
77 	"\\20",
78 	"\\21",
79 	"\\22",
80 	"\\23",
81 	"\\24",
82 	"\\25",
83 	"\\26",
84 	"\\27",
85 	"\\30",
86 	"\\31",
87 	"\\32",
88 	"\\33",
89 	"\\34",
90 	"\\35",
91 	"\\36",
92 	"\\37"
93 };
94 char	rub[] = {"\\177"};
95 
96 extern char TMMES[];
97 
98 execute(file)
99 char *file;
100 {
101 	register char *p1, *p2;
102 	register union reptr	*ipc;
103 	int	c;
104 	char	*execp;
105 
106 	if (file) {
107 		if ((f = open(file, 0)) < 0) {
108 			(void) fprintf(stderr, "sed: ");
109 			perror(file);
110 		}
111 		ifname = file;
112 	} else {
113 		f = 0;
114 		ifname = "standard input";
115 	}
116 
117 	ebp = ibuf;
118 	cbp = ibuf;
119 
120 	if(pending) {
121 		ipc = pending;
122 		pending = 0;
123 		goto yes;
124 	}
125 
126 	for(;;) {
127 		if((execp = gline(linebuf)) == 0) {
128 			(void) close(f);
129 			return;
130 		}
131 		spend = execp;
132 
133 		for(ipc = ptrspace; ipc->r1.command; ) {
134 
135 			p1 = ipc->r1.ad1;
136 			p2 = ipc->r1.ad2;
137 
138 			if(p1) {
139 
140 				if(ipc->r1.inar) {
141 					if(*p2 == CEND) {
142 						p1 = 0;
143 					} else if(*p2 == CLNUM) {
144 						c = (unsigned char)p2[1];
145 						if(lnum > tlno[c]) {
146 							ipc->r1.inar = 0;
147 							if(ipc->r1.negfl)
148 								goto yes;
149 							ipc++;
150 							continue;
151 						}
152 						if(lnum == tlno[c]) {
153 							ipc->r1.inar = 0;
154 						}
155 					} else if(match(p2, 0)) {
156 						ipc->r1.inar = 0;
157 					}
158 				} else if(*p1 == CEND) {
159 					if(!dolflag) {
160 						if(ipc->r1.negfl)
161 							goto yes;
162 						ipc++;
163 						continue;
164 					}
165 
166 				} else if(*p1 == CLNUM) {
167 					c = (unsigned char)p1[1];
168 					if(lnum != tlno[c]) {
169 						if(ipc->r1.negfl)
170 							goto yes;
171 						ipc++;
172 						continue;
173 					}
174 					if(p2)
175 						ipc->r1.inar = 1;
176 				} else if(match(p1, 0)) {
177 					if(p2)
178 						ipc->r1.inar = 1;
179 				} else {
180 					if(ipc->r1.negfl)
181 						goto yes;
182 					ipc++;
183 					continue;
184 				}
185 			}
186 
187 			if(ipc->r1.negfl) {
188 				ipc++;
189 				continue;
190 			}
191 	yes:
192 			command(ipc);
193 
194 			if(delflag)
195 				break;
196 
197 			if(jflag) {
198 				jflag = 0;
199 				if((ipc = ipc->r2.lb1) == 0) {
200 					ipc = ptrspace;
201 					break;
202 				}
203 			} else
204 				ipc++;
205 
206 		}
207 		if(!nflag && !delflag) {
208 			for(p1 = linebuf; p1 < spend; p1++)
209 				(void) putc(*p1, stdout);
210 			(void) putc('\n', stdout);
211 		}
212 
213 		if(aptr > abuf) {
214 			arout();
215 		}
216 
217 		delflag = 0;
218 
219 	}
220 }
221 match(expbuf, gf)
222 char	*expbuf;
223 {
224 	register char   *p1;
225 
226 	if(gf) {
227 		if(*expbuf)	return(0);
228 		locs = p1 = loc2;
229 	} else {
230 		p1 = linebuf;
231 		locs = 0;
232 	}
233 
234 	circf = *expbuf++;
235 	return(step(p1, expbuf));
236 }
237 
238 substitute(ipc)
239 union reptr	*ipc;
240 {
241 	if(match(ipc->r1.re1, 0) == 0)	return(0);
242 
243 	numpass = 0;
244 	sflag = 0;		/* Flags if any substitution was made */
245 	dosub(ipc->r1.rhs, ipc->r1.gfl);
246 
247 	if(ipc->r1.gfl) {
248 		while(*loc2) {
249 			if(match(ipc->r1.re1, 1) == 0) break;
250 			dosub(ipc->r1.rhs, ipc->r1.gfl);
251 		}
252 	}
253 	return(sflag);
254 }
255 
256 dosub(rhsbuf,n)
257 char	*rhsbuf;
258 int	n;
259 {
260 	register char *lp, *sp, *rp;
261 	int c;
262 
263 	if(n > 0 && n < 999)
264 		{numpass++;
265 		if(n != numpass) return;
266 		}
267 	sflag = 1;
268 	lp = linebuf;
269 	sp = genbuf;
270 	rp = rhsbuf;
271 	while (lp < loc1)
272 		*sp++ = *lp++;
273 	while(c = *rp++) {
274 		if (c == '&')
275 			sp = place(sp, loc1, loc2);
276 		else if (c == '\\') {
277 			c = *rp++;
278 			if (c >= '1' && c < NBRA+'1')
279 				sp = place(sp, braslist[c-'1'], braelist[c-'1']);
280 			else
281 				*sp++ = c;
282   		} else
283 			*sp++ = c;
284 		if (sp == &genbuf[LBSIZE+1]) {
285 			(void) fprintf(stderr, "Output line too long.\n");
286 			*--sp = '\0';
287 			goto out;
288 		}
289 	}
290 	lp = loc2;
291 	loc2 = sp - genbuf + linebuf;
292 	while(*sp++ = *lp++)
293 		if (sp == &genbuf[LBSIZE+1]) {
294 			(void) fprintf(stderr, "Output line too long.\n");
295 			*--sp = '\0';
296 			break;
297 		}
298 out:
299 	lp = linebuf;
300 	sp = genbuf;
301 	while (*lp++ = *sp++);
302 	spend = lp-1;
303 }
304 
305 char	*place(asp, al1, al2)
306 char	*asp, *al1, *al2;
307 {
308 	register char *sp, *l1, *l2;
309 
310 	sp = asp;
311 	l1 = al1;
312 	l2 = al2;
313 	while (l1 < l2) {
314 		*sp++ = *l1++;
315 		if (sp == &genbuf[LBSIZE+1])
316 			break;
317 	}
318 	return(sp);
319 }
320 
321 command(ipc)
322 union reptr	*ipc;
323 {
324 	register int	i;
325 	register char   *p1, *p2, *p3;
326 	char	*execp;
327 
328 
329 	switch(ipc->r1.command) {
330 
331 		case ACOM:
332 			if(aptr >= &abuf[ABUFSIZE]) {
333 				(void) fprintf(stderr, "Too many appends or reads after line %lld\n",
334 					lnum);
335 			} else {
336 				*aptr++ = ipc;
337 				*aptr = 0;
338 			}
339 			break;
340 
341 		case CCOM:
342 			delflag = 1;
343 			if(!ipc->r1.inar || dolflag) {
344 				for(p1 = ipc->r1.re1; *p1; )
345 					(void) putc(*p1++, stdout);
346 				(void) putc('\n', stdout);
347 			}
348 			break;
349 		case DCOM:
350 			delflag++;
351 			break;
352 		case CDCOM:
353 			p1 = p2 = linebuf;
354 
355 			while(*p1 != '\n') {
356 				if(*p1++ == 0) {
357 					delflag++;
358 					return;
359 				}
360 			}
361 
362 			p1++;
363 			while(*p2++ = *p1++);
364 			spend = p2-1;
365 			jflag++;
366 			break;
367 
368 		case EQCOM:
369 			(void) fprintf(stdout, "%lld\n", lnum);
370 			break;
371 
372 		case GCOM:
373 			p1 = linebuf;
374 			p2 = holdsp;
375 			while(*p1++ = *p2++);
376 			spend = p1-1;
377 			break;
378 
379 		case CGCOM:
380 			*spend++ = '\n';
381 			p1 = spend;
382 			p2 = holdsp;
383 			do {
384 				if (p1 == &linebuf[LBSIZE+1]) {
385 					(void) fprintf(stderr, "Output line too long.\n");
386 					*--p1 = '\0';
387 				}
388 			} while(*p1++ = *p2++);
389 			spend = p1-1;
390 			break;
391 
392 		case HCOM:
393 			p1 = holdsp;
394 			p2 = linebuf;
395 			while(*p1++ = *p2++);
396 			hspend = p1-1;
397 			break;
398 
399 		case CHCOM:
400 			*hspend++ = '\n';
401 			p1 = hspend;
402 			p2 = linebuf;
403 			do {
404 				if (p1 == &holdsp[LBSIZE+1]) {
405 					(void) fprintf(stderr, "Hold space overflowed.\n");
406 					*--p1 = '\0';
407 				}
408 			} while(*p1++ = *p2++);
409 			hspend = p1-1;
410 			break;
411 
412 		case ICOM:
413 			for(p1 = ipc->r1.re1; *p1; )
414 				(void) putc(*p1++, stdout);
415 			(void) putc('\n', stdout);
416 			break;
417 
418 		case BCOM:
419 			jflag = 1;
420 			break;
421 
422 
423 		case LCOM:
424 			p1 = linebuf;
425 			p2 = genbuf;
426 			genbuf[72] = 0;
427 			while(*p1)
428 				if((unsigned char)*p1 >= 040) {
429 					if(*p1 == 0177) {
430 						p3 = rub;
431 						while(*p2++ = *p3++)
432 							if(p2 >= lcomend) {
433 								*p2 = '\\';
434 								(void) fprintf(stdout, "%s\n", genbuf);
435 								p2 = genbuf;
436 							}
437 						p2--;
438 						p1++;
439 						continue;
440 					}
441 					if(!isprint(*p1 & 0377)) {
442 						*p2++ = '\\';
443 						if(p2 >= lcomend) {
444 							*p2 = '\\';
445 							(void) fprintf(stdout, "%s\n", genbuf);
446 							p2 = genbuf;
447 						}
448 						*p2++ = (*p1 >> 6) + '0';
449 						if(p2 >= lcomend) {
450 							*p2 = '\\';
451 							(void) fprintf(stdout, "%s\n", genbuf);
452 							p2 = genbuf;
453 						}
454 						*p2++ = ((*p1 >> 3) & 07) + '0';
455 						if(p2 >= lcomend) {
456 							*p2 = '\\';
457 							(void) fprintf(stdout, "%s\n", genbuf);
458 							p2 = genbuf;
459 						}
460 						*p2++ = (*p1++ & 07) + '0';
461 						if(p2 >= lcomend) {
462 							*p2 = '\\';
463 							(void) fprintf(stdout, "%s\n", genbuf);
464 							p2 = genbuf;
465 						}
466 					} else {
467 						*p2++ = *p1++;
468 						if(p2 >= lcomend) {
469 							*p2 = '\\';
470 							(void) fprintf(stdout, "%s\n", genbuf);
471 							p2 = genbuf;
472 						}
473 					}
474 				} else {
475 					p3 = trans[(unsigned char)*p1-1];
476 					while(*p2++ = *p3++)
477 						if(p2 >= lcomend) {
478 							*p2 = '\\';
479 							(void) fprintf(stdout, "%s\n", genbuf);
480 							p2 = genbuf;
481 						}
482 					p2--;
483 					p1++;
484 				}
485 			*p2 = 0;
486 			(void) fprintf(stdout, "%s\n", genbuf);
487 			break;
488 
489 		case NCOM:
490 			if(!nflag) {
491 				for(p1 = linebuf; p1 < spend; p1++)
492 					(void) putc(*p1, stdout);
493 				(void) putc('\n', stdout);
494 			}
495 
496 			if(aptr > abuf)
497 				arout();
498 			if((execp = gline(linebuf)) == 0) {
499 				pending = ipc;
500 				delflag = 1;
501 				break;
502 			}
503 			spend = execp;
504 
505 			break;
506 		case CNCOM:
507 			if(aptr > abuf)
508 				arout();
509 			*spend++ = '\n';
510 			if((execp = gline(spend)) == 0) {
511 				pending = ipc;
512 				delflag = 1;
513 				break;
514 			}
515 			spend = execp;
516 			break;
517 
518 		case PCOM:
519 			for(p1 = linebuf; p1 < spend; p1++)
520 				(void) putc(*p1, stdout);
521 			(void) putc('\n', stdout);
522 			break;
523 		case CPCOM:
524 	cpcom:
525 			for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
526 				(void) putc(*p1++, stdout);
527 			(void) putc('\n', stdout);
528 			break;
529 
530 		case QCOM:
531 			if(!nflag) {
532 				for(p1 = linebuf; p1 < spend; p1++)
533 					(void) putc(*p1, stdout);
534 				(void) putc('\n', stdout);
535 			}
536 			if(aptr > abuf) arout();
537 			(void) fclose(stdout);
538 			exit(0);
539 		case RCOM:
540 			if(aptr >= &abuf[ABUFSIZE]) {
541 				(void) fprintf(stderr, "Too many appends or reads after line %lld\n",
542 					lnum);
543 			} else {
544 				*aptr++ = ipc;
545 				*aptr = 0;
546 			}
547 			break;
548 
549 		case SCOM:
550 			i = substitute(ipc);
551 			if(ipc->r1.pfl && nflag && i)
552 				if(ipc->r1.pfl == 1) {
553 					for(p1 = linebuf; p1 < spend; p1++)
554 						(void) putc(*p1, stdout);
555 					(void) putc('\n', stdout);
556 				}
557 				else
558 					goto cpcom;
559 			if(i && ipc->r1.fcode)
560 				goto wcom;
561 			break;
562 
563 		case TCOM:
564 			if(sflag == 0)  break;
565 			sflag = 0;
566 			jflag = 1;
567 			break;
568 
569 		wcom:
570 		case WCOM:
571 			(void) fprintf(ipc->r1.fcode, "%s\n", linebuf);
572 			(void) fflush(ipc->r1.fcode);
573 			break;
574 		case XCOM:
575 			p1 = linebuf;
576 			p2 = genbuf;
577 			while(*p2++ = *p1++);
578 			p1 = holdsp;
579 			p2 = linebuf;
580 			while(*p2++ = *p1++);
581 			spend = p2 - 1;
582 			p1 = genbuf;
583 			p2 = holdsp;
584 			while(*p2++ = *p1++);
585 			hspend = p2 - 1;
586 			break;
587 
588 		case YCOM:
589 			p1 = linebuf;
590 			p2 = ipc->r1.re1;
591 			while(*p1 = p2[(unsigned char)*p1])	p1++;
592 			break;
593 	}
594 
595 }
596 
597 char	*gline(addr)
598 char	*addr;
599 {
600 	register char   *p1, *p2;
601 	register	c;
602 	sflag = 0;
603 	p1 = addr;
604 	p2 = cbp;
605 	for (;;) {
606 		if (p2 >= ebp) {
607 			if(f < 0 || (c = read(f, ibuf, BUFSIZ)) == 0) {
608 				return(0);
609 			}
610 			if(c < 0) {
611 				(void) fprintf(stderr, "sed: error reading ");
612 				perror(ifname);
613 				exit(2);
614 			}
615 			p2 = ibuf;
616 			ebp = ibuf+c;
617 		}
618 		if ((c = *p2++) == '\n') {
619 			if(p2 >=  ebp) {
620 				if(f < 0 || (c = read(f, ibuf, BUFSIZ)) == 0) {
621 					if(f >= 0) {
622 						(void) close(f);
623 						f = -1;
624 					}
625 					if(eargc == 0)
626 							dolflag = 1;
627 				}
628 				if(c < 0) {
629 					(void) fprintf(stderr, "sed: error reading ");
630 					perror(ifname);
631 					exit(2);
632 				}
633 
634 				p2 = ibuf;
635 				ebp = ibuf + c;
636 			}
637 			break;
638 		}
639 		if(c)
640 		if(p1 < &linebuf[LBSIZE])
641 			*p1++ = c;
642 	}
643 	lnum++;
644 	*p1 = 0;
645 	cbp = p2;
646 
647 	return(p1);
648 }
649 
650 char *comple(x1, ep, x3, x4)
651 char *x1, *x3;
652 char x4;
653 register char *ep;
654 {
655 	register char *p;
656 
657 	p = compile(x1, ep + 1, x3, x4);
658 	if(p == ep + 1)
659 		return(ep);
660 	*ep = circf;
661 	return(p);
662 }
663 
664 regerr(err)
665 register err;
666 {
667 	switch(err) {
668 
669 	case 11:
670 		comperr("Range endpoint too large: %s");
671 		break;
672 
673 	case 16:
674 		comperr("Bad number: %s");
675 		break;
676 
677 	case 25:
678 		comperr("``\\digit'' out of range: %s");
679 		break;
680 
681 	case 36:
682 		comperr("Illegal or missing delimiter: %s");
683 		break;
684 
685 	case 41:
686 		comperr("No remembered search string: %s");
687 		break;
688 
689 	case 42:
690 		comperr("\\( \\) imbalance: %s");
691 		break;
692 
693 	case 43:
694 		comperr("Too many \\(: %s");
695 		break;
696 
697 	case 44:
698 		comperr("More than 2 numbers given in \\{ \\}: %s");
699 		break;
700 
701 	case 45:
702 		comperr("} expected after \\: %s");
703 		break;
704 
705 	case 46:
706 		comperr("First number exceeds second in \\{ \\}: %s");
707 		break;
708 
709 	case 49:
710 		comperr("[ ] imbalance: %s");
711 		break;
712 
713 	case 50:
714 		comperr(TMMES);
715 		break;
716 
717 	default:
718 		(void) fprintf(stderr, "Unknown regexp error code %d: %s\n",
719 		    err, linebuf);
720 		exit(2);
721 		break;
722 	}
723 }
724 
725 arout()
726 {
727 	register char   *p1;
728 	FILE	*fi;
729 	char	c;
730 	int	t;
731 
732 	aptr = abuf - 1;
733 	while(*++aptr) {
734 		if((*aptr)->r1.command == ACOM) {
735 			for(p1 = (*aptr)->r1.re1; *p1; )
736 				(void) putc(*p1++, stdout);
737 			(void) putc('\n', stdout);
738 		} else {
739 			if((fi = fopen((*aptr)->r1.re1, "r")) == NULL)
740 				continue;
741 			while((t = getc(fi)) != EOF) {
742 				c = t;
743 				(void) putc(c, stdout);
744 			}
745 			(void) fclose(fi);
746 		}
747 	}
748 	aptr = abuf;
749 	*aptr = 0;
750 }
751 
752