Fixed strict aliasing problem in RtlEnlargedUnsignedDivide.
[wine/multimedia.git] / files / profile.c
blob660079f49d843bd8d22c26b1ca78fb988b5f65ae
1 /*
2 * Profile functions
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <ctype.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winerror.h"
41 #include "winternl.h"
42 #include "wine/winbase16.h"
43 #include "drive.h"
44 #include "file.h"
45 #include "heap.h"
46 #include "wine/unicode.h"
47 #include "wine/server.h"
48 #include "wine/library.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(profile);
53 typedef struct tagPROFILEKEY
55 WCHAR *value;
56 struct tagPROFILEKEY *next;
57 WCHAR name[1];
58 } PROFILEKEY;
60 typedef struct tagPROFILESECTION
62 struct tagPROFILEKEY *key;
63 struct tagPROFILESECTION *next;
64 WCHAR name[1];
65 } PROFILESECTION;
68 typedef struct
70 BOOL changed;
71 PROFILESECTION *section;
72 WCHAR *dos_name;
73 char *unix_name;
74 WCHAR *filename;
75 time_t mtime;
76 } PROFILE;
79 #define N_CACHED_PROFILES 10
81 /* Cached profile files */
82 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
84 #define CurProfile (MRUProfile[0])
86 /* wine.ini config file registry root */
87 static HKEY wine_profile_key;
89 #define PROFILE_MAX_LINE_LEN 1024
91 /* Wine profile name in $HOME directory; must begin with slash */
92 static const char PROFILE_WineIniName[] = "/.winerc";
94 /* Wine profile: the profile file being used */
95 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
97 /* Check for comments in profile */
98 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
100 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
102 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
104 static const char hex[16] = "0123456789ABCDEF";
106 /***********************************************************************
107 * PROFILE_CopyEntry
109 * Copy the content of an entry into a buffer, removing quotes, and possibly
110 * translating environment variables.
112 static void PROFILE_CopyEntry( LPWSTR buffer, LPCWSTR value, int len,
113 int handle_env, BOOL strip_quote )
115 WCHAR quote = '\0';
116 LPCWSTR p;
118 if(!buffer) return;
120 if (strip_quote && ((*value == '\'') || (*value == '\"')))
122 if (value[1] && (value[strlenW(value)-1] == *value)) quote = *value++;
125 if (!handle_env)
127 lstrcpynW( buffer, value, len );
128 if (quote && (len >= strlenW(value))) buffer[strlenW(buffer)-1] = '\0';
129 return;
132 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
134 if ((*p == '$') && (p[1] == '{'))
136 WCHAR env_val[1024];
137 LPCWSTR p2 = strchrW( p, '}' );
138 int copy_len;
139 if (!p2) continue; /* ignore it */
140 copy_len = min( 1024, (int)(p2-p)-1 );
141 strncpyW(env_val, p + 2, copy_len );
142 env_val[copy_len - 1] = 0; /* ensure 0 termination */
143 *buffer = 0;
144 if (GetEnvironmentVariableW( env_val, buffer, len))
146 copy_len = strlenW( buffer );
147 buffer += copy_len;
148 len -= copy_len;
150 p = p2 + 1;
153 if (quote && (len > 1)) buffer--;
154 *buffer = '\0';
158 /***********************************************************************
159 * PROFILE_Save
161 * Save a profile tree to a file.
163 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
165 PROFILEKEY *key;
166 char buffer[PROFILE_MAX_LINE_LEN];
168 for ( ; section; section = section->next)
170 if (section->name[0])
172 WideCharToMultiByte(CP_ACP, 0, section->name, -1, buffer, sizeof(buffer), NULL, NULL);
173 fprintf( file, "\r\n[%s]\r\n", buffer );
175 for (key = section->key; key; key = key->next)
177 WideCharToMultiByte(CP_ACP, 0, key->name, -1, buffer, sizeof(buffer), NULL, NULL);
178 fprintf( file, "%s", buffer );
179 if (key->value)
181 WideCharToMultiByte(CP_ACP, 0, key->value, -1, buffer, sizeof(buffer), NULL, NULL);
182 fprintf( file, "=%s", buffer );
184 fprintf( file, "\r\n" );
190 /***********************************************************************
191 * PROFILE_Free
193 * Free a profile tree.
195 static void PROFILE_Free( PROFILESECTION *section )
197 PROFILESECTION *next_section;
198 PROFILEKEY *key, *next_key;
200 for ( ; section; section = next_section)
202 for (key = section->key; key; key = next_key)
204 next_key = key->next;
205 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
206 HeapFree( GetProcessHeap(), 0, key );
208 next_section = section->next;
209 HeapFree( GetProcessHeap(), 0, section );
213 static inline int PROFILE_isspace(char c)
215 if (isspace(c)) return 1;
216 if (c=='\r' || c==0x1a) return 1;
217 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
218 return 0;
222 /***********************************************************************
223 * PROFILE_Load
225 * Load a profile tree from a file.
227 static PROFILESECTION *PROFILE_Load( FILE *file )
229 char buffer[PROFILE_MAX_LINE_LEN];
230 char *p, *p2;
231 int line = 0, len;
232 PROFILESECTION *section, *first_section;
233 PROFILESECTION **next_section;
234 PROFILEKEY *key, *prev_key, **next_key;
236 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
237 if(first_section == NULL) return NULL;
238 first_section->name[0] = 0;
239 first_section->key = NULL;
240 first_section->next = NULL;
241 next_section = &first_section->next;
242 next_key = &first_section->key;
243 prev_key = NULL;
245 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
247 line++;
248 p = buffer;
249 while (*p && PROFILE_isspace(*p)) p++;
250 if (*p == '[') /* section start */
252 if (!(p2 = strrchr( p, ']' )))
254 WARN("Invalid section header at line %d: '%s'\n",
255 line, p );
257 else
259 *p2 = '\0';
260 p++;
261 len = strlen(p);
262 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) )))
263 break;
264 MultiByteToWideChar(CP_ACP, 0, p, -1, section->name, len + 1);
265 section->key = NULL;
266 section->next = NULL;
267 *next_section = section;
268 next_section = &section->next;
269 next_key = &section->key;
270 prev_key = NULL;
272 TRACE("New section: %s\n", debugstr_w(section->name));
274 continue;
278 p2=p+strlen(p) - 1;
279 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
281 if ((p2 = strchr( p, '=' )) != NULL)
283 char *p3 = p2 - 1;
284 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
285 *p2++ = '\0';
286 while (*p2 && PROFILE_isspace(*p2)) p2++;
289 if(*p || !prev_key || *prev_key->name)
291 len = strlen(p);
292 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + len * sizeof(WCHAR) ))) break;
293 MultiByteToWideChar(CP_ACP, 0, p, -1, key->name, len + 1);
294 if (p2)
296 len = strlen(p2) + 1;
297 key->value = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
298 MultiByteToWideChar(CP_ACP, 0, p2, -1, key->value, len);
300 else key->value = NULL;
302 key->next = NULL;
303 *next_key = key;
304 next_key = &key->next;
305 prev_key = key;
307 TRACE("New key: name=%s, value=%s\n",
308 debugstr_w(key->name), key->value ? debugstr_w(key->value) : "(none)");
311 return first_section;
314 /* convert the .winerc file to the new format */
315 static void convert_config( FILE *in, const char *output_name )
317 char buffer[PROFILE_MAX_LINE_LEN];
318 char *p, *p2;
319 FILE *out;
321 /* create the output file, only if it doesn't exist already */
322 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
323 if (fd == -1)
325 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
326 ExitProcess(1);
329 out = fdopen( fd, "w" );
330 fprintf( out, "WINE REGISTRY Version 2\n" );
331 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
332 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
334 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
335 p = buffer;
336 while (*p && PROFILE_isspace(*p)) p++;
337 if (*p == '[') /* section start */
339 if ((p2 = strrchr( p, ']' )))
341 *p2 = '\0';
342 p++;
343 fprintf( out, "[%s]\n", p );
345 continue;
348 if (*p == ';' || *p == '#')
350 fprintf( out, "%s\n", p );
351 continue;
354 p2=p+strlen(p) - 1;
355 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
357 if ((p2 = strchr( p, '=' )) != NULL)
359 char *p3 = p2 - 1;
360 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
361 *p2++ = '\0';
362 while (*p2 && PROFILE_isspace(*p2)) p2++;
365 if (!*p)
367 fprintf( out, "\n" );
368 continue;
370 fputc( '"', out );
371 while (*p)
373 if (*p == '\\') fputc( '\\', out );
374 fputc( *p, out );
375 p++;
377 fprintf( out, "\" = \"" );
378 if (p2)
380 while (*p2)
382 if (*p2 == '\\') fputc( '\\', out );
383 fputc( *p2, out );
384 p2++;
387 fprintf( out, "\"\n" );
389 fclose( out );
393 /***********************************************************************
394 * PROFILE_DeleteSection
396 * Delete a section from a profile tree.
398 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCWSTR name )
400 while (*section)
402 if ((*section)->name[0] && !strcmpiW( (*section)->name, name ))
404 PROFILESECTION *to_del = *section;
405 *section = to_del->next;
406 to_del->next = NULL;
407 PROFILE_Free( to_del );
408 return TRUE;
410 section = &(*section)->next;
412 return FALSE;
416 /***********************************************************************
417 * PROFILE_DeleteKey
419 * Delete a key from a profile tree.
421 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
422 LPCWSTR section_name, LPCWSTR key_name )
424 while (*section)
426 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
428 PROFILEKEY **key = &(*section)->key;
429 while (*key)
431 if (!strcmpiW( (*key)->name, key_name ))
433 PROFILEKEY *to_del = *key;
434 *key = to_del->next;
435 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
436 HeapFree( GetProcessHeap(), 0, to_del );
437 return TRUE;
439 key = &(*key)->next;
442 section = &(*section)->next;
444 return FALSE;
448 /***********************************************************************
449 * PROFILE_DeleteAllKeys
451 * Delete all keys from a profile tree.
453 void PROFILE_DeleteAllKeys( LPCWSTR section_name)
455 PROFILESECTION **section= &CurProfile->section;
456 while (*section)
458 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
460 PROFILEKEY **key = &(*section)->key;
461 while (*key)
463 PROFILEKEY *to_del = *key;
464 *key = to_del->next;
465 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
466 HeapFree( GetProcessHeap(), 0, to_del );
467 CurProfile->changed =TRUE;
470 section = &(*section)->next;
475 /***********************************************************************
476 * PROFILE_Find
478 * Find a key in a profile tree, optionally creating it.
480 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, LPCWSTR section_name,
481 LPCWSTR key_name, BOOL create, BOOL create_always )
483 LPCWSTR p;
484 int seclen, keylen;
486 while (PROFILE_isspace(*section_name)) section_name++;
487 p = section_name + strlenW(section_name) - 1;
488 while ((p > section_name) && PROFILE_isspace(*p)) p--;
489 seclen = p - section_name + 1;
491 while (PROFILE_isspace(*key_name)) key_name++;
492 p = key_name + strlenW(key_name) - 1;
493 while ((p > key_name) && PROFILE_isspace(*p)) p--;
494 keylen = p - key_name + 1;
496 while (*section)
498 if ( ((*section)->name[0])
499 && (!(strncmpiW( (*section)->name, section_name, seclen )))
500 && (((*section)->name)[seclen] == '\0') )
502 PROFILEKEY **key = &(*section)->key;
504 while (*key)
506 /* If create_always is FALSE then we check if the keyname already exists.
507 * Otherwise we add it regardless of its existence, to allow
508 * keys to be added more then once in some cases.
510 if(!create_always)
512 if ( (!(strncmpiW( (*key)->name, key_name, keylen )))
513 && (((*key)->name)[keylen] == '\0') )
514 return *key;
516 key = &(*key)->next;
518 if (!create) return NULL;
519 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
520 return NULL;
521 strcpyW( (*key)->name, key_name );
522 (*key)->value = NULL;
523 (*key)->next = NULL;
524 return *key;
526 section = &(*section)->next;
528 if (!create) return NULL;
529 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlenW(section_name) * sizeof(WCHAR) );
530 if(*section == NULL) return NULL;
531 strcpyW( (*section)->name, section_name );
532 (*section)->next = NULL;
533 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
534 sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
536 HeapFree(GetProcessHeap(), 0, *section);
537 return NULL;
539 strcpyW( (*section)->key->name, key_name );
540 (*section)->key->value = NULL;
541 (*section)->key->next = NULL;
542 return (*section)->key;
546 /***********************************************************************
547 * PROFILE_FlushFile
549 * Flush the current profile to disk if changed.
551 static BOOL PROFILE_FlushFile(void)
553 char *p, buffer[MAX_PATHNAME_LEN];
554 const char *unix_name;
555 FILE *file = NULL;
556 struct stat buf;
558 if(!CurProfile)
560 WARN("No current profile!\n");
561 return FALSE;
564 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
565 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
567 int drive = toupperW(CurProfile->dos_name[0]) - 'A';
568 WCHAR *name, *name_lwr;
569 /* Try to create it in $HOME/.wine */
570 /* FIXME: this will need a more general solution */
571 strcpy( buffer, wine_get_config_dir() );
572 p = buffer + strlen(buffer);
573 *p++ = '/';
574 *p = 0; /* make strlen() below happy */
575 name = strrchrW( CurProfile->dos_name, '\\' ) + 1;
577 /* create a lower cased version of the name */
578 name_lwr = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
579 strcpyW(name_lwr, name);
580 strlwrW(name_lwr);
581 WideCharToMultiByte(DRIVE_GetCodepage(drive), 0, name_lwr, -1,
582 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
583 HeapFree(GetProcessHeap(), 0, name_lwr);
585 file = fopen( buffer, "w" );
586 unix_name = buffer;
589 if (!file)
591 WARN("could not save profile file %s\n", debugstr_w(CurProfile->dos_name));
592 return FALSE;
595 TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile->dos_name), unix_name );
596 PROFILE_Save( file, CurProfile->section );
597 fclose( file );
598 CurProfile->changed = FALSE;
599 if(!stat(unix_name,&buf))
600 CurProfile->mtime=buf.st_mtime;
601 return TRUE;
605 /***********************************************************************
606 * PROFILE_ReleaseFile
608 * Flush the current profile to disk and remove it from the cache.
610 static void PROFILE_ReleaseFile(void)
612 PROFILE_FlushFile();
613 PROFILE_Free( CurProfile->section );
614 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
615 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
616 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
617 CurProfile->changed = FALSE;
618 CurProfile->section = NULL;
619 CurProfile->dos_name = NULL;
620 CurProfile->unix_name = NULL;
621 CurProfile->filename = NULL;
622 CurProfile->mtime = 0;
626 /***********************************************************************
627 * PROFILE_Open
629 * Open a profile file, checking the cached file first.
631 static BOOL PROFILE_Open( LPCWSTR filename )
633 DOS_FULL_NAME full_name;
634 char buffer[MAX_PATHNAME_LEN];
635 WCHAR *newdos_name;
636 WCHAR *name, *name_lwr;
637 char *p;
638 FILE *file = NULL;
639 int i,j;
640 struct stat buf;
641 PROFILE *tempProfile;
643 /* First time around */
645 if(!CurProfile)
646 for(i=0;i<N_CACHED_PROFILES;i++)
648 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
649 if(MRUProfile[i] == NULL) break;
650 MRUProfile[i]->changed=FALSE;
651 MRUProfile[i]->section=NULL;
652 MRUProfile[i]->dos_name=NULL;
653 MRUProfile[i]->unix_name=NULL;
654 MRUProfile[i]->filename=NULL;
655 MRUProfile[i]->mtime=0;
658 /* Check for a match */
660 if (strchrW( filename, '/' ) || strchrW( filename, '\\' ) ||
661 strchrW( filename, ':' ))
663 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
665 else
667 static const WCHAR bkslashW[] = {'\\',0};
668 WCHAR windirW[MAX_PATH];
670 GetWindowsDirectoryW( windirW, MAX_PATH );
671 strcatW( windirW, bkslashW );
672 strcatW( windirW, filename );
673 if (!DOSFS_GetFullName( windirW, FALSE, &full_name )) return FALSE;
676 for(i=0;i<N_CACHED_PROFILES;i++)
678 if ((MRUProfile[i]->filename && !strcmpW( filename, MRUProfile[i]->filename )) ||
679 (MRUProfile[i]->dos_name && !strcmpW( full_name.short_name, MRUProfile[i]->dos_name )))
681 if(i)
683 PROFILE_FlushFile();
684 tempProfile=MRUProfile[i];
685 for(j=i;j>0;j--)
686 MRUProfile[j]=MRUProfile[j-1];
687 CurProfile=tempProfile;
689 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
690 TRACE("(%s): already opened (mru=%d)\n",
691 debugstr_w(filename), i );
692 else
693 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
694 debugstr_w(filename), i );
695 return TRUE;
699 /* Flush the old current profile */
700 PROFILE_FlushFile();
702 /* Make the oldest profile the current one only in order to get rid of it */
703 if(i==N_CACHED_PROFILES)
705 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
706 for(i=N_CACHED_PROFILES-1;i>0;i--)
707 MRUProfile[i]=MRUProfile[i-1];
708 CurProfile=tempProfile;
710 if(CurProfile->filename) PROFILE_ReleaseFile();
712 /* OK, now that CurProfile is definitely free we assign it our new file */
713 newdos_name = HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name.short_name)+1) * sizeof(WCHAR) );
714 strcpyW( newdos_name, full_name.short_name );
715 CurProfile->dos_name = newdos_name;
716 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, (strlenW(filename)+1) * sizeof(WCHAR) );
717 strcpyW( CurProfile->filename, filename );
719 /* Try to open the profile file, first in $HOME/.wine */
721 /* FIXME: this will need a more general solution */
722 strcpy( buffer, wine_get_config_dir() );
723 p = buffer + strlen(buffer);
724 *p++ = '/';
725 *p = 0; /* make strlen() below happy */
726 name = strrchrW( newdos_name, '\\' ) + 1;
728 /* create a lower cased version of the name */
729 name_lwr = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
730 strcpyW(name_lwr, name);
731 strlwrW(name_lwr);
732 WideCharToMultiByte(DRIVE_GetCodepage(full_name.drive), 0, name_lwr, -1,
733 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
734 HeapFree(GetProcessHeap(), 0, name_lwr);
736 if ((file = fopen( buffer, "r" )))
738 TRACE("(%s): found it in %s\n", debugstr_w(filename), buffer );
739 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
740 strcpy( CurProfile->unix_name, buffer );
742 else
744 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
745 strcpy( CurProfile->unix_name, full_name.long_name );
746 if ((file = fopen( full_name.long_name, "r" )))
747 TRACE("(%s): found it in %s\n",
748 debugstr_w(filename), full_name.long_name );
751 if (file)
753 CurProfile->section = PROFILE_Load( file );
754 fclose( file );
755 if(!stat(CurProfile->unix_name,&buf))
756 CurProfile->mtime=buf.st_mtime;
758 else
760 /* Does not exist yet, we will create it in PROFILE_FlushFile */
761 WARN("profile file %s not found\n", debugstr_w(newdos_name) );
763 return TRUE;
767 /***********************************************************************
768 * PROFILE_GetSection
770 * Returns all keys of a section.
771 * If return_values is TRUE, also include the corresponding values.
773 static INT PROFILE_GetSection( PROFILESECTION *section, LPCWSTR section_name,
774 LPWSTR buffer, UINT len, BOOL handle_env,
775 BOOL return_values )
777 PROFILEKEY *key;
779 if(!buffer) return 0;
781 TRACE("%s,%p,%u\n", debugstr_w(section_name), buffer, len);
783 while (section)
785 if (section->name[0] && !strcmpiW( section->name, section_name ))
787 UINT oldlen = len;
788 for (key = section->key; key; key = key->next)
790 if (len <= 2) break;
791 if (!*key->name) continue; /* Skip empty lines */
792 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
793 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env, 0 );
794 len -= strlenW(buffer) + 1;
795 buffer += strlenW(buffer) + 1;
796 if (len < 2)
797 break;
798 if (return_values && key->value) {
799 buffer[-1] = '=';
800 PROFILE_CopyEntry ( buffer,
801 key->value, len - 1, handle_env, 0 );
802 len -= strlenW(buffer) + 1;
803 buffer += strlenW(buffer) + 1;
806 *buffer = '\0';
807 if (len <= 1)
808 /*If either lpszSection or lpszKey is NULL and the supplied
809 destination buffer is too small to hold all the strings,
810 the last string is truncated and followed by two null characters.
811 In this case, the return value is equal to cchReturnBuffer
812 minus two. */
814 buffer[-1] = '\0';
815 return oldlen - 2;
817 return oldlen - len;
819 section = section->next;
821 buffer[0] = buffer[1] = '\0';
822 return 0;
825 /* See GetPrivateProfileSectionNamesA for documentation */
826 static INT PROFILE_GetSectionNames( LPWSTR buffer, UINT len )
828 LPWSTR buf;
829 UINT f,l;
830 PROFILESECTION *section;
832 if (!buffer || !len)
833 return 0;
834 if (len==1) {
835 *buffer='\0';
836 return 0;
839 f=len-1;
840 buf=buffer;
841 section = CurProfile->section;
842 while ((section!=NULL)) {
843 if (section->name[0]) {
844 l = strlenW(section->name)+1;
845 if (l > f) {
846 if (f>0) {
847 strncpyW(buf, section->name, f-1);
848 buf += f-1;
849 *buf++='\0';
851 *buf='\0';
852 return len-2;
854 strcpyW(buf, section->name);
855 buf += l;
856 f -= l;
858 section = section->next;
860 *buf='\0';
861 return buf-buffer;
865 /***********************************************************************
866 * PROFILE_GetString
868 * Get a profile string.
870 * Tests with GetPrivateProfileString16, W95a,
871 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
872 * section key_name def_val res buffer
873 * "set1" "1" "x" 43 [data]
874 * "set1" "1 " "x" 43 [data] (!)
875 * "set1" " 1 "' "x" 43 [data] (!)
876 * "set1" "" "x" 1 "x"
877 * "set1" "" "x " 1 "x" (!)
878 * "set1" "" " x " 3 " x" (!)
879 * "set1" NULL "x" 6 "1\02\03\0\0"
880 * "set1" "" "x" 1 "x"
881 * NULL "1" "x" 0 "" (!)
882 * "" "1" "x" 1 "x"
883 * NULL NULL "" 0 ""
887 static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name,
888 LPCWSTR def_val, LPWSTR buffer, UINT len )
890 PROFILEKEY *key = NULL;
891 static const WCHAR empty_strW[] = { 0 };
893 if(!buffer) return 0;
895 if (!def_val) def_val = empty_strW;
896 if (key_name)
898 if (!key_name[0])
900 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
901 return 0;
903 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
904 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
905 len, FALSE, TRUE );
906 TRACE("(%s,%s,%s): returning %s\n",
907 debugstr_w(section), debugstr_w(key_name),
908 debugstr_w(def_val), debugstr_w(buffer) );
909 return strlenW( buffer );
911 /* no "else" here ! */
912 if (section && section[0])
914 INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE, FALSE);
915 if (!buffer[0]) /* no luck -> def_val */
917 PROFILE_CopyEntry(buffer, def_val, len, FALSE, TRUE);
918 ret = strlenW(buffer);
920 return ret;
922 buffer[0] = '\0';
923 return 0;
927 /***********************************************************************
928 * PROFILE_SetString
930 * Set a profile string.
932 static BOOL PROFILE_SetString( LPCWSTR section_name, LPCWSTR key_name,
933 LPCWSTR value, BOOL create_always )
935 if (!key_name) /* Delete a whole section */
937 TRACE("(%s)\n", debugstr_w(section_name));
938 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
939 section_name );
940 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
941 this is not an error on application's level.*/
943 else if (!value) /* Delete a key */
945 TRACE("(%s,%s)\n", debugstr_w(section_name), debugstr_w(key_name) );
946 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
947 section_name, key_name );
948 return TRUE; /* same error handling as above */
950 else /* Set the key value */
952 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
953 key_name, TRUE, create_always );
954 TRACE("(%s,%s,%s):\n",
955 debugstr_w(section_name), debugstr_w(key_name), debugstr_w(value) );
956 if (!key) return FALSE;
957 if (key->value)
959 /* strip the leading spaces. We can safely strip \n\r and
960 * friends too, they should not happen here anyway. */
961 while (PROFILE_isspace(*value)) value++;
963 if (!strcmpW( key->value, value ))
965 TRACE(" no change needed\n" );
966 return TRUE; /* No change needed */
968 TRACE(" replacing %s\n", debugstr_w(key->value) );
969 HeapFree( GetProcessHeap(), 0, key->value );
971 else TRACE(" creating key\n" );
972 key->value = HeapAlloc( GetProcessHeap(), 0, (strlenW(value)+1) * sizeof(WCHAR) );
973 strcpyW( key->value, value );
974 CurProfile->changed = TRUE;
976 return TRUE;
980 /***********************************************************************
981 * PROFILE_GetWineIniString
983 * Get a config string from the wine.ini file.
985 int PROFILE_GetWineIniString( LPCWSTR section, LPCWSTR key_name,
986 LPCWSTR def, LPWSTR buffer, int len )
988 HKEY hkey;
989 NTSTATUS err;
990 OBJECT_ATTRIBUTES attr;
991 UNICODE_STRING nameW;
993 attr.Length = sizeof(attr);
994 attr.RootDirectory = wine_profile_key;
995 attr.ObjectName = &nameW;
996 attr.Attributes = 0;
997 attr.SecurityDescriptor = NULL;
998 attr.SecurityQualityOfService = NULL;
999 RtlInitUnicodeString( &nameW, section );
1000 if (!(err = NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )))
1002 char tmp[PROFILE_MAX_LINE_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
1003 DWORD count;
1005 RtlInitUnicodeString( &nameW, key_name );
1006 if (!(err = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1007 tmp, sizeof(tmp), &count )))
1009 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
1010 PROFILE_CopyEntry( buffer, str, len, TRUE, TRUE );
1012 NtClose( hkey );
1015 if (err) PROFILE_CopyEntry( buffer, def, len, TRUE, TRUE );
1016 TRACE( "(%s,%s,%s): returning %s\n", debugstr_w(section),
1017 debugstr_w(key_name), debugstr_w(def), debugstr_w(buffer) );
1018 return strlenW(buffer);
1022 /******************************************************************************
1024 * PROFILE_GetWineIniBool
1026 * Reads a boolean value from the wine.ini file. This function attempts to
1027 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
1028 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
1029 * true. Anything else results in the return of the default value.
1031 * This function uses 1 to indicate true, and 0 for false. You can check
1032 * for existence by setting def to something other than 0 or 1 and
1033 * examining the return value.
1035 int PROFILE_GetWineIniBool( LPCWSTR section, LPCWSTR key_name, int def )
1037 static const WCHAR def_valueW[] = {'~',0};
1038 WCHAR key_value[2];
1039 int retval;
1041 PROFILE_GetWineIniString(section, key_name, def_valueW, key_value, 2);
1043 switch(key_value[0]) {
1044 case 'n':
1045 case 'N':
1046 case 'f':
1047 case 'F':
1048 case '0':
1049 retval = 0;
1050 break;
1052 case 'y':
1053 case 'Y':
1054 case 't':
1055 case 'T':
1056 case '1':
1057 retval = 1;
1058 break;
1060 default:
1061 retval = def;
1064 TRACE("(%s, %s, %s), [%c], ret %s\n", debugstr_w(section), debugstr_w(key_name),
1065 def ? "TRUE" : "FALSE", key_value[0],
1066 retval ? "TRUE" : "FALSE");
1068 return retval;
1072 /***********************************************************************
1073 * PROFILE_LoadWineIni
1075 * Load the old .winerc file.
1077 int PROFILE_LoadWineIni(void)
1079 OBJECT_ATTRIBUTES attr;
1080 UNICODE_STRING nameW;
1081 char buffer[MAX_PATHNAME_LEN];
1082 const char *p;
1083 FILE *f;
1084 HKEY hKeySW;
1085 DWORD disp;
1087 attr.Length = sizeof(attr);
1088 attr.RootDirectory = 0;
1089 attr.ObjectName = &nameW;
1090 attr.Attributes = 0;
1091 attr.SecurityDescriptor = NULL;
1092 attr.SecurityQualityOfService = NULL;
1094 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1095 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1096 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1098 ERR("Cannot create config registry key\n" );
1099 ExitProcess( 1 );
1101 RtlFreeUnicodeString( &nameW );
1102 NtClose( hKeySW );
1104 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1105 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1106 NULL, REG_OPTION_VOLATILE, &disp ))
1108 ERR("Cannot create config registry key\n" );
1109 ExitProcess( 1 );
1111 RtlFreeUnicodeString( &nameW );
1113 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1115 if ((p = getenv( "HOME" )) != NULL)
1117 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1118 strcat( buffer, PROFILE_WineIniName );
1119 if ((f = fopen( buffer, "r" )) != NULL)
1121 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1123 /* convert to the new format */
1124 sprintf( buffer, "%s/config", wine_get_config_dir() );
1125 convert_config( f, buffer );
1126 fclose( f );
1128 MESSAGE( "The '%s' configuration file has been converted\n"
1129 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1130 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1131 "and then remove the old one and restart Wine.\n" );
1132 ExitProcess(0);
1135 else WARN("could not get $HOME value for config file.\n" );
1137 MESSAGE( "Can't open configuration file %s/config\n", wine_get_config_dir() );
1138 return 0;
1142 /***********************************************************************
1143 * PROFILE_UsageWineIni
1145 * Explain the wine.ini file to those who don't read documentation.
1146 * Keep below one screenful in length so that error messages above are
1147 * noticed.
1149 void PROFILE_UsageWineIni(void)
1151 MESSAGE("Perhaps you have not properly edited or created "
1152 "your Wine configuration file.\n");
1153 MESSAGE("This is (supposed to be) '%s/config'\n", wine_get_config_dir());
1154 /* RTFM, so to say */
1158 /********************* API functions **********************************/
1160 /***********************************************************************
1161 * GetProfileInt (KERNEL.57)
1163 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1165 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1169 /***********************************************************************
1170 * GetProfileIntA (KERNEL32.@)
1172 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1174 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1177 /***********************************************************************
1178 * GetProfileIntW (KERNEL32.@)
1180 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1182 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1186 * if allow_section_name_copy is TRUE, allow the copying :
1187 * - of Section names if 'section' is NULL
1188 * - of Keys in a Section if 'entry' is NULL
1189 * (see MSDN doc for GetPrivateProfileString)
1191 static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry,
1192 LPCWSTR def_val, LPWSTR buffer,
1193 UINT len, LPCWSTR filename,
1194 BOOL allow_section_name_copy )
1196 int ret;
1197 LPWSTR pDefVal = NULL;
1199 if (!filename)
1200 filename = wininiW;
1202 TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section), debugstr_w(entry),
1203 debugstr_w(def_val), buffer, len, debugstr_w(filename));
1205 /* strip any trailing ' ' of def_val. */
1206 if (def_val)
1208 LPCWSTR p = &def_val[strlenW(def_val)]; /* even "" works ! */
1210 while (p > def_val)
1212 p--;
1213 if ((*p) != ' ')
1214 break;
1216 if (*p == ' ') /* ouch, contained trailing ' ' */
1218 int len = (int)(p - def_val);
1219 pDefVal = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1220 strncpyW(pDefVal, def_val, len);
1221 pDefVal[len] = '\0';
1224 if (!pDefVal)
1225 pDefVal = (LPWSTR)def_val;
1227 EnterCriticalSection( &PROFILE_CritSect );
1229 if (PROFILE_Open( filename )) {
1230 if ((allow_section_name_copy) && (section == NULL))
1231 ret = PROFILE_GetSectionNames(buffer, len);
1232 else
1233 /* PROFILE_GetString already handles the 'entry == NULL' case */
1234 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1235 } else {
1236 lstrcpynW( buffer, pDefVal, len );
1237 ret = strlenW( buffer );
1240 LeaveCriticalSection( &PROFILE_CritSect );
1242 if (pDefVal != def_val) /* allocated */
1243 HeapFree(GetProcessHeap(), 0, pDefVal);
1245 TRACE("returning %s, %d\n", debugstr_w(buffer), ret);
1247 return ret;
1250 /***********************************************************************
1251 * GetPrivateProfileString (KERNEL.128)
1253 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1254 LPCSTR def_val, LPSTR buffer,
1255 UINT16 len, LPCSTR filename )
1257 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1258 LPWSTR bufferW;
1259 INT16 retW, ret = 0;
1261 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1262 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1263 else sectionW.Buffer = NULL;
1264 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1265 else entryW.Buffer = NULL;
1266 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1267 else def_valW.Buffer = NULL;
1268 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1269 else filenameW.Buffer = NULL;
1271 retW = PROFILE_GetPrivateProfileString( sectionW.Buffer, entryW.Buffer,
1272 def_valW.Buffer, bufferW, len,
1273 filenameW.Buffer, FALSE );
1274 if (len)
1276 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1277 if (!ret)
1279 ret = len - 1;
1280 buffer[ret] = 0;
1282 else
1283 ret--; /* strip terminating 0 */
1286 RtlFreeUnicodeString(&sectionW);
1287 RtlFreeUnicodeString(&entryW);
1288 RtlFreeUnicodeString(&def_valW);
1289 RtlFreeUnicodeString(&filenameW);
1290 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1291 return ret;
1294 /***********************************************************************
1295 * GetPrivateProfileStringA (KERNEL32.@)
1297 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1298 LPCSTR def_val, LPSTR buffer,
1299 UINT len, LPCSTR filename )
1301 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1302 LPWSTR bufferW;
1303 INT retW, ret = 0;
1305 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1306 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1307 else sectionW.Buffer = NULL;
1308 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1309 else entryW.Buffer = NULL;
1310 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1311 else def_valW.Buffer = NULL;
1312 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1313 else filenameW.Buffer = NULL;
1315 retW = GetPrivateProfileStringW( sectionW.Buffer, entryW.Buffer,
1316 def_valW.Buffer, bufferW, len,
1317 filenameW.Buffer);
1318 if (len)
1320 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1321 if (!ret)
1323 ret = len - 1;
1324 buffer[ret] = 0;
1326 else
1327 ret--; /* strip terminating 0 */
1330 RtlFreeUnicodeString(&sectionW);
1331 RtlFreeUnicodeString(&entryW);
1332 RtlFreeUnicodeString(&def_valW);
1333 RtlFreeUnicodeString(&filenameW);
1334 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1335 return ret;
1338 /***********************************************************************
1339 * GetPrivateProfileStringW (KERNEL32.@)
1341 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1342 LPCWSTR def_val, LPWSTR buffer,
1343 UINT len, LPCWSTR filename )
1345 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1346 buffer, len, filename, TRUE );
1349 /***********************************************************************
1350 * GetProfileString (KERNEL.58)
1352 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1353 LPSTR buffer, UINT16 len )
1355 return GetPrivateProfileString16( section, entry, def_val,
1356 buffer, len, "win.ini" );
1359 /***********************************************************************
1360 * GetProfileStringA (KERNEL32.@)
1362 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1363 LPSTR buffer, UINT len )
1365 return GetPrivateProfileStringA( section, entry, def_val,
1366 buffer, len, "win.ini" );
1369 /***********************************************************************
1370 * GetProfileStringW (KERNEL32.@)
1372 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1373 LPCWSTR def_val, LPWSTR buffer, UINT len )
1375 return GetPrivateProfileStringW( section, entry, def_val,
1376 buffer, len, wininiW );
1379 /***********************************************************************
1380 * WriteProfileString (KERNEL.59)
1382 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1383 LPCSTR string )
1385 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1388 /***********************************************************************
1389 * WriteProfileStringA (KERNEL32.@)
1391 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1392 LPCSTR string )
1394 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1397 /***********************************************************************
1398 * WriteProfileStringW (KERNEL32.@)
1400 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1401 LPCWSTR string )
1403 return WritePrivateProfileStringW( section, entry, string, wininiW );
1407 /***********************************************************************
1408 * GetPrivateProfileInt (KERNEL.127)
1410 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1411 INT16 def_val, LPCSTR filename )
1413 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1414 * here, but Win98SE doesn't care about this at all, so I deleted it.
1415 * AFAIR versions prior to Win9x had these limits, though. */
1416 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
1419 /***********************************************************************
1420 * GetPrivateProfileIntA (KERNEL32.@)
1422 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1423 INT def_val, LPCSTR filename )
1425 char buffer[20];
1426 long result;
1428 if (!GetPrivateProfileStringA( section, entry, "",
1429 buffer, sizeof(buffer), filename ))
1430 return def_val;
1431 /* FIXME: if entry can be found but it's empty, then Win16 is
1432 * supposed to return 0 instead of def_val ! Difficult/problematic
1433 * to implement (every other failure also returns zero buffer),
1434 * thus wait until testing framework avail for making sure nothing
1435 * else gets broken that way. */
1436 if (!buffer[0]) return (UINT)def_val;
1438 /* Don't use strtol() here !
1439 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1440 YES, scan for unsigned format ! (otherwise compatibility error) */
1441 if (!sscanf(buffer, "%lu", &result)) return 0;
1442 return (UINT)result;
1445 /***********************************************************************
1446 * GetPrivateProfileIntW (KERNEL32.@)
1448 * FIXME: rewrite using unicode
1450 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1451 INT def_val, LPCWSTR filename )
1453 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1454 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1455 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1456 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1457 HeapFree( GetProcessHeap(), 0, sectionA );
1458 HeapFree( GetProcessHeap(), 0, filenameA );
1459 HeapFree( GetProcessHeap(), 0, entryA );
1460 return res;
1463 /***********************************************************************
1464 * GetPrivateProfileSection (KERNEL.418)
1466 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1467 UINT16 len, LPCSTR filename )
1469 return GetPrivateProfileSectionA( section, buffer, len, filename );
1472 /***********************************************************************
1473 * GetPrivateProfileSectionW (KERNEL32.@)
1475 INT WINAPI GetPrivateProfileSectionW( LPCWSTR section, LPWSTR buffer,
1476 DWORD len, LPCWSTR filename )
1478 int ret = 0;
1480 EnterCriticalSection( &PROFILE_CritSect );
1482 if (PROFILE_Open( filename ))
1483 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1484 FALSE, TRUE);
1486 LeaveCriticalSection( &PROFILE_CritSect );
1488 return ret;
1491 /***********************************************************************
1492 * GetPrivateProfileSectionA (KERNEL32.@)
1494 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1495 DWORD len, LPCSTR filename )
1497 UNICODE_STRING sectionW, filenameW;
1498 LPWSTR bufferW;
1499 INT retW, ret = 0;
1501 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1502 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1503 else sectionW.Buffer = NULL;
1504 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1505 else filenameW.Buffer = NULL;
1507 retW = GetPrivateProfileSectionW(sectionW.Buffer, bufferW, len, filenameW.Buffer);
1508 if (len > 2)
1510 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 2, buffer, len, NULL, NULL);
1511 if (ret > 2)
1512 ret -= 2;
1513 else
1515 ret = 0;
1516 buffer[len-2] = 0;
1517 buffer[len-1] = 0;
1520 else
1522 buffer[0] = 0;
1523 buffer[1] = 0;
1526 RtlFreeUnicodeString(&sectionW);
1527 RtlFreeUnicodeString(&filenameW);
1528 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1529 return ret;
1532 /***********************************************************************
1533 * GetProfileSection (KERNEL.419)
1535 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1537 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1540 /***********************************************************************
1541 * GetProfileSectionA (KERNEL32.@)
1543 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1545 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1548 /***********************************************************************
1549 * GetProfileSectionW (KERNEL32.@)
1551 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1553 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1557 /***********************************************************************
1558 * WritePrivateProfileString (KERNEL.129)
1560 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1561 LPCSTR string, LPCSTR filename )
1563 return WritePrivateProfileStringA(section,entry,string,filename);
1566 /***********************************************************************
1567 * WritePrivateProfileStringW (KERNEL32.@)
1569 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1570 LPCWSTR string, LPCWSTR filename )
1572 BOOL ret = FALSE;
1574 EnterCriticalSection( &PROFILE_CritSect );
1576 if (PROFILE_Open( filename ))
1578 if (!section && !entry && !string) /* documented "file flush" case */
1580 PROFILE_FlushFile();
1581 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1583 else {
1584 if (!section) {
1585 FIXME("(NULL?,%s,%s,%s)?\n",
1586 debugstr_w(entry), debugstr_w(string), debugstr_w(filename));
1587 } else {
1588 ret = PROFILE_SetString( section, entry, string, FALSE);
1589 PROFILE_FlushFile();
1594 LeaveCriticalSection( &PROFILE_CritSect );
1595 return ret;
1598 /***********************************************************************
1599 * WritePrivateProfileStringA (KERNEL32.@)
1601 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1602 LPCSTR string, LPCSTR filename )
1604 UNICODE_STRING sectionW, entryW, stringW, filenameW;
1605 BOOL ret;
1607 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1608 else sectionW.Buffer = NULL;
1609 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1610 else entryW.Buffer = NULL;
1611 if (string) RtlCreateUnicodeStringFromAsciiz(&stringW, string);
1612 else stringW.Buffer = NULL;
1613 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1614 else filenameW.Buffer = NULL;
1616 ret = WritePrivateProfileStringW(sectionW.Buffer, entryW.Buffer,
1617 stringW.Buffer, filenameW.Buffer);
1618 RtlFreeUnicodeString(&sectionW);
1619 RtlFreeUnicodeString(&entryW);
1620 RtlFreeUnicodeString(&stringW);
1621 RtlFreeUnicodeString(&filenameW);
1622 return ret;
1625 /***********************************************************************
1626 * WritePrivateProfileSection (KERNEL.416)
1628 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1629 LPCSTR string, LPCSTR filename )
1631 return WritePrivateProfileSectionA( section, string, filename );
1634 /***********************************************************************
1635 * WritePrivateProfileSectionW (KERNEL32.@)
1637 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1638 LPCWSTR string, LPCWSTR filename )
1640 BOOL ret = FALSE;
1641 LPWSTR p;
1643 EnterCriticalSection( &PROFILE_CritSect );
1645 if (PROFILE_Open( filename )) {
1646 if (!section && !string)
1647 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1648 else if (!string) {/* delete the named section*/
1649 ret = PROFILE_SetString(section,NULL,NULL, FALSE);
1650 PROFILE_FlushFile();
1651 } else {
1652 PROFILE_DeleteAllKeys(section);
1653 ret = TRUE;
1654 while(*string) {
1655 LPWSTR buf = HeapAlloc( GetProcessHeap(), 0, (strlenW(string)+1) * sizeof(WCHAR) );
1656 strcpyW( buf, string );
1657 if((p = strchrW( buf, '='))) {
1658 *p='\0';
1659 ret = PROFILE_SetString( section, buf, p+1, TRUE);
1661 HeapFree( GetProcessHeap(), 0, buf );
1662 string += strlenW(string)+1;
1664 PROFILE_FlushFile();
1668 LeaveCriticalSection( &PROFILE_CritSect );
1669 return ret;
1672 /***********************************************************************
1673 * WritePrivateProfileSectionA (KERNEL32.@)
1675 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1676 LPCSTR string, LPCSTR filename)
1679 UNICODE_STRING sectionW, filenameW;
1680 LPWSTR stringW;
1681 BOOL ret;
1683 if (string)
1685 INT lenA, lenW;
1686 LPCSTR p = string;
1688 while(*p) p += strlen(p) + 1;
1689 lenA = p - string + 1;
1690 lenW = MultiByteToWideChar(CP_ACP, 0, string, lenA, NULL, 0);
1691 if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR))))
1692 MultiByteToWideChar(CP_ACP, 0, string, lenA, stringW, lenW);
1694 else stringW = NULL;
1695 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1696 else sectionW.Buffer = NULL;
1697 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1698 else filenameW.Buffer = NULL;
1700 ret = WritePrivateProfileSectionW(sectionW.Buffer, stringW, filenameW.Buffer);
1702 HeapFree(GetProcessHeap(), 0, stringW);
1703 RtlFreeUnicodeString(&sectionW);
1704 RtlFreeUnicodeString(&filenameW);
1705 return ret;
1708 /***********************************************************************
1709 * WriteProfileSection (KERNEL.417)
1711 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1713 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1716 /***********************************************************************
1717 * WriteProfileSectionA (KERNEL32.@)
1719 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1722 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1725 /***********************************************************************
1726 * WriteProfileSectionW (KERNEL32.@)
1728 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1730 return WritePrivateProfileSectionW(section, keys_n_values, wininiW);
1733 /***********************************************************************
1734 * GetPrivateProfileSectionNames (KERNEL.143)
1736 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1737 LPCSTR filename )
1739 return GetPrivateProfileSectionNamesA(buffer,size,filename);
1743 /***********************************************************************
1744 * GetProfileSectionNames (KERNEL.142)
1746 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
1749 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
1753 /***********************************************************************
1754 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1756 * Returns the section names contained in the specified file.
1757 * FIXME: Where do we find this file when the path is relative?
1758 * The section names are returned as a list of strings with an extra
1759 * '\0' to mark the end of the list. Except for that the behavior
1760 * depends on the Windows version.
1762 * Win95:
1763 * - if the buffer is 0 or 1 character long then it is as if it was of
1764 * infinite length.
1765 * - otherwise, if the buffer is to small only the section names that fit
1766 * are returned.
1767 * - note that this means if the buffer was to small to return even just
1768 * the first section name then a single '\0' will be returned.
1769 * - the return value is the number of characters written in the buffer,
1770 * except if the buffer was too smal in which case len-2 is returned
1772 * Win2000:
1773 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1774 * '\0' and the return value is 0
1775 * - otherwise if the buffer is too small then the first section name that
1776 * does not fit is truncated so that the string list can be terminated
1777 * correctly (double '\0')
1778 * - the return value is the number of characters written in the buffer
1779 * except for the trailing '\0'. If the buffer is too small, then the
1780 * return value is len-2
1781 * - Win2000 has a bug that triggers when the section names and the
1782 * trailing '\0' fit exactly in the buffer. In that case the trailing
1783 * '\0' is missing.
1785 * Wine implements the observed Win2000 behavior (except for the bug).
1787 * Note that when the buffer is big enough then the return value may be any
1788 * value between 1 and len-1 (or len in Win95), including len-2.
1790 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1791 LPCWSTR filename)
1793 DWORD ret = 0;
1795 EnterCriticalSection( &PROFILE_CritSect );
1797 if (PROFILE_Open( filename ))
1798 ret = PROFILE_GetSectionNames(buffer, size);
1800 LeaveCriticalSection( &PROFILE_CritSect );
1802 return ret;
1806 /***********************************************************************
1807 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1809 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1810 LPCSTR filename)
1812 UNICODE_STRING filenameW;
1813 LPWSTR bufferW;
1814 INT retW, ret = 0;
1816 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)) : NULL;
1817 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1818 else filenameW.Buffer = NULL;
1820 retW = GetPrivateProfileSectionNamesW(bufferW, size, filenameW.Buffer);
1821 if (retW && size)
1823 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW, buffer, size, NULL, NULL);
1824 if (!ret)
1826 ret = size;
1827 buffer[size-1] = 0;
1831 RtlFreeUnicodeString(&filenameW);
1832 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1833 return ret;
1836 /***********************************************************************
1837 * GetPrivateProfileStruct (KERNEL.407)
1839 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1840 LPVOID buf, UINT16 len, LPCSTR filename)
1842 return GetPrivateProfileStructA( section, key, buf, len, filename );
1845 /***********************************************************************
1846 * GetPrivateProfileStructW (KERNEL32.@)
1848 * Should match Win95's behaviour pretty much
1850 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1851 LPVOID buf, UINT len, LPCWSTR filename)
1853 BOOL ret = FALSE;
1855 EnterCriticalSection( &PROFILE_CritSect );
1857 if (PROFILE_Open( filename )) {
1858 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
1859 if (k) {
1860 TRACE("value (at %p): %s\n", k->value, debugstr_w(k->value));
1861 if (((strlenW(k->value) - 2) / 2) == len)
1863 LPWSTR end, p;
1864 BOOL valid = TRUE;
1865 WCHAR c;
1866 DWORD chksum = 0;
1868 end = k->value + strlenW(k->value); /* -> '\0' */
1869 /* check for invalid chars in ASCII coded hex string */
1870 for (p=k->value; p < end; p++)
1872 if (!isxdigitW(*p))
1874 WARN("invalid char '%x' in file %s->[%s]->%s !\n",
1875 *p, debugstr_w(filename), debugstr_w(section), debugstr_w(key));
1876 valid = FALSE;
1877 break;
1880 if (valid)
1882 BOOL highnibble = TRUE;
1883 BYTE b = 0, val;
1884 LPBYTE binbuf = (LPBYTE)buf;
1886 end -= 2; /* don't include checksum in output data */
1887 /* translate ASCII hex format into binary data */
1888 for (p=k->value; p < end; p++)
1890 c = toupperW(*p);
1891 val = (c > '9') ?
1892 (c - 'A' + 10) : (c - '0');
1894 if (highnibble)
1895 b = val << 4;
1896 else
1898 b += val;
1899 *binbuf++ = b; /* feed binary data into output */
1900 chksum += b; /* calculate checksum */
1902 highnibble ^= 1; /* toggle */
1904 /* retrieve stored checksum value */
1905 c = toupperW(*p++);
1906 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1907 c = toupperW(*p);
1908 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1909 if (b == (chksum & 0xff)) /* checksums match ? */
1910 ret = TRUE;
1915 LeaveCriticalSection( &PROFILE_CritSect );
1917 return ret;
1920 /***********************************************************************
1921 * GetPrivateProfileStructA (KERNEL32.@)
1923 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1924 LPVOID buffer, UINT len, LPCSTR filename)
1926 UNICODE_STRING sectionW, keyW, filenameW;
1927 INT ret;
1929 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1930 else sectionW.Buffer = NULL;
1931 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
1932 else keyW.Buffer = NULL;
1933 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1934 else filenameW.Buffer = NULL;
1936 ret = GetPrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buffer, len,
1937 filenameW.Buffer);
1938 /* Do not translate binary data. */
1940 RtlFreeUnicodeString(&sectionW);
1941 RtlFreeUnicodeString(&keyW);
1942 RtlFreeUnicodeString(&filenameW);
1943 return ret;
1948 /***********************************************************************
1949 * WritePrivateProfileStruct (KERNEL.406)
1951 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1952 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1954 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1957 /***********************************************************************
1958 * WritePrivateProfileStructW (KERNEL32.@)
1960 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1961 LPVOID buf, UINT bufsize, LPCWSTR filename)
1963 BOOL ret = FALSE;
1964 LPBYTE binbuf;
1965 LPWSTR outstring, p;
1966 DWORD sum = 0;
1968 if (!section && !key && !buf) /* flush the cache */
1969 return WritePrivateProfileStringW( NULL, NULL, NULL, filename );
1971 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1972 outstring = HeapAlloc( GetProcessHeap(), 0, (bufsize*2 + 2 + 1) * sizeof(WCHAR) );
1973 p = outstring;
1974 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1975 *p++ = hex[*binbuf >> 4];
1976 *p++ = hex[*binbuf & 0xf];
1977 sum += *binbuf;
1979 /* checksum is sum & 0xff */
1980 *p++ = hex[(sum & 0xf0) >> 4];
1981 *p++ = hex[sum & 0xf];
1982 *p++ = '\0';
1984 EnterCriticalSection( &PROFILE_CritSect );
1986 if (PROFILE_Open( filename )) {
1987 ret = PROFILE_SetString( section, key, outstring, FALSE);
1988 PROFILE_FlushFile();
1991 LeaveCriticalSection( &PROFILE_CritSect );
1993 HeapFree( GetProcessHeap(), 0, outstring );
1995 return ret;
1998 /***********************************************************************
1999 * WritePrivateProfileStructA (KERNEL32.@)
2001 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
2002 LPVOID buf, UINT bufsize, LPCSTR filename)
2004 UNICODE_STRING sectionW, keyW, filenameW;
2005 INT ret;
2007 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
2008 else sectionW.Buffer = NULL;
2009 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
2010 else keyW.Buffer = NULL;
2011 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
2012 else filenameW.Buffer = NULL;
2014 /* Do not translate binary data. */
2015 ret = WritePrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buf, bufsize,
2016 filenameW.Buffer);
2018 RtlFreeUnicodeString(&sectionW);
2019 RtlFreeUnicodeString(&keyW);
2020 RtlFreeUnicodeString(&filenameW);
2021 return ret;
2025 /***********************************************************************
2026 * WriteOutProfiles (KERNEL.315)
2028 void WINAPI WriteOutProfiles16(void)
2030 EnterCriticalSection( &PROFILE_CritSect );
2031 PROFILE_FlushFile();
2032 LeaveCriticalSection( &PROFILE_CritSect );
2035 /***********************************************************************
2036 * CloseProfileUserMapping (KERNEL32.@)
2038 BOOL WINAPI CloseProfileUserMapping(void) {
2039 FIXME("(), stub!\n");
2040 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2041 return FALSE;