Don't close groups of polylines.
[wine/multimedia.git] / files / profile.c
blobf4fa3bba1ff6a0871cdede3808e54d1409c63b18
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <pwd.h>
15 #include <unistd.h>
17 #include "winbase.h"
18 #include "winerror.h"
19 #include "wine/winbase16.h"
20 #include "windef.h"
21 #include "wingdi.h"
22 #include "winuser.h"
23 #include "winnls.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 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
82 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
84 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
86 static const char hex[16] = "0123456789ABCDEF";
88 /***********************************************************************
89 * PROFILE_CopyEntry
91 * Copy the content of an entry into a buffer, removing quotes, and possibly
92 * translating environment variables.
94 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
95 int handle_env )
97 char quote = '\0';
98 const char *p;
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 lstrcpynA( buffer, env_p, len );
124 buffer += strlen( buffer );
125 len -= strlen( buffer );
127 p = p2 + 1;
130 if (quote && (len > 1)) buffer--;
131 *buffer = '\0';
135 /***********************************************************************
136 * PROFILE_Save
138 * Save a profile tree to a file.
140 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
142 PROFILEKEY *key;
144 for ( ; section; section = section->next)
146 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
147 for (key = section->key; key; key = key->next)
149 fprintf( file, "%s", key->name );
150 if (key->value) fprintf( file, "=%s", key->value );
151 fprintf( file, "\r\n" );
157 /***********************************************************************
158 * PROFILE_Free
160 * Free a profile tree.
162 static void PROFILE_Free( PROFILESECTION *section )
164 PROFILESECTION *next_section;
165 PROFILEKEY *key, *next_key;
167 for ( ; section; section = next_section)
169 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
170 for (key = section->key; key; key = next_key)
172 next_key = key->next;
173 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
174 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
175 HeapFree( GetProcessHeap(), 0, key );
177 next_section = section->next;
178 HeapFree( GetProcessHeap(), 0, section );
182 static inline int PROFILE_isspace(char c)
184 if (isspace(c)) return 1;
185 if (c=='\r' || c==0x1a) return 1;
186 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
187 return 0;
191 /***********************************************************************
192 * PROFILE_Load
194 * Load a profile tree from a file.
196 static PROFILESECTION *PROFILE_Load( FILE *file )
198 char buffer[PROFILE_MAX_LINE_LEN];
199 char *p, *p2;
200 int line = 0;
201 PROFILESECTION *section, *first_section;
202 PROFILESECTION **next_section;
203 PROFILEKEY *key, *prev_key, **next_key;
205 first_section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section) );
206 first_section->name = NULL;
207 first_section->key = NULL;
208 first_section->next = NULL;
209 next_section = &first_section->next;
210 next_key = &first_section->key;
211 prev_key = NULL;
213 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
215 line++;
216 p = buffer;
217 while (*p && PROFILE_isspace(*p)) p++;
218 if (*p == '[') /* section start */
220 if (!(p2 = strrchr( p, ']' )))
222 WARN("Invalid section header at line %d: '%s'\n",
223 line, p );
225 else
227 *p2 = '\0';
228 p++;
229 section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section) );
230 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
231 section->key = NULL;
232 section->next = NULL;
233 *next_section = section;
234 next_section = &section->next;
235 next_key = &section->key;
236 prev_key = NULL;
238 TRACE("New section: '%s'\n",section->name);
240 continue;
244 p2=p+strlen(p) - 1;
245 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
247 if ((p2 = strchr( p, '=' )) != NULL)
249 char *p3 = p2 - 1;
250 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
251 *p2++ = '\0';
252 while (*p2 && PROFILE_isspace(*p2)) p2++;
255 if(*p || !prev_key || *prev_key->name)
257 key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*key) );
258 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
259 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
260 key->next = NULL;
261 *next_key = key;
262 next_key = &key->next;
263 prev_key = key;
265 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
268 return first_section;
272 /***********************************************************************
273 * PROFILE_RegistryLoad
275 * Load a profile tree from a file into a registry key.
277 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
279 HKEY hkey = 0;
280 DWORD err = 0;
281 char buffer[PROFILE_MAX_LINE_LEN];
282 char *p, *p2;
283 int line = 0;
285 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
287 line++;
288 p = buffer;
289 while (*p && PROFILE_isspace(*p)) p++;
290 if (*p == '[') /* section start */
292 if (!(p2 = strrchr( p, ']' )))
294 WARN("Invalid section header at line %d: '%s'\n",
295 line, p );
297 else
299 *p2 = '\0';
300 p++;
301 if (hkey) RegCloseKey( hkey );
302 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
303 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
304 TRACE("New section: '%s'\n",p);
305 continue;
309 p2=p+strlen(p) - 1;
310 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
312 if ((p2 = strchr( p, '=' )) != NULL)
314 char *p3 = p2 - 1;
315 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
316 *p2++ = '\0';
317 while (*p2 && PROFILE_isspace(*p2)) p2++;
320 if (*p && hkey && !IS_ENTRY_COMMENT(p))
322 if (!p2) p2 = "";
323 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
325 RegCloseKey( hkey );
326 return err;
328 TRACE("New key: name='%s', value='%s'\n",p,p2);
331 if (hkey) RegCloseKey( hkey );
332 return 0;
336 /***********************************************************************
337 * PROFILE_DeleteSection
339 * Delete a section from a profile tree.
341 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
343 while (*section)
345 if ((*section)->name && !strcasecmp( (*section)->name, name ))
347 PROFILESECTION *to_del = *section;
348 *section = to_del->next;
349 to_del->next = NULL;
350 PROFILE_Free( to_del );
351 return TRUE;
353 section = &(*section)->next;
355 return FALSE;
359 /***********************************************************************
360 * PROFILE_DeleteKey
362 * Delete a key from a profile tree.
364 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
365 LPCSTR section_name, LPCSTR key_name )
367 while (*section)
369 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
371 PROFILEKEY **key = &(*section)->key;
372 while (*key)
374 if (!strcasecmp( (*key)->name, key_name ))
376 PROFILEKEY *to_del = *key;
377 *key = to_del->next;
378 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
379 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
380 HeapFree( GetProcessHeap(), 0, to_del );
381 return TRUE;
383 key = &(*key)->next;
386 section = &(*section)->next;
388 return FALSE;
392 /***********************************************************************
393 * PROFILE_Find
395 * Find a key in a profile tree, optionally creating it.
397 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
398 const char *section_name,
399 const char *key_name, int create )
401 const char *p;
402 int seclen, keylen;
404 while (PROFILE_isspace(*section_name)) section_name++;
405 p = section_name + strlen(section_name) - 1;
406 while ((p > section_name) && PROFILE_isspace(*p)) p--;
407 seclen = p - section_name + 1;
409 while (PROFILE_isspace(*key_name)) key_name++;
410 p = key_name + strlen(key_name) - 1;
411 while ((p > key_name) && PROFILE_isspace(*p)) p--;
412 keylen = p - key_name + 1;
414 while (*section)
416 if ( ((*section)->name)
417 && (!(strncasecmp( (*section)->name, section_name, seclen )))
418 && (((*section)->name)[seclen] == '\0') )
420 PROFILEKEY **key = &(*section)->key;
421 while (*key)
423 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
424 && (((*key)->name)[keylen] == '\0') )
425 return *key;
426 key = &(*key)->next;
428 if (!create) return NULL;
429 *key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
430 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
431 (*key)->value = NULL;
432 (*key)->next = NULL;
433 return *key;
435 section = &(*section)->next;
437 if (!create) return NULL;
438 *section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
439 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
440 (*section)->next = NULL;
441 (*section)->key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
442 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
443 (*section)->key->value = NULL;
444 (*section)->key->next = NULL;
445 return (*section)->key;
449 /***********************************************************************
450 * PROFILE_FlushFile
452 * Flush the current profile to disk if changed.
454 static BOOL PROFILE_FlushFile(void)
456 char *p, buffer[MAX_PATHNAME_LEN];
457 const char *unix_name;
458 FILE *file = NULL;
459 struct stat buf;
461 if(!CurProfile)
463 WARN("No current profile!\n");
464 return FALSE;
467 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
468 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
470 /* Try to create it in $HOME/.wine */
471 /* FIXME: this will need a more general solution */
472 strcpy( buffer, get_config_dir() );
473 p = buffer + strlen(buffer);
474 *p++ = '/';
475 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
476 CharLowerA( p );
477 file = fopen( buffer, "w" );
478 unix_name = buffer;
481 if (!file)
483 WARN("could not save profile file %s\n", CurProfile->dos_name);
484 return FALSE;
487 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
488 PROFILE_Save( file, CurProfile->section );
489 fclose( file );
490 CurProfile->changed = FALSE;
491 if(!stat(unix_name,&buf))
492 CurProfile->mtime=buf.st_mtime;
493 return TRUE;
497 /***********************************************************************
498 * PROFILE_ReleaseFile
500 * Flush the current profile to disk and remove it from the cache.
502 static void PROFILE_ReleaseFile(void)
504 PROFILE_FlushFile();
505 PROFILE_Free( CurProfile->section );
506 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
507 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
508 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
509 CurProfile->changed = FALSE;
510 CurProfile->section = NULL;
511 CurProfile->dos_name = NULL;
512 CurProfile->unix_name = NULL;
513 CurProfile->filename = NULL;
514 CurProfile->mtime = 0;
518 /***********************************************************************
519 * PROFILE_Open
521 * Open a profile file, checking the cached file first.
523 static BOOL PROFILE_Open( LPCSTR filename )
525 DOS_FULL_NAME full_name;
526 char buffer[MAX_PATHNAME_LEN];
527 char *newdos_name, *p;
528 FILE *file = NULL;
529 int i,j;
530 struct stat buf;
531 PROFILE *tempProfile;
533 /* First time around */
535 if(!CurProfile)
536 for(i=0;i<N_CACHED_PROFILES;i++)
538 MRUProfile[i]=HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILE) );
539 MRUProfile[i]->changed=FALSE;
540 MRUProfile[i]->section=NULL;
541 MRUProfile[i]->dos_name=NULL;
542 MRUProfile[i]->unix_name=NULL;
543 MRUProfile[i]->filename=NULL;
544 MRUProfile[i]->mtime=0;
547 /* Check for a match */
549 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
550 strchr( filename, ':' ))
552 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
554 else
556 GetWindowsDirectoryA( buffer, sizeof(buffer) );
557 strcat( buffer, "\\" );
558 strcat( buffer, filename );
559 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
562 for(i=0;i<N_CACHED_PROFILES;i++)
564 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
565 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
567 if(i)
569 PROFILE_FlushFile();
570 tempProfile=MRUProfile[i];
571 for(j=i;j>0;j--)
572 MRUProfile[j]=MRUProfile[j-1];
573 CurProfile=tempProfile;
575 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
576 TRACE("(%s): already opened (mru=%d)\n",
577 filename, i );
578 else
579 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
580 filename, i );
581 return TRUE;
585 /* Flush the old current profile */
586 PROFILE_FlushFile();
588 /* Make the oldest profile the current one only in order to get rid of it */
589 if(i==N_CACHED_PROFILES)
591 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
592 for(i=N_CACHED_PROFILES-1;i>0;i--)
593 MRUProfile[i]=MRUProfile[i-1];
594 CurProfile=tempProfile;
596 if(CurProfile->filename) PROFILE_ReleaseFile();
598 /* OK, now that CurProfile is definitely free we assign it our new file */
599 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
600 CurProfile->dos_name = newdos_name;
601 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
603 /* Try to open the profile file, first in $HOME/.wine */
605 /* FIXME: this will need a more general solution */
606 strcpy( buffer, get_config_dir() );
607 p = buffer + strlen(buffer);
608 *p++ = '/';
609 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
610 CharLowerA( p );
611 if ((file = fopen( buffer, "r" )))
613 TRACE("(%s): found it in %s\n",
614 filename, buffer );
615 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
618 if (!file)
620 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
621 full_name.long_name );
622 if ((file = fopen( full_name.long_name, "r" )))
623 TRACE("(%s): found it in %s\n",
624 filename, full_name.long_name );
627 if (file)
629 CurProfile->section = PROFILE_Load( file );
630 fclose( file );
631 if(!stat(CurProfile->unix_name,&buf))
632 CurProfile->mtime=buf.st_mtime;
634 else
636 /* Does not exist yet, we will create it in PROFILE_FlushFile */
637 WARN("profile file %s not found\n", newdos_name );
639 return TRUE;
643 /***********************************************************************
644 * PROFILE_GetSection
646 * Returns all keys of a section.
647 * If return_values is TRUE, also include the corresponding values.
649 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
650 LPSTR buffer, UINT len, BOOL handle_env,
651 BOOL return_values )
653 PROFILEKEY *key;
654 while (section)
656 if (section->name && !strcasecmp( section->name, section_name ))
658 UINT oldlen = len;
659 for (key = section->key; key; key = key->next)
661 if (len <= 2) break;
662 if (!*key->name) continue; /* Skip empty lines */
663 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
664 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
665 len -= strlen(buffer) + 1;
666 buffer += strlen(buffer) + 1;
667 if (return_values && key->value) {
668 buffer[-1] = '=';
669 PROFILE_CopyEntry ( buffer,
670 key->value, len - 1, handle_env );
671 len -= strlen(buffer) + 1;
672 buffer += strlen(buffer) + 1;
675 *buffer = '\0';
676 if (len <= 1)
677 /*If either lpszSection or lpszKey is NULL and the supplied
678 destination buffer is too small to hold all the strings,
679 the last string is truncated and followed by two null characters.
680 In this case, the return value is equal to cchReturnBuffer
681 minus two. */
683 buffer[-1] = '\0';
684 return oldlen - 2;
686 return oldlen - len;
688 section = section->next;
690 buffer[0] = buffer[1] = '\0';
691 return 0;
695 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
697 LPSTR buf = buffer;
698 WORD l, cursize = 0;
699 PROFILESECTION *section;
701 for (section = CurProfile->section; section; section = section->next)
702 if (section->name) {
703 l = strlen(section->name);
704 cursize += l+1;
705 if (cursize > len+1)
706 return len-2;
708 strcpy(buf, section->name);
709 buf += l+1;
712 *buf=0;
713 buf++;
714 return buf-buffer;
718 /***********************************************************************
719 * PROFILE_GetString
721 * Get a profile string.
723 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
724 LPCSTR def_val, LPSTR buffer, UINT len )
726 PROFILEKEY *key = NULL;
728 if (!def_val) def_val = "";
729 if (key_name && key_name[0])
731 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
732 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
733 len, FALSE );
734 TRACE("('%s','%s','%s'): returning '%s'\n",
735 section, key_name, def_val, buffer );
736 return strlen( buffer );
738 if (key_name && !(key_name[0]))
739 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
740 return 0;
741 if (section && section[0])
742 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
743 FALSE, FALSE);
744 /* undocumented; both section and key_name are NULL */
745 return PROFILE_GetSectionNames(buffer, len);
749 /***********************************************************************
750 * PROFILE_SetString
752 * Set a profile string.
754 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
755 LPCSTR value )
757 if (!key_name) /* Delete a whole section */
759 TRACE("('%s')\n", section_name);
760 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
761 section_name );
762 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
763 this is not an error on application's level.*/
765 else if (!value) /* Delete a key */
767 TRACE("('%s','%s')\n",
768 section_name, key_name );
769 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
770 section_name, key_name );
771 return TRUE; /* same error handling as above */
773 else /* Set the key value */
775 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
776 key_name, TRUE );
777 TRACE("('%s','%s','%s'): \n",
778 section_name, key_name, value );
779 if (!key) return FALSE;
780 if (key->value)
782 if (!strcmp( key->value, value ))
784 TRACE(" no change needed\n" );
785 return TRUE; /* No change needed */
787 TRACE(" replacing '%s'\n", key->value );
788 HeapFree( GetProcessHeap(), 0, key->value );
790 else TRACE(" creating key\n" );
791 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
792 CurProfile->changed = TRUE;
794 return TRUE;
798 /***********************************************************************
799 * PROFILE_GetWineIniString
801 * Get a config string from the wine.ini file.
803 int PROFILE_GetWineIniString( const char *section, const char *key_name,
804 const char *def, char *buffer, int len )
806 char tmp[PROFILE_MAX_LINE_LEN];
807 HKEY hkey;
808 DWORD err;
810 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
812 DWORD type;
813 DWORD count = sizeof(tmp);
814 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
815 RegCloseKey( hkey );
817 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
818 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
819 return strlen(buffer);
823 /***********************************************************************
824 * PROFILE_EnumWineIniString
826 * Get a config string from the wine.ini file.
828 BOOL PROFILE_EnumWineIniString( const char *section, int index,
829 char *name, int name_len, char *buffer, int len )
831 char tmp[PROFILE_MAX_LINE_LEN];
832 HKEY hkey;
833 DWORD err, type;
834 DWORD count = sizeof(tmp);
836 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
837 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
838 RegCloseKey( hkey );
839 if (!err)
841 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
842 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
844 return !err;
848 /***********************************************************************
849 * PROFILE_GetWineIniInt
851 * Get a config integer from the wine.ini file.
853 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
855 char buffer[20];
856 char *p;
857 long result;
859 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
860 if (!buffer[0]) return def;
861 result = strtol( buffer, &p, 0 );
862 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
866 /******************************************************************************
868 * int PROFILE_GetWineIniBool(
869 * char const *section,
870 * char const *key_name,
871 * int def )
873 * Reads a boolean value from the wine.ini file. This function attempts to
874 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
875 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
876 * true. Anything else results in the return of the default value.
878 * This function uses 1 to indicate true, and 0 for false. You can check
879 * for existence by setting def to something other than 0 or 1 and
880 * examining the return value.
882 int PROFILE_GetWineIniBool(
883 char const *section,
884 char const *key_name,
885 int def )
887 char key_value[2];
888 int retval;
890 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
892 switch(key_value[0]) {
893 case 'n':
894 case 'N':
895 case 'f':
896 case 'F':
897 case '0':
898 retval = 0;
899 break;
901 case 'y':
902 case 'Y':
903 case 't':
904 case 'T':
905 case '1':
906 retval = 1;
907 break;
909 default:
910 retval = def;
913 TRACE("(\"%s\", \"%s\", %s), "
914 "[%c], ret %s.\n", section, key_name,
915 def ? "TRUE" : "FALSE", key_value[0],
916 retval ? "TRUE" : "FALSE");
918 return retval;
922 /***********************************************************************
923 * PROFILE_LoadWineIni
925 * Load the wine.ini file.
927 int PROFILE_LoadWineIni(void)
929 char buffer[MAX_PATHNAME_LEN];
930 const char *p;
931 FILE *f;
932 HKEY hKeySW;
934 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
935 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
937 ERR("Cannot create config registry key\n" );
938 return 0;
940 RegCloseKey( hKeySW );
941 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
942 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, NULL ))
944 ERR("Cannot create config registry key\n" );
945 return 0;
948 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
950 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
952 /* Open -config specified file */
953 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
954 goto found;
957 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
959 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
960 goto found;
962 if ((p = getenv( "HOME" )) != NULL)
964 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
965 strcat( buffer, PROFILE_WineIniName );
966 if ((f = fopen( buffer, "r" )) != NULL)
968 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
969 goto found;
972 else WARN("could not get $HOME value for config file.\n" );
974 /* Try global file */
976 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
978 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
979 goto found;
981 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
982 WINE_INI_GLOBAL, PROFILE_WineIniName );
983 return 0;
985 found:
986 PROFILE_RegistryLoad( wine_profile_key, f );
987 fclose( f );
988 return 1;
992 /***********************************************************************
993 * PROFILE_UsageWineIni
995 * Explain the wine.ini file to those who don't read documentation.
996 * Keep below one screenful in length so that error messages above are
997 * noticed.
999 void PROFILE_UsageWineIni(void)
1001 MESSAGE("Perhaps you have not properly edited or created "
1002 "your Wine configuration file.\n");
1003 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1004 MESSAGE(" or it is determined by the -config option or from\n"
1005 " the WINE_INI environment variable.\n");
1006 if (*PROFILE_WineIniUsed)
1007 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1008 /* RTFM, so to say */
1011 /***********************************************************************
1012 * PROFILE_GetStringItem
1014 * Convenience function that turns a string 'xxx, yyy, zzz' into
1015 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1017 char* PROFILE_GetStringItem( char* start )
1019 char* lpchX, *lpch;
1021 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1023 if( *lpchX == ',' )
1025 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1026 while( *(++lpchX) )
1027 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1029 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1030 else lpch = NULL;
1032 if( lpch ) *lpch = '\0';
1033 return NULL;
1036 /********************* API functions **********************************/
1038 /***********************************************************************
1039 * GetProfileInt16 (KERNEL.57)
1041 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1043 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1047 /***********************************************************************
1048 * GetProfileIntA (KERNEL32.264)
1050 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1052 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1055 /***********************************************************************
1056 * GetProfileIntW (KERNEL32.264)
1058 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1060 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1063 /***********************************************************************
1064 * GetProfileString16 (KERNEL.58)
1066 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1067 LPSTR buffer, UINT16 len )
1069 return GetPrivateProfileString16( section, entry, def_val,
1070 buffer, len, "win.ini" );
1073 /***********************************************************************
1074 * GetProfileStringA (KERNEL32.268)
1076 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1077 LPSTR buffer, UINT len )
1079 return GetPrivateProfileStringA( section, entry, def_val,
1080 buffer, len, "win.ini" );
1083 /***********************************************************************
1084 * GetProfileStringW (KERNEL32.269)
1086 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1087 LPCWSTR def_val, LPWSTR buffer, UINT len )
1089 return GetPrivateProfileStringW( section, entry, def_val,
1090 buffer, len, wininiW );
1093 /***********************************************************************
1094 * WriteProfileString16 (KERNEL.59)
1096 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1097 LPCSTR string )
1099 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1102 /***********************************************************************
1103 * WriteProfileStringA (KERNEL32.587)
1105 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1106 LPCSTR string )
1108 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1111 /***********************************************************************
1112 * WriteProfileStringW (KERNEL32.588)
1114 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1115 LPCWSTR string )
1117 return WritePrivateProfileStringW( section, entry, string, wininiW );
1121 /***********************************************************************
1122 * GetPrivateProfileInt16 (KERNEL.127)
1124 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1125 INT16 def_val, LPCSTR filename )
1127 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1129 if (result > 65535) return 65535;
1130 if (result >= 0) return (UINT16)result;
1131 if (result < -32768) return -32768;
1132 return (UINT16)(INT16)result;
1135 /***********************************************************************
1136 * GetPrivateProfileIntA (KERNEL32.251)
1138 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1139 INT def_val, LPCSTR filename )
1141 char buffer[20];
1142 char *p;
1143 long result;
1145 GetPrivateProfileStringA( section, entry, "",
1146 buffer, sizeof(buffer), filename );
1147 if (!buffer[0]) return (UINT)def_val;
1148 result = strtol( buffer, &p, 0 );
1149 if (p == buffer) return 0; /* No digits at all */
1150 return (UINT)result;
1153 /***********************************************************************
1154 * GetPrivateProfileIntW (KERNEL32.252)
1156 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1157 INT def_val, LPCWSTR filename )
1159 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1160 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1161 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1162 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1163 HeapFree( GetProcessHeap(), 0, sectionA );
1164 HeapFree( GetProcessHeap(), 0, filenameA );
1165 HeapFree( GetProcessHeap(), 0, entryA );
1166 return res;
1169 /***********************************************************************
1170 * GetPrivateProfileString16 (KERNEL.128)
1172 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1173 LPCSTR def_val, LPSTR buffer,
1174 UINT16 len, LPCSTR filename )
1176 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1179 /***********************************************************************
1180 * GetPrivateProfileStringA (KERNEL32.255)
1182 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1183 LPCSTR def_val, LPSTR buffer,
1184 UINT len, LPCSTR filename )
1186 int ret;
1188 if (!filename)
1189 filename = "win.ini";
1191 EnterCriticalSection( &PROFILE_CritSect );
1193 if (PROFILE_Open( filename )) {
1194 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1195 } else {
1196 lstrcpynA( buffer, def_val, len );
1197 ret = strlen( buffer );
1200 LeaveCriticalSection( &PROFILE_CritSect );
1202 return ret;
1205 /***********************************************************************
1206 * GetPrivateProfileStringW (KERNEL32.256)
1208 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1209 LPCWSTR def_val, LPWSTR buffer,
1210 UINT len, LPCWSTR filename )
1212 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1213 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1214 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1215 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1216 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1217 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1218 bufferA, len, filenameA );
1219 lstrcpynAtoW( buffer, bufferA, len );
1220 HeapFree( GetProcessHeap(), 0, sectionA );
1221 HeapFree( GetProcessHeap(), 0, entryA );
1222 HeapFree( GetProcessHeap(), 0, filenameA );
1223 HeapFree( GetProcessHeap(), 0, def_valA );
1224 HeapFree( GetProcessHeap(), 0, bufferA);
1225 return ret;
1228 /***********************************************************************
1229 * GetPrivateProfileSection16 (KERNEL.418)
1231 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1232 UINT16 len, LPCSTR filename )
1234 return GetPrivateProfileSectionA( section, buffer, len, filename );
1237 /***********************************************************************
1238 * GetPrivateProfileSectionA (KERNEL32.255)
1240 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1241 DWORD len, LPCSTR filename )
1243 int ret = 0;
1245 EnterCriticalSection( &PROFILE_CritSect );
1247 if (PROFILE_Open( filename ))
1248 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1249 FALSE, TRUE);
1251 LeaveCriticalSection( &PROFILE_CritSect );
1253 return ret;
1256 /***********************************************************************
1257 * GetPrivateProfileSectionW (KERNEL32.256)
1260 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1261 DWORD len, LPCWSTR filename )
1264 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1265 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1266 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1267 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1268 filenameA );
1269 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1270 HeapFree( GetProcessHeap(), 0, sectionA );
1271 HeapFree( GetProcessHeap(), 0, filenameA );
1272 HeapFree( GetProcessHeap(), 0, bufferA);
1273 return ret;
1276 /***********************************************************************
1277 * GetProfileSection16 (KERNEL.419)
1279 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1281 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1284 /***********************************************************************
1285 * GetProfileSectionA (KERNEL32.268)
1287 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1289 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1292 /***********************************************************************
1293 * GetProfileSectionW (KERNEL32)
1295 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1297 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1301 /***********************************************************************
1302 * WritePrivateProfileString16 (KERNEL.129)
1304 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1305 LPCSTR string, LPCSTR filename )
1307 return WritePrivateProfileStringA(section,entry,string,filename);
1310 /***********************************************************************
1311 * WritePrivateProfileStringA (KERNEL32.582)
1313 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1314 LPCSTR string, LPCSTR filename )
1316 BOOL ret = FALSE;
1318 EnterCriticalSection( &PROFILE_CritSect );
1320 if (PROFILE_Open( filename ))
1322 if (!section && !entry && !string)
1323 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1324 else
1325 ret = PROFILE_SetString( section, entry, string );
1328 LeaveCriticalSection( &PROFILE_CritSect );
1329 return ret;
1332 /***********************************************************************
1333 * WritePrivateProfileStringW (KERNEL32.583)
1335 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1336 LPCWSTR string, LPCWSTR filename )
1338 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1339 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1340 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1341 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1342 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1343 stringA, filenameA );
1344 HeapFree( GetProcessHeap(), 0, sectionA );
1345 HeapFree( GetProcessHeap(), 0, entryA );
1346 HeapFree( GetProcessHeap(), 0, stringA );
1347 HeapFree( GetProcessHeap(), 0, filenameA );
1348 return res;
1351 /***********************************************************************
1352 * WritePrivateProfileSection16 (KERNEL.416)
1354 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1355 LPCSTR string, LPCSTR filename )
1357 return WritePrivateProfileSectionA( section, string, filename );
1360 /***********************************************************************
1361 * WritePrivateProfileSectionA (KERNEL32)
1363 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1364 LPCSTR string, LPCSTR filename )
1366 BOOL ret = FALSE;
1367 LPSTR p ;
1369 EnterCriticalSection( &PROFILE_CritSect );
1371 if (PROFILE_Open( filename )) {
1372 if (!section && !string && !filename)
1373 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1374 else {
1375 while(*string){
1376 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1377 if((p=strchr( buf, '='))){
1378 *p='\0';
1379 ret = PROFILE_SetString( section, buf, p+1 );
1382 HeapFree( GetProcessHeap(), 0, buf );
1383 string += strlen(string)+1;
1389 LeaveCriticalSection( &PROFILE_CritSect );
1390 return ret;
1393 /***********************************************************************
1394 * WritePrivateProfileSectionW (KERNEL32)
1396 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1397 LPCWSTR string, LPCWSTR filename)
1400 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1401 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1402 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1403 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1404 HeapFree( GetProcessHeap(), 0, sectionA );
1405 HeapFree( GetProcessHeap(), 0, stringA );
1406 HeapFree( GetProcessHeap(), 0, filenameA );
1407 return res;
1410 /***********************************************************************
1411 * WriteProfileSection16 (KERNEL.417)
1413 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1415 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1418 /***********************************************************************
1419 * WriteProfileSectionA (KERNEL32.747)
1421 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1424 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1427 /***********************************************************************
1428 * WriteProfileSectionW (KERNEL32.748)
1430 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1432 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1435 /***********************************************************************
1436 * GetPrivateProfileSectionNames16 (KERNEL.143)
1438 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1439 LPCSTR filename )
1441 WORD ret = 0;
1443 EnterCriticalSection( &PROFILE_CritSect );
1445 if (PROFILE_Open( filename ))
1446 ret = PROFILE_GetSectionNames(buffer, size);
1448 LeaveCriticalSection( &PROFILE_CritSect );
1450 return ret;
1454 /***********************************************************************
1455 * GetProfileSectionNames16 (KERNEL.142)
1457 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1460 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1464 /***********************************************************************
1465 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1467 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1468 LPCSTR filename)
1471 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1475 /***********************************************************************
1476 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1478 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1479 LPCWSTR filename)
1482 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1483 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1485 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1486 lstrcpynAtoW( buffer, bufferA, size);
1487 HeapFree( GetProcessHeap(), 0, bufferA);
1488 HeapFree( GetProcessHeap(), 0, filenameA );
1490 return ret;
1493 /***********************************************************************
1494 * GetPrivateProfileStruct16 (KERNEL.407)
1496 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1497 LPVOID buf, UINT16 len, LPCSTR filename)
1499 return GetPrivateProfileStructA( section, key, buf, len, filename );
1502 /***********************************************************************
1503 * GetPrivateProfileStructA (KERNEL32.370)
1505 * Should match Win95's behaviour pretty much
1507 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1508 LPVOID buf, UINT len, LPCSTR filename)
1510 BOOL ret = FALSE;
1512 EnterCriticalSection( &PROFILE_CritSect );
1514 if (PROFILE_Open( filename )) {
1515 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1516 if (k) {
1517 TRACE("value (at %p): '%s'\n", k->value, k->value);
1518 if (((strlen(k->value) - 2) / 2) == len)
1520 LPSTR end, p;
1521 BOOL valid = TRUE;
1522 CHAR c;
1523 DWORD chksum = 0;
1525 end = k->value + strlen(k->value); /* -> '\0' */
1526 /* check for invalid chars in ASCII coded hex string */
1527 for (p=k->value; p < end; p++)
1529 if (!isxdigit(*p))
1531 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1532 *p, filename, section, key);
1533 valid = FALSE;
1534 break;
1537 if (valid)
1539 BOOL highnibble = TRUE;
1540 BYTE b = 0, val;
1541 LPBYTE binbuf = (LPBYTE)buf;
1543 end -= 2; /* don't include checksum in output data */
1544 /* translate ASCII hex format into binary data */
1545 for (p=k->value; p < end; p++)
1547 c = toupper(*p);
1548 val = (c > '9') ?
1549 (c - 'A' + 10) : (c - '0');
1551 if (highnibble)
1552 b = val << 4;
1553 else
1555 b += val;
1556 *binbuf++ = b; /* feed binary data into output */
1557 chksum += b; /* calculate checksum */
1559 highnibble ^= 1; /* toggle */
1561 /* retrieve stored checksum value */
1562 c = toupper(*p++);
1563 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1564 c = toupper(*p);
1565 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1566 if (b == (chksum & 0xff)) /* checksums match ? */
1567 ret = TRUE;
1572 LeaveCriticalSection( &PROFILE_CritSect );
1574 return ret;
1577 /***********************************************************************
1578 * GetPrivateProfileStructW (KERNEL32.543)
1580 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1581 LPVOID buffer, UINT len, LPCWSTR filename)
1583 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1584 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1585 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1586 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1588 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1589 len, filenameA );
1590 lstrcpynAtoW( buffer, bufferA, len );
1591 HeapFree( GetProcessHeap(), 0, bufferA);
1592 HeapFree( GetProcessHeap(), 0, sectionA );
1593 HeapFree( GetProcessHeap(), 0, keyA );
1594 HeapFree( GetProcessHeap(), 0, filenameA );
1596 return ret;
1601 /***********************************************************************
1602 * WritePrivateProfileStruct16 (KERNEL.406)
1604 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1605 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1607 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1610 /***********************************************************************
1611 * WritePrivateProfileStructA (KERNEL32.744)
1613 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1614 LPVOID buf, UINT bufsize, LPCSTR filename)
1616 BOOL ret = FALSE;
1617 LPBYTE binbuf;
1618 LPSTR outstring, p;
1619 DWORD sum = 0;
1621 if (!section && !key && !buf) /* flush the cache */
1622 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1624 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1625 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1626 p = outstring;
1627 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1628 *p++ = hex[*binbuf >> 4];
1629 *p++ = hex[*binbuf & 0xf];
1630 sum += *binbuf;
1632 /* checksum is sum & 0xff */
1633 *p++ = hex[(sum & 0xf0) >> 4];
1634 *p++ = hex[sum & 0xf];
1635 *p++ = '\0';
1637 EnterCriticalSection( &PROFILE_CritSect );
1639 if (PROFILE_Open( filename ))
1640 ret = PROFILE_SetString( section, key, outstring );
1642 LeaveCriticalSection( &PROFILE_CritSect );
1644 HeapFree( GetProcessHeap(), 0, outstring );
1646 return ret;
1649 /***********************************************************************
1650 * WritePrivateProfileStructW (KERNEL32.544)
1652 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1653 LPVOID buf, UINT bufsize, LPCWSTR filename)
1655 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1656 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1657 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1658 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1659 filenameA );
1660 HeapFree( GetProcessHeap(), 0, sectionA );
1661 HeapFree( GetProcessHeap(), 0, keyA );
1662 HeapFree( GetProcessHeap(), 0, filenameA );
1664 return ret;
1668 /***********************************************************************
1669 * WriteOutProfiles (KERNEL.315)
1671 void WINAPI WriteOutProfiles16(void)
1673 EnterCriticalSection( &PROFILE_CritSect );
1674 PROFILE_FlushFile();
1675 LeaveCriticalSection( &PROFILE_CritSect );
1678 /***********************************************************************
1679 * CloseProfileUserMapping (KERNEL.138)
1681 BOOL WINAPI CloseProfileUserMapping(void) {
1682 FIXME("(), stub!\n");
1683 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1684 return FALSE;