4 * Copyright 1993, 1994, 1995 Alexandre Julliard
10 * - The code assumes that LocalAlloc() returns a block aligned on a
11 * 4-bytes boundary (because of the shifting done in HANDLETOATOM).
12 * If this is not the case, the allocation code will have to be changed.
14 * - Integer atoms created with MAKEINTATOM are not supported. This is
15 * because they can't generally be differentiated from string constants
16 * located below 0x10000 in the emulation library. If you need
17 * integer atoms, use the "#1234" form.
20 * Changed the calls to LocalAlloc to LocalAlign. When compiling WINELIB
21 * you call a special version of LocalAlloc that would do the alignement.
22 * When compiling the emulator we depend on LocalAlloc returning the
23 * aligned block. Needed to test the Library.
34 #include "stackframe.h"
37 #define DEFAULT_ATOMTABLE_SIZE 37
38 #define MIN_STR_ATOM 0xc000
40 #define ATOMTOHANDLE(atom) ((HANDLE)(atom) << 2)
41 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
43 #define HAS_ATOM_TABLE(sel) \
44 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
46 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
47 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
50 #define USER_HeapSel 0
53 /***********************************************************************
56 static WORD ATOM_InitTable( WORD selector, WORD entries )
62 /* Allocate the table */
64 handle = LOCAL_Alloc( selector, LMEM_FIXED,
65 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE) );
66 if (!handle) return 0;
67 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
68 table->size = entries;
69 for (i = 0; i < entries; i++) table->entries[i] = 0;
71 /* Store a pointer to the table in the instance data */
73 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
78 /***********************************************************************
81 * Global table initialisation.
85 return ATOM_InitTable( USER_HeapSel, DEFAULT_ATOMTABLE_SIZE );
89 /***********************************************************************
92 * Return a pointer to the atom table of a given segment, creating
95 static ATOMTABLE * ATOM_GetTable( WORD selector, BOOL create )
97 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
100 if (!create) return NULL;
101 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
103 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
107 /***********************************************************************
110 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
112 static ATOMENTRY * ATOM_MakePtr( WORD selector, HANDLE handle )
114 return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
118 /***********************************************************************
121 static WORD ATOM_Hash( WORD entries, LPCSTR str, WORD len )
125 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
126 return hash % entries;
130 /***********************************************************************
133 static ATOM ATOM_AddAtom( WORD selector, LPCSTR str )
137 ATOMENTRY * entryPtr;
141 if ((len = strlen( str )) > 255) len = 255;
143 /* Check for integer atom */
144 /* if (!((int)str & 0xffff0000)) return (ATOM)((int)str & 0xffff); */
145 if (str[0] == '#') return atoi( &str[1] );
147 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
148 hash = ATOM_Hash( table->size, str, len );
149 entry = table->entries[hash];
152 entryPtr = ATOM_MakePtr( selector, entry );
153 if ((entryPtr->length == len) &&
154 (!strncasecmp( entryPtr->str, str, len )))
156 entryPtr->refCount++;
157 return HANDLETOATOM( entry );
159 entry = entryPtr->next;
162 entry = LOCAL_Alloc( selector, LMEM_FIXED, sizeof(ATOMENTRY)+len-1 );
163 if (!entry) return 0;
164 entryPtr = ATOM_MakePtr( selector, entry );
165 entryPtr->next = table->entries[hash];
166 entryPtr->refCount = 1;
167 entryPtr->length = len;
168 memcpy( entryPtr->str, str, len );
169 table->entries[hash] = entry;
170 return HANDLETOATOM( entry );
174 /***********************************************************************
177 static ATOM ATOM_DeleteAtom( WORD selector, ATOM atom )
179 ATOMENTRY * entryPtr;
181 HANDLE entry, *prevEntry;
184 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
186 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
187 entry = ATOMTOHANDLE( atom );
188 entryPtr = ATOM_MakePtr( selector, entry );
190 /* Find previous atom */
191 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
192 prevEntry = &table->entries[hash];
193 while (*prevEntry && *prevEntry != entry)
195 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
196 prevEntry = &prevEntryPtr->next;
198 if (!*prevEntry) return atom;
201 if (--entryPtr->refCount == 0)
203 *prevEntry = entryPtr->next;
204 LOCAL_Free( selector, entry );
210 /***********************************************************************
213 static ATOM ATOM_FindAtom( WORD selector, LPCSTR str )
220 if ((len = strlen( str )) > 255) len = 255;
222 /* Check for integer atom */
223 /* if (!((int)str & 0xffff0000)) return (ATOM)((int)str & 0xffff); */
224 if (str[0] == '#') return atoi( &str[1] );
226 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
227 hash = ATOM_Hash( table->size, str, len );
228 entry = table->entries[hash];
231 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
232 if ((entryPtr->length == len) &&
233 (!strncasecmp( entryPtr->str, str, len )))
234 return HANDLETOATOM( entry );
235 entry = entryPtr->next;
241 /***********************************************************************
244 static WORD ATOM_GetAtomName( WORD selector, ATOM atom,
245 LPSTR buffer, short count )
248 ATOMENTRY * entryPtr;
254 if (!count) return 0;
255 if (atom < MIN_STR_ATOM)
257 sprintf( text, "#%d", atom );
263 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
264 entry = ATOMTOHANDLE( atom );
265 entryPtr = ATOM_MakePtr( selector, entry );
266 len = entryPtr->length;
267 strPtr = entryPtr->str;
269 if (len >= count) len = count-1;
270 memcpy( buffer, strPtr, len );
276 /***********************************************************************
277 * InitAtomTable (KERNEL.68)
279 WORD InitAtomTable( WORD entries )
281 return ATOM_InitTable( CURRENT_DS, entries );
285 /***********************************************************************
286 * GetAtomHandle (KERNEL.73)
288 HANDLE GetAtomHandle( ATOM atom )
290 if (atom < MIN_STR_ATOM) return 0;
291 return ATOMTOHANDLE( atom );
295 /***********************************************************************
296 * AddAtom (KERNEL.70)
298 ATOM AddAtom( LPCSTR str )
300 return ATOM_AddAtom( CURRENT_DS, str );
304 /***********************************************************************
305 * DeleteAtom (KERNEL.71)
307 ATOM DeleteAtom( ATOM atom )
309 return ATOM_DeleteAtom( CURRENT_DS, atom );
313 /***********************************************************************
314 * FindAtom (KERNEL.69)
316 ATOM FindAtom( LPCSTR str )
318 return ATOM_FindAtom( CURRENT_DS, str );
322 /***********************************************************************
323 * GetAtomName (KERNEL.72)
325 WORD GetAtomName( ATOM atom, LPSTR buffer, short count )
327 return ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
331 /***********************************************************************
332 * LocalAddAtom (USER.268)
334 ATOM LocalAddAtom( LPCSTR str )
336 return ATOM_AddAtom( USER_HeapSel, str );
340 /***********************************************************************
341 * LocalDeleteAtom (USER.269)
343 ATOM LocalDeleteAtom( ATOM atom )
345 return ATOM_DeleteAtom( USER_HeapSel, atom );
349 /***********************************************************************
350 * LocalFindAtom (USER.270)
352 ATOM LocalFindAtom( LPCSTR str )
354 return ATOM_FindAtom( USER_HeapSel, str );
358 /***********************************************************************
359 * LocalGetAtomName (USER.271)
361 WORD LocalGetAtomName( ATOM atom, LPSTR buffer, short count )
363 return ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );