/**
 *
 * $Id: DebugUtil.c,v 1.44 1999/07/25 11:53:08 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: DebugUtil.c,v 1.44 1999/07/25 11:53:08 rwscott Exp $";

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <LTconfig.h>
#include <XmI/XmI.h>

#include <XmI/DebugUtil.h>
#include <X11/Xos.h>
#include <Xm/GadgetP.h>
#include <X11/Intrinsic.h>
#include <X11/IntrinsicP.h>
#include <X11/Xresource.h>
#include <Xm/VendorSEP.h>
#include <Xm/DrawingAP.h>
#include <Xm/Display.h>

/*
 * Functionality in this file is influenced at run time by these
 * environment variables :
 * - DEBUGSOURCES : colon-separated list of files from which debug output
 *      is generated. Special value "all" has obvious meaning.
 * - DEBUG_PRINT_WIDGETID : if this variable exists, then all widgets printed
 *      with XdbDebug etc. will also print their widget ID. If the variable
 *      doesn't exist, then they only print their name for identification.
 * - DEBUG_FILE : if this variable exists, then the file is used for output.
 *      If %p is part of the value of DEBUG_FILE, then it is replaced by the
 *      process id.
 *
 * If the C macro LESSTIF_PRODUCTION is defined, then XdbDebug etc. don't
 *      work. Note: this is a compile time option.
 * To have maximum performance, sequences of XdbDebug statements should be
 *      surrounded by an if (XdbInDEBUG(__FILE__, w)) statement.
 *      XdbInDebug is False when LESSTIF_PRODUCTION is defined.
 */

/* Protect ourselves (for now) */

static FILE *XdbFile = NULL;

static void 
XdbOpenFile(void)
{
    char *s, *p, *fn;

    if (XdbFile != NULL)
    {
	return;
    }

    s = getenv("DEBUG_FILE");
    if (s == 0)
    {
	XdbFile = stderr;
	return;
    }

    p = strstr(s, "%p");

    fn = XtMalloc(strlen(s) + 10);
    if (p)
    {
	*(p + 1) = 'd';
	sprintf(fn, s, getpid());
    }
    else
    {
	strcpy(fn, s);
    }

    /* a means append, create if doesn't exist */
    XdbFile = fopen(fn, "a");
    if (XdbFile == 0)
    {
	XdbFile = stderr;
    }
    else
    {
	setbuf(XdbFile, NULL);
    }
}

#ifdef	PRINT_STATE
static char *
_XdbState(Widget w)
{
    if (XtIsRealized(w))
    {
	if (XtIsManaged(w))
	{
	    return "realized, managed";
	}
	else
	{
	    return "realized, not managed";
	}
    }
    else
    {
	if (XtIsManaged(w))
	{
	    return "not realized, not managed";
	}
	else
	{
	    return "not realized, not managed";
	}
    }
}
#endif

#if	0
static void 
_XdbPrintTree(Widget w, int level)
{
    int i;
    CompositeWidget cw = (CompositeWidget)w;

    if (w == NULL)
    {
	return;
    }

    XdbOpenFile();

    for (i = 0; i < level; i++)
    {
	fprintf(XdbFile, "\t");
    }

    fprintf(XdbFile, "%s : %p/%ld", XtName(w), w, XtWindow(w));
    fprintf(XdbFile, "(%s) geo %d %d %d %d",
	    w->core.widget_class->core_class.class_name,
	    XtX(w), XtY(w), XtWidth(w), XtHeight(w));
#ifdef	PRINT_STATE
    fprintf(XdbFile, " state: %s %s",
	    _XdbState(w), w->core.mapped_when_managed ? "mwm" : "");
#endif
    fprintf(XdbFile, "\n");
    if (XtIsSubclass(w, compositeWidgetClass))
    {
	for (i = 0; i < cw->composite.num_children; i++)
	{
	    _XdbPrintTree(cw->composite.children[i], level + 1);
	}
    }

    for (i = 0; i < cw->core.num_popups; i++)
    {
	_XdbPrintTree(cw->core.popup_list[i], level + 1);
    }
}

void 
XdbPrintTree(Widget w)
{
    _XdbPrintTree(w, 0);
}

void 
XdbPrintCompleteTree(Widget w)
{
    Widget ww = w;

    while (ww)
    {
	w = ww;
	ww = XtParent(w);
    }

    _XdbPrintTree(w, 0);
}
#endif

#if XmVERSION > 1
char *
XdbComboBoxType2String(unsigned char type)
{
    switch(type)
    {
    case XmDROP_DOWN_LIST:
    	return("XmDROP_DOWN_LIST");
	break;
    case XmDROP_DOWN_COMBO_BOX:
    	return("XmDROP_DOWN_COMBO_BOX");
	break;
    case XmCOMBO_BOX:
    	return("XmCOMBO_BOX");
	break;
    default:
	return("UNKNOWN");
	break;
    }
}
#endif

char *
XdbGeoAction2String(int action)
{
	switch(action)
	{
	case XmGET_ACTUAL_SIZE:
		return("XmGET_ACTUAL_SIZE");
		break;
	case XmGET_PREFERRED_SIZE:
		return("XmGET_PREFERRED_SIZE");
		break;
	case XmGEO_PRE_SET:
		return("XmGEO_PRE_SET");
		break;
	case XmGEO_POST_SET:
		return("XmGEO_POST_SET");
		break;
	default:
		return("Unknown geo action");
		break;
	}
}

char *
XdbGeometryResult2String(XtGeometryResult r)
{
    switch (r)
    {
    case XtGeometryYes:
	return "Yes";

    case XtGeometryNo:
	return "No";

    case XtGeometryAlmost:
	return "Almost";

    case XtGeometryDone:
	return "Done";

    default:
	return "(invalid geometry result)";
    }
}

static char *
XdbDragType2String(unsigned char r)
{
    switch (r)
    {
    case XmDRAG_NONE:
	return "XmDRAG_NONE";

    case XmDRAG_DROP_ONLY:
	return "XmDRAG_DROP_ONLY";

    case XmDRAG_PREFER_PREREGISTER:
	return "XmDRAG_PREFER_PREREGISTER";

    case XmDRAG_PREFER_DYNAMIC:
	return "XmDRAG_PREFER_DYNAMIC";

    case XmDRAG_PREFER_RECEIVER:
	return "XmDRAG_PREFER_RECEIVER";

    case XmDRAG_DYNAMIC:
	return "XmDRAG_DYNAMIC";

    default:
	return "UNKNOWN";
    }
}

static char *
XdbScrollingPolicy2String(unsigned char r)
{
    switch (r)
    {
    case XmAUTOMATIC:
	return "XmAUTOMATIC";

    case XmCONSTANT:
	return "XmCONSTANT";

    default:
	return "UNKNOWN";
    }
}

static char *
XdbDialogStyle2String(int a)
{
    switch (a)
    {
    case XmDIALOG_WORK_AREA:
	return "XmDIALOG_WORK_AREA or XmDIALOG_MODELESS";

    /*
    case XmDIALOG_MODELESS:
	return "XmDIALOG_MODELESS";
	*/

    case XmDIALOG_PRIMARY_APPLICATION_MODAL:
	return "XmDIALOG_PRIMARY_APPLICATION_MODAL or XmDIALOG_APPLICATION_MODAL";

    case XmDIALOG_FULL_APPLICATION_MODAL:
	return "XmDIALOG_FULL_APPLICATION_MODAL";

    case XmDIALOG_SYSTEM_MODAL:
	return "XmDIALOG_SYSTEM_MODAL";

    /*
    case XmDIALOG_APPLICATION_MODAL:
	return "XmDIALOG_APPLICATION_MODAL";
	*/

    default:
	return "(invalid dialog style)";
    }
}

char *
XdbAttachment2String(int a)
{
    switch (a)
    {
    case XmATTACH_FORM:
	return "XmATTACH_FORM";

    case XmATTACH_OPPOSITE_FORM:
	return "XmATTACH_OPPOSITE_FORM";

    case XmATTACH_WIDGET:
	return "XmATTACH_WIDGET";

    case XmATTACH_OPPOSITE_WIDGET:
	return "XmATTACH_OPPOSITE_WIDGET";

    case XmATTACH_NONE:
	return "XmATTACH_NONE";

    case XmATTACH_POSITION:
	return "XmATTACH_POSITION";

    case XmATTACH_SELF:
	return "XmATTACH_SELF";

    default:
	return "(invalid attachment)";
    }
}

/*
 * See if 'fn' is one of the elements in 'l'.
 * L is a colon-separated list of source files.
 * The ".c" suffix for sources is not required (i.e. Form is equivalent
 * to Form.c).
 *
 * As of post-0.50, the "fn" can contain a directory prefix.
 */
static Boolean
ValidateSource(char *fn, char *l)
{
#ifndef	LESSTIF_PRODUCTION
    char *s, *p, *q;
    int i;

    if (l == NULL)
    {
	return False;
    }

    if (strcmp(l, "all") == 0)
    {
	return True;
    }

    /* remove directory prefix */
    s = strrchr(fn, '/');

    if (s && *(s + 1) != '\0')
    {
	fn = s + 1;
    }

    i = strlen(fn);

    s = l;
    while ((p = strstr(s, fn)) != NULL)
    {
	q = p + i;

	if (*q == '\0' || *q == '.' || *q == ':')
	{
	    return True;
	}

	s = q;
    }
#endif
    return False;
}

/*
 * This is the new style debugging support routine for LessTif.
 *
 * It allows us to choose at run time which sources should spit out
 * their guts.
 */
static char *
_XdbFindDebugSources(Widget w)
{
    static char *env = NULL;
    static int checked=False;

    if (!checked) {
      checked=True;
      if (env == NULL) 	
      {
	env = getenv("DEBUGSOURCES");
      }
    }
    return env;
}

static char *
_XdbPrintWidgetID(void)
{
    static char *env = NULL;
    static int checked=False;

    if (!checked) {
      checked=True;
      if (env == NULL)  
      {
	env = getenv("DEBUG_PRINT_WIDGETID");
      }
    }
    return env;
}

void 
XdbDebug(char *fn, Widget w, char *fmt,...)
{
#ifndef LESSTIF_PRODUCTION
    va_list ap;
    char *dbs = _XdbFindDebugSources(w);

    if (ValidateSource(fn, dbs))
    {
	XdbOpenFile();

	if (w)
	{
	    if (_XdbPrintWidgetID())
	    {
		fprintf(XdbFile, "%s %s [%p]: ",
			w->core.widget_class->core_class.class_name,
			XtName(w), w);
	    }
	    else
	    {
		fprintf(XdbFile, "%s %s: ",
			w->core.widget_class->core_class.class_name, XtName(w));
	    }
	}
	else
	{
	    fprintf(XdbFile, "(null widget): ");
	}

	va_start(ap, fmt);
	vfprintf(XdbFile, fmt, ap);
	va_end(ap);

	fflush(XdbFile);
    }
#endif
}

void 
XdbDebug2(char *fn, Widget w, Widget c, char *fmt,...)
{
#ifndef LESSTIF_PRODUCTION
    va_list ap;
    char *dbs = _XdbFindDebugSources(w);

    if (ValidateSource(fn, dbs))
    {
	XdbOpenFile();

	if (w && c)
	{
	    if (_XdbPrintWidgetID())
	    {
		fprintf(XdbFile, "%s %s [%p] (child %s [%p]): ",
			w->core.widget_class->core_class.class_name,
			XtName(w), w, XtName(c), c);
	    }
	    else
	    {
		fprintf(XdbFile, "%s %s (child %s): ",
			w->core.widget_class->core_class.class_name,
			XtName(w), XtName(c));
	    }
	}
	else if (w)
	{
	    if (_XdbPrintWidgetID())
	    {
		fprintf(XdbFile, "%s %s [%p] (child NULL): ",
			w->core.widget_class->core_class.class_name,
			XtName(w), w);
	    }
	    else
	    {
		fprintf(XdbFile, "%s %s (child NULL): ",
			w->core.widget_class->core_class.class_name,
			XtName(w));
	    }
	}
	else
	{
	    fprintf(XdbFile, "(null widget): ");
	}

	va_start(ap, fmt);
	vfprintf(XdbFile, fmt, ap);
	va_end(ap);
    }
#endif
}

void 
XdbDebug0(char *fn, Widget w, char *fmt,...)
{
#ifndef LESSTIF_PRODUCTION
    va_list ap;
    char *dbs = _XdbFindDebugSources(w);

    if (ValidateSource(fn, dbs))
    {
	XdbOpenFile();

	va_start(ap, fmt);
	vfprintf(XdbFile, fmt, ap);
	va_end(ap);
    }
#endif
}

#ifdef	XdbInDebug
#undef	XdbInDebug
#endif

Boolean 
XdbInDebug(char *fn, Widget w)
{
#ifdef	LESSTIF_PRODUCTION
    return False;
#else
    return ValidateSource(fn, _XdbFindDebugSources(w));
#endif
}

char *
XdbMenuFocusOp2String(int f)
{
    switch (f)
    {
    case XmMENU_FOCUS_SAVE:
    	return ("XmMENU_FOCUS_SAVE");
    	break;
    case XmMENU_FOCUS_RESTORE:
    	return ("XmMENU_FOCUS_RESTORE");
    	break;
    case XmMENU_FOCUS_SET:
    	return ("XmMENU_FOCUS_SET");
    	break;
    default:
    	return("Unknown focus op");
    	break;
    }
}

char *
XdbMenuEnum2String(int f)
{
    switch (f)
    {
    case XmMENU_POPDOWN:
	return "XmMENU_POPDOWN";

    case XmMENU_PROCESS_TREE:
	return "XmMENU_PROCESS_TREE";

    case XmMENU_TRAVERSAL:
	return "XmMENU_TRAVERSAL";

    case XmMENU_SHELL_POPDOWN:
	return "XmMENU_SHELL_POPDOWN";

    case XmMENU_CALLBACK:
	return "XmMENU_CALLBACK";

    case XmMENU_BUTTON:
	return "XmMENU_BUTTON";

    case XmMENU_CASCADING:
	return "XmMENU_CASCADING";

    case XmMENU_SUBMENU:
	return "XmMENU_SUBMENU";

    case XmMENU_ARM:
	return "XmMENU_ARM";

    case XmMENU_DISARM:
	return "XmMENU_DISARM";

    case XmMENU_BAR_CLEANUP:
	return "XmMENU_BAR_CLEANUP";

    case XmMENU_STATUS:
	return "XmMENU_STATUS";

    case XmMENU_MEMWIDGET_UPDATE:
	return "XmMENU_MEMWIDGET_UPDATE";

    case XmMENU_BUTTON_POPDOWN:
	return "XmMENU_BUTTON_POPDOWN";

    case XmMENU_RESTORE_EXCLUDED_TEAROFF_TO_TOPLEVEL_SHELL:
	return "XmMENU_RESTORE_EXCLUDED_TEAROFF_TO_TOPLEVEL_SHELL";

    case XmMENU_RESTORE_TEAROFF_TO_TOPLEVEL_SHELL:
	return "XmMENU_RESTORE_TEAROFF_TO_TOPLEVEL_SHELL";

    case XmMENU_RESTORE_TEAROFF_TO_MENUSHELL:
	return "XmMENU_RESTORE_TEAROFF_TO_MENUSHELL";

    case XmMENU_GET_LAST_SELECT_TOPLEVEL:
	return "XmMENU_GET_LAST_SELECT_TOPLEVEL";

    case XmMENU_TEAR_OFF_ARM:
	return "XmMENU_TEAR_OFF_ARM";

    default:
	return "??";
    }
}

char *
XdbBoolean2String(int b)
{
    if (b)
    {
	return "True";
    }

    return "False";
}

char *
XdbXmString2String(XmString xms)
{
  static char *s = NULL;

    if (s) {
      free(s);
      s=NULL;
    }
    if (xms == (XmString)XmUNSPECIFIED)
    {
	return "XmUNSPECIFIED";
    }
    if ( ! XmStringGetLtoR(xms, XmFONTLIST_DEFAULT_TAG, &s) || s == NULL )
    {
	return "(null)";
    }

    return s;
}

char *
XdbPacking2String(unsigned char p)
{
    static char res[40];

    switch (p)
    {
    case XmPACK_COLUMN:
	return "XmPACK_COLUMN";

    case XmPACK_TIGHT:
	return "XmPACK_TIGHT";

    case XmPACK_NONE:
	return "XmPACK_NONE";

    default:
	sprintf(res, "Invalid packing %d", p);
	return res;
    }
}

char *
XdbRcType2String(unsigned char t)
{
    static char res[40];

    switch (t)
    {
    case XmWORK_AREA:
	return "XmWORK_AREA";

    case XmMENU_BAR:
	return "XmMENU_BAR";

    case XmMENU_PULLDOWN:
	return "XmMENU_PULLDOWN";

    case XmMENU_POPUP:
	return "XmMENU_POPUP";

    case XmMENU_OPTION:
	return "XmMENU_OPTION";

    default:
	sprintf(res, "Invalid RC Type %d", t);
	return res;
    }
}

char *
XdbWidgetGeometry2String(XtWidgetGeometry *g)
{
    static char o1[128], o2[128], b[20], *out = NULL;
    int i;

    if (g == NULL)
    {
	return "NULL_GEOMETRY";
    }

    if (g->request_mode == 0)
    {
	return "GEOMETRY_NO_FIELDS";
    }

/* Some magic to ensure you can call this sucker twice in one C function call */
    if (out == &o1[0])
    {
	out = &o2[0];
    }
    else
    {
	out = &o1[0];
    }

    out[0] = '\0';
    if (g->request_mode & CWX)
    {
	sprintf(b, "x %d ", g->x);
	strcat(out, b);
    }
    if (g->request_mode & CWY)
    {
	sprintf(b, "y %d ", g->y);
	strcat(out, b);
    }
    if (g->request_mode & CWWidth)
    {
	sprintf(b, "w %d ", g->width);
	strcat(out, b);
    }
    if (g->request_mode & CWHeight)
    {
	sprintf(b, "h %d ", g->height);
	strcat(out, b);
    }
    if (g->request_mode & CWBorderWidth)
    {
	sprintf(b, "bw %d ", g->border_width);
	strcat(out, b);
    }

    for (i = 0; out[i]; i++)
    {
    }

    if (i > 0 && out[i - 1] == ' ')
    {
	out[i - 1] = '\0';
    }

    return out;
}

#define	XdbNONE			0
#define	XdbINT			1
#define	XdbSTRING		2
#define	XdbXMSTRING		3
#define	XdbCHAR			4
#define	XdbSHORT		5
#define	XdbATTACHMENT		6
#define	XdbWIDGET		7
#define	XdbBOOLEAN		8
#define	XdbSELECTION_POLICY	9
#define	XdbXMSTRING_LIST	10	/* bingo */
#define XdbDIALOG_STYLE		11
#define XdbEDIT_MODE		12
#define XdbALIGNMENT		13
#define XdbSB_DISPLAY_POLICY	14
#define XdbLIST_SIZE_POLICY	15
#define XdbSB_PLACEMENT		16
#define XdbRESIZE_POLICY	17
#define XdbCOMBOBOX_TYPE	18
#define XdbSCROLLING_POLICY	19
#define XdbDRAG_TYPE		20

static struct
{
    char *name;
    int t;
    char *related;
}
XdbTypes[] =
{
    {
	XmNdragInitiatorProtocolStyle, XdbDRAG_TYPE, NULL
    }
    ,
    {
	XmNdragReceiverProtocolStyle, XdbDRAG_TYPE, NULL
    }
    ,
    {
	XmNscrollingPolicy, XdbSCROLLING_POLICY, NULL
    }
    ,
    {
	XmNmaximum, XdbINT, NULL
    }
    ,
    {
	XmNminimum, XdbINT, NULL
    }
    ,
    {
	XmNsliderSize, XdbINT, NULL
    }
    ,
    {
	XmNpageIncrement, XdbINT, NULL
    }
    ,
    {
	XmNincrement, XdbINT, NULL
    }
    ,
    {
	XmNx, XdbINT, NULL
    }
    ,
    {
	XmNy, XdbINT, NULL
    }
    ,
    {
	XmNwidth, XdbINT, NULL
    }
    ,
    {
	XmNheight, XdbINT, NULL
    }
    ,
    {
	XmNlabelString, XdbXMSTRING, NULL
    }
    ,
    {
	XmNmessageString, XdbXMSTRING, NULL
    }
    ,
    {
	XmNrowColumnType, XdbNONE, NULL
    }
    ,
    {
	XmNbuttonSet, XdbNONE, NULL
    }
    ,
    {
	XmNbuttonCount, XdbINT, NULL
    }
    ,
    {
	XmNoptionLabel, XdbXMSTRING, NULL
    }
    ,
    {
	XmNdirectory, XdbXMSTRING, NULL
    }
    ,
    {
	XmNoptionMnemonic, XdbCHAR, NULL
    }
    ,
    {
	XmNrows, XdbSHORT, NULL
    }
    ,
    {
	XmNcolumns, XdbSHORT, NULL
    }
    ,
    {
	XmNmarginWidth, XdbINT, NULL
    }
    ,
    {
	XmNmarginHeight, XdbINT, NULL
    }
    ,
    {
	XmNmarginTop, XdbINT, NULL
    }
    ,
    {
	XmNmarginBottom, XdbINT, NULL
    }
    ,
    {
	XmNmarginLeft, XdbINT, NULL
    }
    ,
    {
	XmNmarginRight, XdbINT, NULL
    }
    ,
    {
	XmNselectionArrayCount, XdbINT, NULL
    }
    ,
    {
	XmNshadowThickness, XdbINT, NULL
    }
    ,
    {
	XmNhighlightThickness, XdbINT, NULL
    }
    ,
    {
	XmNtopAttachment, XdbATTACHMENT, NULL
    }
    ,
    {
	XmNbottomAttachment, XdbATTACHMENT, NULL
    }
    ,
    {
	XmNleftAttachment, XdbATTACHMENT, NULL
    }
    ,
    {
	XmNrightAttachment, XdbATTACHMENT, NULL
    }
    ,
    {
	XmNtopOffset, XdbINT, NULL
    }
    ,
    {
	XmNbottomOffset, XdbINT, NULL
    }
    ,
    {
	XmNleftOffset, XdbINT, NULL
    }
    ,
    {
	XmNrightOffset, XdbINT, NULL
    }
    ,
    {
	XmNtopPosition, XdbINT, NULL
    }
    ,
    {
	XmNbottomPosition, XdbINT, NULL
    }
    ,
    {
	XmNleftPosition, XdbINT, NULL
    }
    ,
    {
	XmNrightPosition, XdbINT, NULL
    }
    ,
    {
	XmNdefaultButton, XdbWIDGET, NULL
    }
    ,
    {
	XmNmessageWindow, XdbWIDGET, NULL
    }
    ,
    {
	XmNtopWidget, XdbWIDGET, NULL
    }
    ,
    {
	XmNbottomWidget, XdbWIDGET, NULL
    }
    ,
    {
	XmNleftWidget, XdbWIDGET, NULL
    }
    ,
    {
	XmNrightWidget, XdbWIDGET, NULL
    }
    ,
    {
	XmNsensitive, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNresizable, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNmustMatch, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNresizeHeight, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNresizeWidth, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNfractionBase, XdbINT, NULL
    }
    ,
    {
	XmNhorizontalSpacing, XdbINT, NULL
    }
    ,
    {
	XmNverticalSpacing, XdbINT, NULL
    }
    ,
    {
	XmNrubberPositioning, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNitemCount, XdbINT, NULL
    }
    ,
    {
	XmNfileListItemCount, XdbINT, NULL
    }
    ,
    {
	XmNtextString, XdbXMSTRING, NULL
    }
    ,
    {
	XmNdirSpec, XdbXMSTRING, NULL
    }
    ,
    {
	XmNdirMask, XdbXMSTRING, NULL
    }
    ,
    {
	XmNitems, XdbXMSTRING_LIST, XmNitemCount
    }
    ,				/* bingo */
    {
	XmNselectionPolicy, XdbSELECTION_POLICY, NULL
    }
    ,
    {
	XmNautoUnmanage, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNdialogStyle, XdbDIALOG_STYLE, NULL
    }
    ,
    {
	XmNshowAsDefault, XdbSHORT, NULL
    }
    ,
    {
	XmNeditable, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNmaxLength, XdbINT, NULL
    }
    ,
    {
	XmNdirListItemCount, XdbINT, NULL
    }
    ,
    {
	XmNfileListItemCount, XdbINT, NULL
    }
    ,
    {
	XmNeditMode, XdbEDIT_MODE, NULL
    }
    ,
    {
	XmNalignment, XdbALIGNMENT, NULL
    }
    ,
    {
	XmNrecomputeSize, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNdirectoryValid, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNlistUpdated, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNhorizontalScrollBar, XdbWIDGET, NULL
    }
    ,
    {
	XmNverticalScrollBar, XdbWIDGET, NULL
    }
    ,
    {
	XmNworkWindow, XdbWIDGET, NULL
    }
    ,
    {
	XmNmenuBar, XdbWIDGET, NULL
    }
    ,
    {
	XmNcommandWindow, XdbWIDGET, NULL
    }
    ,
    {
	XmNvisibleItemCount, XdbSHORT, NULL
    }
    ,
    {
	XmNdefaultButtonShadowThickness, XdbSHORT, NULL
    }
    ,
    {
	XmNset, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNtraversalOn, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNspacing, XdbSHORT, NULL
    }
    ,
    {
	XmNscrollBarDisplayPolicy, XdbSB_DISPLAY_POLICY, NULL
    }
    ,
    {
	XmNlistSizePolicy, XdbLIST_SIZE_POLICY, NULL
    }
    ,
    {
	XmNscrollBarPlacement, XdbSB_PLACEMENT, NULL
    }
    ,
    {
	XmNuserData, XdbNONE, NULL
    }
    ,
    {
	XmNallowShellResize, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNresizePolicy, XdbRESIZE_POLICY, NULL
    }
    ,
    {
	XmNradioBehavior, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNradioAlwaysOne, XdbBOOLEAN, NULL
    }
    ,
    {
	XmNnumColumns, XdbSHORT, NULL
    }
    ,
#if XmVERSION > 1
    {
	XmNcomboBoxType, XdbCOMBOBOX_TYPE, NULL
    }
    ,
#endif
    {
	NULL, 0, NULL
    }				/* the end */
};

void
XdbPrintArgList(char *fn, Widget w, ArgList al, int n, Boolean Get)
{
#ifndef	LESSTIF_PRODUCTION
    int i, j, num;
    char *dbs = _XdbFindDebugSources(w), *p;

    if (ValidateSource(fn, dbs))
    {
	XdbOpenFile();

	for (i = 0; i < n; i++)
	{
	    int at;

	    for (at = 0; XdbTypes[at].name; at++)
	    {
		if (strcmp(al[i].name, XdbTypes[at].name) == 0)
		{
		    break;
		}
	    }

	    if (XdbTypes[at].name == NULL)
	    {
		fprintf(XdbFile, "Arg[%d] : %s (not handled FIX ME)\n", i, al[i].name);
		continue;
	    }

	    switch (XdbTypes[at].t)
	    {
	    case XdbNONE:
		fprintf(XdbFile, "Arg[%d] : %s\n", i, al[i].name);
		break;

	    case XdbINT:
		fprintf(XdbFile, "Arg[%d] : %s %d\n", i, al[i].name,
			(Get) ? *(int *)al[i].value
			: (int)al[i].value);
		break;

	    case XdbSHORT:
		fprintf(XdbFile, "Arg[%d] : %s %d\n", i, al[i].name,
			(Get) ? *(short *)al[i].value
			: (short)al[i].value);
		break;

	    case XdbSTRING:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name, (char *)al[i].value);
		break;

	    case XdbXMSTRING:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
			XdbXmString2String((XmString)al[i].value));
		break;

	    case XdbCHAR:
		fprintf(XdbFile, "Arg[%d] : %s %c\n", i, al[i].name, (char)al[i].value);
		break;

	    case XdbALIGNMENT:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbAlignment2String(*(unsigned char *)al[i].value)
			: XdbAlignment2String((unsigned char)al[i].value));
		break;

	    case XdbRESIZE_POLICY:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbResizePolicy2String(*(unsigned char *)al[i].value)
			: XdbResizePolicy2String((unsigned char)al[i].value));
		break;

	    case XdbSB_DISPLAY_POLICY:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbSBDisplayPolicy2String(*(unsigned char *)al[i].value)
			: XdbSBDisplayPolicy2String((unsigned char)al[i].value));
		break;

	    case XdbDRAG_TYPE:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbDragType2String(*(unsigned char *)al[i].value)
			: XdbDragType2String((unsigned char)al[i].value));
		break;

	    case XdbSCROLLING_POLICY:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbScrollingPolicy2String(*(unsigned char *)al[i].value)
			: XdbScrollingPolicy2String((unsigned char)al[i].value));
		break;

	    case XdbSB_PLACEMENT:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbSBPlacement2String(*(unsigned char *)al[i].value)
			: XdbSBPlacement2String((unsigned char)al[i].value));
		break;

	    case XdbLIST_SIZE_POLICY:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbListSizePolicy2String(*(unsigned char *)al[i].value)
			: XdbListSizePolicy2String((unsigned char)al[i].value));
		break;

	    case XdbATTACHMENT:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbAttachment2String(*(unsigned char *)al[i].value)
			: XdbAttachment2String((unsigned char)al[i].value));
		break;

	    case XdbDIALOG_STYLE:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
		    (Get) ? XdbDialogStyle2String(*(unsigned char *)al[i].value)
			: XdbDialogStyle2String((unsigned char)al[i].value));
		break;

	    case XdbWIDGET:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
			(Get)
			? ((al[i].value && *(Widget *)al[i].value)
			   ? XtName(*(Widget *)al[i].value)
			   : "(null)")
			: (al[i].value
			   ? XtName((Widget)al[i].value)
			   : "(null)"));
		break;

	    case XdbEDIT_MODE:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
			(Get) ? XdbEditMode2String(*(Boolean *)al[i].value)
			: XdbEditMode2String((Boolean)al[i].value));
		break;

	    case XdbBOOLEAN:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
			(Get) ? XdbBoolean2String(*(Boolean *)al[i].value)
			: XdbBoolean2String((Boolean)al[i].value));
		break;

	    case XdbSELECTION_POLICY:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
			XdbSelectionPolicy2String(al[i].value));
		break;

	    case XdbXMSTRING_LIST:	/* Need related info !! */
		num = 0xdeadbeef;
		p = XdbTypes[at].related;

		XtVaGetValues(w, XdbTypes[at].related, &num, NULL);

		if (num != 0xdeadbeef)
		{
		    fprintf(XdbFile, "Arg[%d] : %s(%d):\n", i, al[i].name, num);

		    for (j = 0; j < num; j++)
		    {
			fprintf(XdbFile, "\tItem %d '%s'\n", j,
			    XdbXmString2String(((XmString *)(al[i].value))[j]));
		    }
		}

		break;
#if XmVERSION > 1
	    case XdbCOMBOBOX_TYPE:
		fprintf(XdbFile, "Arg[%d] : %s %s\n", i, al[i].name,
			XdbComboBoxType2String(al[i].value));
		break;
#endif

	    }
	}
    }
#endif
}

char *
XdbEditMode2String(int n)
{
    switch (n)
    {
    case XmMULTI_LINE_EDIT:
	return "XmMULTI_LINE_EDIT";

    case XmSINGLE_LINE_EDIT:
	return "XmSINGLE_LINE_EDIT";

    default:
	return "???";
    }
}

char *
XdbSelectionPolicy2String(int n)
{
    switch (n)
    {
    case XmSINGLE_SELECT:
	return "XmSINGLE_SELECT";

    case XmBROWSE_SELECT:
	return "XmBROWSE_SELECT";

    case XmMULTIPLE_SELECT:
	return "XmMULTIPLE_SELECT";

    case XmEXTENDED_SELECT:
	return "XmEXTENDED_SELECT";

    default:
	return "???";
    }
}

char *
XdbResizePolicy2String(int n)
{
    switch (n)
    {
    case XmRESIZE_NONE:
	return "XmRESIZE_NONE";

    case XmRESIZE_GROW:
	return "XmRESIZE_GROW";

    case XmRESIZE_ANY:
	return "XmRESIZE_ANY";

    case XmRESIZE_SWINDOW:
	return "XmRESIZE_SWINDOW";

    default:
	return "XmNscrollBarDisplayPolicy - illegal";
    }
}

char *
XdbSBDisplayPolicy2String(int n)
{
    switch (n)
    {
    case XmSTATIC:
	return "XmSTATIC";

    case XmAS_NEEDED:
	return "XmAS_NEEDED";

    default:
	return "XmNscrollBarDisplayPolicy - illegal";
    }
}

char *
XdbSBPlacement2String(int n)
{
    switch (n)
    {
    case XmTOP_LEFT:
	return "XmTOP_LEFT";

    case XmBOTTOM_LEFT:
	return "XmBOTTOM_LEFT";

    case XmTOP_RIGHT:
	return "XmTOP_RIGHT";

    case XmBOTTOM_RIGHT:
	return "XmBOTTOM_RIGHT";

    default:
	return "XmNscrollBarPlacement - illegal";
    }
}

char *
XdbListSizePolicy2String(int n)
{
    switch (n)
    {
    case XmVARIABLE:
	return "XmVARIABLE";

    case XmCONSTANT:
	return "XmCONSTANT";

    case XmRESIZE_IF_POSSIBLE:
	return "XmRESIZE_IF_POSSIBLE";

    default:
	return "XmNlistSizePolicy - illegal";
    }
}

char *
XdbAlignment2String(int n)
{
    switch (n)
    {
    case XmALIGNMENT_BEGINNING:
	return "XmALIGNMENT_BEGINNING";

    case XmALIGNMENT_CENTER:
	return "XmALIGNMENT_CENTER";

    case XmALIGNMENT_END:
	return "XmALIGNMENT_END";

    default:
	return "XmALIGNMENT - illegal";
    }
}

char *
XdbMenuType2String(int n)
{
    switch (n)
    {
    case XmMENU_OPTION:
	return "XmMENU_OPTION";

    case XmMENU_POPUP:
	return "XmMENU_POPUP";

    case XmMENU_PULLDOWN:
	return "XmMENU_PULLDOWN";

    default:
	return "???";
    }
}

char *
XdbNavigability2String(unsigned char n)
{
    switch (n)
    {
    case XmDESCENDANTS_NAVIGABLE:
	return "XmDESCENDANTS_NAVIGABLE";

    case XmDESCENDANTS_TAB_NAVIGABLE:
	return "XmDESCENDANTS_TAB_NAVIGABLE";

    case XmCONTROL_NAVIGABLE:
	return "XmCONTROL_NAVIGABLE";

    case XmNOT_NAVIGABLE:
	return "XmNOT_NAVIGABLE";

    case XmTAB_NAVIGABLE:
	return "XmTAB_NAVIGABLE";

    default:
	return "???";
    }
}

/*
 * For use with dmalloc, a malloc debugging package.
 * Mimick Xt behaviour ...
 */

#ifdef	USE_DMALLOC
#include <dmalloc.h>
#else
#include <X11/Xlibint.h>
#define	_malloc_leap(a,b,c)	Xmalloc(c)
#define	_calloc_leap(a,b,c,d)	Xcalloc(c,d)
#define	_realloc_leap(a,b,c,d)	Xrealloc(c,d)
#define	_free_leap(a,b,c)	Xfree(c)
#endif

extern void _XtAllocError(char *);

XtPointer
XdbMalloc(char *f, int l, int size)
{
    XtPointer r;

    if (size == 0)
    {
	size = 1;
    }

    r = _malloc_leap(f, l, size);

    if (r == NULL)
    {
	_XtAllocError("malloc");
    }

    return r;
}

XtPointer
XdbCalloc(char *f, int l, int count, int size)
{
    XtPointer p;

    if (!size)
    {
	count = size = 1;
    }

    p = _calloc_leap(f, l, count, size);

    if (p == NULL)
    {
	_XtAllocError("calloc");
    }

    return p;
}

XtPointer
XdbRealloc(char *f, int l, XtPointer p, int size)
{
    XtPointer r;

    if (size == 0)
    {
	size = 1;
    }

    if (p == NULL)
    {
	return _malloc_leap(f, l, size);
    }

    r = _realloc_leap(f, l, p, size);
    if (r == NULL)
    {
	_XtAllocError("realloc");
    }

    return r;
}

void
XdbFree(char *f, int l, XtPointer p)
{
    if (p)
    {
	_free_leap(f, l, p);
    }
}

char *
XdbHighlightMode2String(int mode)
{
    switch (mode)
    {
    case XmHIGHLIGHT_NORMAL:
	return "NORMAL";

    case XmHIGHLIGHT_SELECTED:
	return "SELECTED";

    case XmHIGHLIGHT_SECONDARY_SELECTED:
	return "SECONDARY_SELECTED";

    default:
	return "???";
    }
}

/*
 * Allow unconditional printing to the XdbFile
 */
void
XdbPrintString(char *s)
{
    XdbOpenFile();
    fprintf(XdbFile, "%s", s);
}

char *
XdbReason2String(int reason)
{
	switch (reason) {
	case XmCR_NONE:		return "XmCR_NONE";
	case XmCR_HELP:		return "XmCR_HELP";
	case XmCR_VALUE_CHANGED:return "XmCR_VALUE_CHANGED";
	case XmCR_INCREMENT:	return "XmCR_INCREMENT";
	case XmCR_DECREMENT:	return "XmCR_DECREMENT";
	case XmCR_PAGE_INCREMENT:return "XmCR_PAGE_INCREMENT";
	case XmCR_PAGE_DECREMENT:return "XmCR_PAGE_DECREMENT";
	case XmCR_TO_TOP:	return "XmCR_TO_TOP";
	case XmCR_TO_BOTTOM:	return "XmCR_TO_BOTTOM";
	case XmCR_DRAG:		return "XmCR_DRAG";
	case XmCR_ACTIVATE:	return "XmCR_ACTIVATE";
	case XmCR_ARM:		return "XmCR_ARM";
	case XmCR_DISARM:	return "XmCR_DISARM";
	case XmCR_DUMMY13:	return "XmCR_DUMMY13";
	case XmCR_DUMMY14:	return "XmCR_DUMMY14";
	case XmCR_DUMMY15:	return "XmCR_DUMMY15";
	case XmCR_MAP:		return "XmCR_MAP";
	case XmCR_UNMAP:	return "XmCR_UNMAP";
	case XmCR_FOCUS:	return "XmCR_FOCUS";
	case XmCR_LOSING_FOCUS:	return "XmCR_LOSING_FOCUS";
	case XmCR_MODIFYING_TEXT_VALUE:return "XmCR_MODIFYING_TEXT_VALUE";
	case XmCR_MOVING_INSERT_CURSOR:return "XmCR_MOVING_INSERT_CURSOR";
	case XmCR_EXECUTE:	return "XmCR_EXECUTE";
	case XmCR_SINGLE_SELECT:return "XmCR_SINGLE_SELECT";
	case XmCR_MULTIPLE_SELECT:return "XmCR_MULTIPLE_SELECT";
	case XmCR_EXTENDED_SELECT:return "XmCR_EXTENDED_SELECT";
	case XmCR_BROWSE_SELECT:return "XmCR_BROWSE_SELECT";
	case XmCR_DEFAULT_ACTION:return "XmCR_DEFAULT_ACTION";
	case XmCR_CLIPBOARD_DATA_REQUEST:return "XmCR_CLIPBOARD_DATA_REQUEST";
	case XmCR_CLIPBOARD_DATA_DELETE:return "XmCR_CLIPBOARD_DATA_DELETE";
	case XmCR_CASCADING:	return "XmCR_CASCADING";
	case XmCR_OK:		return "XmCR_OK";
	case XmCR_CANCEL:	return "XmCR_CANCEL";
	case XmCR_DUMMY33:	return "XmCR_DUMMY33";
	case XmCR_APPLY:	return "XmCR_APPLY";
	case XmCR_NO_MATCH:	return "XmCR_NO_MATCH";
	case XmCR_COMMAND_ENTERED:return "XmCR_COMMAND_ENTERED";
	case XmCR_COMMAND_CHANGED:return "XmCR_COMMAND_CHANGED";
	case XmCR_EXPOSE:	return "XmCR_EXPOSE";
	case XmCR_RESIZE:	return "XmCR_RESIZE";
	case XmCR_INPUT:	return "XmCR_INPUT";
	case XmCR_GAIN_PRIMARY:	return "XmCR_GAIN_PRIMARY";
	case XmCR_LOSE_PRIMARY:	return "XmCR_LOSE_PRIMARY";
	case XmCR_CREATE:	return "XmCR_CREATE";
	case XmCR_TEAR_OFF_ACTIVATE:return "XmCR_TEAR_OFF_ACTIVATE";
	case XmCR_TEAR_OFF_DEACTIVATE:return "XmCR_TEAR_OFF_DEACTIVATE";
	case XmCR_OBSCURED_TRAVERSAL:return "XmCR_OBSCURED_TRAVERSAL";
	case XmCR_PROTOCOLS:	return "XmCR_PROTOCOLS";
	default:		return "???";
	}
}

char *
XdbFocusChange2String(XmFocusChange c)
{
	switch (c) {
	case XmFOCUS_IN:	return	"XmFOCUS_IN";
	case XmFOCUS_OUT:	return	"XmFOCUS_OUT";
	case XmENTER:		return	"XmENTER";
	case XmLEAVE:		return	"XmLEAVE";
	default:			return	"???";
	}
}

char *
XdbNavigationType2String(XmNavigationType nt)
{
	switch (nt) {
	case XmNONE:				return "XmNONE";
	case XmTAB_GROUP:			return "XmTAB_GROUP";
	case XmSTICKY_TAB_GROUP:	return "XmSTICKY_TAB_GROUP";
	case XmEXCLUSIVE_TAB_GROUP:	return "XmEXCLUSIVE_TAB_GROUP";
	default:					return "???";
	}
}

char *
XdbEventType2String(int type)
{
	switch (type)
	{
	case KeyPress:		return("KeyPress");
	case KeyRelease:	return("KeyRelease");
	case ButtonPress:	return("ButtonPress");
	case ButtonRelease:	return("ButtonRelease");
	case KeymapNotify:	return("KeymapNotify");
	case MotionNotify:	return("MotionNotify");
	case EnterNotify:	return("EnterNotify");
	case LeaveNotify:	return("LeaveNotify");
	case FocusIn:		return("FocusIn");
	case FocusOut:		return("FocusOut");
	case Expose:		return("Expose");
	case GraphicsExpose:	return("GraphicsExpose");
	case NoExpose:		return("NoExpose");
	case ColormapNotify:	return("ColormapNotify");
	case PropertyNotify:	return("PropertyNotify");
	case VisibilityNotify:	return("VisibilityNotify");
	case ResizeRequest:	return("ResizeRequest");
	case CirculateNotify:	return("CirculateNotify");
	case ConfigureNotify:	return("ConfigureNotify");
	case DestroyNotify:	return("DestroyNotify");
	case GravityNotify:	return("GravityNotify");
	case MapNotify:		return("MapNotify");
	case ReparentNotify:	return("ReparentNotify");
	case UnmapNotify:	return("UnmapNotify");
	case CreateNotify:	return("CreateNotify");
	case CirculateRequest:	return("CirculateRequest");
	case ConfigureRequest:	return("ConfigureRequest");
	case MapRequest:	return("MapRequest");
	case MappingNotify:	return("MappingNotify");
	case ClientMessage:	return("ClientMessage");
	case SelectionClear:	return("SelectionClear");
	case SelectionNotify:	return("SelectionNotify");
	case SelectionRequest:	return("SelectionRequest");
	default:		return("UNKNOWN");
	}
}

char *
XdbFocusMode2String(int type)
{
	switch (type)
	{
	case NotifyNormal:		return("NotifyNormal");
	case NotifyGrab:		return("NotifyGrab");
	case NotifyUngrab:		return("NotifyUngrab");
	case NotifyWhileGrabbed:	return("NotifyWhileGrabbed");
	default:			return("UNKNOWN");
	}
}

char *
XdbFocusDetail2String(int type)
{
	switch (type)
	{
	case NotifyAncestor:		return("NotifyAncestor");
	case NotifyDetailNone:		return("NotifyDetailNone");
	case NotifyInferior:		return("NotifyInferior");
	case NotifyNonlinear:		return("NotifyNonlinear");
	case NotifyNonlinearVirtual:	return("NotifyNonlinearVirtual");
	case NotifyPointer:		return("NotifyPointer");
	case NotifyPointerRoot:		return("NotifyPointerRoot");
	case NotifyVirtual:		return("NotifyVirtual");
	default:			return("UNKNOWN");
	}
}
