/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 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 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: strxfrm.c,v 1.2.2.1 92/06/24 14:01:11 marker Exp $"

/*	Copyright (c) 1987 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 Oct 12 1988	*/


#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <locale.h>
#include <malloc.h>
#include "_locale.h"

#define		DEF_COLL	"/LC_COLLATE"
#define		TWOTOONE	0x4000
#define		SECONDARY	0x3f00
#define		PRIMARY		0x00ff

/* The default is 7 bit ASCII here */
short _colltbl[SZ_COLLATE/2] =  {

0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1, 0x1, 0x1, 0x1, 0x1,
0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,
0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1
};

unsigned char _1_to_n[SZ_SUBS] = {0x0, 0x0, 0x0, 0};
unsigned short  _2_to_1[SZ_SUBS] = {0x00, 0};
unsigned short  val_2_to_1[SZ_SUBS] = {0x00, 0 };

static char saved_locale[LC_NAMELEN] = "C";
extern char _cur_locale[][LC_NAMELEN];
extern char *getenv();
#if i386
static void swapbytes();
#endif

/*  Structure of replacement strings  */

struct {
	char		*regexp;
	char		*repl_string;
	unsigned short	repl_length;
	int		regexp_length;
} subs[] = { 0 };

/*
 *	ANSI 4.11.4.5 strxfrm function
 */

int strxfrm(s1,  s2,  maxlen)
/*	start  for MNLS by UNIX Pacific on Oct 12 1988	*/
/* char	*s1; */
unsigned char	*s1;
/*	end  for MNLS	*/
int	maxlen;
/*	start  for MNLS by UNIX Pacific on Oct 12 1988	*/
/* char	*s2; */
unsigned char	*s2;
/*	end  for MNLS	*/
{
	/*  Local Declarations  */
	register int	i, len;

/*	start  for MNLS by UNIX Pacific on Oct 12 1988	*/
/*	register char	*next;	*/
/*	char	*secondary, *start_pr, *start_sec;	*/
	register unsigned char	*next;
	unsigned char	*secondary, *start_pr, *start_sec;
/*	end  for MNLS	*/
	int	matchfound;
	short 	prim_sec;
	unsigned short temp;
	int n_sec = 0;
	int n_prim = 0;

	setcollate();

	/* allocate space for the secondary weights */
/*	start for MNLS by UNIX Pacific on Oct 28 1988	*/	/*MNLS*/
/*	if ((secondary = (char *)malloc(maxlen/2 + 1)) == NULL) {	*/
	if ((secondary = (unsigned char *)malloc(maxlen/2+2)) == NULL) {
/*	end for MNLS	*/
		return maxlen+1 ;
	}
	*secondary = '\0';

	/* initialize pointers to the strings containing the s1 and secondary weights */
	start_pr = s1;
	start_sec = secondary;
	/*  This is where all the work begins  */
	for( ; *s2 != '\0'; s2++) {
		prim_sec = _colltbl[*s2 & 0x0FF];
		i = 0;
		if (prim_sec < 0) { /* we have 1 to n mapping */
	
			/* Start looking through substitute strings array */

			while (_1_to_n[i] != *s2 && _1_to_n[i] != 0) 
				i += strlen(&_1_to_n[i+1]) + 2;
				
			if (_1_to_n[i] == 0)
				continue; /* No match found */
			for (++i; _1_to_n[i] != '\0'; i++) {
				*s1  = _colltbl[_1_to_n[i]] & PRIMARY;
				n_prim++;
				s1++;
				if (_colltbl[_1_to_n[i]] & SECONDARY) {
					n_sec++;
					*secondary++ = (_colltbl[_1_to_n[i]] & SECONDARY) >> 8 ;
				}
				if ((n_prim + n_sec) >= maxlen)
					return maxlen+1;
			}

		/* If the input character is the first one of 
		 * a two to one mapping sequence, then look for 
		 * the next character in the sequence
		 */

		} else if (prim_sec & TWOTOONE) /* 2 to 1 mapping */ {
			matchfound = 0;
			while (_2_to_1[i] != 0 && (*(s2+1) != 0)) {
				temp = *(s2+1) << 8;
				temp |= *s2;
				if( temp == _2_to_1[i]) {
					matchfound = 1;
					*s1 = val_2_to_1[i];
					n_prim++;
					if (val_2_to_1[i] & SECONDARY) {
						n_sec++;
						*secondary++ = (val_2_to_1[i] & SECONDARY)  >> 8;
					}
					if ((n_prim + n_sec) >= maxlen)
						return maxlen+1;
					s1++;
					s2++;
					break;
				}
			i++;
			}
			if (!matchfound)  {
				*s1 = prim_sec & PRIMARY;
				n_prim++;
				if (prim_sec & SECONDARY) {
					n_sec++;
					*secondary++ = (prim_sec & SECONDARY)  >> 8;
				}
				s1++;
				if ((n_prim + n_sec) >= maxlen)
					return maxlen+1;
			}
			else
				continue; /* to get next char */
						

		} else {
			if (prim_sec != 1) {
				*s1 = prim_sec & PRIMARY;
				n_prim++;
				if (prim_sec & SECONDARY) {
					n_sec++;
					*secondary++ = (prim_sec & SECONDARY)  >> 8;
				}
				if ((n_prim + n_sec) >= maxlen)
					return maxlen+1;
				s1++;
			}
		}
	}

	*s1 = '\0';
	*secondary = '\0';
	n_prim++;
	if ((n_prim + n_sec) > maxlen)
		return maxlen+1;

	/*	Now merge the Primary and Secondary strings */

	if (strlen(start_sec) != NULL)
		strcat(start_pr, start_sec);
	free(start_sec);
	return strlen(start_pr) ;
}

int setcollate()
{

	char pathname[128];
	register int fd, ret = -1;
	int size, pcnt, i;
	char *mycoll;
	char *p, *np;
	short *sp;

	if (strcmp(_cur_locale[LC_COLLATE], saved_locale) == 0)
		return 0 ;

	(void)strcpy(pathname, P_locale);
	(void)strcpy(&pathname[L_locale - 1], _cur_locale[LC_COLLATE]);
	(void)strcat(pathname, DEF_COLL);
	if ((fd = open(pathname, O_RDONLY)) >= 0) {
	
		if ((mycoll = malloc(SZ_COLLATE+(5*SZ_SUBS))) ==  NULL) 
			return; 
		if ((size = read(fd, mycoll, SZ_COLLATE + 5*SZ_SUBS)) != 0)
		{
			/*
			 * Update _colltbl only after everything works.
			 */
			if (size <= (SZ_COLLATE + 5*SZ_SUBS)) {
				(void)memcpy(_colltbl, mycoll, SZ_COLLATE);
#if i386
				swapbytes(_colltbl,SZ_COLLATE);
#endif
				p = mycoll + SZ_COLLATE; 
				while ( *p != '\0') 
					p += strlen(p) + 1;
				size = p - &mycoll[SZ_COLLATE];
				memcpy(_1_to_n, mycoll + SZ_COLLATE, size);
				_1_to_n[size] = '\0'; /* Ensure null after sequence */
				p++; pcnt = 0;
				do {
					/* Avoid odd byte boundaries */
					_2_to_1[pcnt] = *p++ << 8;
					_2_to_1[pcnt] |= *p++;
					pcnt++;
					} 
				while (*p != '\0');
				p++;
				_2_to_1[pcnt] = '\0';

				/* Now move the final array: val_2_to_1 */

				i = pcnt; pcnt= 0;
				while (i-- != 0)  {
					val_2_to_1[pcnt] = (*p++ << 8);
					val_2_to_1[pcnt] |= *p++;
					pcnt++;
				}
 
			}
			(void)strcpy(saved_locale, _cur_locale[LC_COLLATE]);
		}
		free(mycoll);
		(void)close(fd);
	}
}

/*
 *	ANSI 4.11.4.3 strcoll() function
 */

int
strcoll(s1, s2)
char *s1;
char *s2;
{
	char buf1[512], buf2[512]; /* Not malloc'ed for speed purposes */

	if (strxfrm(buf1, s1, 512) >= 512) 
		return 0 ;
	if (strxfrm(buf2, s2, 512) >= 512) 
		return 0 ;
	return(strcmp(buf1, buf2));
}

#if i386
static void
swapbytes(  dst , size )
char dst[];
{
char c;
int i;

	for (i=0;i<size;i+=2 ){
		c = dst[i];
		dst[i] = dst[i+1];
		dst[i+1] = c;
	}

}
#endif
