/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1990 MIPS Computer Systems, Inc.            |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 52.227-7013.   |
 * |         MIPS Computer Systems, Inc.                       |
 * |         928 Arques Avenue                                 |
 * |         Sunnyvale, CA 94086                               |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: reg_compile.c,v 1.1.2.1 92/06/24 14:08:47 marker Exp $"

/*	Copyright (c) 1988 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*	This module is modified for MNLS on Feb 1 1989	*/	/*MNLS*/

#ident	"@(#)libgen:reg_compile.c 1.0 AT&T-UP"

#include <euc.h>
#include <pcode.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
#include "_wchar.h"
#include "_regexp.h"

#define GETC() ((unsigned char)*sp++)
#define PEEKC() ((unsigned char)*sp)
#define ERROR(c) { \
		 	regerrno = c; \
			return(ep); \
		    }
#define Popwchar	if((n = mbtowc(&cl, sp, MB_LEN_MAX)) == -1) \
				ERROR(67) \
			oldsp = sp; \
			sp += n; \
			c = cl;

int	nbra, regerrno;

static char	_bittab[] = { 1, 2, 4, 8, 16, 32, 64, 128 };

char *
compile(sp, ep, endbuf)
register char *sp, *ep;
char *endbuf;
{
	register wchar_t c;
	register int n;
	wchar_t d;
	register char *oldsp;
	char *lastep;
	int cclcnt;
	char bracket[NBRA], *bracketp;
	int closed;
	int neg;
	wchar_t lc, cl;
	int i, cflg;
	register char *start;

	eucmask = (_pcwchek(_pcwidth())) ? EUCMASK : F_EUCMASK;

	endbuf--; /* avoid extra check for overflow */
	regerrno = 0;
	lastep = 0;
   /*	bracketp = bracket;  */
   /*	closed = nbra = 0;   */
	Popwchar
	if(c == '\0' || c == '\n') {
		if(ep[1] == 0)
			ERROR(41);
		return(ep);
	}
	bracketp = bracket;
	closed = nbra = 0;
	if(c == '^')
		*ep++ = 1;
	else  {
		*ep++ = 0; 
		sp = oldsp;
	}

	while(1) {
		if(ep >= endbuf)
			ERROR(50);
		Popwchar
		if(c != '*' && ((c != '\\') || (PEEKC() != '{')))
			lastep = ep;
		if(c == '\0') {
			*ep++ = CCEOF;
			if (bracketp != bracket)
				ERROR(42);
			return(ep);
		}
		switch(c) {

		case '.':
			*ep++ = CDOT;
			continue;

		case '\n':
			*ep++ = CCEOF;
			if(bracketp != bracket)
				ERROR(42);
			return(ep);
		
		case '*':
			if(lastep == 0 || *lastep == CBRA || *lastep == CKET)
				goto defchar;
			*lastep |= STAR;
			continue;

		case '$':
			/* look one character ahead to see if $ means
			   to anchor match at end of line */
			if((d = PEEKC()) != '\0' && d != '\n')
				goto defchar;
			*ep++ = CDOL;
			continue;

		case '[':
			start = ep + 34;
			if(start > endbuf)
				ERROR(50);

			*ep++ = CCL;
			lc = 0;
			for(i = 0; i < 32; i++)
				ep[i] = 0;
				
			neg = 0;
			Popwchar
			if(c == '^') {
				neg = 1;
				Popwchar
			}
			if(multibyte) {
				if(neg) {
					/* do not negate bitmap for 
					   for multibyte characters */
					neg = 0;
					ep[-1] = NMCCL;
					/* turn off null byte */
					ep[0] |= 01; 
				} else
					ep[-1] = MCCL;
			}
			do {
				if(c == '\0' || c == '\n')
					ERROR(49);
				if(c == '-' && lc != 0) {
					Popwchar
					if(c == ']') {
						PLACE('-');
						break;
					}
					/*
					 * ranges do not span code sets 
					 */
					if(!multibyte || c <= 0177) 
						while(lc < c ) {
							PLACE(lc);
							lc++;
						}
					else if((c & eucmask) == (lc & eucmask) && lc < c && ((c > 0377 || !iscntrl(c)) && (lc > 0377 || !iscntrl(lc))))
						/* insert '-' for range */
						*start++ = '-';
				}
				lc = c;
				/* put eight bit characters into bitmap */
				if(!multibyte || c <= 0177 || c <= 0377 && iscntrl(c)) 
					 PLACE(c);
				else {
					/*
					 * insert individual bytes of 
					 * multibyte characters after 
					 * bitmap
					 */
					if(start + n > endbuf)
						ERROR(50);
					while(n--)
						*start++ = *oldsp++;
				}
				Popwchar
			} while(c != ']');
			
			if(neg) {
				for(cclcnt = 0; cclcnt < 32; cclcnt++)
					ep[cclcnt] ^= 0377;
				ep[0] &= 0376;
			}
			ep += 32;
			if(multibyte) {
				/*
				 * Only allow 256 bytes to
				 * represent multibyte characters
				 * character class
				 */
				if(start - ep > 255)
					ERROR(50);
				*ep = start - ep;
				ep = start;
			}
			continue;

		case '\\':
			Popwchar
			switch(c) {

			case '(':
				if(nbra >= NBRA)
					ERROR(43);
				*bracketp++ = nbra;
				*ep++ = CBRA;
				*ep++ = nbra++;
				continue;

			case ')':
				if(bracketp <= bracket) 
					ERROR(42);
				*ep++ = CKET;
				*ep++ = *--bracketp;
				closed++;
				continue;

			case '{':
				if(lastep == (char *) 0)
					goto defchar;
				*lastep |= RNGE;
				cflg = 0;
				c = GETC();
			nlim:
				i = 0;
				do {
					if('0' <= c && c <= '9')
						i = 10 * i + c - '0';
					else
						ERROR(16);
				} while(((c = GETC()) != '\\') && (c != ','));
				if(i > 255)
					ERROR(11);
				*ep++ = i;
				if(c == ',') {
					if(cflg++)
						ERROR(44);
					if((c = GETC()) == '\\')
						*ep++ = 255;
					else
						goto nlim;
						/* get 2'nd number */
				}
				if(GETC() != '}')
					ERROR(45);
				if(!cflg)	/* one number */
					*ep++ = i;
				else if((int)(unsigned char)ep[-1] < (int)(unsigned char)ep[-2])
					ERROR(46);
				continue;

			case '\n':
				ERROR(36)

			case 'n':
				c = '\n';
				goto defchar;

			default:
				if(c >= '1' && c <= '9') {
					if((c -= '1') >= closed)
						ERROR(25);
					*ep++ = CBACK;
					*ep++ = c;
					continue;
				}
			}
				
	/* Drop through to default to use \ to turn off special chars */

		defchar:
		default:
			lastep = ep;
			if(!multibyte || c <= 0177) {
				/* 8-bit character */
				*ep++ = CCHR;
				*ep++ = c;
			} else {
				/* multibyte character */
				*ep++ = MCCHR;
				if(ep + n > endbuf)
					ERROR(50);
				while(n--)
					*ep++ = *oldsp++;
			}
		}
	}
}
