/**
 *
 * $Id: ResConvert.c,v 1.54 1999/11/11 13:43:23 rwscott Exp $
 *
 * Copyright (C) 1995 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/

static const char rcsid[] = "$Id: ResConvert.c,v 1.54 1999/11/11 13:43:23 rwscott Exp $";

#include <LTconfig.h>

#include <stdio.h>
#include <stdlib.h>
#if STDC_HEADERS
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <ctype.h>

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include <XmI/XmI.h>
#include <Xm/XmP.h>
#include <Xm/AtomMgr.h>
#include <Xm/RepType.h>
#include <Xm/BulletinBP.h>
#include <Xm/MenuShellP.h>
#include <Xm/VendorSEP.h>
#include <Xm/ExtObjectP.h>
#include <Xm/XmosP.h>
#include <X11/Xfuncs.h>

#include <XmI/DebugUtil.h>

#include "LTmisc.h"

#ifndef XmUNSPECIFIED
#define XmUNSPECIFIED (~0)
#endif

enum
{
    ST_ATOM_LIST, ST_BUTTON_TYPE, ST_KEY_SYM_TABLE, ST_STRING_TABLE,
    ST_XM_STRING_TABLE
};

static Boolean _XmCvtStringToXmString(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToXmFontList(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToCardinal(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToKeySym(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToResIndPosition(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToResIndDimension(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToResIndInt(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToWidget(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToWindow(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToBooleanDimension(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToChar(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToTextPosition(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToTopItemPosition(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);
static Boolean _XmCvtStringToSomeTable(Display *, XrmValue *,
		   Cardinal *, XrmValue *, XrmValue *, XtPointer *);

static void destroy_font_list(XtAppContext app, XrmValue *to,
			      XtPointer converer_data, XrmValue *args,
			      Cardinal *num_args);
static void destroy_table(XtAppContext app, XrmValue *to,
			  XtPointer converer_data, XrmValue *args,
			  Cardinal *num_args);
static void destroy_string_table(XtAppContext app, XrmValue *to,
				 XtPointer converer_data, XrmValue *args,
				 Cardinal *num_args);
static void destroy_xm_string_table(XtAppContext app, XrmValue *to,
				    XtPointer converer_data, XrmValue *args,
				    Cardinal *num_args);
static void get_unit_type(Widget w, Cardinal *size, XrmValue *val);

#if XmVERSION > 1
static Boolean _XmCvtStringToTabList(Display *display, XrmValue *args,
		       Cardinal *num_args, XrmValue *from, XrmValue *to,
		       XtPointer *converter_data);
static Boolean _XmCvtStringToRenderTable(Display *display, XrmValue *args,
		       Cardinal *num_args, XrmValue *from, XrmValue *to,
		       XtPointer *converter_data);
#endif

int	xmUseVersion = 0;

/* please be careful if you're editting these arrays, as
 * the strings have to be in the _same_ order as the
 * enumerated constants in the include files.  Failure to comply
 * will bring about the death of your firstborn.  Have
 * a nice day.
 */

static char *multi_click[] =
{
    "multiclick_discard",
    "multiclick_keep"
};

static char *packing_styles[] =
{
    "no_packing",
    "pack_tight",
    "pack_column",
    "pack_none"
};

static char *focus_policies[] =
{
    "explicit",
    "pointer"
};

static char *label_types[] =
{
    "pixmap",
    "string"
};
static unsigned char label_type_values[] =
{
    XmPIXMAP,
    XmSTRING
};

static char *vertical_alignments[] =
{
    "alignment_baseline_top",
    "alignment_center",
    "alignment_baseline_bottom",
    "alignment_contents_top",
    "alignment_contents_bottom"
};

static char *child_vertical_alignments[] =
{
    "alignment_baseline_top",
    "alignment_center",
    "alignment_baseline_bottom",
    "alignment_widget_top",
    "alignment_widget_bottom"
};

static char *horizontal_alignments[] =
{
    "alignment_beginning",
    "alignment_center",
    "alignment_end"
};

static char *arrow_directions[] =
{
    "arrow_up",
    "arrow_down",
    "arrow_left",
    "arrow_right"
};

static char *attachments[] =
{
    "attach_none",
    "attach_form",
    "attach_opposite_form",
    "attach_widget",
    "attach_opposite_widget",
    "attach_position",
    "attach_self"
};

static char *audible_warnings[] =
{
    "none",
    "bell"
};

static char *frame_child_types[] =
{
    "frame_generic_child",
    "frame_workarea_child",
    "frame_title_child"
};

static char *delete_responses[] =
{
    "destroy",
    "unmap",
    "do_nothing"
};

static char *navigation_types[] =
{
    "none",
    "tab_group",
    "sticky_tab_group",
    "exclusive_tab_group"
};

static char *orientations[] =
{
    "vertical",
    "horizontal",
};
static unsigned char orientation_values[] =
{
    XmVERTICAL,
    XmHORIZONTAL
};

static char *protocol_styles[] =
{
    "drag_none",
    "drag_drop_only",
    "drag_prefer_preregister",
    "drag_preregister",
    "drag_prefer_dynamic",
    "drag_dynamic",
    "drag_prefer_receiver"
};

static char *scrollbar_placement[] =
{
    "bottom_right",
    "top_right",
    "bottom_left",
    "top_left"
};

static char *scrolling_policy[] =
{
    "automatic",
    "application_defined"
};

static char *scrollbar_policy[] =
{
    "static",
    "as_needed"
};

static char *edit_mode[] =
{
    "multi_line_edit",
    "single_line_edit"
};

static char *unit_types[] =
{
    "pixels",
    "100th_millimeters",
    "1000th_inches",
    "100th_points",
    "100th_font_units"
};

static char *dialog_types[] =
{
    "dialog_template",
    "dialog_error",
    "dialog_information",
    "dialog_message",
    "dialog_question",
    "dialog_warning",
    "dialog_working"
};

static char *dialog_styles[] =
{
    "dialog_modeless",
    "dialog_primary_application_modal",
    "dialog_full_application_modal",
    "dialog_system_modal"
};

static char *shadow_types[] =
{
    "shadow_in",
    "shadow_out",
    "shadow_etched_in",
    "shadow_etched_out"
};
static unsigned char shadow_type_values[] =
{
    XmSHADOW_IN,
    XmSHADOW_OUT,
    XmSHADOW_ETCHED_IN,
    XmSHADOW_ETCHED_OUT
};

static char *separator_types[] =
{
    "no_line",
    "single_line",
    "double_line",
    "single_dashed_line",
    "double_dashed_line",
    "shadow_etched_in",
    "shadow_etched_out",
    "shadow_etched_in_dash",
    "shadow_etched_out_dash"
};

static char *row_column_types[] =
{
    "work_area",
    "menu_bar",
    "menu_pulldown",
    "menu_popup",
    "menu_option"
};

static unsigned char row_column_type_values[] =
{
    XmWORK_AREA,
    XmMENU_BAR,
    XmMENU_PULLDOWN,
    XmMENU_POPUP,
    XmMENU_OPTION
};

static char *indicator_types[] =
{
    "n_of_many",
    "one_of_many",
#if XmVERSION > 1
    "one_of_many_round",
    "one_of_many_diamond"
#endif
};

static unsigned char indicator_type_values[] =
{
    XmN_OF_MANY,
    XmONE_OF_MANY,
#if XmVERSION > 1
    XmONE_OF_MANY_ROUND,
    XmONE_OF_MANY_DIAMOND
#endif
};

static char *resize_policies[] =
{
    "resize_none",
    "resize_grow",
    "resize_any"
};

static char *extension_types[] =
{
    "cache_extension",
    "desktop_extension",
    "shell_extension",
    "protocol_extension",
    "default_extension"
};

static unsigned char extension_type_values[] =
{
    XmCACHE_EXTENSION,
    XmDESKTOP_EXTENSION,
    XmSHELL_EXTENSION,
    XmPROTOCOL_EXTENSION,
    XmDEFAULT_EXTENSION
};

static char *icon_attachments[] =
{
    "attach_north_west",
    "attach_north",
    "attach_north_east",
    "attach_east",
    "attach_south_east",
    "attach_south",
    "attach_south_west",
    "attach_west",
    "attach_center",
    "attach_hot"
};

static char *transfer_statuses[] =
{
    "transfer_failure",
    "transfer_success"
};

static char *file_types[] =
{
    "file_directory",
    "file_regular",
    "file_any_type"
};
static unsigned char file_type_values[] =
{
    XmFILE_DIRECTORY,
    XmFILE_REGULAR,
    XmFILE_ANY_TYPE
};

static char *string_directions[] =
{
    "string_direction_l_to_r",
    "string_direction_r_to_l"
};

static char *command_locations[] =
{
    "command_above_workspace",
    "command_below_workspace"
};

static char *default_button_types[] =
{
    "dialog_none",
    "dialog_cancel_button",
    "dialog_ok_button",
    "dialog_help_button"
};
static unsigned char default_button_type_values[] =
{
    XmDIALOG_NONE,
    XmDIALOG_CANCEL_BUTTON,
    XmDIALOG_OK_BUTTON,
    XmDIALOG_HELP_BUTTON
};

static char *processing_directions[] =
{
    "max_on_top",
    "max_on_bottom",
    "max_on_left",
    "max_on_right"
};

static char *unpost_behaviours[] =
{
    "unpost",
    "unpost_and_replay"
};

static char *visual_policies[] =
{
    "variable",
    "constant"
};

static char *child_placements[] =
{
    "place_top",
    "place_above_selection",
    "place_below_selection"
};

static char *selection_policies[] =
{
    "single_select",
    "multiple_select",
    "extended_select",
    "browse_select"
};

static char *list_size_policies[] =
{
    "variable",
    "constant",
    "resize_if_possible"
};

static XtConvertArgRec parentArgs[] = {
	{	XtBaseOffset,
		(XtPointer)XtOffsetOf(WidgetRec, core.parent),
		sizeof(Widget) }
};

#if XmVERSION > 1
static char *toggle_mode[] =
{
    "toggle_boolean",
    "toggle_indeterminate"
};

/* Spinbox */
static char *spb_child_types[] =
{
    "numeric",
    "string"
};

static unsigned char spb_child_type_values[] =
{
    XmNUMERIC,
    XmSTRING
};

static char *spb_arrow_layouts[] =
{
    "arrows_beginning",
    "arrows_end",
    "arrows_split"
};

static unsigned char spb_arrow_layout_values[] =
{
    XmARROWS_BEGINNING,
    XmARROWS_END,
    XmARROWS_SPLIT
};

#if XmVERSION > 1
/* Notebook */
static char *nb_child_types[] =
{
    "none",
    "page",
    "major_tab",
    "minor_tab",
    "status_area",
    "page_scroller"
};

static unsigned char nb_child_type_values[] =
{
    XmNONE,
    XmPAGE,
    XmMAJOR_TAB,
    XmMINOR_TAB,
    XmSTATUS_AREA, 
    XmPAGE_SCROLLER
};
#endif

static char *indicator_on[] =
{
    "indicator_none",
    "indicator_fill",
    "indicator_check",
    "indicator_check_box",
    "indicator_cross",
    "indicator_cross_box",
    "false",			/* Support 1.2 compatible defaults */
    "true",			/* Support 1.2 compatible defaults */
    "off",			/* Boolean compatible values */
    "on",
    "0",
    "1",
    "no",
    "yes",
};

static unsigned char indicator_on_values[] =
{
    XmINDICATOR_NONE,
    XmINDICATOR_FILL,
    XmINDICATOR_CHECK,
    XmINDICATOR_CHECK_BOX,
    XmINDICATOR_CROSS,
    XmINDICATOR_CROSS_BOX,
    XmINDICATOR_NONE,		/* False */
    XmINDICATOR_FILL,		/* True */
    XmINDICATOR_NONE,		/* Off */
    XmINDICATOR_FILL,		/* On */
    XmINDICATOR_NONE,		/* 0 */
    XmINDICATOR_FILL,		/* 1 */
    XmINDICATOR_NONE,		/* no */
    XmINDICATOR_FILL,		/* yes */
};

#endif

void
XmRegisterConverters(void)
{
    /* don't really know the difference between the two, so
       we'll just call the other from here for now. */

    _XmRegisterConverters();
}

void
_XmRegisterConverters(void)
{
    static Boolean first = True;
    static XtConvertArgRec immediate_arg = {XtImmediate, 0, sizeof(XtPointer)};
    static XtConvertArgRec horizontal_args[] = {
	{
	    XtWidgetBaseOffset,
	    (XtPointer)XtOffset(Widget, core.screen),
	    sizeof(Screen *)
	},
	{
	    XtImmediate,
	    (XtPointer)XmHORIZONTAL,
	    sizeof(XtPointer)
	},
	{
	    XtProcedureArg,
	    (XtPointer)get_unit_type,
	    0
	}};
    static XtConvertArgRec vertical_args[] = {
	{
	    XtWidgetBaseOffset,
	    (XtPointer)XtOffset(Widget, core.screen),
	    sizeof(Screen *)
	},
	{
	    XtImmediate,
	    (XtPointer)XmVERTICAL,
	    sizeof(XtPointer)
	},
	{
	    XtProcedureArg,
	    (XtPointer)get_unit_type,
	    0
	}};

#ifdef NONSTANDARD_CONVERTERS
    extern void _XmRegisterNSEConverters(void);
#endif

    if (first)
    {
	first = False;
    }
    else
    {
	return;
    }

    /*
       xmUseVersion is used for a santity check by developers.  It is used within
       a M*tif applications to ensure the version of the (shared) M*tif library
       being used corresponds to the M*tif toolkit header the application was
       compiled against.  8/3/98, pgw@ma.ultranet.com
     */
    xmUseVersion = XmVersion;

#define REPTYPE_REGISTER(reptype,array) \
    XmRepTypeRegister((reptype), \
                     (array), \
                     NULL, XtNumber((array)));
#define REPTYPE_REGISTER_WITH_VALUES(reptype,array,values) \
    XmRepTypeRegister((reptype), \
                     (array), \
                     (values), XtNumber((array)));

    REPTYPE_REGISTER(XmRMultiClick, multi_click);
    REPTYPE_REGISTER(XmRPacking, packing_styles);
    REPTYPE_REGISTER(XmRKeyboardFocusPolicy, focus_policies);
    REPTYPE_REGISTER(XmRVerticalAlignment, vertical_alignments);
    REPTYPE_REGISTER(XmRChildVerticalAlignment, child_vertical_alignments);
    REPTYPE_REGISTER(XmRAlignment, horizontal_alignments);
    REPTYPE_REGISTER(XmRChildHorizontalAlignment, horizontal_alignments);
    REPTYPE_REGISTER(XmRArrowDirection, arrow_directions);
    REPTYPE_REGISTER(XmRAttachment, attachments);
    REPTYPE_REGISTER(XmRAudibleWarning, audible_warnings);
    REPTYPE_REGISTER(XmRChildType, frame_child_types);
    REPTYPE_REGISTER(XmRDeleteResponse, delete_responses);
    REPTYPE_REGISTER(XmRNavigationType, navigation_types);
    REPTYPE_REGISTER(XmRScrollBarPlacement, scrollbar_placement);
    REPTYPE_REGISTER(XmRScrollingPolicy, scrolling_policy);
    REPTYPE_REGISTER(XmRScrollBarDisplayPolicy, scrollbar_policy);
    REPTYPE_REGISTER(XmREditMode, edit_mode);
    REPTYPE_REGISTER(XmRDragInitiatorProtocolStyle, protocol_styles);
    REPTYPE_REGISTER(XmRDragReceiverProtocolStyle, protocol_styles);
    REPTYPE_REGISTER(XmRUnitType, unit_types);
    REPTYPE_REGISTER(XmRDialogType, dialog_types);
    REPTYPE_REGISTER(XmRSelectionType, dialog_types);
    REPTYPE_REGISTER(XmRDialogStyle, dialog_styles);
    REPTYPE_REGISTER(XmRSeparatorType, separator_types);
    REPTYPE_REGISTER(XmRResizePolicy, resize_policies);
    REPTYPE_REGISTER(XmRIconAttachment, icon_attachments);
    REPTYPE_REGISTER(XmRTransferStatus, transfer_statuses);
    REPTYPE_REGISTER(XmRStringDirection, string_directions);
    REPTYPE_REGISTER(XmRCommandWindowLocation, command_locations);
    REPTYPE_REGISTER(XmRProcessingDirection, processing_directions);
    REPTYPE_REGISTER(XmRUnpostBehavior, unpost_behaviours);
    REPTYPE_REGISTER(XmRVisualPolicy, visual_policies);
    REPTYPE_REGISTER(XmRChildPlacement, child_placements);
    REPTYPE_REGISTER(XmRSelectionPolicy, selection_policies);
    REPTYPE_REGISTER(XmRListSizePolicy, list_size_policies);

    REPTYPE_REGISTER_WITH_VALUES(XmRLabelType, label_types, label_type_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRShadowType, shadow_types,
				 shadow_type_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRRowColumnType, row_column_types,
				 row_column_type_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRExtensionType, extension_types,
				 extension_type_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRFileTypeMask, file_types,
				 file_type_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRDefaultButtonType, default_button_types,
				 default_button_type_values);
    REPTYPE_REGISTER_WITH_VALUES(XmROrientation, orientations,
				 orientation_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRIndicatorType, indicator_types,
                                indicator_type_values);

#if XmVERSION > 1
/* Motif 2.0 */
    REPTYPE_REGISTER(XmRToggleMode, toggle_mode);
    REPTYPE_REGISTER_WITH_VALUES(XmRArrowLayout,
                spb_arrow_layouts, spb_arrow_layout_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRSpinBoxChildType,
                spb_child_types, spb_child_type_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRIndicatorOn,
                indicator_on, indicator_on_values);
    REPTYPE_REGISTER_WITH_VALUES(XmRNotebookChildType,
                nb_child_types, nb_child_type_values);
#endif

#undef REPTYPE_REGISTER
#undef REPTYPE_REGISTER_WITH_VALUES

    /* now we install the other toolkit converters */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRXmString,	/* target type */
		       _XmCvtStringToXmString,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheAll,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRFontList,	/* target type */
		       _XmCvtStringToXmFontList,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheByDisplay,	/* caching instructions */
		       destroy_font_list);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRHorizontalDimension,	/* target type */
		       _XmCvtStringToResIndDimension,	/* converter routine */
		       horizontal_args,	/* args for converter routine */
		       XtNumber(horizontal_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRShellHorizDim,	/* target type */
		       _XmCvtStringToResIndDimension,	/* converter routine */
		       horizontal_args,	/* args for converter routine */
		       XtNumber(horizontal_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRHorizontalInt,	/* target type */
		       _XmCvtStringToResIndInt,	/* converter routine */
		       horizontal_args,	/* args for converter routine */
		       XtNumber(horizontal_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRHorizontalPosition,	/* target type */
		       _XmCvtStringToResIndPosition, /* converter routine */
		       horizontal_args,	/* args for converter routine */
		       XtNumber(horizontal_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRShellHorizPos,	/* target type */
		       _XmCvtStringToResIndPosition, /* converter routine */
		       horizontal_args,	/* args for converter routine */
		       XtNumber(horizontal_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRShellVertPos,	/* target type */
		       _XmCvtStringToResIndPosition,	/* converter routine */
		       vertical_args,	/* args for converter routine */
		       XtNumber(vertical_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRVerticalPosition,	/* target type */
		       _XmCvtStringToResIndPosition,	/* converter routine */
		       vertical_args,	/* args for converter routine */
		       XtNumber(vertical_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRShellVertDim,		/* target type */
		       _XmCvtStringToResIndDimension,		/* converter routine */
		       vertical_args,	/* args for converter routine */
		       XtNumber(vertical_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRVerticalDimension,	/* target type */
		       _XmCvtStringToResIndDimension,		/* converter routine */
		       vertical_args,	/* args for converter routine */
		       XtNumber(vertical_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRVerticalInt,	/* target type */
		       _XmCvtStringToResIndInt,	/* converter routine */
		       vertical_args,	/* args for converter routine */
		       XtNumber(vertical_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRKeySym,	/* target type */
		       _XmCvtStringToKeySym,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheAll,	/* caching instructions */
		       NULL);	/* destructor function */

#if 0
    XtSetTypeConverter(XtRString,	/* source type */
		       XmRNavigation,	/* target type */
		       _XmCvtStringToXmNavigation,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */
#endif

    immediate_arg.address_id = (XtPointer)ST_ATOM_LIST;
    XtSetTypeConverter(XtRString,	/* source type */
		       XmRAtomList,	/* target type */
		       _XmCvtStringToSomeTable,	/* converter routine */
		       &immediate_arg,	/* args for converter routine */
		       1,	/* number of args to converter routine */
		       XtCacheNone | XtCacheRefCount,	/* caching instructions */
		       destroy_table);	/* destructor function */

    immediate_arg.address_id = (XtPointer)ST_BUTTON_TYPE;
    XtSetTypeConverter(XtRString,	/* source type */
		       XmRButtonType,	/* target type */
		       _XmCvtStringToSomeTable,	/* converter routine */
		       &immediate_arg,	/* args for converter routine */
		       1,	/* number of args to converter routine */
		       XtCacheNone | XtCacheRefCount,	/* caching instructions */
		       destroy_table);	/* destructor function */

    immediate_arg.address_id = (XtPointer)ST_STRING_TABLE;
    XtSetTypeConverter(XtRString,	/* source type */
		       XmRCharSetTable,	/* target type */
		       _XmCvtStringToSomeTable,	/* converter routine */
		       &immediate_arg,	/* args for converter routine */
		       1,	/* number of args to converter routine */
		       XtCacheNone | XtCacheRefCount,	/* caching instructions */
		       destroy_string_table);	/* destructor function */

    immediate_arg.address_id = (XtPointer)ST_KEY_SYM_TABLE;
    XtSetTypeConverter(XtRString,	/* source type */
		       XmRKeySymTable,	/* target type */
		       _XmCvtStringToSomeTable,	/* converter routine */
		       &immediate_arg,	/* args for converter routine */
		       1,	/* number of args to converter routine */
		       XtCacheNone | XtCacheRefCount,	/* caching instructions */
		       destroy_table);	/* destructor function */

    immediate_arg.address_id = (XtPointer)ST_STRING_TABLE;
    XtSetTypeConverter(XtRString,	/* source type */
		       XmRStringTable,	/* target type */
		       _XmCvtStringToSomeTable,	/* converter routine */
		       &immediate_arg,	/* args for converter routine */
		       1,	/* number of args to converter routine */
		       XtCacheNone | XtCacheRefCount,	/* caching instructions */
		       destroy_string_table);	/* destructor function */

    immediate_arg.address_id = (XtPointer)ST_XM_STRING_TABLE;
    XtSetTypeConverter(XtRString,	/* source type */
		       XmRXmStringTable,	/* target type */
		       _XmCvtStringToSomeTable,	/* converter routine */
		       &immediate_arg,	/* args for converter routine */
		       1,	/* number of args to converter routine */
		       XtCacheNone | XtCacheRefCount,	/* caching instructions */
		       destroy_xm_string_table);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRWidget,	/* target type */
		       _XmCvtStringToWidget,	/* converter routine */
		       parentArgs,	/* args for converter routine */
		       XtNumber(parentArgs),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRWindow,	/* target type */
		       _XmCvtStringToWindow,	/* converter routine */
		       parentArgs,	/* args for converter routine */
		       XtNumber(parentArgs),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRCardinal,	/* target type */
		       _XmCvtStringToCardinal,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRBooleanDimension,	/* target type */
		       _XmCvtStringToBooleanDimension,	/* converter routine */
		       horizontal_args,	/* args for converter routine */
		       XtNumber(horizontal_args),	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRChar,	/* target type */
		       _XmCvtStringToChar,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRTextPosition,	/* target type */
		       _XmCvtStringToTextPosition,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRTopItemPosition,	/* target type */
		       _XmCvtStringToTopItemPosition,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */
#if XmVERSION > 1
    XtSetTypeConverter(XtRString,	/* source type */
		       XmRTabList,	/* target type */
		       _XmCvtStringToTabList,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRRenderTable,	/* target type */
		       _XmCvtStringToRenderTable,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheNone,	/* caching instructions */
		       NULL);	/* destructor function */
#endif

#ifdef NONSTANDARD_CONVERTERS
    _XmRegisterNSEConverters();
#endif
}

/*
 * error convenience
 */
void
#if STDC_HEADERS
_XmError(Widget w, char *fmt,...)
{
    va_list arg_list;
    char buf[256];

    va_start(arg_list, fmt);
#else
_XmError(w, fmt, va_alist)
     Widget w;
     char *fmt;
     va_dcl
{
    char buf[256];
    va_list arg_list;

    va_start(arg_list);
#endif
    if (w)
    {
	vsprintf(buf, fmt, arg_list);
	va_end(arg_list);

	XtAppError(XtWidgetToApplicationContext(w), buf);
    }
    else
    {
	vsprintf(buf, fmt, arg_list);
	va_end(arg_list);

	XtError(buf);
    }
}

/*
 * Warning convenience
 *
 * Added XdbDebug stuff here to be able to avoid infinite loops in applications
 * that redirect stderr to a scrolledText. ML suffers from this, due to LessTif
 * bugs of cource :-(
 */
void
#if STDC_HEADERS
_XmWarning(Widget w, char *fmt,...)
{
    va_list arg_list;
    char buf[256];

    va_start(arg_list, fmt);
#else
_XmWarning(Widget w, fmt, va_list)
     Widget w;
     char *fmt;
     va_dcl
{
    char buf[256];

    va_start(arg_list);
#endif
    if (w)
    {
	sprintf(buf, "\n    Name: %s\n    Class: %s\n    ",
		XtName(w), XtClass(w)->core_class.class_name);

	vsprintf(buf + strlen(buf), fmt, arg_list);
	va_end(arg_list);

	strcat(buf, "\n");

#ifdef	LESSTIF_PRODUCTION
	XtAppWarning(XtWidgetToApplicationContext(w), buf);
#else
	if (getenv("DEBUG_REDIRECT_XMWARNING"))
	{
	    XdbPrintString(buf);
	}
	else
	{
	    XtAppWarning(XtWidgetToApplicationContext(w), buf);
	}
#endif
    }
    else
    {
	buf[0] = '\0';
	vsprintf(buf + strlen(buf), fmt, arg_list);
	va_end(arg_list);

#ifdef	LESSTIF_PRODUCTION
	XtWarning(buf);
#else
	if (getenv("DEBUG_REDIRECT_XMWARNING"))
	{
	    XdbPrintString(buf);
	}
	else
	{
	    XtWarning(buf);
	}
#endif
    }
}

char *
XmRegisterSegmentEncoding(char *fontlist_tag, char *ct_encoding)
{
    return NULL;
}

char *
XmMapSegmentEncoding(char *fontlist_tag)
{
    return NULL;
}

XmString
XmCvtCTToXmString(char *text)
{
    return XmStringCreate(text, XmFONTLIST_DEFAULT_TAG);
}

Boolean
XmCvtTextToXmString(Display *display, XrmValuePtr args,
		    Cardinal *num_args, XrmValue *from_val, XrmValue *to_val,
		    XtPointer *converter_data)
{
    return False;
}

char *
XmCvtXmStringToCT(XmString string)
{
    char *text = (char *)NULL;
    XmStringContext context = NULL;
    char *pbuf = (char *)NULL, *pstr;
    XmStringCharSet tag;
    XmStringDirection direction;
    Boolean separator;

    DEBUGOUT(XdbDebug(__FILE__, NULL, "XmCvtXmStringToCT\n"));

    if (XmStringInitContext(&context, string) == True)
    {
	while (XmStringGetNextSegment(context,
				      &text,
				      &tag,
				      &direction,
				      &separator) == True)
	{
	    if (pbuf == NULL)
	    {
		/* allocate space for the buffer and init it */
		pbuf = XtMalloc(strlen(text) + 2);
		*pbuf = '\0';
	    }
	    else
	    {
		/* allocate more space for the buffer */
		pbuf = XtRealloc(pbuf, sizeof(pbuf) + strlen(text) + 2);
	    }

	    /* reset the pointer pstr to point back at pbuf */
	    pstr = pbuf;

	    pstr += (strlen(strcat(pstr, text)));
	    if (separator == True)
	    {			/* add newline */
		*pstr++ = '\n';
		*pstr = '\0';
	    }

	    /* free the text segment we just grabbed */
	    XtFree(text);
	}
	text = pbuf;
    }

    return text;
}

Boolean
XmCvtXmStringToText(Display *display, XrmValuePtr args,
		    Cardinal *num_args, XrmValue *from_val, XrmValue *to_val,
		    XtPointer *converter_data)
{
    char *value = XtNewString("");
    XmString m = (XmString)from_val->addr;
    XmStringContext c;
    XmStringComponentType t = XmSTRING_COMPONENT_UNKNOWN;

    if (*num_args != 0)
    {
	XtWarningMsg("wrongParameters", "XmCvtXmStringToText",
		     "XtToolkitError",
		     "XmString to String conversion needs no extra arguments",
		     (String *)NULL, (Cardinal *)NULL);
    }

    XmStringInitContext(&c, m);

    while (t != XmSTRING_COMPONENT_END)
    {
	char *s_text            = NULL;
	XmStringCharSet s_cs    = NULL;
	XmStringDirection d     = XmSTRING_DIRECTION_DEFAULT;
	XmStringComponentType u = XmSTRING_COMPONENT_UNKNOWN;
	unsigned short ul       = 0;
	unsigned char *s_uv     = NULL;
	char *text              = NULL;

	t = XmStringGetNextComponent(c, &s_text, &s_cs, &d, &u, &ul, &s_uv);

	switch (t)
	{
	case XmSTRING_COMPONENT_TEXT:
	case XmSTRING_COMPONENT_LOCALE_TEXT:
	    text = s_text;
	    break;

	case XmSTRING_COMPONENT_SEPARATOR:
	    text = "\n";
	    break;

	default:
	    /* Unknown component */
	    text = NULL;
	    break;
	}

	if (text != NULL)
	{
	    value = XtRealloc(value, strlen(value) + strlen(text) + 1);
	    strcat(value, text);
	}

	XtFree(s_text);
	XtFree(s_cs);
	XtFree((char *)s_uv);
    }

    to_val->addr = value;
    to_val->size = strlen(value);  /* FIXME: should this be sizeof(value)? */

    DEBUGOUT(XdbDebug(__FILE__, NULL,
		      "XmCvtXmStringToText(%p) => %s\n",
		      from_val->addr, to_val->addr));

    return True;
}

/*
 * Compare two strings to see if they're equivalent. This one is used
 * whenever comparing motif constants with resource string values. The
 * motif constants must have the Xm prefix stripped off and must be
 * in lower case.
 */
Boolean
_XmStringsAreEqual(char *in_str,
		   char *text_str)
{
    if (in_str[0] && (tolower(in_str[0]) == 'x') &&
	in_str[1] && (tolower(in_str[1]) == 'm'))
    {
	in_str += 2;		/* skip the Xm prefix */
    }

    while (*in_str)
    {
	if (tolower(*in_str) != *text_str)
	    return False;
	in_str++;
	text_str++;
    }

    return *text_str ? False : True;
}

/*
 * Fixed this thing to make a COPY of the fontlist it returns.
 * Danny 16/4/1996
 */
XmFontList
_XmGetDefaultFontList(Widget w,
		      unsigned char fontListType)
{
    static XmFontList labelFontList = NULL;
    static XmFontList buttonFontList = NULL;
    static XmFontList textFontList = NULL;
    Widget par = w;
    XmFontList fontlist;
    XmVendorShellExtObject ve = NULL;

    fontlist = NULL;
    switch (fontListType)
    {
    case XmTEXT_FONTLIST:
	while ((par = XtParent(par)) != NULL)
	{
	    if (XmIsBulletinBoard(par) && BB_TextFontList(par) != NULL)
	    {
		fontlist = BB_TextFontList(par);
		break;
	    }
	    else if (XmIsVendorShell(par))
	    {
		/* Danny, I found out the hard way that this function can
		 * get called before the VSEP child is valid, but the context
		 * has been set.  It was with that UIL compiler you sent.
		 * Thus the next three ve checks have been converted.
		 * - MLM
		 */
		ve = (XmVendorShellExtObject)_LtFindVendorExt((Widget)par);
		if (ve && VSEP_TextFontList(ve) != NULL)
		{
		    fontlist = VSEP_TextFontList(ve);
		    break;
		}
	    }
	}
	if (fontlist)
	{
	    return XmFontListCopy(fontlist);
	}

	if (!textFontList)
	{
	    XmFontListEntry newEntry = XmFontListEntryLoad(XtDisplay(w),
							   XmDEFAULT_FONT,
							   XmFONT_IS_FONT,
						       XmFONTLIST_DEFAULT_TAG);
	    textFontList = XmFontListAppendEntry(NULL, newEntry);
	}

	if (textFontList == NULL) {
		_XmWarning(w, "_XmGetDefaultFontList: returning NULL\n");
	}

	return XmFontListCopy(textFontList);
	break;

    case XmBUTTON_FONTLIST:
	while ((par = XtParent(par)) != NULL)
	{
	    if (XmIsBulletinBoard(par) && BB_ButtonFontList(par) != NULL)
	    {
		fontlist = BB_ButtonFontList(par);
		break;
	    }
	    else if (XmIsMenuShell(par) && MS_ButtonFontList(par) != NULL)
	    {
		fontlist = MS_ButtonFontList(par);
		break;
	    }
	    else if (XmIsVendorShell(par))
	    {
		ve = (XmVendorShellExtObject)_LtFindVendorExt((Widget)par);
		if (ve && VSEP_ButtonFontList(ve) != NULL)
		{
		    fontlist = VSEP_ButtonFontList(ve);
		    break;
		}
	    }
	}
	if (fontlist)
	    return XmFontListCopy(fontlist);

	if (!buttonFontList)
	{
	    XmFontListEntry newEntry = XmFontListEntryLoad(XtDisplay(w),
							   XmDEFAULT_FONT,
							   XmFONT_IS_FONT,
						       XmFONTLIST_DEFAULT_TAG);
	    buttonFontList = XmFontListAppendEntry(NULL, newEntry);
	}

	if (buttonFontList == NULL) {
		_XmWarning(w, "_XmGetDefaultFontList: returning NULL\n");
	}

	return XmFontListCopy(buttonFontList);
	break;

    default:
    case XmLABEL_FONTLIST:
	while ((par = XtParent(par)) != NULL)
	{
	    if (XmIsBulletinBoard(par) && BB_LabelFontList(par) != NULL)
	    {
		fontlist = BB_LabelFontList(par);
		break;
	    }
	    else if (XmIsMenuShell(par) && MS_LabelFontList(par) != NULL)
	    {
		fontlist = MS_LabelFontList(par);
		break;
	    }
	    else if (XmIsVendorShell(par))
	    {
		ve = (XmVendorShellExtObject)_LtFindVendorExt((Widget)par);
		if (ve && VSEP_LabelFontList(ve) != NULL)
		{
		    fontlist = VSEP_LabelFontList(ve);
		    break;
		}
	    }
	}

	if (fontlist)
	{
	    return XmFontListCopy(fontlist);
	}

	if (!labelFontList)
	{
	    XmFontListEntry newEntry = XmFontListEntryLoad(XtDisplay(w),
							   XmDEFAULT_FONT,
							   XmFONT_IS_FONT,
						       XmFONTLIST_DEFAULT_TAG);
	    labelFontList = XmFontListAppendEntry(NULL, newEntry);
	}

	if (labelFontList == NULL) {
		_XmWarning(w, "_XmGetDefaultFontList: returning NULL\n");
	}

	return XmFontListCopy(labelFontList);

	break;
    }
}

/* resource converters, of various types */

char *
_XmConvertCSToString(XmString cs)
{
    return NULL;
}

Boolean
_XmCvtXmStringToCT(XrmValue *from,
		   XrmValue *to)
{
    return False;
}

/*
 * One to convert from String (char *) to XmString
 */
static Boolean
_XmCvtStringToXmString(Display *display,
		       XrmValue *args,
		       Cardinal *num_args,
		       XrmValue *from,
		       XrmValue *to,
		       XtPointer *converter_data)
{
    static XmString newString = NULL;

    if (*num_args != 0)
    {
	XtWarningMsg("wrongParameters", "cvtStringToXmString",
		     "XtToolkitError",
		     "String to XmString conversion needs no extra arguments",
		     (String *)NULL, (Cardinal *)NULL);
    }
    newString = XmStringCreateLtoR(from->addr, XmFONTLIST_DEFAULT_TAG);

    if (newString)
    {
	if (to->addr == NULL)
	{
	    to->addr = (XtPointer)&newString;
	    to->size = sizeof(XmString);
	}
	else
	{
	    if (to->size >= sizeof(XmString))
	    {
		*((XmString *)to->addr) = newString;
		to->size = sizeof(XmString);
	    }
	    else
	    {
		XtDisplayStringConversionWarning(display, (char *)from->addr,
						 XmRXmString);
	    }
	}
    }
    else
    {
	XtDisplayStringConversionWarning(display, (char *)from->addr,
					 XmRXmString);
    }

    DEBUGOUT(XdbDebug(__FILE__, NULL,
		      "_XmCvtStringToXmString(%s) => %p\n",
		      from->addr, to->addr));

    return True;
}

/*
 * This function is only used by the _XmCvtStringToXmFontlist resource
 * converter
 *
 * According to the docs, a font entry is :
 *      font_entry = font_name [ ";" font_name ]+ ":" [ tag ]
 *                 | font_name [ "=" tag ]
 *      font_name = XLFD font name
 *      tag = a string (no space, comma, colon, semicolon, equalsign)
 *
 * For a simple example, see test/Xm/international/test1.
 */
static XmFontList
__XmFontListResourceAddEntry(Display *display,
			     char *full_entry,
			     XmFontList oldFontList)
{
    XmFontList newFontList;
    char *eq, *end, *fn, *ft, *tag, *font, *semi, *colon;

    DEBUGOUT(XdbDebug(__FILE__, NULL,
		      "__XmFontListResourceAddEntry(%s)\n", full_entry));

    eq = strchr(full_entry, (int)'=');

    /* there was an equal sign, the left side is the font,
       and the right side the tag. */
    if (eq)
    {
	/* set the equal sign to a null so we can XtNewString the font */
	*eq = 0;
	fn = font = XtNewString(full_entry);

	/* set it back again, and XtNewString the tag */
	*eq = '=';
	ft = tag = XtNewString(eq + 1);

	end = font + strlen(font);
	while (isspace(*font) && font < end)
	{
	    font++;
	}
	while (isspace(*end) && end > font)
	{
	    end--;
	}

	if (end != font + strlen(font))
	{
	    end++;
	    *end = 0;
	}

	end = tag + strlen(tag);
	while (isspace(*tag) && tag < end)
	{
	    tag++;
	}
	while (isspace(*end) && end > tag)
	{
	    end--;
	}

	if (end != tag + strlen(tag))
	{
	    end++;
	    *end = 0;
	}

	newFontList = XmFontListAppendEntry(oldFontList,
					    XmFontListEntryLoad(display,
								font,
								XmFONT_IS_FONT,
								tag));

	XtFree(ft);
	XtFree(fn);

	return newFontList;
    }

    /* Now treat the case with no equal sign */
    semi = strchr(full_entry, ';');
    colon = strchr(full_entry, ':');

    if (semi || colon)
    {
	/* font_entry = font_name [ ";" font_name ]+ ":" [ tag ] */

	/* First find the tag if there is one */
	if (colon)
	{
	    tag = colon + 1;
	    while (tag && *tag != '\0' && isspace(*tag))
	    {
		tag++;
	    }
	    if (*tag == '\0')
	    {
		tag = XmFONTLIST_DEFAULT_TAG;
	    }
	}
	else
	{
	    tag = XmFONTLIST_DEFAULT_TAG;
	}

	while((semi = strchr(full_entry, ';')) != NULL)
	{
	    *semi = ',';
	}

	/* Find all the font names and process them */
	fn = font = XtNewString(full_entry);
	colon = strchr(fn, ':');

	if (colon)
	{
	    *colon = '\0';
	}
	newFontList = XmFontListAppendEntry(oldFontList,
					    XmFontListEntryLoad(display,
								fn,
							      XmFONT_IS_FONTSET,
								tag));

	XtFree(fn);

	return newFontList;
    }

    /* A simple font name */
    fn = font = XtNewString(full_entry);

    end = font + strlen(font);
    while (isspace(*font) && font < end)
    {
	font++;
    }

    while (isspace(*end) && end > font)
    {
	end--;
    }

    if (end != font + strlen(font))
    {
	end++;
	*end = 0;
    }
    newFontList = XmFontListAppendEntry(oldFontList,
					XmFontListEntryLoad(display, full_entry,
							    XmFONT_IS_FONT,
						      XmFONTLIST_DEFAULT_TAG));
    XtFree(fn);
    return newFontList;
}

/*
 * This thing should do reference counting, or make copies
 * Danny 16/4/1996
 */
/*
 * According to the docs, the following format should be converted :
 *      font_list = font_entry [ "," font_entry ]+
 *      font_entry = font_name [ ";" font_name ]+ ":" [ tag ]
 *                 | font_name [ "=" tag ]
 *      font_name = XLFD font name
 *      tag = a string (no space, comma, colon, semicolon, equalsign)
 *
 * For a simple example, see test/Xm/international/test1.
 */
static Boolean
_XmCvtStringToXmFontList(Display *display,
			 XrmValue *args,
			 Cardinal *num_args,
			 XrmValue *from,
			 XrmValue *to,
			 XtPointer *converter_data)
{
    XmFontList newFontList = NULL;
    char *p, *end, *font, *fn, *buf;

    if (*num_args != 0)
    {
	XtWarningMsg("wrongParameters", "cvtStringToFontlist",
		     "XtToolkitError",
		     "String to Fontlist conversion needs no extra arguments",
		     (String *)NULL, (Cardinal *)NULL);
    }

    /* there is an implicit rule here.  strtok() modifies the passed in buffer
     * at least on Linux, so if a comma is found, a \0 is put there.  This is
     * bad, as this memory didn't come from us, but from the Intrinsics, and
     * may get used again (especially if it's in the resource cache)! */

    buf = XtNewString(from->addr);

    p = strtok(buf, ",");

    /* if there was actually a comma character in the string. */
    if (p)
    {
	do
	{
	    fn = font = XtNewString(p);

	    end = font + strlen(font);
	    while (isspace(*font) && font < end)
	    {
		font++;
	    }
	    while (isspace(*end) && end > font)
	    {
		end--;
	    }
	    if (end != font + strlen(font))
	    {
		end++;
		*end = 0;
	    }

	    newFontList = __XmFontListResourceAddEntry(display, font,
						       newFontList);

	    XtFree(fn);
	    p = strtok(NULL, ",");

	}
	while (p != NULL);

	XtFree(buf);
    }
    else
    {
	fn = font = buf;

	end = font + strlen(font);
	while (isspace(*font) && font < end)
	{
	    font++;
	}
	while (isspace(*end) && end > font)
	{
	    end--;
	}

	if (end != font + strlen(font))
	{
	    end++;
	    *end = 0;
	}
	newFontList = __XmFontListResourceAddEntry(display, font, newFontList);

	XtFree(buf);
    }

    if (newFontList)
    {
	if (to->addr == NULL)
	{
	    to->addr = (XtPointer)&newFontList;
	    to->size = sizeof(XmFontList);
	}
	else
	{
	    if (to->size >= sizeof(XmFontList))
	    {
		*((XmFontList *)to->addr) = newFontList;
		to->size = sizeof(XmFontList);
	    }
	    else
	    {
		XtDisplayStringConversionWarning(display, (char *)from->addr,
						 XmRFontList);
	    }
	}
    }
    else
    {
	XtDisplayStringConversionWarning(display, (char *)from->addr,
					 XmRFontList);
    }

    return True;
}

#if 0
/* One from String to XmNavigationType */
static Boolean
_XmCvtStringToXmNavigation(Display *display,
			   XrmValue *args,
			   Cardinal *num_args,
			   XrmValue *from,
			   XrmValue *to,
			   XtPointer *converter_data)
{
    static XmNavigationType navType;

    navType = 10;

    if (*num_args != 0)
    {
	XtWarningMsg("wrongParameters", "cvtStringToXmNavigation",
		     "XtToolkitError",
		  "String to XmNavigation conversion needs no extra arguments",
		     (String *)NULL, (Cardinal *)NULL);
    }

    if (!strcmp((char *)from->addr, "NONE"))
    {
	navType = XmNONE;
    }
    else if (!strcmp((char *)from->addr, "TAB_GROUP"))
    {
	navType = XmTAB_GROUP;
    }
    else if (!strcmp((char *)from->addr, "STICKY_TAB_GROUP"))
    {
	navType = XmSTICKY_TAB_GROUP;
    }
    else if (!strcmp((char *)from->addr, "EXCLUSIVE_TAB_GROUP"))
    {
	navType = XmEXCLUSIVE_TAB_GROUP;
    }

    if (navType != 10)
    {
	if (to->addr == NULL)
	{
	    to->addr = (XtPointer)&navType;
	    to->size = sizeof(XmNavigationType);
	}
	else
	{
	    if (to->size >= sizeof(XmNavigationType))
	    {
		*((XmNavigationType *)to->addr) = navType;
		to->size = sizeof(XmNavigationType);
	    }
	    else
	    {
		XtDisplayStringConversionWarning(display, (char *)from->addr,
						 XmRNavigationType);
	    }
	}
    }
    else
    {
	XtDisplayStringConversionWarning(display, (char *)from->addr,
					 XmRNavigationType);
    }

    return True;
}
#endif

static Boolean
_XmCvtStringToCardinal(Display *display,
			XrmValue	*args,
			Cardinal	*num_args,
			XrmValue	*from,
			XrmValue	*to,
			XtPointer	*converter_data)
{
	static Cardinal	value;
	char		*end;

	value = 0;
	if (*num_args != 0)
	{
		XtWarningMsg("wrongParameters", "cvtStringToCardinal",
		    "XtToolkitError",
		    "String to Cardinal conversion needs no extra arguments",
		    (String *)NULL, (Cardinal *)NULL);
	}

#ifdef	HAVE_STRTOUL
	value = strtoul((char *)from->addr, &end, 10);
#else
	value = (Cardinal)strtol((char *)from->addr, &end, 10);
#endif

	if (*end == '\0')
	{
		if (to->addr == NULL)
		{
			to->addr = (XtPointer)&value;
			to->size = sizeof(Cardinal);
		}
		else
		{
			if (to->size >= sizeof(Cardinal))
			{
				*((Cardinal *)to->addr) = value;
				to->size = sizeof(Cardinal);
			}
			else
			{
				XtDisplayStringConversionWarning(display,
					(char *)from->addr,
					XmRCardinal);
			}
		}
	}
	else
	{
		XtDisplayStringConversionWarning(display,
			(char *)from->addr,
			XmRCardinal);
	}

	return True;
}

static Boolean
_XmCvtStringToKeySym(Display *d, XrmValue *args, Cardinal *nargs,
		     XrmValue *from, XrmValue *to, XtPointer *data)
{
    static KeySym k;

    k = XStringToKeysym((char *)from->addr);

    if (k != NoSymbol)
    {
	if (to->addr == NULL)
	{
	    to->addr = (XtPointer)&k;
	    to->size = sizeof(k);
	    return True;
	}
	else
	{
	    if (to->size >= sizeof(KeySym))
	    {
		*((KeySym *)to->addr) = k;
		to->size = sizeof(k);
		return True;
	    }
	    else
	    {
		XtDisplayStringConversionWarning(d, (char *)from->addr,
						 XmRKeySym);
		DEBUGOUT(XdbDebug(__FILE__, NULL,
				  "_XmCvtStringToKeySym fail at line %d\n",
				  __LINE__));
		return False;
	    }
	}
    }

    XtDisplayStringConversionWarning(d, (char *)from->addr, XmRKeySym);

    DEBUGOUT(XdbDebug(__FILE__, NULL,
		      "_XmCvtStringToKeySym fail at line %d\n", __LINE__));
    return False;
}

static Boolean
_XmCvtStringToResIndPosition(Display *display,
			     XrmValue *args,
			     Cardinal *num_args,
			     XrmValue *from,
			     XrmValue *to,
			     XtPointer *converter_data)
{
    static Position pos;

    if (*num_args != 3)
	XtWarningMsg("wrongParameters", "_XmCvtStringToResIndPosition",
		     "XtToolkitError",
"String to XmRHorizontal/VerticalPosition conversion needs no extra arguments",
		     (String *)NULL, (Cardinal *)NULL);

    pos = (Position)_XmConvertUnits(*(Screen **)args[0].addr,
				    (int)*(XtPointer *)args[1].addr,
				    *(unsigned char *)args[2].addr,
				    atoi(from->addr),
				    XmPIXELS);

    if (to->addr == NULL)
    {
	to->addr = (XtPointer)&pos;
	to->size = sizeof pos;
    }
    else
    {
	if (to->size < sizeof pos)
	{
	    XtDisplayStringConversionWarning(display, (char *)from->addr,
		(int)*(XtPointer *)args[1].addr == XmHORIZONTAL
		? XmRHorizontalPosition : XmRVerticalPosition);
	    return False;
	}
	*(Position *)to->addr = pos;
	to->size = sizeof pos;
    }

    return True;
}

static Boolean
_XmCvtStringToResIndDimension(Display *display,
			      XrmValue *args,
			      Cardinal *num_args,
			      XrmValue *from,
			      XrmValue *to,
			      XtPointer *converter_data)
{
    static Dimension dim;

    if (*num_args != 3)
	XtWarningMsg("wrongParameters", "_XmCvtStringToResIndDimension",
		     "XtToolkitError",
"String to XmRHorizontal/VerticalDimension conversion needs no extra arguments",
		     (String *)NULL, (Cardinal *)NULL);

    dim = (Dimension)_XmConvertUnits(*(Screen **)args[0].addr,
				     (int)*(XtPointer *)args[1].addr,
				     *(unsigned char *)args[2].addr,
				     atoi(from->addr),
				     XmPIXELS);

    if (to->addr == NULL)
    {
	to->addr = (XtPointer)&dim;
	to->size = sizeof dim;
    }
    else
    {
	if (to->size < sizeof dim)
	{
	    XtDisplayStringConversionWarning(display, (char *)from->addr,
		(int)*(XtPointer *)args[1].addr == XmHORIZONTAL
		? XmRHorizontalDimension : XmRVerticalDimension);
	    return False;
	}
	*(Dimension *)to->addr = dim;
	to->size = sizeof dim;
    }

    return True;
}

static Boolean
_XmCvtStringToResIndInt(Display *display,
			XrmValue *args,
			Cardinal *num_args,
			XrmValue *from,
			XrmValue *to,
			XtPointer *converter_data)
{
    static int pos;

    if (*num_args != 3)
	XtWarningMsg("wrongParameters", "_XmCvtStringToResIndInt",
		     "XtToolkitError",
     "String to XmRHorizontal/VerticalInt conversion needs no extra arguments",
		     (String *)NULL, (Cardinal *)NULL);

    pos = _XmConvertUnits(*(Screen **)args[0].addr,
			  (int)*(XtPointer *)args[1].addr,
			  *(unsigned char *)args[2].addr,
			  atoi(from->addr),
			  XmPIXELS);

    if (to->addr == NULL)
    {
	to->addr = (XtPointer)&pos;
	to->size = sizeof pos;
    }
    else
    {
	if (to->size < sizeof pos)
	{
	    XtDisplayStringConversionWarning(display, (char *)from->addr,
		(int)*(XtPointer *)args[1].addr == XmHORIZONTAL
		? XmRHorizontalInt : XmRVerticalInt);
	    return False;
	}
	*(int *)to->addr = pos;
	to->size = sizeof pos;
    }

    return True;
}

static Boolean
_XmCvtStringToWidget(	Display *display,
			XrmValue *args,
			Cardinal *num_args,
			XrmValue *from,
			XrmValue *to,
			XtPointer *converter_data)
{
    Widget		parent;
    static Widget	child;
    char		*name;

    if (*num_args != 1)
	XtWarningMsg("wrongParameters", "cvtStringToWidget",
		     "XtToolkitError",
	 "String to Widget conversion needs an extra argument",
		     (String *)NULL, (Cardinal *)NULL);

    name = (char *)from->addr;

    parent = * (Widget *) args[0].addr;

    if (name != NULL)
    {
	child = XtNameToWidget(parent, name);

	if (to->addr == NULL)
	{
	    to->addr = (XtPointer)&child;
	    to->size = sizeof(Widget);
	}
	else
	{
	    if (to->size >= sizeof(Widget))
	    {
		*((Widget *)to->addr) = child;
		to->size = sizeof(Widget);
	    }
	    else
	    {
		XtDisplayStringConversionWarning(display, (char *)from->addr,
						 XmRWidget);
	    }
	}
    }
    else
    {
	XtDisplayStringConversionWarning(display, (char *)from->addr,
					 XmRWidget);
    }

    return True;
}

static Boolean
_XmCvtStringToWindow(Display *display,
		     XrmValue *args,
		     Cardinal *num_args,
		     XrmValue *from,
		     XrmValue *to,
		     XtPointer *converter_data)
{
    static Window	win;

    win = atoi( from->addr);
    if (to->addr == NULL) {
	to->addr = (XPointer)&win;
	to->size = sizeof win;
    } else {
	if (!to->size) {
	    XtDisplayStringConversionWarning(display, from->addr, XmRWindow);
	    return False;
	}
	*to->addr = win;
	to->size = sizeof win;
    }

    return True;
}

static Boolean
_XmCvtStringToBooleanDimension( Display *display,
				XrmValue *args,
				Cardinal *num_args,
				XrmValue *from,
				XrmValue *to,
				XtPointer *converter_data)
{
    static Dimension	value;
    int			preval;
    String		str;

    str = (String)from->addr;

    if (*num_args != 3) {
	XtWarningMsg("wrongParameters", "cvtStringToBooleanDimension",
	    "XtToolkitError",
	    "String to BooleanDimension conversion needs no extra arguments",
	    (String *)NULL, (Cardinal *)NULL);
    }

    if (str != NULL) {
	if (isdigit(str[0])) {
	    preval = atoi(from->addr);
	    value = (Dimension)_XmConvertUnits(*(Screen **)args[0].addr,
					       (int)*(XtPointer *)args[1].addr,
					       *(unsigned char *)args[2].addr,
					       preval,
					       XmPIXELS);
	    if (!value && preval)
		value = 1;
	} else {
	    if ((strcasecmp(str, "true") == 0) || (strcasecmp(str, "yes") == 0)
			|| (strcasecmp(str, "on") == 0)) {
		value = True;
	    } else if ((strcasecmp(str, "false") == 0)
			|| (strcasecmp(str, "no") == 0)
			|| (strcasecmp(str, "off") == 0)) {
		value = False;
	    } else {
		XtDisplayStringConversionWarning(display, str,
				XmRBooleanDimension);
		return False;
	    }
	}

	if (to->addr == NULL) {
	    to->addr = (XtPointer)&value;
	    to->size = sizeof(value);
	} else {
	    if (to->size >= sizeof(value)) {
		*((Dimension *)to->addr) = value;
		to->size = sizeof(Dimension);
	    } else {
		XtDisplayStringConversionWarning(display, str,
				XmRBooleanDimension);
		return False;
	    }
	}
    } else {
	XtDisplayStringConversionWarning(display, str, XmRBooleanDimension);
	return False;
    }

    return True;
}

static Boolean
_XmCvtStringToChar( Display *display,
		    XrmValue *args,
		    Cardinal *num_args,
		    XrmValue *from,
		    XrmValue *to,
		    XtPointer *converter_data)
{
    static char	c;

    c = from->addr[0];
    if (to->addr == NULL) {
	to->addr = &c;
	to->size = 1;
    } else {
	if (!to->size) {
	    XtDisplayStringConversionWarning(display, from->addr, XmRChar);
	    return False;
	}
	*to->addr = c;
	to->size = 1;
    }

    return True;
}

static Boolean
_XmCvtStringToTextPosition( Display *display,
			    XrmValue *args,
			    Cardinal *num_args,
			    XrmValue *from,
			    XrmValue *to,
			    XtPointer *converter_data)
{
    static XmTextPosition	tp;

    tp = atol( from->addr);
    if (to->addr == NULL) {
	to->addr = (XtPointer)&tp;
	to->size = sizeof tp;
    } else {
	if (to->size < sizeof tp) {
	    XtDisplayStringConversionWarning(display, from->addr,
					     XmRTextPosition);
	    return False;
	}
	*(XmTextPosition *)to->addr = tp;
	to->size = sizeof tp;
    }

    return True;
}

static Boolean
_XmCvtStringToTopItemPosition( Display *display,
			       XrmValue *args,
			       Cardinal *num_args,
			       XrmValue *from,
			       XrmValue *to,
			       XtPointer *converter_data)
{
    static int	tip;

    tip = atoi( from->addr);
    if (to->addr == NULL) {
	to->addr = (XtPointer)&tip;
	to->size = sizeof tip;
    } else {
	if (to->size < sizeof tip) {
	    XtDisplayStringConversionWarning(display, from->addr,
					     XmRTopItemPosition);
	    return False;
	}
	*(XmTextPosition *)to->addr = tip;
	to->size = sizeof tip;
    }

    return True;
}

/* Converter for various tables of comma-separated strings,
 * with those strings converted each in their own way.
 */

static Boolean
_XmCvtStringToSomeTable( Display *display,
			 XrmValue *args,
			 Cardinal *num_args,
			 XrmValue *from,
			 XrmValue *to,
			 XtPointer *converter_data)
{
    int			nitems, tabsize, tabtype, escaped, anyescaped;
    char		*item, *p, *str, *sp;
    static XtPointer	*table;

    /* Separate the resource string at commas.
     * The commas may be escaped by a backslash
     * (leading whitespace and backslashes themselves may be escaped too).
     */

    table = (XtPointer *)XtMalloc((tabsize = 64) * sizeof(XtPointer));
    nitems = 0;
    item = NULL;
    escaped = anyescaped = False;
    tabtype = (int)*(XtPointer *)args[0].addr;
    for (p = from->addr;; p++)
    {
	if (escaped)
	{
	    /* A previously escaped character.
	     * Treat it like a normal character (not comma, backslash or space)
	     */

	    escaped = False;
	    if (!item)
		item = p;
	}
	else if (p >= from->addr + from->size || !*p || *p == ',')
	{
	    /* End of a string in the table.
	     * Make a copy to work with, both to add a nul and unescape.
	     */

	    if (!item)
		item = p;
	    str = XtMalloc((p - item) + 1);
	    memcpy(str, item, p - item);
	    str[p - item] = 0;
	    if (anyescaped)
	    {
		/* Removed escape characters */

		anyescaped = False;
		for (sp = str; *sp; sp++)
		    if (*sp == '\\' && sp[1])
		    {
			memmove(sp, sp + 1, strlen(sp));
			sp++;
		    }
	    }

	    /* Encode the string into something and put it in the list */

	    switch (tabtype)
	    {
	    case ST_BUTTON_TYPE:
		/* This should use probably use RepType stuff.  But that
		 * converter isn't there, and if it did its name would be
		 * XmRButtonType, which this erroneously is.
		 */

		if (_XmStringsAreEqual( str, "pushbutton"))
		    ((XmButtonType *)table)[nitems] = XmPUSHBUTTON;
		else if (_XmStringsAreEqual( str, "togglebutton"))
		    ((XmButtonType *)table)[nitems] = XmTOGGLEBUTTON;
		else if (_XmStringsAreEqual( str, "radiobutton"))
		    ((XmButtonType *)table)[nitems] = XmRADIOBUTTON;
		else if (_XmStringsAreEqual( str, "cascadebutton"))
		    ((XmButtonType *)table)[nitems] = XmCASCADEBUTTON;
		else if (_XmStringsAreEqual( str, "separator"))
		    ((XmButtonType *)table)[nitems] = XmSEPARATOR;
		else if (_XmStringsAreEqual( str, "double_separator"))
		    ((XmButtonType *)table)[nitems] = XmDOUBLE_SEPARATOR;
		else if (_XmStringsAreEqual( str, "title"))
		    ((XmButtonType *)table)[nitems] = XmTITLE;
		else
		{
		    XtDisplayStringConversionWarning(display, from->addr,
						     XmRButtonType);
		    XtFree(str);
		    XtFree((char *)table);
		    return False;
		}
		break;

	    case ST_KEY_SYM_TABLE:
		if ((table[nitems] = (XtPointer)XStringToKeysym(str)) ==
		    NoSymbol)
		{
		    XtDisplayStringConversionWarning(display, from->addr,
						     XmRKeySymTable);
		    XtFree(str);
		    XtFree((char *)table);
		    return False;
		}
		XtFree(str);
		break;

	    case ST_ATOM_LIST:
		/* Convert to atoms later */
	    case ST_STRING_TABLE:
		table[nitems] = str;
		break;

	    case ST_XM_STRING_TABLE:
		table[nitems] =
		    XmStringCreateLtoR(str, XmFONTLIST_DEFAULT_TAG);
		XtFree(str);
	    }

	    /* If this is the end of the string, stop looking */

	    nitems++;
	    if (p >= from->addr + from->size || !*p)
		break;
	    item = NULL;

	    /* Bump up the table size, re-allocating if needed */

	    if (nitems == tabsize)
		table = (XtPointer *)XtRealloc((char *)table,
		    (tabsize <<= 1) * sizeof(XtPointer));
	}
	else if (*p == '\\' && p < from->addr + from->size - 1 && p[1])
	{
	    /* Escape the next character after a blackslash
	     * (unless this is the end of the string)
	     */

	    escaped = anyescaped = True;
	}
	else if (!item && !isspace(*p))
	{
	    /* Skip leading whitespace for each item.
	     * Strangely, trailing whitespace stays.
	     */

	    item = p;
	}
    }

    /* Wrap up the conversion, including null-terminating the table */

    switch (tabtype)
    {
    case ST_ATOM_LIST:
	/* Now that we have all the atoms, convert them all at once */
	{
	    Atom *atoms = (Atom *)XtMalloc((nitems + 1) * sizeof(Atom));

	    atoms[nitems] = None;
#if XlibSpecificationRelease > 5
	    XInternAtoms(display, (char **)table, nitems, False, atoms);
#else
	    while (nitems--)
		XmInternAtom(display, ((char **)table)[nitems], False);
#endif
	    XtFree((char *)table);
	    table = (XtPointer *)atoms;
	}
	break;

    case ST_BUTTON_TYPE:
	table = (XtPointer *)
	    XtRealloc((char *)table, (nitems + 1) * sizeof(XmButtonType));
	((XmButtonType *)table)[nitems] = 0;
	break;

    default:
	table = (XtPointer *)
	    XtRealloc((char *)table, (nitems + 1) * sizeof(XtPointer));
	table[nitems] = NULL;
    }

    if (to->addr == NULL) {
	to->addr = (XtPointer)&table;
	to->size = sizeof table;
    } else {
	if (to->size < sizeof table) {
	    XtDisplayStringConversionWarning(display, from->addr,
		tabtype == ST_ATOM_LIST ? XmRAtomList :
		tabtype == ST_KEY_SYM_TABLE ? XmRKeySymTable :
		tabtype == ST_STRING_TABLE ? XmRStringTable :
		XmRXmStringTable);
	    return False;
	}
	*(XtPointer **)to->addr = table;
	to->size = sizeof table;
    }

    return True;
}

static void
destroy_font_list(XtAppContext app, XrmValue *to,
		  XtPointer converer_data, XrmValue *args,
		  Cardinal *num_args)
{
    XmFontListFree(*(XmFontList *)to->addr);
}

static void
destroy_table(XtAppContext app, XrmValue *to,
	      XtPointer converer_data, XrmValue *args,
	      Cardinal *num_args)
{
    XtFree(*(char **)to->addr);
}

static void
destroy_string_table(XtAppContext app, XrmValue *to,
		     XtPointer converer_data, XrmValue *args,
		     Cardinal *num_args)
{
    int		i;
    String	*table = *(String **)to->addr;

    for (i = 0; table[i]; i++)
	XtFree(table[i]);
    XtFree((char *)table);
}

static void
destroy_xm_string_table(XtAppContext app, XrmValue *to,
		     XtPointer converer_data, XrmValue *args,
		     Cardinal *num_args)
{
    int			i;
    XmStringTable	table = *(XmStringTable *)to->addr;

    for (i = 0; table[i]; i++)
	XmStringFree(table[i]);
    XtFree((char *)table);
}

static void
get_unit_type(Widget w, Cardinal *size, XrmValue *val)
{
    static unsigned char ut;

    val->addr = (XPointer)&ut;
    val->size = sizeof ut;
    ut = _XmGetUnitType(w);
}

#if	XmVERSION > 1
/*
 * XmConvertStringToUnits converts a string specification value and returns
 * the converted value as the return value from the function. This function
 * uses the specified screen's resolution to compute the number of units for
 * the string specification.
 */
int
XmConvertStringToUnits(Screen *screen, String spec, int orientation,
	int to_type, XtEnum *parse_error)
{
	/* FIX ME not implemented yet */

	if (screen == NULL)
		return 0;

	if (orientation != XmHORIZONTAL && orientation != XmVERTICAL)
		return 0;

	switch (to_type) {
	case XmPIXELS:
	case XmMILLIMETERS:
	case Xm100TH_MILLIMETERS:
	case XmCENTIMETERS:
	case XmINCHES:
	case Xm1000TH_INCHES:
	case XmPOINTS:
	case Xm100TH_POINTS:
	case XmFONT_UNITS:
	case Xm100TH_FONT_UNITS:
		break;
	default:
		return 0;
	}
    return 0;
}

static Boolean
_XmCvtStringToTabList(Display *display,
		       XrmValue *args,
		       Cardinal *num_args,
		       XrmValue *from,
		       XrmValue *to,
		       XtPointer *converter_data)
{
	return False;
}

static Boolean
_XmCvtStringToRenderTable(Display *display,
		       XrmValue *args,
		       Cardinal *num_args,
		       XrmValue *from,
		       XrmValue *to,
		       XtPointer *converter_data)
{
	return False;
}
#endif
