Moved window move/resize syscommand handling to the graphics driver.
[wine/multimedia.git] / files / profile.c
blobc0db4efacac292abb4db9febe7f22f9ecdf4ee74
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 (return_values && key->value) {
726 buffer[-1] = '=';
727 PROFILE_CopyEntry ( buffer,
728 key->value, len - 1, handle_env );
729 len -= strlen(buffer) + 1;
730 buffer += strlen(buffer) + 1;
733 *buffer = '\0';
734 if (len <= 1)
735 /*If either lpszSection or lpszKey is NULL and the supplied
736 destination buffer is too small to hold all the strings,
737 the last string is truncated and followed by two null characters.
738 In this case, the return value is equal to cchReturnBuffer
739 minus two. */
741 buffer[-1] = '\0';
742 return oldlen - 2;
744 return oldlen - len;
746 section = section->next;
748 buffer[0] = buffer[1] = '\0';
749 return 0;
753 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
755 LPSTR buf = buffer;
756 WORD l, cursize = 0;
757 PROFILESECTION *section;
759 if(!buffer) return 0;
761 for (section = CurProfile->section; section; section = section->next)
762 if (section->name) {
763 l = strlen(section->name);
764 cursize += l+1;
765 if (cursize > len+1)
766 return len-2;
768 strcpy(buf, section->name);
769 buf += l+1;
772 *buf=0;
773 buf++;
774 return buf-buffer;
778 /***********************************************************************
779 * PROFILE_GetString
781 * Get a profile string.
783 * Tests with GetPrivateProfileString16, W95a,
784 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
785 * section key_name def_val res buffer
786 * "set1" "1" "x" 43 [data]
787 * "set1" "1 " "x" 43 [data] (!)
788 * "set1" " 1 "' "x" 43 [data] (!)
789 * "set1" "" "x" 1 "x"
790 * "set1" "" "x " 1 "x" (!)
791 * "set1" "" " x " 3 " x" (!)
792 * "set1" NULL "x" 6 "1\02\03\0\0"
793 * "set1" "" "x" 1 "x"
794 * NULL "1" "x" 0 "" (!)
795 * "" "1" "x" 1 "x"
796 * NULL NULL "" 0 ""
800 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
801 LPCSTR def_val, LPSTR buffer, UINT len )
803 PROFILEKEY *key = NULL;
805 if(!buffer) return 0;
807 if (!def_val) def_val = "";
808 if (key_name && key_name[0])
810 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
811 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
812 len, FALSE );
813 TRACE("('%s','%s','%s'): returning '%s'\n",
814 section, key_name, def_val, buffer );
815 return strlen( buffer );
817 if (key_name && !(key_name[0]))
818 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
819 return 0;
820 if (section && section[0])
821 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
822 FALSE, FALSE);
823 buffer[0] = '\0';
824 return 0;
828 /***********************************************************************
829 * PROFILE_SetString
831 * Set a profile string.
833 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
834 LPCSTR value )
836 if (!key_name) /* Delete a whole section */
838 TRACE("('%s')\n", section_name);
839 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
840 section_name );
841 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
842 this is not an error on application's level.*/
844 else if (!value) /* Delete a key */
846 TRACE("('%s','%s')\n",
847 section_name, key_name );
848 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
849 section_name, key_name );
850 return TRUE; /* same error handling as above */
852 else /* Set the key value */
854 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
855 key_name, TRUE );
856 TRACE("('%s','%s','%s'): \n",
857 section_name, key_name, value );
858 if (!key) return FALSE;
859 if (key->value)
861 /* strip the leading spaces. We can safely strip \n\r and
862 * friends too, they should not happen here anyway. */
863 while (PROFILE_isspace(*value)) value++;
865 if (!strcmp( key->value, value ))
867 TRACE(" no change needed\n" );
868 return TRUE; /* No change needed */
870 TRACE(" replacing '%s'\n", key->value );
871 HeapFree( GetProcessHeap(), 0, key->value );
873 else TRACE(" creating key\n" );
874 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
875 CurProfile->changed = TRUE;
877 return TRUE;
881 /***********************************************************************
882 * PROFILE_GetWineIniString
884 * Get a config string from the wine.ini file.
886 int PROFILE_GetWineIniString( const char *section, const char *key_name,
887 const char *def, char *buffer, int len )
889 char tmp[PROFILE_MAX_LINE_LEN];
890 HKEY hkey;
891 DWORD err;
893 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
895 DWORD type;
896 DWORD count = sizeof(tmp);
897 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
898 RegCloseKey( hkey );
900 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
901 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
902 return strlen(buffer);
906 /***********************************************************************
907 * PROFILE_EnumWineIniString
909 * Get a config string from the wine.ini file.
911 BOOL PROFILE_EnumWineIniString( const char *section, int index,
912 char *name, int name_len, char *buffer, int len )
914 char tmp[PROFILE_MAX_LINE_LEN];
915 HKEY hkey;
916 DWORD err, type;
917 DWORD count = sizeof(tmp);
919 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
920 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
921 RegCloseKey( hkey );
922 if (!err)
924 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
925 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
927 return !err;
931 /***********************************************************************
932 * PROFILE_GetWineIniInt
934 * Get a config integer from the wine.ini file.
936 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
938 char buffer[20];
939 char *p;
940 long result;
942 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
943 if (!buffer[0]) return def;
944 result = strtol( buffer, &p, 0 );
945 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
949 /******************************************************************************
951 * int PROFILE_GetWineIniBool(
952 * char const *section,
953 * char const *key_name,
954 * int def )
956 * Reads a boolean value from the wine.ini file. This function attempts to
957 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
958 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
959 * true. Anything else results in the return of the default value.
961 * This function uses 1 to indicate true, and 0 for false. You can check
962 * for existence by setting def to something other than 0 or 1 and
963 * examining the return value.
965 int PROFILE_GetWineIniBool(
966 char const *section,
967 char const *key_name,
968 int def )
970 char key_value[2];
971 int retval;
973 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
975 switch(key_value[0]) {
976 case 'n':
977 case 'N':
978 case 'f':
979 case 'F':
980 case '0':
981 retval = 0;
982 break;
984 case 'y':
985 case 'Y':
986 case 't':
987 case 'T':
988 case '1':
989 retval = 1;
990 break;
992 default:
993 retval = def;
996 TRACE("(\"%s\", \"%s\", %s), "
997 "[%c], ret %s.\n", section, key_name,
998 def ? "TRUE" : "FALSE", key_value[0],
999 retval ? "TRUE" : "FALSE");
1001 return retval;
1005 /***********************************************************************
1006 * PROFILE_LoadWineIni
1008 * Load the old .winerc file.
1010 int PROFILE_LoadWineIni(void)
1012 OBJECT_ATTRIBUTES attr;
1013 UNICODE_STRING nameW;
1014 char buffer[MAX_PATHNAME_LEN];
1015 const char *p;
1016 FILE *f;
1017 HKEY hKeySW;
1018 DWORD disp;
1020 attr.Length = sizeof(attr);
1021 attr.RootDirectory = 0;
1022 attr.ObjectName = &nameW;
1023 attr.Attributes = 0;
1024 attr.SecurityDescriptor = NULL;
1025 attr.SecurityQualityOfService = NULL;
1027 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1028 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1029 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1031 ERR("Cannot create config registry key\n" );
1032 ExitProcess( 1 );
1034 RtlFreeUnicodeString( &nameW );
1035 NtClose( hKeySW );
1037 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1038 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1039 NULL, REG_OPTION_VOLATILE, &disp ))
1041 ERR("Cannot create config registry key\n" );
1042 ExitProcess( 1 );
1044 RtlFreeUnicodeString( &nameW );
1046 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1048 if ((p = getenv( "HOME" )) != NULL)
1050 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1051 strcat( buffer, PROFILE_WineIniName );
1052 if ((f = fopen( buffer, "r" )) != NULL)
1054 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1055 goto found;
1058 else WARN("could not get $HOME value for config file.\n" );
1060 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1062 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1063 return 0;
1065 found:
1067 if (disp == REG_OPENED_EXISTING_KEY)
1069 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1070 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1071 fclose( f );
1072 return 1;
1075 /* convert to the new format */
1076 sprintf( buffer, "%s/config", get_config_dir() );
1077 convert_config( f, buffer );
1078 fclose( f );
1080 MESSAGE( "The '%s' configuration file has been converted\n"
1081 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1082 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1083 "and then remove the old one and restart Wine.\n" );
1084 ExitProcess(0);
1088 /***********************************************************************
1089 * PROFILE_UsageWineIni
1091 * Explain the wine.ini file to those who don't read documentation.
1092 * Keep below one screenful in length so that error messages above are
1093 * noticed.
1095 void PROFILE_UsageWineIni(void)
1097 MESSAGE("Perhaps you have not properly edited or created "
1098 "your Wine configuration file.\n");
1099 MESSAGE("This is '%s/config'\n", get_config_dir());
1100 /* RTFM, so to say */
1103 /***********************************************************************
1104 * PROFILE_GetStringItem
1106 * Convenience function that turns a string 'xxx, yyy, zzz' into
1107 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1109 char* PROFILE_GetStringItem( char* start )
1111 char* lpchX, *lpch;
1113 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1115 if( *lpchX == ',' )
1117 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1118 while( *(++lpchX) )
1119 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1121 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1122 else lpch = NULL;
1124 if( lpch ) *lpch = '\0';
1125 return NULL;
1128 /********************* API functions **********************************/
1130 /***********************************************************************
1131 * GetProfileInt16 (KERNEL.57)
1133 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1135 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1139 /***********************************************************************
1140 * GetProfileIntA (KERNEL32.264)
1142 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1144 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1147 /***********************************************************************
1148 * GetProfileIntW (KERNEL32.264)
1150 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1152 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1156 * undoc_feature means:
1157 * return section names string list if both section and entry are NULL.
1159 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1160 LPCSTR def_val, LPSTR buffer,
1161 UINT16 len, LPCSTR filename,
1162 BOOL undoc_feature )
1164 int ret;
1165 LPSTR pDefVal = NULL;
1167 if (!filename)
1168 filename = "win.ini";
1170 /* strip any trailing ' ' of def_val. */
1171 if (def_val)
1173 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1175 while (p > def_val)
1177 p--;
1178 if ((*p) != ' ')
1179 break;
1181 if (*p == ' ') /* ouch, contained trailing ' ' */
1183 int len = (int)p - (int)def_val;
1184 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1185 strncpy(pDefVal, def_val, len);
1186 pDefVal[len] = '\0';
1189 if (!pDefVal)
1190 pDefVal = (LPSTR)def_val;
1192 EnterCriticalSection( &PROFILE_CritSect );
1194 if (PROFILE_Open( filename )) {
1195 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1196 /* undocumented; both section and entry are NULL */
1197 ret = PROFILE_GetSectionNames(buffer, len);
1198 else
1199 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1200 } else {
1201 lstrcpynA( buffer, pDefVal, len );
1202 ret = strlen( buffer );
1205 LeaveCriticalSection( &PROFILE_CritSect );
1207 if (pDefVal != def_val) /* allocated */
1208 HeapFree(GetProcessHeap(), 0, pDefVal);
1210 return ret;
1213 /***********************************************************************
1214 * GetPrivateProfileString16 (KERNEL.128)
1216 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1217 LPCSTR def_val, LPSTR buffer,
1218 UINT16 len, LPCSTR filename )
1220 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1221 buffer, len, filename, FALSE );
1224 /***********************************************************************
1225 * GetPrivateProfileStringA (KERNEL32.255)
1227 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1228 LPCSTR def_val, LPSTR buffer,
1229 UINT len, LPCSTR filename )
1231 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1232 buffer, len, filename, TRUE );
1235 /***********************************************************************
1236 * GetPrivateProfileStringW (KERNEL32.256)
1238 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1239 LPCWSTR def_val, LPWSTR buffer,
1240 UINT len, LPCWSTR filename )
1242 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1243 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1244 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1245 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1246 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1247 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1248 bufferA, len, filenameA );
1249 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1250 buffer[len-1] = 0;
1251 HeapFree( GetProcessHeap(), 0, sectionA );
1252 HeapFree( GetProcessHeap(), 0, entryA );
1253 HeapFree( GetProcessHeap(), 0, filenameA );
1254 HeapFree( GetProcessHeap(), 0, def_valA );
1255 HeapFree( GetProcessHeap(), 0, bufferA);
1256 return ret;
1259 /***********************************************************************
1260 * GetProfileString16 (KERNEL.58)
1262 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1263 LPSTR buffer, UINT16 len )
1265 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1266 buffer, len, "win.ini", FALSE );
1269 /***********************************************************************
1270 * GetProfileStringA (KERNEL32.268)
1272 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1273 LPSTR buffer, UINT len )
1275 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1276 buffer, len, "win.ini", TRUE );
1279 /***********************************************************************
1280 * GetProfileStringW (KERNEL32.269)
1282 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1283 LPCWSTR def_val, LPWSTR buffer, UINT len )
1285 return GetPrivateProfileStringW( section, entry, def_val,
1286 buffer, len, wininiW );
1289 /***********************************************************************
1290 * WriteProfileString16 (KERNEL.59)
1292 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1293 LPCSTR string )
1295 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1298 /***********************************************************************
1299 * WriteProfileStringA (KERNEL32.587)
1301 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1302 LPCSTR string )
1304 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1307 /***********************************************************************
1308 * WriteProfileStringW (KERNEL32.588)
1310 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1311 LPCWSTR string )
1313 return WritePrivateProfileStringW( section, entry, string, wininiW );
1317 /***********************************************************************
1318 * GetPrivateProfileInt16 (KERNEL.127)
1320 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1321 INT16 def_val, LPCSTR filename )
1323 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1325 if (result > 65535) return 65535;
1326 if (result >= 0) return (UINT16)result;
1327 if (result < -32768) return -32768;
1328 return (UINT16)(INT16)result;
1331 /***********************************************************************
1332 * GetPrivateProfileIntA (KERNEL32.251)
1334 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1335 INT def_val, LPCSTR filename )
1337 char buffer[20];
1338 char *p;
1339 long result;
1341 PROFILE_GetPrivateProfileString( section, entry, "",
1342 buffer, sizeof(buffer), filename, FALSE );
1343 if (!buffer[0]) return (UINT)def_val;
1344 result = strtol( buffer, &p, 0 );
1345 if (p == buffer) return 0; /* No digits at all */
1346 return (UINT)result;
1349 /***********************************************************************
1350 * GetPrivateProfileIntW (KERNEL32.252)
1352 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1353 INT def_val, LPCWSTR filename )
1355 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1356 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1357 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1358 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1359 HeapFree( GetProcessHeap(), 0, sectionA );
1360 HeapFree( GetProcessHeap(), 0, filenameA );
1361 HeapFree( GetProcessHeap(), 0, entryA );
1362 return res;
1365 /***********************************************************************
1366 * GetPrivateProfileSection16 (KERNEL.418)
1368 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1369 UINT16 len, LPCSTR filename )
1371 return GetPrivateProfileSectionA( section, buffer, len, filename );
1374 /***********************************************************************
1375 * GetPrivateProfileSectionA (KERNEL32.255)
1377 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1378 DWORD len, LPCSTR filename )
1380 int ret = 0;
1382 EnterCriticalSection( &PROFILE_CritSect );
1384 if (PROFILE_Open( filename ))
1385 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1386 FALSE, TRUE);
1388 LeaveCriticalSection( &PROFILE_CritSect );
1390 return ret;
1393 /***********************************************************************
1394 * GetPrivateProfileSectionW (KERNEL32.256)
1397 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1398 DWORD len, LPCWSTR filename )
1401 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1402 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1403 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1404 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1405 filenameA );
1406 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1407 HeapFree( GetProcessHeap(), 0, sectionA );
1408 HeapFree( GetProcessHeap(), 0, filenameA );
1409 HeapFree( GetProcessHeap(), 0, bufferA);
1410 return ret;
1413 /***********************************************************************
1414 * GetProfileSection16 (KERNEL.419)
1416 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1418 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1421 /***********************************************************************
1422 * GetProfileSectionA (KERNEL32.268)
1424 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1426 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1429 /***********************************************************************
1430 * GetProfileSectionW (KERNEL32)
1432 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1434 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1438 /***********************************************************************
1439 * WritePrivateProfileString16 (KERNEL.129)
1441 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1442 LPCSTR string, LPCSTR filename )
1444 return WritePrivateProfileStringA(section,entry,string,filename);
1447 /***********************************************************************
1448 * WritePrivateProfileStringA (KERNEL32.582)
1450 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1451 LPCSTR string, LPCSTR filename )
1453 BOOL ret = FALSE;
1455 EnterCriticalSection( &PROFILE_CritSect );
1457 if (PROFILE_Open( filename ))
1459 if (!section && !entry && !string)
1460 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1461 else
1462 ret = PROFILE_SetString( section, entry, string );
1465 LeaveCriticalSection( &PROFILE_CritSect );
1466 return ret;
1469 /***********************************************************************
1470 * WritePrivateProfileStringW (KERNEL32.583)
1472 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1473 LPCWSTR string, LPCWSTR filename )
1475 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1476 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1477 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1478 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1479 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1480 stringA, filenameA );
1481 HeapFree( GetProcessHeap(), 0, sectionA );
1482 HeapFree( GetProcessHeap(), 0, entryA );
1483 HeapFree( GetProcessHeap(), 0, stringA );
1484 HeapFree( GetProcessHeap(), 0, filenameA );
1485 return res;
1488 /***********************************************************************
1489 * WritePrivateProfileSection16 (KERNEL.416)
1491 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1492 LPCSTR string, LPCSTR filename )
1494 return WritePrivateProfileSectionA( section, string, filename );
1497 /***********************************************************************
1498 * WritePrivateProfileSectionA (KERNEL32)
1500 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1501 LPCSTR string, LPCSTR filename )
1503 BOOL ret = FALSE;
1504 LPSTR p ;
1506 EnterCriticalSection( &PROFILE_CritSect );
1508 if (PROFILE_Open( filename )) {
1509 if (!section && !string)
1510 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1511 else if (!string) /* delete the named section*/
1512 ret = PROFILE_SetString(section,NULL,NULL);
1513 else {
1514 PROFILE_DeleteAllKeys(section);
1515 ret = TRUE;
1516 while(*string) {
1517 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1518 if((p=strchr( buf, '='))){
1519 *p='\0';
1520 ret = PROFILE_SetString( section, buf, p+1 );
1523 HeapFree( GetProcessHeap(), 0, buf );
1524 string += strlen(string)+1;
1530 LeaveCriticalSection( &PROFILE_CritSect );
1531 return ret;
1534 /***********************************************************************
1535 * WritePrivateProfileSectionW (KERNEL32)
1537 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1538 LPCWSTR string, LPCWSTR filename)
1541 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1542 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1543 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1544 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1545 HeapFree( GetProcessHeap(), 0, sectionA );
1546 HeapFree( GetProcessHeap(), 0, stringA );
1547 HeapFree( GetProcessHeap(), 0, filenameA );
1548 return res;
1551 /***********************************************************************
1552 * WriteProfileSection16 (KERNEL.417)
1554 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1556 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1559 /***********************************************************************
1560 * WriteProfileSectionA (KERNEL32.747)
1562 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1565 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1568 /***********************************************************************
1569 * WriteProfileSectionW (KERNEL32.748)
1571 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1573 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1576 /***********************************************************************
1577 * GetPrivateProfileSectionNames16 (KERNEL.143)
1579 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1580 LPCSTR filename )
1582 WORD ret = 0;
1584 EnterCriticalSection( &PROFILE_CritSect );
1586 if (PROFILE_Open( filename ))
1587 ret = PROFILE_GetSectionNames(buffer, size);
1589 LeaveCriticalSection( &PROFILE_CritSect );
1591 return ret;
1595 /***********************************************************************
1596 * GetProfileSectionNames16 (KERNEL.142)
1598 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1601 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1605 /***********************************************************************
1606 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1608 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1609 LPCSTR filename)
1612 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1616 /***********************************************************************
1617 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1619 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1620 LPCWSTR filename)
1623 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1624 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1626 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1627 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1628 buffer[size-1] = 0;
1629 HeapFree( GetProcessHeap(), 0, bufferA);
1630 HeapFree( GetProcessHeap(), 0, filenameA );
1632 return ret;
1635 /***********************************************************************
1636 * GetPrivateProfileStruct16 (KERNEL.407)
1638 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1639 LPVOID buf, UINT16 len, LPCSTR filename)
1641 return GetPrivateProfileStructA( section, key, buf, len, filename );
1644 /***********************************************************************
1645 * GetPrivateProfileStructA (KERNEL32.370)
1647 * Should match Win95's behaviour pretty much
1649 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1650 LPVOID buf, UINT len, LPCSTR filename)
1652 BOOL ret = FALSE;
1654 EnterCriticalSection( &PROFILE_CritSect );
1656 if (PROFILE_Open( filename )) {
1657 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1658 if (k) {
1659 TRACE("value (at %p): '%s'\n", k->value, k->value);
1660 if (((strlen(k->value) - 2) / 2) == len)
1662 LPSTR end, p;
1663 BOOL valid = TRUE;
1664 CHAR c;
1665 DWORD chksum = 0;
1667 end = k->value + strlen(k->value); /* -> '\0' */
1668 /* check for invalid chars in ASCII coded hex string */
1669 for (p=k->value; p < end; p++)
1671 if (!isxdigit(*p))
1673 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1674 *p, filename, section, key);
1675 valid = FALSE;
1676 break;
1679 if (valid)
1681 BOOL highnibble = TRUE;
1682 BYTE b = 0, val;
1683 LPBYTE binbuf = (LPBYTE)buf;
1685 end -= 2; /* don't include checksum in output data */
1686 /* translate ASCII hex format into binary data */
1687 for (p=k->value; p < end; p++)
1689 c = toupper(*p);
1690 val = (c > '9') ?
1691 (c - 'A' + 10) : (c - '0');
1693 if (highnibble)
1694 b = val << 4;
1695 else
1697 b += val;
1698 *binbuf++ = b; /* feed binary data into output */
1699 chksum += b; /* calculate checksum */
1701 highnibble ^= 1; /* toggle */
1703 /* retrieve stored checksum value */
1704 c = toupper(*p++);
1705 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1706 c = toupper(*p);
1707 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1708 if (b == (chksum & 0xff)) /* checksums match ? */
1709 ret = TRUE;
1714 LeaveCriticalSection( &PROFILE_CritSect );
1716 return ret;
1719 /***********************************************************************
1720 * GetPrivateProfileStructW (KERNEL32.543)
1722 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1723 LPVOID buffer, UINT len, LPCWSTR filename)
1725 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1726 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1727 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1728 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1730 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1731 len, filenameA );
1732 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1733 ((LPWSTR)buffer)[len-1] = 0;
1734 HeapFree( GetProcessHeap(), 0, bufferA);
1735 HeapFree( GetProcessHeap(), 0, sectionA );
1736 HeapFree( GetProcessHeap(), 0, keyA );
1737 HeapFree( GetProcessHeap(), 0, filenameA );
1739 return ret;
1744 /***********************************************************************
1745 * WritePrivateProfileStruct16 (KERNEL.406)
1747 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1748 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1750 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1753 /***********************************************************************
1754 * WritePrivateProfileStructA (KERNEL32.744)
1756 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1757 LPVOID buf, UINT bufsize, LPCSTR filename)
1759 BOOL ret = FALSE;
1760 LPBYTE binbuf;
1761 LPSTR outstring, p;
1762 DWORD sum = 0;
1764 if (!section && !key && !buf) /* flush the cache */
1765 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1767 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1768 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1769 p = outstring;
1770 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1771 *p++ = hex[*binbuf >> 4];
1772 *p++ = hex[*binbuf & 0xf];
1773 sum += *binbuf;
1775 /* checksum is sum & 0xff */
1776 *p++ = hex[(sum & 0xf0) >> 4];
1777 *p++ = hex[sum & 0xf];
1778 *p++ = '\0';
1780 EnterCriticalSection( &PROFILE_CritSect );
1782 if (PROFILE_Open( filename ))
1783 ret = PROFILE_SetString( section, key, outstring );
1785 LeaveCriticalSection( &PROFILE_CritSect );
1787 HeapFree( GetProcessHeap(), 0, outstring );
1789 return ret;
1792 /***********************************************************************
1793 * WritePrivateProfileStructW (KERNEL32.544)
1795 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1796 LPVOID buf, UINT bufsize, LPCWSTR filename)
1798 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1799 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1800 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1801 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1802 filenameA );
1803 HeapFree( GetProcessHeap(), 0, sectionA );
1804 HeapFree( GetProcessHeap(), 0, keyA );
1805 HeapFree( GetProcessHeap(), 0, filenameA );
1807 return ret;
1811 /***********************************************************************
1812 * WriteOutProfiles (KERNEL.315)
1814 void WINAPI WriteOutProfiles16(void)
1816 EnterCriticalSection( &PROFILE_CritSect );
1817 PROFILE_FlushFile();
1818 LeaveCriticalSection( &PROFILE_CritSect );
1821 /***********************************************************************
1822 * CloseProfileUserMapping (KERNEL.138)
1824 BOOL WINAPI CloseProfileUserMapping(void) {
1825 FIXME("(), stub!\n");
1826 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1827 return FALSE;