| /* | |
| * 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 ); | |
| } |