Implement comctl32.417 and shlwapi.299. This avoids crash in IE's
[wine/hacks.git] / files / profile.c
blob3b6084339e2e7b975c956dfa529cd60addb6b178
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
24 #include <ctype.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #ifdef HAVE_PWD_H
33 # include <pwd.h>
34 #endif
35 #include <unistd.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winerror.h"
41 #include "wine/winbase16.h"
42 #include "winreg.h"
43 #include "file.h"
44 #include "heap.h"
45 #include "wine/server.h"
46 #include "wine/library.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(profile);
51 typedef struct tagPROFILEKEY
53 char *value;
54 struct tagPROFILEKEY *next;
55 char name[1];
56 } PROFILEKEY;
58 typedef struct tagPROFILESECTION
60 struct tagPROFILEKEY *key;
61 struct tagPROFILESECTION *next;
62 char name[1];
63 } PROFILESECTION;
66 typedef struct
68 BOOL changed;
69 PROFILESECTION *section;
70 char *dos_name;
71 char *unix_name;
72 char *filename;
73 time_t mtime;
74 } PROFILE;
77 #define N_CACHED_PROFILES 10
79 /* Cached profile files */
80 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
82 #define CurProfile (MRUProfile[0])
84 /* wine.ini config file registry root */
85 static HKEY wine_profile_key;
87 #define PROFILE_MAX_LINE_LEN 1024
89 /* Wine profile name in $HOME directory; must begin with slash */
90 static const char PROFILE_WineIniName[] = "/.winerc";
92 /* Wine profile: the profile file being used */
93 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
95 /* Check for comments in profile */
96 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
98 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
100 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
102 static const char hex[16] = "0123456789ABCDEF";
104 /***********************************************************************
105 * PROFILE_CopyEntry
107 * Copy the content of an entry into a buffer, removing quotes, and possibly
108 * translating environment variables.
110 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
111 int handle_env )
113 char quote = '\0';
114 const char *p;
116 if(!buffer) return;
118 if ((*value == '\'') || (*value == '\"'))
120 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
123 if (!handle_env)
125 lstrcpynA( buffer, value, len );
126 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
127 return;
130 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
132 if ((*p == '$') && (p[1] == '{'))
134 char env_val[1024];
135 const char *env_p;
136 const char *p2 = strchr( p, '}' );
137 if (!p2) continue; /* ignore it */
138 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
139 if ((env_p = getenv( env_val )) != NULL)
141 int buffer_len;
142 lstrcpynA( buffer, env_p, len );
143 buffer_len = strlen( buffer );
144 buffer += buffer_len;
145 len -= buffer_len;
147 p = p2 + 1;
150 if (quote && (len > 1)) buffer--;
151 *buffer = '\0';
155 /***********************************************************************
156 * PROFILE_Save
158 * Save a profile tree to a file.
160 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
162 PROFILEKEY *key;
164 for ( ; section; section = section->next)
166 if (section->name[0]) fprintf( file, "\r\n[%s]\r\n", section->name );
167 for (key = section->key; key; key = key->next)
169 fprintf( file, "%s", key->name );
170 if (key->value) fprintf( file, "=%s", key->value );
171 fprintf( file, "\r\n" );
177 /***********************************************************************
178 * PROFILE_Free
180 * Free a profile tree.
182 static void PROFILE_Free( PROFILESECTION *section )
184 PROFILESECTION *next_section;
185 PROFILEKEY *key, *next_key;
187 for ( ; section; section = next_section)
189 for (key = section->key; key; key = next_key)
191 next_key = key->next;
192 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
193 HeapFree( GetProcessHeap(), 0, key );
195 next_section = section->next;
196 HeapFree( GetProcessHeap(), 0, section );
200 static inline int PROFILE_isspace(char c)
202 if (isspace(c)) return 1;
203 if (c=='\r' || c==0x1a) return 1;
204 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
205 return 0;
209 /***********************************************************************
210 * PROFILE_Load
212 * Load a profile tree from a file.
214 static PROFILESECTION *PROFILE_Load( FILE *file )
216 char buffer[PROFILE_MAX_LINE_LEN];
217 char *p, *p2;
218 int line = 0;
219 PROFILESECTION *section, *first_section;
220 PROFILESECTION **next_section;
221 PROFILEKEY *key, *prev_key, **next_key;
223 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
224 if(first_section == NULL) return NULL;
225 first_section->name[0] = 0;
226 first_section->key = NULL;
227 first_section->next = NULL;
228 next_section = &first_section->next;
229 next_key = &first_section->key;
230 prev_key = NULL;
232 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
234 line++;
235 p = buffer;
236 while (*p && PROFILE_isspace(*p)) p++;
237 if (*p == '[') /* section start */
239 if (!(p2 = strrchr( p, ']' )))
241 WARN("Invalid section header at line %d: '%s'\n",
242 line, p );
244 else
246 *p2 = '\0';
247 p++;
248 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + strlen(p) )))
249 break;
250 strcpy( section->name, p );
251 section->key = NULL;
252 section->next = NULL;
253 *next_section = section;
254 next_section = &section->next;
255 next_key = &section->key;
256 prev_key = NULL;
258 TRACE("New section: '%s'\n",section->name);
260 continue;
264 p2=p+strlen(p) - 1;
265 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
267 if ((p2 = strchr( p, '=' )) != NULL)
269 char *p3 = p2 - 1;
270 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
271 *p2++ = '\0';
272 while (*p2 && PROFILE_isspace(*p2)) p2++;
275 if(*p || !prev_key || *prev_key->name)
277 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + strlen(p) ))) break;
278 strcpy( key->name, p );
279 if (p2)
281 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(p2)+1 );
282 strcpy( key->value, p2 );
284 else key->value = NULL;
286 key->next = NULL;
287 *next_key = key;
288 next_key = &key->next;
289 prev_key = key;
291 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
294 return first_section;
297 /* convert the .winerc file to the new format */
298 static void convert_config( FILE *in, const char *output_name )
300 char buffer[PROFILE_MAX_LINE_LEN];
301 char *p, *p2;
302 FILE *out;
304 /* create the output file, only if it doesn't exist already */
305 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
306 if (fd == -1)
308 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
309 ExitProcess(1);
312 out = fdopen( fd, "w" );
313 fprintf( out, "WINE REGISTRY Version 2\n" );
314 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
315 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
317 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
318 p = buffer;
319 while (*p && PROFILE_isspace(*p)) p++;
320 if (*p == '[') /* section start */
322 if ((p2 = strrchr( p, ']' )))
324 *p2 = '\0';
325 p++;
326 fprintf( out, "[%s]\n", p );
328 continue;
331 if (*p == ';' || *p == '#')
333 fprintf( out, "%s\n", p );
334 continue;
337 p2=p+strlen(p) - 1;
338 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
340 if ((p2 = strchr( p, '=' )) != NULL)
342 char *p3 = p2 - 1;
343 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
344 *p2++ = '\0';
345 while (*p2 && PROFILE_isspace(*p2)) p2++;
348 if (!*p)
350 fprintf( out, "\n" );
351 continue;
353 fputc( '"', out );
354 while (*p)
356 if (*p == '\\') fputc( '\\', out );
357 fputc( *p, out );
358 p++;
360 fprintf( out, "\" = \"" );
361 if (p2)
363 while (*p2)
365 if (*p2 == '\\') fputc( '\\', out );
366 fputc( *p2, out );
367 p2++;
370 fprintf( out, "\"\n" );
372 fclose( out );
376 /***********************************************************************
377 * PROFILE_DeleteSection
379 * Delete a section from a profile tree.
381 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
383 while (*section)
385 if ((*section)->name[0] && !strcasecmp( (*section)->name, name ))
387 PROFILESECTION *to_del = *section;
388 *section = to_del->next;
389 to_del->next = NULL;
390 PROFILE_Free( to_del );
391 return TRUE;
393 section = &(*section)->next;
395 return FALSE;
399 /***********************************************************************
400 * PROFILE_DeleteKey
402 * Delete a key from a profile tree.
404 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
405 LPCSTR section_name, LPCSTR key_name )
407 while (*section)
409 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
411 PROFILEKEY **key = &(*section)->key;
412 while (*key)
414 if (!strcasecmp( (*key)->name, key_name ))
416 PROFILEKEY *to_del = *key;
417 *key = to_del->next;
418 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
419 HeapFree( GetProcessHeap(), 0, to_del );
420 return TRUE;
422 key = &(*key)->next;
425 section = &(*section)->next;
427 return FALSE;
431 /***********************************************************************
432 * PROFILE_DeleteAllKeys
434 * Delete all keys from a profile tree.
436 void PROFILE_DeleteAllKeys( LPCSTR section_name)
438 PROFILESECTION **section= &CurProfile->section;
439 while (*section)
441 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
443 PROFILEKEY **key = &(*section)->key;
444 while (*key)
446 PROFILEKEY *to_del = *key;
447 *key = to_del->next;
448 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
449 HeapFree( GetProcessHeap(), 0, to_del );
450 CurProfile->changed =TRUE;
453 section = &(*section)->next;
458 /***********************************************************************
459 * PROFILE_Find
461 * Find a key in a profile tree, optionally creating it.
463 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, const char *section_name,
464 const char *key_name, BOOL create, BOOL create_always )
466 const char *p;
467 int seclen, keylen;
469 while (PROFILE_isspace(*section_name)) section_name++;
470 p = section_name + strlen(section_name) - 1;
471 while ((p > section_name) && PROFILE_isspace(*p)) p--;
472 seclen = p - section_name + 1;
474 while (PROFILE_isspace(*key_name)) key_name++;
475 p = key_name + strlen(key_name) - 1;
476 while ((p > key_name) && PROFILE_isspace(*p)) p--;
477 keylen = p - key_name + 1;
479 while (*section)
481 if ( ((*section)->name[0])
482 && (!(strncasecmp( (*section)->name, section_name, seclen )))
483 && (((*section)->name)[seclen] == '\0') )
485 PROFILEKEY **key = &(*section)->key;
487 while (*key)
489 /* If create_always is FALSE then we check if the keyname already exists.
490 * Otherwise we add it regardless of its existence, to allow
491 * keys to be added more then once in some cases.
493 if(!create_always)
495 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
496 && (((*key)->name)[keylen] == '\0') )
497 return *key;
499 key = &(*key)->next;
501 if (!create) return NULL;
502 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlen(key_name) )))
503 return NULL;
504 strcpy( (*key)->name, key_name );
505 (*key)->value = NULL;
506 (*key)->next = NULL;
507 return *key;
509 section = &(*section)->next;
511 if (!create) return NULL;
512 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlen(section_name) );
513 if(*section == NULL) return NULL;
514 strcpy( (*section)->name, section_name );
515 (*section)->next = NULL;
516 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
517 sizeof(PROFILEKEY) + strlen(key_name) )))
519 HeapFree(GetProcessHeap(), 0, *section);
520 return NULL;
522 strcpy( (*section)->key->name, key_name );
523 (*section)->key->value = NULL;
524 (*section)->key->next = NULL;
525 return (*section)->key;
529 /***********************************************************************
530 * PROFILE_FlushFile
532 * Flush the current profile to disk if changed.
534 static BOOL PROFILE_FlushFile(void)
536 char *p, buffer[MAX_PATHNAME_LEN];
537 const char *unix_name;
538 FILE *file = NULL;
539 struct stat buf;
541 if(!CurProfile)
543 WARN("No current profile!\n");
544 return FALSE;
547 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
548 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
550 /* Try to create it in $HOME/.wine */
551 /* FIXME: this will need a more general solution */
552 strcpy( buffer, wine_get_config_dir() );
553 p = buffer + strlen(buffer);
554 *p++ = '/';
555 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
556 _strlwr( p );
557 file = fopen( buffer, "w" );
558 unix_name = buffer;
561 if (!file)
563 WARN("could not save profile file %s\n", CurProfile->dos_name);
564 return FALSE;
567 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
568 PROFILE_Save( file, CurProfile->section );
569 fclose( file );
570 CurProfile->changed = FALSE;
571 if(!stat(unix_name,&buf))
572 CurProfile->mtime=buf.st_mtime;
573 return TRUE;
577 /***********************************************************************
578 * PROFILE_ReleaseFile
580 * Flush the current profile to disk and remove it from the cache.
582 static void PROFILE_ReleaseFile(void)
584 PROFILE_FlushFile();
585 PROFILE_Free( CurProfile->section );
586 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
587 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
588 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
589 CurProfile->changed = FALSE;
590 CurProfile->section = NULL;
591 CurProfile->dos_name = NULL;
592 CurProfile->unix_name = NULL;
593 CurProfile->filename = NULL;
594 CurProfile->mtime = 0;
598 /***********************************************************************
599 * PROFILE_Open
601 * Open a profile file, checking the cached file first.
603 static BOOL PROFILE_Open( LPCSTR filename )
605 DOS_FULL_NAME full_name;
606 char buffer[MAX_PATHNAME_LEN];
607 char *newdos_name, *p;
608 FILE *file = NULL;
609 int i,j;
610 struct stat buf;
611 PROFILE *tempProfile;
613 /* First time around */
615 if(!CurProfile)
616 for(i=0;i<N_CACHED_PROFILES;i++)
618 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
619 if(MRUProfile[i] == NULL) break;
620 MRUProfile[i]->changed=FALSE;
621 MRUProfile[i]->section=NULL;
622 MRUProfile[i]->dos_name=NULL;
623 MRUProfile[i]->unix_name=NULL;
624 MRUProfile[i]->filename=NULL;
625 MRUProfile[i]->mtime=0;
628 /* Check for a match */
630 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
631 strchr( filename, ':' ))
633 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
635 else
637 GetWindowsDirectoryA( buffer, sizeof(buffer) );
638 strcat( buffer, "\\" );
639 strcat( buffer, filename );
640 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
643 for(i=0;i<N_CACHED_PROFILES;i++)
645 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
646 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
648 if(i)
650 PROFILE_FlushFile();
651 tempProfile=MRUProfile[i];
652 for(j=i;j>0;j--)
653 MRUProfile[j]=MRUProfile[j-1];
654 CurProfile=tempProfile;
656 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
657 TRACE("(%s): already opened (mru=%d)\n",
658 filename, i );
659 else
660 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
661 filename, i );
662 return TRUE;
666 /* Flush the old current profile */
667 PROFILE_FlushFile();
669 /* Make the oldest profile the current one only in order to get rid of it */
670 if(i==N_CACHED_PROFILES)
672 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
673 for(i=N_CACHED_PROFILES-1;i>0;i--)
674 MRUProfile[i]=MRUProfile[i-1];
675 CurProfile=tempProfile;
677 if(CurProfile->filename) PROFILE_ReleaseFile();
679 /* OK, now that CurProfile is definitely free we assign it our new file */
680 newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 );
681 strcpy( newdos_name, full_name.short_name );
682 CurProfile->dos_name = newdos_name;
683 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, strlen(filename)+1 );
684 strcpy( CurProfile->filename, filename );
686 /* Try to open the profile file, first in $HOME/.wine */
688 /* FIXME: this will need a more general solution */
689 strcpy( buffer, wine_get_config_dir() );
690 p = buffer + strlen(buffer);
691 *p++ = '/';
692 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
693 _strlwr( p );
694 if ((file = fopen( buffer, "r" )))
696 TRACE("(%s): found it in %s\n",
697 filename, buffer );
698 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
699 strcpy( CurProfile->unix_name, buffer );
702 if (!file)
704 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
705 strcpy( CurProfile->unix_name, full_name.long_name );
706 if ((file = fopen( full_name.long_name, "r" )))
707 TRACE("(%s): found it in %s\n",
708 filename, full_name.long_name );
711 if (file)
713 CurProfile->section = PROFILE_Load( file );
714 fclose( file );
715 if(!stat(CurProfile->unix_name,&buf))
716 CurProfile->mtime=buf.st_mtime;
718 else
720 /* Does not exist yet, we will create it in PROFILE_FlushFile */
721 WARN("profile file %s not found\n", newdos_name );
723 return TRUE;
727 /***********************************************************************
728 * PROFILE_GetSection
730 * Returns all keys of a section.
731 * If return_values is TRUE, also include the corresponding values.
733 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
734 LPSTR buffer, UINT len, BOOL handle_env,
735 BOOL return_values )
737 PROFILEKEY *key;
739 if(!buffer) return 0;
741 while (section)
743 if (section->name[0] && !strcasecmp( section->name, section_name ))
745 UINT oldlen = len;
746 for (key = section->key; key; key = key->next)
748 if (len <= 2) break;
749 if (!*key->name) continue; /* Skip empty lines */
750 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
751 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
752 len -= strlen(buffer) + 1;
753 buffer += strlen(buffer) + 1;
754 if (len < 2)
755 break;
756 if (return_values && key->value) {
757 buffer[-1] = '=';
758 PROFILE_CopyEntry ( buffer,
759 key->value, len - 1, handle_env );
760 len -= strlen(buffer) + 1;
761 buffer += strlen(buffer) + 1;
764 *buffer = '\0';
765 if (len <= 1)
766 /*If either lpszSection or lpszKey is NULL and the supplied
767 destination buffer is too small to hold all the strings,
768 the last string is truncated and followed by two null characters.
769 In this case, the return value is equal to cchReturnBuffer
770 minus two. */
772 buffer[-1] = '\0';
773 return oldlen - 2;
775 return oldlen - len;
777 section = section->next;
779 buffer[0] = buffer[1] = '\0';
780 return 0;
783 /* See GetPrivateProfileSectionNamesA for documentation */
784 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
786 LPSTR buf;
787 UINT f,l;
788 PROFILESECTION *section;
790 if (!buffer || !len)
791 return 0;
792 if (len==1) {
793 *buffer='\0';
794 return 0;
797 f=len-1;
798 buf=buffer;
799 section = CurProfile->section;
800 while ((section!=NULL)) {
801 if (section->name[0]) {
802 l = strlen(section->name)+1;
803 if (l > f) {
804 if (f>0) {
805 strncpy(buf, section->name, f-1);
806 buf += f-1;
807 *buf++='\0';
809 *buf='\0';
810 return len-2;
812 strcpy(buf, section->name);
813 buf += l;
814 f -= l;
816 section = section->next;
818 *buf='\0';
819 return buf-buffer;
823 /***********************************************************************
824 * PROFILE_GetString
826 * Get a profile string.
828 * Tests with GetPrivateProfileString16, W95a,
829 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
830 * section key_name def_val res buffer
831 * "set1" "1" "x" 43 [data]
832 * "set1" "1 " "x" 43 [data] (!)
833 * "set1" " 1 "' "x" 43 [data] (!)
834 * "set1" "" "x" 1 "x"
835 * "set1" "" "x " 1 "x" (!)
836 * "set1" "" " x " 3 " x" (!)
837 * "set1" NULL "x" 6 "1\02\03\0\0"
838 * "set1" "" "x" 1 "x"
839 * NULL "1" "x" 0 "" (!)
840 * "" "1" "x" 1 "x"
841 * NULL NULL "" 0 ""
845 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
846 LPCSTR def_val, LPSTR buffer, UINT len )
848 PROFILEKEY *key = NULL;
850 if(!buffer) return 0;
852 if (!def_val) def_val = "";
853 if (key_name)
855 if (!key_name[0])
856 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
857 return 0;
858 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
859 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
860 len, FALSE );
861 TRACE("('%s','%s','%s'): returning '%s'\n",
862 section, key_name, def_val, buffer );
863 return strlen( buffer );
865 /* no "else" here ! */
866 if (section && section[0])
868 INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE, FALSE);
869 if (!buffer[0]) /* no luck -> def_val */
871 PROFILE_CopyEntry(buffer, def_val, len, FALSE);
872 ret = strlen(buffer);
874 return ret;
876 buffer[0] = '\0';
877 return 0;
881 /***********************************************************************
882 * PROFILE_SetString
884 * Set a profile string.
886 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
887 LPCSTR value, BOOL create_always )
889 if (!key_name) /* Delete a whole section */
891 TRACE("('%s')\n", section_name);
892 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
893 section_name );
894 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
895 this is not an error on application's level.*/
897 else if (!value) /* Delete a key */
899 TRACE("('%s','%s')\n",
900 section_name, key_name );
901 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
902 section_name, key_name );
903 return TRUE; /* same error handling as above */
905 else /* Set the key value */
907 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
908 key_name, TRUE, create_always );
909 TRACE("('%s','%s','%s'): \n",
910 section_name, key_name, value );
911 if (!key) return FALSE;
912 if (key->value)
914 /* strip the leading spaces. We can safely strip \n\r and
915 * friends too, they should not happen here anyway. */
916 while (PROFILE_isspace(*value)) value++;
918 if (!strcmp( key->value, value ))
920 TRACE(" no change needed\n" );
921 return TRUE; /* No change needed */
923 TRACE(" replacing '%s'\n", key->value );
924 HeapFree( GetProcessHeap(), 0, key->value );
926 else TRACE(" creating key\n" );
927 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(value)+1 );
928 strcpy( key->value, value );
929 CurProfile->changed = TRUE;
931 return TRUE;
935 /***********************************************************************
936 * PROFILE_GetWineIniString
938 * Get a config string from the wine.ini file.
940 int PROFILE_GetWineIniString( const char *section, const char *key_name,
941 const char *def, char *buffer, int len )
943 char tmp[PROFILE_MAX_LINE_LEN];
944 HKEY hkey;
945 DWORD err;
947 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
949 DWORD type;
950 DWORD count = sizeof(tmp);
951 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
952 RegCloseKey( hkey );
954 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
955 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
956 return strlen(buffer);
960 /******************************************************************************
962 * int PROFILE_GetWineIniBool(
963 * char const *section,
964 * char const *key_name,
965 * int def )
967 * Reads a boolean value from the wine.ini file. This function attempts to
968 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
969 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
970 * true. Anything else results in the return of the default value.
972 * This function uses 1 to indicate true, and 0 for false. You can check
973 * for existence by setting def to something other than 0 or 1 and
974 * examining the return value.
976 int PROFILE_GetWineIniBool(
977 char const *section,
978 char const *key_name,
979 int def )
981 char key_value[2];
982 int retval;
984 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
986 switch(key_value[0]) {
987 case 'n':
988 case 'N':
989 case 'f':
990 case 'F':
991 case '0':
992 retval = 0;
993 break;
995 case 'y':
996 case 'Y':
997 case 't':
998 case 'T':
999 case '1':
1000 retval = 1;
1001 break;
1003 default:
1004 retval = def;
1007 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name,
1008 def ? "TRUE" : "FALSE", key_value[0],
1009 retval ? "TRUE" : "FALSE");
1011 return retval;
1015 /***********************************************************************
1016 * PROFILE_LoadWineIni
1018 * Load the old .winerc file.
1020 int PROFILE_LoadWineIni(void)
1022 OBJECT_ATTRIBUTES attr;
1023 UNICODE_STRING nameW;
1024 char buffer[MAX_PATHNAME_LEN];
1025 const char *p;
1026 FILE *f;
1027 HKEY hKeySW;
1028 DWORD disp;
1030 attr.Length = sizeof(attr);
1031 attr.RootDirectory = 0;
1032 attr.ObjectName = &nameW;
1033 attr.Attributes = 0;
1034 attr.SecurityDescriptor = NULL;
1035 attr.SecurityQualityOfService = NULL;
1037 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1038 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1039 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1041 ERR("Cannot create config registry key\n" );
1042 ExitProcess( 1 );
1044 RtlFreeUnicodeString( &nameW );
1045 NtClose( hKeySW );
1047 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1048 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1049 NULL, REG_OPTION_VOLATILE, &disp ))
1051 ERR("Cannot create config registry key\n" );
1052 ExitProcess( 1 );
1054 RtlFreeUnicodeString( &nameW );
1056 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1058 if ((p = getenv( "HOME" )) != NULL)
1060 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1061 strcat( buffer, PROFILE_WineIniName );
1062 if ((f = fopen( buffer, "r" )) != NULL)
1064 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1066 /* convert to the new format */
1067 sprintf( buffer, "%s/config", wine_get_config_dir() );
1068 convert_config( f, buffer );
1069 fclose( f );
1071 MESSAGE( "The '%s' configuration file has been converted\n"
1072 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1073 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1074 "and then remove the old one and restart Wine.\n" );
1075 ExitProcess(0);
1078 else WARN("could not get $HOME value for config file.\n" );
1080 MESSAGE( "Can't open configuration file %s/config\n", wine_get_config_dir() );
1081 return 0;
1085 /***********************************************************************
1086 * PROFILE_UsageWineIni
1088 * Explain the wine.ini file to those who don't read documentation.
1089 * Keep below one screenful in length so that error messages above are
1090 * noticed.
1092 void PROFILE_UsageWineIni(void)
1094 MESSAGE("Perhaps you have not properly edited or created "
1095 "your Wine configuration file.\n");
1096 MESSAGE("This is (supposed to be) '%s/config'\n", wine_get_config_dir());
1097 /* RTFM, so to say */
1101 /********************* API functions **********************************/
1103 /***********************************************************************
1104 * GetProfileInt (KERNEL.57)
1106 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1108 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1112 /***********************************************************************
1113 * GetProfileIntA (KERNEL32.@)
1115 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1117 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1120 /***********************************************************************
1121 * GetProfileIntW (KERNEL32.@)
1123 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1125 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1129 * if allow_section_name_copy is TRUE, allow the copying :
1130 * - of Section names if 'section' is NULL
1131 * - of Keys in a Section if 'entry' is NULL
1132 * (see MSDN doc for GetPrivateProfileString)
1134 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1135 LPCSTR def_val, LPSTR buffer,
1136 UINT16 len, LPCSTR filename,
1137 BOOL allow_section_name_copy )
1139 int ret;
1140 LPSTR pDefVal = NULL;
1142 if (!filename)
1143 filename = "win.ini";
1145 /* strip any trailing ' ' of def_val. */
1146 if (def_val)
1148 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1150 while (p > def_val)
1152 p--;
1153 if ((*p) != ' ')
1154 break;
1156 if (*p == ' ') /* ouch, contained trailing ' ' */
1158 int len = (int)p - (int)def_val;
1159 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1160 strncpy(pDefVal, def_val, len);
1161 pDefVal[len] = '\0';
1164 if (!pDefVal)
1165 pDefVal = (LPSTR)def_val;
1167 EnterCriticalSection( &PROFILE_CritSect );
1169 if (PROFILE_Open( filename )) {
1170 if ((allow_section_name_copy) && (section == NULL))
1171 ret = PROFILE_GetSectionNames(buffer, len);
1172 else
1173 /* PROFILE_GetString already handles the 'entry == NULL' case */
1174 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1175 } else {
1176 lstrcpynA( buffer, pDefVal, len );
1177 ret = strlen( buffer );
1180 LeaveCriticalSection( &PROFILE_CritSect );
1182 if (pDefVal != def_val) /* allocated */
1183 HeapFree(GetProcessHeap(), 0, pDefVal);
1185 return ret;
1188 /***********************************************************************
1189 * GetPrivateProfileString (KERNEL.128)
1191 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1192 LPCSTR def_val, LPSTR buffer,
1193 UINT16 len, LPCSTR filename )
1195 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1196 buffer, len, filename, FALSE );
1199 /***********************************************************************
1200 * GetPrivateProfileStringA (KERNEL32.@)
1202 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1203 LPCSTR def_val, LPSTR buffer,
1204 UINT len, LPCSTR filename )
1206 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1207 buffer, len, filename, TRUE );
1210 /***********************************************************************
1211 * GetPrivateProfileStringW (KERNEL32.@)
1213 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1214 LPCWSTR def_val, LPWSTR buffer,
1215 UINT len, LPCWSTR filename )
1217 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1218 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1219 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1220 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1221 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1222 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1223 bufferA, len, filenameA );
1224 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1225 buffer[len-1] = 0;
1226 HeapFree( GetProcessHeap(), 0, sectionA );
1227 HeapFree( GetProcessHeap(), 0, entryA );
1228 HeapFree( GetProcessHeap(), 0, filenameA );
1229 HeapFree( GetProcessHeap(), 0, def_valA );
1230 HeapFree( GetProcessHeap(), 0, bufferA);
1231 return ret;
1234 /***********************************************************************
1235 * GetProfileString (KERNEL.58)
1237 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1238 LPSTR buffer, UINT16 len )
1240 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1241 buffer, len, "win.ini", FALSE );
1244 /***********************************************************************
1245 * GetProfileStringA (KERNEL32.@)
1247 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1248 LPSTR buffer, UINT len )
1250 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1251 buffer, len, "win.ini", TRUE );
1254 /***********************************************************************
1255 * GetProfileStringW (KERNEL32.@)
1257 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1258 LPCWSTR def_val, LPWSTR buffer, UINT len )
1260 return GetPrivateProfileStringW( section, entry, def_val,
1261 buffer, len, wininiW );
1264 /***********************************************************************
1265 * WriteProfileString (KERNEL.59)
1267 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1268 LPCSTR string )
1270 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1273 /***********************************************************************
1274 * WriteProfileStringA (KERNEL32.@)
1276 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1277 LPCSTR string )
1279 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1282 /***********************************************************************
1283 * WriteProfileStringW (KERNEL32.@)
1285 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1286 LPCWSTR string )
1288 return WritePrivateProfileStringW( section, entry, string, wininiW );
1292 /***********************************************************************
1293 * GetPrivateProfileInt (KERNEL.127)
1295 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1296 INT16 def_val, LPCSTR filename )
1298 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1299 * here, but Win98SE doesn't care about this at all, so I deleted it.
1300 * AFAIR versions prior to Win9x had these limits, though. */
1301 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
1304 /***********************************************************************
1305 * GetPrivateProfileIntA (KERNEL32.@)
1307 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1308 INT def_val, LPCSTR filename )
1310 char buffer[20];
1311 long result;
1313 if (!PROFILE_GetPrivateProfileString( section, entry, "",
1314 buffer, sizeof(buffer), filename, FALSE ))
1315 return def_val;
1316 /* FIXME: if entry can be found but it's empty, then Win16 is
1317 * supposed to return 0 instead of def_val ! Difficult/problematic
1318 * to implement (every other failure also returns zero buffer),
1319 * thus wait until testing framework avail for making sure nothing
1320 * else gets broken that way. */
1321 if (!buffer[0]) return (UINT)def_val;
1323 /* Don't use strtol() here !
1324 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1325 YES, scan for unsigned format ! (otherwise compatibility error) */
1326 if (!sscanf(buffer, "%lu", &result)) return 0;
1327 return (UINT)result;
1330 /***********************************************************************
1331 * GetPrivateProfileIntW (KERNEL32.@)
1333 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1334 INT def_val, LPCWSTR filename )
1336 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1337 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1338 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1339 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1340 HeapFree( GetProcessHeap(), 0, sectionA );
1341 HeapFree( GetProcessHeap(), 0, filenameA );
1342 HeapFree( GetProcessHeap(), 0, entryA );
1343 return res;
1346 /***********************************************************************
1347 * GetPrivateProfileSection (KERNEL.418)
1349 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1350 UINT16 len, LPCSTR filename )
1352 return GetPrivateProfileSectionA( section, buffer, len, filename );
1355 /***********************************************************************
1356 * GetPrivateProfileSectionA (KERNEL32.@)
1358 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1359 DWORD len, LPCSTR filename )
1361 int ret = 0;
1363 EnterCriticalSection( &PROFILE_CritSect );
1365 if (PROFILE_Open( filename ))
1366 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1367 FALSE, TRUE);
1369 LeaveCriticalSection( &PROFILE_CritSect );
1371 return ret;
1374 /***********************************************************************
1375 * GetPrivateProfileSectionW (KERNEL32.@)
1378 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1379 DWORD len, LPCWSTR filename )
1382 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1383 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1384 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1385 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1386 filenameA );
1387 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1388 HeapFree( GetProcessHeap(), 0, sectionA );
1389 HeapFree( GetProcessHeap(), 0, filenameA );
1390 HeapFree( GetProcessHeap(), 0, bufferA);
1391 return ret;
1394 /***********************************************************************
1395 * GetProfileSection (KERNEL.419)
1397 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1399 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1402 /***********************************************************************
1403 * GetProfileSectionA (KERNEL32.@)
1405 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1407 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1410 /***********************************************************************
1411 * GetProfileSectionW (KERNEL32.@)
1413 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1415 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1419 /***********************************************************************
1420 * WritePrivateProfileString (KERNEL.129)
1422 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1423 LPCSTR string, LPCSTR filename )
1425 return WritePrivateProfileStringA(section,entry,string,filename);
1428 /***********************************************************************
1429 * WritePrivateProfileStringA (KERNEL32.@)
1431 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1432 LPCSTR string, LPCSTR filename )
1434 BOOL ret = FALSE;
1436 EnterCriticalSection( &PROFILE_CritSect );
1438 if (PROFILE_Open( filename ))
1440 if (!section && !entry && !string) /* documented "file flush" case */
1441 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1442 else {
1443 if (!section) {
1444 FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename);
1445 } else {
1446 ret = PROFILE_SetString( section, entry, string, FALSE);
1451 LeaveCriticalSection( &PROFILE_CritSect );
1452 return ret;
1455 /***********************************************************************
1456 * WritePrivateProfileStringW (KERNEL32.@)
1458 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1459 LPCWSTR string, LPCWSTR filename )
1461 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1462 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1463 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1464 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1465 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1466 stringA, filenameA );
1467 HeapFree( GetProcessHeap(), 0, sectionA );
1468 HeapFree( GetProcessHeap(), 0, entryA );
1469 HeapFree( GetProcessHeap(), 0, stringA );
1470 HeapFree( GetProcessHeap(), 0, filenameA );
1471 return res;
1474 /***********************************************************************
1475 * WritePrivateProfileSection (KERNEL.416)
1477 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1478 LPCSTR string, LPCSTR filename )
1480 return WritePrivateProfileSectionA( section, string, filename );
1483 /***********************************************************************
1484 * WritePrivateProfileSectionA (KERNEL32.@)
1486 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1487 LPCSTR string, LPCSTR filename )
1489 BOOL ret = FALSE;
1490 LPSTR p ;
1492 EnterCriticalSection( &PROFILE_CritSect );
1494 if (PROFILE_Open( filename )) {
1495 if (!section && !string)
1496 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1497 else if (!string) /* delete the named section*/
1498 ret = PROFILE_SetString(section,NULL,NULL, FALSE);
1499 else {
1500 PROFILE_DeleteAllKeys(section);
1501 ret = TRUE;
1502 while(*string) {
1503 LPSTR buf = HeapAlloc( GetProcessHeap(), 0, strlen(string)+1 );
1504 strcpy( buf, string );
1505 if((p=strchr( buf, '='))){
1506 *p='\0';
1507 ret = PROFILE_SetString( section, buf, p+1, TRUE);
1509 HeapFree( GetProcessHeap(), 0, buf );
1510 string += strlen(string)+1;
1515 LeaveCriticalSection( &PROFILE_CritSect );
1516 return ret;
1519 /***********************************************************************
1520 * WritePrivateProfileSectionW (KERNEL32.@)
1522 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1523 LPCWSTR string, LPCWSTR filename)
1526 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1527 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1528 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1529 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1530 HeapFree( GetProcessHeap(), 0, sectionA );
1531 HeapFree( GetProcessHeap(), 0, stringA );
1532 HeapFree( GetProcessHeap(), 0, filenameA );
1533 return res;
1536 /***********************************************************************
1537 * WriteProfileSection (KERNEL.417)
1539 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1541 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1544 /***********************************************************************
1545 * WriteProfileSectionA (KERNEL32.@)
1547 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1550 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1553 /***********************************************************************
1554 * WriteProfileSectionW (KERNEL32.@)
1556 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1558 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1561 /***********************************************************************
1562 * GetPrivateProfileSectionNames (KERNEL.143)
1564 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1565 LPCSTR filename )
1567 return GetPrivateProfileSectionNamesA(buffer,size,filename);
1571 /***********************************************************************
1572 * GetProfileSectionNames (KERNEL.142)
1574 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
1577 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
1581 /***********************************************************************
1582 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1584 * Returns the section names contained in the specified file.
1585 * FIXME: Where do we find this file when the path is relative?
1586 * The section names are returned as a list of strings with an extra
1587 * '\0' to mark the end of the list. Except for that the behavior
1588 * depends on the Windows version.
1590 * Win95:
1591 * - if the buffer is 0 or 1 character long then it is as if it was of
1592 * infinite length.
1593 * - otherwise, if the buffer is to small only the section names that fit
1594 * are returned.
1595 * - note that this means if the buffer was to small to return even just
1596 * the first section name then a single '\0' will be returned.
1597 * - the return value is the number of characters written in the buffer,
1598 * except if the buffer was too smal in which case len-2 is returned
1600 * Win2000:
1601 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1602 * '\0' and the return value is 0
1603 * - otherwise if the buffer is too small then the first section name that
1604 * does not fit is truncated so that the string list can be terminated
1605 * correctly (double '\0')
1606 * - the return value is the number of characters written in the buffer
1607 * except for the trailing '\0'. If the buffer is too small, then the
1608 * return value is len-2
1609 * - Win2000 has a bug that triggers when the section names and the
1610 * trailing '\0' fit exactly in the buffer. In that case the trailing
1611 * '\0' is missing.
1613 * Wine implements the observed Win2000 behavior (except for the bug).
1615 * Note that when the buffer is big enough then the return value may be any
1616 * value between 1 and len-1 (or len in Win95), including len-2.
1618 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1619 LPCSTR filename)
1622 DWORD ret = 0;
1624 EnterCriticalSection( &PROFILE_CritSect );
1626 if (PROFILE_Open( filename ))
1627 ret = PROFILE_GetSectionNames(buffer, size);
1629 LeaveCriticalSection( &PROFILE_CritSect );
1631 return ret;
1635 /***********************************************************************
1636 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1638 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1639 LPCWSTR filename)
1642 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1643 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1645 INT ret = GetPrivateProfileSectionNamesA(bufferA, size, filenameA);
1646 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1647 buffer[size-1] = 0;
1648 HeapFree( GetProcessHeap(), 0, bufferA);
1649 HeapFree( GetProcessHeap(), 0, filenameA );
1651 return ret;
1654 /***********************************************************************
1655 * GetPrivateProfileStruct (KERNEL.407)
1657 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1658 LPVOID buf, UINT16 len, LPCSTR filename)
1660 return GetPrivateProfileStructA( section, key, buf, len, filename );
1663 /***********************************************************************
1664 * GetPrivateProfileStructA (KERNEL32.@)
1666 * Should match Win95's behaviour pretty much
1668 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1669 LPVOID buf, UINT len, LPCSTR filename)
1671 BOOL ret = FALSE;
1673 EnterCriticalSection( &PROFILE_CritSect );
1675 if (PROFILE_Open( filename )) {
1676 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
1677 if (k) {
1678 TRACE("value (at %p): '%s'\n", k->value, k->value);
1679 if (((strlen(k->value) - 2) / 2) == len)
1681 LPSTR end, p;
1682 BOOL valid = TRUE;
1683 CHAR c;
1684 DWORD chksum = 0;
1686 end = k->value + strlen(k->value); /* -> '\0' */
1687 /* check for invalid chars in ASCII coded hex string */
1688 for (p=k->value; p < end; p++)
1690 if (!isxdigit(*p))
1692 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1693 *p, filename, section, key);
1694 valid = FALSE;
1695 break;
1698 if (valid)
1700 BOOL highnibble = TRUE;
1701 BYTE b = 0, val;
1702 LPBYTE binbuf = (LPBYTE)buf;
1704 end -= 2; /* don't include checksum in output data */
1705 /* translate ASCII hex format into binary data */
1706 for (p=k->value; p < end; p++)
1708 c = toupper(*p);
1709 val = (c > '9') ?
1710 (c - 'A' + 10) : (c - '0');
1712 if (highnibble)
1713 b = val << 4;
1714 else
1716 b += val;
1717 *binbuf++ = b; /* feed binary data into output */
1718 chksum += b; /* calculate checksum */
1720 highnibble ^= 1; /* toggle */
1722 /* retrieve stored checksum value */
1723 c = toupper(*p++);
1724 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1725 c = toupper(*p);
1726 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1727 if (b == (chksum & 0xff)) /* checksums match ? */
1728 ret = TRUE;
1733 LeaveCriticalSection( &PROFILE_CritSect );
1735 return ret;
1738 /***********************************************************************
1739 * GetPrivateProfileStructW (KERNEL32.@)
1741 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1742 LPVOID buffer, UINT len, LPCWSTR filename)
1744 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1745 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1746 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1747 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1749 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1750 len, filenameA );
1751 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1752 ((LPWSTR)buffer)[len-1] = 0;
1753 HeapFree( GetProcessHeap(), 0, bufferA);
1754 HeapFree( GetProcessHeap(), 0, sectionA );
1755 HeapFree( GetProcessHeap(), 0, keyA );
1756 HeapFree( GetProcessHeap(), 0, filenameA );
1758 return ret;
1763 /***********************************************************************
1764 * WritePrivateProfileStruct (KERNEL.406)
1766 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1767 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1769 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1772 /***********************************************************************
1773 * WritePrivateProfileStructA (KERNEL32.@)
1775 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1776 LPVOID buf, UINT bufsize, LPCSTR filename)
1778 BOOL ret = FALSE;
1779 LPBYTE binbuf;
1780 LPSTR outstring, p;
1781 DWORD sum = 0;
1783 if (!section && !key && !buf) /* flush the cache */
1784 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1786 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1787 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1788 p = outstring;
1789 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1790 *p++ = hex[*binbuf >> 4];
1791 *p++ = hex[*binbuf & 0xf];
1792 sum += *binbuf;
1794 /* checksum is sum & 0xff */
1795 *p++ = hex[(sum & 0xf0) >> 4];
1796 *p++ = hex[sum & 0xf];
1797 *p++ = '\0';
1799 EnterCriticalSection( &PROFILE_CritSect );
1801 if (PROFILE_Open( filename ))
1802 ret = PROFILE_SetString( section, key, outstring, FALSE);
1804 LeaveCriticalSection( &PROFILE_CritSect );
1806 HeapFree( GetProcessHeap(), 0, outstring );
1808 return ret;
1811 /***********************************************************************
1812 * WritePrivateProfileStructW (KERNEL32.@)
1814 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1815 LPVOID buf, UINT bufsize, LPCWSTR filename)
1817 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1818 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1819 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1820 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1821 filenameA );
1822 HeapFree( GetProcessHeap(), 0, sectionA );
1823 HeapFree( GetProcessHeap(), 0, keyA );
1824 HeapFree( GetProcessHeap(), 0, filenameA );
1826 return ret;
1830 /***********************************************************************
1831 * WriteOutProfiles (KERNEL.315)
1833 void WINAPI WriteOutProfiles16(void)
1835 EnterCriticalSection( &PROFILE_CritSect );
1836 PROFILE_FlushFile();
1837 LeaveCriticalSection( &PROFILE_CritSect );
1840 /***********************************************************************
1841 * CloseProfileUserMapping (KERNEL32.@)
1843 BOOL WINAPI CloseProfileUserMapping(void) {
1844 FIXME("(), stub!\n");
1845 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1846 return FALSE;