Serge Ivanov
[wine.git] / files / profile.c
blob764441310c45f08b44837672cd1229673c9f118c
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 = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
206 if(first_section == NULL) return NULL;
207 first_section->name = NULL;
208 first_section->key = NULL;
209 first_section->next = NULL;
210 next_section = &first_section->next;
211 next_key = &first_section->key;
212 prev_key = NULL;
214 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
216 line++;
217 p = buffer;
218 while (*p && PROFILE_isspace(*p)) p++;
219 if (*p == '[') /* section start */
221 if (!(p2 = strrchr( p, ']' )))
223 WARN("Invalid section header at line %d: '%s'\n",
224 line, p );
226 else
228 *p2 = '\0';
229 p++;
230 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
231 if(section == NULL) break;
232 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
233 section->key = NULL;
234 section->next = NULL;
235 *next_section = section;
236 next_section = &section->next;
237 next_key = &section->key;
238 prev_key = NULL;
240 TRACE("New section: '%s'\n",section->name);
242 continue;
246 p2=p+strlen(p) - 1;
247 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
249 if ((p2 = strchr( p, '=' )) != NULL)
251 char *p3 = p2 - 1;
252 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
253 *p2++ = '\0';
254 while (*p2 && PROFILE_isspace(*p2)) p2++;
257 if(*p || !prev_key || *prev_key->name)
259 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
260 if(key == NULL) break;
261 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
262 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
263 key->next = NULL;
264 *next_key = key;
265 next_key = &key->next;
266 prev_key = key;
268 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
271 return first_section;
275 /***********************************************************************
276 * PROFILE_RegistryLoad
278 * Load a profile tree from a file into a registry key.
280 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
282 HKEY hkey = 0;
283 DWORD err = 0;
284 char buffer[PROFILE_MAX_LINE_LEN];
285 char *p, *p2;
286 int line = 0;
288 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
290 line++;
291 p = buffer;
292 while (*p && PROFILE_isspace(*p)) p++;
293 if (*p == '[') /* section start */
295 if (!(p2 = strrchr( p, ']' )))
297 WARN("Invalid section header at line %d: '%s'\n",
298 line, p );
300 else
302 *p2 = '\0';
303 p++;
304 if (hkey) RegCloseKey( hkey );
305 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
306 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
307 TRACE("New section: '%s'\n",p);
308 continue;
312 p2=p+strlen(p) - 1;
313 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
315 if ((p2 = strchr( p, '=' )) != NULL)
317 char *p3 = p2 - 1;
318 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
319 *p2++ = '\0';
320 while (*p2 && PROFILE_isspace(*p2)) p2++;
323 if (*p && hkey && !IS_ENTRY_COMMENT(p))
325 if (!p2) p2 = "";
326 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
328 RegCloseKey( hkey );
329 return err;
331 TRACE("New key: name='%s', value='%s'\n",p,p2);
334 if (hkey) RegCloseKey( hkey );
335 return 0;
339 /***********************************************************************
340 * PROFILE_DeleteSection
342 * Delete a section from a profile tree.
344 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
346 while (*section)
348 if ((*section)->name && !strcasecmp( (*section)->name, name ))
350 PROFILESECTION *to_del = *section;
351 *section = to_del->next;
352 to_del->next = NULL;
353 PROFILE_Free( to_del );
354 return TRUE;
356 section = &(*section)->next;
358 return FALSE;
362 /***********************************************************************
363 * PROFILE_DeleteKey
365 * Delete a key from a profile tree.
367 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
368 LPCSTR section_name, LPCSTR key_name )
370 while (*section)
372 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
374 PROFILEKEY **key = &(*section)->key;
375 while (*key)
377 if (!strcasecmp( (*key)->name, key_name ))
379 PROFILEKEY *to_del = *key;
380 *key = to_del->next;
381 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
382 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
383 HeapFree( GetProcessHeap(), 0, to_del );
384 return TRUE;
386 key = &(*key)->next;
389 section = &(*section)->next;
391 return FALSE;
395 /***********************************************************************
396 * PROFILE_Find
398 * Find a key in a profile tree, optionally creating it.
400 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
401 const char *section_name,
402 const char *key_name, int create )
404 const char *p;
405 int seclen, keylen;
407 while (PROFILE_isspace(*section_name)) section_name++;
408 p = section_name + strlen(section_name) - 1;
409 while ((p > section_name) && PROFILE_isspace(*p)) p--;
410 seclen = p - section_name + 1;
412 while (PROFILE_isspace(*key_name)) key_name++;
413 p = key_name + strlen(key_name) - 1;
414 while ((p > key_name) && PROFILE_isspace(*p)) p--;
415 keylen = p - key_name + 1;
417 while (*section)
419 if ( ((*section)->name)
420 && (!(strncasecmp( (*section)->name, section_name, seclen )))
421 && (((*section)->name)[seclen] == '\0') )
423 PROFILEKEY **key = &(*section)->key;
424 while (*key)
426 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
427 && (((*key)->name)[keylen] == '\0') )
428 return *key;
429 key = &(*key)->next;
431 if (!create) return NULL;
432 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
433 if(*key == NULL) return NULL;
434 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
435 (*key)->value = NULL;
436 (*key)->next = NULL;
437 return *key;
439 section = &(*section)->next;
441 if (!create) return NULL;
442 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
443 if(*section == NULL) return NULL;
444 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
445 (*section)->next = NULL;
446 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
447 if((*section)->key == NULL)
449 HeapFree(GetProcessHeap(), 0, *section);
450 return NULL;
452 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
453 (*section)->key->value = NULL;
454 (*section)->key->next = NULL;
455 return (*section)->key;
459 /***********************************************************************
460 * PROFILE_FlushFile
462 * Flush the current profile to disk if changed.
464 static BOOL PROFILE_FlushFile(void)
466 char *p, buffer[MAX_PATHNAME_LEN];
467 const char *unix_name;
468 FILE *file = NULL;
469 struct stat buf;
471 if(!CurProfile)
473 WARN("No current profile!\n");
474 return FALSE;
477 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
478 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
480 /* Try to create it in $HOME/.wine */
481 /* FIXME: this will need a more general solution */
482 strcpy( buffer, get_config_dir() );
483 p = buffer + strlen(buffer);
484 *p++ = '/';
485 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
486 CharLowerA( p );
487 file = fopen( buffer, "w" );
488 unix_name = buffer;
491 if (!file)
493 WARN("could not save profile file %s\n", CurProfile->dos_name);
494 return FALSE;
497 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
498 PROFILE_Save( file, CurProfile->section );
499 fclose( file );
500 CurProfile->changed = FALSE;
501 if(!stat(unix_name,&buf))
502 CurProfile->mtime=buf.st_mtime;
503 return TRUE;
507 /***********************************************************************
508 * PROFILE_ReleaseFile
510 * Flush the current profile to disk and remove it from the cache.
512 static void PROFILE_ReleaseFile(void)
514 PROFILE_FlushFile();
515 PROFILE_Free( CurProfile->section );
516 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
517 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
518 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
519 CurProfile->changed = FALSE;
520 CurProfile->section = NULL;
521 CurProfile->dos_name = NULL;
522 CurProfile->unix_name = NULL;
523 CurProfile->filename = NULL;
524 CurProfile->mtime = 0;
528 /***********************************************************************
529 * PROFILE_Open
531 * Open a profile file, checking the cached file first.
533 static BOOL PROFILE_Open( LPCSTR filename )
535 DOS_FULL_NAME full_name;
536 char buffer[MAX_PATHNAME_LEN];
537 char *newdos_name, *p;
538 FILE *file = NULL;
539 int i,j;
540 struct stat buf;
541 PROFILE *tempProfile;
543 /* First time around */
545 if(!CurProfile)
546 for(i=0;i<N_CACHED_PROFILES;i++)
548 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
549 if(MRUProfile[i] == NULL) break;
550 MRUProfile[i]->changed=FALSE;
551 MRUProfile[i]->section=NULL;
552 MRUProfile[i]->dos_name=NULL;
553 MRUProfile[i]->unix_name=NULL;
554 MRUProfile[i]->filename=NULL;
555 MRUProfile[i]->mtime=0;
558 /* Check for a match */
560 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
561 strchr( filename, ':' ))
563 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
565 else
567 GetWindowsDirectoryA( buffer, sizeof(buffer) );
568 strcat( buffer, "\\" );
569 strcat( buffer, filename );
570 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
573 for(i=0;i<N_CACHED_PROFILES;i++)
575 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
576 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
578 if(i)
580 PROFILE_FlushFile();
581 tempProfile=MRUProfile[i];
582 for(j=i;j>0;j--)
583 MRUProfile[j]=MRUProfile[j-1];
584 CurProfile=tempProfile;
586 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
587 TRACE("(%s): already opened (mru=%d)\n",
588 filename, i );
589 else
590 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
591 filename, i );
592 return TRUE;
596 /* Flush the old current profile */
597 PROFILE_FlushFile();
599 /* Make the oldest profile the current one only in order to get rid of it */
600 if(i==N_CACHED_PROFILES)
602 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
603 for(i=N_CACHED_PROFILES-1;i>0;i--)
604 MRUProfile[i]=MRUProfile[i-1];
605 CurProfile=tempProfile;
607 if(CurProfile->filename) PROFILE_ReleaseFile();
609 /* OK, now that CurProfile is definitely free we assign it our new file */
610 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
611 CurProfile->dos_name = newdos_name;
612 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
614 /* Try to open the profile file, first in $HOME/.wine */
616 /* FIXME: this will need a more general solution */
617 strcpy( buffer, get_config_dir() );
618 p = buffer + strlen(buffer);
619 *p++ = '/';
620 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
621 CharLowerA( p );
622 if ((file = fopen( buffer, "r" )))
624 TRACE("(%s): found it in %s\n",
625 filename, buffer );
626 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
629 if (!file)
631 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
632 full_name.long_name );
633 if ((file = fopen( full_name.long_name, "r" )))
634 TRACE("(%s): found it in %s\n",
635 filename, full_name.long_name );
638 if (file)
640 CurProfile->section = PROFILE_Load( file );
641 fclose( file );
642 if(!stat(CurProfile->unix_name,&buf))
643 CurProfile->mtime=buf.st_mtime;
645 else
647 /* Does not exist yet, we will create it in PROFILE_FlushFile */
648 WARN("profile file %s not found\n", newdos_name );
650 return TRUE;
654 /***********************************************************************
655 * PROFILE_GetSection
657 * Returns all keys of a section.
658 * If return_values is TRUE, also include the corresponding values.
660 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
661 LPSTR buffer, UINT len, BOOL handle_env,
662 BOOL return_values )
664 PROFILEKEY *key;
665 while (section)
667 if (section->name && !strcasecmp( section->name, section_name ))
669 UINT oldlen = len;
670 for (key = section->key; key; key = key->next)
672 if (len <= 2) break;
673 if (!*key->name) continue; /* Skip empty lines */
674 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
675 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
676 len -= strlen(buffer) + 1;
677 buffer += strlen(buffer) + 1;
678 if (return_values && key->value) {
679 buffer[-1] = '=';
680 PROFILE_CopyEntry ( buffer,
681 key->value, len - 1, handle_env );
682 len -= strlen(buffer) + 1;
683 buffer += strlen(buffer) + 1;
686 *buffer = '\0';
687 if (len <= 1)
688 /*If either lpszSection or lpszKey is NULL and the supplied
689 destination buffer is too small to hold all the strings,
690 the last string is truncated and followed by two null characters.
691 In this case, the return value is equal to cchReturnBuffer
692 minus two. */
694 buffer[-1] = '\0';
695 return oldlen - 2;
697 return oldlen - len;
699 section = section->next;
701 buffer[0] = buffer[1] = '\0';
702 return 0;
706 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
708 LPSTR buf = buffer;
709 WORD l, cursize = 0;
710 PROFILESECTION *section;
712 for (section = CurProfile->section; section; section = section->next)
713 if (section->name) {
714 l = strlen(section->name);
715 cursize += l+1;
716 if (cursize > len+1)
717 return len-2;
719 strcpy(buf, section->name);
720 buf += l+1;
723 *buf=0;
724 buf++;
725 return buf-buffer;
729 /***********************************************************************
730 * PROFILE_GetString
732 * Get a profile string.
734 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
735 LPCSTR def_val, LPSTR buffer, UINT len )
737 PROFILEKEY *key = NULL;
739 if (!def_val) def_val = "";
740 if (key_name && key_name[0])
742 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
743 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
744 len, FALSE );
745 TRACE("('%s','%s','%s'): returning '%s'\n",
746 section, key_name, def_val, buffer );
747 return strlen( buffer );
749 if (key_name && !(key_name[0]))
750 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
751 return 0;
752 if (section && section[0])
753 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
754 FALSE, FALSE);
755 /* undocumented; both section and key_name are NULL */
756 return PROFILE_GetSectionNames(buffer, len);
760 /***********************************************************************
761 * PROFILE_SetString
763 * Set a profile string.
765 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
766 LPCSTR value )
768 if (!key_name) /* Delete a whole section */
770 TRACE("('%s')\n", section_name);
771 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
772 section_name );
773 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
774 this is not an error on application's level.*/
776 else if (!value) /* Delete a key */
778 TRACE("('%s','%s')\n",
779 section_name, key_name );
780 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
781 section_name, key_name );
782 return TRUE; /* same error handling as above */
784 else /* Set the key value */
786 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
787 key_name, TRUE );
788 TRACE("('%s','%s','%s'): \n",
789 section_name, key_name, value );
790 if (!key) return FALSE;
791 if (key->value)
793 if (!strcmp( key->value, value ))
795 TRACE(" no change needed\n" );
796 return TRUE; /* No change needed */
798 TRACE(" replacing '%s'\n", key->value );
799 HeapFree( GetProcessHeap(), 0, key->value );
801 else TRACE(" creating key\n" );
802 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
803 CurProfile->changed = TRUE;
805 return TRUE;
809 /***********************************************************************
810 * PROFILE_GetWineIniString
812 * Get a config string from the wine.ini file.
814 int PROFILE_GetWineIniString( const char *section, const char *key_name,
815 const char *def, char *buffer, int len )
817 char tmp[PROFILE_MAX_LINE_LEN];
818 HKEY hkey;
819 DWORD err;
821 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
823 DWORD type;
824 DWORD count = sizeof(tmp);
825 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
826 RegCloseKey( hkey );
828 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
829 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
830 return strlen(buffer);
834 /***********************************************************************
835 * PROFILE_EnumWineIniString
837 * Get a config string from the wine.ini file.
839 BOOL PROFILE_EnumWineIniString( const char *section, int index,
840 char *name, int name_len, char *buffer, int len )
842 char tmp[PROFILE_MAX_LINE_LEN];
843 HKEY hkey;
844 DWORD err, type;
845 DWORD count = sizeof(tmp);
847 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
848 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
849 RegCloseKey( hkey );
850 if (!err)
852 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
853 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
855 return !err;
859 /***********************************************************************
860 * PROFILE_GetWineIniInt
862 * Get a config integer from the wine.ini file.
864 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
866 char buffer[20];
867 char *p;
868 long result;
870 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
871 if (!buffer[0]) return def;
872 result = strtol( buffer, &p, 0 );
873 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
877 /******************************************************************************
879 * int PROFILE_GetWineIniBool(
880 * char const *section,
881 * char const *key_name,
882 * int def )
884 * Reads a boolean value from the wine.ini file. This function attempts to
885 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
886 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
887 * true. Anything else results in the return of the default value.
889 * This function uses 1 to indicate true, and 0 for false. You can check
890 * for existence by setting def to something other than 0 or 1 and
891 * examining the return value.
893 int PROFILE_GetWineIniBool(
894 char const *section,
895 char const *key_name,
896 int def )
898 char key_value[2];
899 int retval;
901 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
903 switch(key_value[0]) {
904 case 'n':
905 case 'N':
906 case 'f':
907 case 'F':
908 case '0':
909 retval = 0;
910 break;
912 case 'y':
913 case 'Y':
914 case 't':
915 case 'T':
916 case '1':
917 retval = 1;
918 break;
920 default:
921 retval = def;
924 TRACE("(\"%s\", \"%s\", %s), "
925 "[%c], ret %s.\n", section, key_name,
926 def ? "TRUE" : "FALSE", key_value[0],
927 retval ? "TRUE" : "FALSE");
929 return retval;
933 /***********************************************************************
934 * PROFILE_LoadWineIni
936 * Load the wine.ini file.
938 int PROFILE_LoadWineIni(void)
940 char buffer[MAX_PATHNAME_LEN];
941 const char *p;
942 FILE *f;
943 HKEY hKeySW;
945 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
946 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
948 ERR("Cannot create config registry key\n" );
949 return 0;
951 RegCloseKey( hKeySW );
952 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
953 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, NULL ))
955 ERR("Cannot create config registry key\n" );
956 return 0;
959 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
961 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
963 /* Open -config specified file */
964 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
965 goto found;
968 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
970 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
971 goto found;
973 if ((p = getenv( "HOME" )) != NULL)
975 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
976 strcat( buffer, PROFILE_WineIniName );
977 if ((f = fopen( buffer, "r" )) != NULL)
979 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
980 goto found;
983 else WARN("could not get $HOME value for config file.\n" );
985 /* Try global file */
987 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
989 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
990 goto found;
992 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
993 WINE_INI_GLOBAL, PROFILE_WineIniName );
994 return 0;
996 found:
997 PROFILE_RegistryLoad( wine_profile_key, f );
998 fclose( f );
999 return 1;
1003 /***********************************************************************
1004 * PROFILE_UsageWineIni
1006 * Explain the wine.ini file to those who don't read documentation.
1007 * Keep below one screenful in length so that error messages above are
1008 * noticed.
1010 void PROFILE_UsageWineIni(void)
1012 MESSAGE("Perhaps you have not properly edited or created "
1013 "your Wine configuration file.\n");
1014 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1015 MESSAGE(" or it is determined by the -config option or from\n"
1016 " the WINE_INI environment variable.\n");
1017 if (*PROFILE_WineIniUsed)
1018 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1019 /* RTFM, so to say */
1022 /***********************************************************************
1023 * PROFILE_GetStringItem
1025 * Convenience function that turns a string 'xxx, yyy, zzz' into
1026 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1028 char* PROFILE_GetStringItem( char* start )
1030 char* lpchX, *lpch;
1032 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1034 if( *lpchX == ',' )
1036 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1037 while( *(++lpchX) )
1038 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1040 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1041 else lpch = NULL;
1043 if( lpch ) *lpch = '\0';
1044 return NULL;
1047 /********************* API functions **********************************/
1049 /***********************************************************************
1050 * GetProfileInt16 (KERNEL.57)
1052 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1054 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1058 /***********************************************************************
1059 * GetProfileIntA (KERNEL32.264)
1061 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1063 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1066 /***********************************************************************
1067 * GetProfileIntW (KERNEL32.264)
1069 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1071 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1074 /***********************************************************************
1075 * GetProfileString16 (KERNEL.58)
1077 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1078 LPSTR buffer, UINT16 len )
1080 return GetPrivateProfileString16( section, entry, def_val,
1081 buffer, len, "win.ini" );
1084 /***********************************************************************
1085 * GetProfileStringA (KERNEL32.268)
1087 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1088 LPSTR buffer, UINT len )
1090 return GetPrivateProfileStringA( section, entry, def_val,
1091 buffer, len, "win.ini" );
1094 /***********************************************************************
1095 * GetProfileStringW (KERNEL32.269)
1097 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1098 LPCWSTR def_val, LPWSTR buffer, UINT len )
1100 return GetPrivateProfileStringW( section, entry, def_val,
1101 buffer, len, wininiW );
1104 /***********************************************************************
1105 * WriteProfileString16 (KERNEL.59)
1107 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1108 LPCSTR string )
1110 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1113 /***********************************************************************
1114 * WriteProfileStringA (KERNEL32.587)
1116 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1117 LPCSTR string )
1119 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1122 /***********************************************************************
1123 * WriteProfileStringW (KERNEL32.588)
1125 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1126 LPCWSTR string )
1128 return WritePrivateProfileStringW( section, entry, string, wininiW );
1132 /***********************************************************************
1133 * GetPrivateProfileInt16 (KERNEL.127)
1135 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1136 INT16 def_val, LPCSTR filename )
1138 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1140 if (result > 65535) return 65535;
1141 if (result >= 0) return (UINT16)result;
1142 if (result < -32768) return -32768;
1143 return (UINT16)(INT16)result;
1146 /***********************************************************************
1147 * GetPrivateProfileIntA (KERNEL32.251)
1149 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1150 INT def_val, LPCSTR filename )
1152 char buffer[20];
1153 char *p;
1154 long result;
1156 GetPrivateProfileStringA( section, entry, "",
1157 buffer, sizeof(buffer), filename );
1158 if (!buffer[0]) return (UINT)def_val;
1159 result = strtol( buffer, &p, 0 );
1160 if (p == buffer) return 0; /* No digits at all */
1161 return (UINT)result;
1164 /***********************************************************************
1165 * GetPrivateProfileIntW (KERNEL32.252)
1167 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1168 INT def_val, LPCWSTR filename )
1170 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1171 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1172 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1173 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1174 HeapFree( GetProcessHeap(), 0, sectionA );
1175 HeapFree( GetProcessHeap(), 0, filenameA );
1176 HeapFree( GetProcessHeap(), 0, entryA );
1177 return res;
1180 /***********************************************************************
1181 * GetPrivateProfileString16 (KERNEL.128)
1183 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1184 LPCSTR def_val, LPSTR buffer,
1185 UINT16 len, LPCSTR filename )
1187 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1190 /***********************************************************************
1191 * GetPrivateProfileStringA (KERNEL32.255)
1193 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1194 LPCSTR def_val, LPSTR buffer,
1195 UINT len, LPCSTR filename )
1197 int ret;
1199 if (!filename)
1200 filename = "win.ini";
1202 EnterCriticalSection( &PROFILE_CritSect );
1204 if (PROFILE_Open( filename )) {
1205 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1206 } else {
1207 lstrcpynA( buffer, def_val, len );
1208 ret = strlen( buffer );
1211 LeaveCriticalSection( &PROFILE_CritSect );
1213 return ret;
1216 /***********************************************************************
1217 * GetPrivateProfileStringW (KERNEL32.256)
1219 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1220 LPCWSTR def_val, LPWSTR buffer,
1221 UINT len, LPCWSTR filename )
1223 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1224 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1225 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1226 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1227 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1228 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1229 bufferA, len, filenameA );
1230 lstrcpynAtoW( buffer, bufferA, len );
1231 HeapFree( GetProcessHeap(), 0, sectionA );
1232 HeapFree( GetProcessHeap(), 0, entryA );
1233 HeapFree( GetProcessHeap(), 0, filenameA );
1234 HeapFree( GetProcessHeap(), 0, def_valA );
1235 HeapFree( GetProcessHeap(), 0, bufferA);
1236 return ret;
1239 /***********************************************************************
1240 * GetPrivateProfileSection16 (KERNEL.418)
1242 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1243 UINT16 len, LPCSTR filename )
1245 return GetPrivateProfileSectionA( section, buffer, len, filename );
1248 /***********************************************************************
1249 * GetPrivateProfileSectionA (KERNEL32.255)
1251 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1252 DWORD len, LPCSTR filename )
1254 int ret = 0;
1256 EnterCriticalSection( &PROFILE_CritSect );
1258 if (PROFILE_Open( filename ))
1259 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1260 FALSE, TRUE);
1262 LeaveCriticalSection( &PROFILE_CritSect );
1264 return ret;
1267 /***********************************************************************
1268 * GetPrivateProfileSectionW (KERNEL32.256)
1271 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1272 DWORD len, LPCWSTR filename )
1275 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1276 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1277 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1278 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1279 filenameA );
1280 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1281 HeapFree( GetProcessHeap(), 0, sectionA );
1282 HeapFree( GetProcessHeap(), 0, filenameA );
1283 HeapFree( GetProcessHeap(), 0, bufferA);
1284 return ret;
1287 /***********************************************************************
1288 * GetProfileSection16 (KERNEL.419)
1290 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1292 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1295 /***********************************************************************
1296 * GetProfileSectionA (KERNEL32.268)
1298 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1300 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1303 /***********************************************************************
1304 * GetProfileSectionW (KERNEL32)
1306 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1308 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1312 /***********************************************************************
1313 * WritePrivateProfileString16 (KERNEL.129)
1315 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1316 LPCSTR string, LPCSTR filename )
1318 return WritePrivateProfileStringA(section,entry,string,filename);
1321 /***********************************************************************
1322 * WritePrivateProfileStringA (KERNEL32.582)
1324 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1325 LPCSTR string, LPCSTR filename )
1327 BOOL ret = FALSE;
1329 EnterCriticalSection( &PROFILE_CritSect );
1331 if (PROFILE_Open( filename ))
1333 if (!section && !entry && !string)
1334 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1335 else
1336 ret = PROFILE_SetString( section, entry, string );
1339 LeaveCriticalSection( &PROFILE_CritSect );
1340 return ret;
1343 /***********************************************************************
1344 * WritePrivateProfileStringW (KERNEL32.583)
1346 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1347 LPCWSTR string, LPCWSTR filename )
1349 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1350 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1351 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1352 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1353 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1354 stringA, filenameA );
1355 HeapFree( GetProcessHeap(), 0, sectionA );
1356 HeapFree( GetProcessHeap(), 0, entryA );
1357 HeapFree( GetProcessHeap(), 0, stringA );
1358 HeapFree( GetProcessHeap(), 0, filenameA );
1359 return res;
1362 /***********************************************************************
1363 * WritePrivateProfileSection16 (KERNEL.416)
1365 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1366 LPCSTR string, LPCSTR filename )
1368 return WritePrivateProfileSectionA( section, string, filename );
1371 /***********************************************************************
1372 * WritePrivateProfileSectionA (KERNEL32)
1374 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1375 LPCSTR string, LPCSTR filename )
1377 BOOL ret = FALSE;
1378 LPSTR p ;
1380 EnterCriticalSection( &PROFILE_CritSect );
1382 if (PROFILE_Open( filename )) {
1383 if (!section && !string && !filename)
1384 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1385 else {
1386 while(*string){
1387 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1388 if((p=strchr( buf, '='))){
1389 *p='\0';
1390 ret = PROFILE_SetString( section, buf, p+1 );
1393 HeapFree( GetProcessHeap(), 0, buf );
1394 string += strlen(string)+1;
1400 LeaveCriticalSection( &PROFILE_CritSect );
1401 return ret;
1404 /***********************************************************************
1405 * WritePrivateProfileSectionW (KERNEL32)
1407 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1408 LPCWSTR string, LPCWSTR filename)
1411 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1412 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1413 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1414 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1415 HeapFree( GetProcessHeap(), 0, sectionA );
1416 HeapFree( GetProcessHeap(), 0, stringA );
1417 HeapFree( GetProcessHeap(), 0, filenameA );
1418 return res;
1421 /***********************************************************************
1422 * WriteProfileSection16 (KERNEL.417)
1424 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1426 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1429 /***********************************************************************
1430 * WriteProfileSectionA (KERNEL32.747)
1432 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1435 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1438 /***********************************************************************
1439 * WriteProfileSectionW (KERNEL32.748)
1441 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1443 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1446 /***********************************************************************
1447 * GetPrivateProfileSectionNames16 (KERNEL.143)
1449 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1450 LPCSTR filename )
1452 WORD ret = 0;
1454 EnterCriticalSection( &PROFILE_CritSect );
1456 if (PROFILE_Open( filename ))
1457 ret = PROFILE_GetSectionNames(buffer, size);
1459 LeaveCriticalSection( &PROFILE_CritSect );
1461 return ret;
1465 /***********************************************************************
1466 * GetProfileSectionNames16 (KERNEL.142)
1468 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1471 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1475 /***********************************************************************
1476 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1478 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1479 LPCSTR filename)
1482 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1486 /***********************************************************************
1487 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1489 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1490 LPCWSTR filename)
1493 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1494 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1496 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1497 lstrcpynAtoW( buffer, bufferA, size);
1498 HeapFree( GetProcessHeap(), 0, bufferA);
1499 HeapFree( GetProcessHeap(), 0, filenameA );
1501 return ret;
1504 /***********************************************************************
1505 * GetPrivateProfileStruct16 (KERNEL.407)
1507 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1508 LPVOID buf, UINT16 len, LPCSTR filename)
1510 return GetPrivateProfileStructA( section, key, buf, len, filename );
1513 /***********************************************************************
1514 * GetPrivateProfileStructA (KERNEL32.370)
1516 * Should match Win95's behaviour pretty much
1518 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1519 LPVOID buf, UINT len, LPCSTR filename)
1521 BOOL ret = FALSE;
1523 EnterCriticalSection( &PROFILE_CritSect );
1525 if (PROFILE_Open( filename )) {
1526 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1527 if (k) {
1528 TRACE("value (at %p): '%s'\n", k->value, k->value);
1529 if (((strlen(k->value) - 2) / 2) == len)
1531 LPSTR end, p;
1532 BOOL valid = TRUE;
1533 CHAR c;
1534 DWORD chksum = 0;
1536 end = k->value + strlen(k->value); /* -> '\0' */
1537 /* check for invalid chars in ASCII coded hex string */
1538 for (p=k->value; p < end; p++)
1540 if (!isxdigit(*p))
1542 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1543 *p, filename, section, key);
1544 valid = FALSE;
1545 break;
1548 if (valid)
1550 BOOL highnibble = TRUE;
1551 BYTE b = 0, val;
1552 LPBYTE binbuf = (LPBYTE)buf;
1554 end -= 2; /* don't include checksum in output data */
1555 /* translate ASCII hex format into binary data */
1556 for (p=k->value; p < end; p++)
1558 c = toupper(*p);
1559 val = (c > '9') ?
1560 (c - 'A' + 10) : (c - '0');
1562 if (highnibble)
1563 b = val << 4;
1564 else
1566 b += val;
1567 *binbuf++ = b; /* feed binary data into output */
1568 chksum += b; /* calculate checksum */
1570 highnibble ^= 1; /* toggle */
1572 /* retrieve stored checksum value */
1573 c = toupper(*p++);
1574 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1575 c = toupper(*p);
1576 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1577 if (b == (chksum & 0xff)) /* checksums match ? */
1578 ret = TRUE;
1583 LeaveCriticalSection( &PROFILE_CritSect );
1585 return ret;
1588 /***********************************************************************
1589 * GetPrivateProfileStructW (KERNEL32.543)
1591 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1592 LPVOID buffer, UINT len, LPCWSTR filename)
1594 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1595 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1596 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1597 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1599 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1600 len, filenameA );
1601 lstrcpynAtoW( buffer, bufferA, len );
1602 HeapFree( GetProcessHeap(), 0, bufferA);
1603 HeapFree( GetProcessHeap(), 0, sectionA );
1604 HeapFree( GetProcessHeap(), 0, keyA );
1605 HeapFree( GetProcessHeap(), 0, filenameA );
1607 return ret;
1612 /***********************************************************************
1613 * WritePrivateProfileStruct16 (KERNEL.406)
1615 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1616 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1618 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1621 /***********************************************************************
1622 * WritePrivateProfileStructA (KERNEL32.744)
1624 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1625 LPVOID buf, UINT bufsize, LPCSTR filename)
1627 BOOL ret = FALSE;
1628 LPBYTE binbuf;
1629 LPSTR outstring, p;
1630 DWORD sum = 0;
1632 if (!section && !key && !buf) /* flush the cache */
1633 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1635 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1636 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1637 p = outstring;
1638 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1639 *p++ = hex[*binbuf >> 4];
1640 *p++ = hex[*binbuf & 0xf];
1641 sum += *binbuf;
1643 /* checksum is sum & 0xff */
1644 *p++ = hex[(sum & 0xf0) >> 4];
1645 *p++ = hex[sum & 0xf];
1646 *p++ = '\0';
1648 EnterCriticalSection( &PROFILE_CritSect );
1650 if (PROFILE_Open( filename ))
1651 ret = PROFILE_SetString( section, key, outstring );
1653 LeaveCriticalSection( &PROFILE_CritSect );
1655 HeapFree( GetProcessHeap(), 0, outstring );
1657 return ret;
1660 /***********************************************************************
1661 * WritePrivateProfileStructW (KERNEL32.544)
1663 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1664 LPVOID buf, UINT bufsize, LPCWSTR filename)
1666 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1667 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1668 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1669 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1670 filenameA );
1671 HeapFree( GetProcessHeap(), 0, sectionA );
1672 HeapFree( GetProcessHeap(), 0, keyA );
1673 HeapFree( GetProcessHeap(), 0, filenameA );
1675 return ret;
1679 /***********************************************************************
1680 * WriteOutProfiles (KERNEL.315)
1682 void WINAPI WriteOutProfiles16(void)
1684 EnterCriticalSection( &PROFILE_CritSect );
1685 PROFILE_FlushFile();
1686 LeaveCriticalSection( &PROFILE_CritSect );
1689 /***********************************************************************
1690 * CloseProfileUserMapping (KERNEL.138)
1692 BOOL WINAPI CloseProfileUserMapping(void) {
1693 FIXME("(), stub!\n");
1694 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1695 return FALSE;