Added PROFILE_GetConfigDir function.
[wine/wine-kai.git] / files / profile.c
blobbf46d4dac3d2dfff2ded200954d15e761d729619
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <pwd.h>
14 #include <unistd.h>
16 #include "winbase.h"
17 #include "winerror.h"
18 #include "wine/winbase16.h"
19 #include "winuser.h"
20 #include "winnls.h"
21 #include "file.h"
22 #include "heap.h"
23 #include "debugtools.h"
24 #include "xmalloc.h"
25 #include "options.h"
27 DEFAULT_DEBUG_CHANNEL(profile)
29 typedef struct tagPROFILEKEY
31 char *name;
32 char *value;
33 struct tagPROFILEKEY *next;
34 } PROFILEKEY;
36 typedef struct tagPROFILESECTION
38 char *name;
39 struct tagPROFILEKEY *key;
40 struct tagPROFILESECTION *next;
41 } PROFILESECTION;
44 typedef struct
46 BOOL changed;
47 PROFILESECTION *section;
48 char *dos_name;
49 char *unix_name;
50 char *filename;
51 time_t mtime;
52 } PROFILE;
55 #define N_CACHED_PROFILES 10
57 /* Cached profile files */
58 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
60 #define CurProfile (MRUProfile[0])
62 /* wine.ini profile content */
63 static PROFILESECTION *PROFILE_WineProfile;
65 #define PROFILE_MAX_LINE_LEN 1024
67 /* Wine profile name in $HOME directory; must begin with slash */
68 static const char PROFILE_WineIniName[] = "/.winerc";
70 /* Wine profile: the profile file being used */
71 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
73 /* Check for comments in profile */
74 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
76 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
77 #define WINE_CONFIG_DIR "/.wine" /* config dir inside $HOME */
79 static LPCWSTR wininiW = NULL;
81 static CRITICAL_SECTION PROFILE_CritSect;
84 /***********************************************************************
85 * PROFILE_GetConfigDir
87 * Return the name of the configuration directory ($HOME/.wine)
89 const char *PROFILE_GetConfigDir(void)
91 static char *confdir;
92 if (!confdir)
94 const char *home = getenv( "HOME" );
95 if (!home)
97 struct passwd *pwd = getpwuid( getuid() );
98 if (!pwd)
100 fprintf( stderr, "wine: could not find your home directory\n" );
101 exit(1);
103 home = pwd->pw_dir;
105 confdir = xmalloc( strlen(home) + strlen(WINE_CONFIG_DIR) + 1 );
106 strcpy( confdir, home );
107 strcat( confdir, WINE_CONFIG_DIR );
108 mkdir( confdir, 0755 ); /* create it just in case */
110 return confdir;
114 /***********************************************************************
115 * PROFILE_CopyEntry
117 * Copy the content of an entry into a buffer, removing quotes, and possibly
118 * translating environment variables.
120 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
121 int handle_env )
123 char quote = '\0';
124 const char *p;
126 if ((*value == '\'') || (*value == '\"'))
128 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
131 if (!handle_env)
133 lstrcpynA( buffer, value, len );
134 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
135 return;
138 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
140 if ((*p == '$') && (p[1] == '{'))
142 char env_val[1024];
143 const char *env_p;
144 const char *p2 = strchr( p, '}' );
145 if (!p2) continue; /* ignore it */
146 lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
147 if ((env_p = getenv( env_val )) != NULL)
149 lstrcpynA( buffer, env_p, len );
150 buffer += strlen( buffer );
151 len -= strlen( buffer );
153 p = p2 + 1;
156 if (quote && (len > 1)) buffer--;
157 *buffer = '\0';
161 /***********************************************************************
162 * PROFILE_Save
164 * Save a profile tree to a file.
166 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
168 PROFILEKEY *key;
170 for ( ; section; section = section->next)
172 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
173 for (key = section->key; key; key = key->next)
175 fprintf( file, "%s", key->name );
176 if (key->value) fprintf( file, "=%s", key->value );
177 fprintf( file, "\r\n" );
183 /***********************************************************************
184 * PROFILE_Free
186 * Free a profile tree.
188 static void PROFILE_Free( PROFILESECTION *section )
190 PROFILESECTION *next_section;
191 PROFILEKEY *key, *next_key;
193 for ( ; section; section = next_section)
195 if (section->name) HeapFree( SystemHeap, 0, section->name );
196 for (key = section->key; key; key = next_key)
198 next_key = key->next;
199 if (key->name) HeapFree( SystemHeap, 0, key->name );
200 if (key->value) HeapFree( SystemHeap, 0, key->value );
201 HeapFree( SystemHeap, 0, key );
203 next_section = section->next;
204 HeapFree( SystemHeap, 0, section );
208 static int
209 PROFILE_isspace(char c) {
210 if (isspace(c)) return 1;
211 if (c=='\r' || c==0x1a) return 1;
212 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
213 return 0;
217 /***********************************************************************
218 * PROFILE_Load
220 * Load a profile tree from a file.
222 static PROFILESECTION *PROFILE_Load( FILE *file )
224 char buffer[PROFILE_MAX_LINE_LEN];
225 char *p, *p2;
226 int line = 0;
227 PROFILESECTION *section, *first_section;
228 PROFILESECTION **next_section;
229 PROFILEKEY *key, *prev_key, **next_key;
231 first_section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
232 first_section->name = NULL;
233 first_section->key = NULL;
234 first_section->next = NULL;
235 next_section = &first_section->next;
236 next_key = &first_section->key;
237 prev_key = NULL;
239 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
241 line++;
242 p = buffer;
243 while (*p && PROFILE_isspace(*p)) p++;
244 if (*p == '[') /* section start */
246 if (!(p2 = strrchr( p, ']' )))
248 WARN("Invalid section header at line %d: '%s'\n",
249 line, p );
251 else
253 *p2 = '\0';
254 p++;
255 section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
256 section->name = HEAP_strdupA( SystemHeap, 0, p );
257 section->key = NULL;
258 section->next = NULL;
259 *next_section = section;
260 next_section = &section->next;
261 next_key = &section->key;
262 prev_key = NULL;
264 TRACE("New section: '%s'\n",section->name);
266 continue;
270 p2=p+strlen(p) - 1;
271 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
273 if ((p2 = strchr( p, '=' )) != NULL)
275 char *p3 = p2 - 1;
276 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
277 *p2++ = '\0';
278 while (*p2 && PROFILE_isspace(*p2)) p2++;
281 if(*p || !prev_key || *prev_key->name)
283 key = HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
284 key->name = HEAP_strdupA( SystemHeap, 0, p );
285 key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
286 key->next = NULL;
287 *next_key = key;
288 next_key = &key->next;
289 prev_key = key;
291 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
294 return first_section;
298 /***********************************************************************
299 * PROFILE_DeleteSection
301 * Delete a section from a profile tree.
303 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
305 while (*section)
307 if ((*section)->name && !strcasecmp( (*section)->name, name ))
309 PROFILESECTION *to_del = *section;
310 *section = to_del->next;
311 to_del->next = NULL;
312 PROFILE_Free( to_del );
313 return TRUE;
315 section = &(*section)->next;
317 return FALSE;
321 /***********************************************************************
322 * PROFILE_DeleteKey
324 * Delete a key from a profile tree.
326 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
327 LPCSTR section_name, LPCSTR key_name )
329 while (*section)
331 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
333 PROFILEKEY **key = &(*section)->key;
334 while (*key)
336 if (!strcasecmp( (*key)->name, key_name ))
338 PROFILEKEY *to_del = *key;
339 *key = to_del->next;
340 if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
341 if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
342 HeapFree( SystemHeap, 0, to_del );
343 return TRUE;
345 key = &(*key)->next;
348 section = &(*section)->next;
350 return FALSE;
354 /***********************************************************************
355 * PROFILE_Find
357 * Find a key in a profile tree, optionally creating it.
359 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
360 const char *section_name,
361 const char *key_name, int create )
363 while (*section)
365 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
367 PROFILEKEY **key = &(*section)->key;
368 while (*key)
370 if (!strcasecmp( (*key)->name, key_name )) return *key;
371 key = &(*key)->next;
373 if (!create) return NULL;
374 *key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
375 (*key)->name = HEAP_strdupA( SystemHeap, 0, key_name );
376 (*key)->value = NULL;
377 (*key)->next = NULL;
378 return *key;
380 section = &(*section)->next;
382 if (!create) return NULL;
383 *section = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
384 (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
385 (*section)->next = NULL;
386 (*section)->key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
387 (*section)->key->name = HEAP_strdupA( SystemHeap, 0, key_name );
388 (*section)->key->value = NULL;
389 (*section)->key->next = NULL;
390 return (*section)->key;
394 /***********************************************************************
395 * PROFILE_FlushFile
397 * Flush the current profile to disk if changed.
399 static BOOL PROFILE_FlushFile(void)
401 char *p, buffer[MAX_PATHNAME_LEN];
402 const char *unix_name;
403 FILE *file = NULL;
404 struct stat buf;
406 if(!CurProfile)
408 WARN("No current profile!\n");
409 return FALSE;
412 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
413 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
415 /* Try to create it in $HOME/.wine */
416 /* FIXME: this will need a more general solution */
417 strcpy( buffer, PROFILE_GetConfigDir() );
418 p = buffer + strlen(buffer);
419 *p++ = '/';
420 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
421 CharLowerA( p );
422 file = fopen( buffer, "w" );
423 unix_name = buffer;
426 if (!file)
428 WARN("could not save profile file %s\n", CurProfile->dos_name);
429 return FALSE;
432 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
433 PROFILE_Save( file, CurProfile->section );
434 fclose( file );
435 CurProfile->changed = FALSE;
436 if(!stat(unix_name,&buf))
437 CurProfile->mtime=buf.st_mtime;
438 return TRUE;
442 /***********************************************************************
443 * PROFILE_ReleaseFile
445 * Flush the current profile to disk and remove it from the cache.
447 static void PROFILE_ReleaseFile(void)
449 PROFILE_FlushFile();
450 PROFILE_Free( CurProfile->section );
451 if (CurProfile->dos_name) HeapFree( SystemHeap, 0, CurProfile->dos_name );
452 if (CurProfile->unix_name) HeapFree( SystemHeap, 0, CurProfile->unix_name );
453 if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
454 CurProfile->changed = FALSE;
455 CurProfile->section = NULL;
456 CurProfile->dos_name = NULL;
457 CurProfile->unix_name = NULL;
458 CurProfile->filename = NULL;
459 CurProfile->mtime = 0;
463 /***********************************************************************
464 * PROFILE_Open
466 * Open a profile file, checking the cached file first.
468 static BOOL PROFILE_Open( LPCSTR filename )
470 DOS_FULL_NAME full_name;
471 char buffer[MAX_PATHNAME_LEN];
472 char *newdos_name, *p;
473 FILE *file = NULL;
474 int i,j;
475 struct stat buf;
476 PROFILE *tempProfile;
478 /* First time around */
480 if(!CurProfile)
481 for(i=0;i<N_CACHED_PROFILES;i++)
483 MRUProfile[i]=HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
484 MRUProfile[i]->changed=FALSE;
485 MRUProfile[i]->section=NULL;
486 MRUProfile[i]->dos_name=NULL;
487 MRUProfile[i]->unix_name=NULL;
488 MRUProfile[i]->filename=NULL;
489 MRUProfile[i]->mtime=0;
492 /* Check for a match */
494 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
495 strchr( filename, ':' ))
497 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
499 else
501 GetWindowsDirectoryA( buffer, sizeof(buffer) );
502 strcat( buffer, "\\" );
503 strcat( buffer, filename );
504 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
507 for(i=0;i<N_CACHED_PROFILES;i++)
509 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
510 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
512 if(i)
514 PROFILE_FlushFile();
515 tempProfile=MRUProfile[i];
516 for(j=i;j>0;j--)
517 MRUProfile[j]=MRUProfile[j-1];
518 CurProfile=tempProfile;
520 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
521 TRACE("(%s): already opened (mru=%d)\n",
522 filename, i );
523 else
524 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
525 filename, i );
526 return TRUE;
530 /* Flush the old current profile */
531 PROFILE_FlushFile();
533 /* Make the oldest profile the current one only in order to get rid of it */
534 if(i==N_CACHED_PROFILES)
536 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
537 for(i=N_CACHED_PROFILES-1;i>0;i--)
538 MRUProfile[i]=MRUProfile[i-1];
539 CurProfile=tempProfile;
541 if(CurProfile->filename) PROFILE_ReleaseFile();
543 /* OK, now that CurProfile is definitely free we assign it our new file */
544 newdos_name = HEAP_strdupA( SystemHeap, 0, full_name.short_name );
545 CurProfile->dos_name = newdos_name;
546 CurProfile->filename = HEAP_strdupA( SystemHeap, 0, filename );
548 /* Try to open the profile file, first in $HOME/.wine */
550 /* FIXME: this will need a more general solution */
551 strcpy( buffer, PROFILE_GetConfigDir() );
552 p = buffer + strlen(buffer);
553 *p++ = '/';
554 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
555 CharLowerA( p );
556 if ((file = fopen( buffer, "r" )))
558 TRACE("(%s): found it in %s\n",
559 filename, buffer );
560 CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0, buffer );
563 if (!file)
565 CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0,
566 full_name.long_name );
567 if ((file = fopen( full_name.long_name, "r" )))
568 TRACE("(%s): found it in %s\n",
569 filename, full_name.long_name );
572 if (file)
574 CurProfile->section = PROFILE_Load( file );
575 fclose( file );
576 if(!stat(CurProfile->unix_name,&buf))
577 CurProfile->mtime=buf.st_mtime;
579 else
581 /* Does not exist yet, we will create it in PROFILE_FlushFile */
582 WARN("profile file %s not found\n", newdos_name );
584 return TRUE;
588 /***********************************************************************
589 * PROFILE_GetSection
591 * Returns all keys of a section.
592 * If return_values is TRUE, also include the corresponding values.
594 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
595 LPSTR buffer, UINT len, BOOL handle_env,
596 BOOL return_values )
598 PROFILEKEY *key;
599 while (section)
601 if (section->name && !strcasecmp( section->name, section_name ))
603 UINT oldlen = len;
604 for (key = section->key; key; key = key->next)
606 if (len <= 2) break;
607 if (!*key->name) continue; /* Skip empty lines */
608 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
609 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
610 len -= strlen(buffer) + 1;
611 buffer += strlen(buffer) + 1;
612 if (return_values && key->value) {
613 buffer[-1] = '=';
614 PROFILE_CopyEntry ( buffer,
615 key->value, len - 1, handle_env );
616 len -= strlen(buffer) + 1;
617 buffer += strlen(buffer) + 1;
620 *buffer = '\0';
621 if (len <= 1)
622 /*If either lpszSection or lpszKey is NULL and the supplied
623 destination buffer is too small to hold all the strings,
624 the last string is truncated and followed by two null characters.
625 In this case, the return value is equal to cchReturnBuffer
626 minus two. */
628 buffer[-1] = '\0';
629 return oldlen - 2;
631 return oldlen - len;
633 section = section->next;
635 buffer[0] = buffer[1] = '\0';
636 return 0;
640 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
642 LPSTR buf = buffer;
643 WORD l, cursize = 0;
644 PROFILESECTION *section;
646 for (section = CurProfile->section; section; section = section->next)
647 if (section->name) {
648 l = strlen(section->name);
649 cursize += l+1;
650 if (cursize > len+1)
651 return len-2;
653 strcpy(buf, section->name);
654 buf += l+1;
657 *buf=0;
658 buf++;
659 return buf-buffer;
663 /***********************************************************************
664 * PROFILE_GetString
666 * Get a profile string.
668 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
669 LPCSTR def_val, LPSTR buffer, UINT len )
671 PROFILEKEY *key = NULL;
673 if (!def_val) def_val = "";
674 if (key_name && key_name[0])
676 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
677 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
678 len, FALSE );
679 TRACE("('%s','%s','%s'): returning '%s'\n",
680 section, key_name, def_val, buffer );
681 return strlen( buffer );
683 if (section && section[0])
684 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
685 FALSE, FALSE);
686 /* undocumented; both section and key_name are NULL */
687 return PROFILE_GetSectionNames(buffer, len);
691 /***********************************************************************
692 * PROFILE_SetString
694 * Set a profile string.
696 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
697 LPCSTR value )
699 if (!key_name) /* Delete a whole section */
701 TRACE("('%s')\n", section_name);
702 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
703 section_name );
704 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
705 this is not an error on application's level.*/
707 else if (!value) /* Delete a key */
709 TRACE("('%s','%s')\n",
710 section_name, key_name );
711 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
712 section_name, key_name );
713 return TRUE; /* same error handling as above */
715 else /* Set the key value */
717 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
718 key_name, TRUE );
719 TRACE("('%s','%s','%s'): \n",
720 section_name, key_name, value );
721 if (!key) return FALSE;
722 if (key->value)
724 if (!strcmp( key->value, value ))
726 TRACE(" no change needed\n" );
727 return TRUE; /* No change needed */
729 TRACE(" replacing '%s'\n", key->value );
730 HeapFree( SystemHeap, 0, key->value );
732 else TRACE(" creating key\n" );
733 key->value = HEAP_strdupA( SystemHeap, 0, value );
734 CurProfile->changed = TRUE;
736 return TRUE;
740 /***********************************************************************
741 * PROFILE_GetWineIniString
743 * Get a config string from the wine.ini file.
745 int PROFILE_GetWineIniString( const char *section, const char *key_name,
746 const char *def, char *buffer, int len )
748 int ret;
750 EnterCriticalSection( &PROFILE_CritSect );
752 if (key_name)
754 PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
755 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
756 len, TRUE );
757 TRACE("('%s','%s','%s'): returning '%s'\n",
758 section, key_name, def, buffer );
759 ret = strlen( buffer );
761 else
763 ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
765 LeaveCriticalSection( &PROFILE_CritSect );
767 return ret;
771 /***********************************************************************
772 * PROFILE_GetWineIniInt
774 * Get a config integer from the wine.ini file.
776 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
778 char buffer[20];
779 char *p;
780 long result;
781 PROFILEKEY *key;
782 int ret;
784 EnterCriticalSection( &PROFILE_CritSect );
786 key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
787 if (!key || !key->value) {
788 ret = def;
789 } else {
790 PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
791 result = strtol( buffer, &p, 0 );
792 ret = (p == buffer) ? 0 /* No digits at all */ : (int)result;
795 LeaveCriticalSection( &PROFILE_CritSect );
797 return ret;
801 /******************************************************************************
803 * int PROFILE_EnumerateWineIniSection(
804 * char const *section, #Name of the section to enumerate
805 * void (*cbfn)(char const *key, char const *value, void *user),
806 * # Address of the callback function
807 * void *user ) # User-specified pointer.
809 * For each entry in a section in the wine.conf file, this function will
810 * call the specified callback function, informing it of each key and
811 * value. An optional user pointer may be passed to it (if this is not
812 * needed, pass NULL through it and ignore the value in the callback
813 * function).
815 * The callback function must accept three parameters:
816 * The name of the key (char const *)
817 * The value of the key (char const *)
818 * A user-specified parameter (void *)
819 * Note that the first two are char CONST *'s, not char *'s! The callback
820 * MUST not modify these strings!
822 * The return value indicates the number of times the callback function
823 * was called.
825 int PROFILE_EnumerateWineIniSection(
826 char const *section,
827 void (*cbfn)(char const *, char const *, void *),
828 void *userptr )
830 PROFILESECTION *scansect;
831 PROFILEKEY *scankey;
832 int calls = 0;
834 EnterCriticalSection( &PROFILE_CritSect );
836 /* Search for the correct section */
837 for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
838 if(scansect->name && !strcasecmp(scansect->name, section)) {
840 /* Enumerate each key with the callback */
841 for(scankey = scansect->key; scankey; scankey = scankey->next) {
843 /* Ignore blank entries -- these shouldn't exist, but let's
844 be extra careful */
845 if (!scankey->name[0]) continue;
846 if (!scankey->value) cbfn(scankey->name, NULL, userptr);
847 else
849 char value[1024];
850 PROFILE_CopyEntry(value, scankey->value, sizeof(value), TRUE);
851 cbfn(scankey->name, value, userptr);
853 ++calls;
856 break;
859 LeaveCriticalSection( &PROFILE_CritSect );
861 return calls;
865 /******************************************************************************
867 * int PROFILE_GetWineIniBool(
868 * char const *section,
869 * char const *key_name,
870 * int def )
872 * Reads a boolean value from the wine.ini file. This function attempts to
873 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
874 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
875 * true. Anything else results in the return of the default value.
877 * This function uses 1 to indicate true, and 0 for false. You can check
878 * for existence by setting def to something other than 0 or 1 and
879 * examining the return value.
881 int PROFILE_GetWineIniBool(
882 char const *section,
883 char const *key_name,
884 int def )
886 char key_value[2];
887 int retval;
889 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
891 switch(key_value[0]) {
892 case 'n':
893 case 'N':
894 case 'f':
895 case 'F':
896 case '0':
897 retval = 0;
898 break;
900 case 'y':
901 case 'Y':
902 case 't':
903 case 'T':
904 case '1':
905 retval = 1;
906 break;
908 default:
909 retval = def;
912 TRACE("(\"%s\", \"%s\", %s), "
913 "[%c], ret %s.\n", section, key_name,
914 def ? "TRUE" : "FALSE", key_value[0],
915 retval ? "TRUE" : "FALSE");
917 return retval;
921 /***********************************************************************
922 * PROFILE_LoadWineIni
924 * Load the wine.ini file.
926 int PROFILE_LoadWineIni(void)
928 char buffer[MAX_PATHNAME_LEN];
929 const char *p;
930 FILE *f;
932 InitializeCriticalSection( &PROFILE_CritSect );
933 MakeCriticalSectionGlobal( &PROFILE_CritSect );
935 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
937 /* Open -config specified file */
938 PROFILE_WineProfile = PROFILE_Load ( f);
939 fclose ( f );
940 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
941 return 1;
944 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
946 PROFILE_WineProfile = PROFILE_Load( f );
947 fclose( f );
948 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
949 return 1;
951 if ((p = getenv( "HOME" )) != NULL)
953 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
954 strcat( buffer, PROFILE_WineIniName );
955 if ((f = fopen( buffer, "r" )) != NULL)
957 PROFILE_WineProfile = PROFILE_Load( f );
958 fclose( f );
959 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
960 return 1;
963 else WARN("could not get $HOME value for config file.\n" );
965 /* Try global file */
967 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
969 PROFILE_WineProfile = PROFILE_Load( f );
970 fclose( f );
971 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
972 return 1;
974 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
975 WINE_INI_GLOBAL, PROFILE_WineIniName );
976 return 0;
980 /***********************************************************************
981 * PROFILE_UsageWineIni
983 * Explain the wine.ini file to those who don't read documentation.
984 * Keep below one screenful in length so that error messages above are
985 * noticed.
987 void PROFILE_UsageWineIni(void)
989 MESSAGE("Perhaps you have not properly edited or created "
990 "your Wine configuration file.\n");
991 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
992 MESSAGE(" or it is determined by the -config option or from\n"
993 " the WINE_INI environment variable.\n");
994 if (*PROFILE_WineIniUsed)
995 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
996 /* RTFM, so to say */
999 /***********************************************************************
1000 * PROFILE_GetStringItem
1002 * Convenience function that turns a string 'xxx, yyy, zzz' into
1003 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1005 char* PROFILE_GetStringItem( char* start )
1007 char* lpchX, *lpch;
1009 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1011 if( *lpchX == ',' )
1013 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1014 while( *(++lpchX) )
1015 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1017 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1018 else lpch = NULL;
1020 if( lpch ) *lpch = '\0';
1021 return NULL;
1024 /********************* API functions **********************************/
1026 /***********************************************************************
1027 * GetProfileInt16 (KERNEL.57)
1029 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1031 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1035 /***********************************************************************
1036 * GetProfileInt32A (KERNEL32.264)
1038 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1040 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1043 /***********************************************************************
1044 * GetProfileInt32W (KERNEL32.264)
1046 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1048 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1049 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1052 /***********************************************************************
1053 * GetProfileString16 (KERNEL.58)
1055 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1056 LPSTR buffer, UINT16 len )
1058 return GetPrivateProfileString16( section, entry, def_val,
1059 buffer, len, "win.ini" );
1062 /***********************************************************************
1063 * GetProfileString32A (KERNEL32.268)
1065 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1066 LPSTR buffer, UINT len )
1068 return GetPrivateProfileStringA( section, entry, def_val,
1069 buffer, len, "win.ini" );
1072 /***********************************************************************
1073 * GetProfileString32W (KERNEL32.269)
1075 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1076 LPCWSTR def_val, LPWSTR buffer, UINT len )
1078 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1079 return GetPrivateProfileStringW( section, entry, def_val,
1080 buffer, len, wininiW );
1083 /***********************************************************************
1084 * WriteProfileString16 (KERNEL.59)
1086 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1087 LPCSTR string )
1089 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1092 /***********************************************************************
1093 * WriteProfileString32A (KERNEL32.587)
1095 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1096 LPCSTR string )
1098 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1101 /***********************************************************************
1102 * WriteProfileString32W (KERNEL32.588)
1104 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1105 LPCWSTR string )
1107 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1108 return WritePrivateProfileStringW( section, entry, string, wininiW );
1112 /***********************************************************************
1113 * GetPrivateProfileInt16 (KERNEL.127)
1115 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1116 INT16 def_val, LPCSTR filename )
1118 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1120 if (result > 65535) return 65535;
1121 if (result >= 0) return (UINT16)result;
1122 if (result < -32768) return -32768;
1123 return (UINT16)(INT16)result;
1126 /***********************************************************************
1127 * GetPrivateProfileInt32A (KERNEL32.251)
1129 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1130 INT def_val, LPCSTR filename )
1132 char buffer[20];
1133 char *p;
1134 long result;
1136 GetPrivateProfileStringA( section, entry, "",
1137 buffer, sizeof(buffer), filename );
1138 if (!buffer[0]) return (UINT)def_val;
1139 result = strtol( buffer, &p, 0 );
1140 if (p == buffer) return 0; /* No digits at all */
1141 return (UINT)result;
1144 /***********************************************************************
1145 * GetPrivateProfileInt32W (KERNEL32.252)
1147 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1148 INT def_val, LPCWSTR filename )
1150 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1151 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1152 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1153 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1154 HeapFree( GetProcessHeap(), 0, sectionA );
1155 HeapFree( GetProcessHeap(), 0, filenameA );
1156 HeapFree( GetProcessHeap(), 0, entryA );
1157 return res;
1160 /***********************************************************************
1161 * GetPrivateProfileString16 (KERNEL.128)
1163 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1164 LPCSTR def_val, LPSTR buffer,
1165 UINT16 len, LPCSTR filename )
1167 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1170 /***********************************************************************
1171 * GetPrivateProfileString32A (KERNEL32.255)
1173 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1174 LPCSTR def_val, LPSTR buffer,
1175 UINT len, LPCSTR filename )
1177 int ret;
1179 if (!filename)
1180 filename = "win.ini";
1182 EnterCriticalSection( &PROFILE_CritSect );
1184 if (PROFILE_Open( filename )) {
1185 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1186 } else {
1187 lstrcpynA( buffer, def_val, len );
1188 ret = strlen( buffer );
1191 LeaveCriticalSection( &PROFILE_CritSect );
1193 return ret;
1196 /***********************************************************************
1197 * GetPrivateProfileString32W (KERNEL32.256)
1199 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1200 LPCWSTR def_val, LPWSTR buffer,
1201 UINT len, LPCWSTR filename )
1203 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1204 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1205 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1206 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1207 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1208 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1209 bufferA, len, filenameA );
1210 lstrcpynAtoW( buffer, bufferA, len );
1211 HeapFree( GetProcessHeap(), 0, sectionA );
1212 HeapFree( GetProcessHeap(), 0, entryA );
1213 HeapFree( GetProcessHeap(), 0, filenameA );
1214 HeapFree( GetProcessHeap(), 0, def_valA );
1215 HeapFree( GetProcessHeap(), 0, bufferA);
1216 return ret;
1219 /***********************************************************************
1220 * GetPrivateProfileSection16 (KERNEL.418)
1222 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1223 UINT16 len, LPCSTR filename )
1225 return GetPrivateProfileSectionA( section, buffer, len, filename );
1228 /***********************************************************************
1229 * GetPrivateProfileSection32A (KERNEL32.255)
1231 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1232 DWORD len, LPCSTR filename )
1234 int ret = 0;
1236 EnterCriticalSection( &PROFILE_CritSect );
1238 if (PROFILE_Open( filename ))
1239 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1240 FALSE, TRUE);
1242 LeaveCriticalSection( &PROFILE_CritSect );
1244 return ret;
1247 /***********************************************************************
1248 * GetPrivateProfileSection32W (KERNEL32.256)
1251 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1252 DWORD len, LPCWSTR filename )
1255 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1256 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1257 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1258 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1259 filenameA );
1260 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1261 HeapFree( GetProcessHeap(), 0, sectionA );
1262 HeapFree( GetProcessHeap(), 0, filenameA );
1263 HeapFree( GetProcessHeap(), 0, bufferA);
1264 return ret;
1267 /***********************************************************************
1268 * GetProfileSection16 (KERNEL.419)
1270 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1272 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1275 /***********************************************************************
1276 * GetProfileSection32A (KERNEL32.268)
1278 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1280 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1283 /***********************************************************************
1284 * GetProfileSection32W (KERNEL32)
1286 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1288 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1289 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1293 /***********************************************************************
1294 * WritePrivateProfileString16 (KERNEL.129)
1296 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1297 LPCSTR string, LPCSTR filename )
1299 return WritePrivateProfileStringA(section,entry,string,filename);
1302 /***********************************************************************
1303 * WritePrivateProfileString32A (KERNEL32.582)
1305 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1306 LPCSTR string, LPCSTR filename )
1308 BOOL ret = FALSE;
1310 EnterCriticalSection( &PROFILE_CritSect );
1312 if (PROFILE_Open( filename ))
1314 if (!section && !entry && !string)
1315 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1316 else
1317 ret = PROFILE_SetString( section, entry, string );
1320 LeaveCriticalSection( &PROFILE_CritSect );
1321 return ret;
1324 /***********************************************************************
1325 * WritePrivateProfileString32W (KERNEL32.583)
1327 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1328 LPCWSTR string, LPCWSTR filename )
1330 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1331 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1332 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1333 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1334 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1335 stringA, filenameA );
1336 HeapFree( GetProcessHeap(), 0, sectionA );
1337 HeapFree( GetProcessHeap(), 0, entryA );
1338 HeapFree( GetProcessHeap(), 0, stringA );
1339 HeapFree( GetProcessHeap(), 0, filenameA );
1340 return res;
1343 /***********************************************************************
1344 * WritePrivateProfileSection16 (KERNEL.416)
1346 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1347 LPCSTR string, LPCSTR filename )
1349 return WritePrivateProfileSectionA( section, string, filename );
1352 /***********************************************************************
1353 * WritePrivateProfileSectionA (KERNEL32)
1355 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1356 LPCSTR string, LPCSTR filename )
1358 BOOL ret = FALSE;
1359 LPSTR p ;
1361 EnterCriticalSection( &PROFILE_CritSect );
1363 if (PROFILE_Open( filename )) {
1364 if (!section && !string && !filename)
1365 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1366 else {
1367 while(*string){
1368 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1369 if((p=strchr( buf, '='))){
1370 *p='\0';
1371 ret = PROFILE_SetString( section, buf, p+1 );
1374 HeapFree( GetProcessHeap(), 0, buf );
1375 string += strlen(string)+1;
1381 LeaveCriticalSection( &PROFILE_CritSect );
1382 return ret;
1385 /***********************************************************************
1386 * WritePrivateProfileSection32W (KERNEL32)
1388 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1389 LPCWSTR string, LPCWSTR filename)
1392 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1393 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1394 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1395 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1396 HeapFree( GetProcessHeap(), 0, sectionA );
1397 HeapFree( GetProcessHeap(), 0, stringA );
1398 HeapFree( GetProcessHeap(), 0, filenameA );
1399 return res;
1402 /***********************************************************************
1403 * WriteProfileSection16 (KERNEL.417)
1405 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1407 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1410 /***********************************************************************
1411 * WriteProfileSection32A (KERNEL32.747)
1413 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1416 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1419 /***********************************************************************
1420 * WriteProfileSection32W (KERNEL32.748)
1422 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1424 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini");
1426 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1429 /***********************************************************************
1430 * GetPrivateProfileSectionNames16 (KERNEL.143)
1432 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1433 LPCSTR filename )
1435 WORD ret = 0;
1437 EnterCriticalSection( &PROFILE_CritSect );
1439 if (PROFILE_Open( filename ))
1440 ret = PROFILE_GetSectionNames(buffer, size);
1442 LeaveCriticalSection( &PROFILE_CritSect );
1444 return ret;
1448 /***********************************************************************
1449 * GetProfileSectionNames16 (KERNEL.142)
1451 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1454 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1458 /***********************************************************************
1459 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1461 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1462 LPCSTR filename)
1465 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1469 /***********************************************************************
1470 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1472 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1473 LPCWSTR filename)
1476 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1477 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1479 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1480 lstrcpynAtoW( buffer, bufferA, size);
1481 HeapFree( GetProcessHeap(), 0, bufferA);
1482 HeapFree( GetProcessHeap(), 0, filenameA );
1484 return ret;
1487 /***********************************************************************
1488 * GetPrivateProfileStruct16 (KERNEL.407)
1490 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1491 LPVOID buf, UINT16 len, LPCSTR filename)
1493 return GetPrivateProfileStructA( section, key, buf, len, filename );
1496 /***********************************************************************
1497 * GetPrivateProfileStruct32A (KERNEL32.370)
1499 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1500 LPVOID buf, UINT len, LPCSTR filename)
1502 BOOL ret = FALSE;
1504 EnterCriticalSection( &PROFILE_CritSect );
1506 if (PROFILE_Open( filename )) {
1507 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1508 if (k) {
1509 lstrcpynA( buf, k->value, strlen(k->value));
1510 ret = TRUE;
1513 LeaveCriticalSection( &PROFILE_CritSect );
1515 return FALSE;
1518 /***********************************************************************
1519 * GetPrivateProfileStruct32W (KERNEL32.543)
1521 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1522 LPVOID buffer, UINT len, LPCWSTR filename)
1524 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1525 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1526 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1527 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1529 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1530 len, filenameA );
1531 lstrcpynAtoW( buffer, bufferA, len );
1532 HeapFree( GetProcessHeap(), 0, bufferA);
1533 HeapFree( GetProcessHeap(), 0, sectionA );
1534 HeapFree( GetProcessHeap(), 0, keyA );
1535 HeapFree( GetProcessHeap(), 0, filenameA );
1537 return ret;
1542 /***********************************************************************
1543 * WritePrivateProfileStruct16 (KERNEL.406)
1545 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1546 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1548 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1551 /***********************************************************************
1552 * WritePrivateProfileStruct32A (KERNEL32.744)
1554 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1555 LPVOID buf, UINT bufsize, LPCSTR filename)
1557 BOOL ret = FALSE;
1559 if (!section && !key && !buf) /* flush the cache */
1560 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1562 EnterCriticalSection( &PROFILE_CritSect );
1564 if (PROFILE_Open( filename ))
1565 ret = PROFILE_SetString( section, key, buf );
1567 LeaveCriticalSection( &PROFILE_CritSect );
1569 return ret;
1572 /***********************************************************************
1573 * WritePrivateProfileStruct32W (KERNEL32.544)
1575 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1576 LPVOID buf, UINT bufsize, LPCWSTR filename)
1578 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1579 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1580 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1581 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1582 filenameA );
1583 HeapFree( GetProcessHeap(), 0, sectionA );
1584 HeapFree( GetProcessHeap(), 0, keyA );
1585 HeapFree( GetProcessHeap(), 0, filenameA );
1587 return ret;
1591 /***********************************************************************
1592 * WriteOutProfiles (KERNEL.315)
1594 void WINAPI WriteOutProfiles16(void)
1596 EnterCriticalSection( &PROFILE_CritSect );
1597 PROFILE_FlushFile();
1598 LeaveCriticalSection( &PROFILE_CritSect );
1601 /***********************************************************************
1602 * CloseProfileUserMapping (KERNEL.138)
1604 BOOL WINAPI CloseProfileUserMapping(void) {
1605 FIXME("(), stub!\n");
1606 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1607 return FALSE;