Removed unused functions suspend/remove_all_threads.
[wine/testsucceed.git] / files / profile.c
blob53900124c60ee5a4422cad16e6e86597a7d262fe
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 "server.h"
31 DEFAULT_DEBUG_CHANNEL(profile);
33 typedef struct tagPROFILEKEY
35 char *name;
36 char *value;
37 struct tagPROFILEKEY *next;
38 } PROFILEKEY;
40 typedef struct tagPROFILESECTION
42 char *name;
43 struct tagPROFILEKEY *key;
44 struct tagPROFILESECTION *next;
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;
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 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
172 for (key = section->key; key; key = next_key)
174 next_key = key->next;
175 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
176 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
177 HeapFree( GetProcessHeap(), 0, key );
179 next_section = section->next;
180 HeapFree( GetProcessHeap(), 0, section );
184 static inline int PROFILE_isspace(char c)
186 if (isspace(c)) return 1;
187 if (c=='\r' || c==0x1a) return 1;
188 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
189 return 0;
193 /***********************************************************************
194 * PROFILE_Load
196 * Load a profile tree from a file.
198 static PROFILESECTION *PROFILE_Load( FILE *file )
200 char buffer[PROFILE_MAX_LINE_LEN];
201 char *p, *p2;
202 int line = 0;
203 PROFILESECTION *section, *first_section;
204 PROFILESECTION **next_section;
205 PROFILEKEY *key, *prev_key, **next_key;
207 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
208 if(first_section == NULL) return NULL;
209 first_section->name = NULL;
210 first_section->key = NULL;
211 first_section->next = NULL;
212 next_section = &first_section->next;
213 next_key = &first_section->key;
214 prev_key = NULL;
216 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
218 line++;
219 p = buffer;
220 while (*p && PROFILE_isspace(*p)) p++;
221 if (*p == '[') /* section start */
223 if (!(p2 = strrchr( p, ']' )))
225 WARN("Invalid section header at line %d: '%s'\n",
226 line, p );
228 else
230 *p2 = '\0';
231 p++;
232 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
233 if(section == NULL) break;
234 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
235 section->key = NULL;
236 section->next = NULL;
237 *next_section = section;
238 next_section = &section->next;
239 next_key = &section->key;
240 prev_key = NULL;
242 TRACE("New section: '%s'\n",section->name);
244 continue;
248 p2=p+strlen(p) - 1;
249 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
251 if ((p2 = strchr( p, '=' )) != NULL)
253 char *p3 = p2 - 1;
254 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
255 *p2++ = '\0';
256 while (*p2 && PROFILE_isspace(*p2)) p2++;
259 if(*p || !prev_key || *prev_key->name)
261 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
262 if(key == NULL) break;
263 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
264 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
265 key->next = NULL;
266 *next_key = key;
267 next_key = &key->next;
268 prev_key = key;
270 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
273 return first_section;
276 /* convert the .winerc file to the new format */
277 static void convert_config( FILE *in, const char *output_name )
279 char buffer[PROFILE_MAX_LINE_LEN];
280 char *p, *p2;
281 FILE *out;
283 /* create the output file, only if it doesn't exist already */
284 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
285 if (fd == -1)
287 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
288 ExitProcess(1);
291 out = fdopen( fd, "w" );
292 fprintf( out, "WINE REGISTRY Version 2\n" );
293 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
294 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
296 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
297 p = buffer;
298 while (*p && PROFILE_isspace(*p)) p++;
299 if (*p == '[') /* section start */
301 if ((p2 = strrchr( p, ']' )))
303 *p2 = '\0';
304 p++;
305 fprintf( out, "[%s]\n", p );
307 continue;
310 if (*p == ';' || *p == '#')
312 fprintf( out, "%s\n", p );
313 continue;
316 p2=p+strlen(p) - 1;
317 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
319 if ((p2 = strchr( p, '=' )) != NULL)
321 char *p3 = p2 - 1;
322 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
323 *p2++ = '\0';
324 while (*p2 && PROFILE_isspace(*p2)) p2++;
327 if (!*p)
329 fprintf( out, "\n" );
330 continue;
332 fputc( '"', out );
333 while (*p)
335 if (*p == '\\') fputc( '\\', out );
336 fputc( *p, out );
337 p++;
339 fprintf( out, "\" = \"" );
340 if (p2)
342 while (*p2)
344 if (*p2 == '\\') fputc( '\\', out );
345 fputc( *p2, out );
346 p2++;
349 fprintf( out, "\"\n" );
351 fclose( out );
355 /***********************************************************************
356 * PROFILE_DeleteSection
358 * Delete a section from a profile tree.
360 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
362 while (*section)
364 if ((*section)->name && !strcasecmp( (*section)->name, name ))
366 PROFILESECTION *to_del = *section;
367 *section = to_del->next;
368 to_del->next = NULL;
369 PROFILE_Free( to_del );
370 return TRUE;
372 section = &(*section)->next;
374 return FALSE;
378 /***********************************************************************
379 * PROFILE_DeleteKey
381 * Delete a key from a profile tree.
383 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
384 LPCSTR section_name, LPCSTR key_name )
386 while (*section)
388 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
390 PROFILEKEY **key = &(*section)->key;
391 while (*key)
393 if (!strcasecmp( (*key)->name, key_name ))
395 PROFILEKEY *to_del = *key;
396 *key = to_del->next;
397 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
398 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
399 HeapFree( GetProcessHeap(), 0, to_del );
400 return TRUE;
402 key = &(*key)->next;
405 section = &(*section)->next;
407 return FALSE;
411 /***********************************************************************
412 * PROFILE_DeleteAllKeys
414 * Delete all keys from a profile tree.
416 void PROFILE_DeleteAllKeys( LPCSTR section_name)
418 PROFILESECTION **section= &CurProfile->section;
419 while (*section)
421 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
423 PROFILEKEY **key = &(*section)->key;
424 while (*key)
426 PROFILEKEY *to_del = *key;
427 *key = to_del->next;
428 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
429 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
430 HeapFree( GetProcessHeap(), 0, to_del );
431 CurProfile->changed =TRUE;
434 section = &(*section)->next;
439 /***********************************************************************
440 * PROFILE_Find
442 * Find a key in a profile tree, optionally creating it.
444 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
445 const char *section_name,
446 const char *key_name, int create )
448 const char *p;
449 int seclen, keylen;
451 while (PROFILE_isspace(*section_name)) section_name++;
452 p = section_name + strlen(section_name) - 1;
453 while ((p > section_name) && PROFILE_isspace(*p)) p--;
454 seclen = p - section_name + 1;
456 while (PROFILE_isspace(*key_name)) key_name++;
457 p = key_name + strlen(key_name) - 1;
458 while ((p > key_name) && PROFILE_isspace(*p)) p--;
459 keylen = p - key_name + 1;
461 while (*section)
463 if ( ((*section)->name)
464 && (!(strncasecmp( (*section)->name, section_name, seclen )))
465 && (((*section)->name)[seclen] == '\0') )
467 PROFILEKEY **key = &(*section)->key;
468 while (*key)
470 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
471 && (((*key)->name)[keylen] == '\0') )
472 return *key;
473 key = &(*key)->next;
475 if (!create) return NULL;
476 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
477 if(*key == NULL) return NULL;
478 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
479 (*key)->value = NULL;
480 (*key)->next = NULL;
481 return *key;
483 section = &(*section)->next;
485 if (!create) return NULL;
486 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
487 if(*section == NULL) return NULL;
488 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
489 (*section)->next = NULL;
490 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
491 if((*section)->key == NULL)
493 HeapFree(GetProcessHeap(), 0, *section);
494 return NULL;
496 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
497 (*section)->key->value = NULL;
498 (*section)->key->next = NULL;
499 return (*section)->key;
503 /***********************************************************************
504 * PROFILE_FlushFile
506 * Flush the current profile to disk if changed.
508 static BOOL PROFILE_FlushFile(void)
510 char *p, buffer[MAX_PATHNAME_LEN];
511 const char *unix_name;
512 FILE *file = NULL;
513 struct stat buf;
515 if(!CurProfile)
517 WARN("No current profile!\n");
518 return FALSE;
521 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
522 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
524 /* Try to create it in $HOME/.wine */
525 /* FIXME: this will need a more general solution */
526 strcpy( buffer, get_config_dir() );
527 p = buffer + strlen(buffer);
528 *p++ = '/';
529 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
530 _strlwr( p );
531 file = fopen( buffer, "w" );
532 unix_name = buffer;
535 if (!file)
537 WARN("could not save profile file %s\n", CurProfile->dos_name);
538 return FALSE;
541 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
542 PROFILE_Save( file, CurProfile->section );
543 fclose( file );
544 CurProfile->changed = FALSE;
545 if(!stat(unix_name,&buf))
546 CurProfile->mtime=buf.st_mtime;
547 return TRUE;
551 /***********************************************************************
552 * PROFILE_ReleaseFile
554 * Flush the current profile to disk and remove it from the cache.
556 static void PROFILE_ReleaseFile(void)
558 PROFILE_FlushFile();
559 PROFILE_Free( CurProfile->section );
560 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
561 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
562 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
563 CurProfile->changed = FALSE;
564 CurProfile->section = NULL;
565 CurProfile->dos_name = NULL;
566 CurProfile->unix_name = NULL;
567 CurProfile->filename = NULL;
568 CurProfile->mtime = 0;
572 /***********************************************************************
573 * PROFILE_Open
575 * Open a profile file, checking the cached file first.
577 static BOOL PROFILE_Open( LPCSTR filename )
579 DOS_FULL_NAME full_name;
580 char buffer[MAX_PATHNAME_LEN];
581 char *newdos_name, *p;
582 FILE *file = NULL;
583 int i,j;
584 struct stat buf;
585 PROFILE *tempProfile;
587 /* First time around */
589 if(!CurProfile)
590 for(i=0;i<N_CACHED_PROFILES;i++)
592 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
593 if(MRUProfile[i] == NULL) break;
594 MRUProfile[i]->changed=FALSE;
595 MRUProfile[i]->section=NULL;
596 MRUProfile[i]->dos_name=NULL;
597 MRUProfile[i]->unix_name=NULL;
598 MRUProfile[i]->filename=NULL;
599 MRUProfile[i]->mtime=0;
602 /* Check for a match */
604 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
605 strchr( filename, ':' ))
607 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
609 else
611 GetWindowsDirectoryA( buffer, sizeof(buffer) );
612 strcat( buffer, "\\" );
613 strcat( buffer, filename );
614 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
617 for(i=0;i<N_CACHED_PROFILES;i++)
619 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
620 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
622 if(i)
624 PROFILE_FlushFile();
625 tempProfile=MRUProfile[i];
626 for(j=i;j>0;j--)
627 MRUProfile[j]=MRUProfile[j-1];
628 CurProfile=tempProfile;
630 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
631 TRACE("(%s): already opened (mru=%d)\n",
632 filename, i );
633 else
634 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
635 filename, i );
636 return TRUE;
640 /* Flush the old current profile */
641 PROFILE_FlushFile();
643 /* Make the oldest profile the current one only in order to get rid of it */
644 if(i==N_CACHED_PROFILES)
646 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
647 for(i=N_CACHED_PROFILES-1;i>0;i--)
648 MRUProfile[i]=MRUProfile[i-1];
649 CurProfile=tempProfile;
651 if(CurProfile->filename) PROFILE_ReleaseFile();
653 /* OK, now that CurProfile is definitely free we assign it our new file */
654 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
655 CurProfile->dos_name = newdos_name;
656 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
658 /* Try to open the profile file, first in $HOME/.wine */
660 /* FIXME: this will need a more general solution */
661 strcpy( buffer, get_config_dir() );
662 p = buffer + strlen(buffer);
663 *p++ = '/';
664 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
665 _strlwr( p );
666 if ((file = fopen( buffer, "r" )))
668 TRACE("(%s): found it in %s\n",
669 filename, buffer );
670 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
673 if (!file)
675 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
676 full_name.long_name );
677 if ((file = fopen( full_name.long_name, "r" )))
678 TRACE("(%s): found it in %s\n",
679 filename, full_name.long_name );
682 if (file)
684 CurProfile->section = PROFILE_Load( file );
685 fclose( file );
686 if(!stat(CurProfile->unix_name,&buf))
687 CurProfile->mtime=buf.st_mtime;
689 else
691 /* Does not exist yet, we will create it in PROFILE_FlushFile */
692 WARN("profile file %s not found\n", newdos_name );
694 return TRUE;
698 /***********************************************************************
699 * PROFILE_GetSection
701 * Returns all keys of a section.
702 * If return_values is TRUE, also include the corresponding values.
704 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
705 LPSTR buffer, UINT len, BOOL handle_env,
706 BOOL return_values )
708 PROFILEKEY *key;
710 if(!buffer) return 0;
712 while (section)
714 if (section->name && !strcasecmp( section->name, section_name ))
716 UINT oldlen = len;
717 for (key = section->key; key; key = key->next)
719 if (len <= 2) break;
720 if (!*key->name) continue; /* Skip empty lines */
721 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
722 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
723 len -= strlen(buffer) + 1;
724 buffer += strlen(buffer) + 1;
725 if (len < 2)
726 break;
727 if (return_values && key->value) {
728 buffer[-1] = '=';
729 PROFILE_CopyEntry ( buffer,
730 key->value, len - 1, handle_env );
731 len -= strlen(buffer) + 1;
732 buffer += strlen(buffer) + 1;
735 *buffer = '\0';
736 if (len <= 1)
737 /*If either lpszSection or lpszKey is NULL and the supplied
738 destination buffer is too small to hold all the strings,
739 the last string is truncated and followed by two null characters.
740 In this case, the return value is equal to cchReturnBuffer
741 minus two. */
743 buffer[-1] = '\0';
744 return oldlen - 2;
746 return oldlen - len;
748 section = section->next;
750 buffer[0] = buffer[1] = '\0';
751 return 0;
755 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
757 LPSTR buf = buffer;
758 WORD l, cursize = 0;
759 PROFILESECTION *section;
761 if(!buffer) return 0;
763 for (section = CurProfile->section; section; section = section->next)
764 if (section->name) {
765 l = strlen(section->name);
766 cursize += l+1;
767 if (cursize > len+1)
768 return len-2;
770 strcpy(buf, section->name);
771 buf += l+1;
774 *buf=0;
775 buf++;
776 return buf-buffer;
780 /***********************************************************************
781 * PROFILE_GetString
783 * Get a profile string.
785 * Tests with GetPrivateProfileString16, W95a,
786 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
787 * section key_name def_val res buffer
788 * "set1" "1" "x" 43 [data]
789 * "set1" "1 " "x" 43 [data] (!)
790 * "set1" " 1 "' "x" 43 [data] (!)
791 * "set1" "" "x" 1 "x"
792 * "set1" "" "x " 1 "x" (!)
793 * "set1" "" " x " 3 " x" (!)
794 * "set1" NULL "x" 6 "1\02\03\0\0"
795 * "set1" "" "x" 1 "x"
796 * NULL "1" "x" 0 "" (!)
797 * "" "1" "x" 1 "x"
798 * NULL NULL "" 0 ""
802 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
803 LPCSTR def_val, LPSTR buffer, UINT len )
805 PROFILEKEY *key = NULL;
807 if(!buffer) return 0;
809 if (!def_val) def_val = "";
810 if (key_name && key_name[0])
812 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
813 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
814 len, FALSE );
815 TRACE("('%s','%s','%s'): returning '%s'\n",
816 section, key_name, def_val, buffer );
817 return strlen( buffer );
819 if (key_name && !(key_name[0]))
820 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
821 return 0;
822 if (section && section[0])
823 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
824 FALSE, FALSE);
825 buffer[0] = '\0';
826 return 0;
830 /***********************************************************************
831 * PROFILE_SetString
833 * Set a profile string.
835 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
836 LPCSTR value )
838 if (!key_name) /* Delete a whole section */
840 TRACE("('%s')\n", section_name);
841 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
842 section_name );
843 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
844 this is not an error on application's level.*/
846 else if (!value) /* Delete a key */
848 TRACE("('%s','%s')\n",
849 section_name, key_name );
850 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
851 section_name, key_name );
852 return TRUE; /* same error handling as above */
854 else /* Set the key value */
856 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
857 key_name, TRUE );
858 TRACE("('%s','%s','%s'): \n",
859 section_name, key_name, value );
860 if (!key) return FALSE;
861 if (key->value)
863 /* strip the leading spaces. We can safely strip \n\r and
864 * friends too, they should not happen here anyway. */
865 while (PROFILE_isspace(*value)) value++;
867 if (!strcmp( key->value, value ))
869 TRACE(" no change needed\n" );
870 return TRUE; /* No change needed */
872 TRACE(" replacing '%s'\n", key->value );
873 HeapFree( GetProcessHeap(), 0, key->value );
875 else TRACE(" creating key\n" );
876 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
877 CurProfile->changed = TRUE;
879 return TRUE;
883 /***********************************************************************
884 * PROFILE_GetWineIniString
886 * Get a config string from the wine.ini file.
888 int PROFILE_GetWineIniString( const char *section, const char *key_name,
889 const char *def, char *buffer, int len )
891 char tmp[PROFILE_MAX_LINE_LEN];
892 HKEY hkey;
893 DWORD err;
895 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
897 DWORD type;
898 DWORD count = sizeof(tmp);
899 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
900 RegCloseKey( hkey );
902 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
903 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
904 return strlen(buffer);
908 /***********************************************************************
909 * PROFILE_EnumWineIniString
911 * Get a config string from the wine.ini file.
913 BOOL PROFILE_EnumWineIniString( const char *section, int index,
914 char *name, int name_len, char *buffer, int len )
916 char tmp[PROFILE_MAX_LINE_LEN];
917 HKEY hkey;
918 DWORD err, type;
919 DWORD count = sizeof(tmp);
921 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
922 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
923 RegCloseKey( hkey );
924 if (!err)
926 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
927 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
929 return !err;
933 /***********************************************************************
934 * PROFILE_GetWineIniInt
936 * Get a config integer from the wine.ini file.
938 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
940 char buffer[20];
941 char *p;
942 long result;
944 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
945 if (!buffer[0]) return def;
946 result = strtol( buffer, &p, 0 );
947 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
951 /******************************************************************************
953 * int PROFILE_GetWineIniBool(
954 * char const *section,
955 * char const *key_name,
956 * int def )
958 * Reads a boolean value from the wine.ini file. This function attempts to
959 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
960 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
961 * true. Anything else results in the return of the default value.
963 * This function uses 1 to indicate true, and 0 for false. You can check
964 * for existence by setting def to something other than 0 or 1 and
965 * examining the return value.
967 int PROFILE_GetWineIniBool(
968 char const *section,
969 char const *key_name,
970 int def )
972 char key_value[2];
973 int retval;
975 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
977 switch(key_value[0]) {
978 case 'n':
979 case 'N':
980 case 'f':
981 case 'F':
982 case '0':
983 retval = 0;
984 break;
986 case 'y':
987 case 'Y':
988 case 't':
989 case 'T':
990 case '1':
991 retval = 1;
992 break;
994 default:
995 retval = def;
998 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name,
999 def ? "TRUE" : "FALSE", key_value[0],
1000 retval ? "TRUE" : "FALSE");
1002 return retval;
1006 /***********************************************************************
1007 * PROFILE_LoadWineIni
1009 * Load the old .winerc file.
1011 int PROFILE_LoadWineIni(void)
1013 OBJECT_ATTRIBUTES attr;
1014 UNICODE_STRING nameW;
1015 char buffer[MAX_PATHNAME_LEN];
1016 const char *p;
1017 FILE *f;
1018 HKEY hKeySW;
1019 DWORD disp;
1021 attr.Length = sizeof(attr);
1022 attr.RootDirectory = 0;
1023 attr.ObjectName = &nameW;
1024 attr.Attributes = 0;
1025 attr.SecurityDescriptor = NULL;
1026 attr.SecurityQualityOfService = NULL;
1028 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1029 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1030 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1032 ERR("Cannot create config registry key\n" );
1033 ExitProcess( 1 );
1035 RtlFreeUnicodeString( &nameW );
1036 NtClose( hKeySW );
1038 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1039 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1040 NULL, REG_OPTION_VOLATILE, &disp ))
1042 ERR("Cannot create config registry key\n" );
1043 ExitProcess( 1 );
1045 RtlFreeUnicodeString( &nameW );
1047 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1049 if ((p = getenv( "HOME" )) != NULL)
1051 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1052 strcat( buffer, PROFILE_WineIniName );
1053 if ((f = fopen( buffer, "r" )) != NULL)
1055 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1056 goto found;
1059 else WARN("could not get $HOME value for config file.\n" );
1061 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1063 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1064 return 0;
1066 found:
1068 if (disp == REG_OPENED_EXISTING_KEY)
1070 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1071 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1072 fclose( f );
1073 return 1;
1076 /* convert to the new format */
1077 sprintf( buffer, "%s/config", get_config_dir() );
1078 convert_config( f, buffer );
1079 fclose( f );
1081 MESSAGE( "The '%s' configuration file has been converted\n"
1082 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1083 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1084 "and then remove the old one and restart Wine.\n" );
1085 ExitProcess(0);
1089 /***********************************************************************
1090 * PROFILE_UsageWineIni
1092 * Explain the wine.ini file to those who don't read documentation.
1093 * Keep below one screenful in length so that error messages above are
1094 * noticed.
1096 void PROFILE_UsageWineIni(void)
1098 MESSAGE("Perhaps you have not properly edited or created "
1099 "your Wine configuration file.\n");
1100 MESSAGE("This is '%s/config'\n", get_config_dir());
1101 /* RTFM, so to say */
1104 /***********************************************************************
1105 * PROFILE_GetStringItem
1107 * Convenience function that turns a string 'xxx, yyy, zzz' into
1108 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1110 char* PROFILE_GetStringItem( char* start )
1112 char* lpchX, *lpch;
1114 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1116 if( *lpchX == ',' )
1118 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1119 while( *(++lpchX) )
1120 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1122 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1123 else lpch = NULL;
1125 if( lpch ) *lpch = '\0';
1126 return NULL;
1129 /********************* API functions **********************************/
1131 /***********************************************************************
1132 * GetProfileInt (KERNEL.57)
1134 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1136 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1140 /***********************************************************************
1141 * GetProfileIntA (KERNEL32.@)
1143 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1145 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1148 /***********************************************************************
1149 * GetProfileIntW (KERNEL32.@)
1151 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1153 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1157 * undoc_feature means:
1158 * return section names string list if both section and entry are NULL.
1160 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1161 LPCSTR def_val, LPSTR buffer,
1162 UINT16 len, LPCSTR filename,
1163 BOOL undoc_feature )
1165 int ret;
1166 LPSTR pDefVal = NULL;
1168 if (!filename)
1169 filename = "win.ini";
1171 /* strip any trailing ' ' of def_val. */
1172 if (def_val)
1174 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1176 while (p > def_val)
1178 p--;
1179 if ((*p) != ' ')
1180 break;
1182 if (*p == ' ') /* ouch, contained trailing ' ' */
1184 int len = (int)p - (int)def_val;
1185 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1186 strncpy(pDefVal, def_val, len);
1187 pDefVal[len] = '\0';
1190 if (!pDefVal)
1191 pDefVal = (LPSTR)def_val;
1193 EnterCriticalSection( &PROFILE_CritSect );
1195 if (PROFILE_Open( filename )) {
1196 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1197 /* undocumented; both section and entry are NULL */
1198 ret = PROFILE_GetSectionNames(buffer, len);
1199 else
1200 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1201 } else {
1202 lstrcpynA( buffer, pDefVal, len );
1203 ret = strlen( buffer );
1206 LeaveCriticalSection( &PROFILE_CritSect );
1208 if (pDefVal != def_val) /* allocated */
1209 HeapFree(GetProcessHeap(), 0, pDefVal);
1211 return ret;
1214 /***********************************************************************
1215 * GetPrivateProfileString (KERNEL.128)
1217 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1218 LPCSTR def_val, LPSTR buffer,
1219 UINT16 len, LPCSTR filename )
1221 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1222 buffer, len, filename, FALSE );
1225 /***********************************************************************
1226 * GetPrivateProfileStringA (KERNEL32.@)
1228 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1229 LPCSTR def_val, LPSTR buffer,
1230 UINT len, LPCSTR filename )
1232 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1233 buffer, len, filename, TRUE );
1236 /***********************************************************************
1237 * GetPrivateProfileStringW (KERNEL32.@)
1239 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1240 LPCWSTR def_val, LPWSTR buffer,
1241 UINT len, LPCWSTR filename )
1243 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1244 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1245 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1246 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1247 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1248 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1249 bufferA, len, filenameA );
1250 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1251 buffer[len-1] = 0;
1252 HeapFree( GetProcessHeap(), 0, sectionA );
1253 HeapFree( GetProcessHeap(), 0, entryA );
1254 HeapFree( GetProcessHeap(), 0, filenameA );
1255 HeapFree( GetProcessHeap(), 0, def_valA );
1256 HeapFree( GetProcessHeap(), 0, bufferA);
1257 return ret;
1260 /***********************************************************************
1261 * GetProfileString (KERNEL.58)
1263 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1264 LPSTR buffer, UINT16 len )
1266 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1267 buffer, len, "win.ini", FALSE );
1270 /***********************************************************************
1271 * GetProfileStringA (KERNEL32.@)
1273 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1274 LPSTR buffer, UINT len )
1276 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1277 buffer, len, "win.ini", TRUE );
1280 /***********************************************************************
1281 * GetProfileStringW (KERNEL32.@)
1283 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1284 LPCWSTR def_val, LPWSTR buffer, UINT len )
1286 return GetPrivateProfileStringW( section, entry, def_val,
1287 buffer, len, wininiW );
1290 /***********************************************************************
1291 * WriteProfileString (KERNEL.59)
1293 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1294 LPCSTR string )
1296 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1299 /***********************************************************************
1300 * WriteProfileStringA (KERNEL32.@)
1302 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1303 LPCSTR string )
1305 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1308 /***********************************************************************
1309 * WriteProfileStringW (KERNEL32.@)
1311 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1312 LPCWSTR string )
1314 return WritePrivateProfileStringW( section, entry, string, wininiW );
1318 /***********************************************************************
1319 * GetPrivateProfileInt (KERNEL.127)
1321 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1322 INT16 def_val, LPCSTR filename )
1324 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1326 if (result > 65535) return 65535;
1327 if (result >= 0) return (UINT16)result;
1328 if (result < -32768) return -32768;
1329 return (UINT16)(INT16)result;
1332 /***********************************************************************
1333 * GetPrivateProfileIntA (KERNEL32.@)
1335 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1336 INT def_val, LPCSTR filename )
1338 char buffer[20];
1339 char *p;
1340 long result;
1342 PROFILE_GetPrivateProfileString( section, entry, "",
1343 buffer, sizeof(buffer), filename, FALSE );
1344 if (!buffer[0]) return (UINT)def_val;
1345 result = strtol( buffer, &p, 0 );
1346 if (p == buffer) return 0; /* No digits at all */
1347 return (UINT)result;
1350 /***********************************************************************
1351 * GetPrivateProfileIntW (KERNEL32.@)
1353 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1354 INT def_val, LPCWSTR filename )
1356 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1357 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1358 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1359 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1360 HeapFree( GetProcessHeap(), 0, sectionA );
1361 HeapFree( GetProcessHeap(), 0, filenameA );
1362 HeapFree( GetProcessHeap(), 0, entryA );
1363 return res;
1366 /***********************************************************************
1367 * GetPrivateProfileSection (KERNEL.418)
1369 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1370 UINT16 len, LPCSTR filename )
1372 return GetPrivateProfileSectionA( section, buffer, len, filename );
1375 /***********************************************************************
1376 * GetPrivateProfileSectionA (KERNEL32.@)
1378 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1379 DWORD len, LPCSTR filename )
1381 int ret = 0;
1383 EnterCriticalSection( &PROFILE_CritSect );
1385 if (PROFILE_Open( filename ))
1386 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1387 FALSE, TRUE);
1389 LeaveCriticalSection( &PROFILE_CritSect );
1391 return ret;
1394 /***********************************************************************
1395 * GetPrivateProfileSectionW (KERNEL32.@)
1398 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1399 DWORD len, LPCWSTR filename )
1402 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1403 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1404 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1405 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1406 filenameA );
1407 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1408 HeapFree( GetProcessHeap(), 0, sectionA );
1409 HeapFree( GetProcessHeap(), 0, filenameA );
1410 HeapFree( GetProcessHeap(), 0, bufferA);
1411 return ret;
1414 /***********************************************************************
1415 * GetProfileSection (KERNEL.419)
1417 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1419 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1422 /***********************************************************************
1423 * GetProfileSectionA (KERNEL32.@)
1425 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1427 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1430 /***********************************************************************
1431 * GetProfileSectionW (KERNEL32.@)
1433 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1435 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1439 /***********************************************************************
1440 * WritePrivateProfileString (KERNEL.129)
1442 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1443 LPCSTR string, LPCSTR filename )
1445 return WritePrivateProfileStringA(section,entry,string,filename);
1448 /***********************************************************************
1449 * WritePrivateProfileStringA (KERNEL32.@)
1451 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1452 LPCSTR string, LPCSTR filename )
1454 BOOL ret = FALSE;
1456 EnterCriticalSection( &PROFILE_CritSect );
1458 if (PROFILE_Open( filename ))
1460 if (!section && !entry && !string)
1461 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1462 else
1463 ret = PROFILE_SetString( section, entry, string );
1466 LeaveCriticalSection( &PROFILE_CritSect );
1467 return ret;
1470 /***********************************************************************
1471 * WritePrivateProfileStringW (KERNEL32.@)
1473 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1474 LPCWSTR string, LPCWSTR filename )
1476 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1477 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1478 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1479 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1480 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1481 stringA, filenameA );
1482 HeapFree( GetProcessHeap(), 0, sectionA );
1483 HeapFree( GetProcessHeap(), 0, entryA );
1484 HeapFree( GetProcessHeap(), 0, stringA );
1485 HeapFree( GetProcessHeap(), 0, filenameA );
1486 return res;
1489 /***********************************************************************
1490 * WritePrivateProfileSection (KERNEL.416)
1492 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1493 LPCSTR string, LPCSTR filename )
1495 return WritePrivateProfileSectionA( section, string, filename );
1498 /***********************************************************************
1499 * WritePrivateProfileSectionA (KERNEL32.@)
1501 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1502 LPCSTR string, LPCSTR filename )
1504 BOOL ret = FALSE;
1505 LPSTR p ;
1507 EnterCriticalSection( &PROFILE_CritSect );
1509 if (PROFILE_Open( filename )) {
1510 if (!section && !string)
1511 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1512 else if (!string) /* delete the named section*/
1513 ret = PROFILE_SetString(section,NULL,NULL);
1514 else {
1515 PROFILE_DeleteAllKeys(section);
1516 ret = TRUE;
1517 while(*string) {
1518 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1519 if((p=strchr( buf, '='))){
1520 *p='\0';
1521 ret = PROFILE_SetString( section, buf, p+1 );
1524 HeapFree( GetProcessHeap(), 0, buf );
1525 string += strlen(string)+1;
1531 LeaveCriticalSection( &PROFILE_CritSect );
1532 return ret;
1535 /***********************************************************************
1536 * WritePrivateProfileSectionW (KERNEL32.@)
1538 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1539 LPCWSTR string, LPCWSTR filename)
1542 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1543 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1544 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1545 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1546 HeapFree( GetProcessHeap(), 0, sectionA );
1547 HeapFree( GetProcessHeap(), 0, stringA );
1548 HeapFree( GetProcessHeap(), 0, filenameA );
1549 return res;
1552 /***********************************************************************
1553 * WriteProfileSection (KERNEL.417)
1555 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1557 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1560 /***********************************************************************
1561 * WriteProfileSectionA (KERNEL32.@)
1563 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1566 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1569 /***********************************************************************
1570 * WriteProfileSectionW (KERNEL32.@)
1572 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1574 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1577 /***********************************************************************
1578 * GetPrivateProfileSectionNames (KERNEL.143)
1580 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1581 LPCSTR filename )
1583 WORD ret = 0;
1585 EnterCriticalSection( &PROFILE_CritSect );
1587 if (PROFILE_Open( filename ))
1588 ret = PROFILE_GetSectionNames(buffer, size);
1590 LeaveCriticalSection( &PROFILE_CritSect );
1592 return ret;
1596 /***********************************************************************
1597 * GetProfileSectionNames (KERNEL.142)
1599 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1602 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1606 /***********************************************************************
1607 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1609 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1610 LPCSTR filename)
1613 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1617 /***********************************************************************
1618 * GetPrivateProfileSectionNamesW (KERNEL32.@)
1620 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1621 LPCWSTR filename)
1624 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1625 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1627 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1628 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1629 buffer[size-1] = 0;
1630 HeapFree( GetProcessHeap(), 0, bufferA);
1631 HeapFree( GetProcessHeap(), 0, filenameA );
1633 return ret;
1636 /***********************************************************************
1637 * GetPrivateProfileStruct (KERNEL.407)
1639 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1640 LPVOID buf, UINT16 len, LPCSTR filename)
1642 return GetPrivateProfileStructA( section, key, buf, len, filename );
1645 /***********************************************************************
1646 * GetPrivateProfileStructA (KERNEL32.@)
1648 * Should match Win95's behaviour pretty much
1650 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1651 LPVOID buf, UINT len, LPCSTR filename)
1653 BOOL ret = FALSE;
1655 EnterCriticalSection( &PROFILE_CritSect );
1657 if (PROFILE_Open( filename )) {
1658 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1659 if (k) {
1660 TRACE("value (at %p): '%s'\n", k->value, k->value);
1661 if (((strlen(k->value) - 2) / 2) == len)
1663 LPSTR end, p;
1664 BOOL valid = TRUE;
1665 CHAR c;
1666 DWORD chksum = 0;
1668 end = k->value + strlen(k->value); /* -> '\0' */
1669 /* check for invalid chars in ASCII coded hex string */
1670 for (p=k->value; p < end; p++)
1672 if (!isxdigit(*p))
1674 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1675 *p, filename, section, key);
1676 valid = FALSE;
1677 break;
1680 if (valid)
1682 BOOL highnibble = TRUE;
1683 BYTE b = 0, val;
1684 LPBYTE binbuf = (LPBYTE)buf;
1686 end -= 2; /* don't include checksum in output data */
1687 /* translate ASCII hex format into binary data */
1688 for (p=k->value; p < end; p++)
1690 c = toupper(*p);
1691 val = (c > '9') ?
1692 (c - 'A' + 10) : (c - '0');
1694 if (highnibble)
1695 b = val << 4;
1696 else
1698 b += val;
1699 *binbuf++ = b; /* feed binary data into output */
1700 chksum += b; /* calculate checksum */
1702 highnibble ^= 1; /* toggle */
1704 /* retrieve stored checksum value */
1705 c = toupper(*p++);
1706 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1707 c = toupper(*p);
1708 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1709 if (b == (chksum & 0xff)) /* checksums match ? */
1710 ret = TRUE;
1715 LeaveCriticalSection( &PROFILE_CritSect );
1717 return ret;
1720 /***********************************************************************
1721 * GetPrivateProfileStructW (KERNEL32.@)
1723 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1724 LPVOID buffer, UINT len, LPCWSTR filename)
1726 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1727 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1728 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1729 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1731 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1732 len, filenameA );
1733 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1734 ((LPWSTR)buffer)[len-1] = 0;
1735 HeapFree( GetProcessHeap(), 0, bufferA);
1736 HeapFree( GetProcessHeap(), 0, sectionA );
1737 HeapFree( GetProcessHeap(), 0, keyA );
1738 HeapFree( GetProcessHeap(), 0, filenameA );
1740 return ret;
1745 /***********************************************************************
1746 * WritePrivateProfileStruct (KERNEL.406)
1748 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1749 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1751 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1754 /***********************************************************************
1755 * WritePrivateProfileStructA (KERNEL32.@)
1757 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1758 LPVOID buf, UINT bufsize, LPCSTR filename)
1760 BOOL ret = FALSE;
1761 LPBYTE binbuf;
1762 LPSTR outstring, p;
1763 DWORD sum = 0;
1765 if (!section && !key && !buf) /* flush the cache */
1766 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1768 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1769 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1770 p = outstring;
1771 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1772 *p++ = hex[*binbuf >> 4];
1773 *p++ = hex[*binbuf & 0xf];
1774 sum += *binbuf;
1776 /* checksum is sum & 0xff */
1777 *p++ = hex[(sum & 0xf0) >> 4];
1778 *p++ = hex[sum & 0xf];
1779 *p++ = '\0';
1781 EnterCriticalSection( &PROFILE_CritSect );
1783 if (PROFILE_Open( filename ))
1784 ret = PROFILE_SetString( section, key, outstring );
1786 LeaveCriticalSection( &PROFILE_CritSect );
1788 HeapFree( GetProcessHeap(), 0, outstring );
1790 return ret;
1793 /***********************************************************************
1794 * WritePrivateProfileStructW (KERNEL32.@)
1796 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1797 LPVOID buf, UINT bufsize, LPCWSTR filename)
1799 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1800 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1801 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1802 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1803 filenameA );
1804 HeapFree( GetProcessHeap(), 0, sectionA );
1805 HeapFree( GetProcessHeap(), 0, keyA );
1806 HeapFree( GetProcessHeap(), 0, filenameA );
1808 return ret;
1812 /***********************************************************************
1813 * WriteOutProfiles (KERNEL.315)
1815 void WINAPI WriteOutProfiles16(void)
1817 EnterCriticalSection( &PROFILE_CritSect );
1818 PROFILE_FlushFile();
1819 LeaveCriticalSection( &PROFILE_CritSect );
1822 /***********************************************************************
1823 * CloseProfileUserMapping (KERNEL32.@)
1825 BOOL WINAPI CloseProfileUserMapping(void) {
1826 FIXME("(), stub!\n");
1827 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1828 return FALSE;