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