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