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