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
29 #include <sys/types.h>
37 #include "wine/winbase16.h"
41 #include "wine/debug.h"
43 #include "wine/server.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(profile
);
47 typedef struct tagPROFILEKEY
50 struct tagPROFILEKEY
*next
;
54 typedef struct tagPROFILESECTION
56 struct tagPROFILEKEY
*key
;
57 struct tagPROFILESECTION
*next
;
65 PROFILESECTION
*section
;
73 #define N_CACHED_PROFILES 10
75 /* Cached profile files */
76 static PROFILE
*MRUProfile
[N_CACHED_PROFILES
]={NULL
};
78 #define CurProfile (MRUProfile[0])
80 /* wine.ini config file registry root */
81 static HKEY wine_profile_key
;
83 #define PROFILE_MAX_LINE_LEN 1024
85 /* Wine profile name in $HOME directory; must begin with slash */
86 static const char PROFILE_WineIniName
[] = "/.winerc";
88 /* Wine profile: the profile file being used */
89 static char PROFILE_WineIniUsed
[MAX_PATHNAME_LEN
] = "";
91 /* Check for comments in profile */
92 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
94 static const WCHAR wininiW
[] = { 'w','i','n','.','i','n','i',0 };
96 static CRITICAL_SECTION PROFILE_CritSect
= CRITICAL_SECTION_INIT("PROFILE_CritSect");
98 static const char hex
[16] = "0123456789ABCDEF";
100 /***********************************************************************
103 * Copy the content of an entry into a buffer, removing quotes, and possibly
104 * translating environment variables.
106 static void PROFILE_CopyEntry( char *buffer
, const char *value
, int len
,
114 if ((*value
== '\'') || (*value
== '\"'))
116 if (value
[1] && (value
[strlen(value
)-1] == *value
)) quote
= *value
++;
121 lstrcpynA( buffer
, value
, len
);
122 if (quote
&& (len
>= strlen(value
))) buffer
[strlen(buffer
)-1] = '\0';
126 for (p
= value
; (*p
&& (len
> 1)); *buffer
++ = *p
++, len
-- )
128 if ((*p
== '$') && (p
[1] == '{'))
132 const char *p2
= strchr( p
, '}' );
133 if (!p2
) continue; /* ignore it */
134 lstrcpynA(env_val
, p
+ 2, min( sizeof(env_val
), (int)(p2
-p
)-1 ));
135 if ((env_p
= getenv( env_val
)) != NULL
)
138 lstrcpynA( buffer
, env_p
, len
);
139 buffer_len
= strlen( buffer
);
140 buffer
+= buffer_len
;
146 if (quote
&& (len
> 1)) buffer
--;
151 /***********************************************************************
154 * Save a profile tree to a file.
156 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
160 for ( ; section
; section
= section
->next
)
162 if (section
->name
[0]) fprintf( file
, "\r\n[%s]\r\n", section
->name
);
163 for (key
= section
->key
; key
; key
= key
->next
)
165 fprintf( file
, "%s", key
->name
);
166 if (key
->value
) fprintf( file
, "=%s", key
->value
);
167 fprintf( file
, "\r\n" );
173 /***********************************************************************
176 * Free a profile tree.
178 static void PROFILE_Free( PROFILESECTION
*section
)
180 PROFILESECTION
*next_section
;
181 PROFILEKEY
*key
, *next_key
;
183 for ( ; section
; section
= next_section
)
185 for (key
= section
->key
; key
; key
= next_key
)
187 next_key
= key
->next
;
188 if (key
->value
) HeapFree( GetProcessHeap(), 0, key
->value
);
189 HeapFree( GetProcessHeap(), 0, key
);
191 next_section
= section
->next
;
192 HeapFree( GetProcessHeap(), 0, section
);
196 static inline int PROFILE_isspace(char c
)
198 if (isspace(c
)) return 1;
199 if (c
=='\r' || c
==0x1a) return 1;
200 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
205 /***********************************************************************
208 * Load a profile tree from a file.
210 static PROFILESECTION
*PROFILE_Load( FILE *file
)
212 char buffer
[PROFILE_MAX_LINE_LEN
];
215 PROFILESECTION
*section
, *first_section
;
216 PROFILESECTION
**next_section
;
217 PROFILEKEY
*key
, *prev_key
, **next_key
;
219 first_section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
220 if(first_section
== NULL
) return NULL
;
221 first_section
->name
[0] = 0;
222 first_section
->key
= NULL
;
223 first_section
->next
= NULL
;
224 next_section
= &first_section
->next
;
225 next_key
= &first_section
->key
;
228 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
232 while (*p
&& PROFILE_isspace(*p
)) p
++;
233 if (*p
== '[') /* section start */
235 if (!(p2
= strrchr( p
, ']' )))
237 WARN("Invalid section header at line %d: '%s'\n",
244 if (!(section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) + strlen(p
) )))
246 strcpy( section
->name
, p
);
248 section
->next
= NULL
;
249 *next_section
= section
;
250 next_section
= §ion
->next
;
251 next_key
= §ion
->key
;
254 TRACE("New section: '%s'\n",section
->name
);
261 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
263 if ((p2
= strchr( p
, '=' )) != NULL
)
266 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
268 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
271 if(*p
|| !prev_key
|| *prev_key
->name
)
273 if (!(key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) + strlen(p
) ))) break;
274 strcpy( key
->name
, p
);
277 key
->value
= HeapAlloc( GetProcessHeap(), 0, strlen(p2
)+1 );
278 strcpy( key
->value
, p2
);
280 else key
->value
= NULL
;
284 next_key
= &key
->next
;
287 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
290 return first_section
;
293 /* convert the .winerc file to the new format */
294 static void convert_config( FILE *in
, const char *output_name
)
296 char buffer
[PROFILE_MAX_LINE_LEN
];
300 /* create the output file, only if it doesn't exist already */
301 int fd
= open( output_name
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666 );
304 MESSAGE( "Could not create new config file '%s': %s\n", output_name
, strerror(errno
) );
308 out
= fdopen( fd
, "w" );
309 fprintf( out
, "WINE REGISTRY Version 2\n" );
310 fprintf( out
, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
311 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, in
))
313 if (buffer
[strlen(buffer
)-1] == '\n') buffer
[strlen(buffer
)-1] = 0;
315 while (*p
&& PROFILE_isspace(*p
)) p
++;
316 if (*p
== '[') /* section start */
318 if ((p2
= strrchr( p
, ']' )))
322 fprintf( out
, "[%s]\n", p
);
327 if (*p
== ';' || *p
== '#')
329 fprintf( out
, "%s\n", p
);
334 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
336 if ((p2
= strchr( p
, '=' )) != NULL
)
339 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
341 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
346 fprintf( out
, "\n" );
352 if (*p
== '\\') fputc( '\\', out
);
356 fprintf( out
, "\" = \"" );
361 if (*p2
== '\\') fputc( '\\', out
);
366 fprintf( out
, "\"\n" );
372 /***********************************************************************
373 * PROFILE_DeleteSection
375 * Delete a section from a profile tree.
377 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
381 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, name
))
383 PROFILESECTION
*to_del
= *section
;
384 *section
= to_del
->next
;
386 PROFILE_Free( to_del
);
389 section
= &(*section
)->next
;
395 /***********************************************************************
398 * Delete a key from a profile tree.
400 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
401 LPCSTR section_name
, LPCSTR key_name
)
405 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, section_name
))
407 PROFILEKEY
**key
= &(*section
)->key
;
410 if (!strcasecmp( (*key
)->name
, key_name
))
412 PROFILEKEY
*to_del
= *key
;
414 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
415 HeapFree( GetProcessHeap(), 0, to_del
);
421 section
= &(*section
)->next
;
427 /***********************************************************************
428 * PROFILE_DeleteAllKeys
430 * Delete all keys from a profile tree.
432 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
434 PROFILESECTION
**section
= &CurProfile
->section
;
437 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, section_name
))
439 PROFILEKEY
**key
= &(*section
)->key
;
442 PROFILEKEY
*to_del
= *key
;
444 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
445 HeapFree( GetProcessHeap(), 0, to_del
);
446 CurProfile
->changed
=TRUE
;
449 section
= &(*section
)->next
;
454 /***********************************************************************
457 * Find a key in a profile tree, optionally creating it.
459 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
, const char *section_name
,
460 const char *key_name
, BOOL create
, BOOL create_always
)
465 while (PROFILE_isspace(*section_name
)) section_name
++;
466 p
= section_name
+ strlen(section_name
) - 1;
467 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
468 seclen
= p
- section_name
+ 1;
470 while (PROFILE_isspace(*key_name
)) key_name
++;
471 p
= key_name
+ strlen(key_name
) - 1;
472 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
473 keylen
= p
- key_name
+ 1;
477 if ( ((*section
)->name
[0])
478 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
479 && (((*section
)->name
)[seclen
] == '\0') )
481 PROFILEKEY
**key
= &(*section
)->key
;
485 /* If create_always is FALSE then we check if the keyname already exists.
486 * Otherwise we add it regardless of its existence, to allow
487 * keys to be added more then once in some cases.
491 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
492 && (((*key
)->name
)[keylen
] == '\0') )
497 if (!create
) return NULL
;
498 if (!(*key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) + strlen(key_name
) )))
500 strcpy( (*key
)->name
, key_name
);
501 (*key
)->value
= NULL
;
505 section
= &(*section
)->next
;
507 if (!create
) return NULL
;
508 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) + strlen(section_name
) );
509 if(*section
== NULL
) return NULL
;
510 strcpy( (*section
)->name
, section_name
);
511 (*section
)->next
= NULL
;
512 if (!((*section
)->key
= HeapAlloc( GetProcessHeap(), 0,
513 sizeof(PROFILEKEY
) + strlen(key_name
) )))
515 HeapFree(GetProcessHeap(), 0, *section
);
518 strcpy( (*section
)->key
->name
, key_name
);
519 (*section
)->key
->value
= NULL
;
520 (*section
)->key
->next
= NULL
;
521 return (*section
)->key
;
525 /***********************************************************************
528 * Flush the current profile to disk if changed.
530 static BOOL
PROFILE_FlushFile(void)
532 char *p
, buffer
[MAX_PATHNAME_LEN
];
533 const char *unix_name
;
539 WARN("No current profile!\n");
543 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
544 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
546 /* Try to create it in $HOME/.wine */
547 /* FIXME: this will need a more general solution */
548 strcpy( buffer
, get_config_dir() );
549 p
= buffer
+ strlen(buffer
);
551 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
553 file
= fopen( buffer
, "w" );
559 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
563 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
564 PROFILE_Save( file
, CurProfile
->section
);
566 CurProfile
->changed
= FALSE
;
567 if(!stat(unix_name
,&buf
))
568 CurProfile
->mtime
=buf
.st_mtime
;
573 /***********************************************************************
574 * PROFILE_ReleaseFile
576 * Flush the current profile to disk and remove it from the cache.
578 static void PROFILE_ReleaseFile(void)
581 PROFILE_Free( CurProfile
->section
);
582 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
583 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
584 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
585 CurProfile
->changed
= FALSE
;
586 CurProfile
->section
= NULL
;
587 CurProfile
->dos_name
= NULL
;
588 CurProfile
->unix_name
= NULL
;
589 CurProfile
->filename
= NULL
;
590 CurProfile
->mtime
= 0;
594 /***********************************************************************
597 * Open a profile file, checking the cached file first.
599 static BOOL
PROFILE_Open( LPCSTR filename
)
601 DOS_FULL_NAME full_name
;
602 char buffer
[MAX_PATHNAME_LEN
];
603 char *newdos_name
, *p
;
607 PROFILE
*tempProfile
;
609 /* First time around */
612 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
614 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
615 if(MRUProfile
[i
] == NULL
) break;
616 MRUProfile
[i
]->changed
=FALSE
;
617 MRUProfile
[i
]->section
=NULL
;
618 MRUProfile
[i
]->dos_name
=NULL
;
619 MRUProfile
[i
]->unix_name
=NULL
;
620 MRUProfile
[i
]->filename
=NULL
;
621 MRUProfile
[i
]->mtime
=0;
624 /* Check for a match */
626 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
627 strchr( filename
, ':' ))
629 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
633 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
634 strcat( buffer
, "\\" );
635 strcat( buffer
, filename
);
636 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
639 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
641 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
642 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
647 tempProfile
=MRUProfile
[i
];
649 MRUProfile
[j
]=MRUProfile
[j
-1];
650 CurProfile
=tempProfile
;
652 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
653 TRACE("(%s): already opened (mru=%d)\n",
656 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
662 /* Flush the old current profile */
665 /* Make the oldest profile the current one only in order to get rid of it */
666 if(i
==N_CACHED_PROFILES
)
668 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
669 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
670 MRUProfile
[i
]=MRUProfile
[i
-1];
671 CurProfile
=tempProfile
;
673 if(CurProfile
->filename
) PROFILE_ReleaseFile();
675 /* OK, now that CurProfile is definitely free we assign it our new file */
676 newdos_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.short_name
)+1 );
677 strcpy( newdos_name
, full_name
.short_name
);
678 CurProfile
->dos_name
= newdos_name
;
679 CurProfile
->filename
= HeapAlloc( GetProcessHeap(), 0, strlen(filename
)+1 );
680 strcpy( CurProfile
->filename
, filename
);
682 /* Try to open the profile file, first in $HOME/.wine */
684 /* FIXME: this will need a more general solution */
685 strcpy( buffer
, get_config_dir() );
686 p
= buffer
+ strlen(buffer
);
688 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
690 if ((file
= fopen( buffer
, "r" )))
692 TRACE("(%s): found it in %s\n",
694 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(buffer
)+1 );
695 strcpy( CurProfile
->unix_name
, buffer
);
700 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.long_name
)+1 );
701 strcpy( CurProfile
->unix_name
, full_name
.long_name
);
702 if ((file
= fopen( full_name
.long_name
, "r" )))
703 TRACE("(%s): found it in %s\n",
704 filename
, full_name
.long_name
);
709 CurProfile
->section
= PROFILE_Load( file
);
711 if(!stat(CurProfile
->unix_name
,&buf
))
712 CurProfile
->mtime
=buf
.st_mtime
;
716 /* Does not exist yet, we will create it in PROFILE_FlushFile */
717 WARN("profile file %s not found\n", newdos_name
);
723 /***********************************************************************
726 * Returns all keys of a section.
727 * If return_values is TRUE, also include the corresponding values.
729 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
730 LPSTR buffer
, UINT len
, BOOL handle_env
,
735 if(!buffer
) return 0;
739 if (section
->name
[0] && !strcasecmp( section
->name
, section_name
))
742 for (key
= section
->key
; key
; key
= key
->next
)
745 if (!*key
->name
) continue; /* Skip empty lines */
746 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
747 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
748 len
-= strlen(buffer
) + 1;
749 buffer
+= strlen(buffer
) + 1;
752 if (return_values
&& key
->value
) {
754 PROFILE_CopyEntry ( buffer
,
755 key
->value
, len
- 1, handle_env
);
756 len
-= strlen(buffer
) + 1;
757 buffer
+= strlen(buffer
) + 1;
762 /*If either lpszSection or lpszKey is NULL and the supplied
763 destination buffer is too small to hold all the strings,
764 the last string is truncated and followed by two null characters.
765 In this case, the return value is equal to cchReturnBuffer
773 section
= section
->next
;
775 buffer
[0] = buffer
[1] = '\0';
779 /* See GetPrivateProfileSectionNamesA for documentation */
780 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
784 PROFILESECTION
*section
;
795 section
= CurProfile
->section
;
796 while ((section
!=NULL
)) {
797 if (section
->name
[0]) {
798 l
= strlen(section
->name
)+1;
801 strncpy(buf
, section
->name
, f
-1);
808 strcpy(buf
, section
->name
);
812 section
= section
->next
;
819 /***********************************************************************
822 * Get a profile string.
824 * Tests with GetPrivateProfileString16, W95a,
825 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
826 * section key_name def_val res buffer
827 * "set1" "1" "x" 43 [data]
828 * "set1" "1 " "x" 43 [data] (!)
829 * "set1" " 1 "' "x" 43 [data] (!)
830 * "set1" "" "x" 1 "x"
831 * "set1" "" "x " 1 "x" (!)
832 * "set1" "" " x " 3 " x" (!)
833 * "set1" NULL "x" 6 "1\02\03\0\0"
834 * "set1" "" "x" 1 "x"
835 * NULL "1" "x" 0 "" (!)
841 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
842 LPCSTR def_val
, LPSTR buffer
, UINT len
)
844 PROFILEKEY
*key
= NULL
;
846 if(!buffer
) return 0;
848 if (!def_val
) def_val
= "";
849 if (key_name
&& key_name
[0])
851 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
, FALSE
);
852 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
854 TRACE("('%s','%s','%s'): returning '%s'\n",
855 section
, key_name
, def_val
, buffer
);
856 return strlen( buffer
);
858 if (key_name
&& !(key_name
[0]))
859 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
861 if (section
&& section
[0])
862 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
869 /***********************************************************************
872 * Set a profile string.
874 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
875 LPCSTR value
, BOOL create_always
)
877 if (!key_name
) /* Delete a whole section */
879 TRACE("('%s')\n", section_name
);
880 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
882 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
883 this is not an error on application's level.*/
885 else if (!value
) /* Delete a key */
887 TRACE("('%s','%s')\n",
888 section_name
, key_name
);
889 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
890 section_name
, key_name
);
891 return TRUE
; /* same error handling as above */
893 else /* Set the key value */
895 PROFILEKEY
*key
= PROFILE_Find(&CurProfile
->section
, section_name
,
896 key_name
, TRUE
, create_always
);
897 TRACE("('%s','%s','%s'): \n",
898 section_name
, key_name
, value
);
899 if (!key
) return FALSE
;
902 /* strip the leading spaces. We can safely strip \n\r and
903 * friends too, they should not happen here anyway. */
904 while (PROFILE_isspace(*value
)) value
++;
906 if (!strcmp( key
->value
, value
))
908 TRACE(" no change needed\n" );
909 return TRUE
; /* No change needed */
911 TRACE(" replacing '%s'\n", key
->value
);
912 HeapFree( GetProcessHeap(), 0, key
->value
);
914 else TRACE(" creating key\n" );
915 key
->value
= HeapAlloc( GetProcessHeap(), 0, strlen(value
)+1 );
916 strcpy( key
->value
, value
);
917 CurProfile
->changed
= TRUE
;
923 /***********************************************************************
924 * PROFILE_GetWineIniString
926 * Get a config string from the wine.ini file.
928 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
929 const char *def
, char *buffer
, int len
)
931 char tmp
[PROFILE_MAX_LINE_LEN
];
935 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
938 DWORD count
= sizeof(tmp
);
939 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
942 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
943 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
944 return strlen(buffer
);
948 /***********************************************************************
949 * PROFILE_EnumWineIniString
951 * Get a config string from the wine.ini file.
953 BOOL
PROFILE_EnumWineIniString( const char *section
, int index
,
954 char *name
, int name_len
, char *buffer
, int len
)
956 char tmp
[PROFILE_MAX_LINE_LEN
];
959 DWORD count
= sizeof(tmp
);
961 if (RegOpenKeyA( wine_profile_key
, section
, &hkey
)) return FALSE
;
962 err
= RegEnumValueA( hkey
, index
, name
, (DWORD
*)&name_len
, NULL
, &type
, tmp
, &count
);
966 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
967 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
973 /***********************************************************************
974 * PROFILE_GetWineIniInt
976 * Get a config integer from the wine.ini file.
978 int PROFILE_GetWineIniInt( const char *section
, const char *key_name
, int def
)
984 PROFILE_GetWineIniString( section
, key_name
, "", buffer
, sizeof(buffer
) );
985 if (!buffer
[0]) return def
;
986 /* FIXME: strtol wrong ?? see GetPrivateProfileIntA */
987 result
= strtol( buffer
, &p
, 0 );
988 return (p
== buffer
) ? 0 /* No digits at all */ : (int)result
;
992 /******************************************************************************
994 * int PROFILE_GetWineIniBool(
995 * char const *section,
996 * char const *key_name,
999 * Reads a boolean value from the wine.ini file. This function attempts to
1000 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
1001 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
1002 * true. Anything else results in the return of the default value.
1004 * This function uses 1 to indicate true, and 0 for false. You can check
1005 * for existence by setting def to something other than 0 or 1 and
1006 * examining the return value.
1008 int PROFILE_GetWineIniBool(
1009 char const *section
,
1010 char const *key_name
,
1016 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
1018 switch(key_value
[0]) {
1039 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section
, key_name
,
1040 def
? "TRUE" : "FALSE", key_value
[0],
1041 retval
? "TRUE" : "FALSE");
1047 /***********************************************************************
1048 * PROFILE_LoadWineIni
1050 * Load the old .winerc file.
1052 int PROFILE_LoadWineIni(void)
1054 OBJECT_ATTRIBUTES attr
;
1055 UNICODE_STRING nameW
;
1056 char buffer
[MAX_PATHNAME_LEN
];
1062 attr
.Length
= sizeof(attr
);
1063 attr
.RootDirectory
= 0;
1064 attr
.ObjectName
= &nameW
;
1065 attr
.Attributes
= 0;
1066 attr
.SecurityDescriptor
= NULL
;
1067 attr
.SecurityQualityOfService
= NULL
;
1069 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1070 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1071 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1073 ERR("Cannot create config registry key\n" );
1076 RtlFreeUnicodeString( &nameW
);
1079 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1080 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1081 NULL
, REG_OPTION_VOLATILE
, &disp
))
1083 ERR("Cannot create config registry key\n" );
1086 RtlFreeUnicodeString( &nameW
);
1088 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1090 if ((p
= getenv( "HOME" )) != NULL
)
1092 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1093 strcat( buffer
, PROFILE_WineIniName
);
1094 if ((f
= fopen( buffer
, "r" )) != NULL
)
1096 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1100 else WARN("could not get $HOME value for config file.\n" );
1102 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1104 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1109 if (disp
== REG_OPENED_EXISTING_KEY
)
1111 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1112 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed
);
1117 /* convert to the new format */
1118 sprintf( buffer
, "%s/config", get_config_dir() );
1119 convert_config( f
, buffer
);
1122 MESSAGE( "The '%s' configuration file has been converted\n"
1123 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1124 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1125 "and then remove the old one and restart Wine.\n" );
1130 /***********************************************************************
1131 * PROFILE_UsageWineIni
1133 * Explain the wine.ini file to those who don't read documentation.
1134 * Keep below one screenful in length so that error messages above are
1137 void PROFILE_UsageWineIni(void)
1139 MESSAGE("Perhaps you have not properly edited or created "
1140 "your Wine configuration file.\n");
1141 MESSAGE("This is (supposed to be) '%s/config'\n", get_config_dir());
1142 /* RTFM, so to say */
1145 /***********************************************************************
1146 * PROFILE_GetStringItem
1148 * Convenience function that turns a string 'xxx, yyy, zzz' into
1149 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1151 char* PROFILE_GetStringItem( char* start
)
1155 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1159 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1161 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1163 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1166 if( lpch
) *lpch
= '\0';
1170 /********************* API functions **********************************/
1172 /***********************************************************************
1173 * GetProfileInt (KERNEL.57)
1175 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1177 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1181 /***********************************************************************
1182 * GetProfileIntA (KERNEL32.@)
1184 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1186 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1189 /***********************************************************************
1190 * GetProfileIntW (KERNEL32.@)
1192 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1194 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1198 * if allow_section_name_copy is TRUE, allow the copying :
1199 * - of Section names if 'section' is NULL
1200 * - of Keys in a Section if 'entry' is NULL
1201 * (see MSDN doc for GetPrivateProfileString)
1203 static int PROFILE_GetPrivateProfileString( LPCSTR section
, LPCSTR entry
,
1204 LPCSTR def_val
, LPSTR buffer
,
1205 UINT16 len
, LPCSTR filename
,
1206 BOOL allow_section_name_copy
)
1209 LPSTR pDefVal
= NULL
;
1212 filename
= "win.ini";
1214 /* strip any trailing ' ' of def_val. */
1217 LPSTR p
= (LPSTR
)&def_val
[strlen(def_val
)]; /* even "" works ! */
1225 if (*p
== ' ') /* ouch, contained trailing ' ' */
1227 int len
= (int)p
- (int)def_val
;
1228 pDefVal
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1229 strncpy(pDefVal
, def_val
, len
);
1230 pDefVal
[len
] = '\0';
1234 pDefVal
= (LPSTR
)def_val
;
1236 EnterCriticalSection( &PROFILE_CritSect
);
1238 if (PROFILE_Open( filename
)) {
1239 if ((allow_section_name_copy
) && (section
== NULL
))
1240 ret
= PROFILE_GetSectionNames(buffer
, len
);
1242 /* PROFILE_GetString already handles the 'entry == NULL' case */
1243 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1245 lstrcpynA( buffer
, pDefVal
, len
);
1246 ret
= strlen( buffer
);
1249 LeaveCriticalSection( &PROFILE_CritSect
);
1251 if (pDefVal
!= def_val
) /* allocated */
1252 HeapFree(GetProcessHeap(), 0, pDefVal
);
1257 /***********************************************************************
1258 * GetPrivateProfileString (KERNEL.128)
1260 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1261 LPCSTR def_val
, LPSTR buffer
,
1262 UINT16 len
, LPCSTR filename
)
1264 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1265 buffer
, len
, filename
, FALSE
);
1268 /***********************************************************************
1269 * GetPrivateProfileStringA (KERNEL32.@)
1271 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1272 LPCSTR def_val
, LPSTR buffer
,
1273 UINT len
, LPCSTR filename
)
1275 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1276 buffer
, len
, filename
, TRUE
);
1279 /***********************************************************************
1280 * GetPrivateProfileStringW (KERNEL32.@)
1282 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1283 LPCWSTR def_val
, LPWSTR buffer
,
1284 UINT len
, LPCWSTR filename
)
1286 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1287 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1288 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1289 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1290 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1291 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1292 bufferA
, len
, filenameA
);
1293 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1295 HeapFree( GetProcessHeap(), 0, sectionA
);
1296 HeapFree( GetProcessHeap(), 0, entryA
);
1297 HeapFree( GetProcessHeap(), 0, filenameA
);
1298 HeapFree( GetProcessHeap(), 0, def_valA
);
1299 HeapFree( GetProcessHeap(), 0, bufferA
);
1303 /***********************************************************************
1304 * GetProfileString (KERNEL.58)
1306 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1307 LPSTR buffer
, UINT16 len
)
1309 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1310 buffer
, len
, "win.ini", FALSE
);
1313 /***********************************************************************
1314 * GetProfileStringA (KERNEL32.@)
1316 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1317 LPSTR buffer
, UINT len
)
1319 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1320 buffer
, len
, "win.ini", TRUE
);
1323 /***********************************************************************
1324 * GetProfileStringW (KERNEL32.@)
1326 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1327 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1329 return GetPrivateProfileStringW( section
, entry
, def_val
,
1330 buffer
, len
, wininiW
);
1333 /***********************************************************************
1334 * WriteProfileString (KERNEL.59)
1336 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1339 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1342 /***********************************************************************
1343 * WriteProfileStringA (KERNEL32.@)
1345 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1348 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1351 /***********************************************************************
1352 * WriteProfileStringW (KERNEL32.@)
1354 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1357 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1361 /***********************************************************************
1362 * GetPrivateProfileInt (KERNEL.127)
1364 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1365 INT16 def_val
, LPCSTR filename
)
1367 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1368 * here, but Win98SE doesn't care about this at all, so I deleted it.
1369 * AFAIR versions prior to Win9x had these limits, though. */
1370 return (INT16
)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1373 /***********************************************************************
1374 * GetPrivateProfileIntA (KERNEL32.@)
1376 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1377 INT def_val
, LPCSTR filename
)
1382 if (!PROFILE_GetPrivateProfileString( section
, entry
, "",
1383 buffer
, sizeof(buffer
), filename
, FALSE
))
1385 /* FIXME: if entry can be found but it's empty, then Win16 is
1386 * supposed to return 0 instead of def_val ! Difficult/problematic
1387 * to implement (every other failure also returns zero buffer),
1388 * thus wait until testing framework avail for making sure nothing
1389 * else gets broken that way. */
1390 if (!buffer
[0]) return (UINT
)def_val
;
1392 /* Don't use strtol() here !
1393 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1394 YES, scan for unsigned format ! (otherwise compatibility error) */
1395 if (!sscanf(buffer
, "%lu", &result
)) return 0;
1396 return (UINT
)result
;
1399 /***********************************************************************
1400 * GetPrivateProfileIntW (KERNEL32.@)
1402 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1403 INT def_val
, LPCWSTR filename
)
1405 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1406 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1407 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1408 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1409 HeapFree( GetProcessHeap(), 0, sectionA
);
1410 HeapFree( GetProcessHeap(), 0, filenameA
);
1411 HeapFree( GetProcessHeap(), 0, entryA
);
1415 /***********************************************************************
1416 * GetPrivateProfileSection (KERNEL.418)
1418 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1419 UINT16 len
, LPCSTR filename
)
1421 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1424 /***********************************************************************
1425 * GetPrivateProfileSectionA (KERNEL32.@)
1427 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1428 DWORD len
, LPCSTR filename
)
1432 EnterCriticalSection( &PROFILE_CritSect
);
1434 if (PROFILE_Open( filename
))
1435 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1438 LeaveCriticalSection( &PROFILE_CritSect
);
1443 /***********************************************************************
1444 * GetPrivateProfileSectionW (KERNEL32.@)
1447 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1448 DWORD len
, LPCWSTR filename
)
1451 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1452 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1453 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1454 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1456 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1457 HeapFree( GetProcessHeap(), 0, sectionA
);
1458 HeapFree( GetProcessHeap(), 0, filenameA
);
1459 HeapFree( GetProcessHeap(), 0, bufferA
);
1463 /***********************************************************************
1464 * GetProfileSection (KERNEL.419)
1466 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1468 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1471 /***********************************************************************
1472 * GetProfileSectionA (KERNEL32.@)
1474 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1476 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1479 /***********************************************************************
1480 * GetProfileSectionW (KERNEL32.@)
1482 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1484 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1488 /***********************************************************************
1489 * WritePrivateProfileString (KERNEL.129)
1491 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1492 LPCSTR string
, LPCSTR filename
)
1494 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1497 /***********************************************************************
1498 * WritePrivateProfileStringA (KERNEL32.@)
1500 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1501 LPCSTR string
, LPCSTR filename
)
1505 EnterCriticalSection( &PROFILE_CritSect
);
1507 if (PROFILE_Open( filename
))
1509 if (!section
&& !entry
&& !string
) /* documented "file flush" case */
1510 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1513 FIXME("(NULL?,%s,%s,%s)? \n",entry
,string
,filename
);
1515 ret
= PROFILE_SetString( section
, entry
, string
, FALSE
);
1520 LeaveCriticalSection( &PROFILE_CritSect
);
1524 /***********************************************************************
1525 * WritePrivateProfileStringW (KERNEL32.@)
1527 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1528 LPCWSTR string
, LPCWSTR filename
)
1530 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1531 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1532 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1533 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1534 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1535 stringA
, filenameA
);
1536 HeapFree( GetProcessHeap(), 0, sectionA
);
1537 HeapFree( GetProcessHeap(), 0, entryA
);
1538 HeapFree( GetProcessHeap(), 0, stringA
);
1539 HeapFree( GetProcessHeap(), 0, filenameA
);
1543 /***********************************************************************
1544 * WritePrivateProfileSection (KERNEL.416)
1546 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1547 LPCSTR string
, LPCSTR filename
)
1549 return WritePrivateProfileSectionA( section
, string
, filename
);
1552 /***********************************************************************
1553 * WritePrivateProfileSectionA (KERNEL32.@)
1555 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1556 LPCSTR string
, LPCSTR filename
)
1561 EnterCriticalSection( &PROFILE_CritSect
);
1563 if (PROFILE_Open( filename
)) {
1564 if (!section
&& !string
)
1565 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1566 else if (!string
) /* delete the named section*/
1567 ret
= PROFILE_SetString(section
,NULL
,NULL
, FALSE
);
1569 PROFILE_DeleteAllKeys(section
);
1572 LPSTR buf
= HeapAlloc( GetProcessHeap(), 0, strlen(string
)+1 );
1573 strcpy( buf
, string
);
1574 if((p
=strchr( buf
, '='))){
1576 ret
= PROFILE_SetString( section
, buf
, p
+1, TRUE
);
1578 HeapFree( GetProcessHeap(), 0, buf
);
1579 string
+= strlen(string
)+1;
1584 LeaveCriticalSection( &PROFILE_CritSect
);
1588 /***********************************************************************
1589 * WritePrivateProfileSectionW (KERNEL32.@)
1591 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1592 LPCWSTR string
, LPCWSTR filename
)
1595 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1596 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1597 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1598 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1599 HeapFree( GetProcessHeap(), 0, sectionA
);
1600 HeapFree( GetProcessHeap(), 0, stringA
);
1601 HeapFree( GetProcessHeap(), 0, filenameA
);
1605 /***********************************************************************
1606 * WriteProfileSection (KERNEL.417)
1608 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1610 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1613 /***********************************************************************
1614 * WriteProfileSectionA (KERNEL32.@)
1616 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1619 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1622 /***********************************************************************
1623 * WriteProfileSectionW (KERNEL32.@)
1625 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1627 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1630 /***********************************************************************
1631 * GetPrivateProfileSectionNames (KERNEL.143)
1633 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1636 return GetPrivateProfileSectionNamesA(buffer
,size
,filename
);
1640 /***********************************************************************
1641 * GetProfileSectionNames (KERNEL.142)
1643 WORD WINAPI
GetProfileSectionNames16(LPSTR buffer
, WORD size
)
1646 return GetPrivateProfileSectionNamesA(buffer
,size
,"win.ini");
1650 /***********************************************************************
1651 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1653 * Returns the section names contained in the specified file.
1654 * FIXME: Where do we find this file when the path is relative?
1655 * The section names are returned as a list of strings with an extra
1656 * '\0' to mark the end of the list. Except for that the behavior
1657 * depends on the Windows version.
1660 * - if the buffer is 0 or 1 character long then it is as if it was of
1662 * - otherwise, if the buffer is to small only the section names that fit
1664 * - note that this means if the buffer was to small to return even just
1665 * the first section name then a single '\0' will be returned.
1666 * - the return value is the number of characters written in the buffer,
1667 * except if the buffer was too smal in which case len-2 is returned
1670 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1671 * '\0' and the return value is 0
1672 * - otherwise if the buffer is too small then the first section name that
1673 * does not fit is truncated so that the string list can be terminated
1674 * correctly (double '\0')
1675 * - the return value is the number of characters written in the buffer
1676 * except for the trailing '\0'. If the buffer is too small, then the
1677 * return value is len-2
1678 * - Win2000 has a bug that triggers when the section names and the
1679 * trailing '\0' fit exactly in the buffer. In that case the trailing
1682 * Wine implements the observed Win2000 behavior (except for the bug).
1684 * Note that when the buffer is big enough then the return value may be any
1685 * value between 1 and len-1 (or len in Win95), including len-2.
1687 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1693 EnterCriticalSection( &PROFILE_CritSect
);
1695 if (PROFILE_Open( filename
))
1696 ret
= PROFILE_GetSectionNames(buffer
, size
);
1698 LeaveCriticalSection( &PROFILE_CritSect
);
1704 /***********************************************************************
1705 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1707 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1711 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1712 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1714 INT ret
= GetPrivateProfileSectionNamesA(bufferA
, size
, filenameA
);
1715 if (size
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, size
))
1717 HeapFree( GetProcessHeap(), 0, bufferA
);
1718 HeapFree( GetProcessHeap(), 0, filenameA
);
1723 /***********************************************************************
1724 * GetPrivateProfileStruct (KERNEL.407)
1726 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1727 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1729 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1732 /***********************************************************************
1733 * GetPrivateProfileStructA (KERNEL32.@)
1735 * Should match Win95's behaviour pretty much
1737 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1738 LPVOID buf
, UINT len
, LPCSTR filename
)
1742 EnterCriticalSection( &PROFILE_CritSect
);
1744 if (PROFILE_Open( filename
)) {
1745 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
, FALSE
);
1747 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1748 if (((strlen(k
->value
) - 2) / 2) == len
)
1755 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1756 /* check for invalid chars in ASCII coded hex string */
1757 for (p
=k
->value
; p
< end
; p
++)
1761 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1762 *p
, filename
, section
, key
);
1769 BOOL highnibble
= TRUE
;
1771 LPBYTE binbuf
= (LPBYTE
)buf
;
1773 end
-= 2; /* don't include checksum in output data */
1774 /* translate ASCII hex format into binary data */
1775 for (p
=k
->value
; p
< end
; p
++)
1779 (c
- 'A' + 10) : (c
- '0');
1786 *binbuf
++ = b
; /* feed binary data into output */
1787 chksum
+= b
; /* calculate checksum */
1789 highnibble
^= 1; /* toggle */
1791 /* retrieve stored checksum value */
1793 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1795 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1796 if (b
== (chksum
& 0xff)) /* checksums match ? */
1802 LeaveCriticalSection( &PROFILE_CritSect
);
1807 /***********************************************************************
1808 * GetPrivateProfileStructW (KERNEL32.@)
1810 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1811 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1813 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1814 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1815 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1816 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1818 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1820 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1821 ((LPWSTR
)buffer
)[len
-1] = 0;
1822 HeapFree( GetProcessHeap(), 0, bufferA
);
1823 HeapFree( GetProcessHeap(), 0, sectionA
);
1824 HeapFree( GetProcessHeap(), 0, keyA
);
1825 HeapFree( GetProcessHeap(), 0, filenameA
);
1832 /***********************************************************************
1833 * WritePrivateProfileStruct (KERNEL.406)
1835 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1836 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1838 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1841 /***********************************************************************
1842 * WritePrivateProfileStructA (KERNEL32.@)
1844 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1845 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1852 if (!section
&& !key
&& !buf
) /* flush the cache */
1853 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1855 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1856 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1858 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1859 *p
++ = hex
[*binbuf
>> 4];
1860 *p
++ = hex
[*binbuf
& 0xf];
1863 /* checksum is sum & 0xff */
1864 *p
++ = hex
[(sum
& 0xf0) >> 4];
1865 *p
++ = hex
[sum
& 0xf];
1868 EnterCriticalSection( &PROFILE_CritSect
);
1870 if (PROFILE_Open( filename
))
1871 ret
= PROFILE_SetString( section
, key
, outstring
, FALSE
);
1873 LeaveCriticalSection( &PROFILE_CritSect
);
1875 HeapFree( GetProcessHeap(), 0, outstring
);
1880 /***********************************************************************
1881 * WritePrivateProfileStructW (KERNEL32.@)
1883 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1884 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1886 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1887 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1888 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1889 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1891 HeapFree( GetProcessHeap(), 0, sectionA
);
1892 HeapFree( GetProcessHeap(), 0, keyA
);
1893 HeapFree( GetProcessHeap(), 0, filenameA
);
1899 /***********************************************************************
1900 * WriteOutProfiles (KERNEL.315)
1902 void WINAPI
WriteOutProfiles16(void)
1904 EnterCriticalSection( &PROFILE_CritSect
);
1905 PROFILE_FlushFile();
1906 LeaveCriticalSection( &PROFILE_CritSect
);
1909 /***********************************************************************
1910 * CloseProfileUserMapping (KERNEL32.@)
1912 BOOL WINAPI
CloseProfileUserMapping(void) {
1913 FIXME("(), stub!\n");
1914 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);