Fix use of LOCALE_NOUSEROVERRIDE flag in GetNumberFormatA and
[wine.git] / files / profile.c
blob455e1b0c6807d6d8ee798660ada9522ce5a922a9
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 <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <pwd.h>
31 #include <unistd.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winnls.h"
36 #include "winerror.h"
37 #include "wine/winbase16.h"
38 #include "winreg.h"
39 #include "file.h"
40 #include "heap.h"
41 #include "wine/debug.h"
42 #include "wine/server.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(profile);
46 typedef struct tagPROFILEKEY
48 char *value;
49 struct tagPROFILEKEY *next;
50 char name[1];
51 } PROFILEKEY;
53 typedef struct tagPROFILESECTION
55 struct tagPROFILEKEY *key;
56 struct tagPROFILESECTION *next;
57 char name[1];
58 } PROFILESECTION;
61 typedef struct
63 BOOL changed;
64 PROFILESECTION *section;
65 char *dos_name;
66 char *unix_name;
67 char *filename;
68 time_t mtime;
69 } PROFILE;
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 /***********************************************************************
100 * PROFILE_CopyEntry
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,
106 int handle_env )
108 char quote = '\0';
109 const char *p;
111 if(!buffer) return;
113 if ((*value == '\'') || (*value == '\"'))
115 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
118 if (!handle_env)
120 lstrcpynA( buffer, value, len );
121 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
122 return;
125 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
127 if ((*p == '$') && (p[1] == '{'))
129 char env_val[1024];
130 const char *env_p;
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)
136 int buffer_len;
137 lstrcpynA( buffer, env_p, len );
138 buffer_len = strlen( buffer );
139 buffer += buffer_len;
140 len -= buffer_len;
142 p = p2 + 1;
145 if (quote && (len > 1)) buffer--;
146 *buffer = '\0';
150 /***********************************************************************
151 * PROFILE_Save
153 * Save a profile tree to a file.
155 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
157 PROFILEKEY *key;
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 /***********************************************************************
173 * PROFILE_Free
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) */
200 return 0;
204 /***********************************************************************
205 * PROFILE_Load
207 * Load a profile tree from a file.
209 static PROFILESECTION *PROFILE_Load( FILE *file )
211 char buffer[PROFILE_MAX_LINE_LEN];
212 char *p, *p2;
213 int line = 0;
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;
225 prev_key = NULL;
227 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
229 line++;
230 p = buffer;
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",
237 line, p );
239 else
241 *p2 = '\0';
242 p++;
243 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + strlen(p) )))
244 break;
245 strcpy( section->name, p );
246 section->key = NULL;
247 section->next = NULL;
248 *next_section = section;
249 next_section = &section->next;
250 next_key = &section->key;
251 prev_key = NULL;
253 TRACE("New section: '%s'\n",section->name);
255 continue;
259 p2=p+strlen(p) - 1;
260 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
262 if ((p2 = strchr( p, '=' )) != NULL)
264 char *p3 = p2 - 1;
265 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
266 *p2++ = '\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 );
274 if (p2)
276 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(p2)+1 );
277 strcpy( key->value, p2 );
279 else key->value = NULL;
281 key->next = NULL;
282 *next_key = key;
283 next_key = &key->next;
284 prev_key = key;
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];
296 char *p, *p2;
297 FILE *out;
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 );
301 if (fd == -1)
303 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
304 ExitProcess(1);
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;
313 p = buffer;
314 while (*p && PROFILE_isspace(*p)) p++;
315 if (*p == '[') /* section start */
317 if ((p2 = strrchr( p, ']' )))
319 *p2 = '\0';
320 p++;
321 fprintf( out, "[%s]\n", p );
323 continue;
326 if (*p == ';' || *p == '#')
328 fprintf( out, "%s\n", p );
329 continue;
332 p2=p+strlen(p) - 1;
333 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
335 if ((p2 = strchr( p, '=' )) != NULL)
337 char *p3 = p2 - 1;
338 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
339 *p2++ = '\0';
340 while (*p2 && PROFILE_isspace(*p2)) p2++;
343 if (!*p)
345 fprintf( out, "\n" );
346 continue;
348 fputc( '"', out );
349 while (*p)
351 if (*p == '\\') fputc( '\\', out );
352 fputc( *p, out );
353 p++;
355 fprintf( out, "\" = \"" );
356 if (p2)
358 while (*p2)
360 if (*p2 == '\\') fputc( '\\', out );
361 fputc( *p2, out );
362 p2++;
365 fprintf( out, "\"\n" );
367 fclose( out );
371 /***********************************************************************
372 * PROFILE_DeleteSection
374 * Delete a section from a profile tree.
376 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
378 while (*section)
380 if ((*section)->name[0] && !strcasecmp( (*section)->name, name ))
382 PROFILESECTION *to_del = *section;
383 *section = to_del->next;
384 to_del->next = NULL;
385 PROFILE_Free( to_del );
386 return TRUE;
388 section = &(*section)->next;
390 return FALSE;
394 /***********************************************************************
395 * PROFILE_DeleteKey
397 * Delete a key from a profile tree.
399 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
400 LPCSTR section_name, LPCSTR key_name )
402 while (*section)
404 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
406 PROFILEKEY **key = &(*section)->key;
407 while (*key)
409 if (!strcasecmp( (*key)->name, key_name ))
411 PROFILEKEY *to_del = *key;
412 *key = to_del->next;
413 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
414 HeapFree( GetProcessHeap(), 0, to_del );
415 return TRUE;
417 key = &(*key)->next;
420 section = &(*section)->next;
422 return FALSE;
426 /***********************************************************************
427 * PROFILE_DeleteAllKeys
429 * Delete all keys from a profile tree.
431 void PROFILE_DeleteAllKeys( LPCSTR section_name)
433 PROFILESECTION **section= &CurProfile->section;
434 while (*section)
436 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
438 PROFILEKEY **key = &(*section)->key;
439 while (*key)
441 PROFILEKEY *to_del = *key;
442 *key = to_del->next;
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 /***********************************************************************
454 * PROFILE_Find
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 )
461 const char *p;
462 int seclen, keylen;
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;
474 while (*section)
476 if ( ((*section)->name[0])
477 && (!(strncasecmp( (*section)->name, section_name, seclen )))
478 && (((*section)->name)[seclen] == '\0') )
480 PROFILEKEY **key = &(*section)->key;
482 while (*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.
488 if(!create_always)
490 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
491 && (((*key)->name)[keylen] == '\0') )
492 return *key;
494 key = &(*key)->next;
496 if (!create) return NULL;
497 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlen(key_name) )))
498 return NULL;
499 strcpy( (*key)->name, key_name );
500 (*key)->value = NULL;
501 (*key)->next = NULL;
502 return *key;
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);
515 return NULL;
517 strcpy( (*section)->key->name, key_name );
518 (*section)->key->value = NULL;
519 (*section)->key->next = NULL;
520 return (*section)->key;
524 /***********************************************************************
525 * PROFILE_FlushFile
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;
533 FILE *file = NULL;
534 struct stat buf;
536 if(!CurProfile)
538 WARN("No current profile!\n");
539 return FALSE;
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);
549 *p++ = '/';
550 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
551 _strlwr( p );
552 file = fopen( buffer, "w" );
553 unix_name = buffer;
556 if (!file)
558 WARN("could not save profile file %s\n", CurProfile->dos_name);
559 return FALSE;
562 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
563 PROFILE_Save( file, CurProfile->section );
564 fclose( file );
565 CurProfile->changed = FALSE;
566 if(!stat(unix_name,&buf))
567 CurProfile->mtime=buf.st_mtime;
568 return TRUE;
572 /***********************************************************************
573 * PROFILE_ReleaseFile
575 * Flush the current profile to disk and remove it from the cache.
577 static void PROFILE_ReleaseFile(void)
579 PROFILE_FlushFile();
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 /***********************************************************************
594 * PROFILE_Open
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;
603 FILE *file = NULL;
604 int i,j;
605 struct stat buf;
606 PROFILE *tempProfile;
608 /* First time around */
610 if(!CurProfile)
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;
630 else
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 )))
643 if(i)
645 PROFILE_FlushFile();
646 tempProfile=MRUProfile[i];
647 for(j=i;j>0;j--)
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",
653 filename, i );
654 else
655 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
656 filename, i );
657 return TRUE;
661 /* Flush the old current profile */
662 PROFILE_FlushFile();
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);
686 *p++ = '/';
687 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
688 _strlwr( p );
689 if ((file = fopen( buffer, "r" )))
691 TRACE("(%s): found it in %s\n",
692 filename, buffer );
693 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
694 strcpy( CurProfile->unix_name, buffer );
697 if (!file)
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 );
706 if (file)
708 CurProfile->section = PROFILE_Load( file );
709 fclose( file );
710 if(!stat(CurProfile->unix_name,&buf))
711 CurProfile->mtime=buf.st_mtime;
713 else
715 /* Does not exist yet, we will create it in PROFILE_FlushFile */
716 WARN("profile file %s not found\n", newdos_name );
718 return TRUE;
722 /***********************************************************************
723 * PROFILE_GetSection
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,
730 BOOL return_values )
732 PROFILEKEY *key;
734 if(!buffer) return 0;
736 while (section)
738 if (section->name[0] && !strcasecmp( section->name, section_name ))
740 UINT oldlen = len;
741 for (key = section->key; key; key = key->next)
743 if (len <= 2) break;
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;
749 if (len < 2)
750 break;
751 if (return_values && key->value) {
752 buffer[-1] = '=';
753 PROFILE_CopyEntry ( buffer,
754 key->value, len - 1, handle_env );
755 len -= strlen(buffer) + 1;
756 buffer += strlen(buffer) + 1;
759 *buffer = '\0';
760 if (len <= 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
765 minus two. */
767 buffer[-1] = '\0';
768 return oldlen - 2;
770 return oldlen - len;
772 section = section->next;
774 buffer[0] = buffer[1] = '\0';
775 return 0;
778 /* See GetPrivateProfileSectionNamesA for documentation */
779 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
781 LPSTR buf;
782 UINT f,l;
783 PROFILESECTION *section;
785 if (!buffer || !len)
786 return 0;
787 if (len==1) {
788 *buffer='\0';
789 return 0;
792 f=len-1;
793 buf=buffer;
794 section = CurProfile->section;
795 while ((section!=NULL)) {
796 if (section->name[0]) {
797 l = strlen(section->name)+1;
798 if (l > f) {
799 if (f>0) {
800 strncpy(buf, section->name, f-1);
801 buf += f-1;
802 *buf++='\0';
804 *buf='\0';
805 return len-2;
807 strcpy(buf, section->name);
808 buf += l;
809 f -= l;
811 section = section->next;
813 *buf='\0';
814 return buf-buffer;
818 /***********************************************************************
819 * PROFILE_GetString
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 "" (!)
835 * "" "1" "x" 1 "x"
836 * NULL NULL "" 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 = "";
848 if (key_name)
850 if (!key_name[0])
851 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
852 return 0;
853 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
854 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
855 len, FALSE );
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,
864 FALSE, FALSE);
865 if (!buffer[0]) /* no luck -> def_val */
866 PROFILE_CopyEntry(buffer, def_val, len, FALSE);
867 return strlen(buffer);
869 buffer[0] = '\0';
870 return 0;
874 /***********************************************************************
875 * PROFILE_SetString
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,
886 section_name );
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;
905 if (key->value)
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;
924 return 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];
937 HKEY hkey;
938 DWORD err;
940 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
942 DWORD type;
943 DWORD count = sizeof(tmp);
944 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
945 RegCloseKey( hkey );
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,
958 * int def )
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(
970 char const *section,
971 char const *key_name,
972 int def )
974 char key_value[2];
975 int retval;
977 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
979 switch(key_value[0]) {
980 case 'n':
981 case 'N':
982 case 'f':
983 case 'F':
984 case '0':
985 retval = 0;
986 break;
988 case 'y':
989 case 'Y':
990 case 't':
991 case 'T':
992 case '1':
993 retval = 1;
994 break;
996 default:
997 retval = def;
1000 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name,
1001 def ? "TRUE" : "FALSE", key_value[0],
1002 retval ? "TRUE" : "FALSE");
1004 return retval;
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];
1018 const char *p;
1019 FILE *f;
1020 HKEY hKeySW;
1021 DWORD disp;
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" );
1035 ExitProcess( 1 );
1037 RtlFreeUnicodeString( &nameW );
1038 NtClose( hKeySW );
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" );
1045 ExitProcess( 1 );
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);
1058 goto found;
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() );
1066 return 0;
1068 found:
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 );
1074 fclose( f );
1075 return 1;
1078 /* convert to the new format */
1079 sprintf( buffer, "%s/config", get_config_dir() );
1080 convert_config( f, buffer );
1081 fclose( f );
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" );
1087 ExitProcess(0);
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
1096 * noticed.
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 )
1145 int ret;
1146 LPSTR pDefVal = NULL;
1148 if (!filename)
1149 filename = "win.ini";
1151 /* strip any trailing ' ' of def_val. */
1152 if (def_val)
1154 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1156 while (p > def_val)
1158 p--;
1159 if ((*p) != ' ')
1160 break;
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';
1170 if (!pDefVal)
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);
1178 else
1179 /* PROFILE_GetString already handles the 'entry == NULL' case */
1180 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1181 } else {
1182 lstrcpynA( buffer, pDefVal, len );
1183 ret = strlen( buffer );
1186 LeaveCriticalSection( &PROFILE_CritSect );
1188 if (pDefVal != def_val) /* allocated */
1189 HeapFree(GetProcessHeap(), 0, pDefVal);
1191 return ret;
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 ))
1231 buffer[len-1] = 0;
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);
1237 return ret;
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,
1274 LPCSTR string )
1276 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1279 /***********************************************************************
1280 * WriteProfileStringA (KERNEL32.@)
1282 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1283 LPCSTR string )
1285 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1288 /***********************************************************************
1289 * WriteProfileStringW (KERNEL32.@)
1291 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1292 LPCWSTR string )
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 )
1316 char buffer[20];
1317 long result;
1319 if (!PROFILE_GetPrivateProfileString( section, entry, "",
1320 buffer, sizeof(buffer), filename, FALSE ))
1321 return def_val;
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 );
1349 return res;
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 )
1367 int ret = 0;
1369 EnterCriticalSection( &PROFILE_CritSect );
1371 if (PROFILE_Open( filename ))
1372 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1373 FALSE, TRUE);
1375 LeaveCriticalSection( &PROFILE_CritSect );
1377 return ret;
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,
1392 filenameA );
1393 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1394 HeapFree( GetProcessHeap(), 0, sectionA );
1395 HeapFree( GetProcessHeap(), 0, filenameA );
1396 HeapFree( GetProcessHeap(), 0, bufferA);
1397 return ret;
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 )
1440 BOOL ret = FALSE;
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 */
1448 else {
1449 if (!section) {
1450 FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename);
1451 } else {
1452 ret = PROFILE_SetString( section, entry, string, FALSE);
1457 LeaveCriticalSection( &PROFILE_CritSect );
1458 return ret;
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 );
1477 return res;
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 )
1495 BOOL ret = FALSE;
1496 LPSTR p ;
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);
1505 else {
1506 PROFILE_DeleteAllKeys(section);
1507 ret = TRUE;
1508 while(*string) {
1509 LPSTR buf = HeapAlloc( GetProcessHeap(), 0, strlen(string)+1 );
1510 strcpy( buf, string );
1511 if((p=strchr( buf, '='))){
1512 *p='\0';
1513 ret = PROFILE_SetString( section, buf, p+1, TRUE);
1515 HeapFree( GetProcessHeap(), 0, buf );
1516 string += strlen(string)+1;
1521 LeaveCriticalSection( &PROFILE_CritSect );
1522 return ret;
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 );
1539 return res;
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,
1571 LPCSTR filename )
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.
1596 * Win95:
1597 * - if the buffer is 0 or 1 character long then it is as if it was of
1598 * infinite length.
1599 * - otherwise, if the buffer is to small only the section names that fit
1600 * are returned.
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
1606 * Win2000:
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
1617 * '\0' is missing.
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,
1625 LPCSTR filename)
1628 DWORD ret = 0;
1630 EnterCriticalSection( &PROFILE_CritSect );
1632 if (PROFILE_Open( filename ))
1633 ret = PROFILE_GetSectionNames(buffer, size);
1635 LeaveCriticalSection( &PROFILE_CritSect );
1637 return ret;
1641 /***********************************************************************
1642 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1644 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1645 LPCWSTR filename)
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 ))
1653 buffer[size-1] = 0;
1654 HeapFree( GetProcessHeap(), 0, bufferA);
1655 HeapFree( GetProcessHeap(), 0, filenameA );
1657 return ret;
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)
1677 BOOL ret = FALSE;
1679 EnterCriticalSection( &PROFILE_CritSect );
1681 if (PROFILE_Open( filename )) {
1682 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
1683 if (k) {
1684 TRACE("value (at %p): '%s'\n", k->value, k->value);
1685 if (((strlen(k->value) - 2) / 2) == len)
1687 LPSTR end, p;
1688 BOOL valid = TRUE;
1689 CHAR c;
1690 DWORD chksum = 0;
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++)
1696 if (!isxdigit(*p))
1698 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1699 *p, filename, section, key);
1700 valid = FALSE;
1701 break;
1704 if (valid)
1706 BOOL highnibble = TRUE;
1707 BYTE b = 0, val;
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++)
1714 c = toupper(*p);
1715 val = (c > '9') ?
1716 (c - 'A' + 10) : (c - '0');
1718 if (highnibble)
1719 b = val << 4;
1720 else
1722 b += val;
1723 *binbuf++ = b; /* feed binary data into output */
1724 chksum += b; /* calculate checksum */
1726 highnibble ^= 1; /* toggle */
1728 /* retrieve stored checksum value */
1729 c = toupper(*p++);
1730 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1731 c = toupper(*p);
1732 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1733 if (b == (chksum & 0xff)) /* checksums match ? */
1734 ret = TRUE;
1739 LeaveCriticalSection( &PROFILE_CritSect );
1741 return ret;
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,
1756 len, filenameA );
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 );
1764 return ret;
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)
1784 BOOL ret = FALSE;
1785 LPBYTE binbuf;
1786 LPSTR outstring, p;
1787 DWORD sum = 0;
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);
1794 p = outstring;
1795 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1796 *p++ = hex[*binbuf >> 4];
1797 *p++ = hex[*binbuf & 0xf];
1798 sum += *binbuf;
1800 /* checksum is sum & 0xff */
1801 *p++ = hex[(sum & 0xf0) >> 4];
1802 *p++ = hex[sum & 0xf];
1803 *p++ = '\0';
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 );
1814 return ret;
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,
1827 filenameA );
1828 HeapFree( GetProcessHeap(), 0, sectionA );
1829 HeapFree( GetProcessHeap(), 0, keyA );
1830 HeapFree( GetProcessHeap(), 0, filenameA );
1832 return ret;
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);
1852 return FALSE;