Added include protection for unistd.h and sys/time.h.
[wine/hacks.git] / files / profile.c
blob8f342a26adf0fc1e941c44ce028e6feb7a868bf8
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 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winnls.h"
42 #include "winerror.h"
43 #include "wine/winbase16.h"
44 #include "winreg.h"
45 #include "file.h"
46 #include "heap.h"
47 #include "wine/server.h"
48 #include "wine/library.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(profile);
53 typedef struct tagPROFILEKEY
55 char *value;
56 struct tagPROFILEKEY *next;
57 char name[1];
58 } PROFILEKEY;
60 typedef struct tagPROFILESECTION
62 struct tagPROFILEKEY *key;
63 struct tagPROFILESECTION *next;
64 char name[1];
65 } PROFILESECTION;
68 typedef struct
70 BOOL changed;
71 PROFILESECTION *section;
72 char *dos_name;
73 char *unix_name;
74 char *filename;
75 time_t mtime;
76 } PROFILE;
79 #define N_CACHED_PROFILES 10
81 /* Cached profile files */
82 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
84 #define CurProfile (MRUProfile[0])
86 /* wine.ini config file registry root */
87 static HKEY wine_profile_key;
89 #define PROFILE_MAX_LINE_LEN 1024
91 /* Wine profile name in $HOME directory; must begin with slash */
92 static const char PROFILE_WineIniName[] = "/.winerc";
94 /* Wine profile: the profile file being used */
95 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
97 /* Check for comments in profile */
98 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
100 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
102 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
104 static const char hex[16] = "0123456789ABCDEF";
106 /***********************************************************************
107 * PROFILE_CopyEntry
109 * Copy the content of an entry into a buffer, removing quotes, and possibly
110 * translating environment variables.
112 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
113 int handle_env )
115 char quote = '\0';
116 const char *p;
118 if(!buffer) return;
120 if ((*value == '\'') || (*value == '\"'))
122 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
125 if (!handle_env)
127 lstrcpynA( buffer, value, len );
128 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
129 return;
132 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
134 if ((*p == '$') && (p[1] == '{'))
136 char env_val[1024];
137 const char *env_p;
138 const char *p2 = strchr( p, '}' );
139 if (!p2) continue; /* ignore it */
140 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
141 if ((env_p = getenv( env_val )) != NULL)
143 int buffer_len;
144 lstrcpynA( buffer, env_p, len );
145 buffer_len = strlen( buffer );
146 buffer += buffer_len;
147 len -= buffer_len;
149 p = p2 + 1;
152 if (quote && (len > 1)) buffer--;
153 *buffer = '\0';
157 /***********************************************************************
158 * PROFILE_Save
160 * Save a profile tree to a file.
162 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
164 PROFILEKEY *key;
166 for ( ; section; section = section->next)
168 if (section->name[0]) fprintf( file, "\r\n[%s]\r\n", section->name );
169 for (key = section->key; key; key = key->next)
171 fprintf( file, "%s", key->name );
172 if (key->value) fprintf( file, "=%s", key->value );
173 fprintf( file, "\r\n" );
179 /***********************************************************************
180 * PROFILE_Free
182 * Free a profile tree.
184 static void PROFILE_Free( PROFILESECTION *section )
186 PROFILESECTION *next_section;
187 PROFILEKEY *key, *next_key;
189 for ( ; section; section = next_section)
191 for (key = section->key; key; key = next_key)
193 next_key = key->next;
194 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
195 HeapFree( GetProcessHeap(), 0, key );
197 next_section = section->next;
198 HeapFree( GetProcessHeap(), 0, section );
202 static inline int PROFILE_isspace(char c)
204 if (isspace(c)) return 1;
205 if (c=='\r' || c==0x1a) return 1;
206 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
207 return 0;
211 /***********************************************************************
212 * PROFILE_Load
214 * Load a profile tree from a file.
216 static PROFILESECTION *PROFILE_Load( FILE *file )
218 char buffer[PROFILE_MAX_LINE_LEN];
219 char *p, *p2;
220 int line = 0;
221 PROFILESECTION *section, *first_section;
222 PROFILESECTION **next_section;
223 PROFILEKEY *key, *prev_key, **next_key;
225 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
226 if(first_section == NULL) return NULL;
227 first_section->name[0] = 0;
228 first_section->key = NULL;
229 first_section->next = NULL;
230 next_section = &first_section->next;
231 next_key = &first_section->key;
232 prev_key = NULL;
234 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
236 line++;
237 p = buffer;
238 while (*p && PROFILE_isspace(*p)) p++;
239 if (*p == '[') /* section start */
241 if (!(p2 = strrchr( p, ']' )))
243 WARN("Invalid section header at line %d: '%s'\n",
244 line, p );
246 else
248 *p2 = '\0';
249 p++;
250 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + strlen(p) )))
251 break;
252 strcpy( section->name, p );
253 section->key = NULL;
254 section->next = NULL;
255 *next_section = section;
256 next_section = &section->next;
257 next_key = &section->key;
258 prev_key = NULL;
260 TRACE("New section: '%s'\n",section->name);
262 continue;
266 p2=p+strlen(p) - 1;
267 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
269 if ((p2 = strchr( p, '=' )) != NULL)
271 char *p3 = p2 - 1;
272 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
273 *p2++ = '\0';
274 while (*p2 && PROFILE_isspace(*p2)) p2++;
277 if(*p || !prev_key || *prev_key->name)
279 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + strlen(p) ))) break;
280 strcpy( key->name, p );
281 if (p2)
283 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(p2)+1 );
284 strcpy( key->value, p2 );
286 else key->value = NULL;
288 key->next = NULL;
289 *next_key = key;
290 next_key = &key->next;
291 prev_key = key;
293 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
296 return first_section;
299 /* convert the .winerc file to the new format */
300 static void convert_config( FILE *in, const char *output_name )
302 char buffer[PROFILE_MAX_LINE_LEN];
303 char *p, *p2;
304 FILE *out;
306 /* create the output file, only if it doesn't exist already */
307 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
308 if (fd == -1)
310 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
311 ExitProcess(1);
314 out = fdopen( fd, "w" );
315 fprintf( out, "WINE REGISTRY Version 2\n" );
316 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
317 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
319 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
320 p = buffer;
321 while (*p && PROFILE_isspace(*p)) p++;
322 if (*p == '[') /* section start */
324 if ((p2 = strrchr( p, ']' )))
326 *p2 = '\0';
327 p++;
328 fprintf( out, "[%s]\n", p );
330 continue;
333 if (*p == ';' || *p == '#')
335 fprintf( out, "%s\n", p );
336 continue;
339 p2=p+strlen(p) - 1;
340 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
342 if ((p2 = strchr( p, '=' )) != NULL)
344 char *p3 = p2 - 1;
345 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
346 *p2++ = '\0';
347 while (*p2 && PROFILE_isspace(*p2)) p2++;
350 if (!*p)
352 fprintf( out, "\n" );
353 continue;
355 fputc( '"', out );
356 while (*p)
358 if (*p == '\\') fputc( '\\', out );
359 fputc( *p, out );
360 p++;
362 fprintf( out, "\" = \"" );
363 if (p2)
365 while (*p2)
367 if (*p2 == '\\') fputc( '\\', out );
368 fputc( *p2, out );
369 p2++;
372 fprintf( out, "\"\n" );
374 fclose( out );
378 /***********************************************************************
379 * PROFILE_DeleteSection
381 * Delete a section from a profile tree.
383 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
385 while (*section)
387 if ((*section)->name[0] && !strcasecmp( (*section)->name, name ))
389 PROFILESECTION *to_del = *section;
390 *section = to_del->next;
391 to_del->next = NULL;
392 PROFILE_Free( to_del );
393 return TRUE;
395 section = &(*section)->next;
397 return FALSE;
401 /***********************************************************************
402 * PROFILE_DeleteKey
404 * Delete a key from a profile tree.
406 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
407 LPCSTR section_name, LPCSTR key_name )
409 while (*section)
411 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
413 PROFILEKEY **key = &(*section)->key;
414 while (*key)
416 if (!strcasecmp( (*key)->name, key_name ))
418 PROFILEKEY *to_del = *key;
419 *key = to_del->next;
420 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
421 HeapFree( GetProcessHeap(), 0, to_del );
422 return TRUE;
424 key = &(*key)->next;
427 section = &(*section)->next;
429 return FALSE;
433 /***********************************************************************
434 * PROFILE_DeleteAllKeys
436 * Delete all keys from a profile tree.
438 void PROFILE_DeleteAllKeys( LPCSTR section_name)
440 PROFILESECTION **section= &CurProfile->section;
441 while (*section)
443 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
445 PROFILEKEY **key = &(*section)->key;
446 while (*key)
448 PROFILEKEY *to_del = *key;
449 *key = to_del->next;
450 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
451 HeapFree( GetProcessHeap(), 0, to_del );
452 CurProfile->changed =TRUE;
455 section = &(*section)->next;
460 /***********************************************************************
461 * PROFILE_Find
463 * Find a key in a profile tree, optionally creating it.
465 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, const char *section_name,
466 const char *key_name, BOOL create, BOOL create_always )
468 const char *p;
469 int seclen, keylen;
471 while (PROFILE_isspace(*section_name)) section_name++;
472 p = section_name + strlen(section_name) - 1;
473 while ((p > section_name) && PROFILE_isspace(*p)) p--;
474 seclen = p - section_name + 1;
476 while (PROFILE_isspace(*key_name)) key_name++;
477 p = key_name + strlen(key_name) - 1;
478 while ((p > key_name) && PROFILE_isspace(*p)) p--;
479 keylen = p - key_name + 1;
481 while (*section)
483 if ( ((*section)->name[0])
484 && (!(strncasecmp( (*section)->name, section_name, seclen )))
485 && (((*section)->name)[seclen] == '\0') )
487 PROFILEKEY **key = &(*section)->key;
489 while (*key)
491 /* If create_always is FALSE then we check if the keyname already exists.
492 * Otherwise we add it regardless of its existence, to allow
493 * keys to be added more then once in some cases.
495 if(!create_always)
497 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
498 && (((*key)->name)[keylen] == '\0') )
499 return *key;
501 key = &(*key)->next;
503 if (!create) return NULL;
504 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlen(key_name) )))
505 return NULL;
506 strcpy( (*key)->name, key_name );
507 (*key)->value = NULL;
508 (*key)->next = NULL;
509 return *key;
511 section = &(*section)->next;
513 if (!create) return NULL;
514 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlen(section_name) );
515 if(*section == NULL) return NULL;
516 strcpy( (*section)->name, section_name );
517 (*section)->next = NULL;
518 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
519 sizeof(PROFILEKEY) + strlen(key_name) )))
521 HeapFree(GetProcessHeap(), 0, *section);
522 return NULL;
524 strcpy( (*section)->key->name, key_name );
525 (*section)->key->value = NULL;
526 (*section)->key->next = NULL;
527 return (*section)->key;
531 /***********************************************************************
532 * PROFILE_FlushFile
534 * Flush the current profile to disk if changed.
536 static BOOL PROFILE_FlushFile(void)
538 char *p, buffer[MAX_PATHNAME_LEN];
539 const char *unix_name;
540 FILE *file = NULL;
541 struct stat buf;
543 if(!CurProfile)
545 WARN("No current profile!\n");
546 return FALSE;
549 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
550 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
552 /* Try to create it in $HOME/.wine */
553 /* FIXME: this will need a more general solution */
554 strcpy( buffer, wine_get_config_dir() );
555 p = buffer + strlen(buffer);
556 *p++ = '/';
557 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
558 _strlwr( p );
559 file = fopen( buffer, "w" );
560 unix_name = buffer;
563 if (!file)
565 WARN("could not save profile file %s\n", CurProfile->dos_name);
566 return FALSE;
569 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
570 PROFILE_Save( file, CurProfile->section );
571 fclose( file );
572 CurProfile->changed = FALSE;
573 if(!stat(unix_name,&buf))
574 CurProfile->mtime=buf.st_mtime;
575 return TRUE;
579 /***********************************************************************
580 * PROFILE_ReleaseFile
582 * Flush the current profile to disk and remove it from the cache.
584 static void PROFILE_ReleaseFile(void)
586 PROFILE_FlushFile();
587 PROFILE_Free( CurProfile->section );
588 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
589 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
590 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
591 CurProfile->changed = FALSE;
592 CurProfile->section = NULL;
593 CurProfile->dos_name = NULL;
594 CurProfile->unix_name = NULL;
595 CurProfile->filename = NULL;
596 CurProfile->mtime = 0;
600 /***********************************************************************
601 * PROFILE_Open
603 * Open a profile file, checking the cached file first.
605 static BOOL PROFILE_Open( LPCSTR filename )
607 DOS_FULL_NAME full_name;
608 char buffer[MAX_PATHNAME_LEN];
609 char *newdos_name, *p;
610 FILE *file = NULL;
611 int i,j;
612 struct stat buf;
613 PROFILE *tempProfile;
615 /* First time around */
617 if(!CurProfile)
618 for(i=0;i<N_CACHED_PROFILES;i++)
620 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
621 if(MRUProfile[i] == NULL) break;
622 MRUProfile[i]->changed=FALSE;
623 MRUProfile[i]->section=NULL;
624 MRUProfile[i]->dos_name=NULL;
625 MRUProfile[i]->unix_name=NULL;
626 MRUProfile[i]->filename=NULL;
627 MRUProfile[i]->mtime=0;
630 /* Check for a match */
632 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
633 strchr( filename, ':' ))
635 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
637 else
639 GetWindowsDirectoryA( buffer, sizeof(buffer) );
640 strcat( buffer, "\\" );
641 strcat( buffer, filename );
642 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
645 for(i=0;i<N_CACHED_PROFILES;i++)
647 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
648 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
650 if(i)
652 PROFILE_FlushFile();
653 tempProfile=MRUProfile[i];
654 for(j=i;j>0;j--)
655 MRUProfile[j]=MRUProfile[j-1];
656 CurProfile=tempProfile;
658 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
659 TRACE("(%s): already opened (mru=%d)\n",
660 filename, i );
661 else
662 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
663 filename, i );
664 return TRUE;
668 /* Flush the old current profile */
669 PROFILE_FlushFile();
671 /* Make the oldest profile the current one only in order to get rid of it */
672 if(i==N_CACHED_PROFILES)
674 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
675 for(i=N_CACHED_PROFILES-1;i>0;i--)
676 MRUProfile[i]=MRUProfile[i-1];
677 CurProfile=tempProfile;
679 if(CurProfile->filename) PROFILE_ReleaseFile();
681 /* OK, now that CurProfile is definitely free we assign it our new file */
682 newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 );
683 strcpy( newdos_name, full_name.short_name );
684 CurProfile->dos_name = newdos_name;
685 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, strlen(filename)+1 );
686 strcpy( CurProfile->filename, filename );
688 /* Try to open the profile file, first in $HOME/.wine */
690 /* FIXME: this will need a more general solution */
691 strcpy( buffer, wine_get_config_dir() );
692 p = buffer + strlen(buffer);
693 *p++ = '/';
694 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
695 _strlwr( p );
696 if ((file = fopen( buffer, "r" )))
698 TRACE("(%s): found it in %s\n",
699 filename, buffer );
700 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
701 strcpy( CurProfile->unix_name, buffer );
704 if (!file)
706 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
707 strcpy( CurProfile->unix_name, full_name.long_name );
708 if ((file = fopen( full_name.long_name, "r" )))
709 TRACE("(%s): found it in %s\n",
710 filename, full_name.long_name );
713 if (file)
715 CurProfile->section = PROFILE_Load( file );
716 fclose( file );
717 if(!stat(CurProfile->unix_name,&buf))
718 CurProfile->mtime=buf.st_mtime;
720 else
722 /* Does not exist yet, we will create it in PROFILE_FlushFile */
723 WARN("profile file %s not found\n", newdos_name );
725 return TRUE;
729 /***********************************************************************
730 * PROFILE_GetSection
732 * Returns all keys of a section.
733 * If return_values is TRUE, also include the corresponding values.
735 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
736 LPSTR buffer, UINT len, BOOL handle_env,
737 BOOL return_values )
739 PROFILEKEY *key;
741 if(!buffer) return 0;
743 while (section)
745 if (section->name[0] && !strcasecmp( section->name, section_name ))
747 UINT oldlen = len;
748 for (key = section->key; key; key = key->next)
750 if (len <= 2) break;
751 if (!*key->name) continue; /* Skip empty lines */
752 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
753 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
754 len -= strlen(buffer) + 1;
755 buffer += strlen(buffer) + 1;
756 if (len < 2)
757 break;
758 if (return_values && key->value) {
759 buffer[-1] = '=';
760 PROFILE_CopyEntry ( buffer,
761 key->value, len - 1, handle_env );
762 len -= strlen(buffer) + 1;
763 buffer += strlen(buffer) + 1;
766 *buffer = '\0';
767 if (len <= 1)
768 /*If either lpszSection or lpszKey is NULL and the supplied
769 destination buffer is too small to hold all the strings,
770 the last string is truncated and followed by two null characters.
771 In this case, the return value is equal to cchReturnBuffer
772 minus two. */
774 buffer[-1] = '\0';
775 return oldlen - 2;
777 return oldlen - len;
779 section = section->next;
781 buffer[0] = buffer[1] = '\0';
782 return 0;
785 /* See GetPrivateProfileSectionNamesA for documentation */
786 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
788 LPSTR buf;
789 UINT f,l;
790 PROFILESECTION *section;
792 if (!buffer || !len)
793 return 0;
794 if (len==1) {
795 *buffer='\0';
796 return 0;
799 f=len-1;
800 buf=buffer;
801 section = CurProfile->section;
802 while ((section!=NULL)) {
803 if (section->name[0]) {
804 l = strlen(section->name)+1;
805 if (l > f) {
806 if (f>0) {
807 strncpy(buf, section->name, f-1);
808 buf += f-1;
809 *buf++='\0';
811 *buf='\0';
812 return len-2;
814 strcpy(buf, section->name);
815 buf += l;
816 f -= l;
818 section = section->next;
820 *buf='\0';
821 return buf-buffer;
825 /***********************************************************************
826 * PROFILE_GetString
828 * Get a profile string.
830 * Tests with GetPrivateProfileString16, W95a,
831 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
832 * section key_name def_val res buffer
833 * "set1" "1" "x" 43 [data]
834 * "set1" "1 " "x" 43 [data] (!)
835 * "set1" " 1 "' "x" 43 [data] (!)
836 * "set1" "" "x" 1 "x"
837 * "set1" "" "x " 1 "x" (!)
838 * "set1" "" " x " 3 " x" (!)
839 * "set1" NULL "x" 6 "1\02\03\0\0"
840 * "set1" "" "x" 1 "x"
841 * NULL "1" "x" 0 "" (!)
842 * "" "1" "x" 1 "x"
843 * NULL NULL "" 0 ""
847 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
848 LPCSTR def_val, LPSTR buffer, UINT len )
850 PROFILEKEY *key = NULL;
852 if(!buffer) return 0;
854 if (!def_val) def_val = "";
855 if (key_name)
857 if (!key_name[0])
858 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
859 return 0;
860 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
861 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
862 len, FALSE );
863 TRACE("('%s','%s','%s'): returning '%s'\n",
864 section, key_name, def_val, buffer );
865 return strlen( buffer );
867 /* no "else" here ! */
868 if (section && section[0])
870 INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE, FALSE);
871 if (!buffer[0]) /* no luck -> def_val */
873 PROFILE_CopyEntry(buffer, def_val, len, FALSE);
874 ret = strlen(buffer);
876 return ret;
878 buffer[0] = '\0';
879 return 0;
883 /***********************************************************************
884 * PROFILE_SetString
886 * Set a profile string.
888 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
889 LPCSTR value, BOOL create_always )
891 if (!key_name) /* Delete a whole section */
893 TRACE("('%s')\n", section_name);
894 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
895 section_name );
896 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
897 this is not an error on application's level.*/
899 else if (!value) /* Delete a key */
901 TRACE("('%s','%s')\n",
902 section_name, key_name );
903 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
904 section_name, key_name );
905 return TRUE; /* same error handling as above */
907 else /* Set the key value */
909 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
910 key_name, TRUE, create_always );
911 TRACE("('%s','%s','%s'): \n",
912 section_name, key_name, value );
913 if (!key) return FALSE;
914 if (key->value)
916 /* strip the leading spaces. We can safely strip \n\r and
917 * friends too, they should not happen here anyway. */
918 while (PROFILE_isspace(*value)) value++;
920 if (!strcmp( key->value, value ))
922 TRACE(" no change needed\n" );
923 return TRUE; /* No change needed */
925 TRACE(" replacing '%s'\n", key->value );
926 HeapFree( GetProcessHeap(), 0, key->value );
928 else TRACE(" creating key\n" );
929 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(value)+1 );
930 strcpy( key->value, value );
931 CurProfile->changed = TRUE;
933 return TRUE;
937 /***********************************************************************
938 * PROFILE_GetWineIniString
940 * Get a config string from the wine.ini file.
942 int PROFILE_GetWineIniString( const char *section, const char *key_name,
943 const char *def, char *buffer, int len )
945 char tmp[PROFILE_MAX_LINE_LEN];
946 HKEY hkey;
947 DWORD err;
949 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
951 DWORD type;
952 DWORD count = sizeof(tmp);
953 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
954 RegCloseKey( hkey );
956 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
957 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
958 return strlen(buffer);
962 /******************************************************************************
964 * int PROFILE_GetWineIniBool(
965 * char const *section,
966 * char const *key_name,
967 * int def )
969 * Reads a boolean value from the wine.ini file. This function attempts to
970 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
971 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
972 * true. Anything else results in the return of the default value.
974 * This function uses 1 to indicate true, and 0 for false. You can check
975 * for existence by setting def to something other than 0 or 1 and
976 * examining the return value.
978 int PROFILE_GetWineIniBool(
979 char const *section,
980 char const *key_name,
981 int def )
983 char key_value[2];
984 int retval;
986 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
988 switch(key_value[0]) {
989 case 'n':
990 case 'N':
991 case 'f':
992 case 'F':
993 case '0':
994 retval = 0;
995 break;
997 case 'y':
998 case 'Y':
999 case 't':
1000 case 'T':
1001 case '1':
1002 retval = 1;
1003 break;
1005 default:
1006 retval = def;
1009 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name,
1010 def ? "TRUE" : "FALSE", key_value[0],
1011 retval ? "TRUE" : "FALSE");
1013 return retval;
1017 /***********************************************************************
1018 * PROFILE_LoadWineIni
1020 * Load the old .winerc file.
1022 int PROFILE_LoadWineIni(void)
1024 OBJECT_ATTRIBUTES attr;
1025 UNICODE_STRING nameW;
1026 char buffer[MAX_PATHNAME_LEN];
1027 const char *p;
1028 FILE *f;
1029 HKEY hKeySW;
1030 DWORD disp;
1032 attr.Length = sizeof(attr);
1033 attr.RootDirectory = 0;
1034 attr.ObjectName = &nameW;
1035 attr.Attributes = 0;
1036 attr.SecurityDescriptor = NULL;
1037 attr.SecurityQualityOfService = NULL;
1039 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1040 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1041 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1043 ERR("Cannot create config registry key\n" );
1044 ExitProcess( 1 );
1046 RtlFreeUnicodeString( &nameW );
1047 NtClose( hKeySW );
1049 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1050 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1051 NULL, REG_OPTION_VOLATILE, &disp ))
1053 ERR("Cannot create config registry key\n" );
1054 ExitProcess( 1 );
1056 RtlFreeUnicodeString( &nameW );
1058 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1060 if ((p = getenv( "HOME" )) != NULL)
1062 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1063 strcat( buffer, PROFILE_WineIniName );
1064 if ((f = fopen( buffer, "r" )) != NULL)
1066 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1068 /* convert to the new format */
1069 sprintf( buffer, "%s/config", wine_get_config_dir() );
1070 convert_config( f, buffer );
1071 fclose( f );
1073 MESSAGE( "The '%s' configuration file has been converted\n"
1074 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1075 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1076 "and then remove the old one and restart Wine.\n" );
1077 ExitProcess(0);
1080 else WARN("could not get $HOME value for config file.\n" );
1082 MESSAGE( "Can't open configuration file %s/config\n", wine_get_config_dir() );
1083 return 0;
1087 /***********************************************************************
1088 * PROFILE_UsageWineIni
1090 * Explain the wine.ini file to those who don't read documentation.
1091 * Keep below one screenful in length so that error messages above are
1092 * noticed.
1094 void PROFILE_UsageWineIni(void)
1096 MESSAGE("Perhaps you have not properly edited or created "
1097 "your Wine configuration file.\n");
1098 MESSAGE("This is (supposed to be) '%s/config'\n", wine_get_config_dir());
1099 /* RTFM, so to say */
1103 /********************* API functions **********************************/
1105 /***********************************************************************
1106 * GetProfileInt (KERNEL.57)
1108 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1110 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1114 /***********************************************************************
1115 * GetProfileIntA (KERNEL32.@)
1117 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1119 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1122 /***********************************************************************
1123 * GetProfileIntW (KERNEL32.@)
1125 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1127 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1131 * if allow_section_name_copy is TRUE, allow the copying :
1132 * - of Section names if 'section' is NULL
1133 * - of Keys in a Section if 'entry' is NULL
1134 * (see MSDN doc for GetPrivateProfileString)
1136 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1137 LPCSTR def_val, LPSTR buffer,
1138 UINT16 len, LPCSTR filename,
1139 BOOL allow_section_name_copy )
1141 int ret;
1142 LPSTR pDefVal = NULL;
1144 if (!filename)
1145 filename = "win.ini";
1147 /* strip any trailing ' ' of def_val. */
1148 if (def_val)
1150 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1152 while (p > def_val)
1154 p--;
1155 if ((*p) != ' ')
1156 break;
1158 if (*p == ' ') /* ouch, contained trailing ' ' */
1160 int len = (int)p - (int)def_val;
1161 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1162 strncpy(pDefVal, def_val, len);
1163 pDefVal[len] = '\0';
1166 if (!pDefVal)
1167 pDefVal = (LPSTR)def_val;
1169 EnterCriticalSection( &PROFILE_CritSect );
1171 if (PROFILE_Open( filename )) {
1172 if ((allow_section_name_copy) && (section == NULL))
1173 ret = PROFILE_GetSectionNames(buffer, len);
1174 else
1175 /* PROFILE_GetString already handles the 'entry == NULL' case */
1176 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1177 } else {
1178 lstrcpynA( buffer, pDefVal, len );
1179 ret = strlen( buffer );
1182 LeaveCriticalSection( &PROFILE_CritSect );
1184 if (pDefVal != def_val) /* allocated */
1185 HeapFree(GetProcessHeap(), 0, pDefVal);
1187 return ret;
1190 /***********************************************************************
1191 * GetPrivateProfileString (KERNEL.128)
1193 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1194 LPCSTR def_val, LPSTR buffer,
1195 UINT16 len, LPCSTR filename )
1197 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1198 buffer, len, filename, FALSE );
1201 /***********************************************************************
1202 * GetPrivateProfileStringA (KERNEL32.@)
1204 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1205 LPCSTR def_val, LPSTR buffer,
1206 UINT len, LPCSTR filename )
1208 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1209 buffer, len, filename, TRUE );
1212 /***********************************************************************
1213 * GetPrivateProfileStringW (KERNEL32.@)
1215 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1216 LPCWSTR def_val, LPWSTR buffer,
1217 UINT len, LPCWSTR filename )
1219 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1220 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1221 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1222 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1223 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1224 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1225 bufferA, len, filenameA );
1226 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1227 buffer[len-1] = 0;
1228 HeapFree( GetProcessHeap(), 0, sectionA );
1229 HeapFree( GetProcessHeap(), 0, entryA );
1230 HeapFree( GetProcessHeap(), 0, filenameA );
1231 HeapFree( GetProcessHeap(), 0, def_valA );
1232 HeapFree( GetProcessHeap(), 0, bufferA);
1233 return ret;
1236 /***********************************************************************
1237 * GetProfileString (KERNEL.58)
1239 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1240 LPSTR buffer, UINT16 len )
1242 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1243 buffer, len, "win.ini", FALSE );
1246 /***********************************************************************
1247 * GetProfileStringA (KERNEL32.@)
1249 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1250 LPSTR buffer, UINT len )
1252 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1253 buffer, len, "win.ini", TRUE );
1256 /***********************************************************************
1257 * GetProfileStringW (KERNEL32.@)
1259 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1260 LPCWSTR def_val, LPWSTR buffer, UINT len )
1262 return GetPrivateProfileStringW( section, entry, def_val,
1263 buffer, len, wininiW );
1266 /***********************************************************************
1267 * WriteProfileString (KERNEL.59)
1269 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1270 LPCSTR string )
1272 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1275 /***********************************************************************
1276 * WriteProfileStringA (KERNEL32.@)
1278 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1279 LPCSTR string )
1281 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1284 /***********************************************************************
1285 * WriteProfileStringW (KERNEL32.@)
1287 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1288 LPCWSTR string )
1290 return WritePrivateProfileStringW( section, entry, string, wininiW );
1294 /***********************************************************************
1295 * GetPrivateProfileInt (KERNEL.127)
1297 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1298 INT16 def_val, LPCSTR filename )
1300 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1301 * here, but Win98SE doesn't care about this at all, so I deleted it.
1302 * AFAIR versions prior to Win9x had these limits, though. */
1303 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
1306 /***********************************************************************
1307 * GetPrivateProfileIntA (KERNEL32.@)
1309 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1310 INT def_val, LPCSTR filename )
1312 char buffer[20];
1313 long result;
1315 if (!PROFILE_GetPrivateProfileString( section, entry, "",
1316 buffer, sizeof(buffer), filename, FALSE ))
1317 return def_val;
1318 /* FIXME: if entry can be found but it's empty, then Win16 is
1319 * supposed to return 0 instead of def_val ! Difficult/problematic
1320 * to implement (every other failure also returns zero buffer),
1321 * thus wait until testing framework avail for making sure nothing
1322 * else gets broken that way. */
1323 if (!buffer[0]) return (UINT)def_val;
1325 /* Don't use strtol() here !
1326 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1327 YES, scan for unsigned format ! (otherwise compatibility error) */
1328 if (!sscanf(buffer, "%lu", &result)) return 0;
1329 return (UINT)result;
1332 /***********************************************************************
1333 * GetPrivateProfileIntW (KERNEL32.@)
1335 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1336 INT def_val, LPCWSTR filename )
1338 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1339 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1340 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1341 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1342 HeapFree( GetProcessHeap(), 0, sectionA );
1343 HeapFree( GetProcessHeap(), 0, filenameA );
1344 HeapFree( GetProcessHeap(), 0, entryA );
1345 return res;
1348 /***********************************************************************
1349 * GetPrivateProfileSection (KERNEL.418)
1351 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1352 UINT16 len, LPCSTR filename )
1354 return GetPrivateProfileSectionA( section, buffer, len, filename );
1357 /***********************************************************************
1358 * GetPrivateProfileSectionA (KERNEL32.@)
1360 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1361 DWORD len, LPCSTR filename )
1363 int ret = 0;
1365 EnterCriticalSection( &PROFILE_CritSect );
1367 if (PROFILE_Open( filename ))
1368 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1369 FALSE, TRUE);
1371 LeaveCriticalSection( &PROFILE_CritSect );
1373 return ret;
1376 /***********************************************************************
1377 * GetPrivateProfileSectionW (KERNEL32.@)
1380 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1381 DWORD len, LPCWSTR filename )
1384 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1385 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1386 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1387 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1388 filenameA );
1389 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1390 HeapFree( GetProcessHeap(), 0, sectionA );
1391 HeapFree( GetProcessHeap(), 0, filenameA );
1392 HeapFree( GetProcessHeap(), 0, bufferA);
1393 return ret;
1396 /***********************************************************************
1397 * GetProfileSection (KERNEL.419)
1399 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1401 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1404 /***********************************************************************
1405 * GetProfileSectionA (KERNEL32.@)
1407 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1409 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1412 /***********************************************************************
1413 * GetProfileSectionW (KERNEL32.@)
1415 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1417 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1421 /***********************************************************************
1422 * WritePrivateProfileString (KERNEL.129)
1424 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1425 LPCSTR string, LPCSTR filename )
1427 return WritePrivateProfileStringA(section,entry,string,filename);
1430 /***********************************************************************
1431 * WritePrivateProfileStringA (KERNEL32.@)
1433 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1434 LPCSTR string, LPCSTR filename )
1436 BOOL ret = FALSE;
1438 EnterCriticalSection( &PROFILE_CritSect );
1440 if (PROFILE_Open( filename ))
1442 if (!section && !entry && !string) /* documented "file flush" case */
1443 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1444 else {
1445 if (!section) {
1446 FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename);
1447 } else {
1448 ret = PROFILE_SetString( section, entry, string, FALSE);
1453 LeaveCriticalSection( &PROFILE_CritSect );
1454 return ret;
1457 /***********************************************************************
1458 * WritePrivateProfileStringW (KERNEL32.@)
1460 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1461 LPCWSTR string, LPCWSTR filename )
1463 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1464 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1465 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1466 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1467 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1468 stringA, filenameA );
1469 HeapFree( GetProcessHeap(), 0, sectionA );
1470 HeapFree( GetProcessHeap(), 0, entryA );
1471 HeapFree( GetProcessHeap(), 0, stringA );
1472 HeapFree( GetProcessHeap(), 0, filenameA );
1473 return res;
1476 /***********************************************************************
1477 * WritePrivateProfileSection (KERNEL.416)
1479 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1480 LPCSTR string, LPCSTR filename )
1482 return WritePrivateProfileSectionA( section, string, filename );
1485 /***********************************************************************
1486 * WritePrivateProfileSectionA (KERNEL32.@)
1488 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1489 LPCSTR string, LPCSTR filename )
1491 BOOL ret = FALSE;
1492 LPSTR p ;
1494 EnterCriticalSection( &PROFILE_CritSect );
1496 if (PROFILE_Open( filename )) {
1497 if (!section && !string)
1498 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1499 else if (!string) /* delete the named section*/
1500 ret = PROFILE_SetString(section,NULL,NULL, FALSE);
1501 else {
1502 PROFILE_DeleteAllKeys(section);
1503 ret = TRUE;
1504 while(*string) {
1505 LPSTR buf = HeapAlloc( GetProcessHeap(), 0, strlen(string)+1 );
1506 strcpy( buf, string );
1507 if((p=strchr( buf, '='))){
1508 *p='\0';
1509 ret = PROFILE_SetString( section, buf, p+1, TRUE);
1511 HeapFree( GetProcessHeap(), 0, buf );
1512 string += strlen(string)+1;
1517 LeaveCriticalSection( &PROFILE_CritSect );
1518 return ret;
1521 /***********************************************************************
1522 * WritePrivateProfileSectionW (KERNEL32.@)
1524 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1525 LPCWSTR string, LPCWSTR filename)
1528 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1529 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1530 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1531 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1532 HeapFree( GetProcessHeap(), 0, sectionA );
1533 HeapFree( GetProcessHeap(), 0, stringA );
1534 HeapFree( GetProcessHeap(), 0, filenameA );
1535 return res;
1538 /***********************************************************************
1539 * WriteProfileSection (KERNEL.417)
1541 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1543 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1546 /***********************************************************************
1547 * WriteProfileSectionA (KERNEL32.@)
1549 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1552 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1555 /***********************************************************************
1556 * WriteProfileSectionW (KERNEL32.@)
1558 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1560 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1563 /***********************************************************************
1564 * GetPrivateProfileSectionNames (KERNEL.143)
1566 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1567 LPCSTR filename )
1569 return GetPrivateProfileSectionNamesA(buffer,size,filename);
1573 /***********************************************************************
1574 * GetProfileSectionNames (KERNEL.142)
1576 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
1579 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
1583 /***********************************************************************
1584 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1586 * Returns the section names contained in the specified file.
1587 * FIXME: Where do we find this file when the path is relative?
1588 * The section names are returned as a list of strings with an extra
1589 * '\0' to mark the end of the list. Except for that the behavior
1590 * depends on the Windows version.
1592 * Win95:
1593 * - if the buffer is 0 or 1 character long then it is as if it was of
1594 * infinite length.
1595 * - otherwise, if the buffer is to small only the section names that fit
1596 * are returned.
1597 * - note that this means if the buffer was to small to return even just
1598 * the first section name then a single '\0' will be returned.
1599 * - the return value is the number of characters written in the buffer,
1600 * except if the buffer was too smal in which case len-2 is returned
1602 * Win2000:
1603 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1604 * '\0' and the return value is 0
1605 * - otherwise if the buffer is too small then the first section name that
1606 * does not fit is truncated so that the string list can be terminated
1607 * correctly (double '\0')
1608 * - the return value is the number of characters written in the buffer
1609 * except for the trailing '\0'. If the buffer is too small, then the
1610 * return value is len-2
1611 * - Win2000 has a bug that triggers when the section names and the
1612 * trailing '\0' fit exactly in the buffer. In that case the trailing
1613 * '\0' is missing.
1615 * Wine implements the observed Win2000 behavior (except for the bug).
1617 * Note that when the buffer is big enough then the return value may be any
1618 * value between 1 and len-1 (or len in Win95), including len-2.
1620 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1621 LPCSTR filename)
1624 DWORD ret = 0;
1626 EnterCriticalSection( &PROFILE_CritSect );
1628 if (PROFILE_Open( filename ))
1629 ret = PROFILE_GetSectionNames(buffer, size);
1631 LeaveCriticalSection( &PROFILE_CritSect );
1633 return ret;
1637 /***********************************************************************
1638 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1640 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1641 LPCWSTR filename)
1644 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1645 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1647 INT ret = GetPrivateProfileSectionNamesA(bufferA, size, filenameA);
1648 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1649 buffer[size-1] = 0;
1650 HeapFree( GetProcessHeap(), 0, bufferA);
1651 HeapFree( GetProcessHeap(), 0, filenameA );
1653 return ret;
1656 /***********************************************************************
1657 * GetPrivateProfileStruct (KERNEL.407)
1659 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1660 LPVOID buf, UINT16 len, LPCSTR filename)
1662 return GetPrivateProfileStructA( section, key, buf, len, filename );
1665 /***********************************************************************
1666 * GetPrivateProfileStructA (KERNEL32.@)
1668 * Should match Win95's behaviour pretty much
1670 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1671 LPVOID buf, UINT len, LPCSTR filename)
1673 BOOL ret = FALSE;
1675 EnterCriticalSection( &PROFILE_CritSect );
1677 if (PROFILE_Open( filename )) {
1678 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
1679 if (k) {
1680 TRACE("value (at %p): '%s'\n", k->value, k->value);
1681 if (((strlen(k->value) - 2) / 2) == len)
1683 LPSTR end, p;
1684 BOOL valid = TRUE;
1685 CHAR c;
1686 DWORD chksum = 0;
1688 end = k->value + strlen(k->value); /* -> '\0' */
1689 /* check for invalid chars in ASCII coded hex string */
1690 for (p=k->value; p < end; p++)
1692 if (!isxdigit(*p))
1694 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1695 *p, filename, section, key);
1696 valid = FALSE;
1697 break;
1700 if (valid)
1702 BOOL highnibble = TRUE;
1703 BYTE b = 0, val;
1704 LPBYTE binbuf = (LPBYTE)buf;
1706 end -= 2; /* don't include checksum in output data */
1707 /* translate ASCII hex format into binary data */
1708 for (p=k->value; p < end; p++)
1710 c = toupper(*p);
1711 val = (c > '9') ?
1712 (c - 'A' + 10) : (c - '0');
1714 if (highnibble)
1715 b = val << 4;
1716 else
1718 b += val;
1719 *binbuf++ = b; /* feed binary data into output */
1720 chksum += b; /* calculate checksum */
1722 highnibble ^= 1; /* toggle */
1724 /* retrieve stored checksum value */
1725 c = toupper(*p++);
1726 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1727 c = toupper(*p);
1728 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1729 if (b == (chksum & 0xff)) /* checksums match ? */
1730 ret = TRUE;
1735 LeaveCriticalSection( &PROFILE_CritSect );
1737 return ret;
1740 /***********************************************************************
1741 * GetPrivateProfileStructW (KERNEL32.@)
1743 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1744 LPVOID buffer, UINT len, LPCWSTR filename)
1746 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1747 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1748 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1749 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1751 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1752 len, filenameA );
1753 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1754 ((LPWSTR)buffer)[len-1] = 0;
1755 HeapFree( GetProcessHeap(), 0, bufferA);
1756 HeapFree( GetProcessHeap(), 0, sectionA );
1757 HeapFree( GetProcessHeap(), 0, keyA );
1758 HeapFree( GetProcessHeap(), 0, filenameA );
1760 return ret;
1765 /***********************************************************************
1766 * WritePrivateProfileStruct (KERNEL.406)
1768 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1769 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1771 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1774 /***********************************************************************
1775 * WritePrivateProfileStructA (KERNEL32.@)
1777 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1778 LPVOID buf, UINT bufsize, LPCSTR filename)
1780 BOOL ret = FALSE;
1781 LPBYTE binbuf;
1782 LPSTR outstring, p;
1783 DWORD sum = 0;
1785 if (!section && !key && !buf) /* flush the cache */
1786 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1788 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1789 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1790 p = outstring;
1791 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1792 *p++ = hex[*binbuf >> 4];
1793 *p++ = hex[*binbuf & 0xf];
1794 sum += *binbuf;
1796 /* checksum is sum & 0xff */
1797 *p++ = hex[(sum & 0xf0) >> 4];
1798 *p++ = hex[sum & 0xf];
1799 *p++ = '\0';
1801 EnterCriticalSection( &PROFILE_CritSect );
1803 if (PROFILE_Open( filename ))
1804 ret = PROFILE_SetString( section, key, outstring, FALSE);
1806 LeaveCriticalSection( &PROFILE_CritSect );
1808 HeapFree( GetProcessHeap(), 0, outstring );
1810 return ret;
1813 /***********************************************************************
1814 * WritePrivateProfileStructW (KERNEL32.@)
1816 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1817 LPVOID buf, UINT bufsize, LPCWSTR filename)
1819 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1820 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1821 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1822 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1823 filenameA );
1824 HeapFree( GetProcessHeap(), 0, sectionA );
1825 HeapFree( GetProcessHeap(), 0, keyA );
1826 HeapFree( GetProcessHeap(), 0, filenameA );
1828 return ret;
1832 /***********************************************************************
1833 * WriteOutProfiles (KERNEL.315)
1835 void WINAPI WriteOutProfiles16(void)
1837 EnterCriticalSection( &PROFILE_CritSect );
1838 PROFILE_FlushFile();
1839 LeaveCriticalSection( &PROFILE_CritSect );
1842 /***********************************************************************
1843 * CloseProfileUserMapping (KERNEL32.@)
1845 BOOL WINAPI CloseProfileUserMapping(void) {
1846 FIXME("(), stub!\n");
1847 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1848 return FALSE;