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