Release 980809
[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 "windows.h"
15 #include "file.h"
16 #include "heap.h"
17 #include "debug.h"
18
19 typedef struct tagPROFILEKEY
20 {
21     char                  *name;
22     char                  *value;
23     struct tagPROFILEKEY  *next;
24 } PROFILEKEY;
25
26 typedef struct tagPROFILESECTION
27 {
28     char                       *name;
29     struct tagPROFILEKEY       *key;
30     struct tagPROFILESECTION   *next;
31 } PROFILESECTION; 
32
33
34 typedef struct
35 {
36     BOOL32           changed;
37     PROFILESECTION  *section;
38     char            *dos_name;
39     char            *unix_name;
40     char            *filename;
41     time_t           mtime;
42 } PROFILE;
43
44
45 #define N_CACHED_PROFILES 10
46
47 /* Cached profile files */
48 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
49
50 #define CurProfile (MRUProfile[0])
51
52 /* wine.ini profile content */
53 static PROFILESECTION *WineProfile;
54
55 #define PROFILE_MAX_LINE_LEN   1024
56
57 /* Wine profile name in $HOME directory; must begin with slash */
58 static const char PROFILE_WineIniName[] = "/.winerc";
59
60 /* Check for comments in profile */
61 #define IS_ENTRY_COMMENT(str)  ((str)[0] == ';')
62
63 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
64
65 static LPCWSTR wininiW = NULL;
66
67 /***********************************************************************
68  *           PROFILE_CopyEntry
69  *
70  * Copy the content of an entry into a buffer, removing quotes, and possibly
71  * translating environment variables.
72  */
73 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
74                                int handle_env )
75 {
76     char quote = '\0';
77     const char *p;
78
79     if ((*value == '\'') || (*value == '\"'))
80     {
81         if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
82     }
83
84     if (!handle_env)
85     {
86         lstrcpyn32A( buffer, value, len );
87         if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
88         return;
89     }
90
91     for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
92     {
93         if ((*p == '$') && (p[1] == '{'))
94         {
95             char env_val[1024];
96             const char *env_p;
97             const char *p2 = strchr( p, '}' );
98             if (!p2) continue;  /* ignore it */
99             lstrcpyn32A(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
100             if ((env_p = getenv( env_val )) != NULL)
101             {
102                 lstrcpyn32A( buffer, env_p, len );
103                 buffer += strlen( buffer );
104                 len -= strlen( buffer );
105             }
106             p = p2 + 1;
107         }
108     }
109     *buffer = '\0';
110 }
111
112
113 /***********************************************************************
114  *           PROFILE_Save
115  *
116  * Save a profile tree to a file.
117  */
118 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
119 {
120     PROFILEKEY *key;
121
122     for ( ; section; section = section->next)
123     {
124         if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
125         for (key = section->key; key; key = key->next)
126         {
127             fprintf( file, "%s", key->name );
128             if (key->value) fprintf( file, "=%s", key->value );
129             fprintf( file, "\r\n" );
130         }
131     }
132 }
133
134
135 /***********************************************************************
136  *           PROFILE_Free
137  *
138  * Free a profile tree.
139  */
140 static void PROFILE_Free( PROFILESECTION *section )
141 {
142     PROFILESECTION *next_section;
143     PROFILEKEY *key, *next_key;
144
145     for ( ; section; section = next_section)
146     {
147         if (section->name) HeapFree( SystemHeap, 0, section->name );
148         for (key = section->key; key; key = next_key)
149         {
150             next_key = key->next;
151             if (key->name) HeapFree( SystemHeap, 0, key->name );
152             if (key->value) HeapFree( SystemHeap, 0, key->value );
153             HeapFree( SystemHeap, 0, key );
154         }
155         next_section = section->next;
156         HeapFree( SystemHeap, 0, section );
157     }
158 }
159
160 static int
161 PROFILE_isspace(char c) {
162         if (isspace(c)) return 1;
163         if (c=='\r' || c==0x1a) return 1;
164         /* CR and ^Z (DOS EOF) are spaces too  (found on CD-ROMs) */
165         return 0;
166 }
167
168
169 /***********************************************************************
170  *           PROFILE_Load
171  *
172  * Load a profile tree from a file.
173  */
174 static PROFILESECTION *PROFILE_Load( FILE *file )
175 {
176     char buffer[PROFILE_MAX_LINE_LEN];
177     char *p, *p2;
178     int line = 0;
179     PROFILESECTION *section, *first_section;
180     PROFILESECTION **next_section;
181     PROFILEKEY *key, *prev_key, **next_key;
182
183     first_section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
184     first_section->name = NULL;
185     first_section->key  = NULL;
186     first_section->next = NULL;
187     next_section = &first_section->next;
188     next_key     = &first_section->key;
189     prev_key     = NULL;
190
191     while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
192     {
193         line++;
194         p = buffer;
195         while (*p && PROFILE_isspace(*p)) p++;
196         if (*p == '[')  /* section start */
197         {
198             if (!(p2 = strrchr( p, ']' )))
199             {
200                 WARN(profile, "Invalid section header at line %d: '%s'\n",
201                      line, p );
202             }
203             else
204             {
205                 *p2 = '\0';
206                 p++;
207                 section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
208                 section->name = HEAP_strdupA( SystemHeap, 0, p );
209                 section->key  = NULL;
210                 section->next = NULL;
211                 *next_section = section;
212                 next_section  = &section->next;
213                 next_key      = &section->key;
214                 prev_key      = NULL;
215
216                 TRACE(profile, "New section: '%s'\n",section->name);
217
218                 continue;
219             }
220         }
221
222         p2=p+strlen(p) - 1;
223         while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
224
225         if ((p2 = strchr( p, '=' )) != NULL)
226         {
227             char *p3 = p2 - 1;
228             while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
229             *p2++ = '\0';
230             while (*p2 && PROFILE_isspace(*p2)) p2++;
231         }
232
233         if(*p || !prev_key || *prev_key->name)
234           {
235            key = HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
236            key->name  = HEAP_strdupA( SystemHeap, 0, p );
237            key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
238            key->next  = NULL;
239            *next_key  = key;
240            next_key   = &key->next;
241            prev_key   = key;
242
243            TRACE(profile, "New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
244           }
245     }
246     return first_section;
247 }
248
249
250 /***********************************************************************
251  *           PROFILE_DeleteSection
252  *
253  * Delete a section from a profile tree.
254  */
255 static BOOL32 PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
256 {
257     while (*section)
258     {
259         if ((*section)->name && !strcasecmp( (*section)->name, name ))
260         {
261             PROFILESECTION *to_del = *section;
262             *section = to_del->next;
263             to_del->next = NULL;
264             PROFILE_Free( to_del );
265             return TRUE;
266         }
267         section = &(*section)->next;
268     }
269     return FALSE;
270 }
271
272
273 /***********************************************************************
274  *           PROFILE_DeleteKey
275  *
276  * Delete a key from a profile tree.
277  */
278 static BOOL32 PROFILE_DeleteKey( PROFILESECTION **section,
279                                  LPCSTR section_name, LPCSTR key_name )
280 {
281     while (*section)
282     {
283         if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
284         {
285             PROFILEKEY **key = &(*section)->key;
286             while (*key)
287             {
288                 if (!strcasecmp( (*key)->name, key_name ))
289                 {
290                     PROFILEKEY *to_del = *key;
291                     *key = to_del->next;
292                     if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
293                     if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
294                     HeapFree( SystemHeap, 0, to_del );
295                     return TRUE;
296                 }
297                 key = &(*key)->next;
298             }
299         }
300         section = &(*section)->next;
301     }
302     return FALSE;
303 }
304
305
306 /***********************************************************************
307  *           PROFILE_Find
308  *
309  * Find a key in a profile tree, optionally creating it.
310  */
311 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
312                                  const char *section_name,
313                                  const char *key_name, int create )
314 {
315     while (*section)
316     {
317         if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
318         {
319             PROFILEKEY **key = &(*section)->key;
320             while (*key)
321             {
322                 if (!strcasecmp( (*key)->name, key_name )) return *key;
323                 key = &(*key)->next;
324             }
325             if (!create) return NULL;
326             *key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
327             (*key)->name  = HEAP_strdupA( SystemHeap, 0, key_name );
328             (*key)->value = NULL;
329             (*key)->next  = NULL;
330             return *key;
331         }
332         section = &(*section)->next;
333     }
334     if (!create) return NULL;
335     *section = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
336     (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
337     (*section)->next = NULL;
338     (*section)->key  = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
339     (*section)->key->name  = HEAP_strdupA( SystemHeap, 0, key_name );
340     (*section)->key->value = NULL;
341     (*section)->key->next  = NULL;
342     return (*section)->key;
343 }
344
345
346 /***********************************************************************
347  *           PROFILE_FlushFile
348  *
349  * Flush the current profile to disk if changed.
350  */
351 static BOOL32 PROFILE_FlushFile(void)
352 {
353     char *p, buffer[MAX_PATHNAME_LEN];
354     const char *unix_name;
355     FILE *file = NULL;
356     struct stat buf;
357
358     if(!CurProfile)
359     {
360         WARN(profile, "No current profile!\n");
361         return FALSE;
362     }
363
364     if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
365     if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
366     {
367         /* Try to create it in $HOME/.wine */
368         /* FIXME: this will need a more general solution */
369         if ((p = getenv( "HOME" )) != NULL)
370         {
371             strcpy( buffer, p );
372             strcat( buffer, "/.wine/" );
373             p = buffer + strlen(buffer);
374             strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
375             CharLower32A( p );
376             file = fopen( buffer, "w" );
377             unix_name = buffer;
378         }
379     }
380     
381     if (!file)
382     {
383         WARN(profile, "could not save profile file %s\n", CurProfile->dos_name);
384         return FALSE;
385     }
386
387     TRACE(profile, "Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
388     PROFILE_Save( file, CurProfile->section );
389     fclose( file );
390     CurProfile->changed = FALSE;
391     if(!stat(unix_name,&buf))
392        CurProfile->mtime=buf.st_mtime;
393     return TRUE;
394 }
395
396
397 /***********************************************************************
398  *           PROFILE_Open
399  *
400  * Open a profile file, checking the cached file first.
401  */
402 static BOOL32 PROFILE_Open( LPCSTR filename )
403 {
404     DOS_FULL_NAME full_name;
405     char buffer[MAX_PATHNAME_LEN];
406     char *newdos_name, *p;
407     FILE *file = NULL;
408     int i,j;
409     struct stat buf;
410     PROFILE *tempProfile;
411
412     /* First time around */
413
414     if(!CurProfile)
415        for(i=0;i<N_CACHED_PROFILES;i++)
416          {
417           MRUProfile[i]=HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
418           MRUProfile[i]->changed=FALSE;
419           MRUProfile[i]->section=NULL;
420           MRUProfile[i]->dos_name=NULL;
421           MRUProfile[i]->unix_name=NULL;
422           MRUProfile[i]->filename=NULL;
423           MRUProfile[i]->mtime=0;
424          }
425
426     /* Check for a match */
427
428     if (strchr( filename, '/' ) || strchr( filename, '\\' ) || 
429         strchr( filename, ':' ))
430     {
431         if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
432     }
433     else
434     {
435         GetWindowsDirectory32A( buffer, sizeof(buffer) );
436         strcat( buffer, "\\" );
437         strcat( buffer, filename );
438         if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
439     }
440
441     for(i=0;i<N_CACHED_PROFILES;i++)
442       {
443        if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
444            (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
445          {
446           if(i)
447             {
448              PROFILE_FlushFile();
449              tempProfile=MRUProfile[i];
450              for(j=i;j>0;j--)
451                 MRUProfile[j]=MRUProfile[j-1];
452              CurProfile=tempProfile;
453             }
454           if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
455              TRACE(profile, "(%s): already opened (mru=%d)\n",
456                               filename, i );
457           else
458               TRACE(profile, "(%s): already opened, needs refreshing (mru=%d)\n",
459                              filename, i );
460           return TRUE;
461          }
462       }
463
464     /* Rotate the oldest to the top to be replaced */
465
466     if(i==N_CACHED_PROFILES)
467       {
468        tempProfile=MRUProfile[N_CACHED_PROFILES-1];
469        for(i=N_CACHED_PROFILES-1;i>0;i--)
470           MRUProfile[i]=MRUProfile[i-1];
471        CurProfile=tempProfile;
472       }
473
474     /* Flush the profile */
475
476     if(CurProfile->filename)
477       {
478        PROFILE_FlushFile();
479        PROFILE_Free( CurProfile->section );
480        if (CurProfile->dos_name) HeapFree( SystemHeap, 0, CurProfile->dos_name );
481        if (CurProfile->unix_name) HeapFree( SystemHeap, 0, CurProfile->unix_name );
482        if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
483        CurProfile->changed=FALSE;
484        CurProfile->section=NULL;
485        CurProfile->dos_name=NULL;
486        CurProfile->unix_name=NULL;
487        CurProfile->filename=NULL;
488        CurProfile->mtime=0;
489       }
490
491     newdos_name = HEAP_strdupA( SystemHeap, 0, full_name.short_name );
492     CurProfile->dos_name  = newdos_name;
493     CurProfile->filename  = HEAP_strdupA( SystemHeap, 0, filename );
494
495     /* Try to open the profile file, first in $HOME/.wine */
496
497     /* FIXME: this will need a more general solution */
498     if ((p = getenv( "HOME" )) != NULL)
499     {
500         strcpy( buffer, p );
501         strcat( buffer, "/.wine/" );
502         p = buffer + strlen(buffer);
503         strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
504         CharLower32A( p );
505         if ((file = fopen( buffer, "r" )))
506         {
507             TRACE(profile, "(%s): found it in %s\n",
508                              filename, buffer );
509             CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0, buffer );
510         }
511     }
512
513     if (!file)
514     {
515         CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0,
516                                              full_name.long_name );
517         if ((file = fopen( full_name.long_name, "r" )))
518             TRACE(profile, "(%s): found it in %s\n",
519                              filename, full_name.long_name );
520     }
521
522     if (file)
523     {
524         CurProfile->section = PROFILE_Load( file );
525         fclose( file );
526         if(!stat(CurProfile->unix_name,&buf))
527            CurProfile->mtime=buf.st_mtime;
528     }
529     else
530     {
531         /* Does not exist yet, we will create it in PROFILE_FlushFile */
532         WARN(profile, "profile file %s not found\n", newdos_name );
533     }
534     return TRUE;
535 }
536
537
538 /***********************************************************************
539  *           PROFILE_GetSection
540  *
541  * Returns all keys of a section.
542  * If return_values is TRUE, also include the corresponding values.
543  */
544 static INT32 PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
545                                  LPSTR buffer, UINT32 len, BOOL32 handle_env,
546                                  BOOL32 return_values )
547 {
548     PROFILEKEY *key;
549     while (section)
550     {
551         if (section->name && !strcasecmp( section->name, section_name ))
552         {
553             UINT32 oldlen = len;
554             for (key = section->key; key && *(key->name); key = key->next)
555             {
556                 if (len <= 2) break;
557                 if (IS_ENTRY_COMMENT(key->name)) continue;  /* Skip comments */
558                 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
559                 len -= strlen(buffer) + 1;
560                 buffer += strlen(buffer) + 1;
561                 if (return_values && key->value) {
562                         buffer[-1] = '=';
563                         PROFILE_CopyEntry ( buffer,
564                                 key->value, len - 1, handle_env );
565                         len -= strlen(buffer) + 1;
566                         buffer += strlen(buffer) + 1;
567                 }
568             }
569             *buffer = '\0';
570             if (len < 1)
571                 /*If either lpszSection or lpszKey is NULL and the supplied
572                   destination buffer is too small to hold all the strings, 
573                   the last string is truncated and followed by two null characters.
574                   In this case, the return value is equal to cchReturnBuffer
575                   minus two. */
576             {
577                 buffer[-1] = '\0';
578                 return oldlen - 2;
579             }
580             return oldlen - len;
581         }
582         section = section->next;
583     }
584     buffer[0] = buffer[1] = '\0';
585     return 0;
586 }
587
588
589 /***********************************************************************
590  *           PROFILE_GetString
591  *
592  * Get a profile string.
593  */
594 static INT32 PROFILE_GetString( LPCSTR section, LPCSTR key_name,
595                                 LPCSTR def_val, LPSTR buffer, UINT32 len )
596 {
597     PROFILEKEY *key = NULL;
598
599     if (!def_val) def_val = "";
600     if (key_name && key_name[0])
601     {
602         key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
603         PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
604                            len, FALSE );
605         TRACE(profile, "('%s','%s','%s'): returning '%s'\n",
606                          section, key_name, def_val, buffer );
607         return strlen( buffer );
608     }
609     return PROFILE_GetSection(CurProfile->section, section, buffer, len,
610                                 FALSE, FALSE);
611 }
612
613
614 /***********************************************************************
615  *           PROFILE_SetString
616  *
617  * Set a profile string.
618  */
619 static BOOL32 PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
620                                  LPCSTR value )
621 {
622     if (!key_name)  /* Delete a whole section */
623     {
624         TRACE(profile, "('%s')\n", section_name);
625         CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
626                                                       section_name );
627         return TRUE;         /* Even if PROFILE_DeleteSection() has failed,
628                                 this is not an error on application's level.*/
629     }
630     else if (!value)  /* Delete a key */
631     {
632         TRACE(profile, "('%s','%s')\n",
633                          section_name, key_name );
634         CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
635                                                   section_name, key_name );
636         return TRUE;          /* same error handling as above */
637     }
638     else  /* Set the key value */
639     {
640         PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
641                                         key_name, TRUE );
642         TRACE(profile, "('%s','%s','%s'): \n",
643                          section_name, key_name, value );
644         if (!key) return FALSE;
645         if (key->value)
646         {
647             if (!strcmp( key->value, value ))
648             {
649                 TRACE(profile, "  no change needed\n" );
650                 return TRUE;  /* No change needed */
651             }
652             TRACE(profile, "  replacing '%s'\n", key->value );
653             HeapFree( SystemHeap, 0, key->value );
654         }
655         else TRACE(profile, "  creating key\n" );
656         key->value = HEAP_strdupA( SystemHeap, 0, value );
657         CurProfile->changed = TRUE;
658     }
659     return TRUE;
660 }
661
662
663 /***********************************************************************
664  *           PROFILE_GetWineIniString
665  *
666  * Get a config string from the wine.ini file.
667  */
668 int PROFILE_GetWineIniString( const char *section, const char *key_name,
669                               const char *def, char *buffer, int len )
670 {
671     if (key_name)
672     {
673         PROFILEKEY *key = PROFILE_Find(&WineProfile, section, key_name, FALSE);
674         PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
675                            len, TRUE );
676         TRACE(profile, "('%s','%s','%s'): returning '%s'\n",
677                          section, key_name, def, buffer );
678         return strlen( buffer );
679     }
680     return PROFILE_GetSection( WineProfile, section, buffer, len, TRUE, FALSE );
681 }
682
683
684 /***********************************************************************
685  *           PROFILE_GetWineIniInt
686  *
687  * Get a config integer from the wine.ini file.
688  */
689 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
690 {
691     char buffer[20];
692     char *p;
693     long result;
694
695     PROFILEKEY *key = PROFILE_Find( &WineProfile, section, key_name, FALSE );
696     if (!key || !key->value) return def;
697     PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
698     result = strtol( buffer, &p, 0 );
699     if (p == buffer) return 0;  /* No digits at all */
700     return (int)result;
701 }
702
703
704 /******************************************************************************
705  *
706  *   int  PROFILE_EnumerateWineIniSection(
707  *     char const  *section,  // Name of the section to enumerate
708  *     void  (*cbfn)(char const *key, char const *value, void *user),
709                               // Address of the callback function
710  *     void  *user )          // User-specified pointer.
711  *
712  *   For each entry in a section in the wine.conf file, this function will
713  *   call the specified callback function, informing it of each key and
714  *   value.  An optional user pointer may be passed to it (if this is not
715  *   needed, pass NULL through it and ignore the value in the callback
716  *   function).
717  *
718  *   The callback function must accept three parameters:
719  *      The name of the key (char const *)
720  *      The value of the key (char const *)
721  *      A user-specified parameter (void *)
722  *   Note that the first two are char CONST *'s, not char *'s!  The callback
723  *   MUST not modify these strings!
724  *
725  *   The return value indicates the number of times the callback function
726  *   was called.
727  */
728 int  PROFILE_EnumerateWineIniSection(
729     char const  *section,
730     void  (*cbfn)(char const *, char const *, void *),
731     void  *userptr )
732 {
733     PROFILESECTION  *scansect;
734     PROFILEKEY  *scankey;
735     int  calls = 0;
736
737     /* Search for the correct section */
738     for(scansect = WineProfile; scansect; scansect = scansect->next) {
739         if(scansect->name && !strcasecmp(scansect->name, section)) {
740
741             /* Enumerate each key with the callback */
742             for(scankey = scansect->key; scankey; scankey = scankey->next) {
743
744                 /* Ignore blank entries -- these shouldn't exist, but let's
745                    be extra careful */
746                 if(scankey->name[0]) {
747                     cbfn(scankey->name, scankey->value, userptr);
748                     ++calls;
749                 }
750             }
751         
752             break;
753         }
754     }
755
756     return calls;
757 }
758
759
760 /******************************************************************************
761  *
762  *   int  PROFILE_GetWineIniBool(
763  *      char const  *section,
764  *      char const  *key_name,
765  *      int  def )
766  *
767  *   Reads a boolean value from the wine.ini file.  This function attempts to
768  *   be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
769  *   (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
770  *   true.  Anything else results in the return of the default value.
771  *
772  *   This function uses 1 to indicate true, and 0 for false.  You can check
773  *   for existence by setting def to something other than 0 or 1 and
774  *   examining the return value.
775  */
776 int  PROFILE_GetWineIniBool(
777     char const  *section,
778     char const  *key_name,
779     int  def )
780 {
781     char  key_value[2];
782     int  retval;
783
784     PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
785
786     switch(key_value[0]) {
787     case 'n':
788     case 'N':
789     case 'f':
790     case 'F':
791     case '0':
792         retval = 0;
793         break;
794
795     case 'y':
796     case 'Y':
797     case 't':
798     case 'T':
799     case '1':
800         retval = 1;
801         break;
802
803     default:
804         retval = def;
805     }
806
807     TRACE(profile, "(\"%s\", \"%s\", %s), "
808                     "[%c], ret %s.\n", section, key_name,
809                     def ? "TRUE" : "FALSE", key_value[0],
810                     retval ? "TRUE" : "FALSE");
811
812     return retval;
813 }
814
815
816 /***********************************************************************
817  *           PROFILE_LoadWineIni
818  *
819  * Load the wine.ini file.
820  */
821 int PROFILE_LoadWineIni(void)
822 {
823     char buffer[MAX_PATHNAME_LEN];
824     const char *p;
825     FILE *f;
826
827     if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
828       {
829         WineProfile = PROFILE_Load( f );
830         fclose( f );
831         return 1;
832       }
833     if ((p = getenv( "HOME" )) != NULL)
834     {
835         lstrcpyn32A(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
836         strcat( buffer, PROFILE_WineIniName );
837         if ((f = fopen( buffer, "r" )) != NULL)
838         {
839             WineProfile = PROFILE_Load( f );
840             fclose( f );
841             return 1;
842         }
843     }
844     else WARN(profile, "could not get $HOME value for config file.\n" );
845
846     /* Try global file */
847
848     if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
849     {
850         WineProfile = PROFILE_Load( f );
851         fclose( f );
852         return 1;
853     }
854     MSG( "Can't open configuration file %s or $HOME%s\n",
855          WINE_INI_GLOBAL, PROFILE_WineIniName );
856     return 0;
857 }
858
859
860 /***********************************************************************
861  *           PROFILE_GetStringItem
862  *
863  *  Convenience function that turns a string 'xxx, yyy, zzz' into 
864  *  the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
865  */
866 char* PROFILE_GetStringItem( char* start )
867 {
868     char* lpchX, *lpch;
869
870     for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
871     {
872         if( *lpchX == ',' )
873         {
874             if( lpch ) *lpch = '\0'; else *lpchX = '\0';
875             while( *(++lpchX) )
876                 if( !PROFILE_isspace(*lpchX) ) return lpchX;
877         }
878         else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
879              else lpch = NULL;
880     }
881     if( lpch ) *lpch = '\0';
882     return NULL;
883 }
884
885
886 /********************* API functions **********************************/
887
888 /***********************************************************************
889  *           GetProfileInt16   (KERNEL.57)
890  */
891 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
892 {
893     return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
894 }
895
896
897 /***********************************************************************
898  *           GetProfileInt32A   (KERNEL32.264)
899  */
900 UINT32 WINAPI GetProfileInt32A( LPCSTR section, LPCSTR entry, INT32 def_val )
901 {
902     return GetPrivateProfileInt32A( section, entry, def_val, "win.ini" );
903 }
904
905 /***********************************************************************
906  *           GetProfileInt32W   (KERNEL32.264)
907  */
908 UINT32 WINAPI GetProfileInt32W( LPCWSTR section, LPCWSTR entry, INT32 def_val )
909 {
910     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
911     return GetPrivateProfileInt32W( section, entry, def_val, wininiW );
912 }
913
914 /***********************************************************************
915  *           GetProfileString16   (KERNEL.58)
916  */
917 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
918                                  LPSTR buffer, UINT16 len )
919 {
920     return GetPrivateProfileString16( section, entry, def_val,
921                                       buffer, len, "win.ini" );
922 }
923
924 /***********************************************************************
925  *           GetProfileString32A   (KERNEL32.268)
926  */
927 INT32 WINAPI GetProfileString32A( LPCSTR section, LPCSTR entry, LPCSTR def_val,
928                                   LPSTR buffer, UINT32 len )
929 {
930     return GetPrivateProfileString32A( section, entry, def_val,
931                                        buffer, len, "win.ini" );
932 }
933
934 /***********************************************************************
935  *           GetProfileString32W   (KERNEL32.269)
936  */
937 INT32 WINAPI GetProfileString32W( LPCWSTR section, LPCWSTR entry,
938                                   LPCWSTR def_val, LPWSTR buffer, UINT32 len )
939 {
940     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
941     return GetPrivateProfileString32W( section, entry, def_val,
942                                        buffer, len, wininiW );
943 }
944
945 /***********************************************************************
946  *           GetProfileSection32A   (KERNEL32.268)
947  */
948 INT32 WINAPI GetProfileSection32A( LPCSTR section, LPSTR buffer, UINT32 len )
949 {
950     return GetPrivateProfileSection32A( section, buffer, len, "win.ini" );
951 }
952
953
954 /***********************************************************************
955  *           WriteProfileString16   (KERNEL.59)
956  */
957 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
958                                     LPCSTR string )
959 {
960     return WritePrivateProfileString16( section, entry, string, "win.ini" );
961 }
962
963 /***********************************************************************
964  *           WriteProfileString32A   (KERNEL32.587)
965  */
966 BOOL32 WINAPI WriteProfileString32A( LPCSTR section, LPCSTR entry,
967                                      LPCSTR string )
968 {
969     return WritePrivateProfileString32A( section, entry, string, "win.ini" );
970 }
971
972 /***********************************************************************
973  *           WriteProfileString32W   (KERNEL32.588)
974  */
975 BOOL32 WINAPI WriteProfileString32W( LPCWSTR section, LPCWSTR entry,
976                                      LPCWSTR string )
977 {
978     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
979     return WritePrivateProfileString32W( section, entry, string, wininiW );
980 }
981
982
983 /***********************************************************************
984  *           GetPrivateProfileInt16   (KERNEL.127)
985  */
986 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
987                                       INT16 def_val, LPCSTR filename )
988 {
989     long result=(long)GetPrivateProfileInt32A(section,entry,def_val,filename);
990
991     if (result > 65535) return 65535;
992     if (result >= 0) return (UINT16)result;
993     if (result < -32768) return -32768;
994     return (UINT16)(INT16)result;
995 }
996
997 /***********************************************************************
998  *           GetPrivateProfileInt32A   (KERNEL32.251)
999  */
1000 UINT32 WINAPI GetPrivateProfileInt32A( LPCSTR section, LPCSTR entry,
1001                                        INT32 def_val, LPCSTR filename )
1002 {
1003     char buffer[20];
1004     char *p;
1005     long result;
1006
1007     GetPrivateProfileString32A( section, entry, "",
1008                                 buffer, sizeof(buffer), filename );
1009     if (!buffer[0]) return (UINT32)def_val;
1010     result = strtol( buffer, &p, 0 );
1011     if (p == buffer) return 0;  /* No digits at all */
1012     return (UINT32)result;
1013 }
1014
1015 /***********************************************************************
1016  *           GetPrivateProfileInt32W   (KERNEL32.252)
1017  */
1018 UINT32 WINAPI GetPrivateProfileInt32W( LPCWSTR section, LPCWSTR entry,
1019                                        INT32 def_val, LPCWSTR filename )
1020 {
1021     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1022     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1023     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1024     UINT32 res = GetPrivateProfileInt32A(sectionA, entryA, def_val, filenameA);
1025     HeapFree( GetProcessHeap(), 0, sectionA );
1026     HeapFree( GetProcessHeap(), 0, filenameA );
1027     HeapFree( GetProcessHeap(), 0, entryA );
1028     return res;
1029 }
1030
1031 /***********************************************************************
1032  *           GetPrivateProfileString16   (KERNEL.128)
1033  */
1034 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1035                                         LPCSTR def_val, LPSTR buffer,
1036                                         UINT16 len, LPCSTR filename )
1037 {
1038     return GetPrivateProfileString32A(section,entry,def_val,buffer,len,filename);
1039 }
1040
1041 /***********************************************************************
1042  *           GetPrivateProfileString32A   (KERNEL32.255)
1043  */
1044 INT32 WINAPI GetPrivateProfileString32A( LPCSTR section, LPCSTR entry,
1045                                          LPCSTR def_val, LPSTR buffer,
1046                                          UINT32 len, LPCSTR filename )
1047 {
1048     if (!filename) 
1049         filename = "win.ini";
1050     if (PROFILE_Open( filename ))
1051         return PROFILE_GetString( section, entry, def_val, buffer, len );
1052     lstrcpyn32A( buffer, def_val, len );
1053     return strlen( buffer );
1054 }
1055
1056 /***********************************************************************
1057  *           GetPrivateProfileString32W   (KERNEL32.256)
1058  */
1059 INT32 WINAPI GetPrivateProfileString32W( LPCWSTR section, LPCWSTR entry,
1060                                          LPCWSTR def_val, LPWSTR buffer,
1061                                          UINT32 len, LPCWSTR filename )
1062 {
1063     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1064     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1065     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1066     LPSTR def_valA  = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1067     LPSTR bufferA   = HeapAlloc( GetProcessHeap(), 0, len );
1068     INT32 ret = GetPrivateProfileString32A( sectionA, entryA, def_valA,
1069                                             bufferA, len, filenameA );
1070     lstrcpynAtoW( buffer, bufferA, len );
1071     HeapFree( GetProcessHeap(), 0, sectionA );
1072     HeapFree( GetProcessHeap(), 0, entryA );
1073     HeapFree( GetProcessHeap(), 0, filenameA );
1074     HeapFree( GetProcessHeap(), 0, def_valA );
1075     HeapFree( GetProcessHeap(), 0, bufferA);
1076     return ret;
1077 }
1078
1079 /***********************************************************************
1080  *           GetPrivateProfileSection32A   (KERNEL32.255)
1081  */
1082 INT32 WINAPI GetPrivateProfileSection32A( LPCSTR section, LPSTR buffer,
1083                                           UINT32 len, LPCSTR filename )
1084 {
1085     if (PROFILE_Open( filename ))
1086         return PROFILE_GetSection(CurProfile->section, section, buffer, len,
1087                                 FALSE, TRUE);
1088
1089     return 0;
1090 }
1091
1092 /***********************************************************************
1093  *           WritePrivateProfileString16   (KERNEL.129)
1094  */
1095 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1096                                            LPCSTR string, LPCSTR filename )
1097 {
1098     return WritePrivateProfileString32A(section,entry,string,filename);
1099 }
1100
1101 /***********************************************************************
1102  *           WritePrivateProfileString32A   (KERNEL32.582)
1103  */
1104 BOOL32 WINAPI WritePrivateProfileString32A( LPCSTR section, LPCSTR entry,
1105                                             LPCSTR string, LPCSTR filename )
1106 {
1107     if (!PROFILE_Open( filename )) return FALSE;
1108     if (!section) return PROFILE_FlushFile();
1109     return PROFILE_SetString( section, entry, string );
1110 }
1111
1112 /***********************************************************************
1113  *           WritePrivateProfileString32W   (KERNEL32.583)
1114  */
1115 BOOL32 WINAPI WritePrivateProfileString32W( LPCWSTR section, LPCWSTR entry,
1116                                             LPCWSTR string, LPCWSTR filename )
1117 {
1118     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1119     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1120     LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1121     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1122     BOOL32 res = WritePrivateProfileString32A( sectionA, entryA,
1123                                                stringA, filenameA );
1124     HeapFree( GetProcessHeap(), 0, sectionA );
1125     HeapFree( GetProcessHeap(), 0, entryA );
1126     HeapFree( GetProcessHeap(), 0, stringA );
1127     HeapFree( GetProcessHeap(), 0, filenameA );
1128     return res;
1129 }
1130
1131 /***********************************************************************
1132  *           WritePrivateProfileSection32A   (KERNEL32)
1133  */
1134 BOOL32 WINAPI WritePrivateProfileSection32A( LPCSTR section, 
1135                                             LPCSTR string, LPCSTR filename )
1136 {
1137     char *p =(char*)string;
1138
1139     FIXME(profile, "WritePrivateProfileSection32A empty stup\n");
1140     if (TRACE_ON(profile)) {
1141       TRACE(profile, "(%s) => [%s]\n", filename, section);
1142       while (*(p+1)) {
1143         TRACE(profile, "%s\n", p);
1144         p += strlen(p);
1145         p += 1;
1146       }
1147     }
1148     
1149     return FALSE;
1150 }
1151
1152 /***********************************************************************
1153  *           GetPrivateProfileSectionNames16   (KERNEL.143)
1154  */
1155 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1156                                              LPCSTR filename )
1157 {
1158  char *buf;
1159  int l,cursize;
1160  PROFILESECTION *section;
1161
1162     if (PROFILE_Open( filename )) {
1163         buf=buffer;
1164         cursize=0;
1165         section=CurProfile->section;
1166         for ( ; section; section = section->next) 
1167             if (section->name) {
1168                 l=strlen (section->name);
1169                 cursize+=l+1;
1170                 if (cursize > size+1)
1171                         return size-2;
1172                 strcpy (buf,section->name);
1173                 buf+=l;
1174                 *buf=0;
1175                 buf++;
1176                 }
1177         buf++;
1178         *buf=0;
1179         return (buf-buffer);
1180  }
1181  return FALSE;
1182 }
1183
1184
1185
1186 /***********************************************************************
1187  *           GetPrivateProfileStruct32A (KERNEL32.370)
1188  */
1189 WORD WINAPI GetPrivateProfileStruct32A (LPCSTR section, LPCSTR key, 
1190         LPVOID buf, UINT32 len, LPCSTR filename)
1191 {
1192     PROFILEKEY *k;
1193
1194     if (PROFILE_Open( filename )) {
1195         k=PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1196         if (!k) return FALSE;
1197         lstrcpyn32A( buf, k->value, strlen(k->value));
1198         return TRUE;
1199     }
1200   return FALSE;
1201 }
1202
1203
1204 /***********************************************************************
1205  *           WritePrivateProfileStruct32A (KERNEL32.744)
1206  */
1207 WORD WINAPI WritePrivateProfileStruct32A (LPCSTR section, LPCSTR key, 
1208         LPVOID buf, UINT32 bufsize, LPCSTR filename)
1209 {
1210     if ((!section) && (!key) && (!buf)) {       /* flush the cache */
1211         PROFILE_FlushFile();
1212         return FALSE;
1213         }
1214
1215     if (!PROFILE_Open( filename )) return FALSE;
1216     return PROFILE_SetString( section, key, buf);
1217 }
1218
1219
1220 /***********************************************************************
1221  *           WriteOutProfiles   (KERNEL.315)
1222  */
1223 void WINAPI WriteOutProfiles(void)
1224 {
1225     PROFILE_FlushFile();
1226 }