Release 20020904.
[wine/gsoc-2012-control.git] / files / profile.c
blob58ffa7e715759882f89c7c312f205384e0ef11c6
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <ctype.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winerror.h"
41 #include "ntddk.h"
42 #include "wine/winbase16.h"
43 #include "winreg.h"
44 #include "drive.h"
45 #include "file.h"
46 #include "heap.h"
47 #include "wine/unicode.h"
48 #include "wine/server.h"
49 #include "wine/library.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(profile);
54 typedef struct tagPROFILEKEY
56 WCHAR *value;
57 struct tagPROFILEKEY *next;
58 WCHAR name[1];
59 } PROFILEKEY;
61 typedef struct tagPROFILESECTION
63 struct tagPROFILEKEY *key;
64 struct tagPROFILESECTION *next;
65 WCHAR name[1];
66 } PROFILESECTION;
69 typedef struct
71 BOOL changed;
72 PROFILESECTION *section;
73 WCHAR *dos_name;
74 char *unix_name;
75 WCHAR *filename;
76 time_t mtime;
77 } PROFILE;
80 #define N_CACHED_PROFILES 10
82 /* Cached profile files */
83 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
85 #define CurProfile (MRUProfile[0])
87 /* wine.ini config file registry root */
88 static HKEY wine_profile_key;
90 #define PROFILE_MAX_LINE_LEN 1024
92 /* Wine profile name in $HOME directory; must begin with slash */
93 static const char PROFILE_WineIniName[] = "/.winerc";
95 /* Wine profile: the profile file being used */
96 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
98 /* Check for comments in profile */
99 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
101 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
103 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
105 static const char hex[16] = "0123456789ABCDEF";
107 /***********************************************************************
108 * PROFILE_CopyEntry
110 * Copy the content of an entry into a buffer, removing quotes, and possibly
111 * translating environment variables.
113 static void PROFILE_CopyEntry( LPWSTR buffer, LPCWSTR value, int len,
114 int handle_env, BOOL strip_quote )
116 WCHAR quote = '\0';
117 LPCWSTR p;
119 if(!buffer) return;
121 if (strip_quote && ((*value == '\'') || (*value == '\"')))
123 if (value[1] && (value[strlenW(value)-1] == *value)) quote = *value++;
126 if (!handle_env)
128 lstrcpynW( buffer, value, len );
129 if (quote && (len >= strlenW(value))) buffer[strlenW(buffer)-1] = '\0';
130 return;
133 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
135 if ((*p == '$') && (p[1] == '{'))
137 WCHAR env_val[1024];
138 LPCWSTR p2 = strchrW( p, '}' );
139 int copy_len;
140 if (!p2) continue; /* ignore it */
141 copy_len = min( 1024, (int)(p2-p)-1 );
142 strncpyW(env_val, p + 2, copy_len );
143 env_val[copy_len - 1] = 0; /* ensure 0 termination */
144 *buffer = 0;
145 if (GetEnvironmentVariableW( env_val, buffer, len))
147 copy_len = strlenW( buffer );
148 buffer += copy_len;
149 len -= copy_len;
151 p = p2 + 1;
154 if (quote && (len > 1)) buffer--;
155 *buffer = '\0';
159 /***********************************************************************
160 * PROFILE_Save
162 * Save a profile tree to a file.
164 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
166 PROFILEKEY *key;
167 char buffer[PROFILE_MAX_LINE_LEN];
169 for ( ; section; section = section->next)
171 if (section->name[0])
173 WideCharToMultiByte(CP_ACP, 0, section->name, -1, buffer, sizeof(buffer), NULL, NULL);
174 fprintf( file, "\r\n[%s]\r\n", buffer );
176 for (key = section->key; key; key = key->next)
178 WideCharToMultiByte(CP_ACP, 0, key->name, -1, buffer, sizeof(buffer), NULL, NULL);
179 fprintf( file, "%s", buffer );
180 if (key->value)
182 WideCharToMultiByte(CP_ACP, 0, key->value, -1, buffer, sizeof(buffer), NULL, NULL);
183 fprintf( file, "=%s", buffer );
185 fprintf( file, "\r\n" );
191 /***********************************************************************
192 * PROFILE_Free
194 * Free a profile tree.
196 static void PROFILE_Free( PROFILESECTION *section )
198 PROFILESECTION *next_section;
199 PROFILEKEY *key, *next_key;
201 for ( ; section; section = next_section)
203 for (key = section->key; key; key = next_key)
205 next_key = key->next;
206 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
207 HeapFree( GetProcessHeap(), 0, key );
209 next_section = section->next;
210 HeapFree( GetProcessHeap(), 0, section );
214 static inline int PROFILE_isspace(char c)
216 if (isspace(c)) return 1;
217 if (c=='\r' || c==0x1a) return 1;
218 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
219 return 0;
223 /***********************************************************************
224 * PROFILE_Load
226 * Load a profile tree from a file.
228 static PROFILESECTION *PROFILE_Load( FILE *file )
230 char buffer[PROFILE_MAX_LINE_LEN];
231 char *p, *p2;
232 int line = 0, len;
233 PROFILESECTION *section, *first_section;
234 PROFILESECTION **next_section;
235 PROFILEKEY *key, *prev_key, **next_key;
237 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
238 if(first_section == NULL) return NULL;
239 first_section->name[0] = 0;
240 first_section->key = NULL;
241 first_section->next = NULL;
242 next_section = &first_section->next;
243 next_key = &first_section->key;
244 prev_key = NULL;
246 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
248 line++;
249 p = buffer;
250 while (*p && PROFILE_isspace(*p)) p++;
251 if (*p == '[') /* section start */
253 if (!(p2 = strrchr( p, ']' )))
255 WARN("Invalid section header at line %d: '%s'\n",
256 line, p );
258 else
260 *p2 = '\0';
261 p++;
262 len = strlen(p);
263 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) )))
264 break;
265 MultiByteToWideChar(CP_ACP, 0, p, -1, section->name, len + 1);
266 section->key = NULL;
267 section->next = NULL;
268 *next_section = section;
269 next_section = &section->next;
270 next_key = &section->key;
271 prev_key = NULL;
273 TRACE("New section: %s\n", debugstr_w(section->name));
275 continue;
279 p2=p+strlen(p) - 1;
280 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
282 if ((p2 = strchr( p, '=' )) != NULL)
284 char *p3 = p2 - 1;
285 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
286 *p2++ = '\0';
287 while (*p2 && PROFILE_isspace(*p2)) p2++;
290 if(*p || !prev_key || *prev_key->name)
292 len = strlen(p);
293 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + len * sizeof(WCHAR) ))) break;
294 MultiByteToWideChar(CP_ACP, 0, p, -1, key->name, len + 1);
295 if (p2)
297 len = strlen(p2) + 1;
298 key->value = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
299 MultiByteToWideChar(CP_ACP, 0, p2, -1, key->value, len);
301 else key->value = NULL;
303 key->next = NULL;
304 *next_key = key;
305 next_key = &key->next;
306 prev_key = key;
308 TRACE("New key: name=%s, value=%s\n",
309 debugstr_w(key->name), key->value ? debugstr_w(key->value) : "(none)");
312 return first_section;
315 /* convert the .winerc file to the new format */
316 static void convert_config( FILE *in, const char *output_name )
318 char buffer[PROFILE_MAX_LINE_LEN];
319 char *p, *p2;
320 FILE *out;
322 /* create the output file, only if it doesn't exist already */
323 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
324 if (fd == -1)
326 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
327 ExitProcess(1);
330 out = fdopen( fd, "w" );
331 fprintf( out, "WINE REGISTRY Version 2\n" );
332 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
333 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
335 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
336 p = buffer;
337 while (*p && PROFILE_isspace(*p)) p++;
338 if (*p == '[') /* section start */
340 if ((p2 = strrchr( p, ']' )))
342 *p2 = '\0';
343 p++;
344 fprintf( out, "[%s]\n", p );
346 continue;
349 if (*p == ';' || *p == '#')
351 fprintf( out, "%s\n", p );
352 continue;
355 p2=p+strlen(p) - 1;
356 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
358 if ((p2 = strchr( p, '=' )) != NULL)
360 char *p3 = p2 - 1;
361 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
362 *p2++ = '\0';
363 while (*p2 && PROFILE_isspace(*p2)) p2++;
366 if (!*p)
368 fprintf( out, "\n" );
369 continue;
371 fputc( '"', out );
372 while (*p)
374 if (*p == '\\') fputc( '\\', out );
375 fputc( *p, out );
376 p++;
378 fprintf( out, "\" = \"" );
379 if (p2)
381 while (*p2)
383 if (*p2 == '\\') fputc( '\\', out );
384 fputc( *p2, out );
385 p2++;
388 fprintf( out, "\"\n" );
390 fclose( out );
394 /***********************************************************************
395 * PROFILE_DeleteSection
397 * Delete a section from a profile tree.
399 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCWSTR name )
401 while (*section)
403 if ((*section)->name[0] && !strcmpiW( (*section)->name, name ))
405 PROFILESECTION *to_del = *section;
406 *section = to_del->next;
407 to_del->next = NULL;
408 PROFILE_Free( to_del );
409 return TRUE;
411 section = &(*section)->next;
413 return FALSE;
417 /***********************************************************************
418 * PROFILE_DeleteKey
420 * Delete a key from a profile tree.
422 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
423 LPCWSTR section_name, LPCWSTR key_name )
425 while (*section)
427 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
429 PROFILEKEY **key = &(*section)->key;
430 while (*key)
432 if (!strcmpiW( (*key)->name, key_name ))
434 PROFILEKEY *to_del = *key;
435 *key = to_del->next;
436 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
437 HeapFree( GetProcessHeap(), 0, to_del );
438 return TRUE;
440 key = &(*key)->next;
443 section = &(*section)->next;
445 return FALSE;
449 /***********************************************************************
450 * PROFILE_DeleteAllKeys
452 * Delete all keys from a profile tree.
454 void PROFILE_DeleteAllKeys( LPCWSTR section_name)
456 PROFILESECTION **section= &CurProfile->section;
457 while (*section)
459 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
461 PROFILEKEY **key = &(*section)->key;
462 while (*key)
464 PROFILEKEY *to_del = *key;
465 *key = to_del->next;
466 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
467 HeapFree( GetProcessHeap(), 0, to_del );
468 CurProfile->changed =TRUE;
471 section = &(*section)->next;
476 /***********************************************************************
477 * PROFILE_Find
479 * Find a key in a profile tree, optionally creating it.
481 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, LPCWSTR section_name,
482 LPCWSTR key_name, BOOL create, BOOL create_always )
484 LPCWSTR p;
485 int seclen, keylen;
487 while (PROFILE_isspace(*section_name)) section_name++;
488 p = section_name + strlenW(section_name) - 1;
489 while ((p > section_name) && PROFILE_isspace(*p)) p--;
490 seclen = p - section_name + 1;
492 while (PROFILE_isspace(*key_name)) key_name++;
493 p = key_name + strlenW(key_name) - 1;
494 while ((p > key_name) && PROFILE_isspace(*p)) p--;
495 keylen = p - key_name + 1;
497 while (*section)
499 if ( ((*section)->name[0])
500 && (!(strncmpiW( (*section)->name, section_name, seclen )))
501 && (((*section)->name)[seclen] == '\0') )
503 PROFILEKEY **key = &(*section)->key;
505 while (*key)
507 /* If create_always is FALSE then we check if the keyname already exists.
508 * Otherwise we add it regardless of its existence, to allow
509 * keys to be added more then once in some cases.
511 if(!create_always)
513 if ( (!(strncmpiW( (*key)->name, key_name, keylen )))
514 && (((*key)->name)[keylen] == '\0') )
515 return *key;
517 key = &(*key)->next;
519 if (!create) return NULL;
520 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
521 return NULL;
522 strcpyW( (*key)->name, key_name );
523 (*key)->value = NULL;
524 (*key)->next = NULL;
525 return *key;
527 section = &(*section)->next;
529 if (!create) return NULL;
530 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlenW(section_name) * sizeof(WCHAR) );
531 if(*section == NULL) return NULL;
532 strcpyW( (*section)->name, section_name );
533 (*section)->next = NULL;
534 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
535 sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
537 HeapFree(GetProcessHeap(), 0, *section);
538 return NULL;
540 strcpyW( (*section)->key->name, key_name );
541 (*section)->key->value = NULL;
542 (*section)->key->next = NULL;
543 return (*section)->key;
547 /***********************************************************************
548 * PROFILE_FlushFile
550 * Flush the current profile to disk if changed.
552 static BOOL PROFILE_FlushFile(void)
554 char *p, buffer[MAX_PATHNAME_LEN];
555 const char *unix_name;
556 FILE *file = NULL;
557 struct stat buf;
559 if(!CurProfile)
561 WARN("No current profile!\n");
562 return FALSE;
565 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
566 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
568 int drive = toupperW(CurProfile->dos_name[0]) - 'A';
569 WCHAR *name;
570 /* Try to create it in $HOME/.wine */
571 /* FIXME: this will need a more general solution */
572 strcpy( buffer, wine_get_config_dir() );
573 p = buffer + strlen(buffer);
574 *p++ = '/';
575 *p = 0; /* make strlen() below happy */
576 name = strrchrW( CurProfile->dos_name, '\\' ) + 1;
577 WideCharToMultiByte(DRIVE_GetCodepage(drive), 0, name, -1,
578 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
579 file = fopen( buffer, "w" );
580 unix_name = buffer;
583 if (!file)
585 WARN("could not save profile file %s\n", debugstr_w(CurProfile->dos_name));
586 return FALSE;
589 TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile->dos_name), unix_name );
590 PROFILE_Save( file, CurProfile->section );
591 fclose( file );
592 CurProfile->changed = FALSE;
593 if(!stat(unix_name,&buf))
594 CurProfile->mtime=buf.st_mtime;
595 return TRUE;
599 /***********************************************************************
600 * PROFILE_ReleaseFile
602 * Flush the current profile to disk and remove it from the cache.
604 static void PROFILE_ReleaseFile(void)
606 PROFILE_FlushFile();
607 PROFILE_Free( CurProfile->section );
608 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
609 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
610 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
611 CurProfile->changed = FALSE;
612 CurProfile->section = NULL;
613 CurProfile->dos_name = NULL;
614 CurProfile->unix_name = NULL;
615 CurProfile->filename = NULL;
616 CurProfile->mtime = 0;
620 /***********************************************************************
621 * PROFILE_Open
623 * Open a profile file, checking the cached file first.
625 static BOOL PROFILE_Open( LPCWSTR filename )
627 DOS_FULL_NAME full_name;
628 char buffer[MAX_PATHNAME_LEN];
629 WCHAR *newdos_name;
630 WCHAR *name;
631 char *p;
632 FILE *file = NULL;
633 int i,j;
634 struct stat buf;
635 PROFILE *tempProfile;
637 /* First time around */
639 if(!CurProfile)
640 for(i=0;i<N_CACHED_PROFILES;i++)
642 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
643 if(MRUProfile[i] == NULL) break;
644 MRUProfile[i]->changed=FALSE;
645 MRUProfile[i]->section=NULL;
646 MRUProfile[i]->dos_name=NULL;
647 MRUProfile[i]->unix_name=NULL;
648 MRUProfile[i]->filename=NULL;
649 MRUProfile[i]->mtime=0;
652 /* Check for a match */
654 if (strchrW( filename, '/' ) || strchrW( filename, '\\' ) ||
655 strchrW( filename, ':' ))
657 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
659 else
661 static const WCHAR bkslashW[] = {'\\',0};
662 WCHAR windirW[MAX_PATH];
664 GetWindowsDirectoryW( windirW, MAX_PATH );
665 strcatW( windirW, bkslashW );
666 strcatW( windirW, filename );
667 if (!DOSFS_GetFullName( windirW, FALSE, &full_name )) return FALSE;
670 for(i=0;i<N_CACHED_PROFILES;i++)
672 if ((MRUProfile[i]->filename && !strcmpW( filename, MRUProfile[i]->filename )) ||
673 (MRUProfile[i]->dos_name && !strcmpW( full_name.short_name, MRUProfile[i]->dos_name )))
675 if(i)
677 PROFILE_FlushFile();
678 tempProfile=MRUProfile[i];
679 for(j=i;j>0;j--)
680 MRUProfile[j]=MRUProfile[j-1];
681 CurProfile=tempProfile;
683 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
684 TRACE("(%s): already opened (mru=%d)\n",
685 debugstr_w(filename), i );
686 else
687 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
688 debugstr_w(filename), i );
689 return TRUE;
693 /* Flush the old current profile */
694 PROFILE_FlushFile();
696 /* Make the oldest profile the current one only in order to get rid of it */
697 if(i==N_CACHED_PROFILES)
699 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
700 for(i=N_CACHED_PROFILES-1;i>0;i--)
701 MRUProfile[i]=MRUProfile[i-1];
702 CurProfile=tempProfile;
704 if(CurProfile->filename) PROFILE_ReleaseFile();
706 /* OK, now that CurProfile is definitely free we assign it our new file */
707 newdos_name = HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name.short_name)+1) * sizeof(WCHAR) );
708 strcpyW( newdos_name, full_name.short_name );
709 CurProfile->dos_name = newdos_name;
710 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, (strlenW(filename)+1) * sizeof(WCHAR) );
711 strcpyW( CurProfile->filename, filename );
713 /* Try to open the profile file, first in $HOME/.wine */
715 /* FIXME: this will need a more general solution */
716 strcpy( buffer, wine_get_config_dir() );
717 p = buffer + strlen(buffer);
718 *p++ = '/';
719 *p = 0; /* make strlen() below happy */
720 name = strrchrW( newdos_name, '\\' ) + 1;
721 WideCharToMultiByte(DRIVE_GetCodepage(full_name.drive), 0, name, -1,
722 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
723 if ((file = fopen( buffer, "r" )))
725 TRACE("(%s): found it in %s\n", debugstr_w(filename), buffer );
726 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
727 strcpy( CurProfile->unix_name, buffer );
729 else
731 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
732 strcpy( CurProfile->unix_name, full_name.long_name );
733 if ((file = fopen( full_name.long_name, "r" )))
734 TRACE("(%s): found it in %s\n",
735 debugstr_w(filename), full_name.long_name );
738 if (file)
740 CurProfile->section = PROFILE_Load( file );
741 fclose( file );
742 if(!stat(CurProfile->unix_name,&buf))
743 CurProfile->mtime=buf.st_mtime;
745 else
747 /* Does not exist yet, we will create it in PROFILE_FlushFile */
748 WARN("profile file %s not found\n", debugstr_w(newdos_name) );
750 return TRUE;
754 /***********************************************************************
755 * PROFILE_GetSection
757 * Returns all keys of a section.
758 * If return_values is TRUE, also include the corresponding values.
760 static INT PROFILE_GetSection( PROFILESECTION *section, LPCWSTR section_name,
761 LPWSTR buffer, UINT len, BOOL handle_env,
762 BOOL return_values )
764 PROFILEKEY *key;
766 if(!buffer) return 0;
768 TRACE("%s,%p,%u\n", debugstr_w(section_name), buffer, len);
770 while (section)
772 if (section->name[0] && !strcmpiW( section->name, section_name ))
774 UINT oldlen = len;
775 for (key = section->key; key; key = key->next)
777 if (len <= 2) break;
778 if (!*key->name) continue; /* Skip empty lines */
779 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
780 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env, 0 );
781 len -= strlenW(buffer) + 1;
782 buffer += strlenW(buffer) + 1;
783 if (len < 2)
784 break;
785 if (return_values && key->value) {
786 buffer[-1] = '=';
787 PROFILE_CopyEntry ( buffer,
788 key->value, len - 1, handle_env, 0 );
789 len -= strlenW(buffer) + 1;
790 buffer += strlenW(buffer) + 1;
793 *buffer = '\0';
794 if (len <= 1)
795 /*If either lpszSection or lpszKey is NULL and the supplied
796 destination buffer is too small to hold all the strings,
797 the last string is truncated and followed by two null characters.
798 In this case, the return value is equal to cchReturnBuffer
799 minus two. */
801 buffer[-1] = '\0';
802 return oldlen - 2;
804 return oldlen - len;
806 section = section->next;
808 buffer[0] = buffer[1] = '\0';
809 return 0;
812 /* See GetPrivateProfileSectionNamesA for documentation */
813 static INT PROFILE_GetSectionNames( LPWSTR buffer, UINT len )
815 LPWSTR buf;
816 UINT f,l;
817 PROFILESECTION *section;
819 if (!buffer || !len)
820 return 0;
821 if (len==1) {
822 *buffer='\0';
823 return 0;
826 f=len-1;
827 buf=buffer;
828 section = CurProfile->section;
829 while ((section!=NULL)) {
830 if (section->name[0]) {
831 l = strlenW(section->name)+1;
832 if (l > f) {
833 if (f>0) {
834 strncpyW(buf, section->name, f-1);
835 buf += f-1;
836 *buf++='\0';
838 *buf='\0';
839 return len-2;
841 strcpyW(buf, section->name);
842 buf += l;
843 f -= l;
845 section = section->next;
847 *buf='\0';
848 return buf-buffer;
852 /***********************************************************************
853 * PROFILE_GetString
855 * Get a profile string.
857 * Tests with GetPrivateProfileString16, W95a,
858 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
859 * section key_name def_val res buffer
860 * "set1" "1" "x" 43 [data]
861 * "set1" "1 " "x" 43 [data] (!)
862 * "set1" " 1 "' "x" 43 [data] (!)
863 * "set1" "" "x" 1 "x"
864 * "set1" "" "x " 1 "x" (!)
865 * "set1" "" " x " 3 " x" (!)
866 * "set1" NULL "x" 6 "1\02\03\0\0"
867 * "set1" "" "x" 1 "x"
868 * NULL "1" "x" 0 "" (!)
869 * "" "1" "x" 1 "x"
870 * NULL NULL "" 0 ""
874 static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name,
875 LPCWSTR def_val, LPWSTR buffer, UINT len )
877 PROFILEKEY *key = NULL;
878 static const WCHAR empty_strW[] = { 0 };
880 if(!buffer) return 0;
882 if (!def_val) def_val = empty_strW;
883 if (key_name)
885 if (!key_name[0])
887 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
888 return 0;
890 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
891 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
892 len, FALSE, TRUE );
893 TRACE("(%s,%s,%s): returning %s\n",
894 debugstr_w(section), debugstr_w(key_name),
895 debugstr_w(def_val), debugstr_w(buffer) );
896 return strlenW( buffer );
898 /* no "else" here ! */
899 if (section && section[0])
901 INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE, FALSE);
902 if (!buffer[0]) /* no luck -> def_val */
904 PROFILE_CopyEntry(buffer, def_val, len, FALSE, TRUE);
905 ret = strlenW(buffer);
907 return ret;
909 buffer[0] = '\0';
910 return 0;
914 /***********************************************************************
915 * PROFILE_SetString
917 * Set a profile string.
919 static BOOL PROFILE_SetString( LPCWSTR section_name, LPCWSTR key_name,
920 LPCWSTR value, BOOL create_always )
922 if (!key_name) /* Delete a whole section */
924 TRACE("(%s)\n", debugstr_w(section_name));
925 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
926 section_name );
927 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
928 this is not an error on application's level.*/
930 else if (!value) /* Delete a key */
932 TRACE("(%s,%s)\n", debugstr_w(section_name), debugstr_w(key_name) );
933 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
934 section_name, key_name );
935 return TRUE; /* same error handling as above */
937 else /* Set the key value */
939 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
940 key_name, TRUE, create_always );
941 TRACE("(%s,%s,%s):\n",
942 debugstr_w(section_name), debugstr_w(key_name), debugstr_w(value) );
943 if (!key) return FALSE;
944 if (key->value)
946 /* strip the leading spaces. We can safely strip \n\r and
947 * friends too, they should not happen here anyway. */
948 while (PROFILE_isspace(*value)) value++;
950 if (!strcmpW( key->value, value ))
952 TRACE(" no change needed\n" );
953 return TRUE; /* No change needed */
955 TRACE(" replacing %s\n", debugstr_w(key->value) );
956 HeapFree( GetProcessHeap(), 0, key->value );
958 else TRACE(" creating key\n" );
959 key->value = HeapAlloc( GetProcessHeap(), 0, (strlenW(value)+1) * sizeof(WCHAR) );
960 strcpyW( key->value, value );
961 CurProfile->changed = TRUE;
963 return TRUE;
967 /***********************************************************************
968 * PROFILE_GetWineIniString
970 * Get a config string from the wine.ini file.
972 int PROFILE_GetWineIniString( LPCWSTR section, LPCWSTR key_name,
973 LPCWSTR def, LPWSTR buffer, int len )
975 WCHAR tmp[PROFILE_MAX_LINE_LEN];
976 HKEY hkey;
977 DWORD err;
979 if (!(err = RegOpenKeyW( wine_profile_key, section, &hkey )))
981 DWORD type;
982 DWORD count = sizeof(tmp);
983 err = RegQueryValueExW( hkey, key_name, 0, &type, (LPBYTE)tmp, &count );
984 RegCloseKey( hkey );
987 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE, TRUE );
988 TRACE( "(%s,%s,%s): returning %s\n", debugstr_w(section),
989 debugstr_w(key_name), debugstr_w(def), debugstr_w(buffer) );
990 return strlenW(buffer);
994 /******************************************************************************
996 * PROFILE_GetWineIniBool
998 * Reads a boolean value from the wine.ini file. This function attempts to
999 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
1000 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
1001 * true. Anything else results in the return of the default value.
1003 * This function uses 1 to indicate true, and 0 for false. You can check
1004 * for existence by setting def to something other than 0 or 1 and
1005 * examining the return value.
1007 int PROFILE_GetWineIniBool( LPCWSTR section, LPCWSTR key_name, int def )
1009 static const WCHAR def_valueW[] = {'~',0};
1010 WCHAR key_value[2];
1011 int retval;
1013 PROFILE_GetWineIniString(section, key_name, def_valueW, key_value, 2);
1015 switch(key_value[0]) {
1016 case 'n':
1017 case 'N':
1018 case 'f':
1019 case 'F':
1020 case '0':
1021 retval = 0;
1022 break;
1024 case 'y':
1025 case 'Y':
1026 case 't':
1027 case 'T':
1028 case '1':
1029 retval = 1;
1030 break;
1032 default:
1033 retval = def;
1036 TRACE("(%s, %s, %s), [%c], ret %s\n", debugstr_w(section), debugstr_w(key_name),
1037 def ? "TRUE" : "FALSE", key_value[0],
1038 retval ? "TRUE" : "FALSE");
1040 return retval;
1044 /***********************************************************************
1045 * PROFILE_LoadWineIni
1047 * Load the old .winerc file.
1049 int PROFILE_LoadWineIni(void)
1051 OBJECT_ATTRIBUTES attr;
1052 UNICODE_STRING nameW;
1053 char buffer[MAX_PATHNAME_LEN];
1054 const char *p;
1055 FILE *f;
1056 HKEY hKeySW;
1057 DWORD disp;
1059 attr.Length = sizeof(attr);
1060 attr.RootDirectory = 0;
1061 attr.ObjectName = &nameW;
1062 attr.Attributes = 0;
1063 attr.SecurityDescriptor = NULL;
1064 attr.SecurityQualityOfService = NULL;
1066 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1067 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1068 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1070 ERR("Cannot create config registry key\n" );
1071 ExitProcess( 1 );
1073 RtlFreeUnicodeString( &nameW );
1074 NtClose( hKeySW );
1076 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1077 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1078 NULL, REG_OPTION_VOLATILE, &disp ))
1080 ERR("Cannot create config registry key\n" );
1081 ExitProcess( 1 );
1083 RtlFreeUnicodeString( &nameW );
1085 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1087 if ((p = getenv( "HOME" )) != NULL)
1089 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1090 strcat( buffer, PROFILE_WineIniName );
1091 if ((f = fopen( buffer, "r" )) != NULL)
1093 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1095 /* convert to the new format */
1096 sprintf( buffer, "%s/config", wine_get_config_dir() );
1097 convert_config( f, buffer );
1098 fclose( f );
1100 MESSAGE( "The '%s' configuration file has been converted\n"
1101 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1102 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1103 "and then remove the old one and restart Wine.\n" );
1104 ExitProcess(0);
1107 else WARN("could not get $HOME value for config file.\n" );
1109 MESSAGE( "Can't open configuration file %s/config\n", wine_get_config_dir() );
1110 return 0;
1114 /***********************************************************************
1115 * PROFILE_UsageWineIni
1117 * Explain the wine.ini file to those who don't read documentation.
1118 * Keep below one screenful in length so that error messages above are
1119 * noticed.
1121 void PROFILE_UsageWineIni(void)
1123 MESSAGE("Perhaps you have not properly edited or created "
1124 "your Wine configuration file.\n");
1125 MESSAGE("This is (supposed to be) '%s/config'\n", wine_get_config_dir());
1126 /* RTFM, so to say */
1130 /********************* API functions **********************************/
1132 /***********************************************************************
1133 * GetProfileInt (KERNEL.57)
1135 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1137 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1141 /***********************************************************************
1142 * GetProfileIntA (KERNEL32.@)
1144 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1146 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1149 /***********************************************************************
1150 * GetProfileIntW (KERNEL32.@)
1152 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1154 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1158 * if allow_section_name_copy is TRUE, allow the copying :
1159 * - of Section names if 'section' is NULL
1160 * - of Keys in a Section if 'entry' is NULL
1161 * (see MSDN doc for GetPrivateProfileString)
1163 static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry,
1164 LPCWSTR def_val, LPWSTR buffer,
1165 UINT len, LPCWSTR filename,
1166 BOOL allow_section_name_copy )
1168 int ret;
1169 LPWSTR pDefVal = NULL;
1171 if (!filename)
1172 filename = wininiW;
1174 TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section), debugstr_w(entry),
1175 debugstr_w(def_val), buffer, len, debugstr_w(filename));
1177 /* strip any trailing ' ' of def_val. */
1178 if (def_val)
1180 LPCWSTR p = &def_val[strlenW(def_val)]; /* even "" works ! */
1182 while (p > def_val)
1184 p--;
1185 if ((*p) != ' ')
1186 break;
1188 if (*p == ' ') /* ouch, contained trailing ' ' */
1190 int len = (int)(p - def_val);
1191 pDefVal = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1192 strncpyW(pDefVal, def_val, len);
1193 pDefVal[len] = '\0';
1196 if (!pDefVal)
1197 pDefVal = (LPWSTR)def_val;
1199 EnterCriticalSection( &PROFILE_CritSect );
1201 if (PROFILE_Open( filename )) {
1202 if ((allow_section_name_copy) && (section == NULL))
1203 ret = PROFILE_GetSectionNames(buffer, len);
1204 else
1205 /* PROFILE_GetString already handles the 'entry == NULL' case */
1206 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1207 } else {
1208 lstrcpynW( buffer, pDefVal, len );
1209 ret = strlenW( buffer );
1212 LeaveCriticalSection( &PROFILE_CritSect );
1214 if (pDefVal != def_val) /* allocated */
1215 HeapFree(GetProcessHeap(), 0, pDefVal);
1217 TRACE("returning %s, %d\n", debugstr_w(buffer), ret);
1219 return ret;
1222 /***********************************************************************
1223 * GetPrivateProfileString (KERNEL.128)
1225 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1226 LPCSTR def_val, LPSTR buffer,
1227 UINT16 len, LPCSTR filename )
1229 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1230 LPWSTR bufferW;
1231 INT16 retW, ret = 0;
1233 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1234 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1235 else sectionW.Buffer = NULL;
1236 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1237 else entryW.Buffer = NULL;
1238 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1239 else def_valW.Buffer = NULL;
1240 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1241 else filenameW.Buffer = NULL;
1243 retW = PROFILE_GetPrivateProfileString( sectionW.Buffer, entryW.Buffer,
1244 def_valW.Buffer, bufferW, len,
1245 filenameW.Buffer, FALSE );
1246 if (len)
1248 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1249 if (!ret)
1251 ret = len - 1;
1252 buffer[ret] = 0;
1254 else
1255 ret--; /* strip terminating 0 */
1258 RtlFreeUnicodeString(&sectionW);
1259 RtlFreeUnicodeString(&entryW);
1260 RtlFreeUnicodeString(&def_valW);
1261 RtlFreeUnicodeString(&filenameW);
1262 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1263 return ret;
1266 /***********************************************************************
1267 * GetPrivateProfileStringA (KERNEL32.@)
1269 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1270 LPCSTR def_val, LPSTR buffer,
1271 UINT len, LPCSTR filename )
1273 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1274 LPWSTR bufferW;
1275 INT retW, ret = 0;
1277 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1278 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1279 else sectionW.Buffer = NULL;
1280 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1281 else entryW.Buffer = NULL;
1282 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1283 else def_valW.Buffer = NULL;
1284 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1285 else filenameW.Buffer = NULL;
1287 retW = GetPrivateProfileStringW( sectionW.Buffer, entryW.Buffer,
1288 def_valW.Buffer, bufferW, len,
1289 filenameW.Buffer);
1290 if (len)
1292 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1293 if (!ret)
1295 ret = len - 1;
1296 buffer[ret] = 0;
1298 else
1299 ret--; /* strip terminating 0 */
1302 RtlFreeUnicodeString(&sectionW);
1303 RtlFreeUnicodeString(&entryW);
1304 RtlFreeUnicodeString(&def_valW);
1305 RtlFreeUnicodeString(&filenameW);
1306 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1307 return ret;
1310 /***********************************************************************
1311 * GetPrivateProfileStringW (KERNEL32.@)
1313 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1314 LPCWSTR def_val, LPWSTR buffer,
1315 UINT len, LPCWSTR filename )
1317 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1318 buffer, len, filename, TRUE );
1321 /***********************************************************************
1322 * GetProfileString (KERNEL.58)
1324 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1325 LPSTR buffer, UINT16 len )
1327 return GetPrivateProfileString16( section, entry, def_val,
1328 buffer, len, "win.ini" );
1331 /***********************************************************************
1332 * GetProfileStringA (KERNEL32.@)
1334 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1335 LPSTR buffer, UINT len )
1337 return GetPrivateProfileStringA( section, entry, def_val,
1338 buffer, len, "win.ini" );
1341 /***********************************************************************
1342 * GetProfileStringW (KERNEL32.@)
1344 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1345 LPCWSTR def_val, LPWSTR buffer, UINT len )
1347 return GetPrivateProfileStringW( section, entry, def_val,
1348 buffer, len, wininiW );
1351 /***********************************************************************
1352 * WriteProfileString (KERNEL.59)
1354 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1355 LPCSTR string )
1357 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1360 /***********************************************************************
1361 * WriteProfileStringA (KERNEL32.@)
1363 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1364 LPCSTR string )
1366 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1369 /***********************************************************************
1370 * WriteProfileStringW (KERNEL32.@)
1372 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1373 LPCWSTR string )
1375 return WritePrivateProfileStringW( section, entry, string, wininiW );
1379 /***********************************************************************
1380 * GetPrivateProfileInt (KERNEL.127)
1382 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1383 INT16 def_val, LPCSTR filename )
1385 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1386 * here, but Win98SE doesn't care about this at all, so I deleted it.
1387 * AFAIR versions prior to Win9x had these limits, though. */
1388 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
1391 /***********************************************************************
1392 * GetPrivateProfileIntA (KERNEL32.@)
1394 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1395 INT def_val, LPCSTR filename )
1397 char buffer[20];
1398 long result;
1400 if (!GetPrivateProfileStringA( section, entry, "",
1401 buffer, sizeof(buffer), filename ))
1402 return def_val;
1403 /* FIXME: if entry can be found but it's empty, then Win16 is
1404 * supposed to return 0 instead of def_val ! Difficult/problematic
1405 * to implement (every other failure also returns zero buffer),
1406 * thus wait until testing framework avail for making sure nothing
1407 * else gets broken that way. */
1408 if (!buffer[0]) return (UINT)def_val;
1410 /* Don't use strtol() here !
1411 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1412 YES, scan for unsigned format ! (otherwise compatibility error) */
1413 if (!sscanf(buffer, "%lu", &result)) return 0;
1414 return (UINT)result;
1417 /***********************************************************************
1418 * GetPrivateProfileIntW (KERNEL32.@)
1420 * FIXME: rewrite using unicode
1422 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1423 INT def_val, LPCWSTR filename )
1425 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1426 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1427 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1428 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1429 HeapFree( GetProcessHeap(), 0, sectionA );
1430 HeapFree( GetProcessHeap(), 0, filenameA );
1431 HeapFree( GetProcessHeap(), 0, entryA );
1432 return res;
1435 /***********************************************************************
1436 * GetPrivateProfileSection (KERNEL.418)
1438 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1439 UINT16 len, LPCSTR filename )
1441 return GetPrivateProfileSectionA( section, buffer, len, filename );
1444 /***********************************************************************
1445 * GetPrivateProfileSectionW (KERNEL32.@)
1447 INT WINAPI GetPrivateProfileSectionW( LPCWSTR section, LPWSTR buffer,
1448 DWORD len, LPCWSTR filename )
1450 int ret = 0;
1452 EnterCriticalSection( &PROFILE_CritSect );
1454 if (PROFILE_Open( filename ))
1455 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1456 FALSE, TRUE);
1458 LeaveCriticalSection( &PROFILE_CritSect );
1460 return ret;
1463 /***********************************************************************
1464 * GetPrivateProfileSectionA (KERNEL32.@)
1466 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1467 DWORD len, LPCSTR filename )
1469 UNICODE_STRING sectionW, filenameW;
1470 LPWSTR bufferW;
1471 INT retW, ret = 0;
1473 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1474 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1475 else sectionW.Buffer = NULL;
1476 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1477 else filenameW.Buffer = NULL;
1479 retW = GetPrivateProfileSectionW(sectionW.Buffer, bufferW, len, filenameW.Buffer);
1480 if (len > 2)
1482 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 2, buffer, len, NULL, NULL);
1483 if (ret > 2)
1484 ret -= 2;
1485 else
1487 ret = 0;
1488 buffer[len-2] = 0;
1489 buffer[len-1] = 0;
1492 else
1494 buffer[0] = 0;
1495 buffer[1] = 0;
1498 RtlFreeUnicodeString(&sectionW);
1499 RtlFreeUnicodeString(&filenameW);
1500 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1501 return ret;
1504 /***********************************************************************
1505 * GetProfileSection (KERNEL.419)
1507 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1509 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1512 /***********************************************************************
1513 * GetProfileSectionA (KERNEL32.@)
1515 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1517 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1520 /***********************************************************************
1521 * GetProfileSectionW (KERNEL32.@)
1523 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1525 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1529 /***********************************************************************
1530 * WritePrivateProfileString (KERNEL.129)
1532 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1533 LPCSTR string, LPCSTR filename )
1535 return WritePrivateProfileStringA(section,entry,string,filename);
1538 /***********************************************************************
1539 * WritePrivateProfileStringW (KERNEL32.@)
1541 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1542 LPCWSTR string, LPCWSTR filename )
1544 BOOL ret = FALSE;
1546 EnterCriticalSection( &PROFILE_CritSect );
1548 if (PROFILE_Open( filename ))
1550 if (!section && !entry && !string) /* documented "file flush" case */
1552 PROFILE_FlushFile();
1553 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1555 else {
1556 if (!section) {
1557 FIXME("(NULL?,%s,%s,%s)?\n",
1558 debugstr_w(entry), debugstr_w(string), debugstr_w(filename));
1559 } else {
1560 ret = PROFILE_SetString( section, entry, string, FALSE);
1561 PROFILE_FlushFile();
1566 LeaveCriticalSection( &PROFILE_CritSect );
1567 return ret;
1570 /***********************************************************************
1571 * WritePrivateProfileStringA (KERNEL32.@)
1573 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1574 LPCSTR string, LPCSTR filename )
1576 UNICODE_STRING sectionW, entryW, stringW, filenameW;
1577 BOOL ret;
1579 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1580 else sectionW.Buffer = NULL;
1581 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1582 else entryW.Buffer = NULL;
1583 if (string) RtlCreateUnicodeStringFromAsciiz(&stringW, string);
1584 else stringW.Buffer = NULL;
1585 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1586 else filenameW.Buffer = NULL;
1588 ret = WritePrivateProfileStringW(sectionW.Buffer, entryW.Buffer,
1589 stringW.Buffer, filenameW.Buffer);
1590 RtlFreeUnicodeString(&sectionW);
1591 RtlFreeUnicodeString(&entryW);
1592 RtlFreeUnicodeString(&stringW);
1593 RtlFreeUnicodeString(&filenameW);
1594 return ret;
1597 /***********************************************************************
1598 * WritePrivateProfileSection (KERNEL.416)
1600 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1601 LPCSTR string, LPCSTR filename )
1603 return WritePrivateProfileSectionA( section, string, filename );
1606 /***********************************************************************
1607 * WritePrivateProfileSectionW (KERNEL32.@)
1609 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1610 LPCWSTR string, LPCWSTR filename )
1612 BOOL ret = FALSE;
1613 LPWSTR p;
1615 EnterCriticalSection( &PROFILE_CritSect );
1617 if (PROFILE_Open( filename )) {
1618 if (!section && !string)
1619 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1620 else if (!string) {/* delete the named section*/
1621 ret = PROFILE_SetString(section,NULL,NULL, FALSE);
1622 PROFILE_FlushFile();
1623 } else {
1624 PROFILE_DeleteAllKeys(section);
1625 ret = TRUE;
1626 while(*string) {
1627 LPWSTR buf = HeapAlloc( GetProcessHeap(), 0, (strlenW(string)+1) * sizeof(WCHAR) );
1628 strcpyW( buf, string );
1629 if((p = strchrW( buf, '='))) {
1630 *p='\0';
1631 ret = PROFILE_SetString( section, buf, p+1, TRUE);
1633 HeapFree( GetProcessHeap(), 0, buf );
1634 string += strlenW(string)+1;
1636 PROFILE_FlushFile();
1640 LeaveCriticalSection( &PROFILE_CritSect );
1641 return ret;
1644 /***********************************************************************
1645 * WritePrivateProfileSectionA (KERNEL32.@)
1647 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1648 LPCSTR string, LPCSTR filename)
1651 UNICODE_STRING sectionW, filenameW;
1652 LPWSTR stringW;
1653 BOOL ret;
1655 if (string)
1657 INT lenA, lenW;
1658 LPCSTR p = string;
1660 while(*p) p += strlen(p) + 1;
1661 lenA = p - string + 1;
1662 lenW = MultiByteToWideChar(CP_ACP, 0, string, lenA, NULL, 0);
1663 if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR))))
1664 MultiByteToWideChar(CP_ACP, 0, string, lenA, stringW, lenW);
1666 else stringW = NULL;
1667 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1668 else sectionW.Buffer = NULL;
1669 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1670 else filenameW.Buffer = NULL;
1672 ret = WritePrivateProfileSectionW(sectionW.Buffer, stringW, filenameW.Buffer);
1674 HeapFree(GetProcessHeap(), 0, stringW);
1675 RtlFreeUnicodeString(&sectionW);
1676 RtlFreeUnicodeString(&filenameW);
1677 return ret;
1680 /***********************************************************************
1681 * WriteProfileSection (KERNEL.417)
1683 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1685 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1688 /***********************************************************************
1689 * WriteProfileSectionA (KERNEL32.@)
1691 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1694 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1697 /***********************************************************************
1698 * WriteProfileSectionW (KERNEL32.@)
1700 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1702 return WritePrivateProfileSectionW(section, keys_n_values, wininiW);
1705 /***********************************************************************
1706 * GetPrivateProfileSectionNames (KERNEL.143)
1708 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1709 LPCSTR filename )
1711 return GetPrivateProfileSectionNamesA(buffer,size,filename);
1715 /***********************************************************************
1716 * GetProfileSectionNames (KERNEL.142)
1718 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
1721 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
1725 /***********************************************************************
1726 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1728 * Returns the section names contained in the specified file.
1729 * FIXME: Where do we find this file when the path is relative?
1730 * The section names are returned as a list of strings with an extra
1731 * '\0' to mark the end of the list. Except for that the behavior
1732 * depends on the Windows version.
1734 * Win95:
1735 * - if the buffer is 0 or 1 character long then it is as if it was of
1736 * infinite length.
1737 * - otherwise, if the buffer is to small only the section names that fit
1738 * are returned.
1739 * - note that this means if the buffer was to small to return even just
1740 * the first section name then a single '\0' will be returned.
1741 * - the return value is the number of characters written in the buffer,
1742 * except if the buffer was too smal in which case len-2 is returned
1744 * Win2000:
1745 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1746 * '\0' and the return value is 0
1747 * - otherwise if the buffer is too small then the first section name that
1748 * does not fit is truncated so that the string list can be terminated
1749 * correctly (double '\0')
1750 * - the return value is the number of characters written in the buffer
1751 * except for the trailing '\0'. If the buffer is too small, then the
1752 * return value is len-2
1753 * - Win2000 has a bug that triggers when the section names and the
1754 * trailing '\0' fit exactly in the buffer. In that case the trailing
1755 * '\0' is missing.
1757 * Wine implements the observed Win2000 behavior (except for the bug).
1759 * Note that when the buffer is big enough then the return value may be any
1760 * value between 1 and len-1 (or len in Win95), including len-2.
1762 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1763 LPCWSTR filename)
1765 DWORD ret = 0;
1767 EnterCriticalSection( &PROFILE_CritSect );
1769 if (PROFILE_Open( filename ))
1770 ret = PROFILE_GetSectionNames(buffer, size);
1772 LeaveCriticalSection( &PROFILE_CritSect );
1774 return ret;
1778 /***********************************************************************
1779 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1781 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1782 LPCSTR filename)
1784 UNICODE_STRING filenameW;
1785 LPWSTR bufferW;
1786 INT retW, ret = 0;
1788 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)) : NULL;
1789 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1790 else filenameW.Buffer = NULL;
1792 retW = GetPrivateProfileSectionNamesW(bufferW, size, filenameW.Buffer);
1793 if (retW && size)
1795 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW, buffer, size, NULL, NULL);
1796 if (!ret)
1798 ret = size;
1799 buffer[size-1] = 0;
1803 RtlFreeUnicodeString(&filenameW);
1804 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1805 return ret;
1808 /***********************************************************************
1809 * GetPrivateProfileStruct (KERNEL.407)
1811 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1812 LPVOID buf, UINT16 len, LPCSTR filename)
1814 return GetPrivateProfileStructA( section, key, buf, len, filename );
1817 /***********************************************************************
1818 * GetPrivateProfileStructW (KERNEL32.@)
1820 * Should match Win95's behaviour pretty much
1822 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1823 LPVOID buf, UINT len, LPCWSTR filename)
1825 BOOL ret = FALSE;
1827 EnterCriticalSection( &PROFILE_CritSect );
1829 if (PROFILE_Open( filename )) {
1830 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
1831 if (k) {
1832 TRACE("value (at %p): %s\n", k->value, debugstr_w(k->value));
1833 if (((strlenW(k->value) - 2) / 2) == len)
1835 LPWSTR end, p;
1836 BOOL valid = TRUE;
1837 WCHAR c;
1838 DWORD chksum = 0;
1840 end = k->value + strlenW(k->value); /* -> '\0' */
1841 /* check for invalid chars in ASCII coded hex string */
1842 for (p=k->value; p < end; p++)
1844 if (!isxdigitW(*p))
1846 WARN("invalid char '%x' in file %s->[%s]->%s !\n",
1847 *p, debugstr_w(filename), debugstr_w(section), debugstr_w(key));
1848 valid = FALSE;
1849 break;
1852 if (valid)
1854 BOOL highnibble = TRUE;
1855 BYTE b = 0, val;
1856 LPBYTE binbuf = (LPBYTE)buf;
1858 end -= 2; /* don't include checksum in output data */
1859 /* translate ASCII hex format into binary data */
1860 for (p=k->value; p < end; p++)
1862 c = toupperW(*p);
1863 val = (c > '9') ?
1864 (c - 'A' + 10) : (c - '0');
1866 if (highnibble)
1867 b = val << 4;
1868 else
1870 b += val;
1871 *binbuf++ = b; /* feed binary data into output */
1872 chksum += b; /* calculate checksum */
1874 highnibble ^= 1; /* toggle */
1876 /* retrieve stored checksum value */
1877 c = toupperW(*p++);
1878 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1879 c = toupperW(*p);
1880 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1881 if (b == (chksum & 0xff)) /* checksums match ? */
1882 ret = TRUE;
1887 LeaveCriticalSection( &PROFILE_CritSect );
1889 return ret;
1892 /***********************************************************************
1893 * GetPrivateProfileStructA (KERNEL32.@)
1895 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1896 LPVOID buffer, UINT len, LPCSTR filename)
1898 UNICODE_STRING sectionW, keyW, filenameW;
1899 INT ret;
1901 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1902 else sectionW.Buffer = NULL;
1903 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
1904 else keyW.Buffer = NULL;
1905 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1906 else filenameW.Buffer = NULL;
1908 ret = GetPrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buffer, len,
1909 filenameW.Buffer);
1910 /* Do not translate binary data. */
1912 RtlFreeUnicodeString(&sectionW);
1913 RtlFreeUnicodeString(&keyW);
1914 RtlFreeUnicodeString(&filenameW);
1915 return ret;
1920 /***********************************************************************
1921 * WritePrivateProfileStruct (KERNEL.406)
1923 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1924 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1926 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1929 /***********************************************************************
1930 * WritePrivateProfileStructW (KERNEL32.@)
1932 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1933 LPVOID buf, UINT bufsize, LPCWSTR filename)
1935 BOOL ret = FALSE;
1936 LPBYTE binbuf;
1937 LPWSTR outstring, p;
1938 DWORD sum = 0;
1940 if (!section && !key && !buf) /* flush the cache */
1941 return WritePrivateProfileStringW( NULL, NULL, NULL, filename );
1943 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1944 outstring = HeapAlloc( GetProcessHeap(), 0, (bufsize*2 + 2 + 1) * sizeof(WCHAR) );
1945 p = outstring;
1946 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1947 *p++ = hex[*binbuf >> 4];
1948 *p++ = hex[*binbuf & 0xf];
1949 sum += *binbuf;
1951 /* checksum is sum & 0xff */
1952 *p++ = hex[(sum & 0xf0) >> 4];
1953 *p++ = hex[sum & 0xf];
1954 *p++ = '\0';
1956 EnterCriticalSection( &PROFILE_CritSect );
1958 if (PROFILE_Open( filename )) {
1959 ret = PROFILE_SetString( section, key, outstring, FALSE);
1960 PROFILE_FlushFile();
1963 LeaveCriticalSection( &PROFILE_CritSect );
1965 HeapFree( GetProcessHeap(), 0, outstring );
1967 return ret;
1970 /***********************************************************************
1971 * WritePrivateProfileStructA (KERNEL32.@)
1973 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1974 LPVOID buf, UINT bufsize, LPCSTR filename)
1976 UNICODE_STRING sectionW, keyW, filenameW;
1977 INT ret;
1979 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1980 else sectionW.Buffer = NULL;
1981 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
1982 else keyW.Buffer = NULL;
1983 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1984 else filenameW.Buffer = NULL;
1986 /* Do not translate binary data. */
1987 ret = WritePrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buf, bufsize,
1988 filenameW.Buffer);
1990 RtlFreeUnicodeString(&sectionW);
1991 RtlFreeUnicodeString(&keyW);
1992 RtlFreeUnicodeString(&filenameW);
1993 return ret;
1997 /***********************************************************************
1998 * WriteOutProfiles (KERNEL.315)
2000 void WINAPI WriteOutProfiles16(void)
2002 EnterCriticalSection( &PROFILE_CritSect );
2003 PROFILE_FlushFile();
2004 LeaveCriticalSection( &PROFILE_CritSect );
2007 /***********************************************************************
2008 * CloseProfileUserMapping (KERNEL32.@)
2010 BOOL WINAPI CloseProfileUserMapping(void) {
2011 FIXME("(), stub!\n");
2012 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2013 return FALSE;