hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

sed0.c (23789B)


      1 /*	from Unix 7th Edition sed	*/
      2 /*	Sccsid @(#)sed0.c	1.64 (gritter) 3/12/05>	*/
      3 /*
      4  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *   Redistributions of source code and documentation must retain the
     10  *    above copyright notice, this list of conditions and the following
     11  *    disclaimer.
     12  *   Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *   All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *      This product includes software developed or owned by Caldera
     18  *      International, Inc.
     19  *   Neither the name of Caldera International, Inc. nor the names of
     20  *    other contributors may be used to endorse or promote products
     21  *    derived from this software without specific prior written permission.
     22  *
     23  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
     24  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
     25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
     28  * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
     29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     31  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     33  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     34  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     35  */
     36 #include <unistd.h>
     37 #include <stdlib.h>
     38 #include <locale.h>
     39 #include <libgen.h>
     40 #include <stdarg.h>
     41 #include <wchar.h>
     42 #include "sed.h"
     43 
     44 int	ABUFSIZE;
     45 struct reptr	**abuf;
     46 int	aptr;
     47 char	*genbuf;
     48 int	gbend;
     49 int	lbend;
     50 int	hend;
     51 char	*linebuf;
     52 char	*holdsp;
     53 int	nflag;
     54 long long	*tlno;
     55 char	*cp;
     56 
     57 int	status;
     58 int	multibyte;
     59 int	invchar;
     60 int	needdol;
     61 
     62 int	eargc;
     63 
     64 struct	reptr *ptrspace;
     65 struct reptr	*pending;
     66 char	*badp;
     67 
     68 static const char	CGMES[]	= "\1command garbled: %s";
     69 static const char	TMMES[]	= "Too much text: %s";
     70 static const char	LTL[]	= "Label too long: %s";
     71 static const char	LINTL[]	= "line too long";
     72 static const char	AD0MES[]	= "No addresses allowed: %s";
     73 static const char	AD1MES[]	= "Only one address allowed: %s";
     74 static FILE	**fcode;
     75 static FILE	*fin;
     76 static char	*lastre;
     77 static wchar_t	sed_seof;
     78 static int	PTRSIZE;
     79 static int	eflag;
     80 static int	gflag;
     81 static int	nlno;
     82 static char	**fname;
     83 static int	nfiles;
     84 static int	rep;
     85 static struct label  *ltab;
     86 static int	lab;
     87 static size_t	LABSIZE;
     88 static int	labtab = 1;
     89 static int	depth;
     90 static char	**eargv;
     91 static int	*cmpend;
     92 static size_t	DEPTH;
     93 static char	bad;
     94 static char	compfl;
     95 static char	*progname;
     96 static char	*(*ycomp)(char **);
     97 static int	executing;
     98 
     99 static void fcomp(void);
    100 static char *compsub(char **, char *);
    101 static int rline(void);
    102 static char *address(char **);
    103 static int cmp(const char *, const char *);
    104 static void text(char **);
    105 static int search(struct label *);
    106 static void dechain(void);
    107 static char *ycomp_sb(char **);
    108 static char *ycomp_mb(char **);
    109 static void lab_inc(void);
    110 static void rep_inc(void);
    111 static void depth_check(void);
    112 static void *srealloc(void *, size_t);
    113 static void *scalloc(size_t, size_t);
    114 static char *sed_compile(char **);
    115 static void wfile(void);
    116 static void morefiles(void);
    117 
    118 static char	*null;
    119 #define	check(p, buf, sz, incr, op) \
    120 	if (&p[1] >= &(buf)[sz]) { \
    121 		size_t ppos = p - buf; \
    122 		size_t opos = op - buf; \
    123 		buf = srealloc(buf, (sz += incr) * sizeof *(buf)); \
    124 		p = &(buf)[ppos]; \
    125 		if (op != NULL) \
    126 			op = &(buf)[opos]; \
    127 	}
    128 
    129 int
    130 main(int argc, char **argv)
    131 {
    132 	int c;
    133 	const char optstr[] = "nf:e:g";
    134 
    135 	sed = 1;
    136 	progname = basename(argv[0]);
    137 	eargc = argc;
    138 	eargv = argv;
    139 
    140 #ifdef	__GLIBC__
    141 	putenv("POSIXLY_CORRECT=1");
    142 #endif	/* __GLIBC__ */
    143 #if defined (SUS) || defined (SU3) || defined (S42)
    144 	setlocale(LC_COLLATE, "");
    145 #endif	/* SUS || SU3 || S42 */
    146 	setlocale(LC_CTYPE, "");
    147 	multibyte = MB_CUR_MAX > 1;
    148 	ycomp = multibyte ? ycomp_mb : ycomp_sb;
    149 	badp = &bad;
    150 	aptr_inc();
    151 	lab_inc();
    152 	lab_inc();	/* 0 reserved for end-pointer -> labtab = 1 */
    153 	growsp(NULL);
    154 	rep_inc();
    155 	pending = 0;
    156 	depth = 0;
    157 	morefiles();
    158 	fcode[0] = stdout;
    159 	nfiles = 1;
    160 	morefiles();
    161 
    162 	if(eargc == 1)
    163 		exit(0);
    164 	while ((c = getopt(eargc, eargv, optstr)) != EOF) {
    165 		switch (c) {
    166 		case 'n':
    167 			nflag++;
    168 			continue;
    169 
    170 		case 'f':
    171 			if((fin = fopen(optarg, "r")) == NULL)
    172 				fatal("Cannot open pattern-file: %s", optarg);
    173 
    174 			fcomp();
    175 			fclose(fin);
    176 			continue;
    177 
    178 		case 'e':
    179 			eflag++;
    180 			fcomp();
    181 			eflag = 0;
    182 			continue;
    183 
    184 		case 'g':
    185 			gflag++;
    186 			continue;
    187 
    188 		default:
    189 			exit(2);
    190 		}
    191 	}
    192 
    193 	eargv += optind, eargc -= optind;
    194 
    195 
    196 	if(compfl == 0 && *eargv) {
    197 		optarg = *eargv++;
    198 		eargc--;
    199 		eflag++;
    200 		fcomp();
    201 		eflag = 0;
    202 	}
    203 
    204 	if(depth)
    205 		fatal("Too many {'s");
    206 
    207 	L(labtab)->address = rep;
    208 
    209 	dechain();
    210 
    211 /*	abort();	*/	/*DEBUG*/
    212 
    213 	executing++;
    214 	if(eargc <= 0)
    215 		execute((char *)NULL);
    216 	else while(--eargc >= 0) {
    217 		execute(*eargv++);
    218 	}
    219 	fclose(stdout);
    220 	return status;
    221 }
    222 
    223 static void
    224 fcomp(void)
    225 {
    226 
    227 	register char	*op, *tp, *q;
    228 	int	pt, pt1;
    229 	int	lpt;
    230 
    231 	compfl = 1;
    232 	op = lastre;
    233 
    234 	if(rline() < 0)	return;
    235 	if(*linebuf == '#') {
    236 		if(linebuf[1] == 'n')
    237 			nflag = 1;
    238 	}
    239 	else {
    240 		cp = linebuf;
    241 		goto comploop;
    242 	}
    243 
    244 	for(;;) {
    245 		if(rline() < 0)	break;
    246 
    247 		cp = linebuf;
    248 
    249 comploop:
    250 /*	fprintf(stdout, "cp: %s\n", cp); */	/*DEBUG*/
    251 		while(*cp == ' ' || *cp == '\t')	cp++;
    252 		if(*cp == '\0' || *cp == '#')		continue;
    253 		if(*cp == ';') {
    254 			cp++;
    255 			goto comploop;
    256 		}
    257 
    258 		q = address(&P(rep)->ad1);
    259 		if(q == badp)
    260 			fatal(CGMES, linebuf);
    261 
    262 		if(q != 0 && q == P(rep)->ad1) {
    263 			if(op)
    264 				P(rep)->ad1 = op;
    265 			else
    266 				fatal("First RE may not be null");
    267 		} else if(q == 0) {
    268 			P(rep)->ad1 = 0;
    269 		} else {
    270 			op = P(rep)->ad1;
    271 			if(*cp == ',' || *cp == ';') {
    272 				cp++;
    273 				q = address(&P(rep)->ad2);
    274 				if(q == badp || q == 0)
    275 					fatal(CGMES, linebuf);
    276 				if(q == P(rep)->ad2)
    277 					P(rep)->ad2 = op;
    278 				else
    279 					op = P(rep)->ad2;
    280 
    281 			} else
    282 				P(rep)->ad2 = 0;
    283 		}
    284 
    285 		while(*cp == ' ' || *cp == '\t')	cp++;
    286 
    287 swit:
    288 		switch(*cp++) {
    289 
    290 			default:
    291 				fatal("Unrecognized command: %s", linebuf);
    292 				/*NOTREACHED*/
    293 
    294 			case '!':
    295 				P(rep)->negfl = 1;
    296 				goto swit;
    297 
    298 			case '{':
    299 				P(rep)->command = BCOM;
    300 				P(rep)->negfl = !(P(rep)->negfl);
    301 				depth_check();
    302 				cmpend[depth++] = rep;
    303 				rep_inc();
    304 				if(*cp == '\0')	continue;
    305 
    306 				goto comploop;
    307 
    308 			case '}':
    309 				if(P(rep)->ad1)
    310 					fatal(AD0MES, linebuf);
    311 
    312 				if(--depth < 0)
    313 					fatal("Too many }'s");
    314 				P(cmpend[depth])->bptr.lb1 = rep;
    315 
    316 				continue;
    317 
    318 			case '=':
    319 				P(rep)->command = EQCOM;
    320 				if(P(rep)->ad2)
    321 					fatal(AD1MES, linebuf);
    322 				break;
    323 
    324 			case ':':
    325 				if(P(rep)->ad1)
    326 					fatal(AD0MES, linebuf);
    327 
    328 				while(*cp++ == ' ');
    329 				cp--;
    330 
    331 
    332 				tp = L(lab)->asc;
    333 				while((*tp++ = *cp++))
    334 					if(tp >= &(L(lab)->asc[sizeof
    335 								L(lab)->asc]))
    336 						fatal(LTL, linebuf);
    337 				*--tp = '\0';
    338 
    339 				if(lpt = search(L(lab))) {
    340 					if(L(lpt)->address)
    341 						fatal("Duplicate labels: %s",
    342 								linebuf);
    343 				} else {
    344 					L(lab)->chain = 0;
    345 					lpt = lab;
    346 					lab_inc();
    347 				}
    348 				L(lpt)->address = rep;
    349 
    350 				continue;
    351 
    352 			case 'a':
    353 				P(rep)->command = ACOM;
    354 				if(P(rep)->ad2)
    355 					fatal(AD1MES, linebuf);
    356 				if(*cp == '\\')	cp++;
    357 				if(*cp++ != '\n')
    358 					fatal(CGMES, linebuf);
    359 				text(&P(rep)->bptr.re1);
    360 				break;
    361 			case 'c':
    362 				P(rep)->command = CCOM;
    363 				if(*cp == '\\')	cp++;
    364 				if(*cp++ != ('\n'))
    365 					fatal(CGMES, linebuf);
    366 				text(&P(rep)->bptr.re1);
    367 				needdol = 1;
    368 				break;
    369 			case 'i':
    370 				P(rep)->command = ICOM;
    371 				if(P(rep)->ad2)
    372 					fatal(AD1MES, linebuf);
    373 				if(*cp == '\\')	cp++;
    374 				if(*cp++ != ('\n'))
    375 					fatal(CGMES, linebuf);
    376 				text(&P(rep)->bptr.re1);
    377 				break;
    378 
    379 			case 'g':
    380 				P(rep)->command = GCOM;
    381 				break;
    382 
    383 			case 'G':
    384 				P(rep)->command = CGCOM;
    385 				break;
    386 
    387 			case 'h':
    388 				P(rep)->command = HCOM;
    389 				break;
    390 
    391 			case 'H':
    392 				P(rep)->command = CHCOM;
    393 				break;
    394 
    395 			case 't':
    396 				P(rep)->command = TCOM;
    397 				goto jtcommon;
    398 
    399 			case 'b':
    400 				P(rep)->command = BCOM;
    401 jtcommon:
    402 				while(*cp++ == ' ');
    403 				cp--;
    404 
    405 				if(*cp == '\0') {
    406 					if((pt = L(labtab)->chain) != 0) {
    407 						while((pt1 = P(pt)->bptr.lb1) != 0)
    408 							pt = pt1;
    409 						P(pt)->bptr.lb1 = rep;
    410 					} else
    411 						L(labtab)->chain = rep;
    412 					break;
    413 				}
    414 				tp = L(lab)->asc;
    415 				while((*tp++ = *cp++))
    416 					if(tp >= &(L(lab)->asc[sizeof
    417 								L(lab)->asc]))
    418 						fatal(LTL, linebuf);
    419 				cp--;
    420 				*--tp = '\0';
    421 
    422 				if(lpt = search(L(lab))) {
    423 					if(L(lpt)->address) {
    424 						P(rep)->bptr.lb1 = L(lpt)->address;
    425 					} else {
    426 						pt = L(lpt)->chain;
    427 						while((pt1 = P(pt)->bptr.lb1) != 0)
    428 							pt = pt1;
    429 						P(pt)->bptr.lb1 = rep;
    430 					}
    431 				} else {
    432 					L(lab)->chain = rep;
    433 					L(lab)->address = 0;
    434 					lab_inc();
    435 				}
    436 				break;
    437 
    438 			case 'n':
    439 				P(rep)->command = NCOM;
    440 				break;
    441 
    442 			case 'N':
    443 				P(rep)->command = CNCOM;
    444 				break;
    445 
    446 			case 'p':
    447 				P(rep)->command = PCOM;
    448 				break;
    449 
    450 			case 'P':
    451 				P(rep)->command = CPCOM;
    452 				break;
    453 
    454 			case 'r':
    455 				P(rep)->command = RCOM;
    456 				if(P(rep)->ad2)
    457 					fatal(AD1MES, linebuf);
    458 #if !defined (SUS) && !defined (SU3)
    459 				if(*cp++ != ' ')
    460 					fatal(CGMES, linebuf);
    461 #else	/* SUS, SU3 */
    462 				while (*cp == ' ' || *cp == '\t')
    463 					cp++;
    464 #endif	/* SUS, SU3 */
    465 				text(&P(rep)->bptr.re1);
    466 				break;
    467 
    468 			case 'd':
    469 				P(rep)->command = DCOM;
    470 				break;
    471 
    472 			case 'D':
    473 				P(rep)->command = CDCOM;
    474 				P(rep)->bptr.lb1 = 1;
    475 				break;
    476 
    477 			case 'q':
    478 				P(rep)->command = QCOM;
    479 				if(P(rep)->ad2)
    480 					fatal(AD1MES, linebuf);
    481 				break;
    482 
    483 			case 'l':
    484 				P(rep)->command = LCOM;
    485 				break;
    486 
    487 			case 's':
    488 				P(rep)->command = SCOM;
    489 				sed_seof = fetch(&cp);
    490 				q = sed_compile(&P(rep)->bptr.re1);
    491 				if(q == badp)
    492 					fatal(CGMES, linebuf);
    493 				if(q == P(rep)->bptr.re1) {
    494 					if (op == NULL)
    495 						fatal("First RE may not be null");
    496 					P(rep)->bptr.re1 = op;
    497 				} else {
    498 					op = P(rep)->bptr.re1;
    499 				}
    500 
    501 				if(compsub(&P(rep)->rhs, &P(rep)->nsub) == badp)
    502 					fatal(CGMES, linebuf);
    503 			sloop:	if(*cp == 'g') {
    504 					cp++;
    505 					P(rep)->gfl = -1;
    506 					goto sloop;
    507 				} else if(gflag)
    508 					P(rep)->gfl = -1;
    509 				if (*cp >= '0' && *cp <= '9') {
    510 					while (*cp >= '0' && *cp <= '9') {
    511 						if (P(rep)->gfl == -1)
    512 							P(rep)->gfl = 0;
    513 						P(rep)->gfl = P(rep)->gfl * 10
    514 							+ *cp++ - '0';
    515 					}
    516 					goto sloop;
    517 				}
    518 #if !defined (SUS) && !defined (SU3)
    519 				if (P(rep)->gfl > 0 && P(rep)->gfl > 512)
    520 			fatal("Suffix too large - 512 max: %s", linebuf);
    521 #endif
    522 
    523 				if(*cp == 'p') {
    524 					cp++;
    525 					P(rep)->pfl = 1;
    526 					goto sloop;
    527 				}
    528 
    529 				if(*cp == 'P') {
    530 					cp++;
    531 					P(rep)->pfl = 2;
    532 					goto sloop;
    533 				}
    534 
    535 				if(*cp == 'w') {
    536 					cp++;
    537 					wfile();
    538 				}
    539 				break;
    540 
    541 			case 'w':
    542 				P(rep)->command = WCOM;
    543 				wfile();
    544 				break;
    545 
    546 			case 'x':
    547 				P(rep)->command = XCOM;
    548 				break;
    549 
    550 			case 'y':
    551 				P(rep)->command = YCOM;
    552 				sed_seof = fetch(&cp);
    553 				if (ycomp(&P(rep)->bptr.re1) == badp)
    554 					fatal(CGMES, linebuf);
    555 				break;
    556 
    557 		}
    558 		rep_inc();
    559 
    560 		if(*cp++ != '\0') {
    561 			if(cp[-1] == ';')
    562 				goto comploop;
    563 			fatal(CGMES, linebuf);
    564 		}
    565 
    566 	}
    567 	P(rep)->command = 0;
    568 	lastre = op;
    569 }
    570 
    571 static char	*
    572 compsub(char **rhsbuf, char *nsubp)
    573 {
    574 	register char	*p, *op, *oq;
    575 	char	*q;
    576 	wint_t	c;
    577 	size_t	sz = 32;
    578 
    579 	*rhsbuf = smalloc(sz);
    580 	p = *rhsbuf;
    581 	q = cp;
    582 	*nsubp = 0;
    583 	for(;;) {
    584 		op = p;
    585 		oq = q;
    586 		if((c = fetch(&q)) == '\\') {
    587 			check(p, *rhsbuf, sz, 32, op)
    588 			*p = '\\';
    589 			oq = q;
    590 			c = fetch(&q);
    591 			do {
    592 				check(p, *rhsbuf, sz, 32, op)
    593 				*++p = *oq++;
    594 			} while (oq < q);
    595 			if(c > nbra + '0' && c <= '9')
    596 				return(badp);
    597 			if (c > *nsubp + '0' && c <= '9')
    598 				*nsubp = c - '0';
    599 			check(p, *rhsbuf, sz, 32, op)
    600 			p++;
    601 			continue;
    602 		} else {
    603 			do {
    604 				check(p, *rhsbuf, sz, 32, op)
    605 				*p++ = *oq++;
    606 			} while (oq < q);
    607 			p--;
    608 		}
    609 		if(c == sed_seof) {
    610 			check(p, *rhsbuf, sz, 32, op)
    611 			*op++ = '\0';
    612 			cp = q;
    613 			return(op);
    614 		}
    615 		check(p, *rhsbuf, sz, 32, op)
    616 		if(*p++ == '\0') {
    617 			return(badp);
    618 		}
    619 
    620 	}
    621 }
    622 
    623 #define	rlinechk()	if (c >= lbend-2) \
    624 				growsp(LINTL)
    625 
    626 static int
    627 rline(void)
    628 {
    629 	register char	*q;
    630 	register int	c;
    631 	register int	t;
    632 	static char	*saveq;
    633 
    634 	c = -1;
    635 
    636 	if(eflag) {
    637 		if(eflag > 0) {
    638 			eflag = -1;
    639 			q = optarg;
    640 			rlinechk();
    641 			while(linebuf[++c] = *q++) {
    642 				rlinechk();
    643 				if(linebuf[c] == '\\') {
    644 					if((linebuf[++c] = *q++) == '\0') {
    645 						rlinechk();
    646 						saveq = 0;
    647 						return(-1);
    648 					} else
    649 						continue;
    650 				}
    651 				if(linebuf[c] == '\n') {
    652 					linebuf[c] = '\0';
    653 					saveq = q;
    654 					return(1);
    655 				}
    656 			}
    657 			saveq = 0;
    658 			return(1);
    659 		}
    660 		if((q = saveq) == 0)	return(-1);
    661 
    662 		while(linebuf[++c] = *q++) {
    663 			rlinechk();
    664 			if(linebuf[c] == '\\') {
    665 				if((linebuf[++c] = *q++) == '0') {
    666 					rlinechk();
    667 					saveq = 0;
    668 					return(-1);
    669 				} else
    670 					continue;
    671 			}
    672 			if(linebuf[c] == '\n') {
    673 				linebuf[c] = '\0';
    674 				saveq = q;
    675 				return(1);
    676 			}
    677 		}
    678 		saveq = 0;
    679 		return(1);
    680 	}
    681 
    682 	while((t = getc(fin)) != EOF) {
    683 		rlinechk();
    684 		linebuf[++c] = (char)t;
    685 		if(linebuf[c] == '\\') {
    686 			t = getc(fin);
    687 			rlinechk();
    688 			linebuf[++c] = (char)t;
    689 		}
    690 		else if(linebuf[c] == '\n') {
    691 			linebuf[c] = '\0';
    692 			return(1);
    693 		}
    694 	}
    695 	linebuf[++c] = '\0';
    696 	return(-1);
    697 }
    698 
    699 static char	*
    700 address(char **expbuf)
    701 {
    702 	register char	*rcp, *ep;
    703 	long long	lno;
    704 
    705 	*expbuf = NULL;
    706 	if(*cp == '$') {
    707 		cp++;
    708 		ep = *expbuf = smalloc(2 * sizeof *expbuf);
    709 		*ep++ = CEND;
    710 		*ep++ = ceof;
    711 		needdol = 1;
    712 		return(ep);
    713 	}
    714 
    715 	if(*cp == '/' || *cp == '\\') {
    716 		if (*cp == '\\')
    717 			cp++;
    718 		sed_seof = fetch(&cp);
    719 		return(sed_compile(expbuf));
    720 	}
    721 
    722 	rcp = cp;
    723 	lno = 0;
    724 
    725 	while(*rcp >= '0' && *rcp <= '9')
    726 		lno = lno*10 + *rcp++ - '0';
    727 
    728 	if(rcp > cp) {
    729 		if (nlno > 020000000000 ||
    730 		    (tlno = realloc(tlno, (nlno+1)*sizeof *tlno)) == NULL)
    731 			fatal("Too many line numbers");
    732 		ep = *expbuf = smalloc(6 * sizeof *expbuf);
    733 		*ep++ = CLNUM;
    734 		slno(ep, nlno);
    735 		tlno[nlno++] = lno;
    736 		*ep++ = ceof;
    737 		cp = rcp;
    738 		return(ep);
    739 	}
    740 	return(0);
    741 }
    742 
    743 static int
    744 cmp(const char *a, const char *b)
    745 {
    746 	register const char	*ra, *rb;
    747 
    748 	ra = a - 1;
    749 	rb = b - 1;
    750 
    751 	while(*++ra == *++rb)
    752 		if(*ra == '\0')	return(0);
    753 	return(1);
    754 }
    755 
    756 static void
    757 text(char **textbuf)
    758 {
    759 	register char	*p, *oq;
    760 	char *q;
    761 	size_t sz = 128;
    762 
    763 	*textbuf = smalloc(sz);
    764 	p = *textbuf;
    765 	q = cp;
    766 	for(;;) {
    767 
    768 		oq = q;
    769 		if(fetch(&q) == '\\') {
    770 			oq = q;
    771 			fetch(&q);
    772 		}
    773 		while(oq < q)
    774 			*p++ = *oq++;
    775 		if(p[-1] == '\0') {
    776 			cp = --q;
    777 			return;
    778 		}
    779 		check(p, *textbuf, sz, 128, null)
    780 	}
    781 }
    782 
    783 static int
    784 search(struct label *ptr)
    785 {
    786 	struct label	*rp;
    787 
    788 	rp = L(labtab);
    789 	while(rp < ptr) {
    790 		if(cmp(rp->asc, ptr->asc) == 0)
    791 			return(rp - L(labtab) + 1);
    792 		rp++;
    793 	}
    794 
    795 	return(0);
    796 }
    797 
    798 
    799 static void
    800 dechain(void)
    801 {
    802 	struct label	*lptr;
    803 	int	rptr, trptr;
    804 
    805 	for(lptr = L(labtab); lptr < L(lab); lptr++) {
    806 
    807 		if(lptr->address == 0)
    808 			fatal("Undefined label: %s", lptr->asc);
    809 
    810 		if(lptr->chain) {
    811 			rptr = lptr->chain;
    812 			while((trptr = P(rptr)->bptr.lb1) != 0) {
    813 				P(rptr)->bptr.lb1 = lptr->address;
    814 				rptr = trptr;
    815 			}
    816 			P(rptr)->bptr.lb1 = lptr->address;
    817 		}
    818 	}
    819 }
    820 
    821 static char *
    822 ycomp_sb(char **expbuf)
    823 {
    824 	register int	c, d;
    825 	register char	*ep, *tsp;
    826 	char	*sp;
    827 
    828 	*expbuf = smalloc(0400);
    829 	ep = *expbuf;
    830 	for(c = 0; !(c & 0400); c++)
    831 		ep[c] = '\0';
    832 	sp = cp;
    833 	for(tsp = cp; *tsp != sed_seof; tsp++) {
    834 		if(*tsp == '\\')
    835 			tsp++;
    836 		if(*tsp == '\n' || *tsp == '\0')
    837 			return(badp);
    838 	}
    839 	tsp++;
    840 
    841 	while((c = *sp++ & 0377) != sed_seof) {
    842 		if(c == '\\') {
    843 			c = *sp == 'n' ? '\n' : *sp;
    844 			sp++;
    845 		}
    846 		if((ep[c] = d = *tsp++ & 0377) == '\\') {
    847 			ep[c] = *tsp == 'n' ? '\n' : *tsp;
    848 			tsp++;
    849 		}
    850 		if(d != '\\' && ep[c] == sed_seof || ep[c] == '\0')
    851 			return(badp);
    852 	}
    853 	if(*tsp != sed_seof)
    854 		return(badp);
    855 	cp = ++tsp;
    856 
    857 	for(c = 0; !(c & 0400); c++)
    858 		if(ep[c] == 0)
    859 			ep[c] = (char)c;
    860 
    861 	return(ep + 0400);
    862 }
    863 
    864 static char *
    865 ycomp_mb(char **expbuf)
    866 {
    867 	struct yitem	**yt, *yp;
    868 	register wint_t	c, d;
    869 	char	*otsp, *tsp, *sp, *mp;
    870 
    871 	tsp = sp = cp;
    872 	while ((c = fetch(&tsp)) != sed_seof) {
    873 		if (c == '\\')
    874 			c = fetch(&tsp);
    875 		if (c == '\n' || c == '\0')
    876 			return badp;
    877 	}
    878 	yt = scalloc(200, sizeof *yt);
    879 	while ((c = fetch(&sp)) != sed_seof) {
    880 		if (c == '\\') {
    881 			if ((d = fetch(&sp)) == 'n')
    882 				c = '\n';
    883 			else
    884 				c = d;
    885 		}
    886 		otsp = tsp;
    887 		d = fetch(&tsp);
    888 		yp = ylook(c, yt, 1);
    889 		yp->y_oc = c;
    890 		if ((yp->y_yc = d) == '\\') {
    891 			otsp = tsp;
    892 			if ((c = fetch(&tsp)) == 'n')
    893 				yp->y_yc = '\n';
    894 			else
    895 				yp->y_yc = c;
    896 		}
    897 		if (d != '\\' && yp->y_yc == sed_seof || yp->y_yc == '\0')
    898 			return badp;
    899 		mp = yp->y_mc;
    900 		if (yp->y_yc != '\n')
    901 			while (otsp < tsp)
    902 				*mp++ = *otsp++;
    903 		else
    904 			*mp++ = '\n';
    905 		*mp = '\0';
    906 	}
    907 	if (fetch(&tsp) != sed_seof)
    908 		return badp;
    909 	cp = tsp;
    910 	*expbuf = (char *)yt;
    911 	return &(*expbuf)[1];
    912 }
    913 
    914 static void
    915 rep_inc(void)
    916 {
    917 	register char	*p;
    918 	const int	chunk = 16;
    919 
    920 	if (++rep >= PTRSIZE) {
    921 		ptrspace = srealloc(ptrspace,
    922 				(PTRSIZE += chunk) * sizeof *ptrspace);
    923 		for (p = (char *)&ptrspace[PTRSIZE - chunk];
    924 				p < (char *)&ptrspace[PTRSIZE]; p++)
    925 			*p = '\0';
    926 	}
    927 }
    928 
    929 static void
    930 lab_inc(void)
    931 {
    932 	register char	*p;
    933 	const int	chunk = 8;
    934 
    935 	if (++lab >= LABSIZE) {
    936 		ltab = srealloc(ltab, (LABSIZE += chunk) * sizeof *ltab);
    937 		for (p = (char *)&ltab[LABSIZE - chunk];
    938 				p < (char *)&ltab[LABSIZE]; p++)
    939 			*p = '\0';
    940 	}
    941 }
    942 
    943 void
    944 aptr_inc(void)
    945 {
    946 	register char	*p;
    947 	const int	chunk = 8;
    948 
    949 	if (++aptr > ABUFSIZE) {
    950 		abuf = srealloc(abuf, (ABUFSIZE += chunk) * sizeof *abuf);
    951 		for (p = (char *)&abuf[ABUFSIZE - chunk];
    952 				p < (char *)&abuf[ABUFSIZE]; p++)
    953 			*p = '\0';
    954 	}
    955 }
    956 
    957 static void
    958 depth_check(void)
    959 {
    960 	if (depth + 1 > DEPTH)
    961 		cmpend = srealloc(cmpend, (DEPTH += 8) * sizeof *cmpend);
    962 }
    963 
    964 void
    965 nonfatal(const char *afmt, ...)
    966 {
    967 	va_list ap;
    968 	const char	*fmt;
    969 
    970 	if (*afmt == '\1') {
    971 		fprintf(stderr, "%s: ", progname);
    972 		fmt = &afmt[1];
    973 	} else
    974 		fmt = afmt;
    975 	va_start(ap, afmt);
    976 	vfprintf(stderr, fmt, ap);
    977 	va_end(ap);
    978 	fputc('\n', stderr);
    979 	status |= 1;
    980 }
    981 
    982 void
    983 fatal(const char *afmt, ...)
    984 {
    985 	va_list ap;
    986 	const char	*fmt;
    987 
    988 	if (*afmt == '\1') {
    989 		fprintf(stderr, "%s: ", progname);
    990 		fmt = &afmt[1];
    991 	} else
    992 		fmt = afmt;
    993 	va_start(ap, afmt);
    994 	vfprintf(stderr, fmt, ap);
    995 	va_end(ap);
    996 	fputc('\n', stderr);
    997 	exit(2);
    998 }
    999 
   1000 static void *
   1001 srealloc(void *vp, size_t nbytes)
   1002 {
   1003 	void *p;
   1004 
   1005 	if ((p = realloc(vp, nbytes)) == NULL)
   1006 		fatal(TMMES, linebuf);
   1007 	return p;
   1008 }
   1009 
   1010 void *
   1011 smalloc(size_t nbytes)
   1012 {
   1013 	return srealloc(NULL, nbytes);
   1014 }
   1015 
   1016 static void *
   1017 scalloc(size_t nmemb, size_t size)
   1018 {
   1019 	void *p;
   1020 
   1021 	if ((p = calloc(nmemb, size)) == NULL)
   1022 		fatal(TMMES, linebuf);
   1023 	return p;
   1024 }
   1025 
   1026 #if defined (SUS) || defined (SU3) || defined (S42)
   1027 static char *
   1028 sed_compile(char **ep)
   1029 {
   1030 	struct re_emu	*re;
   1031 	static char	*pat;
   1032 	static size_t	patsz;
   1033 	register char	*p, *oc;
   1034 	wint_t	c, d;
   1035 
   1036 	if (*cp != sed_seof)
   1037 		nbra = 0;
   1038 	if (patsz == 0)
   1039 		pat = smalloc(patsz = 32);
   1040 	p = pat;
   1041 	do {
   1042 		oc = cp;
   1043 		if ((c = fetch(&cp)) == sed_seof)
   1044 			*p = '\0';
   1045 		else if (c == '\\') {
   1046 			oc = cp;
   1047 			if ((c = fetch(&cp)) == 'n')
   1048 				*p = '\n';
   1049 			else {
   1050 				check(p, pat, patsz, 32, null);
   1051 				*p++ = '\\';
   1052 				if (c == '(')
   1053 					nbra++;
   1054 				goto normchar;
   1055 			}
   1056 		} else if (c == '[') {
   1057 			check(p, pat, patsz, 32, null);
   1058 			*p++ = c;
   1059 			d = WEOF;
   1060 			do {
   1061 				oc = cp;
   1062 				c = fetch(&cp);
   1063 				if (c == '\0')
   1064 					goto normchar;
   1065 				do {
   1066 					check(p, pat, patsz, 32, null);
   1067 					*p++ = *oc++;
   1068 				} while (oc < cp);
   1069 				if (d == '[' && (c == ':' || c == '.' ||
   1070 							c == '=')) {
   1071 					d = c;
   1072 					do {
   1073 						oc = cp;
   1074 						c = fetch(&cp);
   1075 						if (c == '\0')
   1076 							goto normchar;
   1077 						do {
   1078 							check(p, pat, patsz,32,
   1079 									null);
   1080 							*p++ = *oc++;
   1081 						} while (oc < cp);
   1082 					} while (c != d || peek(&cp) != ']');
   1083 					oc = cp;
   1084 					c = fetch(&cp);
   1085 					do {
   1086 						check(p, pat, patsz, 32, null);
   1087 						*p++ = *oc++;
   1088 					} while (oc < cp);
   1089 					c = WEOF; /* == reset d and continue */
   1090 				}
   1091 				d = c;
   1092 			} while (c != ']');
   1093 			p--;
   1094 		} else {
   1095 	normchar:	do {
   1096 				check(p, pat, patsz, 32, null)
   1097 				*p++ = *oc++;
   1098 			} while (oc < cp);
   1099 			p--;
   1100 		}
   1101 		check(p, pat, patsz, 32, null);
   1102 	} while (*p++ != '\0');
   1103 	re = scalloc(1, sizeof *re);
   1104 	*ep = (char *)re;
   1105 	if (*pat == '^')
   1106 		**ep = 1;
   1107 	if (*pat != '\0') {
   1108 		int reflags = 0;
   1109 
   1110 #ifdef	REG_ANGLES
   1111 		reflags |= REG_ANGLES;
   1112 #endif	/* REG_ANGLES */
   1113 #if defined (SU3) && defined (REG_AVOIDNULL)
   1114 		reflags |= REG_AVOIDNULL;
   1115 #endif	/* SU3 && AVOIDNULL */
   1116 		if (regcomp(&re->r_preg, pat, reflags) != 0)
   1117 			re = (struct re_emu *)badp;
   1118 	} else
   1119 		**ep = 2;
   1120 	p = (char *)re;
   1121 	if (p != badp && *pat)
   1122 		p++;
   1123 	return p;
   1124 }
   1125 #else	/* !SUS, !SU3, !S42 */
   1126 static char *
   1127 sed_compile(char **ep)
   1128 {
   1129 	extern char *compile(char *, char *, char *, int);
   1130 	register char *p;
   1131 	size_t sz;
   1132 
   1133 	for (sz = 0, p = cp; *p; p++)
   1134 		if (*p == '[')
   1135 			sz += 32;
   1136 	sz += 2 * (p - cp) + 5;
   1137 	*ep = smalloc(sz);
   1138 	(*ep)[1] = '\0';
   1139 	p = compile(NULL, &(*ep)[1], &(*ep)[sz], sed_seof);
   1140 	if (p == &(*ep)[1])
   1141 		return *ep;
   1142 	**ep = circf;
   1143 	return p;
   1144 }
   1145 #endif	/* !SUS, !SU3, !S42 */
   1146 
   1147 wint_t
   1148 wc_get(char **sc, int move)
   1149 {
   1150 	wint_t	c;
   1151 	char	*p = *sc;
   1152 	wchar_t	wcbuf;
   1153 	int	len;
   1154 
   1155 	if ((*p & 0200) == 0) {
   1156 		c = *p;
   1157 		p += (len = 1);
   1158 		invchar = 0;
   1159 	} else if ((len = mbtowc(&wcbuf, p, MB_LEN_MAX)) < 0) {
   1160 		if (!executing)
   1161 			fatal("invalid multibyte character: %s", p);
   1162 		c = (*p++ & 0377);
   1163 		mbtowc(NULL, NULL, 0);
   1164 		invchar = 1;
   1165 	} else if (len == 0) {
   1166 		c = '\0';
   1167 		p++;
   1168 		invchar = 0;
   1169 	} else {
   1170 		c = wcbuf;
   1171 		p += len;
   1172 		invchar = 0;
   1173 	}
   1174 	if (move)
   1175 		*sc = p;
   1176 	return c;
   1177 }
   1178 
   1179 /*
   1180  * Note that this hash is not optimized to distribute the items
   1181  * equally to all buckets. y commands typically handle only a
   1182  * small part of the alphabet, thus most characters will have
   1183  * no entry in the hash table. If no list exists in the bucket
   1184  * for the hash of these characters, the function can return
   1185  * quickly.
   1186  */
   1187 #define	yhash(c)	(c & 0177)
   1188 
   1189 struct yitem *
   1190 ylook(wint_t c, struct yitem **yt, int make)
   1191 {
   1192 	struct yitem	*yp;
   1193 	int	h;
   1194 
   1195 	yp = yt[h = yhash(c)];
   1196 	while (yp != NULL) {
   1197 		if (yp->y_oc == c)
   1198 			break;
   1199 		yp = yp->y_nxt;
   1200 	}
   1201 	if (make && yp == NULL) {
   1202 		yp = scalloc(1, sizeof *yp);
   1203 		yp->y_oc = c;
   1204 		yp->y_nxt = yt[h];
   1205 		yt[h] = yp;
   1206 	}
   1207 	return yp;
   1208 }
   1209 
   1210 void
   1211 growsp(const char *msg)
   1212 {
   1213 	const int	incr = 128;
   1214 	int	olbend, ogbend, ohend;
   1215 
   1216 	olbend = lbend;
   1217 	ogbend = gbend;
   1218 	ohend = hend;
   1219 	if ((linebuf = realloc(linebuf, lbend += incr)) == NULL ||
   1220 			(genbuf = realloc(genbuf, gbend += incr)) == NULL ||
   1221 			(holdsp = realloc(holdsp, hend += incr)) == NULL)
   1222 		fatal(msg ? msg : "Cannot malloc space");
   1223 	while (olbend < lbend)
   1224 		linebuf[olbend++] = '\0';
   1225 	while (ogbend < gbend)
   1226 		genbuf[ogbend++] = '\0';
   1227 	while (ohend < hend)
   1228 		holdsp[ohend++] = '\0';
   1229 }
   1230 
   1231 static void
   1232 wfile(void)
   1233 {
   1234 	int	i;
   1235 
   1236 #if !defined (SUS) && !defined (SU3)
   1237 	if(*cp++ != ' ')
   1238 		fatal(CGMES, linebuf);
   1239 #else	/* SUS, SU3 */
   1240 	while (*cp == ' ' || *cp == '\t')
   1241 		cp++;
   1242 #endif	/* SUS, SU3 */
   1243 
   1244 	text(&fname[nfiles]);
   1245 	for(i = nfiles - 1; i >= 0; i--)
   1246 		if(fname[i] != NULL && cmp(fname[nfiles], fname[i]) == 0) {
   1247 			P(rep)->fcode = fcode[i];
   1248 			free(fname[nfiles]);
   1249 			return;
   1250 		}
   1251 
   1252 	if((P(rep)->fcode = fopen(fname[nfiles], "w")) == NULL)
   1253 		fatal("Cannot create %s", fname[nfiles]);
   1254 	fcode[nfiles++] = P(rep)->fcode;
   1255 	morefiles();
   1256 }
   1257 
   1258 static void
   1259 morefiles(void)
   1260 {
   1261 	if ((fname = realloc(fname, (nfiles+1) * sizeof *fname)) == 0 ||
   1262 	    (fcode = realloc(fcode, (nfiles+1) * sizeof *fcode)) == 0)
   1263 		fatal("Too many files in w commands");
   1264 	fname[nfiles] = 0;
   1265 	fcode[nfiles] = 0;
   1266 }