4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <sys/types.h>
41 #include "wine/winbase16.h"
45 #include "wine/server.h"
46 #include "wine/library.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(profile
);
51 typedef struct tagPROFILEKEY
54 struct tagPROFILEKEY
*next
;
58 typedef struct tagPROFILESECTION
60 struct tagPROFILEKEY
*key
;
61 struct tagPROFILESECTION
*next
;
69 PROFILESECTION
*section
;
77 #define N_CACHED_PROFILES 10
79 /* Cached profile files */
80 static PROFILE
*MRUProfile
[N_CACHED_PROFILES
]={NULL
};
82 #define CurProfile (MRUProfile[0])
84 /* wine.ini config file registry root */
85 static HKEY wine_profile_key
;
87 #define PROFILE_MAX_LINE_LEN 1024
89 /* Wine profile name in $HOME directory; must begin with slash */
90 static const char PROFILE_WineIniName
[] = "/.winerc";
92 /* Wine profile: the profile file being used */
93 static char PROFILE_WineIniUsed
[MAX_PATHNAME_LEN
] = "";
95 /* Check for comments in profile */
96 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
98 static const WCHAR wininiW
[] = { 'w','i','n','.','i','n','i',0 };
100 static CRITICAL_SECTION PROFILE_CritSect
= CRITICAL_SECTION_INIT("PROFILE_CritSect");
102 static const char hex
[16] = "0123456789ABCDEF";
104 /***********************************************************************
107 * Copy the content of an entry into a buffer, removing quotes, and possibly
108 * translating environment variables.
110 static void PROFILE_CopyEntry( char *buffer
, const char *value
, int len
,
118 if ((*value
== '\'') || (*value
== '\"'))
120 if (value
[1] && (value
[strlen(value
)-1] == *value
)) quote
= *value
++;
125 lstrcpynA( buffer
, value
, len
);
126 if (quote
&& (len
>= strlen(value
))) buffer
[strlen(buffer
)-1] = '\0';
130 for (p
= value
; (*p
&& (len
> 1)); *buffer
++ = *p
++, len
-- )
132 if ((*p
== '$') && (p
[1] == '{'))
136 const char *p2
= strchr( p
, '}' );
137 if (!p2
) continue; /* ignore it */
138 lstrcpynA(env_val
, p
+ 2, min( sizeof(env_val
), (int)(p2
-p
)-1 ));
139 if ((env_p
= getenv( env_val
)) != NULL
)
142 lstrcpynA( buffer
, env_p
, len
);
143 buffer_len
= strlen( buffer
);
144 buffer
+= buffer_len
;
150 if (quote
&& (len
> 1)) buffer
--;
155 /***********************************************************************
158 * Save a profile tree to a file.
160 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
164 for ( ; section
; section
= section
->next
)
166 if (section
->name
[0]) fprintf( file
, "\r\n[%s]\r\n", section
->name
);
167 for (key
= section
->key
; key
; key
= key
->next
)
169 fprintf( file
, "%s", key
->name
);
170 if (key
->value
) fprintf( file
, "=%s", key
->value
);
171 fprintf( file
, "\r\n" );
177 /***********************************************************************
180 * Free a profile tree.
182 static void PROFILE_Free( PROFILESECTION
*section
)
184 PROFILESECTION
*next_section
;
185 PROFILEKEY
*key
, *next_key
;
187 for ( ; section
; section
= next_section
)
189 for (key
= section
->key
; key
; key
= next_key
)
191 next_key
= key
->next
;
192 if (key
->value
) HeapFree( GetProcessHeap(), 0, key
->value
);
193 HeapFree( GetProcessHeap(), 0, key
);
195 next_section
= section
->next
;
196 HeapFree( GetProcessHeap(), 0, section
);
200 static inline int PROFILE_isspace(char c
)
202 if (isspace(c
)) return 1;
203 if (c
=='\r' || c
==0x1a) return 1;
204 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
209 /***********************************************************************
212 * Load a profile tree from a file.
214 static PROFILESECTION
*PROFILE_Load( FILE *file
)
216 char buffer
[PROFILE_MAX_LINE_LEN
];
219 PROFILESECTION
*section
, *first_section
;
220 PROFILESECTION
**next_section
;
221 PROFILEKEY
*key
, *prev_key
, **next_key
;
223 first_section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
224 if(first_section
== NULL
) return NULL
;
225 first_section
->name
[0] = 0;
226 first_section
->key
= NULL
;
227 first_section
->next
= NULL
;
228 next_section
= &first_section
->next
;
229 next_key
= &first_section
->key
;
232 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
236 while (*p
&& PROFILE_isspace(*p
)) p
++;
237 if (*p
== '[') /* section start */
239 if (!(p2
= strrchr( p
, ']' )))
241 WARN("Invalid section header at line %d: '%s'\n",
248 if (!(section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) + strlen(p
) )))
250 strcpy( section
->name
, p
);
252 section
->next
= NULL
;
253 *next_section
= section
;
254 next_section
= §ion
->next
;
255 next_key
= §ion
->key
;
258 TRACE("New section: '%s'\n",section
->name
);
265 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
267 if ((p2
= strchr( p
, '=' )) != NULL
)
270 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
272 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
275 if(*p
|| !prev_key
|| *prev_key
->name
)
277 if (!(key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) + strlen(p
) ))) break;
278 strcpy( key
->name
, p
);
281 key
->value
= HeapAlloc( GetProcessHeap(), 0, strlen(p2
)+1 );
282 strcpy( key
->value
, p2
);
284 else key
->value
= NULL
;
288 next_key
= &key
->next
;
291 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
294 return first_section
;
297 /* convert the .winerc file to the new format */
298 static void convert_config( FILE *in
, const char *output_name
)
300 char buffer
[PROFILE_MAX_LINE_LEN
];
304 /* create the output file, only if it doesn't exist already */
305 int fd
= open( output_name
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666 );
308 MESSAGE( "Could not create new config file '%s': %s\n", output_name
, strerror(errno
) );
312 out
= fdopen( fd
, "w" );
313 fprintf( out
, "WINE REGISTRY Version 2\n" );
314 fprintf( out
, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
315 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, in
))
317 if (buffer
[strlen(buffer
)-1] == '\n') buffer
[strlen(buffer
)-1] = 0;
319 while (*p
&& PROFILE_isspace(*p
)) p
++;
320 if (*p
== '[') /* section start */
322 if ((p2
= strrchr( p
, ']' )))
326 fprintf( out
, "[%s]\n", p
);
331 if (*p
== ';' || *p
== '#')
333 fprintf( out
, "%s\n", p
);
338 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
340 if ((p2
= strchr( p
, '=' )) != NULL
)
343 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
345 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
350 fprintf( out
, "\n" );
356 if (*p
== '\\') fputc( '\\', out
);
360 fprintf( out
, "\" = \"" );
365 if (*p2
== '\\') fputc( '\\', out
);
370 fprintf( out
, "\"\n" );
376 /***********************************************************************
377 * PROFILE_DeleteSection
379 * Delete a section from a profile tree.
381 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
385 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, name
))
387 PROFILESECTION
*to_del
= *section
;
388 *section
= to_del
->next
;
390 PROFILE_Free( to_del
);
393 section
= &(*section
)->next
;
399 /***********************************************************************
402 * Delete a key from a profile tree.
404 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
405 LPCSTR section_name
, LPCSTR key_name
)
409 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, section_name
))
411 PROFILEKEY
**key
= &(*section
)->key
;
414 if (!strcasecmp( (*key
)->name
, key_name
))
416 PROFILEKEY
*to_del
= *key
;
418 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
419 HeapFree( GetProcessHeap(), 0, to_del
);
425 section
= &(*section
)->next
;
431 /***********************************************************************
432 * PROFILE_DeleteAllKeys
434 * Delete all keys from a profile tree.
436 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
438 PROFILESECTION
**section
= &CurProfile
->section
;
441 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, section_name
))
443 PROFILEKEY
**key
= &(*section
)->key
;
446 PROFILEKEY
*to_del
= *key
;
448 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
449 HeapFree( GetProcessHeap(), 0, to_del
);
450 CurProfile
->changed
=TRUE
;
453 section
= &(*section
)->next
;
458 /***********************************************************************
461 * Find a key in a profile tree, optionally creating it.
463 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
, const char *section_name
,
464 const char *key_name
, BOOL create
, BOOL create_always
)
469 while (PROFILE_isspace(*section_name
)) section_name
++;
470 p
= section_name
+ strlen(section_name
) - 1;
471 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
472 seclen
= p
- section_name
+ 1;
474 while (PROFILE_isspace(*key_name
)) key_name
++;
475 p
= key_name
+ strlen(key_name
) - 1;
476 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
477 keylen
= p
- key_name
+ 1;
481 if ( ((*section
)->name
[0])
482 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
483 && (((*section
)->name
)[seclen
] == '\0') )
485 PROFILEKEY
**key
= &(*section
)->key
;
489 /* If create_always is FALSE then we check if the keyname already exists.
490 * Otherwise we add it regardless of its existence, to allow
491 * keys to be added more then once in some cases.
495 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
496 && (((*key
)->name
)[keylen
] == '\0') )
501 if (!create
) return NULL
;
502 if (!(*key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) + strlen(key_name
) )))
504 strcpy( (*key
)->name
, key_name
);
505 (*key
)->value
= NULL
;
509 section
= &(*section
)->next
;
511 if (!create
) return NULL
;
512 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) + strlen(section_name
) );
513 if(*section
== NULL
) return NULL
;
514 strcpy( (*section
)->name
, section_name
);
515 (*section
)->next
= NULL
;
516 if (!((*section
)->key
= HeapAlloc( GetProcessHeap(), 0,
517 sizeof(PROFILEKEY
) + strlen(key_name
) )))
519 HeapFree(GetProcessHeap(), 0, *section
);
522 strcpy( (*section
)->key
->name
, key_name
);
523 (*section
)->key
->value
= NULL
;
524 (*section
)->key
->next
= NULL
;
525 return (*section
)->key
;
529 /***********************************************************************
532 * Flush the current profile to disk if changed.
534 static BOOL
PROFILE_FlushFile(void)
536 char *p
, buffer
[MAX_PATHNAME_LEN
];
537 const char *unix_name
;
543 WARN("No current profile!\n");
547 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
548 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
550 /* Try to create it in $HOME/.wine */
551 /* FIXME: this will need a more general solution */
552 strcpy( buffer
, wine_get_config_dir() );
553 p
= buffer
+ strlen(buffer
);
555 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
557 file
= fopen( buffer
, "w" );
563 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
567 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
568 PROFILE_Save( file
, CurProfile
->section
);
570 CurProfile
->changed
= FALSE
;
571 if(!stat(unix_name
,&buf
))
572 CurProfile
->mtime
=buf
.st_mtime
;
577 /***********************************************************************
578 * PROFILE_ReleaseFile
580 * Flush the current profile to disk and remove it from the cache.
582 static void PROFILE_ReleaseFile(void)
585 PROFILE_Free( CurProfile
->section
);
586 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
587 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
588 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
589 CurProfile
->changed
= FALSE
;
590 CurProfile
->section
= NULL
;
591 CurProfile
->dos_name
= NULL
;
592 CurProfile
->unix_name
= NULL
;
593 CurProfile
->filename
= NULL
;
594 CurProfile
->mtime
= 0;
598 /***********************************************************************
601 * Open a profile file, checking the cached file first.
603 static BOOL
PROFILE_Open( LPCSTR filename
)
605 DOS_FULL_NAME full_name
;
606 char buffer
[MAX_PATHNAME_LEN
];
607 char *newdos_name
, *p
;
611 PROFILE
*tempProfile
;
613 /* First time around */
616 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
618 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
619 if(MRUProfile
[i
] == NULL
) break;
620 MRUProfile
[i
]->changed
=FALSE
;
621 MRUProfile
[i
]->section
=NULL
;
622 MRUProfile
[i
]->dos_name
=NULL
;
623 MRUProfile
[i
]->unix_name
=NULL
;
624 MRUProfile
[i
]->filename
=NULL
;
625 MRUProfile
[i
]->mtime
=0;
628 /* Check for a match */
630 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
631 strchr( filename
, ':' ))
633 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
637 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
638 strcat( buffer
, "\\" );
639 strcat( buffer
, filename
);
640 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
643 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
645 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
646 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
651 tempProfile
=MRUProfile
[i
];
653 MRUProfile
[j
]=MRUProfile
[j
-1];
654 CurProfile
=tempProfile
;
656 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
657 TRACE("(%s): already opened (mru=%d)\n",
660 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
666 /* Flush the old current profile */
669 /* Make the oldest profile the current one only in order to get rid of it */
670 if(i
==N_CACHED_PROFILES
)
672 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
673 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
674 MRUProfile
[i
]=MRUProfile
[i
-1];
675 CurProfile
=tempProfile
;
677 if(CurProfile
->filename
) PROFILE_ReleaseFile();
679 /* OK, now that CurProfile is definitely free we assign it our new file */
680 newdos_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.short_name
)+1 );
681 strcpy( newdos_name
, full_name
.short_name
);
682 CurProfile
->dos_name
= newdos_name
;
683 CurProfile
->filename
= HeapAlloc( GetProcessHeap(), 0, strlen(filename
)+1 );
684 strcpy( CurProfile
->filename
, filename
);
686 /* Try to open the profile file, first in $HOME/.wine */
688 /* FIXME: this will need a more general solution */
689 strcpy( buffer
, wine_get_config_dir() );
690 p
= buffer
+ strlen(buffer
);
692 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
694 if ((file
= fopen( buffer
, "r" )))
696 TRACE("(%s): found it in %s\n",
698 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(buffer
)+1 );
699 strcpy( CurProfile
->unix_name
, buffer
);
704 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.long_name
)+1 );
705 strcpy( CurProfile
->unix_name
, full_name
.long_name
);
706 if ((file
= fopen( full_name
.long_name
, "r" )))
707 TRACE("(%s): found it in %s\n",
708 filename
, full_name
.long_name
);
713 CurProfile
->section
= PROFILE_Load( file
);
715 if(!stat(CurProfile
->unix_name
,&buf
))
716 CurProfile
->mtime
=buf
.st_mtime
;
720 /* Does not exist yet, we will create it in PROFILE_FlushFile */
721 WARN("profile file %s not found\n", newdos_name
);
727 /***********************************************************************
730 * Returns all keys of a section.
731 * If return_values is TRUE, also include the corresponding values.
733 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
734 LPSTR buffer
, UINT len
, BOOL handle_env
,
739 if(!buffer
) return 0;
743 if (section
->name
[0] && !strcasecmp( section
->name
, section_name
))
746 for (key
= section
->key
; key
; key
= key
->next
)
749 if (!*key
->name
) continue; /* Skip empty lines */
750 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
751 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
752 len
-= strlen(buffer
) + 1;
753 buffer
+= strlen(buffer
) + 1;
756 if (return_values
&& key
->value
) {
758 PROFILE_CopyEntry ( buffer
,
759 key
->value
, len
- 1, handle_env
);
760 len
-= strlen(buffer
) + 1;
761 buffer
+= strlen(buffer
) + 1;
766 /*If either lpszSection or lpszKey is NULL and the supplied
767 destination buffer is too small to hold all the strings,
768 the last string is truncated and followed by two null characters.
769 In this case, the return value is equal to cchReturnBuffer
777 section
= section
->next
;
779 buffer
[0] = buffer
[1] = '\0';
783 /* See GetPrivateProfileSectionNamesA for documentation */
784 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
788 PROFILESECTION
*section
;
799 section
= CurProfile
->section
;
800 while ((section
!=NULL
)) {
801 if (section
->name
[0]) {
802 l
= strlen(section
->name
)+1;
805 strncpy(buf
, section
->name
, f
-1);
812 strcpy(buf
, section
->name
);
816 section
= section
->next
;
823 /***********************************************************************
826 * Get a profile string.
828 * Tests with GetPrivateProfileString16, W95a,
829 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
830 * section key_name def_val res buffer
831 * "set1" "1" "x" 43 [data]
832 * "set1" "1 " "x" 43 [data] (!)
833 * "set1" " 1 "' "x" 43 [data] (!)
834 * "set1" "" "x" 1 "x"
835 * "set1" "" "x " 1 "x" (!)
836 * "set1" "" " x " 3 " x" (!)
837 * "set1" NULL "x" 6 "1\02\03\0\0"
838 * "set1" "" "x" 1 "x"
839 * NULL "1" "x" 0 "" (!)
845 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
846 LPCSTR def_val
, LPSTR buffer
, UINT len
)
848 PROFILEKEY
*key
= NULL
;
850 if(!buffer
) return 0;
852 if (!def_val
) def_val
= "";
856 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
858 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
, FALSE
);
859 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
861 TRACE("('%s','%s','%s'): returning '%s'\n",
862 section
, key_name
, def_val
, buffer
);
863 return strlen( buffer
);
865 /* no "else" here ! */
866 if (section
&& section
[0])
868 INT ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
, FALSE
, FALSE
);
869 if (!buffer
[0]) /* no luck -> def_val */
871 PROFILE_CopyEntry(buffer
, def_val
, len
, FALSE
);
872 ret
= strlen(buffer
);
881 /***********************************************************************
884 * Set a profile string.
886 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
887 LPCSTR value
, BOOL create_always
)
889 if (!key_name
) /* Delete a whole section */
891 TRACE("('%s')\n", section_name
);
892 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
894 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
895 this is not an error on application's level.*/
897 else if (!value
) /* Delete a key */
899 TRACE("('%s','%s')\n",
900 section_name
, key_name
);
901 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
902 section_name
, key_name
);
903 return TRUE
; /* same error handling as above */
905 else /* Set the key value */
907 PROFILEKEY
*key
= PROFILE_Find(&CurProfile
->section
, section_name
,
908 key_name
, TRUE
, create_always
);
909 TRACE("('%s','%s','%s'): \n",
910 section_name
, key_name
, value
);
911 if (!key
) return FALSE
;
914 /* strip the leading spaces. We can safely strip \n\r and
915 * friends too, they should not happen here anyway. */
916 while (PROFILE_isspace(*value
)) value
++;
918 if (!strcmp( key
->value
, value
))
920 TRACE(" no change needed\n" );
921 return TRUE
; /* No change needed */
923 TRACE(" replacing '%s'\n", key
->value
);
924 HeapFree( GetProcessHeap(), 0, key
->value
);
926 else TRACE(" creating key\n" );
927 key
->value
= HeapAlloc( GetProcessHeap(), 0, strlen(value
)+1 );
928 strcpy( key
->value
, value
);
929 CurProfile
->changed
= TRUE
;
935 /***********************************************************************
936 * PROFILE_GetWineIniString
938 * Get a config string from the wine.ini file.
940 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
941 const char *def
, char *buffer
, int len
)
943 char tmp
[PROFILE_MAX_LINE_LEN
];
947 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
950 DWORD count
= sizeof(tmp
);
951 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
954 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
955 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
956 return strlen(buffer
);
960 /******************************************************************************
962 * int PROFILE_GetWineIniBool(
963 * char const *section,
964 * char const *key_name,
967 * Reads a boolean value from the wine.ini file. This function attempts to
968 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
969 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
970 * true. Anything else results in the return of the default value.
972 * This function uses 1 to indicate true, and 0 for false. You can check
973 * for existence by setting def to something other than 0 or 1 and
974 * examining the return value.
976 int PROFILE_GetWineIniBool(
978 char const *key_name
,
984 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
986 switch(key_value
[0]) {
1007 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section
, key_name
,
1008 def
? "TRUE" : "FALSE", key_value
[0],
1009 retval
? "TRUE" : "FALSE");
1015 /***********************************************************************
1016 * PROFILE_LoadWineIni
1018 * Load the old .winerc file.
1020 int PROFILE_LoadWineIni(void)
1022 OBJECT_ATTRIBUTES attr
;
1023 UNICODE_STRING nameW
;
1024 char buffer
[MAX_PATHNAME_LEN
];
1030 attr
.Length
= sizeof(attr
);
1031 attr
.RootDirectory
= 0;
1032 attr
.ObjectName
= &nameW
;
1033 attr
.Attributes
= 0;
1034 attr
.SecurityDescriptor
= NULL
;
1035 attr
.SecurityQualityOfService
= NULL
;
1037 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1038 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1039 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1041 ERR("Cannot create config registry key\n" );
1044 RtlFreeUnicodeString( &nameW
);
1047 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1048 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1049 NULL
, REG_OPTION_VOLATILE
, &disp
))
1051 ERR("Cannot create config registry key\n" );
1054 RtlFreeUnicodeString( &nameW
);
1056 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1058 if ((p
= getenv( "HOME" )) != NULL
)
1060 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1061 strcat( buffer
, PROFILE_WineIniName
);
1062 if ((f
= fopen( buffer
, "r" )) != NULL
)
1064 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1066 /* convert to the new format */
1067 sprintf( buffer
, "%s/config", wine_get_config_dir() );
1068 convert_config( f
, buffer
);
1071 MESSAGE( "The '%s' configuration file has been converted\n"
1072 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1073 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1074 "and then remove the old one and restart Wine.\n" );
1078 else WARN("could not get $HOME value for config file.\n" );
1080 MESSAGE( "Can't open configuration file %s/config\n", wine_get_config_dir() );
1085 /***********************************************************************
1086 * PROFILE_UsageWineIni
1088 * Explain the wine.ini file to those who don't read documentation.
1089 * Keep below one screenful in length so that error messages above are
1092 void PROFILE_UsageWineIni(void)
1094 MESSAGE("Perhaps you have not properly edited or created "
1095 "your Wine configuration file.\n");
1096 MESSAGE("This is (supposed to be) '%s/config'\n", wine_get_config_dir());
1097 /* RTFM, so to say */
1101 /********************* API functions **********************************/
1103 /***********************************************************************
1104 * GetProfileInt (KERNEL.57)
1106 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1108 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1112 /***********************************************************************
1113 * GetProfileIntA (KERNEL32.@)
1115 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1117 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1120 /***********************************************************************
1121 * GetProfileIntW (KERNEL32.@)
1123 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1125 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1129 * if allow_section_name_copy is TRUE, allow the copying :
1130 * - of Section names if 'section' is NULL
1131 * - of Keys in a Section if 'entry' is NULL
1132 * (see MSDN doc for GetPrivateProfileString)
1134 static int PROFILE_GetPrivateProfileString( LPCSTR section
, LPCSTR entry
,
1135 LPCSTR def_val
, LPSTR buffer
,
1136 UINT16 len
, LPCSTR filename
,
1137 BOOL allow_section_name_copy
)
1140 LPSTR pDefVal
= NULL
;
1143 filename
= "win.ini";
1145 /* strip any trailing ' ' of def_val. */
1148 LPSTR p
= (LPSTR
)&def_val
[strlen(def_val
)]; /* even "" works ! */
1156 if (*p
== ' ') /* ouch, contained trailing ' ' */
1158 int len
= (int)p
- (int)def_val
;
1159 pDefVal
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1160 strncpy(pDefVal
, def_val
, len
);
1161 pDefVal
[len
] = '\0';
1165 pDefVal
= (LPSTR
)def_val
;
1167 EnterCriticalSection( &PROFILE_CritSect
);
1169 if (PROFILE_Open( filename
)) {
1170 if ((allow_section_name_copy
) && (section
== NULL
))
1171 ret
= PROFILE_GetSectionNames(buffer
, len
);
1173 /* PROFILE_GetString already handles the 'entry == NULL' case */
1174 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1176 lstrcpynA( buffer
, pDefVal
, len
);
1177 ret
= strlen( buffer
);
1180 LeaveCriticalSection( &PROFILE_CritSect
);
1182 if (pDefVal
!= def_val
) /* allocated */
1183 HeapFree(GetProcessHeap(), 0, pDefVal
);
1188 /***********************************************************************
1189 * GetPrivateProfileString (KERNEL.128)
1191 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1192 LPCSTR def_val
, LPSTR buffer
,
1193 UINT16 len
, LPCSTR filename
)
1195 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1196 buffer
, len
, filename
, FALSE
);
1199 /***********************************************************************
1200 * GetPrivateProfileStringA (KERNEL32.@)
1202 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1203 LPCSTR def_val
, LPSTR buffer
,
1204 UINT len
, LPCSTR filename
)
1206 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1207 buffer
, len
, filename
, TRUE
);
1210 /***********************************************************************
1211 * GetPrivateProfileStringW (KERNEL32.@)
1213 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1214 LPCWSTR def_val
, LPWSTR buffer
,
1215 UINT len
, LPCWSTR filename
)
1217 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1218 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1219 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1220 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1221 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1222 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1223 bufferA
, len
, filenameA
);
1224 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1226 HeapFree( GetProcessHeap(), 0, sectionA
);
1227 HeapFree( GetProcessHeap(), 0, entryA
);
1228 HeapFree( GetProcessHeap(), 0, filenameA
);
1229 HeapFree( GetProcessHeap(), 0, def_valA
);
1230 HeapFree( GetProcessHeap(), 0, bufferA
);
1234 /***********************************************************************
1235 * GetProfileString (KERNEL.58)
1237 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1238 LPSTR buffer
, UINT16 len
)
1240 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1241 buffer
, len
, "win.ini", FALSE
);
1244 /***********************************************************************
1245 * GetProfileStringA (KERNEL32.@)
1247 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1248 LPSTR buffer
, UINT len
)
1250 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1251 buffer
, len
, "win.ini", TRUE
);
1254 /***********************************************************************
1255 * GetProfileStringW (KERNEL32.@)
1257 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1258 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1260 return GetPrivateProfileStringW( section
, entry
, def_val
,
1261 buffer
, len
, wininiW
);
1264 /***********************************************************************
1265 * WriteProfileString (KERNEL.59)
1267 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1270 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1273 /***********************************************************************
1274 * WriteProfileStringA (KERNEL32.@)
1276 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1279 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1282 /***********************************************************************
1283 * WriteProfileStringW (KERNEL32.@)
1285 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1288 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1292 /***********************************************************************
1293 * GetPrivateProfileInt (KERNEL.127)
1295 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1296 INT16 def_val
, LPCSTR filename
)
1298 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1299 * here, but Win98SE doesn't care about this at all, so I deleted it.
1300 * AFAIR versions prior to Win9x had these limits, though. */
1301 return (INT16
)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1304 /***********************************************************************
1305 * GetPrivateProfileIntA (KERNEL32.@)
1307 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1308 INT def_val
, LPCSTR filename
)
1313 if (!PROFILE_GetPrivateProfileString( section
, entry
, "",
1314 buffer
, sizeof(buffer
), filename
, FALSE
))
1316 /* FIXME: if entry can be found but it's empty, then Win16 is
1317 * supposed to return 0 instead of def_val ! Difficult/problematic
1318 * to implement (every other failure also returns zero buffer),
1319 * thus wait until testing framework avail for making sure nothing
1320 * else gets broken that way. */
1321 if (!buffer
[0]) return (UINT
)def_val
;
1323 /* Don't use strtol() here !
1324 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1325 YES, scan for unsigned format ! (otherwise compatibility error) */
1326 if (!sscanf(buffer
, "%lu", &result
)) return 0;
1327 return (UINT
)result
;
1330 /***********************************************************************
1331 * GetPrivateProfileIntW (KERNEL32.@)
1333 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1334 INT def_val
, LPCWSTR filename
)
1336 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1337 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1338 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1339 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1340 HeapFree( GetProcessHeap(), 0, sectionA
);
1341 HeapFree( GetProcessHeap(), 0, filenameA
);
1342 HeapFree( GetProcessHeap(), 0, entryA
);
1346 /***********************************************************************
1347 * GetPrivateProfileSection (KERNEL.418)
1349 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1350 UINT16 len
, LPCSTR filename
)
1352 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1355 /***********************************************************************
1356 * GetPrivateProfileSectionA (KERNEL32.@)
1358 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1359 DWORD len
, LPCSTR filename
)
1363 EnterCriticalSection( &PROFILE_CritSect
);
1365 if (PROFILE_Open( filename
))
1366 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1369 LeaveCriticalSection( &PROFILE_CritSect
);
1374 /***********************************************************************
1375 * GetPrivateProfileSectionW (KERNEL32.@)
1378 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1379 DWORD len
, LPCWSTR filename
)
1382 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1383 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1384 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1385 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1387 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1388 HeapFree( GetProcessHeap(), 0, sectionA
);
1389 HeapFree( GetProcessHeap(), 0, filenameA
);
1390 HeapFree( GetProcessHeap(), 0, bufferA
);
1394 /***********************************************************************
1395 * GetProfileSection (KERNEL.419)
1397 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1399 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1402 /***********************************************************************
1403 * GetProfileSectionA (KERNEL32.@)
1405 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1407 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1410 /***********************************************************************
1411 * GetProfileSectionW (KERNEL32.@)
1413 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1415 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1419 /***********************************************************************
1420 * WritePrivateProfileString (KERNEL.129)
1422 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1423 LPCSTR string
, LPCSTR filename
)
1425 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1428 /***********************************************************************
1429 * WritePrivateProfileStringA (KERNEL32.@)
1431 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1432 LPCSTR string
, LPCSTR filename
)
1436 EnterCriticalSection( &PROFILE_CritSect
);
1438 if (PROFILE_Open( filename
))
1440 if (!section
&& !entry
&& !string
) /* documented "file flush" case */
1441 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1444 FIXME("(NULL?,%s,%s,%s)? \n",entry
,string
,filename
);
1446 ret
= PROFILE_SetString( section
, entry
, string
, FALSE
);
1451 LeaveCriticalSection( &PROFILE_CritSect
);
1455 /***********************************************************************
1456 * WritePrivateProfileStringW (KERNEL32.@)
1458 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1459 LPCWSTR string
, LPCWSTR filename
)
1461 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1462 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1463 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1464 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1465 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1466 stringA
, filenameA
);
1467 HeapFree( GetProcessHeap(), 0, sectionA
);
1468 HeapFree( GetProcessHeap(), 0, entryA
);
1469 HeapFree( GetProcessHeap(), 0, stringA
);
1470 HeapFree( GetProcessHeap(), 0, filenameA
);
1474 /***********************************************************************
1475 * WritePrivateProfileSection (KERNEL.416)
1477 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1478 LPCSTR string
, LPCSTR filename
)
1480 return WritePrivateProfileSectionA( section
, string
, filename
);
1483 /***********************************************************************
1484 * WritePrivateProfileSectionA (KERNEL32.@)
1486 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1487 LPCSTR string
, LPCSTR filename
)
1492 EnterCriticalSection( &PROFILE_CritSect
);
1494 if (PROFILE_Open( filename
)) {
1495 if (!section
&& !string
)
1496 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1497 else if (!string
) /* delete the named section*/
1498 ret
= PROFILE_SetString(section
,NULL
,NULL
, FALSE
);
1500 PROFILE_DeleteAllKeys(section
);
1503 LPSTR buf
= HeapAlloc( GetProcessHeap(), 0, strlen(string
)+1 );
1504 strcpy( buf
, string
);
1505 if((p
=strchr( buf
, '='))){
1507 ret
= PROFILE_SetString( section
, buf
, p
+1, TRUE
);
1509 HeapFree( GetProcessHeap(), 0, buf
);
1510 string
+= strlen(string
)+1;
1515 LeaveCriticalSection( &PROFILE_CritSect
);
1519 /***********************************************************************
1520 * WritePrivateProfileSectionW (KERNEL32.@)
1522 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1523 LPCWSTR string
, LPCWSTR filename
)
1526 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1527 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1528 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1529 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1530 HeapFree( GetProcessHeap(), 0, sectionA
);
1531 HeapFree( GetProcessHeap(), 0, stringA
);
1532 HeapFree( GetProcessHeap(), 0, filenameA
);
1536 /***********************************************************************
1537 * WriteProfileSection (KERNEL.417)
1539 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1541 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1544 /***********************************************************************
1545 * WriteProfileSectionA (KERNEL32.@)
1547 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1550 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1553 /***********************************************************************
1554 * WriteProfileSectionW (KERNEL32.@)
1556 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1558 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1561 /***********************************************************************
1562 * GetPrivateProfileSectionNames (KERNEL.143)
1564 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1567 return GetPrivateProfileSectionNamesA(buffer
,size
,filename
);
1571 /***********************************************************************
1572 * GetProfileSectionNames (KERNEL.142)
1574 WORD WINAPI
GetProfileSectionNames16(LPSTR buffer
, WORD size
)
1577 return GetPrivateProfileSectionNamesA(buffer
,size
,"win.ini");
1581 /***********************************************************************
1582 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1584 * Returns the section names contained in the specified file.
1585 * FIXME: Where do we find this file when the path is relative?
1586 * The section names are returned as a list of strings with an extra
1587 * '\0' to mark the end of the list. Except for that the behavior
1588 * depends on the Windows version.
1591 * - if the buffer is 0 or 1 character long then it is as if it was of
1593 * - otherwise, if the buffer is to small only the section names that fit
1595 * - note that this means if the buffer was to small to return even just
1596 * the first section name then a single '\0' will be returned.
1597 * - the return value is the number of characters written in the buffer,
1598 * except if the buffer was too smal in which case len-2 is returned
1601 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1602 * '\0' and the return value is 0
1603 * - otherwise if the buffer is too small then the first section name that
1604 * does not fit is truncated so that the string list can be terminated
1605 * correctly (double '\0')
1606 * - the return value is the number of characters written in the buffer
1607 * except for the trailing '\0'. If the buffer is too small, then the
1608 * return value is len-2
1609 * - Win2000 has a bug that triggers when the section names and the
1610 * trailing '\0' fit exactly in the buffer. In that case the trailing
1613 * Wine implements the observed Win2000 behavior (except for the bug).
1615 * Note that when the buffer is big enough then the return value may be any
1616 * value between 1 and len-1 (or len in Win95), including len-2.
1618 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1624 EnterCriticalSection( &PROFILE_CritSect
);
1626 if (PROFILE_Open( filename
))
1627 ret
= PROFILE_GetSectionNames(buffer
, size
);
1629 LeaveCriticalSection( &PROFILE_CritSect
);
1635 /***********************************************************************
1636 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1638 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1642 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1643 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1645 INT ret
= GetPrivateProfileSectionNamesA(bufferA
, size
, filenameA
);
1646 if (size
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, size
))
1648 HeapFree( GetProcessHeap(), 0, bufferA
);
1649 HeapFree( GetProcessHeap(), 0, filenameA
);
1654 /***********************************************************************
1655 * GetPrivateProfileStruct (KERNEL.407)
1657 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1658 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1660 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1663 /***********************************************************************
1664 * GetPrivateProfileStructA (KERNEL32.@)
1666 * Should match Win95's behaviour pretty much
1668 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1669 LPVOID buf
, UINT len
, LPCSTR filename
)
1673 EnterCriticalSection( &PROFILE_CritSect
);
1675 if (PROFILE_Open( filename
)) {
1676 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
, FALSE
);
1678 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1679 if (((strlen(k
->value
) - 2) / 2) == len
)
1686 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1687 /* check for invalid chars in ASCII coded hex string */
1688 for (p
=k
->value
; p
< end
; p
++)
1692 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1693 *p
, filename
, section
, key
);
1700 BOOL highnibble
= TRUE
;
1702 LPBYTE binbuf
= (LPBYTE
)buf
;
1704 end
-= 2; /* don't include checksum in output data */
1705 /* translate ASCII hex format into binary data */
1706 for (p
=k
->value
; p
< end
; p
++)
1710 (c
- 'A' + 10) : (c
- '0');
1717 *binbuf
++ = b
; /* feed binary data into output */
1718 chksum
+= b
; /* calculate checksum */
1720 highnibble
^= 1; /* toggle */
1722 /* retrieve stored checksum value */
1724 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1726 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1727 if (b
== (chksum
& 0xff)) /* checksums match ? */
1733 LeaveCriticalSection( &PROFILE_CritSect
);
1738 /***********************************************************************
1739 * GetPrivateProfileStructW (KERNEL32.@)
1741 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1742 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1744 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1745 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1746 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1747 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1749 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1751 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1752 ((LPWSTR
)buffer
)[len
-1] = 0;
1753 HeapFree( GetProcessHeap(), 0, bufferA
);
1754 HeapFree( GetProcessHeap(), 0, sectionA
);
1755 HeapFree( GetProcessHeap(), 0, keyA
);
1756 HeapFree( GetProcessHeap(), 0, filenameA
);
1763 /***********************************************************************
1764 * WritePrivateProfileStruct (KERNEL.406)
1766 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1767 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1769 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1772 /***********************************************************************
1773 * WritePrivateProfileStructA (KERNEL32.@)
1775 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1776 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1783 if (!section
&& !key
&& !buf
) /* flush the cache */
1784 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1786 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1787 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1789 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1790 *p
++ = hex
[*binbuf
>> 4];
1791 *p
++ = hex
[*binbuf
& 0xf];
1794 /* checksum is sum & 0xff */
1795 *p
++ = hex
[(sum
& 0xf0) >> 4];
1796 *p
++ = hex
[sum
& 0xf];
1799 EnterCriticalSection( &PROFILE_CritSect
);
1801 if (PROFILE_Open( filename
))
1802 ret
= PROFILE_SetString( section
, key
, outstring
, FALSE
);
1804 LeaveCriticalSection( &PROFILE_CritSect
);
1806 HeapFree( GetProcessHeap(), 0, outstring
);
1811 /***********************************************************************
1812 * WritePrivateProfileStructW (KERNEL32.@)
1814 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1815 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1817 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1818 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1819 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1820 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1822 HeapFree( GetProcessHeap(), 0, sectionA
);
1823 HeapFree( GetProcessHeap(), 0, keyA
);
1824 HeapFree( GetProcessHeap(), 0, filenameA
);
1830 /***********************************************************************
1831 * WriteOutProfiles (KERNEL.315)
1833 void WINAPI
WriteOutProfiles16(void)
1835 EnterCriticalSection( &PROFILE_CritSect
);
1836 PROFILE_FlushFile();
1837 LeaveCriticalSection( &PROFILE_CritSect
);
1840 /***********************************************************************
1841 * CloseProfileUserMapping (KERNEL32.@)
1843 BOOL WINAPI
CloseProfileUserMapping(void) {
1844 FIXME("(), stub!\n");
1845 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);