Home | History | Annotate | Download | only in sed
      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