4 * Copyright 1993, 1994, 1995 Alexandre Julliard
8 * Warning: The code assumes that LocalAlloc() returns a block aligned
9 * on a 4-bytes boundary (because of the shifting done in
10 * HANDLETOATOM). If this is not the case, the allocation code will
22 #include "stackframe.h"
30 #define DEFAULT_ATOMTABLE_SIZE 37
31 #define MIN_STR_ATOM 0xc000
32 #define MAX_ATOM_LEN 255
34 #define ATOMTOHANDLE(atom) ((HANDLE)(atom) << 2)
35 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
37 #define HAS_ATOM_TABLE(sel) \
38 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
40 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
41 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
44 /***********************************************************************
47 static HANDLE16 ATOM_InitTable( WORD selector, WORD entries )
53 /* Allocate the table */
55 handle = LOCAL_Alloc( selector, LMEM_FIXED,
56 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE) );
57 if (!handle) return 0;
58 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
59 table->size = entries;
60 for (i = 0; i < entries; i++) table->entries[i] = 0;
62 /* Store a pointer to the table in the instance data */
64 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
69 /***********************************************************************
72 * Global table initialisation.
76 return ATOM_InitTable( USER_HeapSel, DEFAULT_ATOMTABLE_SIZE ) != 0;
80 /***********************************************************************
83 * Return a pointer to the atom table of a given segment, creating
86 static ATOMTABLE * ATOM_GetTable( WORD selector, BOOL create )
88 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
91 if (!create) return NULL;
92 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
93 /* Reload ptr in case it moved in linear memory */
94 ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
96 return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
100 /***********************************************************************
103 * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
105 static ATOMENTRY * ATOM_MakePtr( WORD selector, HANDLE handle )
107 return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
111 /***********************************************************************
114 static WORD ATOM_Hash( WORD entries, LPCSTR str, WORD len )
118 for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
119 return hash % entries;
123 /***********************************************************************
126 static ATOM ATOM_AddAtom( WORD selector, LPCSTR str )
130 ATOMENTRY * entryPtr;
134 if (str[0] == '#') return atoi( &str[1] ); /* Check for integer atom */
135 if ((len = strlen( str )) > 255) len = 255;
136 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
137 hash = ATOM_Hash( table->size, str, len );
138 entry = table->entries[hash];
141 entryPtr = ATOM_MakePtr( selector, entry );
142 if ((entryPtr->length == len) &&
143 (!lstrncmpi32A( entryPtr->str, str, len )))
145 entryPtr->refCount++;
146 return HANDLETOATOM( entry );
148 entry = entryPtr->next;
151 entry = LOCAL_Alloc( selector, LMEM_FIXED, sizeof(ATOMENTRY)+len-1 );
152 if (!entry) return 0;
153 /* Reload the table ptr in case it moved in linear memory */
154 table = ATOM_GetTable( selector, FALSE );
155 entryPtr = ATOM_MakePtr( selector, entry );
156 entryPtr->next = table->entries[hash];
157 entryPtr->refCount = 1;
158 entryPtr->length = len;
159 memcpy( entryPtr->str, str, len );
160 table->entries[hash] = entry;
161 return HANDLETOATOM( entry );
165 /***********************************************************************
168 static ATOM ATOM_DeleteAtom( WORD selector, ATOM atom )
170 ATOMENTRY * entryPtr;
172 HANDLE entry, *prevEntry;
175 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
177 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
178 entry = ATOMTOHANDLE( atom );
179 entryPtr = ATOM_MakePtr( selector, entry );
181 /* Find previous atom */
182 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
183 prevEntry = &table->entries[hash];
184 while (*prevEntry && *prevEntry != entry)
186 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
187 prevEntry = &prevEntryPtr->next;
189 if (!*prevEntry) return atom;
192 if (--entryPtr->refCount == 0)
194 *prevEntry = entryPtr->next;
195 LOCAL_Free( selector, entry );
201 /***********************************************************************
204 static ATOM ATOM_FindAtom( WORD selector, LPCSTR str )
211 if (str[0] == '#') return atoi( &str[1] ); /* Check for integer atom */
212 if ((len = strlen( str )) > 255) len = 255;
213 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
214 hash = ATOM_Hash( table->size, str, len );
215 entry = table->entries[hash];
218 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
219 if ((entryPtr->length == len) &&
220 (!lstrncmpi32A( entryPtr->str, str, len )))
221 return HANDLETOATOM( entry );
222 entry = entryPtr->next;
228 /***********************************************************************
231 static UINT32 ATOM_GetAtomName( WORD selector, ATOM atom,
232 LPSTR buffer, INT32 count )
235 ATOMENTRY * entryPtr;
241 if (!count) return 0;
242 if (atom < MIN_STR_ATOM)
244 sprintf( text, "#%d", atom );
250 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
251 entry = ATOMTOHANDLE( atom );
252 entryPtr = ATOM_MakePtr( selector, entry );
253 len = entryPtr->length;
254 strPtr = entryPtr->str;
256 if (len >= count) len = count-1;
257 memcpy( buffer, strPtr, len );
263 /***********************************************************************
264 * InitAtomTable (KERNEL.68)
266 WORD InitAtomTable( WORD entries )
268 return ATOM_InitTable( CURRENT_DS, entries );
272 /***********************************************************************
273 * GetAtomHandle (KERNEL.73)
275 HANDLE GetAtomHandle( ATOM atom )
277 if (atom < MIN_STR_ATOM) return 0;
278 return ATOMTOHANDLE( atom );
282 /***********************************************************************
283 * AddAtom (KERNEL.70)
285 ATOM AddAtom( SEGPTR str )
288 HANDLE16 ds = CURRENT_DS;
290 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
291 if (SELECTOR_TO_ENTRY(LOWORD(str)) == SELECTOR_TO_ENTRY(ds))
293 /* If the string is in the same data segment as the atom table, make */
294 /* a copy of the string to be sure it doesn't move in linear memory. */
296 lstrcpyn32A( buffer, (char *)PTR_SEG_TO_LIN(str), sizeof(buffer) );
297 atom = ATOM_AddAtom( ds, buffer );
299 else atom = ATOM_AddAtom( ds, (LPCSTR)PTR_SEG_TO_LIN(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( SEGPTR str )
318 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
319 return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
323 /***********************************************************************
324 * GetAtomName (KERNEL.72)
326 WORD GetAtomName( ATOM atom, LPSTR buffer, short count )
328 return (WORD)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
332 /***********************************************************************
333 * GlobalAddAtom16 (USER.268)
335 ATOM GlobalAddAtom16( SEGPTR str )
337 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
339 if (Options.ipc) return DDE_GlobalAddAtom( str );
341 return ATOM_AddAtom( USER_HeapSel, (LPCSTR)PTR_SEG_TO_LIN(str) );
345 /***********************************************************************
346 * GlobalAddAtom32A (KERNEL32.313)
348 ATOM GlobalAddAtom32A( LPCSTR str )
350 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
351 return ATOM_AddAtom( USER_HeapSel, str );
355 /***********************************************************************
356 * GlobalAddAtom32W (KERNEL32.314)
358 ATOM GlobalAddAtom32W( LPCWSTR str )
360 char buffer[MAX_ATOM_LEN+1];
361 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
362 lstrcpynWtoA( buffer, str, sizeof(buffer) );
363 return ATOM_AddAtom( USER_HeapSel, buffer );
367 /***********************************************************************
368 * GlobalDeleteAtom (USER.269) (KERNEL32.317)
370 ATOM GlobalDeleteAtom( ATOM atom )
373 if (Options.ipc) return DDE_GlobalDeleteAtom( atom );
375 return ATOM_DeleteAtom( USER_HeapSel, atom );
379 /***********************************************************************
380 * GlobalFindAtom16 (USER.270)
382 ATOM GlobalFindAtom16( SEGPTR str )
384 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
386 if (Options.ipc) return DDE_GlobalFindAtom( str );
388 return ATOM_FindAtom( USER_HeapSel, (LPCSTR)PTR_SEG_TO_LIN(str) );
392 /***********************************************************************
393 * GlobalFindAtom32A (KERNEL32.318)
395 ATOM GlobalFindAtom32A( LPCSTR str )
397 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
398 return ATOM_FindAtom( USER_HeapSel, str );
402 /***********************************************************************
403 * GlobalFindAtom32W (KERNEL32.319)
405 ATOM GlobalFindAtom32W( LPCWSTR str )
407 char buffer[MAX_ATOM_LEN+1];
408 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
409 lstrcpynWtoA( buffer, str, sizeof(buffer) );
410 return ATOM_FindAtom( USER_HeapSel, buffer );
414 /***********************************************************************
415 * GlobalGetAtomName16 (USER.271)
417 UINT16 GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
420 if (Options.ipc) return DDE_GlobalGetAtomName( atom, buffer, count );
422 return (UINT16)ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
426 /***********************************************************************
427 * GlobalGetAtomName32A (KERNEL32.323)
429 UINT32 GlobalGetAtomName32A( ATOM atom, LPSTR buffer, INT32 count )
431 return ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
434 /***********************************************************************
435 * GlobalGetAtomName32W (KERNEL32.324)
437 UINT32 GlobalGetAtomName32W( ATOM atom, LPWSTR buffer, INT32 count )
439 char tmp[MAX_ATOM_LEN+1];
440 ATOM_GetAtomName( USER_HeapSel, atom, tmp, sizeof(tmp) );
441 lstrcpynAtoW( buffer, tmp, count );
442 return lstrlen32W( buffer );