373 lines
9.1 KiB
C
373 lines
9.1 KiB
C
/*
|
|
* Atom table functions
|
|
*
|
|
* Copyright 1993 Alexandre Julliard
|
|
*/
|
|
|
|
/*
|
|
* Current limitations:
|
|
*
|
|
* - The code assumes that LocalAlloc() returns a block aligned on a
|
|
* 4-bytes boundary (because of the shifting done in HANDLETOATOM).
|
|
* If this is not the case, the allocation code will have to be changed.
|
|
*
|
|
* - Integer atoms created with MAKEINTATOM are not supported. This is
|
|
* because they can't generally be differentiated from string constants
|
|
* located below 0x10000 in the emulation library. If you need
|
|
* integer atoms, use the "#1234" form.
|
|
*
|
|
* 13/Feb, miguel
|
|
* Changed the calls to LocalAlloc to LocalAlign. When compiling WINELIB
|
|
* you call a special version of LocalAlloc that would do the alignement.
|
|
* When compiling the emulator we depend on LocalAlloc returning the
|
|
* aligned block. Needed to test the Library.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "user.h"
|
|
#include "atom.h"
|
|
#include "prototypes.h"
|
|
#ifndef WINELIB
|
|
#include "heap.h"
|
|
#endif
|
|
|
|
#define DEFAULT_ATOMTABLE_SIZE 37
|
|
#define MIN_STR_ATOM 0xc000
|
|
|
|
#ifdef WINELIB
|
|
#define ATOMTOHANDLE
|
|
#define HANDLETOATOM
|
|
#else
|
|
#define ATOMTOHANDLE(atom) ((HANDLE)(atom) << 2)
|
|
#define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
|
|
#endif
|
|
|
|
#ifdef WINELIB
|
|
static ATOMTABLE * localTable = NULL;
|
|
#undef LOCALATOMTABLE
|
|
#define LOCALATOMTABLE() &localTable
|
|
#endif
|
|
|
|
static ATOMTABLE * globalTable = NULL;
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_InitTable
|
|
*/
|
|
static BOOL ATOM_InitTable( ATOMTABLE ** table, WORD entries )
|
|
{
|
|
int i;
|
|
HANDLE handle;
|
|
|
|
if (table == &globalTable)
|
|
{
|
|
handle = USER_HEAP_ALLOC(LMEM_MOVEABLE, sizeof(ATOMTABLE) +
|
|
(entries-1) * sizeof(HANDLE) );
|
|
if (!handle)
|
|
return FALSE;
|
|
*table = (ATOMTABLE *) USER_HEAP_ADDR( handle );
|
|
}
|
|
else
|
|
{
|
|
handle = LocalAlign ( LMEM_MOVEABLE, sizeof(ATOMTABLE) +
|
|
(entries-1) * sizeof(HANDLE) );
|
|
if (!handle)
|
|
return FALSE;
|
|
*table = (ATOMTABLE *) LocalLock( handle );
|
|
}
|
|
|
|
(*table)->size = entries;
|
|
for (i = 0; i < entries; i++)
|
|
(*table)->entries[i] = 0;
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ATOM_Init
|
|
*
|
|
* Global table initialisation.
|
|
*/
|
|
BOOL ATOM_Init()
|
|
{
|
|
return ATOM_InitTable( &globalTable, DEFAULT_ATOMTABLE_SIZE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_MakePtr
|
|
*
|
|
* Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
|
|
* Is is assumed that the atom is in the same segment as the table.
|
|
*/
|
|
static ATOMENTRY * ATOM_MakePtr( ATOMTABLE * table, HANDLE handle )
|
|
{
|
|
#ifdef WINELIB
|
|
return (ATOMENTRY *) LocalLock (handle);
|
|
#else
|
|
return (ATOMENTRY *) (((int)table & 0xffff0000) | (int)handle);
|
|
#endif
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_Hash
|
|
*/
|
|
static WORD ATOM_Hash( WORD entries, LPCSTR str, WORD len )
|
|
{
|
|
WORD i, hash = 0;
|
|
|
|
for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
|
|
return hash % entries;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_AddAtom
|
|
*/
|
|
static ATOM ATOM_AddAtom( ATOMTABLE * table, LPCSTR str )
|
|
{
|
|
WORD hash;
|
|
HANDLE entry;
|
|
ATOMENTRY * entryPtr;
|
|
int len;
|
|
|
|
if ((len = strlen( str )) > 255) len = 255;
|
|
|
|
/* Check for integer atom */
|
|
/* if (!((int)str & 0xffff0000)) return (ATOM)((int)str & 0xffff); */
|
|
if (str[0] == '#') return atoi( &str[1] );
|
|
|
|
hash = ATOM_Hash( table->size, str, len );
|
|
entry = table->entries[hash];
|
|
while (entry)
|
|
{
|
|
entryPtr = ATOM_MakePtr( table, entry );
|
|
if ((entryPtr->length == len) &&
|
|
(!strncasecmp( entryPtr->str, str, len )))
|
|
{
|
|
entryPtr->refCount++;
|
|
return HANDLETOATOM( entry );
|
|
}
|
|
entry = entryPtr->next;
|
|
}
|
|
|
|
if (table == globalTable)
|
|
{
|
|
entry = (int) USER_HEAP_ALLOC(LMEM_MOVEABLE,
|
|
sizeof(ATOMENTRY)+len-1 ) & 0xffff;
|
|
}
|
|
else
|
|
{
|
|
entry = (int) LocalAlign(LMEM_MOVEABLE,
|
|
sizeof(ATOMENTRY)+len-1 ) & 0xffff;
|
|
}
|
|
|
|
if (!entry) return 0;
|
|
entryPtr = ATOM_MakePtr( table, entry );
|
|
entryPtr->next = table->entries[hash];
|
|
entryPtr->refCount = 1;
|
|
entryPtr->length = len;
|
|
memcpy( entryPtr->str, str, len );
|
|
table->entries[hash] = entry;
|
|
return HANDLETOATOM( entry );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_DeleteAtom
|
|
*/
|
|
static ATOM ATOM_DeleteAtom( ATOMTABLE * table, ATOM atom )
|
|
{
|
|
ATOMENTRY * entryPtr;
|
|
HANDLE entry, *prevEntry;
|
|
WORD hash;
|
|
|
|
if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
|
|
|
|
entry = ATOMTOHANDLE( atom );
|
|
entryPtr = ATOM_MakePtr( table, entry );
|
|
|
|
/* Find previous atom */
|
|
hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
|
|
prevEntry = &table->entries[hash];
|
|
while (*prevEntry && *prevEntry != entry)
|
|
{
|
|
ATOMENTRY * prevEntryPtr = ATOM_MakePtr( table, *prevEntry );
|
|
prevEntry = &prevEntryPtr->next;
|
|
}
|
|
if (!*prevEntry) return atom;
|
|
|
|
/* Delete atom */
|
|
if (--entryPtr->refCount == 0)
|
|
{
|
|
*prevEntry = entryPtr->next;
|
|
if (table == globalTable)
|
|
USER_HEAP_FREE(entry);
|
|
else
|
|
LocalFree( entry );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_FindAtom
|
|
*/
|
|
static ATOM ATOM_FindAtom( ATOMTABLE * table, LPCSTR str )
|
|
{
|
|
WORD hash;
|
|
HANDLE entry;
|
|
int len;
|
|
|
|
if ((len = strlen( str )) > 255) len = 255;
|
|
|
|
/* Check for integer atom */
|
|
/* if (!((int)str & 0xffff0000)) return (ATOM)((int)str & 0xffff); */
|
|
if (str[0] == '#') return atoi( &str[1] );
|
|
|
|
hash = ATOM_Hash( table->size, str, len );
|
|
entry = table->entries[hash];
|
|
while (entry)
|
|
{
|
|
ATOMENTRY * entryPtr = ATOM_MakePtr( table, entry );
|
|
if ((entryPtr->length == len) &&
|
|
(!strncasecmp( entryPtr->str, str, len )))
|
|
return HANDLETOATOM( entry );
|
|
entry = entryPtr->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ATOM_GetAtomName
|
|
*/
|
|
static WORD ATOM_GetAtomName( ATOMTABLE * table, ATOM atom,
|
|
LPSTR buffer, short count )
|
|
{
|
|
ATOMENTRY * entryPtr;
|
|
HANDLE entry;
|
|
char * strPtr;
|
|
int len;
|
|
char text[8];
|
|
|
|
if (!count) return 0;
|
|
if (atom < MIN_STR_ATOM)
|
|
{
|
|
sprintf( text, "#%d", atom );
|
|
len = strlen(text);
|
|
strPtr = text;
|
|
}
|
|
else
|
|
{
|
|
entry = ATOMTOHANDLE( atom );
|
|
entryPtr = ATOM_MakePtr( table, entry );
|
|
len = entryPtr->length;
|
|
strPtr = entryPtr->str;
|
|
}
|
|
if (len >= count) len = count-1;
|
|
memcpy( buffer, strPtr, len );
|
|
buffer[len] = '\0';
|
|
return len;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* InitAtomTable (KERNEL.68)
|
|
*/
|
|
BOOL InitAtomTable( WORD entries )
|
|
{
|
|
return ATOM_InitTable( LOCALATOMTABLE(), entries );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetAtomHandle (KERNEL.73)
|
|
*/
|
|
HANDLE GetAtomHandle( ATOM atom )
|
|
{
|
|
if (atom < MIN_STR_ATOM) return 0;
|
|
return ATOMTOHANDLE( atom );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* AddAtom (KERNEL.70)
|
|
*/
|
|
ATOM AddAtom( LPCSTR str )
|
|
{
|
|
if (!*LOCALATOMTABLE()) InitAtomTable( DEFAULT_ATOMTABLE_SIZE );
|
|
return ATOM_AddAtom( *LOCALATOMTABLE(), str );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DeleteAtom (KERNEL.71)
|
|
*/
|
|
ATOM DeleteAtom( ATOM atom )
|
|
{
|
|
if (!*LOCALATOMTABLE()) InitAtomTable( DEFAULT_ATOMTABLE_SIZE );
|
|
return ATOM_DeleteAtom( *LOCALATOMTABLE(), atom );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* FindAtom (KERNEL.69)
|
|
*/
|
|
ATOM FindAtom( LPCSTR str )
|
|
{
|
|
if (!*LOCALATOMTABLE()) InitAtomTable( DEFAULT_ATOMTABLE_SIZE );
|
|
return ATOM_FindAtom( *LOCALATOMTABLE(), str );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetAtomName (KERNEL.72)
|
|
*/
|
|
WORD GetAtomName( ATOM atom, LPSTR buffer, short count )
|
|
{
|
|
if (!*LOCALATOMTABLE()) InitAtomTable( DEFAULT_ATOMTABLE_SIZE );
|
|
return ATOM_GetAtomName( *LOCALATOMTABLE(), atom, buffer, count );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalAddAtom (USER.268)
|
|
*/
|
|
ATOM GlobalAddAtom( LPCSTR str )
|
|
{
|
|
return ATOM_AddAtom( globalTable, str );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalDeleteAtom (USER.269)
|
|
*/
|
|
ATOM GlobalDeleteAtom( ATOM atom )
|
|
{
|
|
return ATOM_DeleteAtom( globalTable, atom );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalFindAtom (USER.270)
|
|
*/
|
|
ATOM GlobalFindAtom( LPCSTR str )
|
|
{
|
|
return ATOM_FindAtom( globalTable, str );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GlobalGetAtomName (USER.271)
|
|
*/
|
|
WORD GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
|
|
{
|
|
return ATOM_GetAtomName( globalTable, atom, buffer, count );
|
|
}
|