Buffer overflows and strncpy fixes.
[wine] / files / profile.c
1 /*
2  * Profile functions
3  *
4  * Copyright 1993 Miguel de Icaza
5  * Copyright 1996 Alexandre Julliard
6  */
7
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include <sys/stat.h>
13
14 #include "winbase.h"
15 #include "winerror.h"
16 #include "wine/winbase16.h"
17 #include "winuser.h"
18 #include "winnls.h"
19 #include "file.h"
20 #include "heap.h"
21 #include "debugtools.h"
22 #include "options.h"
23
24 DEFAULT_DEBUG_CHANNEL(profile)
25
26 typedef struct tagPROFILEKEY
27 {
28     char                  *name;
29     char                  *value;
30     struct tagPROFILEKEY  *next;
31 } PROFILEKEY;
32
33 typedef struct tagPROFILESECTION
34 {
35     char                       *name;
36     struct tagPROFILEKEY       *key;
37     struct tagPROFILESECTION   *next;
38 } PROFILESECTION; 
39
40
41 typedef struct
42 {
43     BOOL             changed;
44     PROFILESECTION  *section;
45     char            *dos_name;
46     char            *unix_name;
47     char            *filename;
48     time_t           mtime;
49 } PROFILE;
50
51
52 #define N_CACHED_PROFILES 10
53
54 /* Cached profile files */
55 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
56
57 #define CurProfile (MRUProfile[0])
58
59 /* wine.ini profile content */
60 static PROFILESECTION *PROFILE_WineProfile;
61
62 #define PROFILE_MAX_LINE_LEN   1024
63
64 /* Wine profile name in $HOME directory; must begin with slash */
65 static const char PROFILE_WineIniName[] = "/.winerc";
66
67 /* Wine profile: the profile file being used */
68 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
69
70 /* Check for comments in profile */
71 #define IS_ENTRY_COMMENT(str)  ((str)[0] == ';')
72
73 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
74
75 static LPCWSTR wininiW = NULL;
76
77 static CRITICAL_SECTION PROFILE_CritSect;
78
79 /***********************************************************************
80  *           PROFILE_CopyEntry
81  *
82  * Copy the content of an entry into a buffer, removing quotes, and possibly
83  * translating environment variables.
84  */
85 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
86                                int handle_env )
87 {
88     char quote = '\0';
89     const char *p;
90
91     if ((*value == '\'') || (*value == '\"'))
92     {
93         if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
94     }
95
96     if (!handle_env)
97     {
98         lstrcpynA( buffer, value, len );
99         if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
100         return;
101     }
102
103     for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
104     {
105         if ((*p == '$') && (p[1] == '{'))
106         {
107             char env_val[1024];
108             const char *env_p;
109             const char *p2 = strchr( p, '}' );
110             if (!p2) continue;  /* ignore it */
111             lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
112             if ((env_p = getenv( env_val )) != NULL)
113             {
114                 lstrcpynA( buffer, env_p, len );
115                 buffer += strlen( buffer );
116                 len -= strlen( buffer );
117             }
118             p = p2 + 1;
119         }
120     }
121     if (quote && (len > 1)) buffer--;
122     *buffer = '\0';
123 }
124
125
126 /***********************************************************************
127  *           PROFILE_Save
128  *
129  * Save a profile tree to a file.
130  */
131 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
132 {
133     PROFILEKEY *key;
134
135     for ( ; section; section = section->next)
136     {
137         if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
138         for (key = section->key; key; key = key->next)
139         {
140             fprintf( file, "%s", key->name );
141             if (key->value) fprintf( file, "=%s", key->value );
142             fprintf( file, "\r\n" );
143         }
144     }
145 }
146
147
148 /***********************************************************************
149  *           PROFILE_Free
150  *
151  * Free a profile tree.
152  */
153 static void PROFILE_Free( PROFILESECTION *section )
154 {
155     PROFILESECTION *next_section;
156     PROFILEKEY *key, *next_key;
157
158     for ( ; section; section = next_section)
159     {
160         if (section->name) HeapFree( SystemHeap, 0, section->name );
161         for (key = section->key; key; key = next_key)
162         {
163             next_key = key->next;
164             if (key->name) HeapFree( SystemHeap, 0, key->name );
165             if (key->value) HeapFree( SystemHeap, 0, key->value );
166             HeapFree( SystemHeap, 0, key );
167         }
168         next_section = section->next;
169         HeapFree( SystemHeap, 0, section );
170     }
171 }
172
173 static int
174 PROFILE_isspace(char c) {
175         if (isspace(c)) return 1;
176         if (c=='\r' || c==0x1a) return 1;
177         /* CR and ^Z (DOS EOF) are spaces too  (found on CD-ROMs) */
178         return 0;
179 }
180
181
182 /***********************************************************************
183  *           PROFILE_Load
184  *
185  * Load a profile tree from a file.
186  */
187 static PROFILESECTION *PROFILE_Load( FILE *file )
188 {
189     char buffer[PROFILE_MAX_LINE_LEN];
190     char *p, *p2;
191     int line = 0;
192     PROFILESECTION *section, *first_section;
193     PROFILESECTION **next_section;
194     PROFILEKEY *key, *prev_key, **next_key;
195
196     first_section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
197     first_section->name = NULL;
198     first_section->key  = NULL;
199     first_section->next = NULL;
200     next_section = &first_section->next;
201     next_key     = &first_section->key;
202     prev_key     = NULL;
203
204     while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
205     {
206         line++;
207         p = buffer;
208         while (*p && PROFILE_isspace(*p)) p++;
209         if (*p == '[')  /* section start */
210         {
211             if (!(p2 = strrchr( p, ']' )))
212             {
213                 WARN("Invalid section header at line %d: '%s'\n",
214                      line, p );
215             }
216             else
217             {
218                 *p2 = '\0';
219                 p++;
220                 section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
221                 section->name = HEAP_strdupA( SystemHeap, 0, p );
222                 section->key  = NULL;
223                 section->next = NULL;
224                 *next_section = section;
225                 next_section  = &section->next;
226                 next_key      = &section->key;
227                 prev_key      = NULL;
228
229                 TRACE("New section: '%s'\n",section->name);
230
231                 continue;
232             }
233         }
234
235         p2=p+strlen(p) - 1;
236         while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
237
238         if ((p2 = strchr( p, '=' )) != NULL)
239         {
240             char *p3 = p2 - 1;
241             while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
242             *p2++ = '\0';
243             while (*p2 && PROFILE_isspace(*p2)) p2++;
244         }
245
246         if(*p || !prev_key || *prev_key->name)
247           {
248            key = HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
249            key->name  = HEAP_strdupA( SystemHeap, 0, p );
250            key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
251            key->next  = NULL;
252            *next_key  = key;
253            next_key   = &key->next;
254            prev_key   = key;
255
256            TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
257           }
258     }
259     return first_section;
260 }
261
262
263 /***********************************************************************
264  *           PROFILE_DeleteSection
265  *
266  * Delete a section from a profile tree.
267  */
268 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
269 {
270     while (*section)
271     {
272         if ((*section)->name && !strcasecmp( (*section)->name, name ))
273         {
274             PROFILESECTION *to_del = *section;
275             *section = to_del->next;
276             to_del->next = NULL;
277             PROFILE_Free( to_del );
278             return TRUE;
279         }
280         section = &(*section)->next;
281     }
282     return FALSE;
283 }
284
285
286 /***********************************************************************
287  *           PROFILE_DeleteKey
288  *
289  * Delete a key from a profile tree.
290  */
291 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
292                                LPCSTR section_name, LPCSTR key_name )
293 {
294     while (*section)
295     {
296         if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
297         {
298             PROFILEKEY **key = &(*section)->key;
299             while (*key)
300             {
301                 if (!strcasecmp( (*key)->name, key_name ))
302                 {
303                     PROFILEKEY *to_del = *key;
304                     *key = to_del->next;
305                     if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
306                     if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
307                     HeapFree( SystemHeap, 0, to_del );
308                     return TRUE;
309                 }
310                 key = &(*key)->next;
311             }
312         }
313         section = &(*section)->next;
314     }
315     return FALSE;
316 }
317
318
319 /***********************************************************************
320  *           PROFILE_Find
321  *
322  * Find a key in a profile tree, optionally creating it.
323  */
324 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
325                                  const char *section_name,
326                                  const char *key_name, int create )
327 {
328     while (*section)
329     {
330         if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
331         {
332             PROFILEKEY **key = &(*section)->key;
333             while (*key)
334             {
335                 if (!strcasecmp( (*key)->name, key_name )) return *key;
336                 key = &(*key)->next;
337             }
338             if (!create) return NULL;
339             *key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
340             (*key)->name  = HEAP_strdupA( SystemHeap, 0, key_name );
341             (*key)->value = NULL;
342             (*key)->next  = NULL;
343             return *key;
344         }
345         section = &(*section)->next;
346     }
347     if (!create) return NULL;
348     *section = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
349     (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
350     (*section)->next = NULL;
351     (*section)->key  = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
352     (*section)->key->name  = HEAP_strdupA( SystemHeap, 0, key_name );
353     (*section)->key->value = NULL;
354     (*section)->key->next  = NULL;
355     return (*section)->key;
356 }
357
358
359 /***********************************************************************
360  *           PROFILE_FlushFile
361  *
362  * Flush the current profile to disk if changed.
363  */
364 static BOOL PROFILE_FlushFile(void)
365 {
366     char *p, buffer[MAX_PATHNAME_LEN];
367     const char *unix_name;
368     FILE *file = NULL;
369     struct stat buf;
370
371     if(!CurProfile)
372     {
373         WARN("No current profile!\n");
374         return FALSE;
375     }
376
377     if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
378     if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
379     {
380         /* Try to create it in $HOME/.wine */
381         /* FIXME: this will need a more general solution */
382         if ((p = getenv( "HOME" )) != NULL)
383         {
384             strcpy( buffer, p );
385             strcat( buffer, "/.wine/" );
386             p = buffer + strlen(buffer);
387             strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
388             CharLowerA( p );
389             file = fopen( buffer, "w" );
390             unix_name = buffer;
391         }
392     }
393     
394     if (!file)
395     {
396         WARN("could not save profile file %s\n", CurProfile->dos_name);
397         return FALSE;
398     }
399
400     TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
401     PROFILE_Save( file, CurProfile->section );
402     fclose( file );
403     CurProfile->changed = FALSE;
404     if(!stat(unix_name,&buf))
405        CurProfile->mtime=buf.st_mtime;
406     return TRUE;
407 }
408
409
410 /***********************************************************************
411  *           PROFILE_ReleaseFile
412  *
413  * Flush the current profile to disk and remove it from the cache.
414  */
415 static void PROFILE_ReleaseFile(void)
416 {
417     PROFILE_FlushFile();
418     PROFILE_Free( CurProfile->section );
419     if (CurProfile->dos_name) HeapFree( SystemHeap, 0, CurProfile->dos_name );
420     if (CurProfile->unix_name) HeapFree( SystemHeap, 0, CurProfile->unix_name );
421     if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
422     CurProfile->changed   = FALSE;
423     CurProfile->section   = NULL;
424     CurProfile->dos_name  = NULL;
425     CurProfile->unix_name = NULL;
426     CurProfile->filename  = NULL;
427     CurProfile->mtime     = 0;
428 }
429
430
431 /***********************************************************************
432  *           PROFILE_Open
433  *
434  * Open a profile file, checking the cached file first.
435  */
436 static BOOL PROFILE_Open( LPCSTR filename )
437 {
438     DOS_FULL_NAME full_name;
439     char buffer[MAX_PATHNAME_LEN];
440     char *newdos_name, *p;
441     FILE *file = NULL;
442     int i,j;
443     struct stat buf;
444     PROFILE *tempProfile;
445
446     /* First time around */
447
448     if(!CurProfile)
449        for(i=0;i<N_CACHED_PROFILES;i++)
450          {
451           MRUProfile[i]=HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
452           MRUProfile[i]->changed=FALSE;
453           MRUProfile[i]->section=NULL;
454           MRUProfile[i]->dos_name=NULL;
455           MRUProfile[i]->unix_name=NULL;
456           MRUProfile[i]->filename=NULL;
457           MRUProfile[i]->mtime=0;
458          }
459
460     /* Check for a match */
461
462     if (strchr( filename, '/' ) || strchr( filename, '\\' ) || 
463         strchr( filename, ':' ))
464     {
465         if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
466     }
467     else
468     {
469         GetWindowsDirectoryA( buffer, sizeof(buffer) );
470         strcat( buffer, "\\" );
471         strcat( buffer, filename );
472         if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
473     }
474
475     for(i=0;i<N_CACHED_PROFILES;i++)
476       {
477        if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
478            (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
479          {
480           if(i)
481             {
482              PROFILE_FlushFile();
483              tempProfile=MRUProfile[i];
484              for(j=i;j>0;j--)
485                 MRUProfile[j]=MRUProfile[j-1];
486              CurProfile=tempProfile;
487             }
488           if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
489              TRACE("(%s): already opened (mru=%d)\n",
490                               filename, i );
491           else
492               TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
493                              filename, i );
494           return TRUE;
495          }
496       }
497
498     /* Flush the old current profile */
499     PROFILE_FlushFile();
500
501     /* Make the oldest profile the current one only in order to get rid of it */
502     if(i==N_CACHED_PROFILES)
503       {
504        tempProfile=MRUProfile[N_CACHED_PROFILES-1];
505        for(i=N_CACHED_PROFILES-1;i>0;i--)
506           MRUProfile[i]=MRUProfile[i-1];
507        CurProfile=tempProfile;
508       }
509     if(CurProfile->filename) PROFILE_ReleaseFile();
510
511     /* OK, now that CurProfile is definitely free we assign it our new file */
512     newdos_name = HEAP_strdupA( SystemHeap, 0, full_name.short_name );
513     CurProfile->dos_name  = newdos_name;
514     CurProfile->filename  = HEAP_strdupA( SystemHeap, 0, filename );
515
516     /* Try to open the profile file, first in $HOME/.wine */
517
518     /* FIXME: this will need a more general solution */
519     if ((p = getenv( "HOME" )) != NULL)
520     {
521         strcpy( buffer, p );
522         strcat( buffer, "/.wine/" );
523         p = buffer + strlen(buffer);
524         strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
525         CharLowerA( p );
526         if ((file = fopen( buffer, "r" )))
527         {
528             TRACE("(%s): found it in %s\n",
529                              filename, buffer );
530             CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0, buffer );
531         }
532     }
533
534     if (!file)
535     {
536         CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0,
537                                              full_name.long_name );
538         if ((file = fopen( full_name.long_name, "r" )))
539             TRACE("(%s): found it in %s\n",
540                              filename, full_name.long_name );
541     }
542
543     if (file)
544     {
545         CurProfile->section = PROFILE_Load( file );
546         fclose( file );
547         if(!stat(CurProfile->unix_name,&buf))
548            CurProfile->mtime=buf.st_mtime;
549     }
550     else
551     {
552         /* Does not exist yet, we will create it in PROFILE_FlushFile */
553         WARN("profile file %s not found\n", newdos_name );
554     }
555     return TRUE;
556 }
557
558
559 /***********************************************************************
560  *           PROFILE_GetSection
561  *
562  * Returns all keys of a section.
563  * If return_values is TRUE, also include the corresponding values.
564  */
565 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
566                                LPSTR buffer, UINT len, BOOL handle_env,
567                                BOOL return_values )
568 {
569     PROFILEKEY *key;
570     while (section)
571     {
572         if (section->name && !strcasecmp( section->name, section_name ))
573         {
574             UINT oldlen = len;
575             for (key = section->key; key; key = key->next)
576             {
577                 if (len <= 2) break;
578                 if (!*key->name) continue;  /* Skip empty lines */
579                 if (IS_ENTRY_COMMENT(key->name)) continue;  /* Skip comments */
580                 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
581                 len -= strlen(buffer) + 1;
582                 buffer += strlen(buffer) + 1;
583                 if (return_values && key->value) {
584                         buffer[-1] = '=';
585                         PROFILE_CopyEntry ( buffer,
586                                 key->value, len - 1, handle_env );
587                         len -= strlen(buffer) + 1;
588                         buffer += strlen(buffer) + 1;
589                 }
590             }
591             *buffer = '\0';
592             if (len <= 1)
593                 /*If either lpszSection or lpszKey is NULL and the supplied
594                   destination buffer is too small to hold all the strings, 
595                   the last string is truncated and followed by two null characters.
596                   In this case, the return value is equal to cchReturnBuffer
597                   minus two. */
598             {
599                 buffer[-1] = '\0';
600                 return oldlen - 2;
601             }
602             return oldlen - len;
603         }
604         section = section->next;
605     }
606     buffer[0] = buffer[1] = '\0';
607     return 0;
608 }
609
610
611 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
612 {
613     LPSTR buf = buffer;
614     WORD l, cursize = 0;
615     PROFILESECTION *section;
616
617     for (section = CurProfile->section; section; section = section->next)
618         if (section->name) {
619             l = strlen(section->name);
620             cursize += l+1;
621             if (cursize > len+1)
622                 return len-2;
623
624             strcpy(buf, section->name);
625             buf += l+1;
626         }
627
628     *buf=0;
629     buf++;
630     return buf-buffer;
631 }
632
633
634 /***********************************************************************
635  *           PROFILE_GetString
636  *
637  * Get a profile string.
638  */
639 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
640                               LPCSTR def_val, LPSTR buffer, UINT len )
641 {
642     PROFILEKEY *key = NULL;
643
644     if (!def_val) def_val = "";
645     if (key_name && key_name[0])
646     {
647         key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
648         PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
649                            len, FALSE );
650         TRACE("('%s','%s','%s'): returning '%s'\n",
651                          section, key_name, def_val, buffer );
652         return strlen( buffer );
653     }
654     if (section && section[0])
655         return PROFILE_GetSection(CurProfile->section, section, buffer, len,
656                                 FALSE, FALSE);
657     /* undocumented; both section and key_name are NULL */
658     return PROFILE_GetSectionNames(buffer, len);
659 }
660
661
662 /***********************************************************************
663  *           PROFILE_SetString
664  *
665  * Set a profile string.
666  */
667 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
668                                LPCSTR value )
669 {
670     if (!key_name)  /* Delete a whole section */
671     {
672         TRACE("('%s')\n", section_name);
673         CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
674                                                       section_name );
675         return TRUE;         /* Even if PROFILE_DeleteSection() has failed,
676                                 this is not an error on application's level.*/
677     }
678     else if (!value)  /* Delete a key */
679     {
680         TRACE("('%s','%s')\n",
681                          section_name, key_name );
682         CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
683                                                   section_name, key_name );
684         return TRUE;          /* same error handling as above */
685     }
686     else  /* Set the key value */
687     {
688         PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
689                                         key_name, TRUE );
690         TRACE("('%s','%s','%s'): \n",
691                          section_name, key_name, value );
692         if (!key) return FALSE;
693         if (key->value)
694         {
695             if (!strcmp( key->value, value ))
696             {
697                 TRACE("  no change needed\n" );
698                 return TRUE;  /* No change needed */
699             }
700             TRACE("  replacing '%s'\n", key->value );
701             HeapFree( SystemHeap, 0, key->value );
702         }
703         else TRACE("  creating key\n" );
704         key->value = HEAP_strdupA( SystemHeap, 0, value );
705         CurProfile->changed = TRUE;
706     }
707     return TRUE;
708 }
709
710
711 /***********************************************************************
712  *           PROFILE_GetWineIniString
713  *
714  * Get a config string from the wine.ini file.
715  */
716 int PROFILE_GetWineIniString( const char *section, const char *key_name,
717                               const char *def, char *buffer, int len )
718 {
719     int ret;
720
721     EnterCriticalSection( &PROFILE_CritSect );
722
723     if (key_name)
724     {
725         PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
726         PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
727                            len, TRUE );
728         TRACE("('%s','%s','%s'): returning '%s'\n",
729                          section, key_name, def, buffer );
730         ret = strlen( buffer );
731     } 
732     else 
733     {
734        ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
735     }
736     LeaveCriticalSection( &PROFILE_CritSect );
737
738     return ret;
739 }
740
741
742 /***********************************************************************
743  *           PROFILE_GetWineIniInt
744  *
745  * Get a config integer from the wine.ini file.
746  */
747 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
748 {
749     char buffer[20];
750     char *p;
751     long result;
752     PROFILEKEY *key;
753     int ret;
754
755     EnterCriticalSection( &PROFILE_CritSect );
756
757     key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
758     if (!key || !key->value) {
759        ret = def;
760     } else {
761        PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
762        result = strtol( buffer, &p, 0 );
763        ret = (p == buffer) ? 0  /* No digits at all */ : (int)result;
764     }
765
766     LeaveCriticalSection( &PROFILE_CritSect );
767
768     return ret;
769 }
770
771
772 /******************************************************************************
773  *
774  *   int  PROFILE_EnumerateWineIniSection(
775  *     char const  *section,  #Name of the section to enumerate
776  *     void  (*cbfn)(char const *key, char const *value, void *user),
777  *                            # Address of the callback function 
778  *     void  *user )          # User-specified pointer.
779  *
780  *   For each entry in a section in the wine.conf file, this function will
781  *   call the specified callback function, informing it of each key and
782  *   value.  An optional user pointer may be passed to it (if this is not
783  *   needed, pass NULL through it and ignore the value in the callback
784  *   function).
785  *
786  *   The callback function must accept three parameters:
787  *      The name of the key (char const *)
788  *      The value of the key (char const *)
789  *      A user-specified parameter (void *)
790  *   Note that the first two are char CONST *'s, not char *'s!  The callback
791  *   MUST not modify these strings!
792  *
793  *   The return value indicates the number of times the callback function
794  *   was called.
795  */
796 int  PROFILE_EnumerateWineIniSection(
797     char const  *section,
798     void  (*cbfn)(char const *, char const *, void *),
799     void  *userptr )
800 {
801     PROFILESECTION  *scansect;
802     PROFILEKEY  *scankey;
803     int  calls = 0;
804
805     EnterCriticalSection( &PROFILE_CritSect );
806
807     /* Search for the correct section */
808     for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
809         if(scansect->name && !strcasecmp(scansect->name, section)) {
810
811             /* Enumerate each key with the callback */
812             for(scankey = scansect->key; scankey; scankey = scankey->next) {
813
814                 /* Ignore blank entries -- these shouldn't exist, but let's
815                    be extra careful */
816                 if (!scankey->name[0]) continue;
817                 if (!scankey->value) cbfn(scankey->name, NULL, userptr);
818                 else
819                 {
820                     char value[1024];
821                     PROFILE_CopyEntry(value, scankey->value, sizeof(value), TRUE);
822                     cbfn(scankey->name, value, userptr);
823                 }
824                 ++calls;
825             }
826         
827             break;
828         }
829     }
830     LeaveCriticalSection( &PROFILE_CritSect );
831
832     return calls;
833 }
834
835
836 /******************************************************************************
837  *
838  *   int  PROFILE_GetWineIniBool(
839  *      char const  *section,
840  *      char const  *key_name,
841  *      int  def )
842  *
843  *   Reads a boolean value from the wine.ini file.  This function attempts to
844  *   be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
845  *   (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
846  *   true.  Anything else results in the return of the default value.
847  *
848  *   This function uses 1 to indicate true, and 0 for false.  You can check
849  *   for existence by setting def to something other than 0 or 1 and
850  *   examining the return value.
851  */
852 int  PROFILE_GetWineIniBool(
853     char const  *section,
854     char const  *key_name,
855     int  def )
856 {
857     char  key_value[2];
858     int  retval;
859
860     PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
861
862     switch(key_value[0]) {
863     case 'n':
864     case 'N':
865     case 'f':
866     case 'F':
867     case '0':
868         retval = 0;
869         break;
870
871     case 'y':
872     case 'Y':
873     case 't':
874     case 'T':
875     case '1':
876         retval = 1;
877         break;
878
879     default:
880         retval = def;
881     }
882
883     TRACE("(\"%s\", \"%s\", %s), "
884                     "[%c], ret %s.\n", section, key_name,
885                     def ? "TRUE" : "FALSE", key_value[0],
886                     retval ? "TRUE" : "FALSE");
887
888     return retval;
889 }
890
891
892 /***********************************************************************
893  *           PROFILE_LoadWineIni
894  *
895  * Load the wine.ini file.
896  */
897 int PROFILE_LoadWineIni(void)
898 {
899     char buffer[MAX_PATHNAME_LEN];
900     const char *p;
901     FILE *f;
902
903     InitializeCriticalSection( &PROFILE_CritSect );
904     MakeCriticalSectionGlobal( &PROFILE_CritSect );
905
906     if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
907     {
908       /* Open -config specified file */
909       PROFILE_WineProfile = PROFILE_Load ( f);
910       fclose ( f );
911       lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
912       return 1;
913     }
914
915     if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
916     {
917         PROFILE_WineProfile = PROFILE_Load( f );
918         fclose( f );
919         lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
920         return 1;
921     }
922     if ((p = getenv( "HOME" )) != NULL)
923     {
924         lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
925         strcat( buffer, PROFILE_WineIniName );
926         if ((f = fopen( buffer, "r" )) != NULL)
927         {
928             PROFILE_WineProfile = PROFILE_Load( f );
929             fclose( f );
930             lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
931             return 1;
932         }
933     }
934     else WARN("could not get $HOME value for config file.\n" );
935
936     /* Try global file */
937
938     if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
939     {
940         PROFILE_WineProfile = PROFILE_Load( f );
941         fclose( f );
942         lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
943         return 1;
944     }
945     MESSAGE( "Can't open configuration file %s or $HOME%s\n",
946          WINE_INI_GLOBAL, PROFILE_WineIniName );
947     return 0;
948 }
949
950
951 /***********************************************************************
952  *           PROFILE_UsageWineIni
953  *
954  * Explain the wine.ini file to those who don't read documentation.
955  * Keep below one screenful in length so that error messages above are
956  * noticed.
957  */
958 void PROFILE_UsageWineIni(void)
959 {
960     MESSAGE("Perhaps you have not properly edited or created "
961         "your Wine configuration file.\n");
962     MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
963     MESSAGE("  or it is determined by the -config option or from\n"
964         "  the WINE_INI environment variable.\n");
965     if (*PROFILE_WineIniUsed)
966         MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
967     /* RTFM, so to say */
968 }
969
970 /***********************************************************************
971  *           PROFILE_GetStringItem
972  *
973  *  Convenience function that turns a string 'xxx, yyy, zzz' into 
974  *  the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
975  */
976 char* PROFILE_GetStringItem( char* start )
977 {
978     char* lpchX, *lpch;
979
980     for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
981     {
982         if( *lpchX == ',' )
983         {
984             if( lpch ) *lpch = '\0'; else *lpchX = '\0';
985             while( *(++lpchX) )
986                 if( !PROFILE_isspace(*lpchX) ) return lpchX;
987         }
988         else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
989              else lpch = NULL;
990     }
991     if( lpch ) *lpch = '\0';
992     return NULL;
993 }
994
995 /********************* API functions **********************************/
996
997 /***********************************************************************
998  *           GetProfileInt16   (KERNEL.57)
999  */
1000 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1001 {
1002     return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1003 }
1004
1005
1006 /***********************************************************************
1007  *           GetProfileInt32A   (KERNEL32.264)
1008  */
1009 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1010 {
1011     return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1012 }
1013
1014 /***********************************************************************
1015  *           GetProfileInt32W   (KERNEL32.264)
1016  */
1017 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1018 {
1019     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1020     return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1021 }
1022
1023 /***********************************************************************
1024  *           GetProfileString16   (KERNEL.58)
1025  */
1026 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1027                                  LPSTR buffer, UINT16 len )
1028 {
1029     return GetPrivateProfileString16( section, entry, def_val,
1030                                       buffer, len, "win.ini" );
1031 }
1032
1033 /***********************************************************************
1034  *           GetProfileString32A   (KERNEL32.268)
1035  */
1036 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1037                               LPSTR buffer, UINT len )
1038 {
1039     return GetPrivateProfileStringA( section, entry, def_val,
1040                                      buffer, len, "win.ini" );
1041 }
1042
1043 /***********************************************************************
1044  *           GetProfileString32W   (KERNEL32.269)
1045  */
1046 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1047                               LPCWSTR def_val, LPWSTR buffer, UINT len )
1048 {
1049     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1050     return GetPrivateProfileStringW( section, entry, def_val,
1051                                      buffer, len, wininiW );
1052 }
1053
1054 /***********************************************************************
1055  *           WriteProfileString16   (KERNEL.59)
1056  */
1057 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1058                                     LPCSTR string )
1059 {
1060     return WritePrivateProfileString16( section, entry, string, "win.ini" );
1061 }
1062
1063 /***********************************************************************
1064  *           WriteProfileString32A   (KERNEL32.587)
1065  */
1066 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1067                                  LPCSTR string )
1068 {
1069     return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1070 }
1071
1072 /***********************************************************************
1073  *           WriteProfileString32W   (KERNEL32.588)
1074  */
1075 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1076                                      LPCWSTR string )
1077 {
1078     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1079     return WritePrivateProfileStringW( section, entry, string, wininiW );
1080 }
1081
1082
1083 /***********************************************************************
1084  *           GetPrivateProfileInt16   (KERNEL.127)
1085  */
1086 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1087                                       INT16 def_val, LPCSTR filename )
1088 {
1089     long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1090
1091     if (result > 65535) return 65535;
1092     if (result >= 0) return (UINT16)result;
1093     if (result < -32768) return -32768;
1094     return (UINT16)(INT16)result;
1095 }
1096
1097 /***********************************************************************
1098  *           GetPrivateProfileInt32A   (KERNEL32.251)
1099  */
1100 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1101                                    INT def_val, LPCSTR filename )
1102 {
1103     char buffer[20];
1104     char *p;
1105     long result;
1106
1107     GetPrivateProfileStringA( section, entry, "",
1108                                 buffer, sizeof(buffer), filename );
1109     if (!buffer[0]) return (UINT)def_val;
1110     result = strtol( buffer, &p, 0 );
1111     if (p == buffer) return 0;  /* No digits at all */
1112     return (UINT)result;
1113 }
1114
1115 /***********************************************************************
1116  *           GetPrivateProfileInt32W   (KERNEL32.252)
1117  */
1118 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1119                                    INT def_val, LPCWSTR filename )
1120 {
1121     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1122     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1123     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1124     UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1125     HeapFree( GetProcessHeap(), 0, sectionA );
1126     HeapFree( GetProcessHeap(), 0, filenameA );
1127     HeapFree( GetProcessHeap(), 0, entryA );
1128     return res;
1129 }
1130
1131 /***********************************************************************
1132  *           GetPrivateProfileString16   (KERNEL.128)
1133  */
1134 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1135                                         LPCSTR def_val, LPSTR buffer,
1136                                         UINT16 len, LPCSTR filename )
1137 {
1138     return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1139 }
1140
1141 /***********************************************************************
1142  *           GetPrivateProfileString32A   (KERNEL32.255)
1143  */
1144 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1145                                      LPCSTR def_val, LPSTR buffer,
1146                                      UINT len, LPCSTR filename )
1147 {
1148     int         ret;
1149
1150     if (!filename) 
1151         filename = "win.ini";
1152
1153     EnterCriticalSection( &PROFILE_CritSect );
1154
1155     if (PROFILE_Open( filename )) {
1156         ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1157     } else {
1158        lstrcpynA( buffer, def_val, len );
1159        ret = strlen( buffer );
1160     }
1161
1162     LeaveCriticalSection( &PROFILE_CritSect );
1163     
1164     return ret;
1165 }
1166
1167 /***********************************************************************
1168  *           GetPrivateProfileString32W   (KERNEL32.256)
1169  */
1170 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1171                                      LPCWSTR def_val, LPWSTR buffer,
1172                                      UINT len, LPCWSTR filename )
1173 {
1174     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1175     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1176     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1177     LPSTR def_valA  = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1178     LPSTR bufferA   = HeapAlloc( GetProcessHeap(), 0, len );
1179     INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1180                                             bufferA, len, filenameA );
1181     lstrcpynAtoW( buffer, bufferA, len );
1182     HeapFree( GetProcessHeap(), 0, sectionA );
1183     HeapFree( GetProcessHeap(), 0, entryA );
1184     HeapFree( GetProcessHeap(), 0, filenameA );
1185     HeapFree( GetProcessHeap(), 0, def_valA );
1186     HeapFree( GetProcessHeap(), 0, bufferA);
1187     return ret;
1188 }
1189
1190 /***********************************************************************
1191  *           GetPrivateProfileSection16   (KERNEL.418)
1192  */
1193 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1194                                         UINT16 len, LPCSTR filename )
1195 {
1196     return GetPrivateProfileSectionA( section, buffer, len, filename );
1197 }
1198
1199 /***********************************************************************
1200  *           GetPrivateProfileSection32A   (KERNEL32.255)
1201  */
1202 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1203                                       DWORD len, LPCSTR filename )
1204 {
1205     int         ret = 0;
1206
1207     EnterCriticalSection( &PROFILE_CritSect );
1208
1209     if (PROFILE_Open( filename ))
1210         ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1211                                  FALSE, TRUE);
1212     
1213     LeaveCriticalSection( &PROFILE_CritSect );
1214
1215     return ret;
1216 }
1217
1218 /***********************************************************************
1219  *           GetPrivateProfileSection32W   (KERNEL32.256)
1220  */
1221
1222 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1223                                       DWORD len, LPCWSTR filename )
1224
1225 {
1226     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1227     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1228     LPSTR bufferA   = HeapAlloc( GetProcessHeap(), 0, len );
1229     INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len, 
1230                                                 filenameA );
1231     MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1232     HeapFree( GetProcessHeap(), 0, sectionA );
1233     HeapFree( GetProcessHeap(), 0, filenameA );
1234     HeapFree( GetProcessHeap(), 0, bufferA);
1235     return ret;
1236 }
1237
1238 /***********************************************************************
1239  *           GetProfileSection16   (KERNEL.419)
1240  */
1241 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1242 {
1243     return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1244 }
1245
1246 /***********************************************************************
1247  *           GetProfileSection32A   (KERNEL32.268)
1248  */
1249 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1250 {
1251     return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1252 }
1253
1254 /***********************************************************************
1255  *           GetProfileSection32W   (KERNEL32)
1256  */
1257 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1258 {
1259     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1260     return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1261 }
1262
1263
1264 /***********************************************************************
1265  *           WritePrivateProfileString16   (KERNEL.129)
1266  */
1267 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1268                                            LPCSTR string, LPCSTR filename )
1269 {
1270     return WritePrivateProfileStringA(section,entry,string,filename);
1271 }
1272
1273 /***********************************************************************
1274  *           WritePrivateProfileString32A   (KERNEL32.582)
1275  */
1276 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1277                                         LPCSTR string, LPCSTR filename )
1278 {
1279     BOOL ret = FALSE;
1280
1281     EnterCriticalSection( &PROFILE_CritSect );
1282
1283     if (PROFILE_Open( filename ))
1284     {
1285         if (!section && !entry && !string)
1286             PROFILE_ReleaseFile();  /* always return FALSE in this case */
1287         else
1288             ret = PROFILE_SetString( section, entry, string );
1289     }
1290
1291     LeaveCriticalSection( &PROFILE_CritSect );
1292     return ret;
1293 }
1294
1295 /***********************************************************************
1296  *           WritePrivateProfileString32W   (KERNEL32.583)
1297  */
1298 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1299                                         LPCWSTR string, LPCWSTR filename )
1300 {
1301     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1302     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1303     LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1304     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1305     BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1306                                            stringA, filenameA );
1307     HeapFree( GetProcessHeap(), 0, sectionA );
1308     HeapFree( GetProcessHeap(), 0, entryA );
1309     HeapFree( GetProcessHeap(), 0, stringA );
1310     HeapFree( GetProcessHeap(), 0, filenameA );
1311     return res;
1312 }
1313
1314 /***********************************************************************
1315  *           WritePrivateProfileSection16   (KERNEL.416)
1316  */
1317 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section, 
1318                                             LPCSTR string, LPCSTR filename )
1319 {
1320     return WritePrivateProfileSectionA( section, string, filename );
1321 }
1322
1323 /***********************************************************************
1324  *           WritePrivateProfileSection32A   (KERNEL32)
1325  */
1326 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section, 
1327                                          LPCSTR string, LPCSTR filename )
1328 {
1329     char *p =(char*)string;
1330
1331     FIXME("WritePrivateProfileSection32A empty stub\n");
1332     if (TRACE_ON(profile)) {
1333       TRACE("(%s) => [%s]\n", filename, section);
1334       while (*(p+1)) {
1335         TRACE("%s\n", p);
1336         p += strlen(p);
1337         p += 1;
1338       }
1339     }
1340     
1341     return FALSE;
1342 }
1343
1344 /***********************************************************************
1345  *           WritePrivateProfileSection32W   (KERNEL32)
1346  */
1347 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1348                                          LPCWSTR string, LPCWSTR filename)
1349
1350 {
1351     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1352     LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1353     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1354     BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1355     HeapFree( GetProcessHeap(), 0, sectionA );
1356     HeapFree( GetProcessHeap(), 0, stringA );
1357     HeapFree( GetProcessHeap(), 0, filenameA );
1358     return res;
1359 }
1360
1361 /***********************************************************************
1362  *           WriteProfileSection16   (KERNEL.417)
1363  */
1364 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1365 {
1366     return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1367 }
1368
1369 /***********************************************************************
1370  *           WriteProfileSection32A   (KERNEL32.747)
1371  */
1372 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1373                                      
1374 {
1375     return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1376 }
1377
1378 /***********************************************************************
1379  *           WriteProfileSection32W   (KERNEL32.748)
1380  */
1381 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1382 {
1383    if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini");
1384    
1385    return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1386 }
1387
1388 /***********************************************************************
1389  *           GetPrivateProfileSectionNames16   (KERNEL.143)
1390  */
1391 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1392                                              LPCSTR filename )
1393 {
1394     WORD ret = 0;
1395
1396     EnterCriticalSection( &PROFILE_CritSect );
1397
1398     if (PROFILE_Open( filename ))
1399         ret = PROFILE_GetSectionNames(buffer, size);
1400
1401     LeaveCriticalSection( &PROFILE_CritSect );
1402
1403     return ret;
1404 }
1405
1406
1407 /***********************************************************************
1408  *           GetProfileSectionNames16   (KERNEL.142)
1409  */
1410 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1411
1412 {
1413     return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1414 }
1415
1416
1417 /***********************************************************************
1418  *           GetPrivateProfileSectionNames32A  (KERNEL32.365)
1419  */
1420 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1421                                              LPCSTR filename)
1422
1423 {
1424  return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1425 }
1426
1427
1428 /***********************************************************************
1429  *           GetPrivateProfileSectionNames32W  (KERNEL32.366)
1430  */
1431 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1432                                              LPCWSTR filename)
1433
1434 {
1435    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1436    LPSTR bufferA   = HeapAlloc( GetProcessHeap(), 0, size);
1437
1438    INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1439    lstrcpynAtoW( buffer, bufferA, size);   
1440    HeapFree( GetProcessHeap(), 0, bufferA);
1441    HeapFree( GetProcessHeap(), 0, filenameA );
1442
1443    return ret;
1444 }
1445
1446 /***********************************************************************
1447  *           GetPrivateProfileStruct16 (KERNEL.407)
1448  */
1449 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key, 
1450                                         LPVOID buf, UINT16 len, LPCSTR filename)
1451 {
1452     return GetPrivateProfileStructA( section, key, buf, len, filename );
1453 }
1454
1455 /***********************************************************************
1456  *           GetPrivateProfileStruct32A (KERNEL32.370)
1457  */
1458 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key, 
1459                                       LPVOID buf, UINT len, LPCSTR filename)
1460 {
1461     BOOL        ret = FALSE;
1462
1463     EnterCriticalSection( &PROFILE_CritSect );
1464
1465     if (PROFILE_Open( filename )) {
1466         PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1467         if (k) {
1468            lstrcpynA( buf, k->value, strlen(k->value));
1469            ret = TRUE;
1470         }
1471     }
1472     LeaveCriticalSection( &PROFILE_CritSect );
1473
1474     return FALSE;
1475 }
1476
1477 /***********************************************************************
1478  *           GetPrivateProfileStruct32W (KERNEL32.543)
1479  */
1480 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1481                                       LPVOID buffer, UINT len, LPCWSTR filename)
1482 {
1483     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1484     LPSTR keyA      = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1485     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1486     LPSTR bufferA   = HeapAlloc( GetProcessHeap(), 0, len );
1487
1488     INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1489                                         len, filenameA );
1490     lstrcpynAtoW( buffer, bufferA, len );
1491     HeapFree( GetProcessHeap(), 0, bufferA);
1492     HeapFree( GetProcessHeap(), 0, sectionA );
1493     HeapFree( GetProcessHeap(), 0, keyA );
1494     HeapFree( GetProcessHeap(), 0, filenameA );
1495
1496     return ret;
1497 }
1498
1499
1500
1501 /***********************************************************************
1502  *           WritePrivateProfileStruct16 (KERNEL.406)
1503  */
1504 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key, 
1505         LPVOID buf, UINT16 bufsize, LPCSTR filename)
1506 {
1507     return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1508 }
1509
1510 /***********************************************************************
1511  *           WritePrivateProfileStruct32A (KERNEL32.744)
1512  */
1513 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key, 
1514                                         LPVOID buf, UINT bufsize, LPCSTR filename)
1515 {
1516     BOOL ret = FALSE;
1517
1518     if (!section && !key && !buf)  /* flush the cache */
1519         return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1520
1521     EnterCriticalSection( &PROFILE_CritSect );
1522
1523     if (PROFILE_Open( filename )) 
1524         ret = PROFILE_SetString( section, key, buf );
1525
1526     LeaveCriticalSection( &PROFILE_CritSect );
1527
1528     return ret;
1529 }
1530
1531 /***********************************************************************
1532  *           WritePrivateProfileStruct32W (KERNEL32.544)
1533  */
1534 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1535                                         LPVOID buf, UINT bufsize, LPCWSTR filename)
1536 {
1537     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1538     LPSTR keyA      = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1539     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1540     INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1541                                           filenameA );
1542     HeapFree( GetProcessHeap(), 0, sectionA );
1543     HeapFree( GetProcessHeap(), 0, keyA );
1544     HeapFree( GetProcessHeap(), 0, filenameA );
1545
1546     return ret;
1547 }
1548
1549
1550 /***********************************************************************
1551  *           WriteOutProfiles   (KERNEL.315)
1552  */
1553 void WINAPI WriteOutProfiles16(void)
1554 {
1555     EnterCriticalSection( &PROFILE_CritSect );
1556     PROFILE_FlushFile();
1557     LeaveCriticalSection( &PROFILE_CritSect );
1558 }
1559
1560 /***********************************************************************
1561  *           CloseProfileUserMapping   (KERNEL.138)
1562  */
1563 BOOL WINAPI CloseProfileUserMapping(void) {
1564     FIXME("(), stub!\n");
1565     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1566     return FALSE;
1567 }