4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
16 #include "wine/winbase16.h"
21 #include "debugtools.h"
24 DEFAULT_DEBUG_CHANNEL(profile)
26 typedef struct tagPROFILEKEY
30 struct tagPROFILEKEY *next;
33 typedef struct tagPROFILESECTION
36 struct tagPROFILEKEY *key;
37 struct tagPROFILESECTION *next;
44 PROFILESECTION *section;
52 #define N_CACHED_PROFILES 10
54 /* Cached profile files */
55 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
57 #define CurProfile (MRUProfile[0])
59 /* wine.ini profile content */
60 static PROFILESECTION *PROFILE_WineProfile;
62 #define PROFILE_MAX_LINE_LEN 1024
64 /* Wine profile name in $HOME directory; must begin with slash */
65 static const char PROFILE_WineIniName[] = "/.winerc";
67 /* Wine profile: the profile file being used */
68 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
70 /* Check for comments in profile */
71 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
73 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
75 static LPCWSTR wininiW = NULL;
77 static CRITICAL_SECTION PROFILE_CritSect;
79 /***********************************************************************
82 * Copy the content of an entry into a buffer, removing quotes, and possibly
83 * translating environment variables.
85 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
91 if ((*value == '\'') || (*value == '\"'))
93 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
98 lstrcpynA( buffer, value, len );
99 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
103 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
105 if ((*p == '$') && (p[1] == '{'))
109 const char *p2 = strchr( p, '}' );
110 if (!p2) continue; /* ignore it */
111 lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
112 if ((env_p = getenv( env_val )) != NULL)
114 lstrcpynA( buffer, env_p, len );
115 buffer += strlen( buffer );
116 len -= strlen( buffer );
121 if (quote && (len > 1)) buffer--;
126 /***********************************************************************
129 * Save a profile tree to a file.
131 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
135 for ( ; section; section = section->next)
137 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
138 for (key = section->key; key; key = key->next)
140 fprintf( file, "%s", key->name );
141 if (key->value) fprintf( file, "=%s", key->value );
142 fprintf( file, "\r\n" );
148 /***********************************************************************
151 * Free a profile tree.
153 static void PROFILE_Free( PROFILESECTION *section )
155 PROFILESECTION *next_section;
156 PROFILEKEY *key, *next_key;
158 for ( ; section; section = next_section)
160 if (section->name) HeapFree( SystemHeap, 0, section->name );
161 for (key = section->key; key; key = next_key)
163 next_key = key->next;
164 if (key->name) HeapFree( SystemHeap, 0, key->name );
165 if (key->value) HeapFree( SystemHeap, 0, key->value );
166 HeapFree( SystemHeap, 0, key );
168 next_section = section->next;
169 HeapFree( SystemHeap, 0, section );
174 PROFILE_isspace(char c) {
175 if (isspace(c)) return 1;
176 if (c=='\r' || c==0x1a) return 1;
177 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
182 /***********************************************************************
185 * Load a profile tree from a file.
187 static PROFILESECTION *PROFILE_Load( FILE *file )
189 char buffer[PROFILE_MAX_LINE_LEN];
192 PROFILESECTION *section, *first_section;
193 PROFILESECTION **next_section;
194 PROFILEKEY *key, *prev_key, **next_key;
196 first_section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
197 first_section->name = NULL;
198 first_section->key = NULL;
199 first_section->next = NULL;
200 next_section = &first_section->next;
201 next_key = &first_section->key;
204 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
208 while (*p && PROFILE_isspace(*p)) p++;
209 if (*p == '[') /* section start */
211 if (!(p2 = strrchr( p, ']' )))
213 WARN("Invalid section header at line %d: '%s'\n",
220 section = HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
221 section->name = HEAP_strdupA( SystemHeap, 0, p );
223 section->next = NULL;
224 *next_section = section;
225 next_section = §ion->next;
226 next_key = §ion->key;
229 TRACE("New section: '%s'\n",section->name);
236 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
238 if ((p2 = strchr( p, '=' )) != NULL)
241 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
243 while (*p2 && PROFILE_isspace(*p2)) p2++;
246 if(*p || !prev_key || *prev_key->name)
248 key = HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
249 key->name = HEAP_strdupA( SystemHeap, 0, p );
250 key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
253 next_key = &key->next;
256 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
259 return first_section;
263 /***********************************************************************
264 * PROFILE_DeleteSection
266 * Delete a section from a profile tree.
268 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
272 if ((*section)->name && !strcasecmp( (*section)->name, name ))
274 PROFILESECTION *to_del = *section;
275 *section = to_del->next;
277 PROFILE_Free( to_del );
280 section = &(*section)->next;
286 /***********************************************************************
289 * Delete a key from a profile tree.
291 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
292 LPCSTR section_name, LPCSTR key_name )
296 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
298 PROFILEKEY **key = &(*section)->key;
301 if (!strcasecmp( (*key)->name, key_name ))
303 PROFILEKEY *to_del = *key;
305 if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
306 if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
307 HeapFree( SystemHeap, 0, to_del );
313 section = &(*section)->next;
319 /***********************************************************************
322 * Find a key in a profile tree, optionally creating it.
324 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
325 const char *section_name,
326 const char *key_name, int create )
330 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
332 PROFILEKEY **key = &(*section)->key;
335 if (!strcasecmp( (*key)->name, key_name )) return *key;
338 if (!create) return NULL;
339 *key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
340 (*key)->name = HEAP_strdupA( SystemHeap, 0, key_name );
341 (*key)->value = NULL;
345 section = &(*section)->next;
347 if (!create) return NULL;
348 *section = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
349 (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
350 (*section)->next = NULL;
351 (*section)->key = HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
352 (*section)->key->name = HEAP_strdupA( SystemHeap, 0, key_name );
353 (*section)->key->value = NULL;
354 (*section)->key->next = NULL;
355 return (*section)->key;
359 /***********************************************************************
362 * Flush the current profile to disk if changed.
364 static BOOL PROFILE_FlushFile(void)
366 char *p, buffer[MAX_PATHNAME_LEN];
367 const char *unix_name;
373 WARN("No current profile!\n");
377 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
378 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
380 /* Try to create it in $HOME/.wine */
381 /* FIXME: this will need a more general solution */
382 if ((p = getenv( "HOME" )) != NULL)
385 strcat( buffer, "/.wine/" );
386 p = buffer + strlen(buffer);
387 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
389 file = fopen( buffer, "w" );
396 WARN("could not save profile file %s\n", CurProfile->dos_name);
400 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
401 PROFILE_Save( file, CurProfile->section );
403 CurProfile->changed = FALSE;
404 if(!stat(unix_name,&buf))
405 CurProfile->mtime=buf.st_mtime;
410 /***********************************************************************
411 * PROFILE_ReleaseFile
413 * Flush the current profile to disk and remove it from the cache.
415 static void PROFILE_ReleaseFile(void)
418 PROFILE_Free( CurProfile->section );
419 if (CurProfile->dos_name) HeapFree( SystemHeap, 0, CurProfile->dos_name );
420 if (CurProfile->unix_name) HeapFree( SystemHeap, 0, CurProfile->unix_name );
421 if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
422 CurProfile->changed = FALSE;
423 CurProfile->section = NULL;
424 CurProfile->dos_name = NULL;
425 CurProfile->unix_name = NULL;
426 CurProfile->filename = NULL;
427 CurProfile->mtime = 0;
431 /***********************************************************************
434 * Open a profile file, checking the cached file first.
436 static BOOL PROFILE_Open( LPCSTR filename )
438 DOS_FULL_NAME full_name;
439 char buffer[MAX_PATHNAME_LEN];
440 char *newdos_name, *p;
444 PROFILE *tempProfile;
446 /* First time around */
449 for(i=0;i<N_CACHED_PROFILES;i++)
451 MRUProfile[i]=HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
452 MRUProfile[i]->changed=FALSE;
453 MRUProfile[i]->section=NULL;
454 MRUProfile[i]->dos_name=NULL;
455 MRUProfile[i]->unix_name=NULL;
456 MRUProfile[i]->filename=NULL;
457 MRUProfile[i]->mtime=0;
460 /* Check for a match */
462 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
463 strchr( filename, ':' ))
465 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
469 GetWindowsDirectoryA( buffer, sizeof(buffer) );
470 strcat( buffer, "\\" );
471 strcat( buffer, filename );
472 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
475 for(i=0;i<N_CACHED_PROFILES;i++)
477 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
478 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
483 tempProfile=MRUProfile[i];
485 MRUProfile[j]=MRUProfile[j-1];
486 CurProfile=tempProfile;
488 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
489 TRACE("(%s): already opened (mru=%d)\n",
492 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
498 /* Flush the old current profile */
501 /* Make the oldest profile the current one only in order to get rid of it */
502 if(i==N_CACHED_PROFILES)
504 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
505 for(i=N_CACHED_PROFILES-1;i>0;i--)
506 MRUProfile[i]=MRUProfile[i-1];
507 CurProfile=tempProfile;
509 if(CurProfile->filename) PROFILE_ReleaseFile();
511 /* OK, now that CurProfile is definitely free we assign it our new file */
512 newdos_name = HEAP_strdupA( SystemHeap, 0, full_name.short_name );
513 CurProfile->dos_name = newdos_name;
514 CurProfile->filename = HEAP_strdupA( SystemHeap, 0, filename );
516 /* Try to open the profile file, first in $HOME/.wine */
518 /* FIXME: this will need a more general solution */
519 if ((p = getenv( "HOME" )) != NULL)
522 strcat( buffer, "/.wine/" );
523 p = buffer + strlen(buffer);
524 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
526 if ((file = fopen( buffer, "r" )))
528 TRACE("(%s): found it in %s\n",
530 CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0, buffer );
536 CurProfile->unix_name = HEAP_strdupA( SystemHeap, 0,
537 full_name.long_name );
538 if ((file = fopen( full_name.long_name, "r" )))
539 TRACE("(%s): found it in %s\n",
540 filename, full_name.long_name );
545 CurProfile->section = PROFILE_Load( file );
547 if(!stat(CurProfile->unix_name,&buf))
548 CurProfile->mtime=buf.st_mtime;
552 /* Does not exist yet, we will create it in PROFILE_FlushFile */
553 WARN("profile file %s not found\n", newdos_name );
559 /***********************************************************************
562 * Returns all keys of a section.
563 * If return_values is TRUE, also include the corresponding values.
565 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
566 LPSTR buffer, UINT len, BOOL handle_env,
572 if (section->name && !strcasecmp( section->name, section_name ))
575 for (key = section->key; key; key = key->next)
578 if (!*key->name) continue; /* Skip empty lines */
579 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
580 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
581 len -= strlen(buffer) + 1;
582 buffer += strlen(buffer) + 1;
583 if (return_values && key->value) {
585 PROFILE_CopyEntry ( buffer,
586 key->value, len - 1, handle_env );
587 len -= strlen(buffer) + 1;
588 buffer += strlen(buffer) + 1;
593 /*If either lpszSection or lpszKey is NULL and the supplied
594 destination buffer is too small to hold all the strings,
595 the last string is truncated and followed by two null characters.
596 In this case, the return value is equal to cchReturnBuffer
604 section = section->next;
606 buffer[0] = buffer[1] = '\0';
611 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
615 PROFILESECTION *section;
617 for (section = CurProfile->section; section; section = section->next)
619 l = strlen(section->name);
624 strcpy(buf, section->name);
634 /***********************************************************************
637 * Get a profile string.
639 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
640 LPCSTR def_val, LPSTR buffer, UINT len )
642 PROFILEKEY *key = NULL;
644 if (!def_val) def_val = "";
645 if (key_name && key_name[0])
647 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
648 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
650 TRACE("('%s','%s','%s'): returning '%s'\n",
651 section, key_name, def_val, buffer );
652 return strlen( buffer );
654 if (section && section[0])
655 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
657 /* undocumented; both section and key_name are NULL */
658 return PROFILE_GetSectionNames(buffer, len);
662 /***********************************************************************
665 * Set a profile string.
667 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
670 if (!key_name) /* Delete a whole section */
672 TRACE("('%s')\n", section_name);
673 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
675 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
676 this is not an error on application's level.*/
678 else if (!value) /* Delete a key */
680 TRACE("('%s','%s')\n",
681 section_name, key_name );
682 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
683 section_name, key_name );
684 return TRUE; /* same error handling as above */
686 else /* Set the key value */
688 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
690 TRACE("('%s','%s','%s'): \n",
691 section_name, key_name, value );
692 if (!key) return FALSE;
695 if (!strcmp( key->value, value ))
697 TRACE(" no change needed\n" );
698 return TRUE; /* No change needed */
700 TRACE(" replacing '%s'\n", key->value );
701 HeapFree( SystemHeap, 0, key->value );
703 else TRACE(" creating key\n" );
704 key->value = HEAP_strdupA( SystemHeap, 0, value );
705 CurProfile->changed = TRUE;
711 /***********************************************************************
712 * PROFILE_GetWineIniString
714 * Get a config string from the wine.ini file.
716 int PROFILE_GetWineIniString( const char *section, const char *key_name,
717 const char *def, char *buffer, int len )
721 EnterCriticalSection( &PROFILE_CritSect );
725 PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
726 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
728 TRACE("('%s','%s','%s'): returning '%s'\n",
729 section, key_name, def, buffer );
730 ret = strlen( buffer );
734 ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
736 LeaveCriticalSection( &PROFILE_CritSect );
742 /***********************************************************************
743 * PROFILE_GetWineIniInt
745 * Get a config integer from the wine.ini file.
747 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
755 EnterCriticalSection( &PROFILE_CritSect );
757 key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
758 if (!key || !key->value) {
761 PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
762 result = strtol( buffer, &p, 0 );
763 ret = (p == buffer) ? 0 /* No digits at all */ : (int)result;
766 LeaveCriticalSection( &PROFILE_CritSect );
772 /******************************************************************************
774 * int PROFILE_EnumerateWineIniSection(
775 * char const *section, #Name of the section to enumerate
776 * void (*cbfn)(char const *key, char const *value, void *user),
777 * # Address of the callback function
778 * void *user ) # User-specified pointer.
780 * For each entry in a section in the wine.conf file, this function will
781 * call the specified callback function, informing it of each key and
782 * value. An optional user pointer may be passed to it (if this is not
783 * needed, pass NULL through it and ignore the value in the callback
786 * The callback function must accept three parameters:
787 * The name of the key (char const *)
788 * The value of the key (char const *)
789 * A user-specified parameter (void *)
790 * Note that the first two are char CONST *'s, not char *'s! The callback
791 * MUST not modify these strings!
793 * The return value indicates the number of times the callback function
796 int PROFILE_EnumerateWineIniSection(
798 void (*cbfn)(char const *, char const *, void *),
801 PROFILESECTION *scansect;
805 EnterCriticalSection( &PROFILE_CritSect );
807 /* Search for the correct section */
808 for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
809 if(scansect->name && !strcasecmp(scansect->name, section)) {
811 /* Enumerate each key with the callback */
812 for(scankey = scansect->key; scankey; scankey = scankey->next) {
814 /* Ignore blank entries -- these shouldn't exist, but let's
816 if (!scankey->name[0]) continue;
817 if (!scankey->value) cbfn(scankey->name, NULL, userptr);
821 PROFILE_CopyEntry(value, scankey->value, sizeof(value), TRUE);
822 cbfn(scankey->name, value, userptr);
830 LeaveCriticalSection( &PROFILE_CritSect );
836 /******************************************************************************
838 * int PROFILE_GetWineIniBool(
839 * char const *section,
840 * char const *key_name,
843 * Reads a boolean value from the wine.ini file. This function attempts to
844 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
845 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
846 * true. Anything else results in the return of the default value.
848 * This function uses 1 to indicate true, and 0 for false. You can check
849 * for existence by setting def to something other than 0 or 1 and
850 * examining the return value.
852 int PROFILE_GetWineIniBool(
854 char const *key_name,
860 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
862 switch(key_value[0]) {
883 TRACE("(\"%s\", \"%s\", %s), "
884 "[%c], ret %s.\n", section, key_name,
885 def ? "TRUE" : "FALSE", key_value[0],
886 retval ? "TRUE" : "FALSE");
892 /***********************************************************************
893 * PROFILE_LoadWineIni
895 * Load the wine.ini file.
897 int PROFILE_LoadWineIni(void)
899 char buffer[MAX_PATHNAME_LEN];
903 InitializeCriticalSection( &PROFILE_CritSect );
904 MakeCriticalSectionGlobal( &PROFILE_CritSect );
906 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
908 /* Open -config specified file */
909 PROFILE_WineProfile = PROFILE_Load ( f);
911 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
915 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
917 PROFILE_WineProfile = PROFILE_Load( f );
919 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
922 if ((p = getenv( "HOME" )) != NULL)
924 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
925 strcat( buffer, PROFILE_WineIniName );
926 if ((f = fopen( buffer, "r" )) != NULL)
928 PROFILE_WineProfile = PROFILE_Load( f );
930 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
934 else WARN("could not get $HOME value for config file.\n" );
936 /* Try global file */
938 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
940 PROFILE_WineProfile = PROFILE_Load( f );
942 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
945 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
946 WINE_INI_GLOBAL, PROFILE_WineIniName );
951 /***********************************************************************
952 * PROFILE_UsageWineIni
954 * Explain the wine.ini file to those who don't read documentation.
955 * Keep below one screenful in length so that error messages above are
958 void PROFILE_UsageWineIni(void)
960 MESSAGE("Perhaps you have not properly edited or created "
961 "your Wine configuration file.\n");
962 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
963 MESSAGE(" or it is determined by the -config option or from\n"
964 " the WINE_INI environment variable.\n");
965 if (*PROFILE_WineIniUsed)
966 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
967 /* RTFM, so to say */
970 /***********************************************************************
971 * PROFILE_GetStringItem
973 * Convenience function that turns a string 'xxx, yyy, zzz' into
974 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
976 char* PROFILE_GetStringItem( char* start )
980 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
984 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
986 if( !PROFILE_isspace(*lpchX) ) return lpchX;
988 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
991 if( lpch ) *lpch = '\0';
995 /********************* API functions **********************************/
997 /***********************************************************************
998 * GetProfileInt16 (KERNEL.57)
1000 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1002 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1006 /***********************************************************************
1007 * GetProfileInt32A (KERNEL32.264)
1009 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1011 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1014 /***********************************************************************
1015 * GetProfileInt32W (KERNEL32.264)
1017 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1019 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1020 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1023 /***********************************************************************
1024 * GetProfileString16 (KERNEL.58)
1026 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1027 LPSTR buffer, UINT16 len )
1029 return GetPrivateProfileString16( section, entry, def_val,
1030 buffer, len, "win.ini" );
1033 /***********************************************************************
1034 * GetProfileString32A (KERNEL32.268)
1036 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1037 LPSTR buffer, UINT len )
1039 return GetPrivateProfileStringA( section, entry, def_val,
1040 buffer, len, "win.ini" );
1043 /***********************************************************************
1044 * GetProfileString32W (KERNEL32.269)
1046 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1047 LPCWSTR def_val, LPWSTR buffer, UINT len )
1049 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1050 return GetPrivateProfileStringW( section, entry, def_val,
1051 buffer, len, wininiW );
1054 /***********************************************************************
1055 * WriteProfileString16 (KERNEL.59)
1057 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1060 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1063 /***********************************************************************
1064 * WriteProfileString32A (KERNEL32.587)
1066 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1069 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1072 /***********************************************************************
1073 * WriteProfileString32W (KERNEL32.588)
1075 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1078 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1079 return WritePrivateProfileStringW( section, entry, string, wininiW );
1083 /***********************************************************************
1084 * GetPrivateProfileInt16 (KERNEL.127)
1086 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1087 INT16 def_val, LPCSTR filename )
1089 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1091 if (result > 65535) return 65535;
1092 if (result >= 0) return (UINT16)result;
1093 if (result < -32768) return -32768;
1094 return (UINT16)(INT16)result;
1097 /***********************************************************************
1098 * GetPrivateProfileInt32A (KERNEL32.251)
1100 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1101 INT def_val, LPCSTR filename )
1107 GetPrivateProfileStringA( section, entry, "",
1108 buffer, sizeof(buffer), filename );
1109 if (!buffer[0]) return (UINT)def_val;
1110 result = strtol( buffer, &p, 0 );
1111 if (p == buffer) return 0; /* No digits at all */
1112 return (UINT)result;
1115 /***********************************************************************
1116 * GetPrivateProfileInt32W (KERNEL32.252)
1118 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1119 INT def_val, LPCWSTR filename )
1121 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1122 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1123 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1124 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1125 HeapFree( GetProcessHeap(), 0, sectionA );
1126 HeapFree( GetProcessHeap(), 0, filenameA );
1127 HeapFree( GetProcessHeap(), 0, entryA );
1131 /***********************************************************************
1132 * GetPrivateProfileString16 (KERNEL.128)
1134 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1135 LPCSTR def_val, LPSTR buffer,
1136 UINT16 len, LPCSTR filename )
1138 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1141 /***********************************************************************
1142 * GetPrivateProfileString32A (KERNEL32.255)
1144 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1145 LPCSTR def_val, LPSTR buffer,
1146 UINT len, LPCSTR filename )
1151 filename = "win.ini";
1153 EnterCriticalSection( &PROFILE_CritSect );
1155 if (PROFILE_Open( filename )) {
1156 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1158 lstrcpynA( buffer, def_val, len );
1159 ret = strlen( buffer );
1162 LeaveCriticalSection( &PROFILE_CritSect );
1167 /***********************************************************************
1168 * GetPrivateProfileString32W (KERNEL32.256)
1170 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1171 LPCWSTR def_val, LPWSTR buffer,
1172 UINT len, LPCWSTR filename )
1174 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1175 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1176 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1177 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1178 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1179 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1180 bufferA, len, filenameA );
1181 lstrcpynAtoW( buffer, bufferA, len );
1182 HeapFree( GetProcessHeap(), 0, sectionA );
1183 HeapFree( GetProcessHeap(), 0, entryA );
1184 HeapFree( GetProcessHeap(), 0, filenameA );
1185 HeapFree( GetProcessHeap(), 0, def_valA );
1186 HeapFree( GetProcessHeap(), 0, bufferA);
1190 /***********************************************************************
1191 * GetPrivateProfileSection16 (KERNEL.418)
1193 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1194 UINT16 len, LPCSTR filename )
1196 return GetPrivateProfileSectionA( section, buffer, len, filename );
1199 /***********************************************************************
1200 * GetPrivateProfileSection32A (KERNEL32.255)
1202 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1203 DWORD len, LPCSTR filename )
1207 EnterCriticalSection( &PROFILE_CritSect );
1209 if (PROFILE_Open( filename ))
1210 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1213 LeaveCriticalSection( &PROFILE_CritSect );
1218 /***********************************************************************
1219 * GetPrivateProfileSection32W (KERNEL32.256)
1222 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1223 DWORD len, LPCWSTR filename )
1226 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1227 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1228 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1229 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1231 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1232 HeapFree( GetProcessHeap(), 0, sectionA );
1233 HeapFree( GetProcessHeap(), 0, filenameA );
1234 HeapFree( GetProcessHeap(), 0, bufferA);
1238 /***********************************************************************
1239 * GetProfileSection16 (KERNEL.419)
1241 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1243 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1246 /***********************************************************************
1247 * GetProfileSection32A (KERNEL32.268)
1249 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1251 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1254 /***********************************************************************
1255 * GetProfileSection32W (KERNEL32)
1257 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1259 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1260 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1264 /***********************************************************************
1265 * WritePrivateProfileString16 (KERNEL.129)
1267 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1268 LPCSTR string, LPCSTR filename )
1270 return WritePrivateProfileStringA(section,entry,string,filename);
1273 /***********************************************************************
1274 * WritePrivateProfileString32A (KERNEL32.582)
1276 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1277 LPCSTR string, LPCSTR filename )
1281 EnterCriticalSection( &PROFILE_CritSect );
1283 if (PROFILE_Open( filename ))
1285 if (!section && !entry && !string)
1286 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1288 ret = PROFILE_SetString( section, entry, string );
1291 LeaveCriticalSection( &PROFILE_CritSect );
1295 /***********************************************************************
1296 * WritePrivateProfileString32W (KERNEL32.583)
1298 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1299 LPCWSTR string, LPCWSTR filename )
1301 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1302 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1303 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1304 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1305 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1306 stringA, filenameA );
1307 HeapFree( GetProcessHeap(), 0, sectionA );
1308 HeapFree( GetProcessHeap(), 0, entryA );
1309 HeapFree( GetProcessHeap(), 0, stringA );
1310 HeapFree( GetProcessHeap(), 0, filenameA );
1314 /***********************************************************************
1315 * WritePrivateProfileSection16 (KERNEL.416)
1317 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1318 LPCSTR string, LPCSTR filename )
1320 return WritePrivateProfileSectionA( section, string, filename );
1323 /***********************************************************************
1324 * WritePrivateProfileSection32A (KERNEL32)
1326 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1327 LPCSTR string, LPCSTR filename )
1329 char *p =(char*)string;
1331 FIXME("WritePrivateProfileSection32A empty stub\n");
1332 if (TRACE_ON(profile)) {
1333 TRACE("(%s) => [%s]\n", filename, section);
1344 /***********************************************************************
1345 * WritePrivateProfileSection32W (KERNEL32)
1347 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1348 LPCWSTR string, LPCWSTR filename)
1351 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1352 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1353 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1354 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1355 HeapFree( GetProcessHeap(), 0, sectionA );
1356 HeapFree( GetProcessHeap(), 0, stringA );
1357 HeapFree( GetProcessHeap(), 0, filenameA );
1361 /***********************************************************************
1362 * WriteProfileSection16 (KERNEL.417)
1364 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1366 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1369 /***********************************************************************
1370 * WriteProfileSection32A (KERNEL32.747)
1372 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1375 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1378 /***********************************************************************
1379 * WriteProfileSection32W (KERNEL32.748)
1381 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1383 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini");
1385 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1388 /***********************************************************************
1389 * GetPrivateProfileSectionNames16 (KERNEL.143)
1391 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1396 EnterCriticalSection( &PROFILE_CritSect );
1398 if (PROFILE_Open( filename ))
1399 ret = PROFILE_GetSectionNames(buffer, size);
1401 LeaveCriticalSection( &PROFILE_CritSect );
1407 /***********************************************************************
1408 * GetProfileSectionNames16 (KERNEL.142)
1410 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1413 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1417 /***********************************************************************
1418 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1420 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1424 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1428 /***********************************************************************
1429 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1431 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1435 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1436 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1438 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1439 lstrcpynAtoW( buffer, bufferA, size);
1440 HeapFree( GetProcessHeap(), 0, bufferA);
1441 HeapFree( GetProcessHeap(), 0, filenameA );
1446 /***********************************************************************
1447 * GetPrivateProfileStruct16 (KERNEL.407)
1449 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1450 LPVOID buf, UINT16 len, LPCSTR filename)
1452 return GetPrivateProfileStructA( section, key, buf, len, filename );
1455 /***********************************************************************
1456 * GetPrivateProfileStruct32A (KERNEL32.370)
1458 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1459 LPVOID buf, UINT len, LPCSTR filename)
1463 EnterCriticalSection( &PROFILE_CritSect );
1465 if (PROFILE_Open( filename )) {
1466 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1468 lstrcpynA( buf, k->value, strlen(k->value));
1472 LeaveCriticalSection( &PROFILE_CritSect );
1477 /***********************************************************************
1478 * GetPrivateProfileStruct32W (KERNEL32.543)
1480 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1481 LPVOID buffer, UINT len, LPCWSTR filename)
1483 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1484 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1485 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1486 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1488 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1490 lstrcpynAtoW( buffer, bufferA, len );
1491 HeapFree( GetProcessHeap(), 0, bufferA);
1492 HeapFree( GetProcessHeap(), 0, sectionA );
1493 HeapFree( GetProcessHeap(), 0, keyA );
1494 HeapFree( GetProcessHeap(), 0, filenameA );
1501 /***********************************************************************
1502 * WritePrivateProfileStruct16 (KERNEL.406)
1504 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1505 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1507 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1510 /***********************************************************************
1511 * WritePrivateProfileStruct32A (KERNEL32.744)
1513 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1514 LPVOID buf, UINT bufsize, LPCSTR filename)
1518 if (!section && !key && !buf) /* flush the cache */
1519 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1521 EnterCriticalSection( &PROFILE_CritSect );
1523 if (PROFILE_Open( filename ))
1524 ret = PROFILE_SetString( section, key, buf );
1526 LeaveCriticalSection( &PROFILE_CritSect );
1531 /***********************************************************************
1532 * WritePrivateProfileStruct32W (KERNEL32.544)
1534 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1535 LPVOID buf, UINT bufsize, LPCWSTR filename)
1537 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1538 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1539 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1540 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1542 HeapFree( GetProcessHeap(), 0, sectionA );
1543 HeapFree( GetProcessHeap(), 0, keyA );
1544 HeapFree( GetProcessHeap(), 0, filenameA );
1550 /***********************************************************************
1551 * WriteOutProfiles (KERNEL.315)
1553 void WINAPI WriteOutProfiles16(void)
1555 EnterCriticalSection( &PROFILE_CritSect );
1556 PROFILE_FlushFile();
1557 LeaveCriticalSection( &PROFILE_CritSect );
1560 /***********************************************************************
1561 * CloseProfileUserMapping (KERNEL.138)
1563 BOOL WINAPI CloseProfileUserMapping(void) {
1564 FIXME("(), stub!\n");
1565 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);