Release 950727
[wine] / misc / atom.c
1 /*
2  * Atom table functions
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  */
6
7 /*
8  * Current limitations:
9  *
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.
13  *
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.
18  *
19  * 13/Feb, miguel
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.
24  */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30
31 #include "atom.h"
32 #include "instance.h"
33 #include "ldt.h"
34 #include "stackframe.h"
35 #include "user.h"
36
37 #define DEFAULT_ATOMTABLE_SIZE    37
38 #define MIN_STR_ATOM              0xc000
39
40 #define ATOMTOHANDLE(atom)        ((HANDLE)(atom) << 2)
41 #define HANDLETOATOM(handle)      ((ATOM)(0xc000 | ((handle) >> 2)))
42
43 #define HAS_ATOM_TABLE(sel)  \
44           ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable != 0)
45
46 #define GET_ATOM_TABLE(sel)  ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
47           ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
48                 
49 #ifdef WINELIB
50 #define USER_HeapSel    0
51 #endif
52
53 /***********************************************************************
54  *           ATOM_InitTable
55  */
56 static WORD ATOM_InitTable( WORD selector, WORD entries )
57 {
58     int i;
59     HANDLE handle;
60     ATOMTABLE *table;
61
62       /* Allocate the table */
63
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;
70
71       /* Store a pointer to the table in the instance data */
72
73     ((INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 ))->atomtable = handle;
74     return handle;
75 }
76
77
78 /***********************************************************************
79  *           ATOM_Init
80  *
81  * Global table initialisation.
82  */
83 WORD ATOM_Init()
84 {
85     return ATOM_InitTable( USER_HeapSel, DEFAULT_ATOMTABLE_SIZE );
86 }
87
88
89 /***********************************************************************
90  *           ATOM_GetTable
91  *
92  * Return a pointer to the atom table of a given segment, creating
93  * it if necessary.
94  */
95 static ATOMTABLE * ATOM_GetTable( WORD selector, BOOL create )
96 {
97     INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( selector, 0 );
98     if (!ptr->atomtable)
99     {
100         if (!create) return NULL;
101         if (!ATOM_InitTable( selector, DEFAULT_ATOMTABLE_SIZE )) return NULL;
102     }
103     return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
104 }
105
106
107 /***********************************************************************
108  *           ATOM_MakePtr
109  *
110  * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
111  */
112 static ATOMENTRY * ATOM_MakePtr( WORD selector, HANDLE handle )
113 {
114     return (ATOMENTRY *)PTR_SEG_OFF_TO_LIN( selector, handle );
115 }
116
117
118 /***********************************************************************
119  *           ATOM_Hash
120  */
121 static WORD ATOM_Hash( WORD entries, LPCSTR str, WORD len )
122 {
123     WORD i, hash = 0;
124
125     for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
126     return hash % entries;
127 }
128
129
130 /***********************************************************************
131  *           ATOM_AddAtom
132  */
133 static ATOM ATOM_AddAtom( WORD selector, LPCSTR str )
134 {
135     WORD hash;
136     HANDLE entry;
137     ATOMENTRY * entryPtr;
138     ATOMTABLE * table;
139     int len;
140     
141     if ((len = strlen( str )) > 255) len = 255;
142
143       /* Check for integer atom */
144 /*    if (!((int)str & 0xffff0000)) return (ATOM)((int)str & 0xffff); */
145     if (str[0] == '#') return atoi( &str[1] );
146
147     if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
148     hash = ATOM_Hash( table->size, str, len );
149     entry = table->entries[hash];
150     while (entry)
151     {
152         entryPtr = ATOM_MakePtr( selector, entry );
153         if ((entryPtr->length == len) && 
154             (!strncasecmp( entryPtr->str, str, len )))
155         {
156             entryPtr->refCount++;
157             return HANDLETOATOM( entry );
158         }
159         entry = entryPtr->next;
160     }
161
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 );
171 }
172
173
174 /***********************************************************************
175  *           ATOM_DeleteAtom
176  */
177 static ATOM ATOM_DeleteAtom( WORD selector, ATOM atom )
178 {
179     ATOMENTRY * entryPtr;
180     ATOMTABLE * table;
181     HANDLE entry, *prevEntry;
182     WORD hash;
183     
184     if (atom < MIN_STR_ATOM) return 0;  /* Integer atom */
185
186     if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
187     entry = ATOMTOHANDLE( atom );
188     entryPtr = ATOM_MakePtr( selector, entry );
189
190       /* Find previous atom */
191     hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
192     prevEntry = &table->entries[hash];
193     while (*prevEntry && *prevEntry != entry)
194     {
195         ATOMENTRY * prevEntryPtr = ATOM_MakePtr( selector, *prevEntry );
196         prevEntry = &prevEntryPtr->next;
197     }    
198     if (!*prevEntry) return atom;
199
200       /* Delete atom */
201     if (--entryPtr->refCount == 0)
202     {
203         *prevEntry = entryPtr->next;
204         LOCAL_Free( selector, entry );
205     }    
206     return 0;
207 }
208
209
210 /***********************************************************************
211  *           ATOM_FindAtom
212  */
213 static ATOM ATOM_FindAtom( WORD selector, LPCSTR str )
214 {
215     ATOMTABLE * table;
216     WORD hash;
217     HANDLE entry;
218     int len;
219     
220     if ((len = strlen( str )) > 255) len = 255;
221     
222       /* Check for integer atom */
223 /*    if (!((int)str & 0xffff0000)) return (ATOM)((int)str & 0xffff); */
224     if (str[0] == '#') return atoi( &str[1] );
225
226     if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
227     hash = ATOM_Hash( table->size, str, len );
228     entry = table->entries[hash];
229     while (entry)
230     {
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;
236     }
237     return 0;
238 }
239
240
241 /***********************************************************************
242  *           ATOM_GetAtomName
243  */
244 static WORD ATOM_GetAtomName( WORD selector, ATOM atom,
245                               LPSTR buffer, short count )
246 {
247     ATOMTABLE * table;
248     ATOMENTRY * entryPtr;
249     HANDLE entry;
250     char * strPtr;
251     int len;
252     char text[8];
253     
254     if (!count) return 0;
255     if (atom < MIN_STR_ATOM)
256     {
257         sprintf( text, "#%d", atom );
258         len = strlen(text);
259         strPtr = text;
260     }
261     else
262     {
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;
268     }
269     if (len >= count) len = count-1;
270     memcpy( buffer, strPtr, len );
271     buffer[len] = '\0';
272     return len;
273 }
274
275
276 /***********************************************************************
277  *           InitAtomTable   (KERNEL.68)
278  */
279 WORD InitAtomTable( WORD entries )
280 {
281     return ATOM_InitTable( CURRENT_DS, entries );
282 }
283
284
285 /***********************************************************************
286  *           GetAtomHandle   (KERNEL.73)
287  */
288 HANDLE GetAtomHandle( ATOM atom )
289 {
290     if (atom < MIN_STR_ATOM) return 0;
291     return ATOMTOHANDLE( atom );
292 }
293
294
295 /***********************************************************************
296  *           AddAtom   (KERNEL.70)
297  */
298 ATOM AddAtom( LPCSTR str )
299 {
300     return ATOM_AddAtom( CURRENT_DS, str );
301 }
302
303
304 /***********************************************************************
305  *           DeleteAtom   (KERNEL.71)
306  */
307 ATOM DeleteAtom( ATOM atom )
308 {
309     return ATOM_DeleteAtom( CURRENT_DS, atom );
310 }
311
312
313 /***********************************************************************
314  *           FindAtom   (KERNEL.69)
315  */
316 ATOM FindAtom( LPCSTR str )
317 {
318     return ATOM_FindAtom( CURRENT_DS, str );
319 }
320
321
322 /***********************************************************************
323  *           GetAtomName   (KERNEL.72)
324  */
325 WORD GetAtomName( ATOM atom, LPSTR buffer, short count )
326 {
327     return ATOM_GetAtomName( CURRENT_DS, atom, buffer, count );
328 }
329
330
331 /***********************************************************************
332  *           LocalAddAtom   (USER.268)
333  */
334 ATOM LocalAddAtom( LPCSTR str )
335 {
336     return ATOM_AddAtom( USER_HeapSel, str );
337 }
338
339
340 /***********************************************************************
341  *           LocalDeleteAtom   (USER.269)
342  */
343 ATOM LocalDeleteAtom( ATOM atom )
344 {
345     return ATOM_DeleteAtom( USER_HeapSel, atom );
346 }
347
348
349 /***********************************************************************
350  *           LocalFindAtom   (USER.270)
351  */
352 ATOM LocalFindAtom( LPCSTR str )
353 {
354     return ATOM_FindAtom( USER_HeapSel, str );
355 }
356
357
358 /***********************************************************************
359  *           LocalGetAtomName   (USER.271)
360  */
361 WORD LocalGetAtomName( ATOM atom, LPSTR buffer, short count )
362 {
363     return ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
364 }