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