Track memory allocations in the SQL parser.
[wine] / dlls / kernel / atom.c
1 /*
2  * Atom table functions
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
41 #include "wine/server.h"
42 #include "wine/unicode.h"
43 #include "kernel_private.h"
44
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(atom);
48
49 #define MAX_ATOM_LEN 255
50
51 static struct atom_table* get_local_table(DWORD entries)
52 {
53     static struct atom_table*   local_table;
54
55     if (!local_table)
56     {
57         NTSTATUS                status;
58         struct atom_table*      table;
59
60         SERVER_START_REQ( init_atom_table )
61         {
62             req->entries = entries;
63             status = wine_server_call( req );
64             table = reply->table;
65         }
66         SERVER_END_REQ;
67
68         if (status)
69             SetLastError( RtlNtStatusToDosError( status ) );
70         else if (InterlockedCompareExchangePointer((void*)&local_table, table, NULL) != NULL)
71             NtClose((HANDLE)table);
72     }
73     return local_table;
74 }
75
76 /***********************************************************************
77  *           ATOM_IsIntAtomA
78  */
79 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
80 {
81     UINT atom = 0;
82     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
83     else
84     {
85         if (*atomstr++ != '#') return FALSE;
86         while (*atomstr >= '0' && *atomstr <= '9')
87         {
88             atom = atom * 10 + *atomstr - '0';
89             atomstr++;
90         }
91         if (*atomstr) return FALSE;
92     }
93     if (atom >= MAXINTATOM)
94     {
95         SetLastError( ERROR_INVALID_PARAMETER );
96         atom = 0;
97     }
98     *atomid = atom;
99     return TRUE;
100 }
101
102
103 /***********************************************************************
104  *           ATOM_IsIntAtomW
105  */
106 static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
107 {
108     UINT atom = 0;
109     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
110     else
111     {
112         if (*atomstr++ != '#') return FALSE;
113         while (*atomstr >= '0' && *atomstr <= '9')
114         {
115             atom = atom * 10 + *atomstr - '0';
116             atomstr++;
117         }
118         if (*atomstr) return FALSE;
119     }
120     if (atom >= MAXINTATOM)
121     {
122         SetLastError( ERROR_INVALID_PARAMETER );
123         atom = 0;
124     }
125     *atomid = atom;
126     return TRUE;
127 }
128
129
130 /***********************************************************************
131  *           InitAtomTable   (KERNEL32.@)
132  *
133  * Initialise the global atom table.
134  *
135  * PARAMS
136  *  entries [I] The number of entries to reserve in the table.
137  *
138  * RETURNS
139  *  Success: TRUE.
140  *  Failure: FALSE.
141  */
142 BOOL WINAPI InitAtomTable( DWORD entries )
143 {
144     return get_local_table( entries ) ? TRUE : FALSE;
145 }
146
147
148 static ATOM ATOM_AddAtomA( LPCSTR str, struct atom_table* table )
149 {
150     ATOM atom = 0;
151     if (!ATOM_IsIntAtomA( str, &atom ))
152     {
153         WCHAR buffer[MAX_ATOM_LEN];
154
155         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
156         if (!len)
157         {
158             SetLastError( ERROR_INVALID_PARAMETER );
159             return 0;
160         }
161         SERVER_START_REQ( add_atom )
162         {
163             wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
164             req->table = table;
165             if (!wine_server_call_err(req)) atom = reply->atom;
166         }
167         SERVER_END_REQ;
168     }
169     TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_a(str), atom );
170     return atom;
171 }
172
173
174 /***********************************************************************
175  *           GlobalAddAtomA   (KERNEL32.@)
176  *
177  * Add a character string to the global atom table and return a unique
178  * value identifying it.
179  *
180  * RETURNS
181  *      Success: The atom allocated to str.
182  *      Failure: 0.
183  */
184 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ )
185 {
186     return ATOM_AddAtomA( str, NULL );
187 }
188
189
190 /***********************************************************************
191  *           AddAtomA   (KERNEL32.@)
192  *
193  * Add a character string to the global atom table and return a unique
194  * value identifying it.
195  *
196  * RETURNS
197  *      Success: The atom allocated to str.
198  *      Failure: 0.
199  */
200 ATOM WINAPI AddAtomA( LPCSTR str /* [in] String to add */ )
201 {
202     return ATOM_AddAtomA( str, get_local_table(0) );
203 }
204
205
206 static ATOM ATOM_AddAtomW( LPCWSTR str, struct atom_table* table )
207 {
208     ATOM atom = 0;
209     if (!ATOM_IsIntAtomW( str, &atom ))
210     {
211         DWORD len = strlenW(str);
212         if (len > MAX_ATOM_LEN)
213         {
214             SetLastError( ERROR_INVALID_PARAMETER );
215             return 0;
216         }
217         SERVER_START_REQ( add_atom )
218         {
219             req->table = table;
220             wine_server_add_data( req, str, len * sizeof(WCHAR) );
221             if (!wine_server_call_err(req)) atom = reply->atom;
222         }
223         SERVER_END_REQ;
224     }
225     TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_w(str), atom );
226     return atom;
227 }
228
229
230 /***********************************************************************
231  *           GlobalAddAtomW   (KERNEL32.@)
232  *
233  * Unicode version of GlobalAddAtomA.
234  */
235 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
236 {
237     return ATOM_AddAtomW( str, NULL );
238 }
239
240
241 /***********************************************************************
242  *           AddAtomW   (KERNEL32.@)
243  *
244  * Unicode version of AddAtomA.          
245  */
246 ATOM WINAPI AddAtomW( LPCWSTR str )
247 {
248     return ATOM_AddAtomW( str, get_local_table(0) );
249 }
250
251
252 static ATOM ATOM_DeleteAtom( ATOM atom, struct atom_table* table )
253 {
254     TRACE( "(%s) %x\n", table ? "local" : "global", atom );
255     if (atom >= MAXINTATOM)
256     {
257         SERVER_START_REQ( delete_atom )
258         {
259             req->atom = atom;
260             req->table = table;
261             wine_server_call_err( req );
262         }
263         SERVER_END_REQ;
264     }
265     return 0;
266 }
267
268
269 /***********************************************************************
270  *           GlobalDeleteAtom   (KERNEL32.@)
271  *
272  * Decrement the reference count of a string atom.  If the count is
273  * zero, the string associated with the atom is removed from the table.
274  *
275  * RETURNS
276  *      Success: 0.
277  *      Failure: atom.
278  */
279 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
280 {
281     return ATOM_DeleteAtom( atom, NULL);
282 }
283
284
285 /***********************************************************************
286  *           DeleteAtom   (KERNEL32.@)
287  *
288  * Decrement the reference count of a string atom.  If the count becomes
289  * zero, the string associated with the atom is removed from the table.
290  *
291  * RETURNS
292  *      Success: 0.
293  *      Failure: atom
294  */
295 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
296 {
297     return ATOM_DeleteAtom( atom, get_local_table(0) );
298 }
299
300
301 static ATOM ATOM_FindAtomA( LPCSTR str, struct atom_table* table )
302 {
303     ATOM atom = 0;
304     if (!ATOM_IsIntAtomA( str, &atom ))
305     {
306         WCHAR buffer[MAX_ATOM_LEN];
307
308         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
309         if (!len)
310         {
311             SetLastError( ERROR_INVALID_PARAMETER );
312             return 0;
313         }
314         SERVER_START_REQ( find_atom )
315         {
316             req->table = table;
317             wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
318             if (!wine_server_call_err(req)) atom = reply->atom;
319         }
320         SERVER_END_REQ;
321     }
322     TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_a(str), atom );
323     return atom;
324 }
325
326
327 /***********************************************************************
328  *           GlobalFindAtomA   (KERNEL32.@)
329  *
330  * Get the atom associated with a string.
331  *
332  * RETURNS
333  *      Success: The associated atom.
334  *      Failure: 0.
335  */
336 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
337 {
338     return ATOM_FindAtomA( str, NULL );
339 }
340
341 /***********************************************************************
342  *           FindAtomA   (KERNEL32.@)
343  *
344  * Get the atom associated with a string.
345  *
346  * RETURNS
347  *      Success: The associated atom.
348  *      Failure: 0.
349  */
350 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
351 {
352     return ATOM_FindAtomA( str, get_local_table(0) );
353 }
354
355
356 static ATOM ATOM_FindAtomW( LPCWSTR str, struct atom_table* table )
357 {
358     ATOM atom = 0;
359     if (!ATOM_IsIntAtomW( str, &atom ))
360     {
361         DWORD len = strlenW(str);
362         if (len > MAX_ATOM_LEN)
363         {
364             SetLastError( ERROR_INVALID_PARAMETER );
365             return 0;
366         }
367         SERVER_START_REQ( find_atom )
368         {
369             wine_server_add_data( req, str, len * sizeof(WCHAR) );
370             req->table = table;
371             if (!wine_server_call_err( req )) atom = reply->atom;
372         }
373         SERVER_END_REQ;
374     }
375     TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_w(str), atom );
376     return atom;
377 }
378
379
380 /***********************************************************************
381  *           GlobalFindAtomW   (KERNEL32.@)
382  *
383  * Unicode version of GlobalFindAtomA.
384  */
385 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
386 {
387     return ATOM_FindAtomW( str, NULL );
388 }
389
390
391 /***********************************************************************
392  *           FindAtomW   (KERNEL32.@)
393  *
394  * Unicode version of FindAtomA.
395  */
396 ATOM WINAPI FindAtomW( LPCWSTR str )
397 {
398     return ATOM_FindAtomW( str, get_local_table(0) );
399 }
400
401
402 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, struct atom_table* table )
403 {
404     INT len;
405
406     if (count <= 0)
407     {
408         SetLastError( ERROR_MORE_DATA );
409         return 0;
410     }
411     if (atom < MAXINTATOM)
412     {
413         char name[8];
414         if (!atom)
415         {
416             SetLastError( ERROR_INVALID_PARAMETER );
417             return 0;
418         }
419         len = sprintf( name, "#%d", atom );
420         lstrcpynA( buffer, name, count );
421     }
422     else
423     {
424         WCHAR full_name[MAX_ATOM_LEN];
425
426         len = 0;
427         SERVER_START_REQ( get_atom_information )
428         {
429             req->atom = atom;
430             req->table = table;
431             wine_server_set_reply( req, full_name, sizeof(full_name) );
432             if (!wine_server_call_err( req ))
433             {
434                 len = WideCharToMultiByte( CP_ACP, 0, full_name,
435                                            wine_server_reply_size(reply) / sizeof(WCHAR),
436                                            buffer, count - 1, NULL, NULL );
437                 if (!len) len = count; /* overflow */
438                 else buffer[len] = 0;
439             }
440         }
441         SERVER_END_REQ;
442     }
443
444     if (len && count <= len)
445     {
446         SetLastError( ERROR_MORE_DATA );
447         buffer[count-1] = 0;
448         return 0;
449     }
450     TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_a(buffer) );
451     return len;
452 }
453
454
455 /***********************************************************************
456  *           GlobalGetAtomNameA   (KERNEL32.@)
457  *
458  * Get a copy of the string associated with an atom.
459  *
460  * RETURNS
461  *      Success: The length of the returned string in characters.
462  *      Failure: 0.
463  */
464 UINT WINAPI GlobalGetAtomNameA(
465               ATOM atom,    /* [in]  Atom identifier */
466               LPSTR buffer, /* [out] Pointer to buffer for atom string */
467               INT count )   /* [in]  Size of buffer */
468 {
469     return ATOM_GetAtomNameA( atom, buffer, count, NULL );
470 }
471
472
473 /***********************************************************************
474  *           GetAtomNameA   (KERNEL32.@)
475  *
476  * Get a copy of the string associated with an atom.
477  *
478  * RETURNS
479  *      Success: The length of the returned string in characters.
480  *      Failure: 0.
481  */
482 UINT WINAPI GetAtomNameA(
483               ATOM atom,    /* [in]  Atom */
484               LPSTR buffer, /* [out] Pointer to string for atom string */
485               INT count)    /* [in]  Size of buffer */
486 {
487     return ATOM_GetAtomNameA( atom, buffer, count, get_local_table(0) );
488 }
489
490
491 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, struct atom_table* table )
492 {
493     INT len;
494
495     if (count <= 0)
496     {
497         SetLastError( ERROR_MORE_DATA );
498         return 0;
499     }
500     if (atom < MAXINTATOM)
501     {
502         char name[8];
503         if (!atom)
504         {
505             SetLastError( ERROR_INVALID_PARAMETER );
506             return 0;
507         }
508         sprintf( name, "#%d", atom );
509         len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
510         if (!len) buffer[count-1] = 0;  /* overflow */
511     }
512     else
513     {
514         WCHAR full_name[MAX_ATOM_LEN];
515
516         len = 0;
517         SERVER_START_REQ( get_atom_information )
518         {
519             req->atom = atom;
520             req->table = table;
521             wine_server_set_reply( req, full_name, sizeof(full_name) );
522             if (!wine_server_call_err( req ))
523             {
524                 len = wine_server_reply_size(reply) / sizeof(WCHAR);
525                 if (count > len) count = len + 1;
526                 memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
527                 buffer[count-1] = 0;
528             }
529         }
530         SERVER_END_REQ;
531         if (!len) return 0;
532     }
533     TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_w(buffer) );
534     return len;
535 }
536
537
538 /***********************************************************************
539  *           GlobalGetAtomNameW   (KERNEL32.@)
540  *
541  * Unicode version of GlobalGetAtomNameA.
542  */
543 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
544 {
545     return ATOM_GetAtomNameW( atom, buffer, count, NULL);
546 }
547
548
549 /***********************************************************************
550  *           GetAtomNameW   (KERNEL32.@)
551  *
552  * Unicode version of GetAtomNameA.
553  */
554 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
555 {
556     return ATOM_GetAtomNameW( atom, buffer, count, get_local_table(0) );
557 }