Implemented waitable timers.
[wine.git] / files / profile.c
bloba09ed9517f35be39ffea6a48b7ca446bd9b7ce96
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 if (quote && (len > 1)) buffer--;
121 *buffer = '\0';
125 /***********************************************************************
126 * PROFILE_Save
128 * Save a profile tree to a file.
130 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
132 PROFILEKEY *key;
134 for ( ; section; section = section->next)
136 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
137 for (key = section->key; key; key = key->next)
139 fprintf( file, "%s", key->name );
140 if (key->value) fprintf( file, "=%s", key->value );
141 fprintf( file, "\r\n" );
147 /***********************************************************************
148 * PROFILE_Free
150 * Free a profile tree.
152 static void PROFILE_Free( PROFILESECTION *section )
154 PROFILESECTION *next_section;
155 PROFILEKEY *key, *next_key;
157 for ( ; section; section = next_section)
159 if (section->name) HeapFree( SystemHeap, 0, section->name );
160 for (key = section->key; key; key = next_key)
162 next_key = key->next;
163 if (key->name) HeapFree( SystemHeap, 0, key->name );
164 if (key->value) HeapFree( SystemHeap, 0, key->value );
165 HeapFree( SystemHeap, 0, key );
167 next_section = section->next;
168 HeapFree( SystemHeap, 0, section );
172 static int
173 PROFILE_isspace(char c) {
174 if (isspace(c)) return 1;
175 if (c=='\r' || c==0x1a) return 1;
176 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
177 return 0;
181 /***********************************************************************
182 * PROFILE_Load
184 * Load a profile tree from a file.
186 static PROFILESECTION *PROFILE_Load( FILE *file )
188 char buffer[PROFILE_MAX_LINE_LEN];
189 char *p, *p2;
190 int line = 0;
191 PROFILESECTION *section, *first_section;
192 PROFILESECTION **next_section;
193 PROFILEKEY *key, *prev_key, **next_key;
195 first_section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
196 first_section->name = NULL;
197 first_section->key = NULL;
198 first_section->next = NULL;
199 next_section = &first_section->next;
200 next_key = &first_section->key;
201 prev_key = NULL;
203 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
205 line++;
206 p = buffer;
207 while (*p && PROFILE_isspace(*p)) p++;
208 if (*p == '[') /* section start */
210 if (!(p2 = strrchr( p, ']' )))
212 WARN("Invalid section header at line %d: '%s'\n",
213 line, p );
215 else
217 *p2 = '\0';
218 p++;
219 section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
220 section->name = HEAP_strdupA( SystemHeap, 0, p );
221 section->key = NULL;
222 section->next = NULL;
223 *next_section = section;
224 next_section = &section->next;
225 next_key = &section->key;
226 prev_key = NULL;
228 TRACE("New section: '%s'\n",section->name);
230 continue;
234 p2=p+strlen(p) - 1;
235 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
237 if ((p2 = strchr( p, '=' )) != NULL)
239 char *p3 = p2 - 1;
240 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
241 *p2++ = '\0';
242 while (*p2 && PROFILE_isspace(*p2)) p2++;
245 if(*p || !prev_key || *prev_key->name)
247 key = HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
248 key->name = HEAP_strdupA( SystemHeap, 0, p );
249 key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
250 key->next = NULL;
251 *next_key = key;
252 next_key = &key->next;
253 prev_key = key;
255 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
258 return first_section;
262 /***********************************************************************
263 * PROFILE_DeleteSection
265 * Delete a section from a profile tree.
267 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
269 while (*section)
271 if ((*section)->name && !strcasecmp( (*section)->name, name ))
273 PROFILESECTION *to_del = *section;
274 *section = to_del->next;
275 to_del->next = NULL;
276 PROFILE_Free( to_del );
277 return TRUE;
279 section = &(*section)->next;
281 return FALSE;
285 /***********************************************************************
286 * PROFILE_DeleteKey
288 * Delete a key from a profile tree.
290 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
291 LPCSTR section_name, LPCSTR key_name )
293 while (*section)
295 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
297 PROFILEKEY **key = &(*section)->key;
298 while (*key)
300 if (!strcasecmp( (*key)->name, key_name ))
302 PROFILEKEY *to_del = *key;
303 *key = to_del->next;
304 if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
305 if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
306 HeapFree( SystemHeap, 0, to_del );
307 return TRUE;
309 key = &(*key)->next;
312 section = &(*section)->next;
314 return FALSE;
318 /***********************************************************************
319 * PROFILE_Find
321 * Find a key in a profile tree, optionally creating it.
323 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
324 const char *section_name,
325 const char *key_name, int create )
327 while (*section)
329 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
331 PROFILEKEY **key = &(*section)->key;
332 while (*key)
334 if (!strcasecmp( (*key)->name, key_name )) return *key;
335 key = &(*key)->next;
337 if (!create) return NULL;
338 *key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
339 (*key)->name = HEAP_strdupA( SystemHeap, 0, key_name );
340 (*key)->value = NULL;
341 (*key)->next = NULL;
342 return *key;
344 section = &(*section)->next;
346 if (!create) return NULL;
347 *section = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
348 (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
349 (*section)->next = NULL;
350 (*section)->key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
351 (*section)->key->name = HEAP_strdupA( SystemHeap, 0, key_name );
352 (*section)->key->value = NULL;
353 (*section)->key->next = NULL;
354 return (*section)->key;
358 /***********************************************************************
359 * PROFILE_FlushFile
361 * Flush the current profile to disk if changed.
363 static BOOL PROFILE_FlushFile(void)
365 char *p, buffer[MAX_PATHNAME_LEN];
366 const char *unix_name;
367 FILE *file = NULL;
368 struct stat buf;
370 if(!CurProfile)
372 WARN("No current profile!\n");
373 return FALSE;
376 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
377 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
379 /* Try to create it in $HOME/.wine */
380 /* FIXME: this will need a more general solution */
381 if ((p = getenv( "HOME" )) != NULL)
383 strcpy( buffer, p );
384 strcat( buffer, "/.wine/" );
385 p = buffer + strlen(buffer);
386 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
387 CharLowerA( p );
388 file = fopen( buffer, "w" );
389 unix_name = buffer;
393 if (!file)
395 WARN("could not save profile file %s\n", CurProfile->dos_name);
396 return FALSE;
399 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
400 PROFILE_Save( file, CurProfile->section );
401 fclose( file );
402 CurProfile->changed = FALSE;
403 if(!stat(unix_name,&buf))
404 CurProfile->mtime=buf.st_mtime;
405 return TRUE;
409 /***********************************************************************
410 * PROFILE_ReleaseFile
412 * Flush the current profile to disk and remove it from the cache.
414 static void PROFILE_ReleaseFile(void)
416 PROFILE_FlushFile();
417 PROFILE_Free( CurProfile->section );
418 if (CurProfile->dos_name) HeapFree( SystemHeap, 0, CurProfile->dos_name );
419 if (CurProfile->unix_name) HeapFree( SystemHeap, 0, CurProfile->unix_name );
420 if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
421 CurProfile->changed = FALSE;
422 CurProfile->section = NULL;
423 CurProfile->dos_name = NULL;
424 CurProfile->unix_name = NULL;
425 CurProfile->filename = NULL;
426 CurProfile->mtime = 0;
430 /***********************************************************************
431 * PROFILE_Open
433 * Open a profile file, checking the cached file first.
435 static BOOL PROFILE_Open( LPCSTR filename )
437 DOS_FULL_NAME full_name;
438 char buffer[MAX_PATHNAME_LEN];
439 char *newdos_name, *p;
440 FILE *file = NULL;
441 int i,j;
442 struct stat buf;
443 PROFILE *tempProfile;
445 /* First time around */
447 if(!CurProfile)
448 for(i=0;i<N_CACHED_PROFILES;i++)
450 MRUProfile[i]=HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
451 MRUProfile[i]->changed=FALSE;
452 MRUProfile[i]->section=NULL;
453 MRUProfile[i]->dos_name=NULL;
454 MRUProfile[i]->unix_name=NULL;
455 MRUProfile[i]->filename=NULL;
456 MRUProfile[i]->mtime=0;
459 /* Check for a match */
461 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
462 strchr( filename, ':' ))
464 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
466 else
468 GetWindowsDirectoryA( buffer, sizeof(buffer) );
469 strcat( buffer, "\\" );
470 strcat( buffer, filename );
471 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
474 for(i=0;i<N_CACHED_PROFILES;i++)
476 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
477 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
479 if(i)
481 PROFILE_FlushFile();
482 tempProfile=MRUProfile[i];
483 for(j=i;j>0;j--)
484 MRUProfile[j]=MRUProfile[j-1];
485 CurProfile=tempProfile;
487 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
488 TRACE("(%s): already opened (mru=%d)\n",
489 filename, i );
490 else
491 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
492 filename, i );
493 return TRUE;
497 /* Flush the old current profile */
498 PROFILE_FlushFile();
500 /* Make the oldest profile the current one only in order to get rid of it */
501 if(i==N_CACHED_PROFILES)
503 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
504 for(i=N_CACHED_PROFILES-1;i>0;i--)
505 MRUProfile[i]=MRUProfile[i-1];
506 CurProfile=tempProfile;
508 if(CurProfile->filename) PROFILE_ReleaseFile();
510 /* OK, now that CurProfile is definitely free we assign it our new file */
511 newdos_name = HEAP_strdupA( SystemHeap, 0, full_name.short_name );
512 CurProfile->dos_name = newdos_name;
513 CurProfile->filename = HEAP_strdupA( SystemHeap, 0, filename );
515 /* Try to open the profile file, first in $HOME/.wine */
517 /* FIXME: this will need a more general solution */
518 if ((p = getenv( "HOME" )) != NULL)
520 strcpy( buffer, p );
521 strcat( buffer, "/.wine/" );
522 p = buffer + strlen(buffer);
523 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
524 CharLowerA( p );
525 if ((file = fopen( buffer, "r" )))
527 TRACE("(%s): found it in %s\n",
528 filename, buffer );
529 CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0, buffer );
533 if (!file)
535 CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0,
536 full_name.long_name );
537 if ((file = fopen( full_name.long_name, "r" )))
538 TRACE("(%s): found it in %s\n",
539 filename, full_name.long_name );
542 if (file)
544 CurProfile->section = PROFILE_Load( file );
545 fclose( file );
546 if(!stat(CurProfile->unix_name,&buf))
547 CurProfile->mtime=buf.st_mtime;
549 else
551 /* Does not exist yet, we will create it in PROFILE_FlushFile */
552 WARN("profile file %s not found\n", newdos_name );
554 return TRUE;
558 /***********************************************************************
559 * PROFILE_GetSection
561 * Returns all keys of a section.
562 * If return_values is TRUE, also include the corresponding values.
564 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
565 LPSTR buffer, UINT len, BOOL handle_env,
566 BOOL return_values )
568 PROFILEKEY *key;
569 while (section)
571 if (section->name && !strcasecmp( section->name, section_name ))
573 UINT oldlen = len;
574 for (key = section->key; key; key = key->next)
576 if (len <= 2) break;
577 if (!*key->name) continue; /* Skip empty lines */
578 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
579 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
580 len -= strlen(buffer) + 1;
581 buffer += strlen(buffer) + 1;
582 if (return_values && key->value) {
583 buffer[-1] = '=';
584 PROFILE_CopyEntry ( buffer,
585 key->value, len - 1, handle_env );
586 len -= strlen(buffer) + 1;
587 buffer += strlen(buffer) + 1;
590 *buffer = '\0';
591 if (len <= 1)
592 /*If either lpszSection or lpszKey is NULL and the supplied
593 destination buffer is too small to hold all the strings,
594 the last string is truncated and followed by two null characters.
595 In this case, the return value is equal to cchReturnBuffer
596 minus two. */
598 buffer[-1] = '\0';
599 return oldlen - 2;
601 return oldlen - len;
603 section = section->next;
605 buffer[0] = buffer[1] = '\0';
606 return 0;
610 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
612 LPSTR buf = buffer;
613 WORD l, cursize = 0;
614 PROFILESECTION *section;
616 for (section = CurProfile->section; section; section = section->next)
617 if (section->name) {
618 l = strlen(section->name);
619 cursize += l+1;
620 if (cursize > len+1)
621 return len-2;
623 strcpy(buf, section->name);
624 buf += l+1;
627 *buf=0;
628 buf++;
629 return buf-buffer;
633 /***********************************************************************
634 * PROFILE_GetString
636 * Get a profile string.
638 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
639 LPCSTR def_val, LPSTR buffer, UINT len )
641 PROFILEKEY *key = NULL;
643 if (!def_val) def_val = "";
644 if (key_name && key_name[0])
646 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
647 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
648 len, FALSE );
649 TRACE("('%s','%s','%s'): returning '%s'\n",
650 section, key_name, def_val, buffer );
651 return strlen( buffer );
653 if (section && section[0])
654 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
655 FALSE, FALSE);
656 /* undocumented; both section and key_name are NULL */
657 return PROFILE_GetSectionNames(buffer, len);
661 /***********************************************************************
662 * PROFILE_SetString
664 * Set a profile string.
666 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
667 LPCSTR value )
669 if (!key_name) /* Delete a whole section */
671 TRACE("('%s')\n", section_name);
672 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
673 section_name );
674 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
675 this is not an error on application's level.*/
677 else if (!value) /* Delete a key */
679 TRACE("('%s','%s')\n",
680 section_name, key_name );
681 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
682 section_name, key_name );
683 return TRUE; /* same error handling as above */
685 else /* Set the key value */
687 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
688 key_name, TRUE );
689 TRACE("('%s','%s','%s'): \n",
690 section_name, key_name, value );
691 if (!key) return FALSE;
692 if (key->value)
694 if (!strcmp( key->value, value ))
696 TRACE(" no change needed\n" );
697 return TRUE; /* No change needed */
699 TRACE(" replacing '%s'\n", key->value );
700 HeapFree( SystemHeap, 0, key->value );
702 else TRACE(" creating key\n" );
703 key->value = HEAP_strdupA( SystemHeap, 0, value );
704 CurProfile->changed = TRUE;
706 return TRUE;
710 /***********************************************************************
711 * PROFILE_GetWineIniString
713 * Get a config string from the wine.ini file.
715 int PROFILE_GetWineIniString( const char *section, const char *key_name,
716 const char *def, char *buffer, int len )
718 int ret;
720 EnterCriticalSection( &PROFILE_CritSect );
722 if (key_name)
724 PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
725 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
726 len, TRUE );
727 TRACE("('%s','%s','%s'): returning '%s'\n",
728 section, key_name, def, buffer );
729 ret = strlen( buffer );
731 else
733 ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
735 LeaveCriticalSection( &PROFILE_CritSect );
737 return ret;
741 /***********************************************************************
742 * PROFILE_GetWineIniInt
744 * Get a config integer from the wine.ini file.
746 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
748 char buffer[20];
749 char *p;
750 long result;
751 PROFILEKEY *key;
752 int ret;
754 EnterCriticalSection( &PROFILE_CritSect );
756 key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
757 if (!key || !key->value) {
758 ret = def;
759 } else {
760 PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
761 result = strtol( buffer, &p, 0 );
762 ret = (p == buffer) ? 0 /* No digits at all */ : (int)result;
765 LeaveCriticalSection( &PROFILE_CritSect );
767 return ret;
771 /******************************************************************************
773 * int PROFILE_EnumerateWineIniSection(
774 * char const *section, #Name of the section to enumerate
775 * void (*cbfn)(char const *key, char const *value, void *user),
776 * # Address of the callback function
777 * void *user ) # User-specified pointer.
779 * For each entry in a section in the wine.conf file, this function will
780 * call the specified callback function, informing it of each key and
781 * value. An optional user pointer may be passed to it (if this is not
782 * needed, pass NULL through it and ignore the value in the callback
783 * function).
785 * The callback function must accept three parameters:
786 * The name of the key (char const *)
787 * The value of the key (char const *)
788 * A user-specified parameter (void *)
789 * Note that the first two are char CONST *'s, not char *'s! The callback
790 * MUST not modify these strings!
792 * The return value indicates the number of times the callback function
793 * was called.
795 int PROFILE_EnumerateWineIniSection(
796 char const *section,
797 void (*cbfn)(char const *, char const *, void *),
798 void *userptr )
800 PROFILESECTION *scansect;
801 PROFILEKEY *scankey;
802 int calls = 0;
804 EnterCriticalSection( &PROFILE_CritSect );
806 /* Search for the correct section */
807 for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
808 if(scansect->name && !strcasecmp(scansect->name, section)) {
810 /* Enumerate each key with the callback */
811 for(scankey = scansect->key; scankey; scankey = scankey->next) {
813 /* Ignore blank entries -- these shouldn't exist, but let's
814 be extra careful */
815 if (!scankey->name[0]) continue;
816 if (!scankey->value) cbfn(scankey->name, NULL, userptr);
817 else
819 char value[1024];
820 PROFILE_CopyEntry(value, scankey->value, sizeof(value), TRUE);
821 cbfn(scankey->name, value, userptr);
823 ++calls;
826 break;
829 LeaveCriticalSection( &PROFILE_CritSect );
831 return calls;
835 /******************************************************************************
837 * int PROFILE_GetWineIniBool(
838 * char const *section,
839 * char const *key_name,
840 * int def )
842 * Reads a boolean value from the wine.ini file. This function attempts to
843 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
844 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
845 * true. Anything else results in the return of the default value.
847 * This function uses 1 to indicate true, and 0 for false. You can check
848 * for existence by setting def to something other than 0 or 1 and
849 * examining the return value.
851 int PROFILE_GetWineIniBool(
852 char const *section,
853 char const *key_name,
854 int def )
856 char key_value[2];
857 int retval;
859 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
861 switch(key_value[0]) {
862 case 'n':
863 case 'N':
864 case 'f':
865 case 'F':
866 case '0':
867 retval = 0;
868 break;
870 case 'y':
871 case 'Y':
872 case 't':
873 case 'T':
874 case '1':
875 retval = 1;
876 break;
878 default:
879 retval = def;
882 TRACE("(\"%s\", \"%s\", %s), "
883 "[%c], ret %s.\n", section, key_name,
884 def ? "TRUE" : "FALSE", key_value[0],
885 retval ? "TRUE" : "FALSE");
887 return retval;
891 /***********************************************************************
892 * PROFILE_LoadWineIni
894 * Load the wine.ini file.
896 int PROFILE_LoadWineIni(void)
898 char buffer[MAX_PATHNAME_LEN];
899 const char *p;
900 FILE *f;
902 InitializeCriticalSection( &PROFILE_CritSect );
903 MakeCriticalSectionGlobal( &PROFILE_CritSect );
905 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
907 /* Open -config specified file */
908 PROFILE_WineProfile = PROFILE_Load ( f);
909 fclose ( f );
910 strncpy(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN-1);
911 return 1;
914 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
916 PROFILE_WineProfile = PROFILE_Load( f );
917 fclose( f );
918 strncpy(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN-1);
919 return 1;
921 if ((p = getenv( "HOME" )) != NULL)
923 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
924 strcat( buffer, PROFILE_WineIniName );
925 if ((f = fopen( buffer, "r" )) != NULL)
927 PROFILE_WineProfile = PROFILE_Load( f );
928 fclose( f );
929 strncpy(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN-1);
930 return 1;
933 else WARN("could not get $HOME value for config file.\n" );
935 /* Try global file */
937 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
939 PROFILE_WineProfile = PROFILE_Load( f );
940 fclose( f );
941 strncpy(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN-1);
942 return 1;
944 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
945 WINE_INI_GLOBAL, PROFILE_WineIniName );
946 return 0;
950 /***********************************************************************
951 * PROFILE_UsageWineIni
953 * Explain the wine.ini file to those who don't read documentation.
954 * Keep below one screenful in length so that error messages above are
955 * noticed.
957 void PROFILE_UsageWineIni(void)
959 MESSAGE("Perhaps you have not properly edited or created "
960 "your Wine configuration file.\n");
961 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
962 MESSAGE(" or it is determined by the -config option or from\n"
963 " the WINE_INI environment variable.\n");
964 if (*PROFILE_WineIniUsed)
965 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
966 /* RTFM, so to say */
969 /***********************************************************************
970 * PROFILE_GetStringItem
972 * Convenience function that turns a string 'xxx, yyy, zzz' into
973 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
975 char* PROFILE_GetStringItem( char* start )
977 char* lpchX, *lpch;
979 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
981 if( *lpchX == ',' )
983 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
984 while( *(++lpchX) )
985 if( !PROFILE_isspace(*lpchX) ) return lpchX;
987 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
988 else lpch = NULL;
990 if( lpch ) *lpch = '\0';
991 return NULL;
994 /********************* API functions **********************************/
996 /***********************************************************************
997 * GetProfileInt16 (KERNEL.57)
999 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1001 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1005 /***********************************************************************
1006 * GetProfileInt32A (KERNEL32.264)
1008 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1010 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1013 /***********************************************************************
1014 * GetProfileInt32W (KERNEL32.264)
1016 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1018 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1019 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1022 /***********************************************************************
1023 * GetProfileString16 (KERNEL.58)
1025 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1026 LPSTR buffer, UINT16 len )
1028 return GetPrivateProfileString16( section, entry, def_val,
1029 buffer, len, "win.ini" );
1032 /***********************************************************************
1033 * GetProfileString32A (KERNEL32.268)
1035 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1036 LPSTR buffer, UINT len )
1038 return GetPrivateProfileStringA( section, entry, def_val,
1039 buffer, len, "win.ini" );
1042 /***********************************************************************
1043 * GetProfileString32W (KERNEL32.269)
1045 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1046 LPCWSTR def_val, LPWSTR buffer, UINT len )
1048 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1049 return GetPrivateProfileStringW( section, entry, def_val,
1050 buffer, len, wininiW );
1053 /***********************************************************************
1054 * WriteProfileString16 (KERNEL.59)
1056 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1057 LPCSTR string )
1059 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1062 /***********************************************************************
1063 * WriteProfileString32A (KERNEL32.587)
1065 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1066 LPCSTR string )
1068 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1071 /***********************************************************************
1072 * WriteProfileString32W (KERNEL32.588)
1074 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1075 LPCWSTR string )
1077 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1078 return WritePrivateProfileStringW( section, entry, string, wininiW );
1082 /***********************************************************************
1083 * GetPrivateProfileInt16 (KERNEL.127)
1085 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1086 INT16 def_val, LPCSTR filename )
1088 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1090 if (result > 65535) return 65535;
1091 if (result >= 0) return (UINT16)result;
1092 if (result < -32768) return -32768;
1093 return (UINT16)(INT16)result;
1096 /***********************************************************************
1097 * GetPrivateProfileInt32A (KERNEL32.251)
1099 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1100 INT def_val, LPCSTR filename )
1102 char buffer[20];
1103 char *p;
1104 long result;
1106 GetPrivateProfileStringA( section, entry, "",
1107 buffer, sizeof(buffer), filename );
1108 if (!buffer[0]) return (UINT)def_val;
1109 result = strtol( buffer, &p, 0 );
1110 if (p == buffer) return 0; /* No digits at all */
1111 return (UINT)result;
1114 /***********************************************************************
1115 * GetPrivateProfileInt32W (KERNEL32.252)
1117 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1118 INT def_val, LPCWSTR filename )
1120 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1121 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1122 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1123 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1124 HeapFree( GetProcessHeap(), 0, sectionA );
1125 HeapFree( GetProcessHeap(), 0, filenameA );
1126 HeapFree( GetProcessHeap(), 0, entryA );
1127 return res;
1130 /***********************************************************************
1131 * GetPrivateProfileString16 (KERNEL.128)
1133 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1134 LPCSTR def_val, LPSTR buffer,
1135 UINT16 len, LPCSTR filename )
1137 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1140 /***********************************************************************
1141 * GetPrivateProfileString32A (KERNEL32.255)
1143 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1144 LPCSTR def_val, LPSTR buffer,
1145 UINT len, LPCSTR filename )
1147 int ret;
1149 if (!filename)
1150 filename = "win.ini";
1152 EnterCriticalSection( &PROFILE_CritSect );
1154 if (PROFILE_Open( filename )) {
1155 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1156 } else {
1157 lstrcpynA( buffer, def_val, len );
1158 ret = strlen( buffer );
1161 LeaveCriticalSection( &PROFILE_CritSect );
1163 return ret;
1166 /***********************************************************************
1167 * GetPrivateProfileString32W (KERNEL32.256)
1169 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1170 LPCWSTR def_val, LPWSTR buffer,
1171 UINT len, LPCWSTR filename )
1173 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1174 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1175 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1176 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1177 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1178 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1179 bufferA, len, filenameA );
1180 lstrcpynAtoW( buffer, bufferA, len );
1181 HeapFree( GetProcessHeap(), 0, sectionA );
1182 HeapFree( GetProcessHeap(), 0, entryA );
1183 HeapFree( GetProcessHeap(), 0, filenameA );
1184 HeapFree( GetProcessHeap(), 0, def_valA );
1185 HeapFree( GetProcessHeap(), 0, bufferA);
1186 return ret;
1189 /***********************************************************************
1190 * GetPrivateProfileSection16 (KERNEL.418)
1192 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1193 UINT16 len, LPCSTR filename )
1195 return GetPrivateProfileSectionA( section, buffer, len, filename );
1198 /***********************************************************************
1199 * GetPrivateProfileSection32A (KERNEL32.255)
1201 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1202 DWORD len, LPCSTR filename )
1204 int ret = 0;
1206 EnterCriticalSection( &PROFILE_CritSect );
1208 if (PROFILE_Open( filename ))
1209 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1210 FALSE, TRUE);
1212 LeaveCriticalSection( &PROFILE_CritSect );
1214 return ret;
1217 /***********************************************************************
1218 * GetPrivateProfileSection32W (KERNEL32.256)
1221 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1222 DWORD len, LPCWSTR filename )
1225 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1226 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1227 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1228 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1229 filenameA );
1230 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1231 HeapFree( GetProcessHeap(), 0, sectionA );
1232 HeapFree( GetProcessHeap(), 0, filenameA );
1233 HeapFree( GetProcessHeap(), 0, bufferA);
1234 return ret;
1237 /***********************************************************************
1238 * GetProfileSection16 (KERNEL.419)
1240 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1242 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1245 /***********************************************************************
1246 * GetProfileSection32A (KERNEL32.268)
1248 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1250 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1253 /***********************************************************************
1254 * GetProfileSection32W (KERNEL32)
1256 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1258 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1259 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1263 /***********************************************************************
1264 * WritePrivateProfileString16 (KERNEL.129)
1266 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1267 LPCSTR string, LPCSTR filename )
1269 return WritePrivateProfileStringA(section,entry,string,filename);
1272 /***********************************************************************
1273 * WritePrivateProfileString32A (KERNEL32.582)
1275 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1276 LPCSTR string, LPCSTR filename )
1278 BOOL ret = FALSE;
1280 EnterCriticalSection( &PROFILE_CritSect );
1282 if (PROFILE_Open( filename ))
1284 if (!section && !entry && !string)
1285 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1286 else
1287 ret = PROFILE_SetString( section, entry, string );
1290 LeaveCriticalSection( &PROFILE_CritSect );
1291 return ret;
1294 /***********************************************************************
1295 * WritePrivateProfileString32W (KERNEL32.583)
1297 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1298 LPCWSTR string, LPCWSTR filename )
1300 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1301 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1302 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1303 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1304 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1305 stringA, filenameA );
1306 HeapFree( GetProcessHeap(), 0, sectionA );
1307 HeapFree( GetProcessHeap(), 0, entryA );
1308 HeapFree( GetProcessHeap(), 0, stringA );
1309 HeapFree( GetProcessHeap(), 0, filenameA );
1310 return res;
1313 /***********************************************************************
1314 * WritePrivateProfileSection16 (KERNEL.416)
1316 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1317 LPCSTR string, LPCSTR filename )
1319 return WritePrivateProfileSectionA( section, string, filename );
1322 /***********************************************************************
1323 * WritePrivateProfileSection32A (KERNEL32)
1325 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1326 LPCSTR string, LPCSTR filename )
1328 char *p =(char*)string;
1330 FIXME("WritePrivateProfileSection32A empty stub\n");
1331 if (TRACE_ON(profile)) {
1332 TRACE("(%s) => [%s]\n", filename, section);
1333 while (*(p+1)) {
1334 TRACE("%s\n", p);
1335 p += strlen(p);
1336 p += 1;
1340 return FALSE;
1343 /***********************************************************************
1344 * WritePrivateProfileSection32W (KERNEL32)
1346 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1347 LPCWSTR string, LPCWSTR filename)
1350 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1351 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1352 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1353 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1354 HeapFree( GetProcessHeap(), 0, sectionA );
1355 HeapFree( GetProcessHeap(), 0, stringA );
1356 HeapFree( GetProcessHeap(), 0, filenameA );
1357 return res;
1360 /***********************************************************************
1361 * WriteProfileSection16 (KERNEL.417)
1363 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1365 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1368 /***********************************************************************
1369 * WriteProfileSection32A (KERNEL32.747)
1371 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1374 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1377 /***********************************************************************
1378 * WriteProfileSection32W (KERNEL32.748)
1380 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1382 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini");
1384 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1387 /***********************************************************************
1388 * GetPrivateProfileSectionNames16 (KERNEL.143)
1390 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1391 LPCSTR filename )
1393 WORD ret = 0;
1395 EnterCriticalSection( &PROFILE_CritSect );
1397 if (PROFILE_Open( filename ))
1398 ret = PROFILE_GetSectionNames(buffer, size);
1400 LeaveCriticalSection( &PROFILE_CritSect );
1402 return ret;
1406 /***********************************************************************
1407 * GetProfileSectionNames16 (KERNEL.142)
1409 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1412 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1416 /***********************************************************************
1417 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1419 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1420 LPCSTR filename)
1423 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1427 /***********************************************************************
1428 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1430 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1431 LPCWSTR filename)
1434 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1435 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1437 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1438 lstrcpynAtoW( buffer, bufferA, size);
1439 HeapFree( GetProcessHeap(), 0, bufferA);
1440 HeapFree( GetProcessHeap(), 0, filenameA );
1442 return ret;
1445 /***********************************************************************
1446 * GetPrivateProfileStruct16 (KERNEL.407)
1448 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1449 LPVOID buf, UINT16 len, LPCSTR filename)
1451 return GetPrivateProfileStructA( section, key, buf, len, filename );
1454 /***********************************************************************
1455 * GetPrivateProfileStruct32A (KERNEL32.370)
1457 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1458 LPVOID buf, UINT len, LPCSTR filename)
1460 BOOL ret = FALSE;
1462 EnterCriticalSection( &PROFILE_CritSect );
1464 if (PROFILE_Open( filename )) {
1465 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1466 if (k) {
1467 lstrcpynA( buf, k->value, strlen(k->value));
1468 ret = TRUE;
1471 LeaveCriticalSection( &PROFILE_CritSect );
1473 return FALSE;
1476 /***********************************************************************
1477 * GetPrivateProfileStruct32W (KERNEL32.543)
1479 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1480 LPVOID buffer, UINT len, LPCWSTR filename)
1482 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1483 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1484 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1485 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1487 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1488 len, filenameA );
1489 lstrcpynAtoW( buffer, bufferA, len );
1490 HeapFree( GetProcessHeap(), 0, bufferA);
1491 HeapFree( GetProcessHeap(), 0, sectionA );
1492 HeapFree( GetProcessHeap(), 0, keyA );
1493 HeapFree( GetProcessHeap(), 0, filenameA );
1495 return ret;
1500 /***********************************************************************
1501 * WritePrivateProfileStruct16 (KERNEL.406)
1503 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1504 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1506 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1509 /***********************************************************************
1510 * WritePrivateProfileStruct32A (KERNEL32.744)
1512 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1513 LPVOID buf, UINT bufsize, LPCSTR filename)
1515 BOOL ret = FALSE;
1517 if (!section && !key && !buf) /* flush the cache */
1518 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1520 EnterCriticalSection( &PROFILE_CritSect );
1522 if (PROFILE_Open( filename ))
1523 ret = PROFILE_SetString( section, key, buf );
1525 LeaveCriticalSection( &PROFILE_CritSect );
1527 return ret;
1530 /***********************************************************************
1531 * WritePrivateProfileStruct32W (KERNEL32.544)
1533 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1534 LPVOID buf, UINT bufsize, LPCWSTR filename)
1536 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1537 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1538 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1539 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1540 filenameA );
1541 HeapFree( GetProcessHeap(), 0, sectionA );
1542 HeapFree( GetProcessHeap(), 0, keyA );
1543 HeapFree( GetProcessHeap(), 0, filenameA );
1545 return ret;
1549 /***********************************************************************
1550 * WriteOutProfiles (KERNEL.315)
1552 void WINAPI WriteOutProfiles16(void)
1554 EnterCriticalSection( &PROFILE_CritSect );
1555 PROFILE_FlushFile();
1556 LeaveCriticalSection( &PROFILE_CritSect );