/***
*initctyp.c - contains _init_ctype
*
*	Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved.
*
*Purpose:
*	Contains the locale-category initialization function: _init_ctype().
*	
*	Each initialization function sets up locale-specific information
*	for their category, for use by functions which are affected by
*	their locale category.
*
*	*** For internal use by setlocale() only ***
*
*Revision History:
*	12-08-91  ETC	Created.
*	12-20-91  ETC	Updated to use new NLSAPI GetLocaleInfo.
*	12-18-92  CFW	Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3.
*	01-19-03  CFW	Move to _NEWCTYPETABLE, remove switch.
*	02-08-93  CFW	Bug fixes under _INTL switch.
*	05-20-93  GJF	Include windows.h, not individual win*.h files
*	06-11-93  CFW	Now inithelp takes void *.
*
*******************************************************************************/

#ifdef _INTL

#include <stdlib.h>
#include <windows.h>
#include <locale.h>
#include <setlocal.h>
#include <ctype.h>
#include <malloc.h>
#include <limits.h>

#define _CTABSIZE	257		/* size of ctype tables */

/***
*int _init_ctype() - initialization for LC_CTYPE locale category.
*
*Purpose:
*	In non-C locales, preread ctype tables for chars and wide-chars.
*	Old tables are freed when new tables are fully established, else
*	the old tables remain intact (as if original state unaltered).
*	The leadbyte table is implemented as the high bit in ctype1.
*
*	In the C locale, ctype tables are freed, and pointers point to
*	the static ctype table.
*
*	Tables contain 257 entries: -1 to 256.
*	Table pointers point to entry 0 (to allow index -1).
*
*Entry:
*	None.
*
*Exit:
*	0 success
*	1 fail
*
*Exceptions:
*
*******************************************************************************/

int _CRTAPI3 _init_ctype (
	void
	)
{
	/* non-C locale table for char's    */
	static unsigned short *ctype1 = NULL; /* keep around until next time */
	unsigned short *newctype1; /* temp new table */

   /* non-C locale table for wchar_t's */
	static unsigned short *wctype1 = NULL; /* keep around until next time */
	unsigned short *newwctype1; /* temp new table */

	int size;			// char buffer sizes
	int wcsize;			// wide char buffer sizes
	unsigned char *cbuffer = NULL;		// char working buffer
	wchar_t *wbuffer = NULL;	// wchar_t working buffer

	int i;				// general purpose counter
    unsigned char *cp;			// char pointer
    wchar_t *wcp;  	// wide char pointer
    CPINFO CPInfo;  // struct for use with GetCPInfo

	/* allocate and set up buffers before destroying old ones */
	/* codepage will be restored by setlocale if error */

	if (_lc_handle[LC_CTYPE] != _CLOCALEHANDLE)
    {
		if (_lc_codepage == 0)
        { /* code page was not specified */
            if (_getlocaleinfo(LC_INT_TYPE, MAKELCID(_lc_id[LC_CTYPE].wLanguage, SORT_DEFAULT),
                LOCALE_IDEFAULTCODEPAGE,
                (void *)&_lc_codepage) == -1)
				goto error_cleanup;
		}

		/* allocate new buffers for tables */
		newctype1 = (unsigned short *) malloc
            (_CTABSIZE * sizeof(unsigned short));
		newwctype1 = (unsigned short *) malloc 
			(_CTABSIZE * sizeof(unsigned short));
		cbuffer = (unsigned char *) malloc (_CTABSIZE * sizeof(char));
		wbuffer = (wchar_t *) malloc (_CTABSIZE * sizeof(wchar_t));

		if (!newctype1 || !newwctype1 || !cbuffer || !wbuffer)
			goto error_cleanup;

		/* construct string composed of first 256 chars in sequence */
		for (cp=cbuffer, i=0; i<_CTABSIZE-1; i++)
			*cp++ = (unsigned char)i;

        if (GetCPInfo( _lc_codepage, &CPInfo) == FALSE)
			goto error_cleanup;

        if (CPInfo.MaxCharSize > MB_LEN_MAX)
            goto error_cleanup;

        __mb_cur_max = (unsigned short) CPInfo.MaxCharSize;

        /* zero out leadbytes so MBtoWC doesn't interpret as multi-byte chars */
        if (__mb_cur_max > 1)
        {
            for (cp = (unsigned char *)CPInfo.LeadByte; cp[0] && cp[1]; cp += 2)
            {
			   for (i = cp[0]; i <= cp[1]; i++)
				   cbuffer[i] = 0;
            }
        }

		/* convert to wide character string */
		size = (_CTABSIZE-1) * sizeof(char);
        wcsize = (_CTABSIZE-1) * sizeof(wchar_t);
		if (MultiByteToWideChar (_lc_codepage, 0, (char *)cbuffer, size, 
			wbuffer, wcsize) == 0) 
            goto error_cleanup;

		/* convert to newctype1 table */
		if (GetStringTypeW (CT_CTYPE1, wbuffer, _CTABSIZE-1, newctype1+1)
			== FALSE) 
			goto error_cleanup;
		*newctype1 = 0;	/* entry for EOF */

        /* construct wide char string composed of first 256 chars in sequence */
		for (wcp=wbuffer, i=0; i<_CTABSIZE-1; i++)
			*wcp++ = (wchar_t)i;

        /* convert to newctype1 table */
		if (GetStringTypeW (CT_CTYPE1, wbuffer, _CTABSIZE-1, newwctype1+1)
			== FALSE) 
			goto error_cleanup;
		*newwctype1 = 0;	/* entry for EOF */

        /* ignore DefaultChar */
		
		/* mark lead-byte entries in newctype1 table */
        if (__mb_cur_max > 1)
        {
    		for (cp = (unsigned char *)CPInfo.LeadByte; cp[0] && cp[1]; cp += 2)
            {
                for (i = cp[0]; i <= cp[1]; i++)
                    newctype1[i+1] = _LEADBYTE;
            }
        }

		/* set pointers to point to entry 0 of tables */
		_pctype = newctype1 + 1;
		_pwctype = newwctype1 + 1;

		/* free old tables */
		if (ctype1)
			free (ctype1);
		ctype1 = newctype1;

		if (wctype1)
	      free (wctype1);
        wctype1 = newwctype1;

		/* cleanup and return success */
		free (cbuffer);
		free (wbuffer);
		return 0;

error_cleanup:
		free (newctype1);
		free (newwctype1);
		free (cbuffer);
		free (wbuffer);
		return 1;

	} else {

		/* set pointers to static C-locale table */
		_pctype = _ctype + 1;
		_pwctype = _ctype + 1;

		/* free dynamic locale-specific tables */
		free (ctype1);
		free (wctype1);
		ctype1 = NULL;
		wctype1 = NULL;

		return 0;
	}
}
#endif /* _INTL */
