Release 970616
[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  *           PROFILE_LoadWineIni
609  *
610  * Load the wine.ini file.
611  */
612 int PROFILE_LoadWineIni(void)
613 {
614     char buffer[MAX_PATHNAME_LEN];
615     const char *p;
616     FILE *f;
617
618     if ((p = getenv( "HOME" )) != NULL)
619     {
620         lstrcpyn32A(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
621         strcat( buffer, PROFILE_WineIniName );
622         if ((f = fopen( buffer, "r" )) != NULL)
623         {
624             WineProfile = PROFILE_Load( f );
625             fclose( f );
626             return 1;
627         }
628     }
629     else fprintf( stderr, "Warning: could not get $HOME value for config file.\n" );
630
631     /* Try global file */
632
633     if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
634     {
635         WineProfile = PROFILE_Load( f );
636         fclose( f );
637         return 1;
638     }
639     fprintf( stderr, "Can't open configuration file %s or $HOME%s\n",
640              WINE_INI_GLOBAL, PROFILE_WineIniName );
641     return 0;
642 }
643
644
645 /***********************************************************************
646  *           PROFILE_GetStringItem
647  *
648  *  Convenience function that turns a string 'xxx, yyy, zzz' into 
649  *  the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
650  */
651 char* PROFILE_GetStringItem( char* start )
652 {
653     char* lpchX, *lpch;
654
655     for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
656     {
657         if( isspace( *lpchX ) ) lpch = lpch ? lpch : lpchX;
658         else lpch = NULL;
659
660         if( *lpchX == ',' )
661         {
662             if( lpch ) *lpch = '\0'; else *lpchX = '\0';
663             while( *(++lpchX) )
664                 if( !isspace(*lpchX) ) return lpchX;
665         }
666     }
667     if( lpch ) *lpch = '\0';
668     return NULL;
669 }
670
671
672 /********************* API functions **********************************/
673
674 /***********************************************************************
675  *           GetProfileInt16   (KERNEL.57)
676  */
677 UINT16 GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
678 {
679     return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
680 }
681
682
683 /***********************************************************************
684  *           GetProfileInt32A   (KERNEL32.264)
685  */
686 UINT32 GetProfileInt32A( LPCSTR section, LPCSTR entry, INT32 def_val )
687 {
688     return GetPrivateProfileInt32A( section, entry, def_val, "win.ini" );
689 }
690
691 /***********************************************************************
692  *           GetProfileInt32W   (KERNEL32.264)
693  */
694 UINT32 GetProfileInt32W( LPCWSTR section, LPCWSTR entry, INT32 def_val )
695 {
696     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
697     return GetPrivateProfileInt32W( section, entry, def_val, wininiW );
698 }
699
700 /***********************************************************************
701  *           GetProfileString16   (KERNEL.58)
702  */
703 INT16 GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
704                           LPSTR buffer, INT16 len )
705 {
706     return GetPrivateProfileString16( section, entry, def_val,
707                                       buffer, len, "win.ini" );
708 }
709
710 /***********************************************************************
711  *           GetProfileString32A   (KERNEL32.268)
712  */
713 INT32 GetProfileString32A( LPCSTR section, LPCSTR entry, LPCSTR def_val,
714                            LPSTR buffer, INT32 len )
715 {
716     return GetPrivateProfileString32A( section, entry, def_val,
717                                        buffer, len, "win.ini" );
718 }
719
720 /***********************************************************************
721  *           GetProfileString32W   (KERNEL32.269)
722  */
723 INT32 GetProfileString32W( LPCWSTR section,LPCWSTR entry,LPCWSTR def_val,
724                            LPWSTR buffer, INT32 len )
725 {
726     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
727     return GetPrivateProfileString32W( section, entry, def_val,
728                                        buffer, len, wininiW );
729 }
730
731
732 /***********************************************************************
733  *           WriteProfileString16   (KERNEL.59)
734  */
735 BOOL16 WriteProfileString16( LPCSTR section, LPCSTR entry, LPCSTR string )
736 {
737     return WritePrivateProfileString16( section, entry, string, "win.ini" );
738 }
739
740 /***********************************************************************
741  *           WriteProfileString32A   (KERNEL32.587)
742  */
743 BOOL32 WriteProfileString32A( LPCSTR section, LPCSTR entry, LPCSTR string )
744 {
745     return WritePrivateProfileString32A( section, entry, string, "win.ini" );
746 }
747
748 /***********************************************************************
749  *           WriteProfileString32W   (KERNEL32.588)
750  */
751 BOOL32 WriteProfileString32W( LPCWSTR section, LPCWSTR entry, LPCWSTR string )
752 {
753     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
754     return WritePrivateProfileString32W( section, entry, string, wininiW );
755 }
756
757
758 /***********************************************************************
759  *           GetPrivateProfileInt16   (KERNEL.127)
760  */
761 UINT16 GetPrivateProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val,
762                                LPCSTR filename )
763 {
764     long result=(long)GetPrivateProfileInt32A(section,entry,def_val,filename);
765
766     if (result > 65535) return 65535;
767     if (result >= 0) return (UINT16)result;
768     if (result < -32768) return -32768;
769     return (UINT16)(INT16)result;
770 }
771
772 /***********************************************************************
773  *           GetPrivateProfileInt32A   (KERNEL32.251)
774  */
775 UINT32 GetPrivateProfileInt32A( LPCSTR section, LPCSTR entry, INT32 def_val,
776                                 LPCSTR filename )
777 {
778     char buffer[20];
779     char *p;
780     long result;
781
782     GetPrivateProfileString32A( section, entry, "",
783                                 buffer, sizeof(buffer), filename );
784     if (!buffer[0]) return (UINT32)def_val;
785     result = strtol( buffer, &p, 0 );
786     if (p == buffer) return 0;  /* No digits at all */
787     return (UINT32)result;
788 }
789
790 /***********************************************************************
791  *           GetPrivateProfileInt32W   (KERNEL32.252)
792  */
793 UINT32 GetPrivateProfileInt32W( LPCWSTR section, LPCWSTR entry, INT32 def_val,
794                                 LPCWSTR filename )
795 {
796     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
797     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
798     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
799     UINT32 res = GetPrivateProfileInt32A(sectionA, entryA, def_val, filenameA);
800     HeapFree( GetProcessHeap(), 0, sectionA );
801     HeapFree( GetProcessHeap(), 0, filenameA );
802     HeapFree( GetProcessHeap(), 0, entryA );
803     return res;
804 }
805
806 /***********************************************************************
807  *           GetPrivateProfileString16   (KERNEL.128)
808  */
809 INT16 GetPrivateProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
810                                  LPSTR buffer, INT16 len, LPCSTR filename )
811 {
812     return GetPrivateProfileString32A(section,entry,def_val,buffer,len,filename);
813 }
814
815 /***********************************************************************
816  *           GetPrivateProfileString32A   (KERNEL32.255)
817  */
818 INT32 GetPrivateProfileString32A( LPCSTR section, LPCSTR entry, LPCSTR def_val,
819                                   LPSTR buffer, INT32 len, LPCSTR filename )
820 {
821     if (PROFILE_Open( filename ))
822         return PROFILE_GetString( section, entry, def_val, buffer, len );
823     lstrcpyn32A( buffer, def_val, len );
824     return strlen( buffer );
825 }
826
827 /***********************************************************************
828  *           GetPrivateProfileString32W   (KERNEL32.256)
829  */
830 INT32 GetPrivateProfileString32W( LPCWSTR section, LPCWSTR entry,
831                                   LPCWSTR def_val, LPWSTR buffer,
832                                   INT32 len, LPCWSTR filename )
833 {
834     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
835     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
836     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
837     LPSTR def_valA  = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
838     LPSTR bufferA   = HeapAlloc( GetProcessHeap(), 0, len );
839     INT32 ret = GetPrivateProfileString32A( sectionA, entryA, def_valA,
840                                             bufferA, len, filenameA );
841     lstrcpynAtoW( buffer, bufferA, len );
842     HeapFree( GetProcessHeap(), 0, sectionA );
843     HeapFree( GetProcessHeap(), 0, entryA );
844     HeapFree( GetProcessHeap(), 0, filenameA );
845     HeapFree( GetProcessHeap(), 0, def_valA );
846     HeapFree( GetProcessHeap(), 0, bufferA);
847     return ret;
848 }
849
850
851
852 /***********************************************************************
853  *           WritePrivateProfileString16   (KERNEL.129)
854  */
855 BOOL16 WritePrivateProfileString16(LPCSTR section,LPCSTR entry,LPCSTR string,
856                                    LPCSTR filename)
857 {
858     return WritePrivateProfileString32A(section,entry,string,filename);
859 }
860
861 /***********************************************************************
862  *           WritePrivateProfileString32A   (KERNEL32.582)
863  */
864 BOOL32 WritePrivateProfileString32A(LPCSTR section,LPCSTR entry,LPCSTR string,
865                                     LPCSTR filename )
866 {
867     if (!PROFILE_Open( filename )) return FALSE;
868     if (!section) return PROFILE_FlushFile();
869     return PROFILE_SetString( section, entry, string );
870 }
871
872 /***********************************************************************
873  *           WritePrivateProfileString32W   (KERNEL32.583)
874  */
875 BOOL32 WritePrivateProfileString32W( LPCWSTR section, LPCWSTR entry,
876                                      LPCWSTR string, LPCWSTR filename )
877 {
878     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
879     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
880     LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
881     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
882     BOOL32 res = WritePrivateProfileString32A( sectionA, entryA,
883                                                stringA, filenameA );
884     HeapFree( GetProcessHeap(), 0, sectionA );
885     HeapFree( GetProcessHeap(), 0, entryA );
886     HeapFree( GetProcessHeap(), 0, stringA );
887     HeapFree( GetProcessHeap(), 0, filenameA );
888     return res;
889 }
890
891
892 /***********************************************************************
893  *           WriteOutProfiles   (KERNEL.315)
894  */
895 void WriteOutProfiles(void)
896 {
897     PROFILE_FlushFile();
898 }