#include "Xlibint.h"
#include "Xutil.h"
#ifdef XTHREADS
#include "locking.h"
#endif
#define INITHASHMASK 63
typedef struct _TableEntryRec {
XID rid;
XContext context;
XPointer data;
struct _TableEntryRec *next;
} TableEntryRec, *TableEntry;
typedef struct _XContextDB {
TableEntry *table;
int mask;
int numentries;
#ifdef XTHREADS
LockInfoRec linfo;
#endif
} DBRec, *DB;
#ifdef MOTIFBC
static DB NullDB = (DB)0;
#endif
#define Hash(db,rid,context) \
(db)->table[(((rid) << 1) + context) & (db)->mask]
static void ResizeTable(DB db)
{
TableEntry *otable;
register TableEntry entry, next, *pold, *head;
register int i, j;
otable = db->table;
for (i = INITHASHMASK+1; (i + i) < db->numentries; )
i += i;
db->table = (TableEntry *) Xcalloc((unsigned)i, sizeof(TableEntry));
if (!db->table) {
db->table = otable;
return;
}
j = db->mask + 1;
db->mask = i - 1;
for (pold = otable ; --j >= 0; pold++) {
for (entry = *pold; entry; entry = next) {
next = entry->next;
head = &Hash(db, entry->rid, entry->context);
entry->next = *head;
*head = entry;
}
}
Xfree((char *) otable);
}
static void _XFreeContextDB(Display *display)
{
register DB db;
register int i;
register TableEntry *pentry, entry, next;
db = display->context_db;
if (db) {
for (i = db->mask + 1, pentry = db->table ; --i >= 0; pentry++) {
for (entry = *pentry; entry; entry = next) {
next = entry->next;
Xfree((char *)entry);
}
}
Xfree((char *) db->table);
_XFreeMutex(&db->linfo);
Xfree((char *) db);
}
}
int XSaveContext(
Display *display,
register XID rid,
register XContext context,
_Xconst char* data)
{
DB *pdb;
register DB db;
TableEntry *head;
register TableEntry entry;
#ifdef MOTIFBC
if (!display) {
pdb = &NullDB;
db = *pdb;
} else
#endif
{
LockDisplay(display);
pdb = &display->context_db;
db = *pdb;
UnlockDisplay(display);
}
if (!db) {
db = (DB) Xmalloc(sizeof(DBRec));
if (!db)
return XCNOMEM;
db->mask = INITHASHMASK;
db->table = (TableEntry *)Xcalloc(db->mask + 1, sizeof(TableEntry));
if (!db->table) {
Xfree((char *)db);
return XCNOMEM;
}
db->numentries = 0;
_XCreateMutex(&db->linfo);
#ifdef MOTIFBC
if (!display) *pdb = db; else
#endif
{
LockDisplay(display);
*pdb = db;
display->free_funcs->context_db = _XFreeContextDB;
UnlockDisplay(display);
}
}
_XLockMutex(&db->linfo);
head = &Hash(db, rid, context);
_XUnlockMutex(&db->linfo);
for (entry = *head; entry; entry = entry->next) {
if (entry->rid == rid && entry->context == context) {
entry->data = (XPointer)data;
return 0;
}
}
entry = (TableEntry) Xmalloc(sizeof(TableEntryRec));
if (!entry)
return XCNOMEM;
entry->rid = rid;
entry->context = context;
entry->data = (XPointer)data;
entry->next = *head;
*head = entry;
_XLockMutex(&db->linfo);
db->numentries++;
if (db->numentries > (db->mask << 2))
ResizeTable(db);
_XUnlockMutex(&db->linfo);
return 0;
}
int XFindContext(display, rid, context, data)
Display *display;
register XID rid;
register XContext context;
XPointer *data;
{
register DB db;
register TableEntry entry;
#ifdef MOTIFBC
if (!display) db = NullDB; else
#endif
{
LockDisplay(display);
db = display->context_db;
UnlockDisplay(display);
}
if (!db)
return XCNOENT;
_XLockMutex(&db->linfo);
for (entry = Hash(db, rid, context); entry; entry = entry->next)
{
if (entry->rid == rid && entry->context == context) {
*data = (XPointer)entry->data;
_XUnlockMutex(&db->linfo);
return 0;
}
}
_XUnlockMutex(&db->linfo);
return XCNOENT;
}
int XDeleteContext(display, rid, context)
Display *display;
register XID rid;
register XContext context;
{
register DB db;
register TableEntry entry, *prev;
#ifdef MOTIFBC
if (!display) db = NullDB; else
#endif
{
LockDisplay(display);
db = display->context_db;
UnlockDisplay(display);
}
if (!db)
return XCNOENT;
_XLockMutex(&db->linfo);
for (prev = &Hash(db, rid, context);
(entry = *prev);
prev = &entry->next) {
if (entry->rid == rid && entry->context == context) {
*prev = entry->next;
Xfree((char *) entry);
db->numentries--;
if (db->numentries < db->mask && db->mask > INITHASHMASK)
ResizeTable(db);
_XUnlockMutex(&db->linfo);
return 0;
}
}
_XUnlockMutex(&db->linfo);
return XCNOENT;
}