/* $XConsortium: omGeneric.c,v 1.6 94/03/29 22:52:12 rws Exp $ */
/*
 * 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
 */

#include "Xlibint.h"
#include "XomGeneric.h"
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <stdio.h>

#define MAXFONTS		100

extern int _XmbDefalutTextEscapement(), _XwcDefalutTextEscapement();
extern int _XmbDefalutTextExtents(), _XwcDefalutTextExtents();
extern Status _XmbDefalutTextPerCharExtents(), _XwcDefalutTextPerCharExtents();
extern int _XmbDefalutDrawString(), _XwcDefalutDrawString();
extern void _XmbDefalutDrawImageString(), _XwcDefalutDrawImageString();

extern int _XmbGenericTextEscapement(), _XwcGenericTextEscapement();
extern int _XmbGenericTextExtents(), _XwcGenericTextExtents();
extern Status _XmbGenericTextPerCharExtents(), _XwcGenericTextPerCharExtents();
extern int _XmbGenericDrawString(), _XwcGenericDrawString();
extern void _XmbGenericDrawImageString(), _XwcGenericDrawImageString();

static Bool
init_fontset(oc)
    XOC oc;
{
    XOCGenericPart *gen;
    FontSet font_set;
    OMData data;
    int count;

    count = XOM_GENERIC(oc->core.om)->data_num;
    data = XOM_GENERIC(oc->core.om)->data;

    font_set = (FontSet) Xmalloc(sizeof(FontSetRec) * count);
    if (font_set == NULL)
	return False;
    bzero((char *) font_set, sizeof(FontSetRec) * count);

    gen = XOC_GENERIC(oc);
    gen->font_set_num = count;
    gen->font_set = font_set;

    for ( ; count-- > 0; data++, font_set++) {
	font_set->charset_count = data->charset_count;
	font_set->charset_list = data->charset_list;
	font_set->font_data_count = data->font_data_count;
	font_set->font_data = data->font_data;
    }

    return True;
}

static char *
get_prop_name(dpy, fs)
    Display *dpy;
    XFontStruct	*fs;
{
    unsigned long fp;

    if (XGetFontProperty(fs, XA_FONT, &fp))
	return XGetAtomName(dpy, fp); 

    return (char *) NULL;
}

static FontData
check_charset(font_set, font_name)
    FontSet font_set;
    char *font_name;
{
    FontData font_data;
    char *last;
    int count, length, name_len;

    name_len = strlen(font_name);
    last = font_name + name_len;

    count = font_set->font_data_count;
    font_data = font_set->font_data;
    for ( ; count-- > 0; font_data++) {
	length = strlen(font_data->name);
	if (length > name_len)
	    continue;
	
	if (_XlcCompareISOLatin1(last - length, font_data->name) == 0)
	    return font_data;
    }

    return (FontData) NULL;
}

static int
check_fontname(oc, name, found_num)
    XOC oc;
    char *name;
    int found_num;
{
    Display *dpy = oc->core.om->core.display;
    XOCGenericPart *gen = XOC_GENERIC(oc);
    FontData data;
    FontSet font_set;
    XFontStruct *fs_list;
    char **fn_list, *fname, *prop_fname;
    int list_num, font_set_num, i;

    fn_list = XListFontsWithInfo(dpy, name, MAXFONTS, &list_num, &fs_list);
    if (fn_list == NULL)
	return found_num;

    for (i = 0; i < list_num; i++) {
	fname = fn_list[i];
 	prop_fname = get_prop_name(dpy, fs_list + i);

	font_set = gen->font_set;
	font_set_num = gen->font_set_num;

	for ( ; font_set_num-- > 0; font_set++) {
	    if (font_set->font_name)
		continue;

	    if (data = check_charset(font_set, fname))
		goto found;
	    else if (prop_fname &&
		     (data = check_charset(font_set, prop_fname))) {
		fname = prop_fname;
found:
		font_set->side = data->side;
		font_set->font_name = (char *) Xmalloc(strlen(fname) + 1);
		if (font_set->font_name) {
		    strcpy(font_set->font_name, fname);
		    found_num++;
		}
		if (found_num == gen->font_set_num)
		    break;
	    }
	}
	if (prop_fname)
	    Xfree(prop_fname);
    }

    XFreeFontInfo(fn_list, fs_list, list_num);

    return found_num;
}

static Bool
load_font(oc)
    XOC oc;
{
    Display *dpy = oc->core.om->core.display;
    XOCGenericPart *gen = XOC_GENERIC(oc);
    FontSet font_set = gen->font_set;
    int num = gen->font_set_num;

    for ( ; num-- > 0; font_set++) {
	if (font_set->font_name == NULL)
	    continue;

	if (font_set->font == NULL) {
	    font_set->font = XLoadQueryFont(dpy, font_set->font_name);
	    if (font_set->font == NULL)
		return False;
	    
	    if (font_set->font->min_byte1 || font_set->font->max_byte1)
		font_set->is_xchar2b = True;
	    else
		font_set->is_xchar2b = False;
	}
    }

    return True;
}

static Bool
load_font_info(oc)
    XOC oc;
{
    Display *dpy = oc->core.om->core.display;
    XOCGenericPart *gen = XOC_GENERIC(oc);
    FontSet font_set = gen->font_set;
    char **fn_list;
    int fn_num, num = gen->font_set_num;

    for ( ; num-- > 0; font_set++) {
	if (font_set->font_name == NULL)
	    continue;

	if (font_set->info == NULL) {
	    fn_list = XListFontsWithInfo(dpy, font_set->font_name, 1, &fn_num,
					 &font_set->info);
	    if (font_set->info == NULL)
		return False;
	    
	    XFreeFontNames(fn_list);
	}
    }

    return True;
}

static void
set_fontset_extents(oc)
    XOC oc;
{
    XRectangle *ink = &oc->core.font_set_extents.max_ink_extent;
    XRectangle *logical = &oc->core.font_set_extents.max_logical_extent;
    XFontStruct **font_list, *font;
    XCharStruct overall;
    int logical_ascent, logical_descent;
    int	num = oc->core.font_info.num_font;

    font_list = oc->core.font_info.font_struct_list;
    font = *font_list++;
    overall = font->max_bounds;
    overall.lbearing = font->min_bounds.lbearing;
    logical_ascent = font->ascent;
    logical_descent = font->descent;

    while (--num > 0) {
	font = *font_list++;
	overall.lbearing = min(overall.lbearing, font->min_bounds.lbearing);
	overall.rbearing = max(overall.rbearing, font->max_bounds.rbearing);
	overall.ascent = max(overall.ascent, font->max_bounds.ascent);
	overall.descent = max(overall.descent, font->max_bounds.descent);
	overall.width = max(overall.width, font->max_bounds.width);
	logical_ascent = max(logical_ascent, font->ascent);
	logical_descent = max(logical_descent, font->descent);
    }

    ink->x = overall.lbearing;
    ink->y = -(overall.ascent);
    ink->width = overall.rbearing - overall.lbearing;
    ink->height = overall.ascent + overall.descent;

    logical->x = 0;
    logical->y = -(logical_ascent);
    logical->width = overall.width;
    logical->height = logical_ascent + logical_descent;
}

static Bool
init_core_part(oc)
    XOC oc;
{
    XOCGenericPart *gen = XOC_GENERIC(oc);
    FontSet font_set;
    int font_set_num;
    XFontStruct **font_struct_list;
    char **font_name_list, *font_name_buf;
    int	count, length;

    font_set = gen->font_set;
    font_set_num = gen->font_set_num;
    count = length = 0;

    for ( ; font_set_num-- > 0; font_set++) {
	if (font_set->font_name == NULL)
	    continue;

	length += strlen(font_set->font_name) + 1;
	count++;
    }
    if (count == 0)
        return False;

    font_struct_list = (XFontStruct **) Xmalloc(sizeof(XFontStruct *) * count);
    if (font_struct_list == NULL)
	return False;

    font_name_list = (char **) Xmalloc(sizeof(char *) * count);
    if (font_name_list == NULL)
	goto err;

    font_name_buf = (char *) Xmalloc(length);
    if (font_name_buf == NULL)
	goto err;

    oc->core.font_info.num_font = count;
    oc->core.font_info.font_name_list = font_name_list;
    oc->core.font_info.font_struct_list = font_struct_list;
    oc->core.context_dependent = False;

    font_set = gen->font_set;
    font_set_num = gen->font_set_num;

    for (count = 0; font_set_num-- > 0; font_set++, count++) {
	if (font_set->font_name == NULL)
	    continue;

	font_set->id = count;
	if (font_set->font)
	    *font_struct_list++ = font_set->font;
	else
	    *font_struct_list++ = font_set->info;
	strcpy(font_name_buf, font_set->font_name);
	Xfree(font_set->font_name);
	*font_name_list++ = font_set->font_name = font_name_buf;
	font_name_buf += strlen(font_name_buf) + 1;
    }

    set_fontset_extents(oc);

    return True;

err:
    if (font_name_list)
	Xfree(font_name_list);
    Xfree(font_struct_list);

    return False;
}

static char *
get_font_name(oc, pattern)
    XOC oc;
    char *pattern;
{
    char **list, *name;
    int count;

    list = XListFonts(oc->core.om->core.display, pattern, 1, &count);
    if (list == NULL)
	return NULL;

    name = (char *) Xmalloc(strlen(*list) + 1);
    if (name)
	strcpy(name, *list);
    
    XFreeFontNames(list);

    return name;
}

static int
parse_fontname(oc)
    XOC oc;
{
    XOCGenericPart *gen = XOC_GENERIC(oc);
    FontSet font_set;
    FontData font_data;
    char *pattern, *last, buf[BUFSIZ];
    int font_set_num, font_data_count, length, found_num = 0;
    Bool is_found;
    int count;
    char *base_name, *font_name, **name_list, **cur_name_list;

    name_list = _XParseBaseFontNameList(oc->core.base_name_list, &count);
    if (name_list == NULL)
	return -1;
    cur_name_list = name_list;

    while (count-- > 0) {
        pattern = *cur_name_list++;
	if (pattern == NULL || *pattern == '\0')
	    continue;

 	is_found = False;

	if (strchr(pattern, '*') == NULL &&
	    (font_name = get_font_name(oc, pattern))) {

	    font_set = gen->font_set;
	    font_set_num = gen->font_set_num;

	    for ( ; font_set_num-- > 0; font_set++) {
 		if (font_set->font_name)
 		    continue;
		font_data = check_charset(font_set, font_name);
		if (font_data == NULL)
 		    continue;

		font_set->side = font_data->side;
		font_set->font_name = (char *) Xmalloc(strlen(font_name) + 1);
		if (font_set->font_name == NULL) {
		    Xfree(font_name);
		    goto err;
		}
		strcpy(font_set->font_name, font_name);

 		found_num++;
 		is_found = True;
	    }

	    Xfree(font_name);

	    if (is_found)
		continue;
	}

 	strcpy(buf, pattern);
 	length = strlen(pattern);
	last = buf + length - 1;

 	if (length > 1 && *last == '*' && *(last - 1) == '-') {
	    if (length > 3 && *(last - 2) == '*' && *(last - 3) == '-')
		last -= 2;
	} else {
	    ++last;
	    *last++ = '-';
	}

	font_set = gen->font_set;
	font_set_num = gen->font_set_num;

	for ( ; font_set_num-- > 0; font_set++) {
 	    if (font_set->font_name)
 		continue;
	    
	    font_data = font_set->font_data;
	    font_data_count = font_set->font_data_count;

	    for ( ; font_data_count-- > 0; font_data++) {
		strcpy(last, font_data->name);
		if (font_set->font_name = get_font_name(oc, buf))
		    break;

		*last = '*';
		*(last + 1) = '-';
		strcpy(last + 2, font_data->name);
		if (font_set->font_name = get_font_name(oc, buf))
		    break;
	    }

	    if (font_set->font_name == NULL)
 		continue;

	    font_set->side = font_data->side;
 
 	    found_num++;
 	    is_found = True;
 	}

 	if (found_num == gen->font_set_num)
 	    break;
 	if (is_found == True)
 	    continue;
 
	found_num = check_fontname(oc, pattern, found_num);
	if (found_num == gen->font_set_num)
	    break;
    }

    base_name = (char *) Xmalloc(strlen(oc->core.base_name_list) + 1);
    if (base_name == NULL)
	goto err;

    strcpy(base_name, oc->core.base_name_list);
    oc->core.base_name_list = base_name;

    XFreeStringList(name_list);		

    return found_num;

err:
    XFreeStringList(name_list);		

    return -1;
}

static Bool
set_missing_list(oc)
    XOC oc;
{
    XOCGenericPart *gen = XOC_GENERIC(oc);
    FontSet font_set;
    char **charset_list, *charset_buf;
    int	count, length, font_set_num;

    font_set = gen->font_set;
    font_set_num = gen->font_set_num;
    count = length = 0;

    for ( ; font_set_num-- > 0; font_set++) {
	if (font_set->info || font_set->font) 
	    continue;
	
	length += strlen(font_set->font_data->name) + 1;
	count++;
    }

    if (count < 1)
	return True;

    charset_list = (char **) Xmalloc(sizeof(char *) * count);
    if (charset_list == NULL)
	return False;

    charset_buf = (char *) Xmalloc(length);
    if (charset_buf == NULL) {
	Xfree(charset_list);
	return False;
    }

    oc->core.missing_list.charset_list = charset_list;
    oc->core.missing_list.charset_count = count;

    font_set = gen->font_set;
    font_set_num = gen->font_set_num;

    for ( ; font_set_num-- > 0; font_set++) {
	if (font_set->info || font_set->font) 
	    continue;

	strcpy(charset_buf, font_set->font_data->name);
	*charset_list++ = charset_buf;
	charset_buf += strlen(charset_buf) + 1;
    } 

    return True;
}

static Bool
create_fontset(oc)
    XOC oc;
{
    XOMGenericPart *gen = XOM_GENERIC(oc->core.om);
    int found_num;

    if (init_fontset(oc) == False)
        return False;

    found_num = parse_fontname(oc);
    if (found_num <= 0) {
	if (found_num == 0)
	    set_missing_list(oc);
	return False;
    }

    if (gen->on_demand_loading == True) {
	if (load_font_info(oc) == False)
	    return False;
    } else {
	if (load_font(oc) == False)
	    return False;
    }

    if (init_core_part(oc) == False)
	return False;

    if (set_missing_list(oc) == False)
	return False;

    return True;
}

static void
destroy_oc(oc)
    XOC oc;
{
    Display *dpy = oc->core.om->core.display;
    XOCGenericPart *gen = XOC_GENERIC(oc);
    XFontStruct **font_list, *font;
    int count;

    if (gen->mbs_to_cs)
	_XlcCloseConverter(gen->mbs_to_cs);

    if (gen->wcs_to_cs)
	_XlcCloseConverter(gen->wcs_to_cs);

    if (gen->font_set)
	Xfree(gen->font_set);

    if (oc->core.base_name_list)
	Xfree(oc->core.base_name_list);

    if (oc->core.font_info.font_name_list)
	XFreeStringList(oc->core.font_info.font_name_list);

    if (font_list = oc->core.font_info.font_struct_list) {
	for (count = oc->core.font_info.num_font; count-- > 0; font_list++) {
	    if (font = *font_list) {
		if (font->fid)
		    XFreeFont(dpy, font);
		else
		    XFreeFontInfo(NULL, font, 1);
	    }
	}
	Xfree(oc->core.font_info.font_struct_list);
    }

    if (oc->core.missing_list.charset_list)
	XFreeStringList(oc->core.missing_list.charset_list);

#ifdef notdef
    if (oc->core.res_name)
	Xfree(oc->core.res_name);
    if (oc->core.res_class)
	Xfree(oc->core.res_class);
#endif
    
    Xfree(oc);
}

static char *
set_oc_values(oc, args, num_args)
    XOC oc;
    XlcArgList args;
    int num_args;
{
    if (oc->core.resources == NULL)
	return NULL;

    return _XlcSetValues((XPointer) oc, oc->core.resources,
			 oc->core.num_resources, args, num_args, XlcSetMask);
}

static char *
get_oc_values(oc, args, num_args)
    XOC oc;
    XlcArgList args;
    int num_args;
{
    if (oc->core.resources == NULL)
	return NULL;

    return _XlcGetValues((XPointer) oc, oc->core.resources,
			 oc->core.num_resources, args, num_args, XlcGetMask);
}

static XOCMethodsRec oc_default_methods = {
    destroy_oc,
    set_oc_values,
    get_oc_values,
    _XmbDefalutTextEscapement,
    _XmbDefalutTextExtents,
    _XmbDefalutTextPerCharExtents,
    _XmbDefalutDrawString,
    _XmbDefalutDrawImageString,
    _XwcDefalutTextEscapement,
    _XwcDefalutTextExtents,
    _XwcDefalutTextPerCharExtents,
    _XwcDefalutDrawString,
    _XwcDefalutDrawImageString
};

static XOCMethodsRec oc_generic_methods = {
    destroy_oc,
    set_oc_values,
    get_oc_values,
    _XmbGenericTextEscapement,
    _XmbGenericTextExtents,
    _XmbGenericTextPerCharExtents,
    _XmbGenericDrawString,
    _XmbGenericDrawImageString,
    _XwcGenericTextEscapement,
    _XwcGenericTextExtents,
    _XwcGenericTextPerCharExtents,
    _XwcGenericDrawString,
    _XwcGenericDrawImageString
};

typedef struct _XOCMethodsListRec {
    char *name;
    XOCMethods methods;
} XOCMethodsListRec, *XOCMethodsList;

static XOCMethodsListRec oc_methods_list[] = {
    { "default", &oc_default_methods },
    { "generic", &oc_generic_methods }
};

static XlcResource oc_resources[] = {
    { XNBaseFontName, NULLQUARK, sizeof(char *),
      XOffsetOf(XOCRec, core.base_name_list), XlcCreateMask | XlcGetMask },
    { XNOMAutomatic, NULLQUARK, sizeof(Bool),
      XOffsetOf(XOCRec, core.om_automatic), XlcGetMask },
    { XNMissingCharSet, NULLQUARK, sizeof(XOMCharSetList),
      XOffsetOf(XOCRec, core.missing_list), XlcGetMask },
    { XNDefaultString, NULLQUARK, sizeof(char *),
      XOffsetOf(XOCRec, core.default_string), XlcGetMask },
    { XNOrientation, NULLQUARK, sizeof(XOrientation),
      XOffsetOf(XOCRec, core.orientation), XlcSetMask | XlcGetMask },
    { XNDirectionalDependentDrawing, NULLQUARK, sizeof(Bool),
      XOffsetOf(XOCRec, core.directional_dependent), XlcGetMask },
    { XNContextualDrawing, NULLQUARK, sizeof(Bool),
      XOffsetOf(XOCRec, core.contextual_drawing), XlcGetMask },
    { XNResourceName, NULLQUARK, sizeof(char *),
      XOffsetOf(XOCRec, core.res_name), XlcSetMask | XlcGetMask },
    { XNResourceClass, NULLQUARK, sizeof(char *),
      XOffsetOf(XOCRec, core.res_class), XlcSetMask | XlcGetMask },
    { XNFontInfo, NULLQUARK, sizeof(XOMFontInfo),
      XOffsetOf(XOCRec, core.font_info), XlcGetMask }
};

static XOC
create_oc(om, args, num_args)
    XOM om;
    XlcArgList args;
    int num_args;
{
    XOC oc;
    XOMGenericPart *gen = XOM_GENERIC(om);
    XOCMethodsList methods_list = oc_methods_list;
    int count;

    oc = (XOC) Xmalloc(sizeof(XOCGenericRec));
    if (oc == NULL)
	return (XOC) NULL;
    bzero((char *) oc, sizeof(XOCGenericRec));
    
    oc->core.om = om;

    if (oc_resources[0].xrm_name == NULLQUARK)
	_XlcCompileResourceList(oc_resources, XlcNumber(oc_resources));
    
    if (_XlcSetValues((XPointer) oc, oc_resources, XlcNumber(oc_resources),
		      args, num_args, XlcCreateMask | XlcDefaultMask))
	goto err;

    if (oc->core.base_name_list == NULL)
	goto err;

    oc->core.resources = oc_resources;
    oc->core.num_resources = XlcNumber(oc_resources);

    if (create_fontset(oc) == False)
	goto err;

    oc->methods = &oc_generic_methods;

    if (gen->object_name) {
	count = XlcNumber(oc_methods_list);

	for ( ; count-- > 0; methods_list++) {
	    if (!_XlcCompareISOLatin1(gen->object_name, methods_list->name)) {
		oc->methods = methods_list->methods;
		break;
	    }
	}
    }

    return oc;

err:
    destroy_oc(oc);

    return (XOC) NULL;
}

static Status
close_om(om)
    XOM om;
{
    XOMGenericPart *gen = XOM_GENERIC(om);
    OMData data;
    int count;

    if (data = gen->data) {
	for (count = gen->data_num; count-- > 0; data++) {
	    if (data->charset_list)
		Xfree(data->charset_list);

	    if (data->font_data) {
		if (data->font_data->name)
		    Xfree(data->font_data->name);
		Xfree(data->font_data);
	    }
	}
	Xfree(gen->data);
    }

    if (gen->object_name)
	Xfree(gen->object_name);

    if (om->core.res_name)
	Xfree(om->core.res_name);
    if (om->core.res_class)
	Xfree(om->core.res_class);
    if (om->core.required_charset.charset_list &&
	om->core.required_charset.charset_count > 0)
	XFreeStringList(om->core.required_charset.charset_list);
    else
	Xfree((char*)om->core.required_charset.charset_list);
    if (om->core.orientation_list.orient)
	Xfree(om->core.orientation_list.orient);

    Xfree(om);

    return 0;
}

static char *
set_om_values(om, args, num_args)
    XOM om;
    XlcArgList args;
    int num_args;
{
    if (om->core.resources == NULL)
	return NULL;

    return _XlcSetValues((XPointer) om, om->core.resources,
			 om->core.num_resources, args, num_args, XlcSetMask);
}

static char *
get_om_values(om, args, num_args)
    XOM om;
    XlcArgList args;
    int num_args;
{
    if (om->core.resources == NULL)
	return NULL;

    return _XlcGetValues((XPointer) om, om->core.resources,
			 om->core.num_resources, args, num_args, XlcGetMask);
}

static XOMMethodsRec methods = {
    close_om,
    set_om_values,
    get_om_values,
    create_oc
};

static XlcResource om_resources[] = {
    { XNRequiredCharSet, NULLQUARK, sizeof(XOMCharSetList),
      XOffsetOf(XOMRec, core.required_charset), XlcGetMask },
    { XNQueryOrientation, NULLQUARK, sizeof(XOMOrientation),
      XOffsetOf(XOMRec, core.orientation_list), XlcGetMask }
};

static XOM
create_om(lcd, dpy, rdb, res_name, res_class)
    XLCd lcd;
    Display *dpy;
    XrmDatabase rdb;
    char *res_name;
    char *res_class;
{
    XOM om;

    om = (XOM) Xmalloc(sizeof(XOMGenericRec));
    if (om == NULL)
	return (XOM) NULL;
    bzero((char *) om, sizeof(XOMGenericRec));
    
    om->methods = &methods;
    om->core.lcd = lcd;
    om->core.display = dpy;
    om->core.rdb = rdb;
    if (res_name) {
	om->core.res_name = (char *) Xmalloc(strlen(res_name) + 1);
	if (om->core.res_name == NULL)
	    goto err;
	strcpy(om->core.res_name, res_name);
    }
    if (res_class) {
	om->core.res_class = (char *) Xmalloc(strlen(res_class) + 1);
	if (om->core.res_class == NULL)
	    goto err;
	strcpy(om->core.res_class, res_class);
    }

    if (om_resources[0].xrm_name == NULLQUARK)
	_XlcCompileResourceList(om_resources, XlcNumber(om_resources));
    
    om->core.resources = om_resources;
    om->core.num_resources = XlcNumber(om_resources);

    return om;

err:
    close_om(om);

    return (XOM) NULL;
}

static OMData
add_data(om)
    XOM om;
{
    XOMGenericPart *gen = XOM_GENERIC(om);
    OMData new;
    int num;

    if (num = gen->data_num)
        new = (OMData) Xrealloc(gen->data, (num + 1) * sizeof(OMDataRec));
    else
        new = (OMData) Xmalloc(sizeof(OMDataRec));

    if (new == NULL)
        return NULL;

    gen->data_num = num + 1;
    gen->data = new;

    new += num;
    bzero((char *) new, sizeof(OMDataRec));

    return new;
}

static Bool
init_om(om)
    XOM om;
{
    XLCd lcd = om->core.lcd;
    XOMGenericPart *gen = XOM_GENERIC(om);
    OMData data;
    XlcCharSet *charset_list;
    FontData font_data;
    char **required_list;
    XOrientation *orientation;
    char **value, buf[BUFSIZ], *bufptr;
    int count, num, length = 0;

    _XlcGetResource(lcd, "XLC_FONTSET", "on_demand_loading", &value, &count);
    if (count > 0 && _XlcCompareISOLatin1(*value, "True") == 0)
	gen->on_demand_loading = True;

    _XlcGetResource(lcd, "XLC_FONTSET", "object_name", &value, &count);
    if (count > 0) {
	gen->object_name = (char *) Xmalloc(strlen(*value) + 1);
	if (gen->object_name == NULL)
	    return False;
	strcpy(gen->object_name, *value);
    }

    for (num = 0; ; num++) {
	sprintf(buf, "fs%d.charset", num);
	_XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
	if (count < 1)
	    break;

	data = add_data(om);
	if (data == NULL)
	    return False;
	
	charset_list = (XlcCharSet *) Xmalloc(sizeof(XlcCharSet) * count);
	if (charset_list == NULL)
	    return False;
	data->charset_list = charset_list;
	data->charset_count = count;

	while (count-- > 0)
	    *charset_list++ = _XlcGetCharSet(*value++);

	sprintf(buf, "fs%d.font", num);
	_XlcGetResource(lcd, "XLC_FONTSET", buf, &value, &count);
	if (count < 1)
	    return False;

	font_data = (FontData) Xmalloc(sizeof(FontDataRec) * count);
	if (font_data == NULL)
	    return False;
	bzero((char *) font_data, sizeof(FontDataRec) * count);
	data->font_data = font_data;
	data->font_data_count = count;

	for ( ; count-- > 0; font_data++) {
	    strcpy(buf, *value++);
	    if (bufptr = strrchr(buf, ':'))
		*bufptr++ = '\0';
	    font_data->name = (char *) Xmalloc(strlen(buf) + 1);
	    if (font_data->name == NULL)
		return False;
	    strcpy(font_data->name, buf);
	    if (bufptr && _XlcCompareISOLatin1(bufptr, "GL") == 0)
		font_data->side = XlcGL;
	    else if (bufptr && _XlcCompareISOLatin1(bufptr, "GR") == 0)
		font_data->side = XlcGR;
	    else
		font_data->side = XlcGLGR;
	}

	length += strlen(data->font_data->name) + 1;
    }

    /* required charset list */
    required_list = (char **) Xmalloc(sizeof(char *) * gen->data_num);
    if (required_list == NULL)
	return False;

    bufptr = (char *) Xmalloc(length);
    if (bufptr == NULL) {
	Xfree(required_list);
	return False;
    }

    om->core.required_charset.charset_list = required_list;
    om->core.required_charset.charset_count = gen->data_num;

    count = gen->data_num;
    data = gen->data;

    for ( ; count-- > 0; data++) {
	strcpy(bufptr, data->font_data->name);
	*required_list++ = bufptr;
	bufptr += strlen(bufptr) + 1;
    }

    /* orientation list */
    orientation = (XOrientation *) Xmalloc(sizeof(XOrientation));
    if (orientation == NULL)
	return False;

    *orientation = XOMOrientation_LTR_TTB;
    om->core.orientation_list.orient = orientation;
    om->core.orientation_list.num_orient = 1;

    return True;
}

XOM
#if NeedFunctionPrototypes
_XomGenericOpenOM(XLCd lcd, Display *dpy, XrmDatabase rdb,
		  _Xconst char *res_name, _Xconst char *res_class)
#else
_XomGenericOpenOM(lcd, dpy, rdb, res_name, res_class)
    XLCd lcd;
    Display *dpy;
    XrmDatabase rdb;
    char *res_name;
    char *res_class;
#endif
{
    XOM om;

    om = create_om(lcd, dpy, rdb, res_name, res_class);
    if (om == NULL)
	return (XOM) NULL;
    
    if (init_om(om) == False)
	goto err;

    return om;

err:
    close_om(om);

    return (XOM) NULL;
}

Bool
_XInitOM(lcd)
    XLCd lcd;
{
    lcd->methods->open_om = _XomGenericOpenOM;

    return True;
}
