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