makefiles: Generate the dependencies line to avoid some code duplication.
[wine] / dlls / kernel32 / atom16.c
1 /*
2  * Atom table functions - 16 bit variant
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 /*
22  * Warning: The code assumes that LocalAlloc() returns a block aligned
23  * on a 4-bytes boundary (because of the shifting done in
24  * HANDLETOATOM).  If this is not the case, the allocation code will
25  * have to be changed.
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "winternl.h"
41
42 #include "wine/unicode.h"
43 #include "wine/winbase16.h"
44 #include "kernel_private.h"
45 #include "kernel16_private.h"
46
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(atom);
50
51 #define DEFAULT_ATOMTABLE_SIZE    37
52 #define MAX_ATOM_LEN              255
53
54 #define ATOMTOHANDLE(atom)        ((HANDLE16)(atom) << 2)
55 #define HANDLETOATOM(handle)      ((ATOM)(0xc000 | ((handle) >> 2)))
56
57 typedef struct
58 {
59     HANDLE16    next;
60     WORD        refCount;
61     BYTE        length;
62     CHAR        str[1];
63 } ATOMENTRY;
64
65 typedef struct
66 {
67     WORD        size;
68     HANDLE16    entries[1];
69 } ATOMTABLE;
70
71
72 /***********************************************************************
73  *           ATOM_GetTable
74  *
75  * Return a pointer to the atom table of a given segment, creating
76  * it if necessary.
77  *
78  * RETURNS
79  *      Pointer to table: Success
80  *      NULL: Failure
81  */
82 static ATOMTABLE *ATOM_GetTable( BOOL create  /* [in] Create */ )
83 {
84     INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
85     if (ptr->atomtable)
86     {
87         ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
88         if (table->size) return table;
89     }
90     if (!create) return NULL;
91     if (!InitAtomTable16( 0 )) return NULL;
92     /* Reload ptr in case it moved in linear memory */
93     ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
94     return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
95 }
96
97
98 /***********************************************************************
99  *           ATOM_Hash
100  * RETURNS
101  *      The hash value for the input string
102  */
103 static WORD ATOM_Hash(
104             WORD entries, /* [in] Total number of entries */
105             LPCSTR str,   /* [in] Pointer to string to hash */
106             WORD len      /* [in] Length of string */
107 ) {
108     WORD i, hash = 0;
109
110     TRACE("%x, %s, %x\n", entries, str, len);
111
112     for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
113     return hash % entries;
114 }
115
116
117 /***********************************************************************
118  *           ATOM_IsIntAtomA
119  */
120 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
121 {
122     UINT atom = 0;
123     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
124     else
125     {
126         if (*atomstr++ != '#') return FALSE;
127         while (*atomstr >= '0' && *atomstr <= '9')
128         {
129             atom = atom * 10 + *atomstr - '0';
130             atomstr++;
131         }
132         if (*atomstr) return FALSE;
133     }
134     if (atom >= MAXINTATOM)
135     {
136         SetLastError( ERROR_INVALID_PARAMETER );
137         atom = 0;
138     }
139     *atomid = atom;
140     return TRUE;
141 }
142
143
144 /***********************************************************************
145  *           ATOM_MakePtr
146  *
147  * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
148  */
149 static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
150 {
151     return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
152 }
153
154
155 /***********************************************************************
156  *           InitAtomTable   (KERNEL.68)
157  */
158 WORD WINAPI InitAtomTable16( WORD entries )
159 {
160     int i;
161     HANDLE16 handle;
162     ATOMTABLE *table;
163
164       /* Allocate the table */
165
166     if (!entries) entries = DEFAULT_ATOMTABLE_SIZE;  /* sanity check */
167     handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
168     if (!handle) return 0;
169     table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
170     table->size = entries;
171     for (i = 0; i < entries; i++) table->entries[i] = 0;
172
173       /* Store a pointer to the table in the instance data */
174
175     ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
176     return handle;
177 }
178
179 /***********************************************************************
180  *           GetAtomHandle   (KERNEL.73)
181  */
182 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
183 {
184     if (atom < MAXINTATOM) return 0;
185     return ATOMTOHANDLE( atom );
186 }
187
188
189 /***********************************************************************
190  *           AddAtom   (KERNEL.70)
191  *
192  * Windows DWORD aligns the atom entry size.
193  * The remaining unused string space created by the alignment
194  * gets padded with '\0's in a certain way to ensure
195  * that at least one trailing '\0' remains.
196  *
197  * RETURNS
198  *      Atom: Success
199  *      0: Failure
200  */
201 ATOM WINAPI AddAtom16( LPCSTR str )
202 {
203     char buffer[MAX_ATOM_LEN+1];
204     WORD hash;
205     HANDLE16 entry;
206     ATOMENTRY * entryPtr;
207     ATOMTABLE * table;
208     int len, ae_len;
209     WORD iatom;
210
211     if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
212
213     TRACE("%s\n",debugstr_a(str));
214
215     if (!(table = ATOM_GetTable( TRUE ))) return 0;
216
217     /* Make a copy of the string to be sure it doesn't move in linear memory. */
218     lstrcpynA( buffer, str, sizeof(buffer) );
219
220     len = strlen( buffer );
221     hash = ATOM_Hash( table->size, buffer, len );
222     entry = table->entries[hash];
223     while (entry)
224     {
225         entryPtr = ATOM_MakePtr( entry );
226         if ((entryPtr->length == len) &&
227             (!strncasecmp( entryPtr->str, buffer, len )))
228         {
229             entryPtr->refCount++;
230             TRACE("-- existing 0x%x\n", entry);
231             return HANDLETOATOM( entry );
232         }
233         entry = entryPtr->next;
234     }
235
236     ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
237     entry = LocalAlloc16( LMEM_FIXED, ae_len );
238     if (!entry) return 0;
239     /* Reload the table ptr in case it moved in linear memory */
240     table = ATOM_GetTable( FALSE );
241     entryPtr = ATOM_MakePtr( entry );
242     entryPtr->next = table->entries[hash];
243     entryPtr->refCount = 1;
244     entryPtr->length = len;
245     memcpy( entryPtr->str, buffer, len);
246     /* Some applications _need_ the '\0' padding provided by memset */
247     /* Note that 1 byte of the str is accounted for in the ATOMENTRY struct */
248     memset( entryPtr->str+len, 0, ae_len - sizeof(ATOMENTRY) - (len - 1));
249     table->entries[hash] = entry;
250     TRACE("-- new 0x%x\n", entry);
251     return HANDLETOATOM( entry );
252 }
253
254
255 /***********************************************************************
256  *           DeleteAtom   (KERNEL.71)
257  */
258 ATOM WINAPI DeleteAtom16( ATOM atom )
259 {
260     ATOMENTRY * entryPtr;
261     ATOMTABLE * table;
262     HANDLE16 entry, *prevEntry;
263     WORD hash;
264
265     if (atom < MAXINTATOM) return 0;  /* Integer atom */
266
267     TRACE("0x%x\n",atom);
268
269     if (!(table = ATOM_GetTable( FALSE ))) return 0;
270     entry = ATOMTOHANDLE( atom );
271     entryPtr = ATOM_MakePtr( entry );
272
273     /* Find previous atom */
274     hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
275     prevEntry = &table->entries[hash];
276     while (*prevEntry && *prevEntry != entry)
277     {
278         ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
279         prevEntry = &prevEntryPtr->next;
280     }
281     if (!*prevEntry) return atom;
282
283     /* Delete atom */
284     if (--entryPtr->refCount == 0)
285     {
286         *prevEntry = entryPtr->next;
287         LocalFree16( entry );
288     }
289     return 0;
290 }
291
292
293 /***********************************************************************
294  *           FindAtom   (KERNEL.69)
295  */
296 ATOM WINAPI FindAtom16( LPCSTR str )
297 {
298     ATOMTABLE * table;
299     WORD hash,iatom;
300     HANDLE16 entry;
301     int len;
302
303     TRACE("%s\n",debugstr_a(str));
304
305     if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
306     if ((len = strlen( str )) > 255) len = 255;
307     if (!(table = ATOM_GetTable( FALSE ))) return 0;
308     hash = ATOM_Hash( table->size, str, len );
309     entry = table->entries[hash];
310     while (entry)
311     {
312         ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
313         if ((entryPtr->length == len) &&
314             (!strncasecmp( entryPtr->str, str, len )))
315         {
316             TRACE("-- found %x\n", entry);
317             return HANDLETOATOM( entry );
318         }
319         entry = entryPtr->next;
320     }
321     TRACE("-- not found\n");
322     return 0;
323 }
324
325
326 /***********************************************************************
327  *           GetAtomName   (KERNEL.72)
328  */
329 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
330 {
331     ATOMENTRY * entryPtr;
332     HANDLE16 entry;
333     char * strPtr;
334     INT len;
335     char text[8];
336
337     TRACE("%x\n",atom);
338
339     if (!count) return 0;
340     if (atom < MAXINTATOM)
341     {
342         sprintf( text, "#%d", atom );
343         len = strlen(text);
344         strPtr = text;
345     }
346     else
347     {
348         if (!ATOM_GetTable( FALSE )) return 0;
349         entry = ATOMTOHANDLE( atom );
350         entryPtr = ATOM_MakePtr( entry );
351         len = entryPtr->length;
352         strPtr = entryPtr->str;
353     }
354     if (len >= count) len = count-1;
355     memcpy( buffer, strPtr, len );
356     buffer[len] = '\0';
357     return len;
358 }