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"
42 #include "wine/server.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(profile
);
46 typedef struct tagPROFILEKEY
49 struct tagPROFILEKEY
*next
;
53 typedef struct tagPROFILESECTION
55 struct tagPROFILEKEY
*key
;
56 struct tagPROFILESECTION
*next
;
64 PROFILESECTION
*section
;
72 #define N_CACHED_PROFILES 10
74 /* Cached profile files */
75 static PROFILE
*MRUProfile
[N_CACHED_PROFILES
]={NULL
};
77 #define CurProfile (MRUProfile[0])
79 /* wine.ini config file registry root */
80 static HKEY wine_profile_key
;
82 #define PROFILE_MAX_LINE_LEN 1024
84 /* Wine profile name in $HOME directory; must begin with slash */
85 static const char PROFILE_WineIniName
[] = "/.winerc";
87 /* Wine profile: the profile file being used */
88 static char PROFILE_WineIniUsed
[MAX_PATHNAME_LEN
] = "";
90 /* Check for comments in profile */
91 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
93 static const WCHAR wininiW
[] = { 'w','i','n','.','i','n','i',0 };
95 static CRITICAL_SECTION PROFILE_CritSect
= CRITICAL_SECTION_INIT("PROFILE_CritSect");
97 static const char hex
[16] = "0123456789ABCDEF";
99 /***********************************************************************
102 * Copy the content of an entry into a buffer, removing quotes, and possibly
103 * translating environment variables.
105 static void PROFILE_CopyEntry( char *buffer
, const char *value
, int len
,
113 if ((*value
== '\'') || (*value
== '\"'))
115 if (value
[1] && (value
[strlen(value
)-1] == *value
)) quote
= *value
++;
120 lstrcpynA( buffer
, value
, len
);
121 if (quote
&& (len
>= strlen(value
))) buffer
[strlen(buffer
)-1] = '\0';
125 for (p
= value
; (*p
&& (len
> 1)); *buffer
++ = *p
++, len
-- )
127 if ((*p
== '$') && (p
[1] == '{'))
131 const char *p2
= strchr( p
, '}' );
132 if (!p2
) continue; /* ignore it */
133 lstrcpynA(env_val
, p
+ 2, min( sizeof(env_val
), (int)(p2
-p
)-1 ));
134 if ((env_p
= getenv( env_val
)) != NULL
)
137 lstrcpynA( buffer
, env_p
, len
);
138 buffer_len
= strlen( buffer
);
139 buffer
+= buffer_len
;
145 if (quote
&& (len
> 1)) buffer
--;
150 /***********************************************************************
153 * Save a profile tree to a file.
155 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
159 for ( ; section
; section
= section
->next
)
161 if (section
->name
[0]) fprintf( file
, "\r\n[%s]\r\n", section
->name
);
162 for (key
= section
->key
; key
; key
= key
->next
)
164 fprintf( file
, "%s", key
->name
);
165 if (key
->value
) fprintf( file
, "=%s", key
->value
);
166 fprintf( file
, "\r\n" );
172 /***********************************************************************
175 * Free a profile tree.
177 static void PROFILE_Free( PROFILESECTION
*section
)
179 PROFILESECTION
*next_section
;
180 PROFILEKEY
*key
, *next_key
;
182 for ( ; section
; section
= next_section
)
184 for (key
= section
->key
; key
; key
= next_key
)
186 next_key
= key
->next
;
187 if (key
->value
) HeapFree( GetProcessHeap(), 0, key
->value
);
188 HeapFree( GetProcessHeap(), 0, key
);
190 next_section
= section
->next
;
191 HeapFree( GetProcessHeap(), 0, section
);
195 static inline int PROFILE_isspace(char c
)
197 if (isspace(c
)) return 1;
198 if (c
=='\r' || c
==0x1a) return 1;
199 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
204 /***********************************************************************
207 * Load a profile tree from a file.
209 static PROFILESECTION
*PROFILE_Load( FILE *file
)
211 char buffer
[PROFILE_MAX_LINE_LEN
];
214 PROFILESECTION
*section
, *first_section
;
215 PROFILESECTION
**next_section
;
216 PROFILEKEY
*key
, *prev_key
, **next_key
;
218 first_section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
219 if(first_section
== NULL
) return NULL
;
220 first_section
->name
[0] = 0;
221 first_section
->key
= NULL
;
222 first_section
->next
= NULL
;
223 next_section
= &first_section
->next
;
224 next_key
= &first_section
->key
;
227 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
231 while (*p
&& PROFILE_isspace(*p
)) p
++;
232 if (*p
== '[') /* section start */
234 if (!(p2
= strrchr( p
, ']' )))
236 WARN("Invalid section header at line %d: '%s'\n",
243 if (!(section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) + strlen(p
) )))
245 strcpy( section
->name
, p
);
247 section
->next
= NULL
;
248 *next_section
= section
;
249 next_section
= §ion
->next
;
250 next_key
= §ion
->key
;
253 TRACE("New section: '%s'\n",section
->name
);
260 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
262 if ((p2
= strchr( p
, '=' )) != NULL
)
265 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
267 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
270 if(*p
|| !prev_key
|| *prev_key
->name
)
272 if (!(key
= HeapAlloc( GetProcessHeap(), 0, sizeof(*key
) + strlen(p
) ))) break;
273 strcpy( key
->name
, p
);
276 key
->value
= HeapAlloc( GetProcessHeap(), 0, strlen(p2
)+1 );
277 strcpy( key
->value
, p2
);
279 else key
->value
= NULL
;
283 next_key
= &key
->next
;
286 TRACE("New key: name='%s', value='%s'\n",key
->name
,key
->value
?key
->value
:"(none)");
289 return first_section
;
292 /* convert the .winerc file to the new format */
293 static void convert_config( FILE *in
, const char *output_name
)
295 char buffer
[PROFILE_MAX_LINE_LEN
];
299 /* create the output file, only if it doesn't exist already */
300 int fd
= open( output_name
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666 );
303 MESSAGE( "Could not create new config file '%s': %s\n", output_name
, strerror(errno
) );
307 out
= fdopen( fd
, "w" );
308 fprintf( out
, "WINE REGISTRY Version 2\n" );
309 fprintf( out
, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
310 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, in
))
312 if (buffer
[strlen(buffer
)-1] == '\n') buffer
[strlen(buffer
)-1] = 0;
314 while (*p
&& PROFILE_isspace(*p
)) p
++;
315 if (*p
== '[') /* section start */
317 if ((p2
= strrchr( p
, ']' )))
321 fprintf( out
, "[%s]\n", p
);
326 if (*p
== ';' || *p
== '#')
328 fprintf( out
, "%s\n", p
);
333 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
335 if ((p2
= strchr( p
, '=' )) != NULL
)
338 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
340 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
345 fprintf( out
, "\n" );
351 if (*p
== '\\') fputc( '\\', out
);
355 fprintf( out
, "\" = \"" );
360 if (*p2
== '\\') fputc( '\\', out
);
365 fprintf( out
, "\"\n" );
371 /***********************************************************************
372 * PROFILE_DeleteSection
374 * Delete a section from a profile tree.
376 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
380 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, name
))
382 PROFILESECTION
*to_del
= *section
;
383 *section
= to_del
->next
;
385 PROFILE_Free( to_del
);
388 section
= &(*section
)->next
;
394 /***********************************************************************
397 * Delete a key from a profile tree.
399 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
400 LPCSTR section_name
, LPCSTR key_name
)
404 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, section_name
))
406 PROFILEKEY
**key
= &(*section
)->key
;
409 if (!strcasecmp( (*key
)->name
, key_name
))
411 PROFILEKEY
*to_del
= *key
;
413 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
414 HeapFree( GetProcessHeap(), 0, to_del
);
420 section
= &(*section
)->next
;
426 /***********************************************************************
427 * PROFILE_DeleteAllKeys
429 * Delete all keys from a profile tree.
431 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
433 PROFILESECTION
**section
= &CurProfile
->section
;
436 if ((*section
)->name
[0] && !strcasecmp( (*section
)->name
, section_name
))
438 PROFILEKEY
**key
= &(*section
)->key
;
441 PROFILEKEY
*to_del
= *key
;
443 if (to_del
->value
) HeapFree( GetProcessHeap(), 0, to_del
->value
);
444 HeapFree( GetProcessHeap(), 0, to_del
);
445 CurProfile
->changed
=TRUE
;
448 section
= &(*section
)->next
;
453 /***********************************************************************
456 * Find a key in a profile tree, optionally creating it.
458 static PROFILEKEY
*PROFILE_Find( PROFILESECTION
**section
, const char *section_name
,
459 const char *key_name
, BOOL create
, BOOL create_always
)
464 while (PROFILE_isspace(*section_name
)) section_name
++;
465 p
= section_name
+ strlen(section_name
) - 1;
466 while ((p
> section_name
) && PROFILE_isspace(*p
)) p
--;
467 seclen
= p
- section_name
+ 1;
469 while (PROFILE_isspace(*key_name
)) key_name
++;
470 p
= key_name
+ strlen(key_name
) - 1;
471 while ((p
> key_name
) && PROFILE_isspace(*p
)) p
--;
472 keylen
= p
- key_name
+ 1;
476 if ( ((*section
)->name
[0])
477 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
478 && (((*section
)->name
)[seclen
] == '\0') )
480 PROFILEKEY
**key
= &(*section
)->key
;
484 /* If create_always is FALSE then we check if the keyname already exists.
485 * Otherwise we add it regardless of its existence, to allow
486 * keys to be added more then once in some cases.
490 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
491 && (((*key
)->name
)[keylen
] == '\0') )
496 if (!create
) return NULL
;
497 if (!(*key
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY
) + strlen(key_name
) )))
499 strcpy( (*key
)->name
, key_name
);
500 (*key
)->value
= NULL
;
504 section
= &(*section
)->next
;
506 if (!create
) return NULL
;
507 *section
= HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION
) + strlen(section_name
) );
508 if(*section
== NULL
) return NULL
;
509 strcpy( (*section
)->name
, section_name
);
510 (*section
)->next
= NULL
;
511 if (!((*section
)->key
= HeapAlloc( GetProcessHeap(), 0,
512 sizeof(PROFILEKEY
) + strlen(key_name
) )))
514 HeapFree(GetProcessHeap(), 0, *section
);
517 strcpy( (*section
)->key
->name
, key_name
);
518 (*section
)->key
->value
= NULL
;
519 (*section
)->key
->next
= NULL
;
520 return (*section
)->key
;
524 /***********************************************************************
527 * Flush the current profile to disk if changed.
529 static BOOL
PROFILE_FlushFile(void)
531 char *p
, buffer
[MAX_PATHNAME_LEN
];
532 const char *unix_name
;
538 WARN("No current profile!\n");
542 if (!CurProfile
->changed
|| !CurProfile
->dos_name
) return TRUE
;
543 if (!(unix_name
= CurProfile
->unix_name
) || !(file
= fopen(unix_name
, "w")))
545 /* Try to create it in $HOME/.wine */
546 /* FIXME: this will need a more general solution */
547 strcpy( buffer
, get_config_dir() );
548 p
= buffer
+ strlen(buffer
);
550 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
552 file
= fopen( buffer
, "w" );
558 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
562 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
563 PROFILE_Save( file
, CurProfile
->section
);
565 CurProfile
->changed
= FALSE
;
566 if(!stat(unix_name
,&buf
))
567 CurProfile
->mtime
=buf
.st_mtime
;
572 /***********************************************************************
573 * PROFILE_ReleaseFile
575 * Flush the current profile to disk and remove it from the cache.
577 static void PROFILE_ReleaseFile(void)
580 PROFILE_Free( CurProfile
->section
);
581 if (CurProfile
->dos_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->dos_name
);
582 if (CurProfile
->unix_name
) HeapFree( GetProcessHeap(), 0, CurProfile
->unix_name
);
583 if (CurProfile
->filename
) HeapFree( GetProcessHeap(), 0, CurProfile
->filename
);
584 CurProfile
->changed
= FALSE
;
585 CurProfile
->section
= NULL
;
586 CurProfile
->dos_name
= NULL
;
587 CurProfile
->unix_name
= NULL
;
588 CurProfile
->filename
= NULL
;
589 CurProfile
->mtime
= 0;
593 /***********************************************************************
596 * Open a profile file, checking the cached file first.
598 static BOOL
PROFILE_Open( LPCSTR filename
)
600 DOS_FULL_NAME full_name
;
601 char buffer
[MAX_PATHNAME_LEN
];
602 char *newdos_name
, *p
;
606 PROFILE
*tempProfile
;
608 /* First time around */
611 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
613 MRUProfile
[i
]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE
) );
614 if(MRUProfile
[i
] == NULL
) break;
615 MRUProfile
[i
]->changed
=FALSE
;
616 MRUProfile
[i
]->section
=NULL
;
617 MRUProfile
[i
]->dos_name
=NULL
;
618 MRUProfile
[i
]->unix_name
=NULL
;
619 MRUProfile
[i
]->filename
=NULL
;
620 MRUProfile
[i
]->mtime
=0;
623 /* Check for a match */
625 if (strchr( filename
, '/' ) || strchr( filename
, '\\' ) ||
626 strchr( filename
, ':' ))
628 if (!DOSFS_GetFullName( filename
, FALSE
, &full_name
)) return FALSE
;
632 GetWindowsDirectoryA( buffer
, sizeof(buffer
) );
633 strcat( buffer
, "\\" );
634 strcat( buffer
, filename
);
635 if (!DOSFS_GetFullName( buffer
, FALSE
, &full_name
)) return FALSE
;
638 for(i
=0;i
<N_CACHED_PROFILES
;i
++)
640 if ((MRUProfile
[i
]->filename
&& !strcmp( filename
, MRUProfile
[i
]->filename
)) ||
641 (MRUProfile
[i
]->dos_name
&& !strcmp( full_name
.short_name
, MRUProfile
[i
]->dos_name
)))
646 tempProfile
=MRUProfile
[i
];
648 MRUProfile
[j
]=MRUProfile
[j
-1];
649 CurProfile
=tempProfile
;
651 if(!stat(CurProfile
->unix_name
,&buf
) && CurProfile
->mtime
==buf
.st_mtime
)
652 TRACE("(%s): already opened (mru=%d)\n",
655 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
661 /* Flush the old current profile */
664 /* Make the oldest profile the current one only in order to get rid of it */
665 if(i
==N_CACHED_PROFILES
)
667 tempProfile
=MRUProfile
[N_CACHED_PROFILES
-1];
668 for(i
=N_CACHED_PROFILES
-1;i
>0;i
--)
669 MRUProfile
[i
]=MRUProfile
[i
-1];
670 CurProfile
=tempProfile
;
672 if(CurProfile
->filename
) PROFILE_ReleaseFile();
674 /* OK, now that CurProfile is definitely free we assign it our new file */
675 newdos_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.short_name
)+1 );
676 strcpy( newdos_name
, full_name
.short_name
);
677 CurProfile
->dos_name
= newdos_name
;
678 CurProfile
->filename
= HeapAlloc( GetProcessHeap(), 0, strlen(filename
)+1 );
679 strcpy( CurProfile
->filename
, filename
);
681 /* Try to open the profile file, first in $HOME/.wine */
683 /* FIXME: this will need a more general solution */
684 strcpy( buffer
, get_config_dir() );
685 p
= buffer
+ strlen(buffer
);
687 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
689 if ((file
= fopen( buffer
, "r" )))
691 TRACE("(%s): found it in %s\n",
693 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(buffer
)+1 );
694 strcpy( CurProfile
->unix_name
, buffer
);
699 CurProfile
->unix_name
= HeapAlloc( GetProcessHeap(), 0, strlen(full_name
.long_name
)+1 );
700 strcpy( CurProfile
->unix_name
, full_name
.long_name
);
701 if ((file
= fopen( full_name
.long_name
, "r" )))
702 TRACE("(%s): found it in %s\n",
703 filename
, full_name
.long_name
);
708 CurProfile
->section
= PROFILE_Load( file
);
710 if(!stat(CurProfile
->unix_name
,&buf
))
711 CurProfile
->mtime
=buf
.st_mtime
;
715 /* Does not exist yet, we will create it in PROFILE_FlushFile */
716 WARN("profile file %s not found\n", newdos_name
);
722 /***********************************************************************
725 * Returns all keys of a section.
726 * If return_values is TRUE, also include the corresponding values.
728 static INT
PROFILE_GetSection( PROFILESECTION
*section
, LPCSTR section_name
,
729 LPSTR buffer
, UINT len
, BOOL handle_env
,
734 if(!buffer
) return 0;
738 if (section
->name
[0] && !strcasecmp( section
->name
, section_name
))
741 for (key
= section
->key
; key
; key
= key
->next
)
744 if (!*key
->name
) continue; /* Skip empty lines */
745 if (IS_ENTRY_COMMENT(key
->name
)) continue; /* Skip comments */
746 PROFILE_CopyEntry( buffer
, key
->name
, len
- 1, handle_env
);
747 len
-= strlen(buffer
) + 1;
748 buffer
+= strlen(buffer
) + 1;
751 if (return_values
&& key
->value
) {
753 PROFILE_CopyEntry ( buffer
,
754 key
->value
, len
- 1, handle_env
);
755 len
-= strlen(buffer
) + 1;
756 buffer
+= strlen(buffer
) + 1;
761 /*If either lpszSection or lpszKey is NULL and the supplied
762 destination buffer is too small to hold all the strings,
763 the last string is truncated and followed by two null characters.
764 In this case, the return value is equal to cchReturnBuffer
772 section
= section
->next
;
774 buffer
[0] = buffer
[1] = '\0';
778 /* See GetPrivateProfileSectionNamesA for documentation */
779 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
783 PROFILESECTION
*section
;
794 section
= CurProfile
->section
;
795 while ((section
!=NULL
)) {
796 if (section
->name
[0]) {
797 l
= strlen(section
->name
)+1;
800 strncpy(buf
, section
->name
, f
-1);
807 strcpy(buf
, section
->name
);
811 section
= section
->next
;
818 /***********************************************************************
821 * Get a profile string.
823 * Tests with GetPrivateProfileString16, W95a,
824 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
825 * section key_name def_val res buffer
826 * "set1" "1" "x" 43 [data]
827 * "set1" "1 " "x" 43 [data] (!)
828 * "set1" " 1 "' "x" 43 [data] (!)
829 * "set1" "" "x" 1 "x"
830 * "set1" "" "x " 1 "x" (!)
831 * "set1" "" " x " 3 " x" (!)
832 * "set1" NULL "x" 6 "1\02\03\0\0"
833 * "set1" "" "x" 1 "x"
834 * NULL "1" "x" 0 "" (!)
840 static INT
PROFILE_GetString( LPCSTR section
, LPCSTR key_name
,
841 LPCSTR def_val
, LPSTR buffer
, UINT len
)
843 PROFILEKEY
*key
= NULL
;
845 if(!buffer
) return 0;
847 if (!def_val
) def_val
= "";
851 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
853 key
= PROFILE_Find( &CurProfile
->section
, section
, key_name
, FALSE
, FALSE
);
854 PROFILE_CopyEntry( buffer
, (key
&& key
->value
) ? key
->value
: def_val
,
856 TRACE("('%s','%s','%s'): returning '%s'\n",
857 section
, key_name
, def_val
, buffer
);
858 return strlen( buffer
);
860 /* no "else" here ! */
861 if (section
&& section
[0])
863 PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
865 if (!buffer
[0]) /* no luck -> def_val */
866 PROFILE_CopyEntry(buffer
, def_val
, len
, FALSE
);
867 return strlen(buffer
);
874 /***********************************************************************
877 * Set a profile string.
879 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
880 LPCSTR value
, BOOL create_always
)
882 if (!key_name
) /* Delete a whole section */
884 TRACE("('%s')\n", section_name
);
885 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
887 return TRUE
; /* Even if PROFILE_DeleteSection() has failed,
888 this is not an error on application's level.*/
890 else if (!value
) /* Delete a key */
892 TRACE("('%s','%s')\n",
893 section_name
, key_name
);
894 CurProfile
->changed
|= PROFILE_DeleteKey( &CurProfile
->section
,
895 section_name
, key_name
);
896 return TRUE
; /* same error handling as above */
898 else /* Set the key value */
900 PROFILEKEY
*key
= PROFILE_Find(&CurProfile
->section
, section_name
,
901 key_name
, TRUE
, create_always
);
902 TRACE("('%s','%s','%s'): \n",
903 section_name
, key_name
, value
);
904 if (!key
) return FALSE
;
907 /* strip the leading spaces. We can safely strip \n\r and
908 * friends too, they should not happen here anyway. */
909 while (PROFILE_isspace(*value
)) value
++;
911 if (!strcmp( key
->value
, value
))
913 TRACE(" no change needed\n" );
914 return TRUE
; /* No change needed */
916 TRACE(" replacing '%s'\n", key
->value
);
917 HeapFree( GetProcessHeap(), 0, key
->value
);
919 else TRACE(" creating key\n" );
920 key
->value
= HeapAlloc( GetProcessHeap(), 0, strlen(value
)+1 );
921 strcpy( key
->value
, value
);
922 CurProfile
->changed
= TRUE
;
928 /***********************************************************************
929 * PROFILE_GetWineIniString
931 * Get a config string from the wine.ini file.
933 int PROFILE_GetWineIniString( const char *section
, const char *key_name
,
934 const char *def
, char *buffer
, int len
)
936 char tmp
[PROFILE_MAX_LINE_LEN
];
940 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
943 DWORD count
= sizeof(tmp
);
944 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
947 PROFILE_CopyEntry( buffer
, err
? def
: tmp
, len
, TRUE
);
948 TRACE( "('%s','%s','%s'): returning '%s'\n", section
, key_name
, def
, buffer
);
949 return strlen(buffer
);
953 /******************************************************************************
955 * int PROFILE_GetWineIniBool(
956 * char const *section,
957 * char const *key_name,
960 * Reads a boolean value from the wine.ini file. This function attempts to
961 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
962 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
963 * true. Anything else results in the return of the default value.
965 * This function uses 1 to indicate true, and 0 for false. You can check
966 * for existence by setting def to something other than 0 or 1 and
967 * examining the return value.
969 int PROFILE_GetWineIniBool(
971 char const *key_name
,
977 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
979 switch(key_value
[0]) {
1000 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section
, key_name
,
1001 def
? "TRUE" : "FALSE", key_value
[0],
1002 retval
? "TRUE" : "FALSE");
1008 /***********************************************************************
1009 * PROFILE_LoadWineIni
1011 * Load the old .winerc file.
1013 int PROFILE_LoadWineIni(void)
1015 OBJECT_ATTRIBUTES attr
;
1016 UNICODE_STRING nameW
;
1017 char buffer
[MAX_PATHNAME_LEN
];
1023 attr
.Length
= sizeof(attr
);
1024 attr
.RootDirectory
= 0;
1025 attr
.ObjectName
= &nameW
;
1026 attr
.Attributes
= 0;
1027 attr
.SecurityDescriptor
= NULL
;
1028 attr
.SecurityQualityOfService
= NULL
;
1030 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1031 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine" ) ||
1032 NtCreateKey( &hKeySW
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1034 ERR("Cannot create config registry key\n" );
1037 RtlFreeUnicodeString( &nameW
);
1040 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1041 NtCreateKey( &wine_profile_key
, KEY_ALL_ACCESS
, &attr
, 0,
1042 NULL
, REG_OPTION_VOLATILE
, &disp
))
1044 ERR("Cannot create config registry key\n" );
1047 RtlFreeUnicodeString( &nameW
);
1049 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1051 if ((p
= getenv( "HOME" )) != NULL
)
1053 lstrcpynA(buffer
, p
, MAX_PATHNAME_LEN
- sizeof(PROFILE_WineIniName
));
1054 strcat( buffer
, PROFILE_WineIniName
);
1055 if ((f
= fopen( buffer
, "r" )) != NULL
)
1057 lstrcpynA(PROFILE_WineIniUsed
,buffer
,MAX_PATHNAME_LEN
);
1061 else WARN("could not get $HOME value for config file.\n" );
1063 if (disp
== REG_OPENED_EXISTING_KEY
) return 1; /* loaded by the server */
1065 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1070 if (disp
== REG_OPENED_EXISTING_KEY
)
1072 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1073 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed
);
1078 /* convert to the new format */
1079 sprintf( buffer
, "%s/config", get_config_dir() );
1080 convert_config( f
, buffer
);
1083 MESSAGE( "The '%s' configuration file has been converted\n"
1084 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed
, buffer
);
1085 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1086 "and then remove the old one and restart Wine.\n" );
1091 /***********************************************************************
1092 * PROFILE_UsageWineIni
1094 * Explain the wine.ini file to those who don't read documentation.
1095 * Keep below one screenful in length so that error messages above are
1098 void PROFILE_UsageWineIni(void)
1100 MESSAGE("Perhaps you have not properly edited or created "
1101 "your Wine configuration file.\n");
1102 MESSAGE("This is (supposed to be) '%s/config'\n", get_config_dir());
1103 /* RTFM, so to say */
1107 /********************* API functions **********************************/
1109 /***********************************************************************
1110 * GetProfileInt (KERNEL.57)
1112 UINT16 WINAPI
GetProfileInt16( LPCSTR section
, LPCSTR entry
, INT16 def_val
)
1114 return GetPrivateProfileInt16( section
, entry
, def_val
, "win.ini" );
1118 /***********************************************************************
1119 * GetProfileIntA (KERNEL32.@)
1121 UINT WINAPI
GetProfileIntA( LPCSTR section
, LPCSTR entry
, INT def_val
)
1123 return GetPrivateProfileIntA( section
, entry
, def_val
, "win.ini" );
1126 /***********************************************************************
1127 * GetProfileIntW (KERNEL32.@)
1129 UINT WINAPI
GetProfileIntW( LPCWSTR section
, LPCWSTR entry
, INT def_val
)
1131 return GetPrivateProfileIntW( section
, entry
, def_val
, wininiW
);
1135 * if allow_section_name_copy is TRUE, allow the copying :
1136 * - of Section names if 'section' is NULL
1137 * - of Keys in a Section if 'entry' is NULL
1138 * (see MSDN doc for GetPrivateProfileString)
1140 static int PROFILE_GetPrivateProfileString( LPCSTR section
, LPCSTR entry
,
1141 LPCSTR def_val
, LPSTR buffer
,
1142 UINT16 len
, LPCSTR filename
,
1143 BOOL allow_section_name_copy
)
1146 LPSTR pDefVal
= NULL
;
1149 filename
= "win.ini";
1151 /* strip any trailing ' ' of def_val. */
1154 LPSTR p
= (LPSTR
)&def_val
[strlen(def_val
)]; /* even "" works ! */
1162 if (*p
== ' ') /* ouch, contained trailing ' ' */
1164 int len
= (int)p
- (int)def_val
;
1165 pDefVal
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1166 strncpy(pDefVal
, def_val
, len
);
1167 pDefVal
[len
] = '\0';
1171 pDefVal
= (LPSTR
)def_val
;
1173 EnterCriticalSection( &PROFILE_CritSect
);
1175 if (PROFILE_Open( filename
)) {
1176 if ((allow_section_name_copy
) && (section
== NULL
))
1177 ret
= PROFILE_GetSectionNames(buffer
, len
);
1179 /* PROFILE_GetString already handles the 'entry == NULL' case */
1180 ret
= PROFILE_GetString( section
, entry
, pDefVal
, buffer
, len
);
1182 lstrcpynA( buffer
, pDefVal
, len
);
1183 ret
= strlen( buffer
);
1186 LeaveCriticalSection( &PROFILE_CritSect
);
1188 if (pDefVal
!= def_val
) /* allocated */
1189 HeapFree(GetProcessHeap(), 0, pDefVal
);
1194 /***********************************************************************
1195 * GetPrivateProfileString (KERNEL.128)
1197 INT16 WINAPI
GetPrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1198 LPCSTR def_val
, LPSTR buffer
,
1199 UINT16 len
, LPCSTR filename
)
1201 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1202 buffer
, len
, filename
, FALSE
);
1205 /***********************************************************************
1206 * GetPrivateProfileStringA (KERNEL32.@)
1208 INT WINAPI
GetPrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1209 LPCSTR def_val
, LPSTR buffer
,
1210 UINT len
, LPCSTR filename
)
1212 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1213 buffer
, len
, filename
, TRUE
);
1216 /***********************************************************************
1217 * GetPrivateProfileStringW (KERNEL32.@)
1219 INT WINAPI
GetPrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1220 LPCWSTR def_val
, LPWSTR buffer
,
1221 UINT len
, LPCWSTR filename
)
1223 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1224 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1225 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1226 LPSTR def_valA
= HEAP_strdupWtoA( GetProcessHeap(), 0, def_val
);
1227 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1228 INT ret
= GetPrivateProfileStringA( sectionA
, entryA
, def_valA
,
1229 bufferA
, len
, filenameA
);
1230 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1232 HeapFree( GetProcessHeap(), 0, sectionA
);
1233 HeapFree( GetProcessHeap(), 0, entryA
);
1234 HeapFree( GetProcessHeap(), 0, filenameA
);
1235 HeapFree( GetProcessHeap(), 0, def_valA
);
1236 HeapFree( GetProcessHeap(), 0, bufferA
);
1240 /***********************************************************************
1241 * GetProfileString (KERNEL.58)
1243 INT16 WINAPI
GetProfileString16( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1244 LPSTR buffer
, UINT16 len
)
1246 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1247 buffer
, len
, "win.ini", FALSE
);
1250 /***********************************************************************
1251 * GetProfileStringA (KERNEL32.@)
1253 INT WINAPI
GetProfileStringA( LPCSTR section
, LPCSTR entry
, LPCSTR def_val
,
1254 LPSTR buffer
, UINT len
)
1256 return PROFILE_GetPrivateProfileString( section
, entry
, def_val
,
1257 buffer
, len
, "win.ini", TRUE
);
1260 /***********************************************************************
1261 * GetProfileStringW (KERNEL32.@)
1263 INT WINAPI
GetProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1264 LPCWSTR def_val
, LPWSTR buffer
, UINT len
)
1266 return GetPrivateProfileStringW( section
, entry
, def_val
,
1267 buffer
, len
, wininiW
);
1270 /***********************************************************************
1271 * WriteProfileString (KERNEL.59)
1273 BOOL16 WINAPI
WriteProfileString16( LPCSTR section
, LPCSTR entry
,
1276 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1279 /***********************************************************************
1280 * WriteProfileStringA (KERNEL32.@)
1282 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1285 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1288 /***********************************************************************
1289 * WriteProfileStringW (KERNEL32.@)
1291 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1294 return WritePrivateProfileStringW( section
, entry
, string
, wininiW
);
1298 /***********************************************************************
1299 * GetPrivateProfileInt (KERNEL.127)
1301 UINT16 WINAPI
GetPrivateProfileInt16( LPCSTR section
, LPCSTR entry
,
1302 INT16 def_val
, LPCSTR filename
)
1304 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1305 * here, but Win98SE doesn't care about this at all, so I deleted it.
1306 * AFAIR versions prior to Win9x had these limits, though. */
1307 return (INT16
)GetPrivateProfileIntA(section
,entry
,def_val
,filename
);
1310 /***********************************************************************
1311 * GetPrivateProfileIntA (KERNEL32.@)
1313 UINT WINAPI
GetPrivateProfileIntA( LPCSTR section
, LPCSTR entry
,
1314 INT def_val
, LPCSTR filename
)
1319 if (!PROFILE_GetPrivateProfileString( section
, entry
, "",
1320 buffer
, sizeof(buffer
), filename
, FALSE
))
1322 /* FIXME: if entry can be found but it's empty, then Win16 is
1323 * supposed to return 0 instead of def_val ! Difficult/problematic
1324 * to implement (every other failure also returns zero buffer),
1325 * thus wait until testing framework avail for making sure nothing
1326 * else gets broken that way. */
1327 if (!buffer
[0]) return (UINT
)def_val
;
1329 /* Don't use strtol() here !
1330 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1331 YES, scan for unsigned format ! (otherwise compatibility error) */
1332 if (!sscanf(buffer
, "%lu", &result
)) return 0;
1333 return (UINT
)result
;
1336 /***********************************************************************
1337 * GetPrivateProfileIntW (KERNEL32.@)
1339 UINT WINAPI
GetPrivateProfileIntW( LPCWSTR section
, LPCWSTR entry
,
1340 INT def_val
, LPCWSTR filename
)
1342 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1343 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1344 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1345 UINT res
= GetPrivateProfileIntA(sectionA
, entryA
, def_val
, filenameA
);
1346 HeapFree( GetProcessHeap(), 0, sectionA
);
1347 HeapFree( GetProcessHeap(), 0, filenameA
);
1348 HeapFree( GetProcessHeap(), 0, entryA
);
1352 /***********************************************************************
1353 * GetPrivateProfileSection (KERNEL.418)
1355 INT16 WINAPI
GetPrivateProfileSection16( LPCSTR section
, LPSTR buffer
,
1356 UINT16 len
, LPCSTR filename
)
1358 return GetPrivateProfileSectionA( section
, buffer
, len
, filename
);
1361 /***********************************************************************
1362 * GetPrivateProfileSectionA (KERNEL32.@)
1364 INT WINAPI
GetPrivateProfileSectionA( LPCSTR section
, LPSTR buffer
,
1365 DWORD len
, LPCSTR filename
)
1369 EnterCriticalSection( &PROFILE_CritSect
);
1371 if (PROFILE_Open( filename
))
1372 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1375 LeaveCriticalSection( &PROFILE_CritSect
);
1380 /***********************************************************************
1381 * GetPrivateProfileSectionW (KERNEL32.@)
1384 INT WINAPI
GetPrivateProfileSectionW (LPCWSTR section
, LPWSTR buffer
,
1385 DWORD len
, LPCWSTR filename
)
1388 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1389 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1390 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1391 INT ret
= GetPrivateProfileSectionA( sectionA
, bufferA
, len
,
1393 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1394 HeapFree( GetProcessHeap(), 0, sectionA
);
1395 HeapFree( GetProcessHeap(), 0, filenameA
);
1396 HeapFree( GetProcessHeap(), 0, bufferA
);
1400 /***********************************************************************
1401 * GetProfileSection (KERNEL.419)
1403 INT16 WINAPI
GetProfileSection16( LPCSTR section
, LPSTR buffer
, UINT16 len
)
1405 return GetPrivateProfileSection16( section
, buffer
, len
, "win.ini" );
1408 /***********************************************************************
1409 * GetProfileSectionA (KERNEL32.@)
1411 INT WINAPI
GetProfileSectionA( LPCSTR section
, LPSTR buffer
, DWORD len
)
1413 return GetPrivateProfileSectionA( section
, buffer
, len
, "win.ini" );
1416 /***********************************************************************
1417 * GetProfileSectionW (KERNEL32.@)
1419 INT WINAPI
GetProfileSectionW( LPCWSTR section
, LPWSTR buffer
, DWORD len
)
1421 return GetPrivateProfileSectionW( section
, buffer
, len
, wininiW
);
1425 /***********************************************************************
1426 * WritePrivateProfileString (KERNEL.129)
1428 BOOL16 WINAPI
WritePrivateProfileString16( LPCSTR section
, LPCSTR entry
,
1429 LPCSTR string
, LPCSTR filename
)
1431 return WritePrivateProfileStringA(section
,entry
,string
,filename
);
1434 /***********************************************************************
1435 * WritePrivateProfileStringA (KERNEL32.@)
1437 BOOL WINAPI
WritePrivateProfileStringA( LPCSTR section
, LPCSTR entry
,
1438 LPCSTR string
, LPCSTR filename
)
1442 EnterCriticalSection( &PROFILE_CritSect
);
1444 if (PROFILE_Open( filename
))
1446 if (!section
&& !entry
&& !string
) /* documented "file flush" case */
1447 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1450 FIXME("(NULL?,%s,%s,%s)? \n",entry
,string
,filename
);
1452 ret
= PROFILE_SetString( section
, entry
, string
, FALSE
);
1457 LeaveCriticalSection( &PROFILE_CritSect
);
1461 /***********************************************************************
1462 * WritePrivateProfileStringW (KERNEL32.@)
1464 BOOL WINAPI
WritePrivateProfileStringW( LPCWSTR section
, LPCWSTR entry
,
1465 LPCWSTR string
, LPCWSTR filename
)
1467 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1468 LPSTR entryA
= HEAP_strdupWtoA( GetProcessHeap(), 0, entry
);
1469 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1470 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1471 BOOL res
= WritePrivateProfileStringA( sectionA
, entryA
,
1472 stringA
, filenameA
);
1473 HeapFree( GetProcessHeap(), 0, sectionA
);
1474 HeapFree( GetProcessHeap(), 0, entryA
);
1475 HeapFree( GetProcessHeap(), 0, stringA
);
1476 HeapFree( GetProcessHeap(), 0, filenameA
);
1480 /***********************************************************************
1481 * WritePrivateProfileSection (KERNEL.416)
1483 BOOL16 WINAPI
WritePrivateProfileSection16( LPCSTR section
,
1484 LPCSTR string
, LPCSTR filename
)
1486 return WritePrivateProfileSectionA( section
, string
, filename
);
1489 /***********************************************************************
1490 * WritePrivateProfileSectionA (KERNEL32.@)
1492 BOOL WINAPI
WritePrivateProfileSectionA( LPCSTR section
,
1493 LPCSTR string
, LPCSTR filename
)
1498 EnterCriticalSection( &PROFILE_CritSect
);
1500 if (PROFILE_Open( filename
)) {
1501 if (!section
&& !string
)
1502 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1503 else if (!string
) /* delete the named section*/
1504 ret
= PROFILE_SetString(section
,NULL
,NULL
, FALSE
);
1506 PROFILE_DeleteAllKeys(section
);
1509 LPSTR buf
= HeapAlloc( GetProcessHeap(), 0, strlen(string
)+1 );
1510 strcpy( buf
, string
);
1511 if((p
=strchr( buf
, '='))){
1513 ret
= PROFILE_SetString( section
, buf
, p
+1, TRUE
);
1515 HeapFree( GetProcessHeap(), 0, buf
);
1516 string
+= strlen(string
)+1;
1521 LeaveCriticalSection( &PROFILE_CritSect
);
1525 /***********************************************************************
1526 * WritePrivateProfileSectionW (KERNEL32.@)
1528 BOOL WINAPI
WritePrivateProfileSectionW( LPCWSTR section
,
1529 LPCWSTR string
, LPCWSTR filename
)
1532 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1533 LPSTR stringA
= HEAP_strdupWtoA( GetProcessHeap(), 0, string
);
1534 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1535 BOOL res
= WritePrivateProfileSectionA( sectionA
, stringA
, filenameA
);
1536 HeapFree( GetProcessHeap(), 0, sectionA
);
1537 HeapFree( GetProcessHeap(), 0, stringA
);
1538 HeapFree( GetProcessHeap(), 0, filenameA
);
1542 /***********************************************************************
1543 * WriteProfileSection (KERNEL.417)
1545 BOOL16 WINAPI
WriteProfileSection16( LPCSTR section
, LPCSTR keys_n_values
)
1547 return WritePrivateProfileSection16( section
, keys_n_values
, "win.ini");
1550 /***********************************************************************
1551 * WriteProfileSectionA (KERNEL32.@)
1553 BOOL WINAPI
WriteProfileSectionA( LPCSTR section
, LPCSTR keys_n_values
)
1556 return WritePrivateProfileSectionA( section
, keys_n_values
, "win.ini");
1559 /***********************************************************************
1560 * WriteProfileSectionW (KERNEL32.@)
1562 BOOL WINAPI
WriteProfileSectionW( LPCWSTR section
, LPCWSTR keys_n_values
)
1564 return (WritePrivateProfileSectionW (section
,keys_n_values
, wininiW
));
1567 /***********************************************************************
1568 * GetPrivateProfileSectionNames (KERNEL.143)
1570 WORD WINAPI
GetPrivateProfileSectionNames16( LPSTR buffer
, WORD size
,
1573 return GetPrivateProfileSectionNamesA(buffer
,size
,filename
);
1577 /***********************************************************************
1578 * GetProfileSectionNames (KERNEL.142)
1580 WORD WINAPI
GetProfileSectionNames16(LPSTR buffer
, WORD size
)
1583 return GetPrivateProfileSectionNamesA(buffer
,size
,"win.ini");
1587 /***********************************************************************
1588 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1590 * Returns the section names contained in the specified file.
1591 * FIXME: Where do we find this file when the path is relative?
1592 * The section names are returned as a list of strings with an extra
1593 * '\0' to mark the end of the list. Except for that the behavior
1594 * depends on the Windows version.
1597 * - if the buffer is 0 or 1 character long then it is as if it was of
1599 * - otherwise, if the buffer is to small only the section names that fit
1601 * - note that this means if the buffer was to small to return even just
1602 * the first section name then a single '\0' will be returned.
1603 * - the return value is the number of characters written in the buffer,
1604 * except if the buffer was too smal in which case len-2 is returned
1607 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1608 * '\0' and the return value is 0
1609 * - otherwise if the buffer is too small then the first section name that
1610 * does not fit is truncated so that the string list can be terminated
1611 * correctly (double '\0')
1612 * - the return value is the number of characters written in the buffer
1613 * except for the trailing '\0'. If the buffer is too small, then the
1614 * return value is len-2
1615 * - Win2000 has a bug that triggers when the section names and the
1616 * trailing '\0' fit exactly in the buffer. In that case the trailing
1619 * Wine implements the observed Win2000 behavior (except for the bug).
1621 * Note that when the buffer is big enough then the return value may be any
1622 * value between 1 and len-1 (or len in Win95), including len-2.
1624 DWORD WINAPI
GetPrivateProfileSectionNamesA( LPSTR buffer
, DWORD size
,
1630 EnterCriticalSection( &PROFILE_CritSect
);
1632 if (PROFILE_Open( filename
))
1633 ret
= PROFILE_GetSectionNames(buffer
, size
);
1635 LeaveCriticalSection( &PROFILE_CritSect
);
1641 /***********************************************************************
1642 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1644 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
1648 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1649 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, size
);
1651 INT ret
= GetPrivateProfileSectionNamesA(bufferA
, size
, filenameA
);
1652 if (size
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, size
))
1654 HeapFree( GetProcessHeap(), 0, bufferA
);
1655 HeapFree( GetProcessHeap(), 0, filenameA
);
1660 /***********************************************************************
1661 * GetPrivateProfileStruct (KERNEL.407)
1663 BOOL16 WINAPI
GetPrivateProfileStruct16(LPCSTR section
, LPCSTR key
,
1664 LPVOID buf
, UINT16 len
, LPCSTR filename
)
1666 return GetPrivateProfileStructA( section
, key
, buf
, len
, filename
);
1669 /***********************************************************************
1670 * GetPrivateProfileStructA (KERNEL32.@)
1672 * Should match Win95's behaviour pretty much
1674 BOOL WINAPI
GetPrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1675 LPVOID buf
, UINT len
, LPCSTR filename
)
1679 EnterCriticalSection( &PROFILE_CritSect
);
1681 if (PROFILE_Open( filename
)) {
1682 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
, FALSE
);
1684 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1685 if (((strlen(k
->value
) - 2) / 2) == len
)
1692 end
= k
->value
+ strlen(k
->value
); /* -> '\0' */
1693 /* check for invalid chars in ASCII coded hex string */
1694 for (p
=k
->value
; p
< end
; p
++)
1698 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1699 *p
, filename
, section
, key
);
1706 BOOL highnibble
= TRUE
;
1708 LPBYTE binbuf
= (LPBYTE
)buf
;
1710 end
-= 2; /* don't include checksum in output data */
1711 /* translate ASCII hex format into binary data */
1712 for (p
=k
->value
; p
< end
; p
++)
1716 (c
- 'A' + 10) : (c
- '0');
1723 *binbuf
++ = b
; /* feed binary data into output */
1724 chksum
+= b
; /* calculate checksum */
1726 highnibble
^= 1; /* toggle */
1728 /* retrieve stored checksum value */
1730 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1732 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1733 if (b
== (chksum
& 0xff)) /* checksums match ? */
1739 LeaveCriticalSection( &PROFILE_CritSect
);
1744 /***********************************************************************
1745 * GetPrivateProfileStructW (KERNEL32.@)
1747 BOOL WINAPI
GetPrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1748 LPVOID buffer
, UINT len
, LPCWSTR filename
)
1750 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1751 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1752 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1753 LPSTR bufferA
= HeapAlloc( GetProcessHeap(), 0, len
);
1755 INT ret
= GetPrivateProfileStructA( sectionA
, keyA
, bufferA
,
1757 if (len
> 0 && !MultiByteToWideChar( CP_ACP
, 0, bufferA
, -1, buffer
, len
))
1758 ((LPWSTR
)buffer
)[len
-1] = 0;
1759 HeapFree( GetProcessHeap(), 0, bufferA
);
1760 HeapFree( GetProcessHeap(), 0, sectionA
);
1761 HeapFree( GetProcessHeap(), 0, keyA
);
1762 HeapFree( GetProcessHeap(), 0, filenameA
);
1769 /***********************************************************************
1770 * WritePrivateProfileStruct (KERNEL.406)
1772 BOOL16 WINAPI
WritePrivateProfileStruct16 (LPCSTR section
, LPCSTR key
,
1773 LPVOID buf
, UINT16 bufsize
, LPCSTR filename
)
1775 return WritePrivateProfileStructA( section
, key
, buf
, bufsize
, filename
);
1778 /***********************************************************************
1779 * WritePrivateProfileStructA (KERNEL32.@)
1781 BOOL WINAPI
WritePrivateProfileStructA (LPCSTR section
, LPCSTR key
,
1782 LPVOID buf
, UINT bufsize
, LPCSTR filename
)
1789 if (!section
&& !key
&& !buf
) /* flush the cache */
1790 return WritePrivateProfileStringA( NULL
, NULL
, NULL
, filename
);
1792 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1793 outstring
= HeapAlloc( GetProcessHeap(), 0, bufsize
*2 + 2 + 1);
1795 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1796 *p
++ = hex
[*binbuf
>> 4];
1797 *p
++ = hex
[*binbuf
& 0xf];
1800 /* checksum is sum & 0xff */
1801 *p
++ = hex
[(sum
& 0xf0) >> 4];
1802 *p
++ = hex
[sum
& 0xf];
1805 EnterCriticalSection( &PROFILE_CritSect
);
1807 if (PROFILE_Open( filename
))
1808 ret
= PROFILE_SetString( section
, key
, outstring
, FALSE
);
1810 LeaveCriticalSection( &PROFILE_CritSect
);
1812 HeapFree( GetProcessHeap(), 0, outstring
);
1817 /***********************************************************************
1818 * WritePrivateProfileStructW (KERNEL32.@)
1820 BOOL WINAPI
WritePrivateProfileStructW (LPCWSTR section
, LPCWSTR key
,
1821 LPVOID buf
, UINT bufsize
, LPCWSTR filename
)
1823 LPSTR sectionA
= HEAP_strdupWtoA( GetProcessHeap(), 0, section
);
1824 LPSTR keyA
= HEAP_strdupWtoA( GetProcessHeap(), 0, key
);
1825 LPSTR filenameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
1826 INT ret
= WritePrivateProfileStructA( sectionA
, keyA
, buf
, bufsize
,
1828 HeapFree( GetProcessHeap(), 0, sectionA
);
1829 HeapFree( GetProcessHeap(), 0, keyA
);
1830 HeapFree( GetProcessHeap(), 0, filenameA
);
1836 /***********************************************************************
1837 * WriteOutProfiles (KERNEL.315)
1839 void WINAPI
WriteOutProfiles16(void)
1841 EnterCriticalSection( &PROFILE_CritSect
);
1842 PROFILE_FlushFile();
1843 LeaveCriticalSection( &PROFILE_CritSect
);
1846 /***********************************************************************
1847 * CloseProfileUserMapping (KERNEL32.@)
1849 BOOL WINAPI
CloseProfileUserMapping(void) {
1850 FIXME("(), stub!\n");
1851 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);