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