/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* HISTORY
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: Mrmwci.c /main/16 1999/05/19 15:25:58 mgreess $"
#endif
#endif
/* *
* (c) Copyright 1996 Hewlett-Packard Company *
* (c) Copyright 1996 International Business Machines Corp. *
* (c) Copyright 1996 Sun Microsystems, Inc. *
* (c) Copyright 1996 Novell, Inc. *
* (c) Copyright 1989, 1990, 1996 Digital Equipment Corporation. *
* (c) Copyright 1996 FUJITSU LIMITED. *
* (c) Copyright 1996 Hitachi. *
*/
/*
*++
* FACILITY:
*
* UIL Resource Manager (URM):
*
* ABSTRACT:
*
* This module holds all routines, structures, and structure definitions
* required for the FT1 widget class information package (WCI). This
* package provides routines which register information about widget
* classes, and which retrieve information about widget classes
* as required by URM.
*
*--
*/
/*
*
* INCLUDE FILES
*
*/
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>
#include <Mrm/MrmAppl.h>
#include <Mrm/Mrm.h>
#include "MrmMsgI.h"
/*
*
* TABLE OF CONTENTS
*
*/
static int hash_function ( int l_length , char *c_value );
/*
*
* GLOBAL VARIABLE DECLARATIONS
*
*/
/*
* The list of registered classes, so they can be searched.
*/
externaldef(urm__wci) WCIClassDescPtr wci_cldesc_list = NULL;
/*
*
* OWN VARIABLE DECLARATIONS
*
*/
/*
** Hash tables
*/
/* The hash tables are initialized to NULL by default. */
static Boolean hash_hash_inited = FALSE;
static URMHashTableEntryPtr hash_az_hash_table [k_hash_table_size];
static Boolean cldesc_hash_inited = FALSE;
static URMHashTableEntryPtr cldesc_hash_table [k_hash_table_size];
/*
*++
*
*
* PROCEDURE DESCRIPTION:
*
* MrmRegisterClass saves the information needed to access the widget
* creation routine using the information in URM databases.
* type conversion of arglists.
*
* FORMAL PARAMETERS:
*
* class_code NOW UNUSED
* class_name NOW UNUSED
* create_name The case-sensitive name of the low-level
* create routine for the class; an example
* from the Motif toolkit is XmLabelCreate.
* Arguments are (parent, name, arglist, argcount)
* The string which names the class in UIL.
* creator The low-level routine named create_name
* class_record The toolkit class record for the class
*
* IMPLICIT INPUTS:
*
* IMPLICIT OUTPUTS:
*
* FUNCTION VALUE:
*
* MrmSUCCESS operation succeeded
* MrmFAILURE failure allocating class descriptor
*
* SIDE EFFECTS:
*
*--
*/
/*ARGSUSED*/
Cardinal
MrmRegisterClass (
#if NeedWidePrototypes
int class_code, /* unused */
#else
MrmType class_code, /* unused */
#endif
String class_name, /* unused */
String create_name,
Widget (* creator) (),
WidgetClass class_record)
{
Cardinal status = MrmRegisterClassWithCleanup(
class_code, class_name,
create_name, creator,
class_record, NULL);
return status;
}
/*ARGSUSED*/
Cardinal
MrmRegisterClassWithCleanup (
#if NeedWidePrototypes
int class_code, /* unused */
#else
MrmType class_code, /* unused */
#endif
String class_name, /* unused */
String create_name,
Widget (* creator) (),
WidgetClass class_record,
void (* cleanup) ())
{
/*
* Local variables
*/
WCIClassDescPtr cldesc; /* creator descriptor being written */
URMHashTableEntryPtr hash_entry; /* new hash entry */
_MrmProcessLock();
/*
* Allocate and fill in a new descriptor
*/
if (create_name == NULL)
{
_MrmProcessUnlock();
return MrmFAILURE;
}
cldesc = (WCIClassDescPtr) XtMalloc (sizeof(WCIClassDesc) +
strlen(create_name) + 1);
if ( cldesc == NULL )
{
_MrmProcessUnlock();
return MrmFAILURE;
}
cldesc->creator_name = (String) cldesc + sizeof(WCIClassDesc);
strcpy (cldesc->creator_name, create_name);
cldesc->validation = URMWCIClassDescValid;
cldesc->next_desc = wci_cldesc_list;
wci_cldesc_list = cldesc;
cldesc->creator = creator;
cldesc->class_record = class_record;
cldesc->cleanup = cleanup;
/*
* Enter the descriptor in the descriptor hash table
*/
hash_initialize (cldesc_hash_table, &cldesc_hash_inited);
hash_entry = (URMHashTableEntryPtr)
hash_insert_name (cldesc_hash_table, cldesc->creator_name);
/* Begin fixing CR 5573 */
if (hash_entry->az_value != NULL)
XtFree ((char *) hash_entry->az_value);
/* End fixing CR 5573 */
hash_entry->az_value = (char *) cldesc;
_MrmProcessUnlock();
return MrmSUCCESS;
}
Cardinal
Urm__WCI_UnregisterName (String name)
{
/*
* Make sure the hash table is initialized
*/
hash_initialize (hash_az_hash_table, &hash_hash_inited);
hash_delete_name (hash_az_hash_table, name);
return MrmSUCCESS; /* in any case */
}
/*
*++
*
* PROCEDURE DESCRIPTION:
*
* This routine inserts the names and their associated values into
* the hash table. No check for duplicate names is made - new
* values for duplicate names will override the previous value.
*
* FORMAL PARAMETERS:
*
* names A vector of case-sensitive callback routine names.
* values A vector of the corresponding routine addresses
* num_cb The number of entries in names and values.
*
* IMPLICIT INPUTS:
*
* IMPLICIT OUTPUTS:
*
* FUNCTION VALUE:
*
* MrmSUCCESS operation succeeded
*
* SIDE EFFECTS:
*
*--
*/
Cardinal
Urm__WCI_RegisterNames (String *names,
XtPointer *values,
MrmCount num_cb)
{
int ndx;
URMHashTableEntryPtr hash_entry;
char *current_name;
char *current_value;
/*
* Make sure the hash table is initialized
*/
hash_initialize (hash_az_hash_table, &hash_hash_inited);
/*
* Store each name-value pair in the hash table.
*/
for (ndx = 0 ; ndx < num_cb ; ndx++)
{
current_name = names [ndx];
current_value = values [ndx];
hash_entry = (URMHashTableEntryPtr)
hash_insert_name (hash_az_hash_table, current_name);
hash_entry -> az_value = current_value;
}
return MrmSUCCESS;
}
/*
*++
*
* PROCEDURE DESCRIPTION:
*
* This routin returns a pointer to the class descriptor for a class.
* The descriptor hash table is used to look up descriptors.
*
* FORMAL PARAMETERS:
*
* class_name Class name if class_code is URMwcUnknown
* class_return To return pointer to class descriptor
*
* IMPLICIT INPUTS:
*
* IMPLICIT OUTPUTS:
*
* FUNCTION VALUE:
*
* MrmSUCCESS operation succeeded
* MrmNOT_FOUND descriptor not found
*
* SIDE EFFECTS:
*
*--
*/
Cardinal
Urm__WCI_LookupClassDescriptor (String class_name,
WCIClassDescPtr *class_return)
{
/*
* Local variables
*/
URMHashTableEntryPtr hash_entry; /* hash entry found */
char err_msg[300];
/*
* Find a hash entry, and return the value.
*/
hash_entry = (URMHashTableEntryPtr)
hash_find_name (cldesc_hash_table, class_name);
if ( hash_entry == NULL )
{
*class_return = NULL;
sprintf (err_msg, _MrmMMsg_0051, class_name);
return Urm__UT_Error ("Urm__WCI_LookupClassDescriptor",
err_msg, NULL, NULL, MrmNOT_FOUND);
}
*class_return = (WCIClassDescPtr) hash_entry->az_value;
return MrmSUCCESS;
}
/*
*++
*
* PROCEDURE DESCRIPTION:
*
* This routine locates a class record for a given class name,
* and returns the widget class record associated with it.
* It searches for a match on either the name in the class record
* or the creation routine name.
*
* FORMAL PARAMETERS:
*
* clname the display name of the class
*
* IMPLICIT INPUTS:
*
* IMPLICIT OUTPUTS:
*
* FUNCTION VALUE:
*
* Class record pointer, or NULL if not found
*
* SIDE EFFECTS:
*
*--
*/
WidgetClass
Urm__WCI_GetClRecOfName (String clname)
{
/*
* Local variables
*/
WCIClassDescPtr cldesc; /* current class */
/*
* Search the class list
*/
for ( cldesc=wci_cldesc_list ; cldesc!=NULL ; cldesc=cldesc->next_desc)
{
if ( strcmp(clname,cldesc->creator_name) == 0 )
return cldesc->class_record;
if ( cldesc->class_record == NULL ) continue;
if ( strcmp(clname,cldesc->class_record->core_class.class_name) == 0 )
return cldesc->class_record;
}
return NULL;
}
/*
*++
*
* PROCEDURE DESCRIPTION:
*
* This routine gets, from the hash table, the value that corresponds
* to the given name. If no match is found, NULL is returned.
*
* FORMAL PARAMETERS:
*
* name case-sensitive name to be matched
* value_return to return value.
*
* IMPLICIT INPUTS:
*
* IMPLICIT OUTPUTS:
*
* FUNCTION VALUE:
*
* MrmSUCCESS operation succeeded
* MrmNOT_FOUND no match found
*
* SIDE EFFECTS:
*
*--
*/
Cardinal
Urm__WCI_LookupRegisteredName (String name,
XtPointer *value_return)
{
URMHashTableEntryPtr hash_entry;
hash_entry = (URMHashTableEntryPtr)
hash_find_name (hash_az_hash_table, name);
if (hash_entry == NULL)
{
*value_return = NULL;
return MrmNOT_FOUND;
}
else
{
*value_return = hash_entry->az_value;
return MrmSUCCESS;
}
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This routine initializes a hash table.
**
** FORMAL PARAMETERS:
**
** htable the hash table to initialize
** initflag if TRUE, the table is already initialized
**
** IMPLICIT INPUTS:
**
** IMPLICIT OUTPUTS:
**
** none
**
** FUNCTION VALUE:
**
** SIDE EFFECTS:
**
** none
**
**--
**/
void
hash_initialize (URMHashTableEntryPtr *htable,
Boolean *initflag)
{
int ndx; /* loop index */
/*
* Initialize only once
*/
if ( *initflag )
return;
for ( ndx=0 ; ndx<k_hash_table_size ; ndx++ )
htable[ndx] = NULL;
*initflag = TRUE;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This routine searches for a hash table entry of the same name
** as its parameters. If the entry is found, a pointer to the
** found hash table entry is returned as the value of the function.
** If no entry is found, a NULL pointer is returned.
**
** FORMAL PARAMETERS:
**
** htable the hash table to search
** c_text pointer to a null terminated string for name
**
** IMPLICIT INPUTS:
**
** IMPLICIT OUTPUTS:
**
** none
**
** FUNCTION VALUE:
**
** a pointer to a hash table entry, or NULL
**
** SIDE EFFECTS:
**
** none
**
**--
**/
URMHashTableEntryPtr
hash_find_name (URMHashTableEntryPtr *htable,
char *c_text)
{
int l_length;
URMHashTableEntryPtr az_current_name;
int l_hash_code;
int l_compare_result;
if (c_text == NULL) return(NULL);
/* obtain the hash code for the name */
l_length = strlen (c_text);
l_hash_code = hash_function( l_length, c_text );
/*
** chain along hash chain looking for symbol - exit loop under 3 condition
** 1) come to the end of the chain: name not found
** 2) find symbol: return this symbol
** 3) find node > symbol: name not found
*/
for (az_current_name = htable[ l_hash_code ];
az_current_name != NULL;
az_current_name = az_current_name->az_next_entry)
{
l_compare_result = strcmp (c_text, az_current_name->c_text);
if (l_compare_result == 0) /* c_text = current name */
{
/* found the entry we are looking for */
return az_current_name;
}
if (l_compare_result > 0) /* c_text > current name */
{
/* return NULL - name should be before this spot in list */
return (URMHashTableEntryPtr) NULL;
}
}
/* came to end of the list without finding the name */
return (URMHashTableEntryPtr) NULL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This routine searches for a name entry of the same name as its parameters.
** If the entry is found, a pointer to that entry node is
** returned as the value of the function. If no entry is found, one is
** allocated and inserted. In this case the value of the function is
** a pointer to the name entry created.
**
** Name entries are linked off of a hash table. Those
** entries that have the same hash code, are sorted according to the
** collating sequence. Thus the algorithm involves hashing the symbol and
** then following the chain for that hash code until one of the following
** conditions is met. 1) the identifier is found, then return a pointer
** to that entry. 2) come to the end of the chain or a hash table
** entry that comes later in the collating sequence than the symbol being
** searched for. In this case the name is inserted just prior to this
** point in the chain.
**
** FORMAL PARAMETERS:
**
** htable the hash table to update
** c_text pointer to a null terminated string for name
**
** IMPLICIT INPUTS:
**
** IMPLICIT OUTPUTS:
**
** htable may be updated with an additional name
**
** FUNCTION VALUE:
**
** a pointer to a hash table entry
**
** SIDE EFFECTS:
**
** may create a new entry and update the hash table
**
**--
**/
URMHashTableEntryPtr
hash_insert_name (URMHashTableEntryPtr *htable,
char *c_text)
{
int l_length;
URMHashTableEntryPtr az_previous_name;
URMHashTableEntryPtr az_current_name;
URMHashTableEntryPtr az_new_name;
int l_hash_code;
int l_compare_result;
/*
** algorithm keeps 2 pointers, one for the previous name and one
** for the current name. This permits easy insertion of a new name
*/
/* obtain the hash code of for the name */
l_length = strlen (c_text);
l_hash_code = hash_function( l_length, c_text );
/*
** chain along hash chain looking for symbol - exit loop under 3 condition
** 1) come to the end of the chain: insert new node on end
** 2) find symbol: return this symbol
** 3) find node > symbol: insert new node prior to current node
*/
for (az_current_name = htable[ l_hash_code ],
az_previous_name = (URMHashTableEntryPtr) NULL;
az_current_name != (URMHashTableEntryPtr) NULL;
az_previous_name = az_current_name,
az_current_name = az_current_name->az_next_entry)
{
l_compare_result = strcmp (c_text, az_current_name->c_text);
if (l_compare_result == 0) /* c_text = current name */
{
/* found the name we are looking for */
return az_current_name;
}
if (l_compare_result > 0) /* c_text > current name */
{
/* exit the loop to insert just prior to current name */
goto insert_name;
}
}
insert_name:
/*
** name is not in the table so it must be inserted between the
** az_previous_name and az_current_name entries.
*/
/* allocate and initialize the name entry, including the null */
az_new_name = (URMHashTableEntryPtr)
XtMalloc (sizeof(URMHashTableEntry)+l_length+1);
az_new_name -> az_value = (char *) NULL;
UrmBCopy (c_text, az_new_name -> c_text, l_length + 1);
/*
** link the name entry into the hash table
*/
az_new_name->az_next_entry = az_current_name;
if (az_previous_name == (URMHashTableEntryPtr) NULL)
htable[ l_hash_code ] = az_new_name;
else
az_previous_name->az_next_entry = az_new_name;
return az_new_name;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** just like hash_insert_name but removes the item instead
**--
*/
URMHashTableEntryPtr
hash_delete_name (URMHashTableEntryPtr *htable,
char *c_text)
{
int l_length;
URMHashTableEntryPtr az_previous_name;
URMHashTableEntryPtr az_current_name;
int l_hash_code;
int l_compare_result;
/*
** algorithm keeps 2 pointers, one for the previous name and one
** for the current name. This permits easy deletion of a name
*/
/* obtain the hash code of for the name */
l_length = strlen (c_text);
l_hash_code = hash_function( l_length, c_text );
/*
** chain along hash chain looking for symbol - exit loop under 3 condition
** 1) come to the end of the chain: too far; return
** 2) find symbol: delete
** 3) find node > symbol: too far; return
*/
for (az_current_name = htable[ l_hash_code ],
az_previous_name = (URMHashTableEntryPtr) NULL;
az_current_name != (URMHashTableEntryPtr) NULL;
az_previous_name = az_current_name,
az_current_name = az_current_name->az_next_entry)
{
l_compare_result = strcmp (c_text, az_current_name->c_text);
if (l_compare_result == 0) /* c_text = current name */
{
/* found the name we are looking for */
goto delete_name;
}
if (l_compare_result > 0) /* c_text > current name */
{
/* return NULL - name should be before this spot in list */
return (URMHashTableEntryPtr) NULL;
}
}
/* came to end of the list without finding the name */
return (URMHashTableEntryPtr) NULL;
delete_name:
/*
** remove the name entry from the hash table
*/
if (az_previous_name == (URMHashTableEntryPtr) NULL)
htable[ l_hash_code ] = az_current_name->az_next_entry;
else
az_previous_name->az_next_entry = az_current_name->az_next_entry;
XtFree((char*)az_current_name);
return (URMHashTableEntryPtr) NULL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This procedure is a hashing function. It takes a length and a
** pointer to a value. Using this value as a string, the function
** returns an integer in the range of 0 to sym_k_hash_table_limit-1.
**
** FORMAL PARAMETERS:
**
** l_length length of the value in bytes not including null
** c_value a null terminated string
**
** IMPLICIT INPUTS:
**
** sym_k_hash_table_limit
**
** IMPLICIT OUTPUTS:
**
** none
**
** FUNCTION VALUE:
**
** integer (the hash code) in range 0 to sym_k_hash_table_limit-1
**
** SIDE EFFECTS:
**
** none
**
**--
**/
static int
hash_function(int l_length,
char *c_value)
{
#ifdef WORD64
#define _shift 3
static unsigned int XmConst mask[ 8 ] =
{ 0x00000000000000FF, 0x000000000000FFFF,
0x0000000000FFFFFF, 0x00000000FFFFFFFF,
0x00000000FFFFFFFF, 0x0000FFFFFFFFFFFF,
0x00FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, };
#else
#define _shift 2
static unsigned int XmConst mask[ 4 ] =
{ 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF };
#endif
unsigned int l_hash_code;
unsigned int al_value[20];
int l_limit;
int l_extra;
int i;
/* BEGIN OSF Fix CR 5232 */
/* Don't go past array bounds */
if (l_length > (sizeof(int) * 20)) l_length = sizeof(int) * 20;
/* END OSF Fix CR 5232 */
l_limit = (l_length-1) >> _shift; /* divide by wordsize */
/* BEGIN OSF Fix CR 5232 */
l_extra = (l_length-1) & _shift; /* remainder from divide by wordsize */
/* END OSF Fix CR 5232 */
bzero((char *)al_value, sizeof(int) * 20);
strncpy((char *)al_value, c_value, l_length);
l_hash_code = 0;
for (i = 0 ; i < l_limit ; i++)
l_hash_code = l_hash_code ^ al_value[ i ];
l_hash_code = l_hash_code ^ (al_value[ i ] & mask[ l_extra ]);
/* BEGIN OSF Fix CR 5232 */
/* Make sure result isn't negative */
return abs((int)(l_hash_code % k_hash_table_size));
/* END OSF Fix CR 5232 */
}