Added stub for WIN32S16.EXP1 (most likely LoadPeResource16).
[wine/dcerpc.git] / files / profile.c
blob6f1a50f2ed83252ce6b166b8c2009f482255e4d8
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>
12 #include <sys/stat.h>
14 #include "winbase.h"
15 #include "wine/winbase16.h"
16 #include "winuser.h"
17 #include "winnls.h"
18 #include "file.h"
19 #include "heap.h"
20 #include "debugtools.h"
21 #include "options.h"
23 DEFAULT_DEBUG_CHANNEL(profile)
25 typedef struct tagPROFILEKEY
27 char *name;
28 char *value;
29 struct tagPROFILEKEY *next;
30 } PROFILEKEY;
32 typedef struct tagPROFILESECTION
34 char *name;
35 struct tagPROFILEKEY *key;
36 struct tagPROFILESECTION *next;
37 } PROFILESECTION;
40 typedef struct
42 BOOL changed;
43 PROFILESECTION *section;
44 char *dos_name;
45 char *unix_name;
46 char *filename;
47 time_t mtime;
48 } PROFILE;
51 #define N_CACHED_PROFILES 10
53 /* Cached profile files */
54 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
56 #define CurProfile (MRUProfile[0])
58 /* wine.ini profile content */
59 static PROFILESECTION *PROFILE_WineProfile;
61 #define PROFILE_MAX_LINE_LEN 1024
63 /* Wine profile name in $HOME directory; must begin with slash */
64 static const char PROFILE_WineIniName[] = "/.winerc";
66 /* Wine profile: the profile file being used */
67 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
69 /* Check for comments in profile */
70 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
72 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
74 static LPCWSTR wininiW = NULL;
76 static CRITICAL_SECTION PROFILE_CritSect;
78 /***********************************************************************
79 * PROFILE_CopyEntry
81 * Copy the content of an entry into a buffer, removing quotes, and possibly
82 * translating environment variables.
84 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
85 int handle_env )
87 char quote = '\0';
88 const char *p;
90 if ((*value == '\'') || (*value == '\"'))
92 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
95 if (!handle_env)
97 lstrcpynA( buffer, value, len );
98 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
99 return;
102 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
104 if ((*p == '$') && (p[1] == '{'))
106 char env_val[1024];
107 const char *env_p;
108 const char *p2 = strchr( p, '}' );
109 if (!p2) continue; /* ignore it */
110 lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
111 if ((env_p = getenv( env_val )) != NULL)
113 lstrcpynA( buffer, env_p, len );
114 buffer += strlen( buffer );
115 len -= strlen( buffer );
117 p = p2 + 1;
120 *buffer = '\0';
124 /***********************************************************************
125 * PROFILE_Save
127 * Save a profile tree to a file.
129 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
131 PROFILEKEY *key;
133 for ( ; section; section = section->next)
135 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
136 for (key = section->key; key; key = key->next)
138 fprintf( file, "%s", key->name );
139 if (key->value) fprintf( file, "=%s", key->value );
140 fprintf( file, "\r\n" );
146 /***********************************************************************
147 * PROFILE_Free
149 * Free a profile tree.
151 static void PROFILE_Free( PROFILESECTION *section )
153 PROFILESECTION *next_section;
154 PROFILEKEY *key, *next_key;
156 for ( ; section; section = next_section)
158 if (section->name) HeapFree( SystemHeap, 0, section->name );
159 for (key = section->key; key; key = next_key)
161 next_key = key->next;
162 if (key->name) HeapFree( SystemHeap, 0, key->name );
163 if (key->value) HeapFree( SystemHeap, 0, key->value );
164 HeapFree( SystemHeap, 0, key );
166 next_section = section->next;
167 HeapFree( SystemHeap, 0, section );
171 static int
172 PROFILE_isspace(char c) {
173 if (isspace(c)) return 1;
174 if (c=='\r' || c==0x1a) return 1;
175 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
176 return 0;
180 /***********************************************************************
181 * PROFILE_Load
183 * Load a profile tree from a file.
185 static PROFILESECTION *PROFILE_Load( FILE *file )
187 char buffer[PROFILE_MAX_LINE_LEN];
188 char *p, *p2;
189 int line = 0;
190 PROFILESECTION *section, *first_section;
191 PROFILESECTION **next_section;
192 PROFILEKEY *key, *prev_key, **next_key;
194 first_section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
195 first_section->name = NULL;
196 first_section->key = NULL;
197 first_section->next = NULL;
198 next_section = &first_section->next;
199 next_key = &first_section->key;
200 prev_key = NULL;
202 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
204 line++;
205 p = buffer;
206 while (*p && PROFILE_isspace(*p)) p++;
207 if (*p == '[') /* section start */
209 if (!(p2 = strrchr( p, ']' )))
211 WARN("Invalid section header at line %d: '%s'\n",
212 line, p );
214 else
216 *p2 = '\0';
217 p++;
218 section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
219 section->name = HEAP_strdupA( SystemHeap, 0, p );
220 section->key = NULL;
221 section->next = NULL;
222 *next_section = section;
223 next_section = &section->next;
224 next_key = &section->key;
225 prev_key = NULL;
227 TRACE("New section: '%s'\n",section->name);
229 continue;
233 p2=p+strlen(p) - 1;
234 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
236 if ((p2 = strchr( p, '=' )) != NULL)
238 char *p3 = p2 - 1;
239 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
240 *p2++ = '\0';
241 while (*p2 && PROFILE_isspace(*p2)) p2++;
244 if(*p || !prev_key || *prev_key->name)
246 key = HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
247 key->name = HEAP_strdupA( SystemHeap, 0, p );
248 key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
249 key->next = NULL;
250 *next_key = key;
251 next_key = &key->next;
252 prev_key = key;
254 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
257 return first_section;
261 /***********************************************************************
262 * PROFILE_DeleteSection
264 * Delete a section from a profile tree.
266 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
268 while (*section)
270 if ((*section)->name && !strcasecmp( (*section)->name, name ))
272 PROFILESECTION *to_del = *section;
273 *section = to_del->next;
274 to_del->next = NULL;
275 PROFILE_Free( to_del );
276 return TRUE;
278 section = &(*section)->next;
280 return FALSE;
284 /***********************************************************************
285 * PROFILE_DeleteKey
287 * Delete a key from a profile tree.
289 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
290 LPCSTR section_name, LPCSTR key_name )
292 while (*section)
294 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
296 PROFILEKEY **key = &(*section)->key;
297 while (*key)
299 if (!strcasecmp( (*key)->name, key_name ))
301 PROFILEKEY *to_del = *key;
302 *key = to_del->next;
303 if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
304 if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
305 HeapFree( SystemHeap, 0, to_del );
306 return TRUE;
308 key = &(*key)->next;
311 section = &(*section)->next;
313 return FALSE;
317 /***********************************************************************
318 * PROFILE_Find
320 * Find a key in a profile tree, optionally creating it.
322 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
323 const char *section_name,
324 const char *key_name, int create )
326 while (*section)
328 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
330 PROFILEKEY **key = &(*section)->key;
331 while (*key)
333 if (!strcasecmp( (*key)->name, key_name )) return *key;
334 key = &(*key)->next;
336 if (!create) return NULL;
337 *key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
338 (*key)->name = HEAP_strdupA( SystemHeap, 0, key_name );
339 (*key)->value = NULL;
340 (*key)->next = NULL;
341 return *key;
343 section = &(*section)->next;
345 if (!create) return NULL;
346 *section = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
347 (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
348 (*section)->next = NULL;
349 (*section)->key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
350 (*section)->key->name = HEAP_strdupA( SystemHeap, 0, key_name );
351 (*section)->key->value = NULL;
352 (*section)->key->next = NULL;
353 return (*section)->key;
357 /***********************************************************************
358 * PROFILE_FlushFile
360 * Flush the current profile to disk if changed.
362 static BOOL PROFILE_FlushFile(void)
364 char *p, buffer[MAX_PATHNAME_LEN];
365 const char *unix_name;
366 FILE *file = NULL;
367 struct stat buf;
369 if(!CurProfile)
371 WARN("No current profile!\n");
372 return FALSE;
375 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
376 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
378 /* Try to create it in $HOME/.wine */
379 /* FIXME: this will need a more general solution */
380 if ((p = getenv( "HOME" )) != NULL)
382 strcpy( buffer, p );
383 strcat( buffer, "/.wine/" );
384 p = buffer + strlen(buffer);
385 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
386 CharLowerA( p );
387 file = fopen( buffer, "w" );
388 unix_name = buffer;
392 if (!file)
394 WARN("could not save profile file %s\n", CurProfile->dos_name);
395 return FALSE;
398 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
399 PROFILE_Save( file, CurProfile->section );
400 fclose( file );
401 CurProfile->changed = FALSE;
402 if(!stat(unix_name,&buf))
403 CurProfile->mtime=buf.st_mtime;
404 return TRUE;
408 /***********************************************************************
409 * PROFILE_ReleaseFile
411 * Flush the current profile to disk and remove it from the cache.
413 static void PROFILE_ReleaseFile(void)
415 PROFILE_FlushFile();
416 PROFILE_Free( CurProfile->section );
417 if (CurProfile->dos_name) HeapFree( SystemHeap, 0, CurProfile->dos_name );
418 if (CurProfile->unix_name) HeapFree( SystemHeap, 0, CurProfile->unix_name );
419 if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
420 CurProfile->changed = FALSE;
421 CurProfile->section = NULL;
422 CurProfile->dos_name = NULL;
423 CurProfile->unix_name = NULL;
424 CurProfile->filename = NULL;
425 CurProfile->mtime = 0;
429 /***********************************************************************
430 * PROFILE_Open
432 * Open a profile file, checking the cached file first.
434 static BOOL PROFILE_Open( LPCSTR filename )
436 DOS_FULL_NAME full_name;
437 char buffer[MAX_PATHNAME_LEN];
438 char *newdos_name, *p;
439 FILE *file = NULL;
440 int i,j;
441 struct stat buf;
442 PROFILE *tempProfile;
444 /* First time around */
446 if(!CurProfile)
447 for(i=0;i<N_CACHED_PROFILES;i++)
449 MRUProfile[i]=HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
450 MRUProfile[i]->changed=FALSE;
451 MRUProfile[i]->section=NULL;
452 MRUProfile[i]->dos_name=NULL;
453 MRUProfile[i]->unix_name=NULL;
454 MRUProfile[i]->filename=NULL;
455 MRUProfile[i]->mtime=0;
458 /* Check for a match */
460 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
461 strchr( filename, ':' ))
463 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
465 else
467 GetWindowsDirectoryA( buffer, sizeof(buffer) );
468 strcat( buffer, "\\" );
469 strcat( buffer, filename );
470 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
473 for(i=0;i<N_CACHED_PROFILES;i++)
475 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
476 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
478 if(i)
480 PROFILE_FlushFile();
481 tempProfile=MRUProfile[i];
482 for(j=i;j>0;j--)
483 MRUProfile[j]=MRUProfile[j-1];
484 CurProfile=tempProfile;
486 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
487 TRACE("(%s): already opened (mru=%d)\n",
488 filename, i );
489 else
490 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
491 filename, i );
492 return TRUE;
496 /* Rotate the oldest to the top to be replaced */
498 if(i==N_CACHED_PROFILES)
500 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
501 for(i=N_CACHED_PROFILES-1;i>0;i--)
502 MRUProfile[i]=MRUProfile[i-1];
503 CurProfile=tempProfile;
506 /* Flush the profile */
508 if(CurProfile->filename) PROFILE_ReleaseFile();
510 newdos_name = HEAP_strdupA( SystemHeap, 0, full_name.short_name );
511 CurProfile->dos_name = newdos_name;
512 CurProfile->filename = HEAP_strdupA( SystemHeap, 0, filename );
514 /* Try to open the profile file, first in $HOME/.wine */
516 /* FIXME: this will need a more general solution */
517 if ((p = getenv( "HOME" )) != NULL)
519 strcpy( buffer, p );
520 strcat( buffer, "/.wine/" );
521 p = buffer + strlen(buffer);
522 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
523 CharLowerA( p );
524 if ((file = fopen( buffer, "r" )))
526 TRACE("(%s): found it in %s\n",
527 filename, buffer );
528 CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0, buffer );
532 if (!file)
534 CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0,
535 full_name.long_name );
536 if ((file = fopen( full_name.long_name, "r" )))
537 TRACE("(%s): found it in %s\n",
538 filename, full_name.long_name );
541 if (file)
543 CurProfile->section = PROFILE_Load( file );
544 fclose( file );
545 if(!stat(CurProfile->unix_name,&buf))
546 CurProfile->mtime=buf.st_mtime;
548 else
550 /* Does not exist yet, we will create it in PROFILE_FlushFile */
551 WARN("profile file %s not found\n", newdos_name );
553 return TRUE;
557 /***********************************************************************
558 * PROFILE_GetSection
560 * Returns all keys of a section.
561 * If return_values is TRUE, also include the corresponding values.
563 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
564 LPSTR buffer, UINT len, BOOL handle_env,
565 BOOL return_values )
567 PROFILEKEY *key;
568 while (section)
570 if (section->name && !strcasecmp( section->name, section_name ))
572 UINT oldlen = len;
573 for (key = section->key; key; key = key->next)
575 if (len <= 2) break;
576 if (!*key->name) continue; /* Skip empty lines */
577 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
578 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
579 len -= strlen(buffer) + 1;
580 buffer += strlen(buffer) + 1;
581 if (return_values && key->value) {
582 buffer[-1] = '=';
583 PROFILE_CopyEntry ( buffer,
584 key->value, len - 1, handle_env );
585 len -= strlen(buffer) + 1;
586 buffer += strlen(buffer) + 1;
589 *buffer = '\0';
590 if (len <= 1)
591 /*If either lpszSection or lpszKey is NULL and the supplied
592 destination buffer is too small to hold all the strings,
593 the last string is truncated and followed by two null characters.
594 In this case, the return value is equal to cchReturnBuffer
595 minus two. */
597 buffer[-1] = '\0';
598 return oldlen - 2;
600 return oldlen - len;
602 section = section->next;
604 buffer[0] = buffer[1] = '\0';
605 return 0;
609 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
611 LPSTR buf = buffer;
612 WORD l, cursize = 0;
613 PROFILESECTION *section;
615 for (section = CurProfile->section; section; section = section->next)
616 if (section->name) {
617 l = strlen(section->name);
618 cursize += l+1;
619 if (cursize > len+1)
620 return len-2;
622 strcpy(buf, section->name);
623 buf += l+1;
626 *buf=0;
627 buf++;
628 return buf-buffer;
632 /***********************************************************************
633 * PROFILE_GetString
635 * Get a profile string.
637 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
638 LPCSTR def_val, LPSTR buffer, UINT len )
640 PROFILEKEY *key = NULL;
642 if (!def_val) def_val = "";
643 if (key_name && key_name[0])
645 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
646 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
647 len, FALSE );
648 TRACE("('%s','%s','%s'): returning '%s'\n",
649 section, key_name, def_val, buffer );
650 return strlen( buffer );
652 if (section && section[0])
653 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
654 FALSE, FALSE);
655 /* undocumented; both section and key_name are NULL */
656 return PROFILE_GetSectionNames(buffer, len);
660 /***********************************************************************
661 * PROFILE_SetString
663 * Set a profile string.
665 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
666 LPCSTR value )
668 if (!key_name) /* Delete a whole section */
670 TRACE("('%s')\n", section_name);
671 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
672 section_name );
673 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
674 this is not an error on application's level.*/
676 else if (!value) /* Delete a key */
678 TRACE("('%s','%s')\n",
679 section_name, key_name );
680 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
681 section_name, key_name );
682 return TRUE; /* same error handling as above */
684 else /* Set the key value */
686 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
687 key_name, TRUE );
688 TRACE("('%s','%s','%s'): \n",
689 section_name, key_name, value );
690 if (!key) return FALSE;
691 if (key->value)
693 if (!strcmp( key->value, value ))
695 TRACE(" no change needed\n" );
696 return TRUE; /* No change needed */
698 TRACE(" replacing '%s'\n", key->value );
699 HeapFree( SystemHeap, 0, key->value );
701 else TRACE(" creating key\n" );
702 key->value = HEAP_strdupA( SystemHeap, 0, value );
703 CurProfile->changed = TRUE;
705 return TRUE;
709 /***********************************************************************
710 * PROFILE_GetWineIniString
712 * Get a config string from the wine.ini file.
714 int PROFILE_GetWineIniString( const char *section, const char *key_name,
715 const char *def, char *buffer, int len )
717 int ret;
719 EnterCriticalSection( &PROFILE_CritSect );
721 if (key_name)
723 PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
724 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
725 len, TRUE );
726 TRACE("('%s','%s','%s'): returning '%s'\n",
727 section, key_name, def, buffer );
728 ret = strlen( buffer );
730 else
732 ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
734 LeaveCriticalSection( &PROFILE_CritSect );
736 return ret;
740 /***********************************************************************
741 * PROFILE_GetWineIniInt
743 * Get a config integer from the wine.ini file.
745 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
747 char buffer[20];
748 char *p;
749 long result;
750 PROFILEKEY *key;
751 int ret;
753 EnterCriticalSection( &PROFILE_CritSect );
755 key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
756 if (!key || !key->value) {
757 ret = def;
758 } else {
759 PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
760 result = strtol( buffer, &p, 0 );
761 ret = (p == buffer) ? 0 /* No digits at all */ : (int)result;
764 LeaveCriticalSection( &PROFILE_CritSect );
766 return ret;
770 /******************************************************************************
772 * int PROFILE_EnumerateWineIniSection(
773 * char const *section, #Name of the section to enumerate
774 * void (*cbfn)(char const *key, char const *value, void *user),
775 * # Address of the callback function
776 * void *user ) # User-specified pointer.
778 * For each entry in a section in the wine.conf file, this function will
779 * call the specified callback function, informing it of each key and
780 * value. An optional user pointer may be passed to it (if this is not
781 * needed, pass NULL through it and ignore the value in the callback
782 * function).
784 * The callback function must accept three parameters:
785 * The name of the key (char const *)
786 * The value of the key (char const *)
787 * A user-specified parameter (void *)
788 * Note that the first two are char CONST *'s, not char *'s! The callback
789 * MUST not modify these strings!
791 * The return value indicates the number of times the callback function
792 * was called.
794 int PROFILE_EnumerateWineIniSection(
795 char const *section,
796 void (*cbfn)(char const *, char const *, void *),
797 void *userptr )
799 PROFILESECTION *scansect;
800 PROFILEKEY *scankey;
801 int calls = 0;
803 EnterCriticalSection( &PROFILE_CritSect );
805 /* Search for the correct section */
806 for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
807 if(scansect->name && !strcasecmp(scansect->name, section)) {
809 /* Enumerate each key with the callback */
810 for(scankey = scansect->key; scankey; scankey = scankey->next) {
812 /* Ignore blank entries -- these shouldn't exist, but let's
813 be extra careful */
814 if (!scankey->name[0]) continue;
815 if (!scankey->value) cbfn(scankey->name, NULL, userptr);
816 else
818 char value[1024];
819 PROFILE_CopyEntry(value, scankey->value, sizeof(value), TRUE);
820 cbfn(scankey->name, value, userptr);
822 ++calls;
825 break;
828 LeaveCriticalSection( &PROFILE_CritSect );
830 return calls;
834 /******************************************************************************
836 * int PROFILE_GetWineIniBool(
837 * char const *section,
838 * char const *key_name,
839 * int def )
841 * Reads a boolean value from the wine.ini file. This function attempts to
842 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
843 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
844 * true. Anything else results in the return of the default value.
846 * This function uses 1 to indicate true, and 0 for false. You can check
847 * for existence by setting def to something other than 0 or 1 and
848 * examining the return value.
850 int PROFILE_GetWineIniBool(
851 char const *section,
852 char const *key_name,
853 int def )
855 char key_value[2];
856 int retval;
858 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
860 switch(key_value[0]) {
861 case 'n':
862 case 'N':
863 case 'f':
864 case 'F':
865 case '0':
866 retval = 0;
867 break;
869 case 'y':
870 case 'Y':
871 case 't':
872 case 'T':
873 case '1':
874 retval = 1;
875 break;
877 default:
878 retval = def;
881 TRACE("(\"%s\", \"%s\", %s), "
882 "[%c], ret %s.\n", section, key_name,
883 def ? "TRUE" : "FALSE", key_value[0],
884 retval ? "TRUE" : "FALSE");
886 return retval;
890 /***********************************************************************
891 * PROFILE_LoadWineIni
893 * Load the wine.ini file.
895 int PROFILE_LoadWineIni(void)
897 char buffer[MAX_PATHNAME_LEN];
898 const char *p;
899 FILE *f;
901 InitializeCriticalSection( &PROFILE_CritSect );
902 MakeCriticalSectionGlobal( &PROFILE_CritSect );
904 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
906 /* Open -config specified file */
907 PROFILE_WineProfile = PROFILE_Load ( f);
908 fclose ( f );
909 strncpy(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN-1);
910 return 1;
913 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
915 PROFILE_WineProfile = PROFILE_Load( f );
916 fclose( f );
917 strncpy(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN-1);
918 return 1;
920 if ((p = getenv( "HOME" )) != NULL)
922 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
923 strcat( buffer, PROFILE_WineIniName );
924 if ((f = fopen( buffer, "r" )) != NULL)
926 PROFILE_WineProfile = PROFILE_Load( f );
927 fclose( f );
928 strncpy(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN-1);
929 return 1;
932 else WARN("could not get $HOME value for config file.\n" );
934 /* Try global file */
936 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
938 PROFILE_WineProfile = PROFILE_Load( f );
939 fclose( f );
940 strncpy(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN-1);
941 return 1;
943 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
944 WINE_INI_GLOBAL, PROFILE_WineIniName );
945 return 0;
949 /***********************************************************************
950 * PROFILE_UsageWineIni
952 * Explain the wine.ini file to those who don't read documentation.
953 * Keep below one screenful in length so that error messages above are
954 * noticed.
956 void PROFILE_UsageWineIni(void)
958 MESSAGE("Perhaps you have not properly edited or created "
959 "your Wine configuration file.\n");
960 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
961 MESSAGE(" or it is determined by the -config option or from\n"
962 " the WINE_INI environment variable.\n");
963 if (*PROFILE_WineIniUsed)
964 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
965 /* RTFM, so to say */
968 /***********************************************************************
969 * PROFILE_GetStringItem
971 * Convenience function that turns a string 'xxx, yyy, zzz' into
972 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
974 char* PROFILE_GetStringItem( char* start )
976 char* lpchX, *lpch;
978 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
980 if( *lpchX == ',' )
982 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
983 while( *(++lpchX) )
984 if( !PROFILE_isspace(*lpchX) ) return lpchX;
986 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
987 else lpch = NULL;
989 if( lpch ) *lpch = '\0';
990 return NULL;
993 /********************* API functions **********************************/
995 /***********************************************************************
996 * GetProfileInt16 (KERNEL.57)
998 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1000 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1004 /***********************************************************************
1005 * GetProfileInt32A (KERNEL32.264)
1007 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1009 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1012 /***********************************************************************
1013 * GetProfileInt32W (KERNEL32.264)
1015 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1017 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1018 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1021 /***********************************************************************
1022 * GetProfileString16 (KERNEL.58)
1024 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1025 LPSTR buffer, UINT16 len )
1027 return GetPrivateProfileString16( section, entry, def_val,
1028 buffer, len, "win.ini" );
1031 /***********************************************************************
1032 * GetProfileString32A (KERNEL32.268)
1034 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1035 LPSTR buffer, UINT len )
1037 return GetPrivateProfileStringA( section, entry, def_val,
1038 buffer, len, "win.ini" );
1041 /***********************************************************************
1042 * GetProfileString32W (KERNEL32.269)
1044 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1045 LPCWSTR def_val, LPWSTR buffer, UINT len )
1047 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1048 return GetPrivateProfileStringW( section, entry, def_val,
1049 buffer, len, wininiW );
1052 /***********************************************************************
1053 * WriteProfileString16 (KERNEL.59)
1055 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1056 LPCSTR string )
1058 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1061 /***********************************************************************
1062 * WriteProfileString32A (KERNEL32.587)
1064 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1065 LPCSTR string )
1067 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1070 /***********************************************************************
1071 * WriteProfileString32W (KERNEL32.588)
1073 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1074 LPCWSTR string )
1076 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1077 return WritePrivateProfileStringW( section, entry, string, wininiW );
1081 /***********************************************************************
1082 * GetPrivateProfileInt16 (KERNEL.127)
1084 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1085 INT16 def_val, LPCSTR filename )
1087 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1089 if (result > 65535) return 65535;
1090 if (result >= 0) return (UINT16)result;
1091 if (result < -32768) return -32768;
1092 return (UINT16)(INT16)result;
1095 /***********************************************************************
1096 * GetPrivateProfileInt32A (KERNEL32.251)
1098 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1099 INT def_val, LPCSTR filename )
1101 char buffer[20];
1102 char *p;
1103 long result;
1105 GetPrivateProfileStringA( section, entry, "",
1106 buffer, sizeof(buffer), filename );
1107 if (!buffer[0]) return (UINT)def_val;
1108 result = strtol( buffer, &p, 0 );
1109 if (p == buffer) return 0; /* No digits at all */
1110 return (UINT)result;
1113 /***********************************************************************
1114 * GetPrivateProfileInt32W (KERNEL32.252)
1116 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1117 INT def_val, LPCWSTR filename )
1119 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1120 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1121 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1122 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1123 HeapFree( GetProcessHeap(), 0, sectionA );
1124 HeapFree( GetProcessHeap(), 0, filenameA );
1125 HeapFree( GetProcessHeap(), 0, entryA );
1126 return res;
1129 /***********************************************************************
1130 * GetPrivateProfileString16 (KERNEL.128)
1132 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1133 LPCSTR def_val, LPSTR buffer,
1134 UINT16 len, LPCSTR filename )
1136 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1139 /***********************************************************************
1140 * GetPrivateProfileString32A (KERNEL32.255)
1142 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1143 LPCSTR def_val, LPSTR buffer,
1144 UINT len, LPCSTR filename )
1146 int ret;
1148 if (!filename)
1149 filename = "win.ini";
1151 EnterCriticalSection( &PROFILE_CritSect );
1153 if (PROFILE_Open( filename )) {
1154 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1155 } else {
1156 lstrcpynA( buffer, def_val, len );
1157 ret = strlen( buffer );
1160 LeaveCriticalSection( &PROFILE_CritSect );
1162 return ret;
1165 /***********************************************************************
1166 * GetPrivateProfileString32W (KERNEL32.256)
1168 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1169 LPCWSTR def_val, LPWSTR buffer,
1170 UINT len, LPCWSTR filename )
1172 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1173 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1174 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1175 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1176 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1177 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1178 bufferA, len, filenameA );
1179 lstrcpynAtoW( buffer, bufferA, len );
1180 HeapFree( GetProcessHeap(), 0, sectionA );
1181 HeapFree( GetProcessHeap(), 0, entryA );
1182 HeapFree( GetProcessHeap(), 0, filenameA );
1183 HeapFree( GetProcessHeap(), 0, def_valA );
1184 HeapFree( GetProcessHeap(), 0, bufferA);
1185 return ret;
1188 /***********************************************************************
1189 * GetPrivateProfileSection16 (KERNEL.418)
1191 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1192 UINT16 len, LPCSTR filename )
1194 return GetPrivateProfileSectionA( section, buffer, len, filename );
1197 /***********************************************************************
1198 * GetPrivateProfileSection32A (KERNEL32.255)
1200 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1201 DWORD len, LPCSTR filename )
1203 int ret = 0;
1205 EnterCriticalSection( &PROFILE_CritSect );
1207 if (PROFILE_Open( filename ))
1208 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1209 FALSE, TRUE);
1211 LeaveCriticalSection( &PROFILE_CritSect );
1213 return ret;
1216 /***********************************************************************
1217 * GetPrivateProfileSection32W (KERNEL32.256)
1220 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1221 DWORD len, LPCWSTR filename )
1224 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1225 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1226 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1227 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1228 filenameA );
1229 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1230 HeapFree( GetProcessHeap(), 0, sectionA );
1231 HeapFree( GetProcessHeap(), 0, filenameA );
1232 HeapFree( GetProcessHeap(), 0, bufferA);
1233 return ret;
1236 /***********************************************************************
1237 * GetProfileSection16 (KERNEL.419)
1239 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1241 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1244 /***********************************************************************
1245 * GetProfileSection32A (KERNEL32.268)
1247 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1249 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1252 /***********************************************************************
1253 * GetProfileSection32W (KERNEL32)
1255 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1257 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1258 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1262 /***********************************************************************
1263 * WritePrivateProfileString16 (KERNEL.129)
1265 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1266 LPCSTR string, LPCSTR filename )
1268 return WritePrivateProfileStringA(section,entry,string,filename);
1271 /***********************************************************************
1272 * WritePrivateProfileString32A (KERNEL32.582)
1274 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1275 LPCSTR string, LPCSTR filename )
1277 BOOL ret = FALSE;
1279 EnterCriticalSection( &PROFILE_CritSect );
1281 if (PROFILE_Open( filename ))
1283 if (!section && !entry && !string)
1284 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1285 else
1286 ret = PROFILE_SetString( section, entry, string );
1289 LeaveCriticalSection( &PROFILE_CritSect );
1290 return ret;
1293 /***********************************************************************
1294 * WritePrivateProfileString32W (KERNEL32.583)
1296 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1297 LPCWSTR string, LPCWSTR filename )
1299 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1300 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1301 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1302 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1303 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1304 stringA, filenameA );
1305 HeapFree( GetProcessHeap(), 0, sectionA );
1306 HeapFree( GetProcessHeap(), 0, entryA );
1307 HeapFree( GetProcessHeap(), 0, stringA );
1308 HeapFree( GetProcessHeap(), 0, filenameA );
1309 return res;
1312 /***********************************************************************
1313 * WritePrivateProfileSection16 (KERNEL.416)
1315 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1316 LPCSTR string, LPCSTR filename )
1318 return WritePrivateProfileSectionA( section, string, filename );
1321 /***********************************************************************
1322 * WritePrivateProfileSection32A (KERNEL32)
1324 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1325 LPCSTR string, LPCSTR filename )
1327 char *p =(char*)string;
1329 FIXME("WritePrivateProfileSection32A empty stub\n");
1330 if (TRACE_ON(profile)) {
1331 TRACE("(%s) => [%s]\n", filename, section);
1332 while (*(p+1)) {
1333 TRACE("%s\n", p);
1334 p += strlen(p);
1335 p += 1;
1339 return FALSE;
1342 /***********************************************************************
1343 * WritePrivateProfileSection32W (KERNEL32)
1345 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1346 LPCWSTR string, LPCWSTR filename)
1349 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1350 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1351 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1352 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1353 HeapFree( GetProcessHeap(), 0, sectionA );
1354 HeapFree( GetProcessHeap(), 0, stringA );
1355 HeapFree( GetProcessHeap(), 0, filenameA );
1356 return res;
1359 /***********************************************************************
1360 * WriteProfileSection16 (KERNEL.417)
1362 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1364 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1367 /***********************************************************************
1368 * WriteProfileSection32A (KERNEL32.747)
1370 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1373 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1376 /***********************************************************************
1377 * WriteProfileSection32W (KERNEL32.748)
1379 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1381 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini");
1383 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1386 /***********************************************************************
1387 * GetPrivateProfileSectionNames16 (KERNEL.143)
1389 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1390 LPCSTR filename )
1392 WORD ret = 0;
1394 EnterCriticalSection( &PROFILE_CritSect );
1396 if (PROFILE_Open( filename ))
1397 ret = PROFILE_GetSectionNames(buffer, size);
1399 LeaveCriticalSection( &PROFILE_CritSect );
1401 return ret;
1405 /***********************************************************************
1406 * GetProfileSectionNames16 (KERNEL.142)
1408 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1411 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1415 /***********************************************************************
1416 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1418 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1419 LPCSTR filename)
1422 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1426 /***********************************************************************
1427 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1429 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1430 LPCWSTR filename)
1433 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1434 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1436 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1437 lstrcpynAtoW( buffer, bufferA, size);
1438 HeapFree( GetProcessHeap(), 0, bufferA);
1439 HeapFree( GetProcessHeap(), 0, filenameA );
1441 return ret;
1444 /***********************************************************************
1445 * GetPrivateProfileStruct16 (KERNEL.407)
1447 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1448 LPVOID buf, UINT16 len, LPCSTR filename)
1450 return GetPrivateProfileStructA( section, key, buf, len, filename );
1453 /***********************************************************************
1454 * GetPrivateProfileStruct32A (KERNEL32.370)
1456 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1457 LPVOID buf, UINT len, LPCSTR filename)
1459 BOOL ret = FALSE;
1461 EnterCriticalSection( &PROFILE_CritSect );
1463 if (PROFILE_Open( filename )) {
1464 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1465 if (k) {
1466 lstrcpynA( buf, k->value, strlen(k->value));
1467 ret = TRUE;
1470 LeaveCriticalSection( &PROFILE_CritSect );
1472 return FALSE;
1475 /***********************************************************************
1476 * GetPrivateProfileStruct32W (KERNEL32.543)
1478 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1479 LPVOID buffer, UINT len, LPCWSTR filename)
1481 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1482 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1483 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1484 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1486 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1487 len, filenameA );
1488 lstrcpynAtoW( buffer, bufferA, len );
1489 HeapFree( GetProcessHeap(), 0, bufferA);
1490 HeapFree( GetProcessHeap(), 0, sectionA );
1491 HeapFree( GetProcessHeap(), 0, keyA );
1492 HeapFree( GetProcessHeap(), 0, filenameA );
1494 return ret;
1499 /***********************************************************************
1500 * WritePrivateProfileStruct16 (KERNEL.406)
1502 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1503 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1505 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1508 /***********************************************************************
1509 * WritePrivateProfileStruct32A (KERNEL32.744)
1511 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1512 LPVOID buf, UINT bufsize, LPCSTR filename)
1514 BOOL ret = FALSE;
1516 if (!section && !key && !buf) /* flush the cache */
1517 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1519 EnterCriticalSection( &PROFILE_CritSect );
1521 if (PROFILE_Open( filename ))
1522 ret = PROFILE_SetString( section, key, buf );
1524 LeaveCriticalSection( &PROFILE_CritSect );
1526 return ret;
1529 /***********************************************************************
1530 * WritePrivateProfileStruct32W (KERNEL32.544)
1532 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1533 LPVOID buf, UINT bufsize, LPCWSTR filename)
1535 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1536 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1537 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1538 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1539 filenameA );
1540 HeapFree( GetProcessHeap(), 0, sectionA );
1541 HeapFree( GetProcessHeap(), 0, keyA );
1542 HeapFree( GetProcessHeap(), 0, filenameA );
1544 return ret;
1548 /***********************************************************************
1549 * WriteOutProfiles (KERNEL.315)
1551 void WINAPI WriteOutProfiles16(void)
1553 EnterCriticalSection( &PROFILE_CritSect );
1554 PROFILE_FlushFile();
1555 LeaveCriticalSection( &PROFILE_CritSect );