/*
 * Copyright 1992, 1993 by TOSHIBA Corp.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of TOSHIBA not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission. TOSHIBA make no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * TOSHIBA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * Author: Katsuhisa Yano	TOSHIBA Corp.
 *			   	mopi@osa.ilab.toshiba.co.jp
 * Bug fixes: Bruno Haible	XFree86 Inc.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "Xlibint.h"
#include "XlcPubI.h"
#include <stdio.h>

/*
 * Default implementation of methods for Xrm parsing.
 */

/* ======================= Unibyte implementation ======================= */

/* Only for efficiency, to speed up things. */

/* This implementation must keep the locale, for lcname. */
typedef struct _UbStateRec {
    XLCd	lcd;
} UbStateRec, *UbState;

/* Sets the state to the initial state.
   Initiates a sequence of calls to mbchar. */
static void
ub_mbinit(
    XPointer state)
{
}

/* Transforms one multibyte character, and return a 'char' in the same
   parsing class. Returns the number of consumed bytes in *lenp. */
static char
ub_mbchar(
    XPointer state,
    const char *str,
    int	*lenp)
{
    *lenp = 1;
    return *str;
}

/* Terminates a sequence of calls to mbchar. */
static void
ub_mbfinish(
    XPointer state)
{
}

/* Returns the name of the state's locale, as a static string. */
static const char *
ub_lcname(
    XPointer state)
{
    return ((UbState) state)->lcd->core->name;
}

/* Frees the state, which was allocated by _XrmDefaultInitParseInfo. */
static void
ub_destroy(
    XPointer state)
{
    _XCloseLC(((UbState) state)->lcd);
    Xfree(state);
}

static const XrmMethodsRec ub_methods = {
    ub_mbinit,
    ub_mbchar,
    ub_mbfinish,
    ub_lcname,
    ub_destroy
};

/* ======================= Multibyte implementation ======================= */

/* This implementation uses an XlcConv from XlcNMultiByte to XlcNWideChar. */
typedef struct _MbStateRec {
    XLCd	lcd;
    XlcConv	conv;
} MbStateRec, *MbState;

/* Sets the state to the initial state.
   Initiates a sequence of calls to mbchar. */
static void
mb_mbinit(
    XPointer state)
{
    _XlcResetConverter(((MbState) state)->conv);
}

/* Transforms one multibyte character, and return a 'char' in the same
   parsing class. Returns the number of consumed bytes in *lenp. */
static char
mb_mbchar(
    XPointer state,
    const char *str,
    int	*lenp)
{
    XlcConv conv = ((MbState) state)->conv;
    const char *from;
    wchar_t *to, wc;
    int cur_max, i, from_left, to_left, ret;

    cur_max = XLC_PUBLIC(((MbState) state)->lcd, mb_cur_max);

    from = str;
    /* Determine from_left. Avoid overrun error which could occur if
       from_left > strlen(str). */
    from_left = cur_max;
    for (i = 0; i < cur_max; i++)
	if (str[i] == '\0') {
	    from_left = i;
	    break;
	}
    *lenp = from_left;

    to = &wc;
    to_left = 1;

    ret = _XlcConvert(conv, (XPointer *) &from, &from_left,
		      (XPointer *) &to, &to_left, NULL, 0);
    *lenp -= from_left;

    if (ret < 0 || to_left > 0) {
	/* Invalid or incomplete multibyte character seen. */
	*lenp = 1;
	return 0x7f;
    }
    /* Return a 'char' equivalent to wc. */
    return (wc >= 0 && wc <= 0x7f ? wc : 0x7f);
}

/* Terminates a sequence of calls to mbchar. */
static void
mb_mbfinish(
    XPointer state)
{
}

/* Returns the name of the state's locale, as a static string. */
static const char *
mb_lcname(
    XPointer state)
{
    return ((MbState) state)->lcd->core->name;
}

/* Frees the state, which was allocated by _XrmDefaultInitParseInfo. */
static void
mb_destroy(
    XPointer state)
{
    _XlcCloseConverter(((MbState) state)->conv);
    _XCloseLC(((MbState) state)->lcd);
    Xfree(state);
}

static const XrmMethodsRec mb_methods = {
    mb_mbinit,
    mb_mbchar,
    mb_mbfinish,
    mb_lcname,
    mb_destroy
};

/* ======================= Exported function ======================= */

XrmMethods
_XrmDefaultInitParseInfo(
    XLCd lcd,
    XPointer *rm_state)
{
    if (XLC_PUBLIC(lcd, mb_cur_max) == 1) {
	/* Unibyte case. */
	UbState state = Xmalloc(sizeof(UbStateRec));
	if (state == NULL)
	    return (XrmMethods) NULL;

	state->lcd = lcd;

	*rm_state = (XPointer) state;
	return &ub_methods;
    } else {
	/* Multibyte case. */
	MbState state = Xmalloc(sizeof(MbStateRec));
	if (state == NULL)
	    return (XrmMethods) NULL;

	state->lcd = lcd;
	state->conv = _XlcOpenConverter(lcd, XlcNMultiByte, lcd, XlcNWideChar);
	if (state->conv == NULL) {
	    Xfree(state);
	    return (XrmMethods) NULL;
	}

	*rm_state = (XPointer) state;
	return &mb_methods;
    }
}