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
33 #define ATOMTOHANDLE(atom) ((HANDLE)(atom) << 2)
34 #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2)))
36 #define HAS_ATOM_TABLE(sel) \
37 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
39 #define GET_ATOM_TABLE(sel) ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
40 ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
43 #define USER_HeapSel 0
46 /***********************************************************************
49 static WORD ATOM_InitTable( WORD selector, WORD entries )
55 /* Allocate the table */
57 handle = LOCAL_Alloc( selector, LMEM_FIXED,
58 sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE) );
59 if (!handle) return 0;
60 table = (ATOMTABLE *)PTR_SEG_OFF_TO_LIN( selector, handle );
61 table->size = entries;
62 for (i = 0; i < entries; i++) table->entries[i] = 0;
64 /* Store a pointer to the table in the instance data */
66 ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
71 /***********************************************************************
74 * Global table initialisation.
78 return ATOM_InitTable( USER_HeapSel, DEFAULT_ATOMTABLE_SIZE );
82 /***********************************************************************
85 * Return a pointer to the atom table of a given segment, creating
88 static ATOMTABLE * ATOM_GetTable( WORD selector, BOOL create )
90 INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
93 if (!create) return NULL;
94 if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
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, SEGPTR name )
130 ATOMENTRY * entryPtr;
135 /* Check for integer atom */
137 if (!HIWORD(name)) return (ATOM)LOWORD(name);
138 str = PTR_SEG_TO_LIN( name );
139 if (str[0] == '#') return atoi( &str[1] );
141 if ((len = strlen( str )) > 255) len = 255;
142 if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
143 hash = ATOM_Hash( table->size, str, len );
144 entry = table->entries[hash];
147 entryPtr = ATOM_MakePtr( selector, entry );
148 if ((entryPtr->length == len) &&
149 (!strncasecmp( entryPtr->str, str, len )))
151 entryPtr->refCount++;
152 return HANDLETOATOM( entry );
154 entry = entryPtr->next;
157 entry = LOCAL_Alloc( selector, LMEM_FIXED, sizeof(ATOMENTRY)+len-1 );
158 if (!entry) return 0;
159 entryPtr = ATOM_MakePtr( selector, entry );
160 entryPtr->next = table->entries[hash];
161 entryPtr->refCount = 1;
162 entryPtr->length = len;
163 memcpy( entryPtr->str, str, len );
164 table->entries[hash] = entry;
165 return HANDLETOATOM( entry );
169 /***********************************************************************
172 static ATOM ATOM_DeleteAtom( WORD selector, ATOM atom )
174 ATOMENTRY * entryPtr;
176 HANDLE entry, *prevEntry;
179 if (atom < MIN_STR_ATOM) return 0; /* Integer atom */
181 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
182 entry = ATOMTOHANDLE( atom );
183 entryPtr = ATOM_MakePtr( selector, entry );
185 /* Find previous atom */
186 hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
187 prevEntry = &table->entries[hash];
188 while (*prevEntry && *prevEntry != entry)
190 ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
191 prevEntry = &prevEntryPtr->next;
193 if (!*prevEntry) return atom;
196 if (--entryPtr->refCount == 0)
198 *prevEntry = entryPtr->next;
199 LOCAL_Free( selector, entry );
205 /***********************************************************************
208 static ATOM ATOM_FindAtom( WORD selector, SEGPTR name )
216 /* Check for integer atom */
218 if (!HIWORD(name)) return (ATOM)LOWORD(name);
219 str = PTR_SEG_TO_LIN( name );
220 if (str[0] == '#') return atoi( &str[1] );
222 if ((len = strlen( str )) > 255) len = 255;
223 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
224 hash = ATOM_Hash( table->size, str, len );
225 entry = table->entries[hash];
228 ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
229 if ((entryPtr->length == len) &&
230 (!strncasecmp( entryPtr->str, str, len )))
231 return HANDLETOATOM( entry );
232 entry = entryPtr->next;
238 /***********************************************************************
241 static WORD ATOM_GetAtomName( WORD selector, ATOM atom,
242 LPSTR buffer, short count )
245 ATOMENTRY * entryPtr;
251 if (!count) return 0;
252 if (atom < MIN_STR_ATOM)
254 sprintf( text, "#%d", atom );
260 if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
261 entry = ATOMTOHANDLE( atom );
262 entryPtr = ATOM_MakePtr( selector, entry );
263 len = entryPtr->length;
264 strPtr = entryPtr->str;
266 if (len >= count) len = count-1;
267 memcpy( buffer, strPtr, len );
273 /***********************************************************************
274 * InitAtomTable (KERNEL.68)
276 WORD InitAtomTable( WORD entries )
278 return ATOM_InitTable( CURRENT_DS, entries );
282 /***********************************************************************
283 * GetAtomHandle (KERNEL.73)
285 HANDLE GetAtomHandle( ATOM atom )
287 if (atom < MIN_STR_ATOM) return 0;
288 return ATOMTOHANDLE( atom );
292 /***********************************************************************
293 * AddAtom (KERNEL.70)
295 ATOM AddAtom( SEGPTR str )
297 return ATOM_AddAtom( CURRENT_DS, str );
301 /***********************************************************************
302 * DeleteAtom (KERNEL.71)
304 ATOM DeleteAtom( ATOM atom )
306 return ATOM_DeleteAtom( CURRENT_DS, atom );
310 /***********************************************************************
311 * FindAtom (KERNEL.69)
313 ATOM FindAtom( SEGPTR str )
315 return ATOM_FindAtom( CURRENT_DS, str );
319 /***********************************************************************
320 * GetAtomName (KERNEL.72)
322 WORD GetAtomName( ATOM atom, LPSTR buffer, short count )
324 return ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
328 /***********************************************************************
329 * GlobalAddAtom (USER.268)
331 ATOM GlobalAddAtom( SEGPTR str )
334 if (Options.ipc) return DDE_GlobalAddAtom( str );
336 return ATOM_AddAtom( USER_HeapSel, str );
340 /***********************************************************************
341 * GlobalDeleteAtom (USER.269)
343 ATOM GlobalDeleteAtom( ATOM atom )
346 if (Options.ipc) return DDE_GlobalDeleteAtom( atom );
348 return ATOM_DeleteAtom( USER_HeapSel, atom );
352 /***********************************************************************
353 * GlobalFindAtom (USER.270)
355 ATOM GlobalFindAtom( SEGPTR str )
358 if (Options.ipc) return DDE_GlobalFindAtom( str );
360 return ATOM_FindAtom( USER_HeapSel, str );
364 /***********************************************************************
365 * GlobalGetAtomName (USER.271)
367 WORD GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
370 if (Options.ipc) return DDE_GlobalGetAtomName( atom, buffer, count );
372 return ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );