Added 24->32 packed pixel mapping support to convert.
[wine/multimedia.git] / files / profile.c
blob99d04f4f14ab623790e87d43e1af934579e84837
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 /* strip the leading spaces. We can safely strip \n\r and
794 * friends too, they should not happen here anyway. */
795 while (PROFILE_isspace(*value)) value++;
797 if (!strcmp( key->value, value ))
799 TRACE(" no change needed\n" );
800 return TRUE; /* No change needed */
802 TRACE(" replacing '%s'\n", key->value );
803 HeapFree( GetProcessHeap(), 0, key->value );
805 else TRACE(" creating key\n" );
806 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
807 CurProfile->changed = TRUE;
809 return TRUE;
813 /***********************************************************************
814 * PROFILE_GetWineIniString
816 * Get a config string from the wine.ini file.
818 int PROFILE_GetWineIniString( const char *section, const char *key_name,
819 const char *def, char *buffer, int len )
821 char tmp[PROFILE_MAX_LINE_LEN];
822 HKEY hkey;
823 DWORD err;
825 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
827 DWORD type;
828 DWORD count = sizeof(tmp);
829 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
830 RegCloseKey( hkey );
832 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
833 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
834 return strlen(buffer);
838 /***********************************************************************
839 * PROFILE_EnumWineIniString
841 * Get a config string from the wine.ini file.
843 BOOL PROFILE_EnumWineIniString( const char *section, int index,
844 char *name, int name_len, char *buffer, int len )
846 char tmp[PROFILE_MAX_LINE_LEN];
847 HKEY hkey;
848 DWORD err, type;
849 DWORD count = sizeof(tmp);
851 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
852 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
853 RegCloseKey( hkey );
854 if (!err)
856 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
857 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
859 return !err;
863 /***********************************************************************
864 * PROFILE_GetWineIniInt
866 * Get a config integer from the wine.ini file.
868 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
870 char buffer[20];
871 char *p;
872 long result;
874 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
875 if (!buffer[0]) return def;
876 result = strtol( buffer, &p, 0 );
877 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
881 /******************************************************************************
883 * int PROFILE_GetWineIniBool(
884 * char const *section,
885 * char const *key_name,
886 * int def )
888 * Reads a boolean value from the wine.ini file. This function attempts to
889 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
890 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
891 * true. Anything else results in the return of the default value.
893 * This function uses 1 to indicate true, and 0 for false. You can check
894 * for existence by setting def to something other than 0 or 1 and
895 * examining the return value.
897 int PROFILE_GetWineIniBool(
898 char const *section,
899 char const *key_name,
900 int def )
902 char key_value[2];
903 int retval;
905 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
907 switch(key_value[0]) {
908 case 'n':
909 case 'N':
910 case 'f':
911 case 'F':
912 case '0':
913 retval = 0;
914 break;
916 case 'y':
917 case 'Y':
918 case 't':
919 case 'T':
920 case '1':
921 retval = 1;
922 break;
924 default:
925 retval = def;
928 TRACE("(\"%s\", \"%s\", %s), "
929 "[%c], ret %s.\n", section, key_name,
930 def ? "TRUE" : "FALSE", key_value[0],
931 retval ? "TRUE" : "FALSE");
933 return retval;
937 /***********************************************************************
938 * PROFILE_LoadWineIni
940 * Load the wine.ini file.
942 int PROFILE_LoadWineIni(void)
944 char buffer[MAX_PATHNAME_LEN];
945 const char *p;
946 FILE *f;
947 HKEY hKeySW;
949 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
950 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
952 ERR("Cannot create config registry key\n" );
953 return 0;
955 RegCloseKey( hKeySW );
956 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
957 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, NULL ))
959 ERR("Cannot create config registry key\n" );
960 return 0;
963 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
965 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
967 /* Open -config specified file */
968 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
969 goto found;
972 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
974 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
975 goto found;
977 if ((p = getenv( "HOME" )) != NULL)
979 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
980 strcat( buffer, PROFILE_WineIniName );
981 if ((f = fopen( buffer, "r" )) != NULL)
983 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
984 goto found;
987 else WARN("could not get $HOME value for config file.\n" );
989 /* Try global file */
991 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
993 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
994 goto found;
996 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
997 WINE_INI_GLOBAL, PROFILE_WineIniName );
998 return 0;
1000 found:
1001 PROFILE_RegistryLoad( wine_profile_key, f );
1002 fclose( f );
1003 return 1;
1007 /***********************************************************************
1008 * PROFILE_UsageWineIni
1010 * Explain the wine.ini file to those who don't read documentation.
1011 * Keep below one screenful in length so that error messages above are
1012 * noticed.
1014 void PROFILE_UsageWineIni(void)
1016 MESSAGE("Perhaps you have not properly edited or created "
1017 "your Wine configuration file.\n");
1018 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1019 MESSAGE(" or it is determined by the -config option or from\n"
1020 " the WINE_INI environment variable.\n");
1021 if (*PROFILE_WineIniUsed)
1022 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1023 /* RTFM, so to say */
1026 /***********************************************************************
1027 * PROFILE_GetStringItem
1029 * Convenience function that turns a string 'xxx, yyy, zzz' into
1030 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1032 char* PROFILE_GetStringItem( char* start )
1034 char* lpchX, *lpch;
1036 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1038 if( *lpchX == ',' )
1040 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1041 while( *(++lpchX) )
1042 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1044 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1045 else lpch = NULL;
1047 if( lpch ) *lpch = '\0';
1048 return NULL;
1051 /********************* API functions **********************************/
1053 /***********************************************************************
1054 * GetProfileInt16 (KERNEL.57)
1056 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1058 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1062 /***********************************************************************
1063 * GetProfileIntA (KERNEL32.264)
1065 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1067 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1070 /***********************************************************************
1071 * GetProfileIntW (KERNEL32.264)
1073 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1075 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1078 /***********************************************************************
1079 * GetProfileString16 (KERNEL.58)
1081 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1082 LPSTR buffer, UINT16 len )
1084 return GetPrivateProfileString16( section, entry, def_val,
1085 buffer, len, "win.ini" );
1088 /***********************************************************************
1089 * GetProfileStringA (KERNEL32.268)
1091 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1092 LPSTR buffer, UINT len )
1094 return GetPrivateProfileStringA( section, entry, def_val,
1095 buffer, len, "win.ini" );
1098 /***********************************************************************
1099 * GetProfileStringW (KERNEL32.269)
1101 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1102 LPCWSTR def_val, LPWSTR buffer, UINT len )
1104 return GetPrivateProfileStringW( section, entry, def_val,
1105 buffer, len, wininiW );
1108 /***********************************************************************
1109 * WriteProfileString16 (KERNEL.59)
1111 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1112 LPCSTR string )
1114 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1117 /***********************************************************************
1118 * WriteProfileStringA (KERNEL32.587)
1120 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1121 LPCSTR string )
1123 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1126 /***********************************************************************
1127 * WriteProfileStringW (KERNEL32.588)
1129 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1130 LPCWSTR string )
1132 return WritePrivateProfileStringW( section, entry, string, wininiW );
1136 /***********************************************************************
1137 * GetPrivateProfileInt16 (KERNEL.127)
1139 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1140 INT16 def_val, LPCSTR filename )
1142 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1144 if (result > 65535) return 65535;
1145 if (result >= 0) return (UINT16)result;
1146 if (result < -32768) return -32768;
1147 return (UINT16)(INT16)result;
1150 /***********************************************************************
1151 * GetPrivateProfileIntA (KERNEL32.251)
1153 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1154 INT def_val, LPCSTR filename )
1156 char buffer[20];
1157 char *p;
1158 long result;
1160 GetPrivateProfileStringA( section, entry, "",
1161 buffer, sizeof(buffer), filename );
1162 if (!buffer[0]) return (UINT)def_val;
1163 result = strtol( buffer, &p, 0 );
1164 if (p == buffer) return 0; /* No digits at all */
1165 return (UINT)result;
1168 /***********************************************************************
1169 * GetPrivateProfileIntW (KERNEL32.252)
1171 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1172 INT def_val, LPCWSTR filename )
1174 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1175 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1176 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1177 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1178 HeapFree( GetProcessHeap(), 0, sectionA );
1179 HeapFree( GetProcessHeap(), 0, filenameA );
1180 HeapFree( GetProcessHeap(), 0, entryA );
1181 return res;
1184 /***********************************************************************
1185 * GetPrivateProfileString16 (KERNEL.128)
1187 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1188 LPCSTR def_val, LPSTR buffer,
1189 UINT16 len, LPCSTR filename )
1191 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1194 /***********************************************************************
1195 * GetPrivateProfileStringA (KERNEL32.255)
1197 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1198 LPCSTR def_val, LPSTR buffer,
1199 UINT len, LPCSTR filename )
1201 int ret;
1203 if (!filename)
1204 filename = "win.ini";
1206 EnterCriticalSection( &PROFILE_CritSect );
1208 if (PROFILE_Open( filename )) {
1209 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1210 } else {
1211 lstrcpynA( buffer, def_val, len );
1212 ret = strlen( buffer );
1215 LeaveCriticalSection( &PROFILE_CritSect );
1217 return ret;
1220 /***********************************************************************
1221 * GetPrivateProfileStringW (KERNEL32.256)
1223 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1224 LPCWSTR def_val, LPWSTR buffer,
1225 UINT len, LPCWSTR filename )
1227 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1228 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1229 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1230 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1231 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1232 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1233 bufferA, len, filenameA );
1234 lstrcpynAtoW( buffer, bufferA, len );
1235 HeapFree( GetProcessHeap(), 0, sectionA );
1236 HeapFree( GetProcessHeap(), 0, entryA );
1237 HeapFree( GetProcessHeap(), 0, filenameA );
1238 HeapFree( GetProcessHeap(), 0, def_valA );
1239 HeapFree( GetProcessHeap(), 0, bufferA);
1240 return ret;
1243 /***********************************************************************
1244 * GetPrivateProfileSection16 (KERNEL.418)
1246 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1247 UINT16 len, LPCSTR filename )
1249 return GetPrivateProfileSectionA( section, buffer, len, filename );
1252 /***********************************************************************
1253 * GetPrivateProfileSectionA (KERNEL32.255)
1255 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1256 DWORD len, LPCSTR filename )
1258 int ret = 0;
1260 EnterCriticalSection( &PROFILE_CritSect );
1262 if (PROFILE_Open( filename ))
1263 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1264 FALSE, TRUE);
1266 LeaveCriticalSection( &PROFILE_CritSect );
1268 return ret;
1271 /***********************************************************************
1272 * GetPrivateProfileSectionW (KERNEL32.256)
1275 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1276 DWORD len, LPCWSTR filename )
1279 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1280 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1281 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1282 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1283 filenameA );
1284 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1285 HeapFree( GetProcessHeap(), 0, sectionA );
1286 HeapFree( GetProcessHeap(), 0, filenameA );
1287 HeapFree( GetProcessHeap(), 0, bufferA);
1288 return ret;
1291 /***********************************************************************
1292 * GetProfileSection16 (KERNEL.419)
1294 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1296 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1299 /***********************************************************************
1300 * GetProfileSectionA (KERNEL32.268)
1302 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1304 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1307 /***********************************************************************
1308 * GetProfileSectionW (KERNEL32)
1310 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1312 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1316 /***********************************************************************
1317 * WritePrivateProfileString16 (KERNEL.129)
1319 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1320 LPCSTR string, LPCSTR filename )
1322 return WritePrivateProfileStringA(section,entry,string,filename);
1325 /***********************************************************************
1326 * WritePrivateProfileStringA (KERNEL32.582)
1328 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1329 LPCSTR string, LPCSTR filename )
1331 BOOL ret = FALSE;
1333 EnterCriticalSection( &PROFILE_CritSect );
1335 if (PROFILE_Open( filename ))
1337 if (!section && !entry && !string)
1338 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1339 else
1340 ret = PROFILE_SetString( section, entry, string );
1343 LeaveCriticalSection( &PROFILE_CritSect );
1344 return ret;
1347 /***********************************************************************
1348 * WritePrivateProfileStringW (KERNEL32.583)
1350 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1351 LPCWSTR string, LPCWSTR filename )
1353 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1354 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1355 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1356 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1357 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1358 stringA, filenameA );
1359 HeapFree( GetProcessHeap(), 0, sectionA );
1360 HeapFree( GetProcessHeap(), 0, entryA );
1361 HeapFree( GetProcessHeap(), 0, stringA );
1362 HeapFree( GetProcessHeap(), 0, filenameA );
1363 return res;
1366 /***********************************************************************
1367 * WritePrivateProfileSection16 (KERNEL.416)
1369 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1370 LPCSTR string, LPCSTR filename )
1372 return WritePrivateProfileSectionA( section, string, filename );
1375 /***********************************************************************
1376 * WritePrivateProfileSectionA (KERNEL32)
1378 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1379 LPCSTR string, LPCSTR filename )
1381 BOOL ret = FALSE;
1382 LPSTR p ;
1384 EnterCriticalSection( &PROFILE_CritSect );
1386 if (PROFILE_Open( filename )) {
1387 if (!section && !string && !filename)
1388 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1389 else {
1390 while(*string){
1391 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1392 if((p=strchr( buf, '='))){
1393 *p='\0';
1394 ret = PROFILE_SetString( section, buf, p+1 );
1397 HeapFree( GetProcessHeap(), 0, buf );
1398 string += strlen(string)+1;
1404 LeaveCriticalSection( &PROFILE_CritSect );
1405 return ret;
1408 /***********************************************************************
1409 * WritePrivateProfileSectionW (KERNEL32)
1411 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1412 LPCWSTR string, LPCWSTR filename)
1415 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1416 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1417 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1418 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1419 HeapFree( GetProcessHeap(), 0, sectionA );
1420 HeapFree( GetProcessHeap(), 0, stringA );
1421 HeapFree( GetProcessHeap(), 0, filenameA );
1422 return res;
1425 /***********************************************************************
1426 * WriteProfileSection16 (KERNEL.417)
1428 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1430 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1433 /***********************************************************************
1434 * WriteProfileSectionA (KERNEL32.747)
1436 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1439 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1442 /***********************************************************************
1443 * WriteProfileSectionW (KERNEL32.748)
1445 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1447 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1450 /***********************************************************************
1451 * GetPrivateProfileSectionNames16 (KERNEL.143)
1453 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1454 LPCSTR filename )
1456 WORD ret = 0;
1458 EnterCriticalSection( &PROFILE_CritSect );
1460 if (PROFILE_Open( filename ))
1461 ret = PROFILE_GetSectionNames(buffer, size);
1463 LeaveCriticalSection( &PROFILE_CritSect );
1465 return ret;
1469 /***********************************************************************
1470 * GetProfileSectionNames16 (KERNEL.142)
1472 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1475 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1479 /***********************************************************************
1480 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1482 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1483 LPCSTR filename)
1486 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1490 /***********************************************************************
1491 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1493 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1494 LPCWSTR filename)
1497 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1498 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1500 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1501 lstrcpynAtoW( buffer, bufferA, size);
1502 HeapFree( GetProcessHeap(), 0, bufferA);
1503 HeapFree( GetProcessHeap(), 0, filenameA );
1505 return ret;
1508 /***********************************************************************
1509 * GetPrivateProfileStruct16 (KERNEL.407)
1511 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1512 LPVOID buf, UINT16 len, LPCSTR filename)
1514 return GetPrivateProfileStructA( section, key, buf, len, filename );
1517 /***********************************************************************
1518 * GetPrivateProfileStructA (KERNEL32.370)
1520 * Should match Win95's behaviour pretty much
1522 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1523 LPVOID buf, UINT len, LPCSTR filename)
1525 BOOL ret = FALSE;
1527 EnterCriticalSection( &PROFILE_CritSect );
1529 if (PROFILE_Open( filename )) {
1530 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1531 if (k) {
1532 TRACE("value (at %p): '%s'\n", k->value, k->value);
1533 if (((strlen(k->value) - 2) / 2) == len)
1535 LPSTR end, p;
1536 BOOL valid = TRUE;
1537 CHAR c;
1538 DWORD chksum = 0;
1540 end = k->value + strlen(k->value); /* -> '\0' */
1541 /* check for invalid chars in ASCII coded hex string */
1542 for (p=k->value; p < end; p++)
1544 if (!isxdigit(*p))
1546 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1547 *p, filename, section, key);
1548 valid = FALSE;
1549 break;
1552 if (valid)
1554 BOOL highnibble = TRUE;
1555 BYTE b = 0, val;
1556 LPBYTE binbuf = (LPBYTE)buf;
1558 end -= 2; /* don't include checksum in output data */
1559 /* translate ASCII hex format into binary data */
1560 for (p=k->value; p < end; p++)
1562 c = toupper(*p);
1563 val = (c > '9') ?
1564 (c - 'A' + 10) : (c - '0');
1566 if (highnibble)
1567 b = val << 4;
1568 else
1570 b += val;
1571 *binbuf++ = b; /* feed binary data into output */
1572 chksum += b; /* calculate checksum */
1574 highnibble ^= 1; /* toggle */
1576 /* retrieve stored checksum value */
1577 c = toupper(*p++);
1578 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1579 c = toupper(*p);
1580 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1581 if (b == (chksum & 0xff)) /* checksums match ? */
1582 ret = TRUE;
1587 LeaveCriticalSection( &PROFILE_CritSect );
1589 return ret;
1592 /***********************************************************************
1593 * GetPrivateProfileStructW (KERNEL32.543)
1595 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1596 LPVOID buffer, UINT len, LPCWSTR filename)
1598 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1599 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1600 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1601 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1603 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1604 len, filenameA );
1605 lstrcpynAtoW( buffer, bufferA, len );
1606 HeapFree( GetProcessHeap(), 0, bufferA);
1607 HeapFree( GetProcessHeap(), 0, sectionA );
1608 HeapFree( GetProcessHeap(), 0, keyA );
1609 HeapFree( GetProcessHeap(), 0, filenameA );
1611 return ret;
1616 /***********************************************************************
1617 * WritePrivateProfileStruct16 (KERNEL.406)
1619 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1620 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1622 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1625 /***********************************************************************
1626 * WritePrivateProfileStructA (KERNEL32.744)
1628 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1629 LPVOID buf, UINT bufsize, LPCSTR filename)
1631 BOOL ret = FALSE;
1632 LPBYTE binbuf;
1633 LPSTR outstring, p;
1634 DWORD sum = 0;
1636 if (!section && !key && !buf) /* flush the cache */
1637 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1639 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1640 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1641 p = outstring;
1642 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1643 *p++ = hex[*binbuf >> 4];
1644 *p++ = hex[*binbuf & 0xf];
1645 sum += *binbuf;
1647 /* checksum is sum & 0xff */
1648 *p++ = hex[(sum & 0xf0) >> 4];
1649 *p++ = hex[sum & 0xf];
1650 *p++ = '\0';
1652 EnterCriticalSection( &PROFILE_CritSect );
1654 if (PROFILE_Open( filename ))
1655 ret = PROFILE_SetString( section, key, outstring );
1657 LeaveCriticalSection( &PROFILE_CritSect );
1659 HeapFree( GetProcessHeap(), 0, outstring );
1661 return ret;
1664 /***********************************************************************
1665 * WritePrivateProfileStructW (KERNEL32.544)
1667 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1668 LPVOID buf, UINT bufsize, LPCWSTR filename)
1670 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1671 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1672 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1673 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1674 filenameA );
1675 HeapFree( GetProcessHeap(), 0, sectionA );
1676 HeapFree( GetProcessHeap(), 0, keyA );
1677 HeapFree( GetProcessHeap(), 0, filenameA );
1679 return ret;
1683 /***********************************************************************
1684 * WriteOutProfiles (KERNEL.315)
1686 void WINAPI WriteOutProfiles16(void)
1688 EnterCriticalSection( &PROFILE_CritSect );
1689 PROFILE_FlushFile();
1690 LeaveCriticalSection( &PROFILE_CritSect );
1693 /***********************************************************************
1694 * CloseProfileUserMapping (KERNEL.138)
1696 BOOL WINAPI CloseProfileUserMapping(void) {
1697 FIXME("(), stub!\n");
1698 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1699 return FALSE;