Moved undocshell.h to dlls/shell32. Removed shell16.h.
[wine/multimedia.git] / files / profile.c
blobc20fbb57276e4dab9141a9baa8253541c94c0ced
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;
759 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
761 LPSTR buf = buffer;
762 WORD l, cursize = 0;
763 PROFILESECTION *section;
765 if(!buffer) return 0;
767 for (section = CurProfile->section; section; section = section->next)
768 if (section->name[0]) {
769 l = strlen(section->name);
770 cursize += l+1;
771 if (cursize > len+1)
772 return len-2;
774 strcpy(buf, section->name);
775 buf += l+1;
778 *buf=0;
779 buf++;
780 return buf-buffer;
784 /***********************************************************************
785 * PROFILE_GetString
787 * Get a profile string.
789 * Tests with GetPrivateProfileString16, W95a,
790 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
791 * section key_name def_val res buffer
792 * "set1" "1" "x" 43 [data]
793 * "set1" "1 " "x" 43 [data] (!)
794 * "set1" " 1 "' "x" 43 [data] (!)
795 * "set1" "" "x" 1 "x"
796 * "set1" "" "x " 1 "x" (!)
797 * "set1" "" " x " 3 " x" (!)
798 * "set1" NULL "x" 6 "1\02\03\0\0"
799 * "set1" "" "x" 1 "x"
800 * NULL "1" "x" 0 "" (!)
801 * "" "1" "x" 1 "x"
802 * NULL NULL "" 0 ""
806 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
807 LPCSTR def_val, LPSTR buffer, UINT len )
809 PROFILEKEY *key = NULL;
811 if(!buffer) return 0;
813 if (!def_val) def_val = "";
814 if (key_name && key_name[0])
816 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
817 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
818 len, FALSE );
819 TRACE("('%s','%s','%s'): returning '%s'\n",
820 section, key_name, def_val, buffer );
821 return strlen( buffer );
823 if (key_name && !(key_name[0]))
824 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
825 return 0;
826 if (section && section[0])
827 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
828 FALSE, FALSE);
829 buffer[0] = '\0';
830 return 0;
834 /***********************************************************************
835 * PROFILE_SetString
837 * Set a profile string.
839 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
840 LPCSTR value )
842 if (!key_name) /* Delete a whole section */
844 TRACE("('%s')\n", section_name);
845 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
846 section_name );
847 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
848 this is not an error on application's level.*/
850 else if (!value) /* Delete a key */
852 TRACE("('%s','%s')\n",
853 section_name, key_name );
854 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
855 section_name, key_name );
856 return TRUE; /* same error handling as above */
858 else /* Set the key value */
860 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
861 key_name, TRUE );
862 TRACE("('%s','%s','%s'): \n",
863 section_name, key_name, value );
864 if (!key) return FALSE;
865 if (key->value)
867 /* strip the leading spaces. We can safely strip \n\r and
868 * friends too, they should not happen here anyway. */
869 while (PROFILE_isspace(*value)) value++;
871 if (!strcmp( key->value, value ))
873 TRACE(" no change needed\n" );
874 return TRUE; /* No change needed */
876 TRACE(" replacing '%s'\n", key->value );
877 HeapFree( GetProcessHeap(), 0, key->value );
879 else TRACE(" creating key\n" );
880 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(value)+1 );
881 strcpy( key->value, value );
882 CurProfile->changed = TRUE;
884 return TRUE;
888 /***********************************************************************
889 * PROFILE_GetWineIniString
891 * Get a config string from the wine.ini file.
893 int PROFILE_GetWineIniString( const char *section, const char *key_name,
894 const char *def, char *buffer, int len )
896 char tmp[PROFILE_MAX_LINE_LEN];
897 HKEY hkey;
898 DWORD err;
900 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
902 DWORD type;
903 DWORD count = sizeof(tmp);
904 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
905 RegCloseKey( hkey );
907 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
908 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
909 return strlen(buffer);
913 /***********************************************************************
914 * PROFILE_EnumWineIniString
916 * Get a config string from the wine.ini file.
918 BOOL PROFILE_EnumWineIniString( const char *section, int index,
919 char *name, int name_len, char *buffer, int len )
921 char tmp[PROFILE_MAX_LINE_LEN];
922 HKEY hkey;
923 DWORD err, type;
924 DWORD count = sizeof(tmp);
926 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
927 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
928 RegCloseKey( hkey );
929 if (!err)
931 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
932 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
934 return !err;
938 /***********************************************************************
939 * PROFILE_GetWineIniInt
941 * Get a config integer from the wine.ini file.
943 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
945 char buffer[20];
946 char *p;
947 long result;
949 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
950 if (!buffer[0]) return def;
951 result = strtol( buffer, &p, 0 );
952 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
956 /******************************************************************************
958 * int PROFILE_GetWineIniBool(
959 * char const *section,
960 * char const *key_name,
961 * int def )
963 * Reads a boolean value from the wine.ini file. This function attempts to
964 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
965 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
966 * true. Anything else results in the return of the default value.
968 * This function uses 1 to indicate true, and 0 for false. You can check
969 * for existence by setting def to something other than 0 or 1 and
970 * examining the return value.
972 int PROFILE_GetWineIniBool(
973 char const *section,
974 char const *key_name,
975 int def )
977 char key_value[2];
978 int retval;
980 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
982 switch(key_value[0]) {
983 case 'n':
984 case 'N':
985 case 'f':
986 case 'F':
987 case '0':
988 retval = 0;
989 break;
991 case 'y':
992 case 'Y':
993 case 't':
994 case 'T':
995 case '1':
996 retval = 1;
997 break;
999 default:
1000 retval = def;
1003 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name,
1004 def ? "TRUE" : "FALSE", key_value[0],
1005 retval ? "TRUE" : "FALSE");
1007 return retval;
1011 /***********************************************************************
1012 * PROFILE_LoadWineIni
1014 * Load the old .winerc file.
1016 int PROFILE_LoadWineIni(void)
1018 OBJECT_ATTRIBUTES attr;
1019 UNICODE_STRING nameW;
1020 char buffer[MAX_PATHNAME_LEN];
1021 const char *p;
1022 FILE *f;
1023 HKEY hKeySW;
1024 DWORD disp;
1026 attr.Length = sizeof(attr);
1027 attr.RootDirectory = 0;
1028 attr.ObjectName = &nameW;
1029 attr.Attributes = 0;
1030 attr.SecurityDescriptor = NULL;
1031 attr.SecurityQualityOfService = NULL;
1033 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1034 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1035 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1037 ERR("Cannot create config registry key\n" );
1038 ExitProcess( 1 );
1040 RtlFreeUnicodeString( &nameW );
1041 NtClose( hKeySW );
1043 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1044 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1045 NULL, REG_OPTION_VOLATILE, &disp ))
1047 ERR("Cannot create config registry key\n" );
1048 ExitProcess( 1 );
1050 RtlFreeUnicodeString( &nameW );
1052 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1054 if ((p = getenv( "HOME" )) != NULL)
1056 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1057 strcat( buffer, PROFILE_WineIniName );
1058 if ((f = fopen( buffer, "r" )) != NULL)
1060 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1061 goto found;
1064 else WARN("could not get $HOME value for config file.\n" );
1066 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1068 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1069 return 0;
1071 found:
1073 if (disp == REG_OPENED_EXISTING_KEY)
1075 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1076 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1077 fclose( f );
1078 return 1;
1081 /* convert to the new format */
1082 sprintf( buffer, "%s/config", get_config_dir() );
1083 convert_config( f, buffer );
1084 fclose( f );
1086 MESSAGE( "The '%s' configuration file has been converted\n"
1087 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1088 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1089 "and then remove the old one and restart Wine.\n" );
1090 ExitProcess(0);
1094 /***********************************************************************
1095 * PROFILE_UsageWineIni
1097 * Explain the wine.ini file to those who don't read documentation.
1098 * Keep below one screenful in length so that error messages above are
1099 * noticed.
1101 void PROFILE_UsageWineIni(void)
1103 MESSAGE("Perhaps you have not properly edited or created "
1104 "your Wine configuration file.\n");
1105 MESSAGE("This is '%s/config'\n", get_config_dir());
1106 /* RTFM, so to say */
1109 /***********************************************************************
1110 * PROFILE_GetStringItem
1112 * Convenience function that turns a string 'xxx, yyy, zzz' into
1113 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1115 char* PROFILE_GetStringItem( char* start )
1117 char* lpchX, *lpch;
1119 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1121 if( *lpchX == ',' )
1123 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1124 while( *(++lpchX) )
1125 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1127 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1128 else lpch = NULL;
1130 if( lpch ) *lpch = '\0';
1131 return NULL;
1134 /********************* API functions **********************************/
1136 /***********************************************************************
1137 * GetProfileInt (KERNEL.57)
1139 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1141 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1145 /***********************************************************************
1146 * GetProfileIntA (KERNEL32.@)
1148 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1150 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1153 /***********************************************************************
1154 * GetProfileIntW (KERNEL32.@)
1156 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1158 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1162 * if allow_section_name_copy is TRUE, allow the copying :
1163 * - of Section names if 'section' is NULL
1164 * - of Keys in a Section if 'entry' is NULL
1165 * (see MSDN doc for GetPrivateProfileString)
1167 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1168 LPCSTR def_val, LPSTR buffer,
1169 UINT16 len, LPCSTR filename,
1170 BOOL allow_section_name_copy )
1172 int ret;
1173 LPSTR pDefVal = NULL;
1175 if (!filename)
1176 filename = "win.ini";
1178 /* strip any trailing ' ' of def_val. */
1179 if (def_val)
1181 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1183 while (p > def_val)
1185 p--;
1186 if ((*p) != ' ')
1187 break;
1189 if (*p == ' ') /* ouch, contained trailing ' ' */
1191 int len = (int)p - (int)def_val;
1192 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1193 strncpy(pDefVal, def_val, len);
1194 pDefVal[len] = '\0';
1197 if (!pDefVal)
1198 pDefVal = (LPSTR)def_val;
1200 EnterCriticalSection( &PROFILE_CritSect );
1202 if (PROFILE_Open( filename )) {
1203 if ((allow_section_name_copy) && (section == NULL))
1204 ret = PROFILE_GetSectionNames(buffer, len);
1205 else
1206 /* PROFILE_GetString already handles the 'entry == NULL' case */
1207 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1208 } else {
1209 lstrcpynA( buffer, pDefVal, len );
1210 ret = strlen( buffer );
1213 LeaveCriticalSection( &PROFILE_CritSect );
1215 if (pDefVal != def_val) /* allocated */
1216 HeapFree(GetProcessHeap(), 0, pDefVal);
1218 return ret;
1221 /***********************************************************************
1222 * GetPrivateProfileString (KERNEL.128)
1224 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1225 LPCSTR def_val, LPSTR buffer,
1226 UINT16 len, LPCSTR filename )
1228 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1229 buffer, len, filename, FALSE );
1232 /***********************************************************************
1233 * GetPrivateProfileStringA (KERNEL32.@)
1235 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1236 LPCSTR def_val, LPSTR buffer,
1237 UINT len, LPCSTR filename )
1239 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1240 buffer, len, filename, TRUE );
1243 /***********************************************************************
1244 * GetPrivateProfileStringW (KERNEL32.@)
1246 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1247 LPCWSTR def_val, LPWSTR buffer,
1248 UINT len, LPCWSTR filename )
1250 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1251 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1252 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1253 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1254 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1255 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1256 bufferA, len, filenameA );
1257 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1258 buffer[len-1] = 0;
1259 HeapFree( GetProcessHeap(), 0, sectionA );
1260 HeapFree( GetProcessHeap(), 0, entryA );
1261 HeapFree( GetProcessHeap(), 0, filenameA );
1262 HeapFree( GetProcessHeap(), 0, def_valA );
1263 HeapFree( GetProcessHeap(), 0, bufferA);
1264 return ret;
1267 /***********************************************************************
1268 * GetProfileString (KERNEL.58)
1270 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1271 LPSTR buffer, UINT16 len )
1273 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1274 buffer, len, "win.ini", FALSE );
1277 /***********************************************************************
1278 * GetProfileStringA (KERNEL32.@)
1280 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1281 LPSTR buffer, UINT len )
1283 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1284 buffer, len, "win.ini", TRUE );
1287 /***********************************************************************
1288 * GetProfileStringW (KERNEL32.@)
1290 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1291 LPCWSTR def_val, LPWSTR buffer, UINT len )
1293 return GetPrivateProfileStringW( section, entry, def_val,
1294 buffer, len, wininiW );
1297 /***********************************************************************
1298 * WriteProfileString (KERNEL.59)
1300 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1301 LPCSTR string )
1303 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1306 /***********************************************************************
1307 * WriteProfileStringA (KERNEL32.@)
1309 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1310 LPCSTR string )
1312 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1315 /***********************************************************************
1316 * WriteProfileStringW (KERNEL32.@)
1318 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1319 LPCWSTR string )
1321 return WritePrivateProfileStringW( section, entry, string, wininiW );
1325 /***********************************************************************
1326 * GetPrivateProfileInt (KERNEL.127)
1328 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1329 INT16 def_val, LPCSTR filename )
1331 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1333 if (result > 65535) return 65535;
1334 if (result >= 0) return (UINT16)result;
1335 if (result < -32768) return -32768;
1336 return (UINT16)(INT16)result;
1339 /***********************************************************************
1340 * GetPrivateProfileIntA (KERNEL32.@)
1342 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1343 INT def_val, LPCSTR filename )
1345 char buffer[20];
1346 char *p;
1347 long result;
1349 PROFILE_GetPrivateProfileString( section, entry, "",
1350 buffer, sizeof(buffer), filename, FALSE );
1351 if (!buffer[0]) return (UINT)def_val;
1352 result = strtol( buffer, &p, 0 );
1353 if (p == buffer) return 0; /* No digits at all */
1354 return (UINT)result;
1357 /***********************************************************************
1358 * GetPrivateProfileIntW (KERNEL32.@)
1360 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1361 INT def_val, LPCWSTR filename )
1363 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1364 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1365 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1366 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1367 HeapFree( GetProcessHeap(), 0, sectionA );
1368 HeapFree( GetProcessHeap(), 0, filenameA );
1369 HeapFree( GetProcessHeap(), 0, entryA );
1370 return res;
1373 /***********************************************************************
1374 * GetPrivateProfileSection (KERNEL.418)
1376 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1377 UINT16 len, LPCSTR filename )
1379 return GetPrivateProfileSectionA( section, buffer, len, filename );
1382 /***********************************************************************
1383 * GetPrivateProfileSectionA (KERNEL32.@)
1385 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1386 DWORD len, LPCSTR filename )
1388 int ret = 0;
1390 EnterCriticalSection( &PROFILE_CritSect );
1392 if (PROFILE_Open( filename ))
1393 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1394 FALSE, TRUE);
1396 LeaveCriticalSection( &PROFILE_CritSect );
1398 return ret;
1401 /***********************************************************************
1402 * GetPrivateProfileSectionW (KERNEL32.@)
1405 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1406 DWORD len, LPCWSTR filename )
1409 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1410 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1411 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1412 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1413 filenameA );
1414 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1415 HeapFree( GetProcessHeap(), 0, sectionA );
1416 HeapFree( GetProcessHeap(), 0, filenameA );
1417 HeapFree( GetProcessHeap(), 0, bufferA);
1418 return ret;
1421 /***********************************************************************
1422 * GetProfileSection (KERNEL.419)
1424 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1426 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1429 /***********************************************************************
1430 * GetProfileSectionA (KERNEL32.@)
1432 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1434 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1437 /***********************************************************************
1438 * GetProfileSectionW (KERNEL32.@)
1440 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1442 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1446 /***********************************************************************
1447 * WritePrivateProfileString (KERNEL.129)
1449 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1450 LPCSTR string, LPCSTR filename )
1452 return WritePrivateProfileStringA(section,entry,string,filename);
1455 /***********************************************************************
1456 * WritePrivateProfileStringA (KERNEL32.@)
1458 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1459 LPCSTR string, LPCSTR filename )
1461 BOOL ret = FALSE;
1463 EnterCriticalSection( &PROFILE_CritSect );
1465 if (PROFILE_Open( filename ))
1467 if (!section && !entry && !string)
1468 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1469 else
1470 ret = PROFILE_SetString( section, entry, string );
1473 LeaveCriticalSection( &PROFILE_CritSect );
1474 return ret;
1477 /***********************************************************************
1478 * WritePrivateProfileStringW (KERNEL32.@)
1480 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1481 LPCWSTR string, LPCWSTR filename )
1483 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1484 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1485 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1486 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1487 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1488 stringA, filenameA );
1489 HeapFree( GetProcessHeap(), 0, sectionA );
1490 HeapFree( GetProcessHeap(), 0, entryA );
1491 HeapFree( GetProcessHeap(), 0, stringA );
1492 HeapFree( GetProcessHeap(), 0, filenameA );
1493 return res;
1496 /***********************************************************************
1497 * WritePrivateProfileSection (KERNEL.416)
1499 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1500 LPCSTR string, LPCSTR filename )
1502 return WritePrivateProfileSectionA( section, string, filename );
1505 /***********************************************************************
1506 * WritePrivateProfileSectionA (KERNEL32.@)
1508 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1509 LPCSTR string, LPCSTR filename )
1511 BOOL ret = FALSE;
1512 LPSTR p ;
1514 EnterCriticalSection( &PROFILE_CritSect );
1516 if (PROFILE_Open( filename )) {
1517 if (!section && !string)
1518 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1519 else if (!string) /* delete the named section*/
1520 ret = PROFILE_SetString(section,NULL,NULL);
1521 else {
1522 PROFILE_DeleteAllKeys(section);
1523 ret = TRUE;
1524 while(*string) {
1525 LPSTR buf = HeapAlloc( GetProcessHeap(), 0, strlen(string)+1 );
1526 strcpy( buf, string );
1527 if((p=strchr( buf, '='))){
1528 *p='\0';
1529 ret = PROFILE_SetString( section, buf, p+1 );
1532 HeapFree( GetProcessHeap(), 0, buf );
1533 string += strlen(string)+1;
1539 LeaveCriticalSection( &PROFILE_CritSect );
1540 return ret;
1543 /***********************************************************************
1544 * WritePrivateProfileSectionW (KERNEL32.@)
1546 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1547 LPCWSTR string, LPCWSTR filename)
1550 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1551 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1552 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1553 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1554 HeapFree( GetProcessHeap(), 0, sectionA );
1555 HeapFree( GetProcessHeap(), 0, stringA );
1556 HeapFree( GetProcessHeap(), 0, filenameA );
1557 return res;
1560 /***********************************************************************
1561 * WriteProfileSection (KERNEL.417)
1563 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1565 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1568 /***********************************************************************
1569 * WriteProfileSectionA (KERNEL32.@)
1571 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1574 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1577 /***********************************************************************
1578 * WriteProfileSectionW (KERNEL32.@)
1580 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1582 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1585 /***********************************************************************
1586 * GetPrivateProfileSectionNames (KERNEL.143)
1588 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1589 LPCSTR filename )
1591 WORD ret = 0;
1593 EnterCriticalSection( &PROFILE_CritSect );
1595 if (PROFILE_Open( filename ))
1596 ret = PROFILE_GetSectionNames(buffer, size);
1598 LeaveCriticalSection( &PROFILE_CritSect );
1600 return ret;
1604 /***********************************************************************
1605 * GetProfileSectionNames (KERNEL.142)
1607 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1610 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1614 /***********************************************************************
1615 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1617 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1618 LPCSTR filename)
1621 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1625 /***********************************************************************
1626 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1628 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1629 LPCWSTR filename)
1632 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1633 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1635 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1636 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1637 buffer[size-1] = 0;
1638 HeapFree( GetProcessHeap(), 0, bufferA);
1639 HeapFree( GetProcessHeap(), 0, filenameA );
1641 return ret;
1644 /***********************************************************************
1645 * GetPrivateProfileStruct (KERNEL.407)
1647 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1648 LPVOID buf, UINT16 len, LPCSTR filename)
1650 return GetPrivateProfileStructA( section, key, buf, len, filename );
1653 /***********************************************************************
1654 * GetPrivateProfileStructA (KERNEL32.@)
1656 * Should match Win95's behaviour pretty much
1658 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1659 LPVOID buf, UINT len, LPCSTR filename)
1661 BOOL ret = FALSE;
1663 EnterCriticalSection( &PROFILE_CritSect );
1665 if (PROFILE_Open( filename )) {
1666 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1667 if (k) {
1668 TRACE("value (at %p): '%s'\n", k->value, k->value);
1669 if (((strlen(k->value) - 2) / 2) == len)
1671 LPSTR end, p;
1672 BOOL valid = TRUE;
1673 CHAR c;
1674 DWORD chksum = 0;
1676 end = k->value + strlen(k->value); /* -> '\0' */
1677 /* check for invalid chars in ASCII coded hex string */
1678 for (p=k->value; p < end; p++)
1680 if (!isxdigit(*p))
1682 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1683 *p, filename, section, key);
1684 valid = FALSE;
1685 break;
1688 if (valid)
1690 BOOL highnibble = TRUE;
1691 BYTE b = 0, val;
1692 LPBYTE binbuf = (LPBYTE)buf;
1694 end -= 2; /* don't include checksum in output data */
1695 /* translate ASCII hex format into binary data */
1696 for (p=k->value; p < end; p++)
1698 c = toupper(*p);
1699 val = (c > '9') ?
1700 (c - 'A' + 10) : (c - '0');
1702 if (highnibble)
1703 b = val << 4;
1704 else
1706 b += val;
1707 *binbuf++ = b; /* feed binary data into output */
1708 chksum += b; /* calculate checksum */
1710 highnibble ^= 1; /* toggle */
1712 /* retrieve stored checksum value */
1713 c = toupper(*p++);
1714 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1715 c = toupper(*p);
1716 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1717 if (b == (chksum & 0xff)) /* checksums match ? */
1718 ret = TRUE;
1723 LeaveCriticalSection( &PROFILE_CritSect );
1725 return ret;
1728 /***********************************************************************
1729 * GetPrivateProfileStructW (KERNEL32.@)
1731 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1732 LPVOID buffer, UINT len, LPCWSTR filename)
1734 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1735 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1736 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1737 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1739 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1740 len, filenameA );
1741 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1742 ((LPWSTR)buffer)[len-1] = 0;
1743 HeapFree( GetProcessHeap(), 0, bufferA);
1744 HeapFree( GetProcessHeap(), 0, sectionA );
1745 HeapFree( GetProcessHeap(), 0, keyA );
1746 HeapFree( GetProcessHeap(), 0, filenameA );
1748 return ret;
1753 /***********************************************************************
1754 * WritePrivateProfileStruct (KERNEL.406)
1756 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1757 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1759 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1762 /***********************************************************************
1763 * WritePrivateProfileStructA (KERNEL32.@)
1765 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1766 LPVOID buf, UINT bufsize, LPCSTR filename)
1768 BOOL ret = FALSE;
1769 LPBYTE binbuf;
1770 LPSTR outstring, p;
1771 DWORD sum = 0;
1773 if (!section && !key && !buf) /* flush the cache */
1774 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1776 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1777 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1778 p = outstring;
1779 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1780 *p++ = hex[*binbuf >> 4];
1781 *p++ = hex[*binbuf & 0xf];
1782 sum += *binbuf;
1784 /* checksum is sum & 0xff */
1785 *p++ = hex[(sum & 0xf0) >> 4];
1786 *p++ = hex[sum & 0xf];
1787 *p++ = '\0';
1789 EnterCriticalSection( &PROFILE_CritSect );
1791 if (PROFILE_Open( filename ))
1792 ret = PROFILE_SetString( section, key, outstring );
1794 LeaveCriticalSection( &PROFILE_CritSect );
1796 HeapFree( GetProcessHeap(), 0, outstring );
1798 return ret;
1801 /***********************************************************************
1802 * WritePrivateProfileStructW (KERNEL32.@)
1804 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1805 LPVOID buf, UINT bufsize, LPCWSTR filename)
1807 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1808 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1809 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1810 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1811 filenameA );
1812 HeapFree( GetProcessHeap(), 0, sectionA );
1813 HeapFree( GetProcessHeap(), 0, keyA );
1814 HeapFree( GetProcessHeap(), 0, filenameA );
1816 return ret;
1820 /***********************************************************************
1821 * WriteOutProfiles (KERNEL.315)
1823 void WINAPI WriteOutProfiles16(void)
1825 EnterCriticalSection( &PROFILE_CritSect );
1826 PROFILE_FlushFile();
1827 LeaveCriticalSection( &PROFILE_CritSect );
1830 /***********************************************************************
1831 * CloseProfileUserMapping (KERNEL32.@)
1833 BOOL WINAPI CloseProfileUserMapping(void) {
1834 FIXME("(), stub!\n");
1835 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1836 return FALSE;