- Add stubs for _25, _33, _35
[wine/multimedia.git] / files / profile.c
blob4c655efe5f695877fb226b6ec7221a57b1c237c8
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <ctype.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <pwd.h>
17 #include <unistd.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "winnls.h"
22 #include "winerror.h"
23 #include "wine/winbase16.h"
24 #include "winreg.h"
25 #include "file.h"
26 #include "heap.h"
27 #include "debugtools.h"
28 #include "options.h"
29 #include "wine/server.h"
31 DEFAULT_DEBUG_CHANNEL(profile);
33 typedef struct tagPROFILEKEY
35 char *value;
36 struct tagPROFILEKEY *next;
37 char name[1];
38 } PROFILEKEY;
40 typedef struct tagPROFILESECTION
42 struct tagPROFILEKEY *key;
43 struct tagPROFILESECTION *next;
44 char name[1];
45 } PROFILESECTION;
48 typedef struct
50 BOOL changed;
51 PROFILESECTION *section;
52 char *dos_name;
53 char *unix_name;
54 char *filename;
55 time_t mtime;
56 } PROFILE;
59 #define N_CACHED_PROFILES 10
61 /* Cached profile files */
62 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
64 #define CurProfile (MRUProfile[0])
66 /* wine.ini config file registry root */
67 static HKEY wine_profile_key;
69 #define PROFILE_MAX_LINE_LEN 1024
71 /* Wine profile name in $HOME directory; must begin with slash */
72 static const char PROFILE_WineIniName[] = "/.winerc";
74 /* Wine profile: the profile file being used */
75 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
77 /* Check for comments in profile */
78 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
80 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
82 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
84 static const char hex[16] = "0123456789ABCDEF";
86 /***********************************************************************
87 * PROFILE_CopyEntry
89 * Copy the content of an entry into a buffer, removing quotes, and possibly
90 * translating environment variables.
92 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
93 int handle_env )
95 char quote = '\0';
96 const char *p;
98 if(!buffer) return;
100 if ((*value == '\'') || (*value == '\"'))
102 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
105 if (!handle_env)
107 lstrcpynA( buffer, value, len );
108 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
109 return;
112 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
114 if ((*p == '$') && (p[1] == '{'))
116 char env_val[1024];
117 const char *env_p;
118 const char *p2 = strchr( p, '}' );
119 if (!p2) continue; /* ignore it */
120 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
121 if ((env_p = getenv( env_val )) != NULL)
123 int buffer_len;
124 lstrcpynA( buffer, env_p, len );
125 buffer_len = strlen( buffer );
126 buffer += buffer_len;
127 len -= buffer_len;
129 p = p2 + 1;
132 if (quote && (len > 1)) buffer--;
133 *buffer = '\0';
137 /***********************************************************************
138 * PROFILE_Save
140 * Save a profile tree to a file.
142 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
144 PROFILEKEY *key;
146 for ( ; section; section = section->next)
148 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
149 for (key = section->key; key; key = key->next)
151 fprintf( file, "%s", key->name );
152 if (key->value) fprintf( file, "=%s", key->value );
153 fprintf( file, "\r\n" );
159 /***********************************************************************
160 * PROFILE_Free
162 * Free a profile tree.
164 static void PROFILE_Free( PROFILESECTION *section )
166 PROFILESECTION *next_section;
167 PROFILEKEY *key, *next_key;
169 for ( ; section; section = next_section)
171 for (key = section->key; key; key = next_key)
173 next_key = key->next;
174 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
175 HeapFree( GetProcessHeap(), 0, key );
177 next_section = section->next;
178 HeapFree( GetProcessHeap(), 0, section );
182 static inline int PROFILE_isspace(char c)
184 if (isspace(c)) return 1;
185 if (c=='\r' || c==0x1a) return 1;
186 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
187 return 0;
191 /***********************************************************************
192 * PROFILE_Load
194 * Load a profile tree from a file.
196 static PROFILESECTION *PROFILE_Load( FILE *file )
198 char buffer[PROFILE_MAX_LINE_LEN];
199 char *p, *p2;
200 int line = 0;
201 PROFILESECTION *section, *first_section;
202 PROFILESECTION **next_section;
203 PROFILEKEY *key, *prev_key, **next_key;
205 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
206 if(first_section == NULL) return NULL;
207 first_section->name[0] = 0;
208 first_section->key = NULL;
209 first_section->next = NULL;
210 next_section = &first_section->next;
211 next_key = &first_section->key;
212 prev_key = NULL;
214 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
216 line++;
217 p = buffer;
218 while (*p && PROFILE_isspace(*p)) p++;
219 if (*p == '[') /* section start */
221 if (!(p2 = strrchr( p, ']' )))
223 WARN("Invalid section header at line %d: '%s'\n",
224 line, p );
226 else
228 *p2 = '\0';
229 p++;
230 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + strlen(p) )))
231 break;
232 strcpy( section->name, p );
233 section->key = NULL;
234 section->next = NULL;
235 *next_section = section;
236 next_section = &section->next;
237 next_key = &section->key;
238 prev_key = NULL;
240 TRACE("New section: '%s'\n",section->name);
242 continue;
246 p2=p+strlen(p) - 1;
247 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
249 if ((p2 = strchr( p, '=' )) != NULL)
251 char *p3 = p2 - 1;
252 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
253 *p2++ = '\0';
254 while (*p2 && PROFILE_isspace(*p2)) p2++;
257 if(*p || !prev_key || *prev_key->name)
259 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + strlen(p) ))) break;
260 strcpy( key->name, p );
261 if (p2)
263 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(p2)+1 );
264 strcpy( key->value, p2 );
266 else key->value = NULL;
268 key->next = NULL;
269 *next_key = key;
270 next_key = &key->next;
271 prev_key = key;
273 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
276 return first_section;
279 /* convert the .winerc file to the new format */
280 static void convert_config( FILE *in, const char *output_name )
282 char buffer[PROFILE_MAX_LINE_LEN];
283 char *p, *p2;
284 FILE *out;
286 /* create the output file, only if it doesn't exist already */
287 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
288 if (fd == -1)
290 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
291 ExitProcess(1);
294 out = fdopen( fd, "w" );
295 fprintf( out, "WINE REGISTRY Version 2\n" );
296 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
297 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
299 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
300 p = buffer;
301 while (*p && PROFILE_isspace(*p)) p++;
302 if (*p == '[') /* section start */
304 if ((p2 = strrchr( p, ']' )))
306 *p2 = '\0';
307 p++;
308 fprintf( out, "[%s]\n", p );
310 continue;
313 if (*p == ';' || *p == '#')
315 fprintf( out, "%s\n", p );
316 continue;
319 p2=p+strlen(p) - 1;
320 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
322 if ((p2 = strchr( p, '=' )) != NULL)
324 char *p3 = p2 - 1;
325 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
326 *p2++ = '\0';
327 while (*p2 && PROFILE_isspace(*p2)) p2++;
330 if (!*p)
332 fprintf( out, "\n" );
333 continue;
335 fputc( '"', out );
336 while (*p)
338 if (*p == '\\') fputc( '\\', out );
339 fputc( *p, out );
340 p++;
342 fprintf( out, "\" = \"" );
343 if (p2)
345 while (*p2)
347 if (*p2 == '\\') fputc( '\\', out );
348 fputc( *p2, out );
349 p2++;
352 fprintf( out, "\"\n" );
354 fclose( out );
358 /***********************************************************************
359 * PROFILE_DeleteSection
361 * Delete a section from a profile tree.
363 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
365 while (*section)
367 if ((*section)->name[0] && !strcasecmp( (*section)->name, name ))
369 PROFILESECTION *to_del = *section;
370 *section = to_del->next;
371 to_del->next = NULL;
372 PROFILE_Free( to_del );
373 return TRUE;
375 section = &(*section)->next;
377 return FALSE;
381 /***********************************************************************
382 * PROFILE_DeleteKey
384 * Delete a key from a profile tree.
386 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
387 LPCSTR section_name, LPCSTR key_name )
389 while (*section)
391 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
393 PROFILEKEY **key = &(*section)->key;
394 while (*key)
396 if (!strcasecmp( (*key)->name, key_name ))
398 PROFILEKEY *to_del = *key;
399 *key = to_del->next;
400 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
401 HeapFree( GetProcessHeap(), 0, to_del );
402 return TRUE;
404 key = &(*key)->next;
407 section = &(*section)->next;
409 return FALSE;
413 /***********************************************************************
414 * PROFILE_DeleteAllKeys
416 * Delete all keys from a profile tree.
418 void PROFILE_DeleteAllKeys( LPCSTR section_name)
420 PROFILESECTION **section= &CurProfile->section;
421 while (*section)
423 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
425 PROFILEKEY **key = &(*section)->key;
426 while (*key)
428 PROFILEKEY *to_del = *key;
429 *key = to_del->next;
430 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
431 HeapFree( GetProcessHeap(), 0, to_del );
432 CurProfile->changed =TRUE;
435 section = &(*section)->next;
440 /***********************************************************************
441 * PROFILE_Find
443 * Find a key in a profile tree, optionally creating it.
445 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
446 const char *section_name,
447 const char *key_name, int create )
449 const char *p;
450 int seclen, keylen;
452 while (PROFILE_isspace(*section_name)) section_name++;
453 p = section_name + strlen(section_name) - 1;
454 while ((p > section_name) && PROFILE_isspace(*p)) p--;
455 seclen = p - section_name + 1;
457 while (PROFILE_isspace(*key_name)) key_name++;
458 p = key_name + strlen(key_name) - 1;
459 while ((p > key_name) && PROFILE_isspace(*p)) p--;
460 keylen = p - key_name + 1;
462 while (*section)
464 if ( ((*section)->name[0])
465 && (!(strncasecmp( (*section)->name, section_name, seclen )))
466 && (((*section)->name)[seclen] == '\0') )
468 PROFILEKEY **key = &(*section)->key;
469 while (*key)
471 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
472 && (((*key)->name)[keylen] == '\0') )
473 return *key;
474 key = &(*key)->next;
476 if (!create) return NULL;
477 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlen(key_name) )))
478 return NULL;
479 strcpy( (*key)->name, key_name );
480 (*key)->value = NULL;
481 (*key)->next = NULL;
482 return *key;
484 section = &(*section)->next;
486 if (!create) return NULL;
487 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlen(section_name) );
488 if(*section == NULL) return NULL;
489 strcpy( (*section)->name, section_name );
490 (*section)->next = NULL;
491 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
492 sizeof(PROFILEKEY) + strlen(key_name) )))
494 HeapFree(GetProcessHeap(), 0, *section);
495 return NULL;
497 strcpy( (*section)->key->name, key_name );
498 (*section)->key->value = NULL;
499 (*section)->key->next = NULL;
500 return (*section)->key;
504 /***********************************************************************
505 * PROFILE_FlushFile
507 * Flush the current profile to disk if changed.
509 static BOOL PROFILE_FlushFile(void)
511 char *p, buffer[MAX_PATHNAME_LEN];
512 const char *unix_name;
513 FILE *file = NULL;
514 struct stat buf;
516 if(!CurProfile)
518 WARN("No current profile!\n");
519 return FALSE;
522 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
523 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
525 /* Try to create it in $HOME/.wine */
526 /* FIXME: this will need a more general solution */
527 strcpy( buffer, get_config_dir() );
528 p = buffer + strlen(buffer);
529 *p++ = '/';
530 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
531 _strlwr( p );
532 file = fopen( buffer, "w" );
533 unix_name = buffer;
536 if (!file)
538 WARN("could not save profile file %s\n", CurProfile->dos_name);
539 return FALSE;
542 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
543 PROFILE_Save( file, CurProfile->section );
544 fclose( file );
545 CurProfile->changed = FALSE;
546 if(!stat(unix_name,&buf))
547 CurProfile->mtime=buf.st_mtime;
548 return TRUE;
552 /***********************************************************************
553 * PROFILE_ReleaseFile
555 * Flush the current profile to disk and remove it from the cache.
557 static void PROFILE_ReleaseFile(void)
559 PROFILE_FlushFile();
560 PROFILE_Free( CurProfile->section );
561 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
562 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
563 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
564 CurProfile->changed = FALSE;
565 CurProfile->section = NULL;
566 CurProfile->dos_name = NULL;
567 CurProfile->unix_name = NULL;
568 CurProfile->filename = NULL;
569 CurProfile->mtime = 0;
573 /***********************************************************************
574 * PROFILE_Open
576 * Open a profile file, checking the cached file first.
578 static BOOL PROFILE_Open( LPCSTR filename )
580 DOS_FULL_NAME full_name;
581 char buffer[MAX_PATHNAME_LEN];
582 char *newdos_name, *p;
583 FILE *file = NULL;
584 int i,j;
585 struct stat buf;
586 PROFILE *tempProfile;
588 /* First time around */
590 if(!CurProfile)
591 for(i=0;i<N_CACHED_PROFILES;i++)
593 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
594 if(MRUProfile[i] == NULL) break;
595 MRUProfile[i]->changed=FALSE;
596 MRUProfile[i]->section=NULL;
597 MRUProfile[i]->dos_name=NULL;
598 MRUProfile[i]->unix_name=NULL;
599 MRUProfile[i]->filename=NULL;
600 MRUProfile[i]->mtime=0;
603 /* Check for a match */
605 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
606 strchr( filename, ':' ))
608 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
610 else
612 GetWindowsDirectoryA( buffer, sizeof(buffer) );
613 strcat( buffer, "\\" );
614 strcat( buffer, filename );
615 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
618 for(i=0;i<N_CACHED_PROFILES;i++)
620 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
621 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
623 if(i)
625 PROFILE_FlushFile();
626 tempProfile=MRUProfile[i];
627 for(j=i;j>0;j--)
628 MRUProfile[j]=MRUProfile[j-1];
629 CurProfile=tempProfile;
631 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
632 TRACE("(%s): already opened (mru=%d)\n",
633 filename, i );
634 else
635 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
636 filename, i );
637 return TRUE;
641 /* Flush the old current profile */
642 PROFILE_FlushFile();
644 /* Make the oldest profile the current one only in order to get rid of it */
645 if(i==N_CACHED_PROFILES)
647 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
648 for(i=N_CACHED_PROFILES-1;i>0;i--)
649 MRUProfile[i]=MRUProfile[i-1];
650 CurProfile=tempProfile;
652 if(CurProfile->filename) PROFILE_ReleaseFile();
654 /* OK, now that CurProfile is definitely free we assign it our new file */
655 newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 );
656 strcpy( newdos_name, full_name.short_name );
657 CurProfile->dos_name = newdos_name;
658 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, strlen(filename)+1 );
659 strcpy( CurProfile->filename, filename );
661 /* Try to open the profile file, first in $HOME/.wine */
663 /* FIXME: this will need a more general solution */
664 strcpy( buffer, get_config_dir() );
665 p = buffer + strlen(buffer);
666 *p++ = '/';
667 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
668 _strlwr( p );
669 if ((file = fopen( buffer, "r" )))
671 TRACE("(%s): found it in %s\n",
672 filename, buffer );
673 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
674 strcpy( CurProfile->unix_name, buffer );
677 if (!file)
679 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
680 strcpy( CurProfile->unix_name, full_name.long_name );
681 if ((file = fopen( full_name.long_name, "r" )))
682 TRACE("(%s): found it in %s\n",
683 filename, full_name.long_name );
686 if (file)
688 CurProfile->section = PROFILE_Load( file );
689 fclose( file );
690 if(!stat(CurProfile->unix_name,&buf))
691 CurProfile->mtime=buf.st_mtime;
693 else
695 /* Does not exist yet, we will create it in PROFILE_FlushFile */
696 WARN("profile file %s not found\n", newdos_name );
698 return TRUE;
702 /***********************************************************************
703 * PROFILE_GetSection
705 * Returns all keys of a section.
706 * If return_values is TRUE, also include the corresponding values.
708 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
709 LPSTR buffer, UINT len, BOOL handle_env,
710 BOOL return_values )
712 PROFILEKEY *key;
714 if(!buffer) return 0;
716 while (section)
718 if (section->name[0] && !strcasecmp( section->name, section_name ))
720 UINT oldlen = len;
721 for (key = section->key; key; key = key->next)
723 if (len <= 2) break;
724 if (!*key->name) continue; /* Skip empty lines */
725 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
726 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
727 len -= strlen(buffer) + 1;
728 buffer += strlen(buffer) + 1;
729 if (len < 2)
730 break;
731 if (return_values && key->value) {
732 buffer[-1] = '=';
733 PROFILE_CopyEntry ( buffer,
734 key->value, len - 1, handle_env );
735 len -= strlen(buffer) + 1;
736 buffer += strlen(buffer) + 1;
739 *buffer = '\0';
740 if (len <= 1)
741 /*If either lpszSection or lpszKey is NULL and the supplied
742 destination buffer is too small to hold all the strings,
743 the last string is truncated and followed by two null characters.
744 In this case, the return value is equal to cchReturnBuffer
745 minus two. */
747 buffer[-1] = '\0';
748 return oldlen - 2;
750 return oldlen - len;
752 section = section->next;
754 buffer[0] = buffer[1] = '\0';
755 return 0;
758 /* See GetPrivateProfileSectionNamesA for documentation */
759 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
761 LPSTR buf;
762 UINT f,l;
763 PROFILESECTION *section;
765 if (!buffer || !len)
766 return 0;
767 if (len==1) {
768 *buffer='\0';
769 return 0;
772 f=len-1;
773 buf=buffer;
774 section = CurProfile->section;
775 while ((section!=NULL)) {
776 if (section->name[0]) {
777 l = strlen(section->name)+1;
778 if (l > f) {
779 if (f>0) {
780 strncpy(buf, section->name, f-1);
781 buf += f-1;
782 *buf++='\0';
784 *buf='\0';
785 return len-2;
787 strcpy(buf, section->name);
788 buf += l;
789 f -= l;
791 section = section->next;
793 *buf='\0';
794 return buf-buffer;
798 /***********************************************************************
799 * PROFILE_GetString
801 * Get a profile string.
803 * Tests with GetPrivateProfileString16, W95a,
804 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
805 * section key_name def_val res buffer
806 * "set1" "1" "x" 43 [data]
807 * "set1" "1 " "x" 43 [data] (!)
808 * "set1" " 1 "' "x" 43 [data] (!)
809 * "set1" "" "x" 1 "x"
810 * "set1" "" "x " 1 "x" (!)
811 * "set1" "" " x " 3 " x" (!)
812 * "set1" NULL "x" 6 "1\02\03\0\0"
813 * "set1" "" "x" 1 "x"
814 * NULL "1" "x" 0 "" (!)
815 * "" "1" "x" 1 "x"
816 * NULL NULL "" 0 ""
820 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
821 LPCSTR def_val, LPSTR buffer, UINT len )
823 PROFILEKEY *key = NULL;
825 if(!buffer) return 0;
827 if (!def_val) def_val = "";
828 if (key_name && key_name[0])
830 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
831 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
832 len, FALSE );
833 TRACE("('%s','%s','%s'): returning '%s'\n",
834 section, key_name, def_val, buffer );
835 return strlen( buffer );
837 if (key_name && !(key_name[0]))
838 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
839 return 0;
840 if (section && section[0])
841 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
842 FALSE, FALSE);
843 buffer[0] = '\0';
844 return 0;
848 /***********************************************************************
849 * PROFILE_SetString
851 * Set a profile string.
853 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
854 LPCSTR value )
856 if (!key_name) /* Delete a whole section */
858 TRACE("('%s')\n", section_name);
859 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
860 section_name );
861 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
862 this is not an error on application's level.*/
864 else if (!value) /* Delete a key */
866 TRACE("('%s','%s')\n",
867 section_name, key_name );
868 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
869 section_name, key_name );
870 return TRUE; /* same error handling as above */
872 else /* Set the key value */
874 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
875 key_name, TRUE );
876 TRACE("('%s','%s','%s'): \n",
877 section_name, key_name, value );
878 if (!key) return FALSE;
879 if (key->value)
881 /* strip the leading spaces. We can safely strip \n\r and
882 * friends too, they should not happen here anyway. */
883 while (PROFILE_isspace(*value)) value++;
885 if (!strcmp( key->value, value ))
887 TRACE(" no change needed\n" );
888 return TRUE; /* No change needed */
890 TRACE(" replacing '%s'\n", key->value );
891 HeapFree( GetProcessHeap(), 0, key->value );
893 else TRACE(" creating key\n" );
894 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(value)+1 );
895 strcpy( key->value, value );
896 CurProfile->changed = TRUE;
898 return TRUE;
902 /***********************************************************************
903 * PROFILE_GetWineIniString
905 * Get a config string from the wine.ini file.
907 int PROFILE_GetWineIniString( const char *section, const char *key_name,
908 const char *def, char *buffer, int len )
910 char tmp[PROFILE_MAX_LINE_LEN];
911 HKEY hkey;
912 DWORD err;
914 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
916 DWORD type;
917 DWORD count = sizeof(tmp);
918 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
919 RegCloseKey( hkey );
921 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
922 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
923 return strlen(buffer);
927 /***********************************************************************
928 * PROFILE_EnumWineIniString
930 * Get a config string from the wine.ini file.
932 BOOL PROFILE_EnumWineIniString( const char *section, int index,
933 char *name, int name_len, char *buffer, int len )
935 char tmp[PROFILE_MAX_LINE_LEN];
936 HKEY hkey;
937 DWORD err, type;
938 DWORD count = sizeof(tmp);
940 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
941 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
942 RegCloseKey( hkey );
943 if (!err)
945 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
946 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
948 return !err;
952 /***********************************************************************
953 * PROFILE_GetWineIniInt
955 * Get a config integer from the wine.ini file.
957 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
959 char buffer[20];
960 char *p;
961 long result;
963 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
964 if (!buffer[0]) return def;
965 result = strtol( buffer, &p, 0 );
966 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
970 /******************************************************************************
972 * int PROFILE_GetWineIniBool(
973 * char const *section,
974 * char const *key_name,
975 * int def )
977 * Reads a boolean value from the wine.ini file. This function attempts to
978 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
979 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
980 * true. Anything else results in the return of the default value.
982 * This function uses 1 to indicate true, and 0 for false. You can check
983 * for existence by setting def to something other than 0 or 1 and
984 * examining the return value.
986 int PROFILE_GetWineIniBool(
987 char const *section,
988 char const *key_name,
989 int def )
991 char key_value[2];
992 int retval;
994 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
996 switch(key_value[0]) {
997 case 'n':
998 case 'N':
999 case 'f':
1000 case 'F':
1001 case '0':
1002 retval = 0;
1003 break;
1005 case 'y':
1006 case 'Y':
1007 case 't':
1008 case 'T':
1009 case '1':
1010 retval = 1;
1011 break;
1013 default:
1014 retval = def;
1017 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name,
1018 def ? "TRUE" : "FALSE", key_value[0],
1019 retval ? "TRUE" : "FALSE");
1021 return retval;
1025 /***********************************************************************
1026 * PROFILE_LoadWineIni
1028 * Load the old .winerc file.
1030 int PROFILE_LoadWineIni(void)
1032 OBJECT_ATTRIBUTES attr;
1033 UNICODE_STRING nameW;
1034 char buffer[MAX_PATHNAME_LEN];
1035 const char *p;
1036 FILE *f;
1037 HKEY hKeySW;
1038 DWORD disp;
1040 attr.Length = sizeof(attr);
1041 attr.RootDirectory = 0;
1042 attr.ObjectName = &nameW;
1043 attr.Attributes = 0;
1044 attr.SecurityDescriptor = NULL;
1045 attr.SecurityQualityOfService = NULL;
1047 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1048 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1049 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1051 ERR("Cannot create config registry key\n" );
1052 ExitProcess( 1 );
1054 RtlFreeUnicodeString( &nameW );
1055 NtClose( hKeySW );
1057 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1058 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1059 NULL, REG_OPTION_VOLATILE, &disp ))
1061 ERR("Cannot create config registry key\n" );
1062 ExitProcess( 1 );
1064 RtlFreeUnicodeString( &nameW );
1066 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1068 if ((p = getenv( "HOME" )) != NULL)
1070 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1071 strcat( buffer, PROFILE_WineIniName );
1072 if ((f = fopen( buffer, "r" )) != NULL)
1074 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1075 goto found;
1078 else WARN("could not get $HOME value for config file.\n" );
1080 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1082 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1083 return 0;
1085 found:
1087 if (disp == REG_OPENED_EXISTING_KEY)
1089 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1090 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1091 fclose( f );
1092 return 1;
1095 /* convert to the new format */
1096 sprintf( buffer, "%s/config", 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);
1108 /***********************************************************************
1109 * PROFILE_UsageWineIni
1111 * Explain the wine.ini file to those who don't read documentation.
1112 * Keep below one screenful in length so that error messages above are
1113 * noticed.
1115 void PROFILE_UsageWineIni(void)
1117 MESSAGE("Perhaps you have not properly edited or created "
1118 "your Wine configuration file.\n");
1119 MESSAGE("This is '%s/config'\n", get_config_dir());
1120 /* RTFM, so to say */
1123 /***********************************************************************
1124 * PROFILE_GetStringItem
1126 * Convenience function that turns a string 'xxx, yyy, zzz' into
1127 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1129 char* PROFILE_GetStringItem( char* start )
1131 char* lpchX, *lpch;
1133 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1135 if( *lpchX == ',' )
1137 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1138 while( *(++lpchX) )
1139 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1141 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1142 else lpch = NULL;
1144 if( lpch ) *lpch = '\0';
1145 return NULL;
1148 /********************* API functions **********************************/
1150 /***********************************************************************
1151 * GetProfileInt (KERNEL.57)
1153 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1155 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1159 /***********************************************************************
1160 * GetProfileIntA (KERNEL32.@)
1162 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1164 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1167 /***********************************************************************
1168 * GetProfileIntW (KERNEL32.@)
1170 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1172 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1176 * if allow_section_name_copy is TRUE, allow the copying :
1177 * - of Section names if 'section' is NULL
1178 * - of Keys in a Section if 'entry' is NULL
1179 * (see MSDN doc for GetPrivateProfileString)
1181 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1182 LPCSTR def_val, LPSTR buffer,
1183 UINT16 len, LPCSTR filename,
1184 BOOL allow_section_name_copy )
1186 int ret;
1187 LPSTR pDefVal = NULL;
1189 if (!filename)
1190 filename = "win.ini";
1192 /* strip any trailing ' ' of def_val. */
1193 if (def_val)
1195 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1197 while (p > def_val)
1199 p--;
1200 if ((*p) != ' ')
1201 break;
1203 if (*p == ' ') /* ouch, contained trailing ' ' */
1205 int len = (int)p - (int)def_val;
1206 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1207 strncpy(pDefVal, def_val, len);
1208 pDefVal[len] = '\0';
1211 if (!pDefVal)
1212 pDefVal = (LPSTR)def_val;
1214 EnterCriticalSection( &PROFILE_CritSect );
1216 if (PROFILE_Open( filename )) {
1217 if ((allow_section_name_copy) && (section == NULL))
1218 ret = PROFILE_GetSectionNames(buffer, len);
1219 else
1220 /* PROFILE_GetString already handles the 'entry == NULL' case */
1221 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1222 } else {
1223 lstrcpynA( buffer, pDefVal, len );
1224 ret = strlen( buffer );
1227 LeaveCriticalSection( &PROFILE_CritSect );
1229 if (pDefVal != def_val) /* allocated */
1230 HeapFree(GetProcessHeap(), 0, pDefVal);
1232 return ret;
1235 /***********************************************************************
1236 * GetPrivateProfileString (KERNEL.128)
1238 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1239 LPCSTR def_val, LPSTR buffer,
1240 UINT16 len, LPCSTR filename )
1242 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1243 buffer, len, filename, FALSE );
1246 /***********************************************************************
1247 * GetPrivateProfileStringA (KERNEL32.@)
1249 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1250 LPCSTR def_val, LPSTR buffer,
1251 UINT len, LPCSTR filename )
1253 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1254 buffer, len, filename, TRUE );
1257 /***********************************************************************
1258 * GetPrivateProfileStringW (KERNEL32.@)
1260 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1261 LPCWSTR def_val, LPWSTR buffer,
1262 UINT len, LPCWSTR filename )
1264 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1265 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1266 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1267 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1268 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1269 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1270 bufferA, len, filenameA );
1271 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1272 buffer[len-1] = 0;
1273 HeapFree( GetProcessHeap(), 0, sectionA );
1274 HeapFree( GetProcessHeap(), 0, entryA );
1275 HeapFree( GetProcessHeap(), 0, filenameA );
1276 HeapFree( GetProcessHeap(), 0, def_valA );
1277 HeapFree( GetProcessHeap(), 0, bufferA);
1278 return ret;
1281 /***********************************************************************
1282 * GetProfileString (KERNEL.58)
1284 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1285 LPSTR buffer, UINT16 len )
1287 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1288 buffer, len, "win.ini", FALSE );
1291 /***********************************************************************
1292 * GetProfileStringA (KERNEL32.@)
1294 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1295 LPSTR buffer, UINT len )
1297 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1298 buffer, len, "win.ini", TRUE );
1301 /***********************************************************************
1302 * GetProfileStringW (KERNEL32.@)
1304 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1305 LPCWSTR def_val, LPWSTR buffer, UINT len )
1307 return GetPrivateProfileStringW( section, entry, def_val,
1308 buffer, len, wininiW );
1311 /***********************************************************************
1312 * WriteProfileString (KERNEL.59)
1314 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1315 LPCSTR string )
1317 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1320 /***********************************************************************
1321 * WriteProfileStringA (KERNEL32.@)
1323 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1324 LPCSTR string )
1326 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1329 /***********************************************************************
1330 * WriteProfileStringW (KERNEL32.@)
1332 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1333 LPCWSTR string )
1335 return WritePrivateProfileStringW( section, entry, string, wininiW );
1339 /***********************************************************************
1340 * GetPrivateProfileInt (KERNEL.127)
1342 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1343 INT16 def_val, LPCSTR filename )
1345 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1347 if (result > 65535) return 65535;
1348 if (result >= 0) return (UINT16)result;
1349 if (result < -32768) return -32768;
1350 return (UINT16)(INT16)result;
1353 /***********************************************************************
1354 * GetPrivateProfileIntA (KERNEL32.@)
1356 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1357 INT def_val, LPCSTR filename )
1359 char buffer[20];
1360 char *p;
1361 long result;
1363 PROFILE_GetPrivateProfileString( section, entry, "",
1364 buffer, sizeof(buffer), filename, FALSE );
1365 if (!buffer[0]) return (UINT)def_val;
1366 result = strtol( buffer, &p, 0 );
1367 if (p == buffer) return 0; /* No digits at all */
1368 return (UINT)result;
1371 /***********************************************************************
1372 * GetPrivateProfileIntW (KERNEL32.@)
1374 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1375 INT def_val, LPCWSTR filename )
1377 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1378 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1379 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1380 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1381 HeapFree( GetProcessHeap(), 0, sectionA );
1382 HeapFree( GetProcessHeap(), 0, filenameA );
1383 HeapFree( GetProcessHeap(), 0, entryA );
1384 return res;
1387 /***********************************************************************
1388 * GetPrivateProfileSection (KERNEL.418)
1390 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1391 UINT16 len, LPCSTR filename )
1393 return GetPrivateProfileSectionA( section, buffer, len, filename );
1396 /***********************************************************************
1397 * GetPrivateProfileSectionA (KERNEL32.@)
1399 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1400 DWORD len, LPCSTR filename )
1402 int ret = 0;
1404 EnterCriticalSection( &PROFILE_CritSect );
1406 if (PROFILE_Open( filename ))
1407 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1408 FALSE, TRUE);
1410 LeaveCriticalSection( &PROFILE_CritSect );
1412 return ret;
1415 /***********************************************************************
1416 * GetPrivateProfileSectionW (KERNEL32.@)
1419 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1420 DWORD len, LPCWSTR filename )
1423 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1424 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1425 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1426 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1427 filenameA );
1428 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1429 HeapFree( GetProcessHeap(), 0, sectionA );
1430 HeapFree( GetProcessHeap(), 0, filenameA );
1431 HeapFree( GetProcessHeap(), 0, bufferA);
1432 return ret;
1435 /***********************************************************************
1436 * GetProfileSection (KERNEL.419)
1438 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1440 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1443 /***********************************************************************
1444 * GetProfileSectionA (KERNEL32.@)
1446 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1448 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1451 /***********************************************************************
1452 * GetProfileSectionW (KERNEL32.@)
1454 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1456 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1460 /***********************************************************************
1461 * WritePrivateProfileString (KERNEL.129)
1463 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1464 LPCSTR string, LPCSTR filename )
1466 return WritePrivateProfileStringA(section,entry,string,filename);
1469 /***********************************************************************
1470 * WritePrivateProfileStringA (KERNEL32.@)
1472 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1473 LPCSTR string, LPCSTR filename )
1475 BOOL ret = FALSE;
1477 EnterCriticalSection( &PROFILE_CritSect );
1479 if (PROFILE_Open( filename ))
1481 if (!section && !entry && !string) /* documented "file flush" case */
1482 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1483 else
1484 ret = PROFILE_SetString( section, entry, string );
1487 LeaveCriticalSection( &PROFILE_CritSect );
1488 return ret;
1491 /***********************************************************************
1492 * WritePrivateProfileStringW (KERNEL32.@)
1494 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1495 LPCWSTR string, LPCWSTR filename )
1497 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1498 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1499 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1500 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1501 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1502 stringA, filenameA );
1503 HeapFree( GetProcessHeap(), 0, sectionA );
1504 HeapFree( GetProcessHeap(), 0, entryA );
1505 HeapFree( GetProcessHeap(), 0, stringA );
1506 HeapFree( GetProcessHeap(), 0, filenameA );
1507 return res;
1510 /***********************************************************************
1511 * WritePrivateProfileSection (KERNEL.416)
1513 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1514 LPCSTR string, LPCSTR filename )
1516 return WritePrivateProfileSectionA( section, string, filename );
1519 /***********************************************************************
1520 * WritePrivateProfileSectionA (KERNEL32.@)
1522 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1523 LPCSTR string, LPCSTR filename )
1525 BOOL ret = FALSE;
1526 LPSTR p ;
1528 EnterCriticalSection( &PROFILE_CritSect );
1530 if (PROFILE_Open( filename )) {
1531 if (!section && !string)
1532 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1533 else if (!string) /* delete the named section*/
1534 ret = PROFILE_SetString(section,NULL,NULL);
1535 else {
1536 PROFILE_DeleteAllKeys(section);
1537 ret = TRUE;
1538 while(*string) {
1539 LPSTR buf = HeapAlloc( GetProcessHeap(), 0, strlen(string)+1 );
1540 strcpy( buf, string );
1541 if((p=strchr( buf, '='))){
1542 *p='\0';
1543 ret = PROFILE_SetString( section, buf, p+1 );
1546 HeapFree( GetProcessHeap(), 0, buf );
1547 string += strlen(string)+1;
1553 LeaveCriticalSection( &PROFILE_CritSect );
1554 return ret;
1557 /***********************************************************************
1558 * WritePrivateProfileSectionW (KERNEL32.@)
1560 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1561 LPCWSTR string, LPCWSTR filename)
1564 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1565 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1566 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1567 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1568 HeapFree( GetProcessHeap(), 0, sectionA );
1569 HeapFree( GetProcessHeap(), 0, stringA );
1570 HeapFree( GetProcessHeap(), 0, filenameA );
1571 return res;
1574 /***********************************************************************
1575 * WriteProfileSection (KERNEL.417)
1577 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1579 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1582 /***********************************************************************
1583 * WriteProfileSectionA (KERNEL32.@)
1585 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1588 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1591 /***********************************************************************
1592 * WriteProfileSectionW (KERNEL32.@)
1594 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1596 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1599 /***********************************************************************
1600 * GetPrivateProfileSectionNames (KERNEL.143)
1602 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1603 LPCSTR filename )
1605 return GetPrivateProfileSectionNamesA(buffer,size,filename);
1609 /***********************************************************************
1610 * GetProfileSectionNames (KERNEL.142)
1612 WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
1615 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
1619 /***********************************************************************
1620 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1622 * Returns the section names contained in the specified file.
1623 * FIXME: Where do we find this file when the path is relative?
1624 * The section names are returned as a list of strings with an extra
1625 * '\0' to mark the end of the list. Except for that the behavior
1626 * depends on the Windows version.
1628 * Win95:
1629 * - if the buffer is 0 or 1 character long then it is as if it was of
1630 * infinite length.
1631 * - otherwise, if the buffer is to small only the section names that fit
1632 * are returned.
1633 * - note that this means if the buffer was to small to return even just
1634 * the first section name then a single '\0' will be returned.
1635 * - the return value is the number of characters written in the buffer,
1636 * except if the buffer was too smal in which case len-2 is returned
1638 * Win2000:
1639 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1640 * '\0' and the return value is 0
1641 * - otherwise if the buffer is too small then the first section name that
1642 * does not fit is truncated so that the string list can be terminated
1643 * correctly (double '\0')
1644 * - the return value is the number of characters written in the buffer
1645 * except for the trailing '\0'. If the buffer is too small, then the
1646 * return value is len-2
1647 * - Win2000 has a bug that triggers when the section names and the
1648 * trailing '\0' fit exactly in the buffer. In that case the trailing
1649 * '\0' is missing.
1651 * Wine implements the observed Win2000 behavior (except for the bug).
1653 * Note that when the buffer is big enough then the return value may be any
1654 * value between 1 and len-1 (or len in Win95), including len-2.
1656 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1657 LPCSTR filename)
1660 DWORD ret = 0;
1662 EnterCriticalSection( &PROFILE_CritSect );
1664 if (PROFILE_Open( filename ))
1665 ret = PROFILE_GetSectionNames(buffer, size);
1667 LeaveCriticalSection( &PROFILE_CritSect );
1669 return ret;
1673 /***********************************************************************
1674 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1676 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1677 LPCWSTR filename)
1680 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1681 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1683 INT ret = GetPrivateProfileSectionNamesA(bufferA, size, filenameA);
1684 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1685 buffer[size-1] = 0;
1686 HeapFree( GetProcessHeap(), 0, bufferA);
1687 HeapFree( GetProcessHeap(), 0, filenameA );
1689 return ret;
1692 /***********************************************************************
1693 * GetPrivateProfileStruct (KERNEL.407)
1695 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1696 LPVOID buf, UINT16 len, LPCSTR filename)
1698 return GetPrivateProfileStructA( section, key, buf, len, filename );
1701 /***********************************************************************
1702 * GetPrivateProfileStructA (KERNEL32.@)
1704 * Should match Win95's behaviour pretty much
1706 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1707 LPVOID buf, UINT len, LPCSTR filename)
1709 BOOL ret = FALSE;
1711 EnterCriticalSection( &PROFILE_CritSect );
1713 if (PROFILE_Open( filename )) {
1714 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1715 if (k) {
1716 TRACE("value (at %p): '%s'\n", k->value, k->value);
1717 if (((strlen(k->value) - 2) / 2) == len)
1719 LPSTR end, p;
1720 BOOL valid = TRUE;
1721 CHAR c;
1722 DWORD chksum = 0;
1724 end = k->value + strlen(k->value); /* -> '\0' */
1725 /* check for invalid chars in ASCII coded hex string */
1726 for (p=k->value; p < end; p++)
1728 if (!isxdigit(*p))
1730 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1731 *p, filename, section, key);
1732 valid = FALSE;
1733 break;
1736 if (valid)
1738 BOOL highnibble = TRUE;
1739 BYTE b = 0, val;
1740 LPBYTE binbuf = (LPBYTE)buf;
1742 end -= 2; /* don't include checksum in output data */
1743 /* translate ASCII hex format into binary data */
1744 for (p=k->value; p < end; p++)
1746 c = toupper(*p);
1747 val = (c > '9') ?
1748 (c - 'A' + 10) : (c - '0');
1750 if (highnibble)
1751 b = val << 4;
1752 else
1754 b += val;
1755 *binbuf++ = b; /* feed binary data into output */
1756 chksum += b; /* calculate checksum */
1758 highnibble ^= 1; /* toggle */
1760 /* retrieve stored checksum value */
1761 c = toupper(*p++);
1762 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1763 c = toupper(*p);
1764 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1765 if (b == (chksum & 0xff)) /* checksums match ? */
1766 ret = TRUE;
1771 LeaveCriticalSection( &PROFILE_CritSect );
1773 return ret;
1776 /***********************************************************************
1777 * GetPrivateProfileStructW (KERNEL32.@)
1779 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1780 LPVOID buffer, UINT len, LPCWSTR filename)
1782 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1783 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1784 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1785 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1787 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1788 len, filenameA );
1789 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1790 ((LPWSTR)buffer)[len-1] = 0;
1791 HeapFree( GetProcessHeap(), 0, bufferA);
1792 HeapFree( GetProcessHeap(), 0, sectionA );
1793 HeapFree( GetProcessHeap(), 0, keyA );
1794 HeapFree( GetProcessHeap(), 0, filenameA );
1796 return ret;
1801 /***********************************************************************
1802 * WritePrivateProfileStruct (KERNEL.406)
1804 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1805 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1807 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1810 /***********************************************************************
1811 * WritePrivateProfileStructA (KERNEL32.@)
1813 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1814 LPVOID buf, UINT bufsize, LPCSTR filename)
1816 BOOL ret = FALSE;
1817 LPBYTE binbuf;
1818 LPSTR outstring, p;
1819 DWORD sum = 0;
1821 if (!section && !key && !buf) /* flush the cache */
1822 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1824 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1825 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1826 p = outstring;
1827 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1828 *p++ = hex[*binbuf >> 4];
1829 *p++ = hex[*binbuf & 0xf];
1830 sum += *binbuf;
1832 /* checksum is sum & 0xff */
1833 *p++ = hex[(sum & 0xf0) >> 4];
1834 *p++ = hex[sum & 0xf];
1835 *p++ = '\0';
1837 EnterCriticalSection( &PROFILE_CritSect );
1839 if (PROFILE_Open( filename ))
1840 ret = PROFILE_SetString( section, key, outstring );
1842 LeaveCriticalSection( &PROFILE_CritSect );
1844 HeapFree( GetProcessHeap(), 0, outstring );
1846 return ret;
1849 /***********************************************************************
1850 * WritePrivateProfileStructW (KERNEL32.@)
1852 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1853 LPVOID buf, UINT bufsize, LPCWSTR filename)
1855 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1856 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1857 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1858 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1859 filenameA );
1860 HeapFree( GetProcessHeap(), 0, sectionA );
1861 HeapFree( GetProcessHeap(), 0, keyA );
1862 HeapFree( GetProcessHeap(), 0, filenameA );
1864 return ret;
1868 /***********************************************************************
1869 * WriteOutProfiles (KERNEL.315)
1871 void WINAPI WriteOutProfiles16(void)
1873 EnterCriticalSection( &PROFILE_CritSect );
1874 PROFILE_FlushFile();
1875 LeaveCriticalSection( &PROFILE_CritSect );
1878 /***********************************************************************
1879 * CloseProfileUserMapping (KERNEL32.@)
1881 BOOL WINAPI CloseProfileUserMapping(void) {
1882 FIXME("(), stub!\n");
1883 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1884 return FALSE;