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) ((HANDLE16)(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(HANDLE16) );
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.
74 BOOL32 ATOM_Init(void)
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, BOOL32 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, HANDLE16 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 )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
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 HANDLE16 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 * InitAtomTable16 (KERNEL.68)
266 WORD WINAPI InitAtomTable16( WORD entries )
268 return ATOM_InitTable( CURRENT_DS, entries );
272 /***********************************************************************
273 * GetAtomHandle (KERNEL.73)
275 HANDLE16 WINAPI GetAtomHandle( ATOM atom )
277 if (atom < MIN_STR_ATOM) return 0;
278 return ATOMTOHANDLE( atom );
282 /***********************************************************************
283 * AddAtom16 (KERNEL.70)
285 ATOM WINAPI AddAtom16( 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. */
295 char buffer[MAX_ATOM_LEN+1];
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 * AddAtom32A (KERNEL32.0)
307 ATOM WINAPI AddAtom32A( LPCSTR str )
309 return GlobalAddAtom32A( str ); /* FIXME */
313 /***********************************************************************
314 * AddAtom32W (KERNEL32.1)
316 ATOM WINAPI AddAtom32W( LPCWSTR str )
318 return GlobalAddAtom32W( str ); /* FIXME */
322 /***********************************************************************
323 * DeleteAtom16 (KERNEL.71)
325 ATOM WINAPI DeleteAtom16( ATOM atom )
327 return ATOM_DeleteAtom( CURRENT_DS, atom );
331 /***********************************************************************
332 * DeleteAtom32 (KERNEL32.69)
334 ATOM WINAPI DeleteAtom32( ATOM atom )
336 return GlobalDeleteAtom( atom ); /* FIXME */
340 /***********************************************************************
341 * FindAtom16 (KERNEL.69)
343 ATOM WINAPI FindAtom16( SEGPTR str )
345 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
346 return ATOM_FindAtom( CURRENT_DS, (LPCSTR)PTR_SEG_TO_LIN(str) );
350 /***********************************************************************
351 * FindAtom32A (KERNEL32.117)
353 ATOM WINAPI FindAtom32A( LPCSTR str )
355 return GlobalFindAtom32A( str ); /* FIXME */
359 /***********************************************************************
360 * FindAtom32W (KERNEL32.118)
362 ATOM WINAPI FindAtom32W( LPCWSTR str )
364 return GlobalFindAtom32W( str ); /* FIXME */
368 /***********************************************************************
369 * GetAtomName16 (KERNEL.72)
371 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
373 return (UINT16)ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
377 /***********************************************************************
378 * GetAtomName32A (KERNEL32.149)
380 UINT32 WINAPI GetAtomName32A( ATOM atom, LPSTR buffer, INT32 count )
382 return GlobalGetAtomName32A( atom, buffer, count ); /* FIXME */
386 /***********************************************************************
387 * GetAtomName32W (KERNEL32.150)
389 UINT32 WINAPI GetAtomName32W( ATOM atom, LPWSTR buffer, INT32 count )
391 return GlobalGetAtomName32W( atom, buffer, count ); /* FIXME */
395 /***********************************************************************
396 * GlobalAddAtom16 (USER.268)
398 ATOM WINAPI GlobalAddAtom16( SEGPTR str )
400 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
402 if (Options.ipc) return DDE_GlobalAddAtom( str );
404 return ATOM_AddAtom( USER_HeapSel, (LPCSTR)PTR_SEG_TO_LIN(str) );
408 /***********************************************************************
409 * GlobalAddAtom32A (KERNEL32.313)
411 ATOM WINAPI GlobalAddAtom32A( LPCSTR str )
413 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
414 return ATOM_AddAtom( USER_HeapSel, str );
418 /***********************************************************************
419 * GlobalAddAtom32W (KERNEL32.314)
421 ATOM WINAPI GlobalAddAtom32W( LPCWSTR str )
423 char buffer[MAX_ATOM_LEN+1];
424 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
425 lstrcpynWtoA( buffer, str, sizeof(buffer) );
426 return ATOM_AddAtom( USER_HeapSel, buffer );
430 /***********************************************************************
431 * GlobalDeleteAtom (USER.269) (KERNEL32.317)
433 ATOM WINAPI GlobalDeleteAtom( ATOM atom )
436 if (Options.ipc) return DDE_GlobalDeleteAtom( atom );
438 return ATOM_DeleteAtom( USER_HeapSel, atom );
442 /***********************************************************************
443 * GlobalFindAtom16 (USER.270)
445 ATOM WINAPI GlobalFindAtom16( SEGPTR str )
447 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
449 if (Options.ipc) return DDE_GlobalFindAtom( str );
451 return ATOM_FindAtom( USER_HeapSel, (LPCSTR)PTR_SEG_TO_LIN(str) );
455 /***********************************************************************
456 * GlobalFindAtom32A (KERNEL32.318)
458 ATOM WINAPI GlobalFindAtom32A( LPCSTR str )
460 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
461 return ATOM_FindAtom( USER_HeapSel, str );
465 /***********************************************************************
466 * GlobalFindAtom32W (KERNEL32.319)
468 ATOM WINAPI GlobalFindAtom32W( LPCWSTR str )
470 char buffer[MAX_ATOM_LEN+1];
471 if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
472 lstrcpynWtoA( buffer, str, sizeof(buffer) );
473 return ATOM_FindAtom( USER_HeapSel, buffer );
477 /***********************************************************************
478 * GlobalGetAtomName16 (USER.271)
480 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
483 if (Options.ipc) return DDE_GlobalGetAtomName( atom, buffer, count );
485 return (UINT16)ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
489 /***********************************************************************
490 * GlobalGetAtomName32A (KERNEL32.323)
492 UINT32 WINAPI GlobalGetAtomName32A( ATOM atom, LPSTR buffer, INT32 count )
494 return ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
497 /***********************************************************************
498 * GlobalGetAtomName32W (KERNEL32.324)
500 UINT32 WINAPI GlobalGetAtomName32W( ATOM atom, LPWSTR buffer, INT32 count )
502 char tmp[MAX_ATOM_LEN+1];
503 ATOM_GetAtomName( USER_HeapSel, atom, tmp, sizeof(tmp) );
504 lstrcpynAtoW( buffer, tmp, count );
505 return lstrlen32W( buffer );