Added support for DirectDraw overlays using the XVideo extension.
[wine/multimedia.git] / files / profile.c
blobd9d50ab8b52f77e4a9f6148b2e0bd77525b5190b
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 "wine/winestring.h"
21 #include "windef.h"
22 #include "winnls.h"
23 #include "winreg.h"
24 #include "file.h"
25 #include "heap.h"
26 #include "debugtools.h"
27 #include "options.h"
28 #include "server.h"
30 DEFAULT_DEBUG_CHANNEL(profile);
32 typedef struct tagPROFILEKEY
34 char *name;
35 char *value;
36 struct tagPROFILEKEY *next;
37 } PROFILEKEY;
39 typedef struct tagPROFILESECTION
41 char *name;
42 struct tagPROFILEKEY *key;
43 struct tagPROFILESECTION *next;
44 } PROFILESECTION;
47 typedef struct
49 BOOL changed;
50 PROFILESECTION *section;
51 char *dos_name;
52 char *unix_name;
53 char *filename;
54 time_t mtime;
55 } PROFILE;
58 #define N_CACHED_PROFILES 10
60 /* Cached profile files */
61 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
63 #define CurProfile (MRUProfile[0])
65 /* wine.ini config file registry root */
66 static HKEY wine_profile_key;
68 #define PROFILE_MAX_LINE_LEN 1024
70 /* Wine profile name in $HOME directory; must begin with slash */
71 static const char PROFILE_WineIniName[] = "/.winerc";
73 /* Wine profile: the profile file being used */
74 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
76 /* Check for comments in profile */
77 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
79 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
81 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
83 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
85 static const char hex[16] = "0123456789ABCDEF";
87 /***********************************************************************
88 * PROFILE_CopyEntry
90 * Copy the content of an entry into a buffer, removing quotes, and possibly
91 * translating environment variables.
93 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
94 int handle_env )
96 char quote = '\0';
97 const char *p;
99 if ((*value == '\'') || (*value == '\"'))
101 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
104 if (!handle_env)
106 lstrcpynA( buffer, value, len );
107 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
108 return;
111 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
113 if ((*p == '$') && (p[1] == '{'))
115 char env_val[1024];
116 const char *env_p;
117 const char *p2 = strchr( p, '}' );
118 if (!p2) continue; /* ignore it */
119 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
120 if ((env_p = getenv( env_val )) != NULL)
122 lstrcpynA( buffer, env_p, len );
123 buffer += strlen( buffer );
124 len -= strlen( buffer );
126 p = p2 + 1;
129 if (quote && (len > 1)) buffer--;
130 *buffer = '\0';
134 /***********************************************************************
135 * PROFILE_Save
137 * Save a profile tree to a file.
139 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
141 PROFILEKEY *key;
143 for ( ; section; section = section->next)
145 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
146 for (key = section->key; key; key = key->next)
148 fprintf( file, "%s", key->name );
149 if (key->value) fprintf( file, "=%s", key->value );
150 fprintf( file, "\r\n" );
156 /***********************************************************************
157 * PROFILE_Free
159 * Free a profile tree.
161 static void PROFILE_Free( PROFILESECTION *section )
163 PROFILESECTION *next_section;
164 PROFILEKEY *key, *next_key;
166 for ( ; section; section = next_section)
168 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
169 for (key = section->key; key; key = next_key)
171 next_key = key->next;
172 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
173 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
174 HeapFree( GetProcessHeap(), 0, key );
176 next_section = section->next;
177 HeapFree( GetProcessHeap(), 0, section );
181 static inline int PROFILE_isspace(char c)
183 if (isspace(c)) return 1;
184 if (c=='\r' || c==0x1a) return 1;
185 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
186 return 0;
190 /***********************************************************************
191 * PROFILE_Load
193 * Load a profile tree from a file.
195 static PROFILESECTION *PROFILE_Load( FILE *file )
197 char buffer[PROFILE_MAX_LINE_LEN];
198 char *p, *p2;
199 int line = 0;
200 PROFILESECTION *section, *first_section;
201 PROFILESECTION **next_section;
202 PROFILEKEY *key, *prev_key, **next_key;
204 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
205 if(first_section == NULL) return NULL;
206 first_section->name = NULL;
207 first_section->key = NULL;
208 first_section->next = NULL;
209 next_section = &first_section->next;
210 next_key = &first_section->key;
211 prev_key = NULL;
213 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
215 line++;
216 p = buffer;
217 while (*p && PROFILE_isspace(*p)) p++;
218 if (*p == '[') /* section start */
220 if (!(p2 = strrchr( p, ']' )))
222 WARN("Invalid section header at line %d: '%s'\n",
223 line, p );
225 else
227 *p2 = '\0';
228 p++;
229 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
230 if(section == NULL) break;
231 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
232 section->key = NULL;
233 section->next = NULL;
234 *next_section = section;
235 next_section = &section->next;
236 next_key = &section->key;
237 prev_key = NULL;
239 TRACE("New section: '%s'\n",section->name);
241 continue;
245 p2=p+strlen(p) - 1;
246 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
248 if ((p2 = strchr( p, '=' )) != NULL)
250 char *p3 = p2 - 1;
251 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
252 *p2++ = '\0';
253 while (*p2 && PROFILE_isspace(*p2)) p2++;
256 if(*p || !prev_key || *prev_key->name)
258 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
259 if(key == NULL) break;
260 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
261 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
262 key->next = NULL;
263 *next_key = key;
264 next_key = &key->next;
265 prev_key = key;
267 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
270 return first_section;
274 /***********************************************************************
275 * PROFILE_RegistryLoad
277 * Load a profile tree from a file into a registry key.
279 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
281 HKEY hkey = 0;
282 DWORD err = 0;
283 char buffer[PROFILE_MAX_LINE_LEN];
284 char *p, *p2;
285 int line = 0;
287 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
289 line++;
290 p = buffer;
291 while (*p && PROFILE_isspace(*p)) p++;
292 if (*p == '[') /* section start */
294 if (!(p2 = strrchr( p, ']' )))
296 WARN("Invalid section header at line %d: '%s'\n",
297 line, p );
299 else
301 *p2 = '\0';
302 p++;
303 if (hkey) RegCloseKey( hkey );
304 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
305 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
306 TRACE("New section: '%s'\n",p);
307 continue;
311 p2=p+strlen(p) - 1;
312 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
314 if ((p2 = strchr( p, '=' )) != NULL)
316 char *p3 = p2 - 1;
317 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
318 *p2++ = '\0';
319 while (*p2 && PROFILE_isspace(*p2)) p2++;
322 if (*p && hkey && !IS_ENTRY_COMMENT(p))
324 if (!p2) p2 = "";
325 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
327 RegCloseKey( hkey );
328 return err;
330 TRACE("New key: name='%s', value='%s'\n",p,p2);
333 if (hkey) RegCloseKey( hkey );
334 return 0;
338 /***********************************************************************
339 * PROFILE_DeleteSection
341 * Delete a section from a profile tree.
343 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
345 while (*section)
347 if ((*section)->name && !strcasecmp( (*section)->name, name ))
349 PROFILESECTION *to_del = *section;
350 *section = to_del->next;
351 to_del->next = NULL;
352 PROFILE_Free( to_del );
353 return TRUE;
355 section = &(*section)->next;
357 return FALSE;
361 /***********************************************************************
362 * PROFILE_DeleteKey
364 * Delete a key from a profile tree.
366 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
367 LPCSTR section_name, LPCSTR key_name )
369 while (*section)
371 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
373 PROFILEKEY **key = &(*section)->key;
374 while (*key)
376 if (!strcasecmp( (*key)->name, key_name ))
378 PROFILEKEY *to_del = *key;
379 *key = to_del->next;
380 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
381 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
382 HeapFree( GetProcessHeap(), 0, to_del );
383 return TRUE;
385 key = &(*key)->next;
388 section = &(*section)->next;
390 return FALSE;
394 /***********************************************************************
395 * PROFILE_DeleteAllKeys
397 * Delete all keys from a profile tree.
399 void PROFILE_DeleteAllKeys( LPCSTR section_name)
401 PROFILESECTION **section= &CurProfile->section;
402 while (*section)
404 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
406 PROFILEKEY **key = &(*section)->key;
407 while (*key)
409 PROFILEKEY *to_del = *key;
410 *key = to_del->next;
411 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
412 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
413 HeapFree( GetProcessHeap(), 0, to_del );
414 CurProfile->changed =TRUE;
417 section = &(*section)->next;
422 /***********************************************************************
423 * PROFILE_Find
425 * Find a key in a profile tree, optionally creating it.
427 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
428 const char *section_name,
429 const char *key_name, int create )
431 const char *p;
432 int seclen, keylen;
434 while (PROFILE_isspace(*section_name)) section_name++;
435 p = section_name + strlen(section_name) - 1;
436 while ((p > section_name) && PROFILE_isspace(*p)) p--;
437 seclen = p - section_name + 1;
439 while (PROFILE_isspace(*key_name)) key_name++;
440 p = key_name + strlen(key_name) - 1;
441 while ((p > key_name) && PROFILE_isspace(*p)) p--;
442 keylen = p - key_name + 1;
444 while (*section)
446 if ( ((*section)->name)
447 && (!(strncasecmp( (*section)->name, section_name, seclen )))
448 && (((*section)->name)[seclen] == '\0') )
450 PROFILEKEY **key = &(*section)->key;
451 while (*key)
453 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
454 && (((*key)->name)[keylen] == '\0') )
455 return *key;
456 key = &(*key)->next;
458 if (!create) return NULL;
459 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
460 if(*key == NULL) return NULL;
461 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
462 (*key)->value = NULL;
463 (*key)->next = NULL;
464 return *key;
466 section = &(*section)->next;
468 if (!create) return NULL;
469 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
470 if(*section == NULL) return NULL;
471 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
472 (*section)->next = NULL;
473 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
474 if((*section)->key == NULL)
476 HeapFree(GetProcessHeap(), 0, *section);
477 return NULL;
479 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
480 (*section)->key->value = NULL;
481 (*section)->key->next = NULL;
482 return (*section)->key;
486 /***********************************************************************
487 * PROFILE_FlushFile
489 * Flush the current profile to disk if changed.
491 static BOOL PROFILE_FlushFile(void)
493 char *p, buffer[MAX_PATHNAME_LEN];
494 const char *unix_name;
495 FILE *file = NULL;
496 struct stat buf;
498 if(!CurProfile)
500 WARN("No current profile!\n");
501 return FALSE;
504 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
505 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
507 /* Try to create it in $HOME/.wine */
508 /* FIXME: this will need a more general solution */
509 strcpy( buffer, get_config_dir() );
510 p = buffer + strlen(buffer);
511 *p++ = '/';
512 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
513 _strlwr( p );
514 file = fopen( buffer, "w" );
515 unix_name = buffer;
518 if (!file)
520 WARN("could not save profile file %s\n", CurProfile->dos_name);
521 return FALSE;
524 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
525 PROFILE_Save( file, CurProfile->section );
526 fclose( file );
527 CurProfile->changed = FALSE;
528 if(!stat(unix_name,&buf))
529 CurProfile->mtime=buf.st_mtime;
530 return TRUE;
534 /***********************************************************************
535 * PROFILE_ReleaseFile
537 * Flush the current profile to disk and remove it from the cache.
539 static void PROFILE_ReleaseFile(void)
541 PROFILE_FlushFile();
542 PROFILE_Free( CurProfile->section );
543 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
544 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
545 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
546 CurProfile->changed = FALSE;
547 CurProfile->section = NULL;
548 CurProfile->dos_name = NULL;
549 CurProfile->unix_name = NULL;
550 CurProfile->filename = NULL;
551 CurProfile->mtime = 0;
555 /***********************************************************************
556 * PROFILE_Open
558 * Open a profile file, checking the cached file first.
560 static BOOL PROFILE_Open( LPCSTR filename )
562 DOS_FULL_NAME full_name;
563 char buffer[MAX_PATHNAME_LEN];
564 char *newdos_name, *p;
565 FILE *file = NULL;
566 int i,j;
567 struct stat buf;
568 PROFILE *tempProfile;
570 /* First time around */
572 if(!CurProfile)
573 for(i=0;i<N_CACHED_PROFILES;i++)
575 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
576 if(MRUProfile[i] == NULL) break;
577 MRUProfile[i]->changed=FALSE;
578 MRUProfile[i]->section=NULL;
579 MRUProfile[i]->dos_name=NULL;
580 MRUProfile[i]->unix_name=NULL;
581 MRUProfile[i]->filename=NULL;
582 MRUProfile[i]->mtime=0;
585 /* Check for a match */
587 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
588 strchr( filename, ':' ))
590 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
592 else
594 GetWindowsDirectoryA( buffer, sizeof(buffer) );
595 strcat( buffer, "\\" );
596 strcat( buffer, filename );
597 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
600 for(i=0;i<N_CACHED_PROFILES;i++)
602 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
603 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
605 if(i)
607 PROFILE_FlushFile();
608 tempProfile=MRUProfile[i];
609 for(j=i;j>0;j--)
610 MRUProfile[j]=MRUProfile[j-1];
611 CurProfile=tempProfile;
613 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
614 TRACE("(%s): already opened (mru=%d)\n",
615 filename, i );
616 else
617 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
618 filename, i );
619 return TRUE;
623 /* Flush the old current profile */
624 PROFILE_FlushFile();
626 /* Make the oldest profile the current one only in order to get rid of it */
627 if(i==N_CACHED_PROFILES)
629 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
630 for(i=N_CACHED_PROFILES-1;i>0;i--)
631 MRUProfile[i]=MRUProfile[i-1];
632 CurProfile=tempProfile;
634 if(CurProfile->filename) PROFILE_ReleaseFile();
636 /* OK, now that CurProfile is definitely free we assign it our new file */
637 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
638 CurProfile->dos_name = newdos_name;
639 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
641 /* Try to open the profile file, first in $HOME/.wine */
643 /* FIXME: this will need a more general solution */
644 strcpy( buffer, get_config_dir() );
645 p = buffer + strlen(buffer);
646 *p++ = '/';
647 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
648 _strlwr( p );
649 if ((file = fopen( buffer, "r" )))
651 TRACE("(%s): found it in %s\n",
652 filename, buffer );
653 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
656 if (!file)
658 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
659 full_name.long_name );
660 if ((file = fopen( full_name.long_name, "r" )))
661 TRACE("(%s): found it in %s\n",
662 filename, full_name.long_name );
665 if (file)
667 CurProfile->section = PROFILE_Load( file );
668 fclose( file );
669 if(!stat(CurProfile->unix_name,&buf))
670 CurProfile->mtime=buf.st_mtime;
672 else
674 /* Does not exist yet, we will create it in PROFILE_FlushFile */
675 WARN("profile file %s not found\n", newdos_name );
677 return TRUE;
681 /***********************************************************************
682 * PROFILE_GetSection
684 * Returns all keys of a section.
685 * If return_values is TRUE, also include the corresponding values.
687 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
688 LPSTR buffer, UINT len, BOOL handle_env,
689 BOOL return_values )
691 PROFILEKEY *key;
692 while (section)
694 if (section->name && !strcasecmp( section->name, section_name ))
696 UINT oldlen = len;
697 for (key = section->key; key; key = key->next)
699 if (len <= 2) break;
700 if (!*key->name) continue; /* Skip empty lines */
701 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
702 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
703 len -= strlen(buffer) + 1;
704 buffer += strlen(buffer) + 1;
705 if (return_values && key->value) {
706 buffer[-1] = '=';
707 PROFILE_CopyEntry ( buffer,
708 key->value, len - 1, handle_env );
709 len -= strlen(buffer) + 1;
710 buffer += strlen(buffer) + 1;
713 *buffer = '\0';
714 if (len <= 1)
715 /*If either lpszSection or lpszKey is NULL and the supplied
716 destination buffer is too small to hold all the strings,
717 the last string is truncated and followed by two null characters.
718 In this case, the return value is equal to cchReturnBuffer
719 minus two. */
721 buffer[-1] = '\0';
722 return oldlen - 2;
724 return oldlen - len;
726 section = section->next;
728 buffer[0] = buffer[1] = '\0';
729 return 0;
733 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
735 LPSTR buf = buffer;
736 WORD l, cursize = 0;
737 PROFILESECTION *section;
739 for (section = CurProfile->section; section; section = section->next)
740 if (section->name) {
741 l = strlen(section->name);
742 cursize += l+1;
743 if (cursize > len+1)
744 return len-2;
746 strcpy(buf, section->name);
747 buf += l+1;
750 *buf=0;
751 buf++;
752 return buf-buffer;
756 /***********************************************************************
757 * PROFILE_GetString
759 * Get a profile string.
761 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
762 LPCSTR def_val, LPSTR buffer, UINT len )
764 PROFILEKEY *key = NULL;
766 if (!def_val) def_val = "";
767 if (key_name && key_name[0])
769 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
770 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
771 len, FALSE );
772 TRACE("('%s','%s','%s'): returning '%s'\n",
773 section, key_name, def_val, buffer );
774 return strlen( buffer );
776 if (key_name && !(key_name[0]))
777 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
778 return 0;
779 if (section && section[0])
780 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
781 FALSE, FALSE);
782 /* undocumented; both section and key_name are NULL */
783 return PROFILE_GetSectionNames(buffer, len);
787 /***********************************************************************
788 * PROFILE_SetString
790 * Set a profile string.
792 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
793 LPCSTR value )
795 if (!key_name) /* Delete a whole section */
797 TRACE("('%s')\n", section_name);
798 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
799 section_name );
800 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
801 this is not an error on application's level.*/
803 else if (!value) /* Delete a key */
805 TRACE("('%s','%s')\n",
806 section_name, key_name );
807 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
808 section_name, key_name );
809 return TRUE; /* same error handling as above */
811 else /* Set the key value */
813 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
814 key_name, TRUE );
815 TRACE("('%s','%s','%s'): \n",
816 section_name, key_name, value );
817 if (!key) return FALSE;
818 if (key->value)
820 /* strip the leading spaces. We can safely strip \n\r and
821 * friends too, they should not happen here anyway. */
822 while (PROFILE_isspace(*value)) value++;
824 if (!strcmp( key->value, value ))
826 TRACE(" no change needed\n" );
827 return TRUE; /* No change needed */
829 TRACE(" replacing '%s'\n", key->value );
830 HeapFree( GetProcessHeap(), 0, key->value );
832 else TRACE(" creating key\n" );
833 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
834 CurProfile->changed = TRUE;
836 return TRUE;
840 /***********************************************************************
841 * PROFILE_GetWineIniString
843 * Get a config string from the wine.ini file.
845 int PROFILE_GetWineIniString( const char *section, const char *key_name,
846 const char *def, char *buffer, int len )
848 char tmp[PROFILE_MAX_LINE_LEN];
849 HKEY hkey;
850 DWORD err;
852 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
854 DWORD type;
855 DWORD count = sizeof(tmp);
856 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
857 RegCloseKey( hkey );
859 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
860 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
861 return strlen(buffer);
865 /***********************************************************************
866 * PROFILE_EnumWineIniString
868 * Get a config string from the wine.ini file.
870 BOOL PROFILE_EnumWineIniString( const char *section, int index,
871 char *name, int name_len, char *buffer, int len )
873 char tmp[PROFILE_MAX_LINE_LEN];
874 HKEY hkey;
875 DWORD err, type;
876 DWORD count = sizeof(tmp);
878 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
879 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
880 RegCloseKey( hkey );
881 if (!err)
883 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
884 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
886 return !err;
890 /***********************************************************************
891 * PROFILE_GetWineIniInt
893 * Get a config integer from the wine.ini file.
895 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
897 char buffer[20];
898 char *p;
899 long result;
901 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
902 if (!buffer[0]) return def;
903 result = strtol( buffer, &p, 0 );
904 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
908 /******************************************************************************
910 * int PROFILE_GetWineIniBool(
911 * char const *section,
912 * char const *key_name,
913 * int def )
915 * Reads a boolean value from the wine.ini file. This function attempts to
916 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
917 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
918 * true. Anything else results in the return of the default value.
920 * This function uses 1 to indicate true, and 0 for false. You can check
921 * for existence by setting def to something other than 0 or 1 and
922 * examining the return value.
924 int PROFILE_GetWineIniBool(
925 char const *section,
926 char const *key_name,
927 int def )
929 char key_value[2];
930 int retval;
932 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
934 switch(key_value[0]) {
935 case 'n':
936 case 'N':
937 case 'f':
938 case 'F':
939 case '0':
940 retval = 0;
941 break;
943 case 'y':
944 case 'Y':
945 case 't':
946 case 'T':
947 case '1':
948 retval = 1;
949 break;
951 default:
952 retval = def;
955 TRACE("(\"%s\", \"%s\", %s), "
956 "[%c], ret %s.\n", section, key_name,
957 def ? "TRUE" : "FALSE", key_value[0],
958 retval ? "TRUE" : "FALSE");
960 return retval;
964 /***********************************************************************
965 * PROFILE_LoadWineIni
967 * Load the wine.ini file.
969 int PROFILE_LoadWineIni(void)
971 char buffer[MAX_PATHNAME_LEN];
972 const char *p;
973 FILE *f;
974 HKEY hKeySW;
975 DWORD disp;
977 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
978 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
980 ERR("Cannot create config registry key\n" );
981 return 0;
983 RegCloseKey( hKeySW );
984 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
985 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, &disp ))
987 ERR("Cannot create config registry key\n" );
988 return 0;
991 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
993 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
995 /* Open -config specified file */
996 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
997 goto found;
1000 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
1002 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
1003 goto found;
1005 if ((p = getenv( "HOME" )) != NULL)
1007 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1008 strcat( buffer, PROFILE_WineIniName );
1009 if ((f = fopen( buffer, "r" )) != NULL)
1011 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1012 goto found;
1015 else WARN("could not get $HOME value for config file.\n" );
1017 /* Try global file */
1019 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
1021 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
1022 goto found;
1025 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1027 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1028 WINE_INI_GLOBAL, PROFILE_WineIniName );
1029 return 0;
1031 found:
1033 if (disp == REG_OPENED_EXISTING_KEY)
1035 MESSAGE( "Warning: configuration loaded by the server from %s/config,\n"
1036 " file %s was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1037 fclose( f );
1038 return 1;
1041 PROFILE_RegistryLoad( wine_profile_key, f );
1042 fclose( f );
1043 return 1;
1047 /***********************************************************************
1048 * PROFILE_UsageWineIni
1050 * Explain the wine.ini file to those who don't read documentation.
1051 * Keep below one screenful in length so that error messages above are
1052 * noticed.
1054 void PROFILE_UsageWineIni(void)
1056 MESSAGE("Perhaps you have not properly edited or created "
1057 "your Wine configuration file.\n");
1058 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1059 MESSAGE(" or it is determined by the -config option or from\n"
1060 " the WINE_INI environment variable.\n");
1061 if (*PROFILE_WineIniUsed)
1062 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1063 /* RTFM, so to say */
1066 /***********************************************************************
1067 * PROFILE_GetStringItem
1069 * Convenience function that turns a string 'xxx, yyy, zzz' into
1070 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1072 char* PROFILE_GetStringItem( char* start )
1074 char* lpchX, *lpch;
1076 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1078 if( *lpchX == ',' )
1080 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1081 while( *(++lpchX) )
1082 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1084 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1085 else lpch = NULL;
1087 if( lpch ) *lpch = '\0';
1088 return NULL;
1091 /********************* API functions **********************************/
1093 /***********************************************************************
1094 * GetProfileInt16 (KERNEL.57)
1096 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1098 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1102 /***********************************************************************
1103 * GetProfileIntA (KERNEL32.264)
1105 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1107 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1110 /***********************************************************************
1111 * GetProfileIntW (KERNEL32.264)
1113 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1115 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1118 /***********************************************************************
1119 * GetProfileString16 (KERNEL.58)
1121 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1122 LPSTR buffer, UINT16 len )
1124 return GetPrivateProfileString16( section, entry, def_val,
1125 buffer, len, "win.ini" );
1128 /***********************************************************************
1129 * GetProfileStringA (KERNEL32.268)
1131 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1132 LPSTR buffer, UINT len )
1134 return GetPrivateProfileStringA( section, entry, def_val,
1135 buffer, len, "win.ini" );
1138 /***********************************************************************
1139 * GetProfileStringW (KERNEL32.269)
1141 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1142 LPCWSTR def_val, LPWSTR buffer, UINT len )
1144 return GetPrivateProfileStringW( section, entry, def_val,
1145 buffer, len, wininiW );
1148 /***********************************************************************
1149 * WriteProfileString16 (KERNEL.59)
1151 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1152 LPCSTR string )
1154 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1157 /***********************************************************************
1158 * WriteProfileStringA (KERNEL32.587)
1160 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1161 LPCSTR string )
1163 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1166 /***********************************************************************
1167 * WriteProfileStringW (KERNEL32.588)
1169 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1170 LPCWSTR string )
1172 return WritePrivateProfileStringW( section, entry, string, wininiW );
1176 /***********************************************************************
1177 * GetPrivateProfileInt16 (KERNEL.127)
1179 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1180 INT16 def_val, LPCSTR filename )
1182 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1184 if (result > 65535) return 65535;
1185 if (result >= 0) return (UINT16)result;
1186 if (result < -32768) return -32768;
1187 return (UINT16)(INT16)result;
1190 /***********************************************************************
1191 * GetPrivateProfileIntA (KERNEL32.251)
1193 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1194 INT def_val, LPCSTR filename )
1196 char buffer[20];
1197 char *p;
1198 long result;
1200 GetPrivateProfileStringA( section, entry, "",
1201 buffer, sizeof(buffer), filename );
1202 if (!buffer[0]) return (UINT)def_val;
1203 result = strtol( buffer, &p, 0 );
1204 if (p == buffer) return 0; /* No digits at all */
1205 return (UINT)result;
1208 /***********************************************************************
1209 * GetPrivateProfileIntW (KERNEL32.252)
1211 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1212 INT def_val, LPCWSTR filename )
1214 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1215 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1216 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1217 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1218 HeapFree( GetProcessHeap(), 0, sectionA );
1219 HeapFree( GetProcessHeap(), 0, filenameA );
1220 HeapFree( GetProcessHeap(), 0, entryA );
1221 return res;
1224 /***********************************************************************
1225 * GetPrivateProfileString16 (KERNEL.128)
1227 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1228 LPCSTR def_val, LPSTR buffer,
1229 UINT16 len, LPCSTR filename )
1231 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1234 /***********************************************************************
1235 * GetPrivateProfileStringA (KERNEL32.255)
1237 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1238 LPCSTR def_val, LPSTR buffer,
1239 UINT len, LPCSTR filename )
1241 int ret;
1243 if (!filename)
1244 filename = "win.ini";
1246 EnterCriticalSection( &PROFILE_CritSect );
1248 if (PROFILE_Open( filename )) {
1249 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1250 } else {
1251 lstrcpynA( buffer, def_val, len );
1252 ret = strlen( buffer );
1255 LeaveCriticalSection( &PROFILE_CritSect );
1257 return ret;
1260 /***********************************************************************
1261 * GetPrivateProfileStringW (KERNEL32.256)
1263 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1264 LPCWSTR def_val, LPWSTR buffer,
1265 UINT len, LPCWSTR filename )
1267 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1268 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1269 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1270 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1271 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1272 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1273 bufferA, len, filenameA );
1274 lstrcpynAtoW( buffer, bufferA, len );
1275 HeapFree( GetProcessHeap(), 0, sectionA );
1276 HeapFree( GetProcessHeap(), 0, entryA );
1277 HeapFree( GetProcessHeap(), 0, filenameA );
1278 HeapFree( GetProcessHeap(), 0, def_valA );
1279 HeapFree( GetProcessHeap(), 0, bufferA);
1280 return ret;
1283 /***********************************************************************
1284 * GetPrivateProfileSection16 (KERNEL.418)
1286 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1287 UINT16 len, LPCSTR filename )
1289 return GetPrivateProfileSectionA( section, buffer, len, filename );
1292 /***********************************************************************
1293 * GetPrivateProfileSectionA (KERNEL32.255)
1295 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1296 DWORD len, LPCSTR filename )
1298 int ret = 0;
1300 EnterCriticalSection( &PROFILE_CritSect );
1302 if (PROFILE_Open( filename ))
1303 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1304 FALSE, TRUE);
1306 LeaveCriticalSection( &PROFILE_CritSect );
1308 return ret;
1311 /***********************************************************************
1312 * GetPrivateProfileSectionW (KERNEL32.256)
1315 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1316 DWORD len, LPCWSTR filename )
1319 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1320 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1321 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1322 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1323 filenameA );
1324 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1325 HeapFree( GetProcessHeap(), 0, sectionA );
1326 HeapFree( GetProcessHeap(), 0, filenameA );
1327 HeapFree( GetProcessHeap(), 0, bufferA);
1328 return ret;
1331 /***********************************************************************
1332 * GetProfileSection16 (KERNEL.419)
1334 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1336 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1339 /***********************************************************************
1340 * GetProfileSectionA (KERNEL32.268)
1342 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1344 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1347 /***********************************************************************
1348 * GetProfileSectionW (KERNEL32)
1350 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1352 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1356 /***********************************************************************
1357 * WritePrivateProfileString16 (KERNEL.129)
1359 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1360 LPCSTR string, LPCSTR filename )
1362 return WritePrivateProfileStringA(section,entry,string,filename);
1365 /***********************************************************************
1366 * WritePrivateProfileStringA (KERNEL32.582)
1368 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1369 LPCSTR string, LPCSTR filename )
1371 BOOL ret = FALSE;
1373 EnterCriticalSection( &PROFILE_CritSect );
1375 if (PROFILE_Open( filename ))
1377 if (!section && !entry && !string)
1378 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1379 else
1380 ret = PROFILE_SetString( section, entry, string );
1383 LeaveCriticalSection( &PROFILE_CritSect );
1384 return ret;
1387 /***********************************************************************
1388 * WritePrivateProfileStringW (KERNEL32.583)
1390 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1391 LPCWSTR string, LPCWSTR filename )
1393 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1394 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1395 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1396 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1397 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1398 stringA, filenameA );
1399 HeapFree( GetProcessHeap(), 0, sectionA );
1400 HeapFree( GetProcessHeap(), 0, entryA );
1401 HeapFree( GetProcessHeap(), 0, stringA );
1402 HeapFree( GetProcessHeap(), 0, filenameA );
1403 return res;
1406 /***********************************************************************
1407 * WritePrivateProfileSection16 (KERNEL.416)
1409 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1410 LPCSTR string, LPCSTR filename )
1412 return WritePrivateProfileSectionA( section, string, filename );
1415 /***********************************************************************
1416 * WritePrivateProfileSectionA (KERNEL32)
1418 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1419 LPCSTR string, LPCSTR filename )
1421 BOOL ret = FALSE;
1422 LPSTR p ;
1424 EnterCriticalSection( &PROFILE_CritSect );
1426 if (PROFILE_Open( filename )) {
1427 if (!section && !string && !filename)
1428 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1429 else if (!string) /* delete the named section*/
1430 ret = PROFILE_SetString(section,NULL,NULL);
1431 else {
1432 PROFILE_DeleteAllKeys(section);
1433 ret = TRUE;
1434 while(*string) {
1435 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1436 if((p=strchr( buf, '='))){
1437 *p='\0';
1438 ret = PROFILE_SetString( section, buf, p+1 );
1441 HeapFree( GetProcessHeap(), 0, buf );
1442 string += strlen(string)+1;
1448 LeaveCriticalSection( &PROFILE_CritSect );
1449 return ret;
1452 /***********************************************************************
1453 * WritePrivateProfileSectionW (KERNEL32)
1455 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1456 LPCWSTR string, LPCWSTR filename)
1459 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1460 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1461 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1462 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1463 HeapFree( GetProcessHeap(), 0, sectionA );
1464 HeapFree( GetProcessHeap(), 0, stringA );
1465 HeapFree( GetProcessHeap(), 0, filenameA );
1466 return res;
1469 /***********************************************************************
1470 * WriteProfileSection16 (KERNEL.417)
1472 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1474 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1477 /***********************************************************************
1478 * WriteProfileSectionA (KERNEL32.747)
1480 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1483 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1486 /***********************************************************************
1487 * WriteProfileSectionW (KERNEL32.748)
1489 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1491 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1494 /***********************************************************************
1495 * GetPrivateProfileSectionNames16 (KERNEL.143)
1497 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1498 LPCSTR filename )
1500 WORD ret = 0;
1502 EnterCriticalSection( &PROFILE_CritSect );
1504 if (PROFILE_Open( filename ))
1505 ret = PROFILE_GetSectionNames(buffer, size);
1507 LeaveCriticalSection( &PROFILE_CritSect );
1509 return ret;
1513 /***********************************************************************
1514 * GetProfileSectionNames16 (KERNEL.142)
1516 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1519 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1523 /***********************************************************************
1524 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1526 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1527 LPCSTR filename)
1530 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1534 /***********************************************************************
1535 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1537 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1538 LPCWSTR filename)
1541 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1542 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1544 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1545 lstrcpynAtoW( buffer, bufferA, size);
1546 HeapFree( GetProcessHeap(), 0, bufferA);
1547 HeapFree( GetProcessHeap(), 0, filenameA );
1549 return ret;
1552 /***********************************************************************
1553 * GetPrivateProfileStruct16 (KERNEL.407)
1555 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1556 LPVOID buf, UINT16 len, LPCSTR filename)
1558 return GetPrivateProfileStructA( section, key, buf, len, filename );
1561 /***********************************************************************
1562 * GetPrivateProfileStructA (KERNEL32.370)
1564 * Should match Win95's behaviour pretty much
1566 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1567 LPVOID buf, UINT len, LPCSTR filename)
1569 BOOL ret = FALSE;
1571 EnterCriticalSection( &PROFILE_CritSect );
1573 if (PROFILE_Open( filename )) {
1574 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1575 if (k) {
1576 TRACE("value (at %p): '%s'\n", k->value, k->value);
1577 if (((strlen(k->value) - 2) / 2) == len)
1579 LPSTR end, p;
1580 BOOL valid = TRUE;
1581 CHAR c;
1582 DWORD chksum = 0;
1584 end = k->value + strlen(k->value); /* -> '\0' */
1585 /* check for invalid chars in ASCII coded hex string */
1586 for (p=k->value; p < end; p++)
1588 if (!isxdigit(*p))
1590 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1591 *p, filename, section, key);
1592 valid = FALSE;
1593 break;
1596 if (valid)
1598 BOOL highnibble = TRUE;
1599 BYTE b = 0, val;
1600 LPBYTE binbuf = (LPBYTE)buf;
1602 end -= 2; /* don't include checksum in output data */
1603 /* translate ASCII hex format into binary data */
1604 for (p=k->value; p < end; p++)
1606 c = toupper(*p);
1607 val = (c > '9') ?
1608 (c - 'A' + 10) : (c - '0');
1610 if (highnibble)
1611 b = val << 4;
1612 else
1614 b += val;
1615 *binbuf++ = b; /* feed binary data into output */
1616 chksum += b; /* calculate checksum */
1618 highnibble ^= 1; /* toggle */
1620 /* retrieve stored checksum value */
1621 c = toupper(*p++);
1622 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1623 c = toupper(*p);
1624 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1625 if (b == (chksum & 0xff)) /* checksums match ? */
1626 ret = TRUE;
1631 LeaveCriticalSection( &PROFILE_CritSect );
1633 return ret;
1636 /***********************************************************************
1637 * GetPrivateProfileStructW (KERNEL32.543)
1639 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1640 LPVOID buffer, UINT len, LPCWSTR filename)
1642 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1643 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1644 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1645 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1647 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1648 len, filenameA );
1649 lstrcpynAtoW( buffer, bufferA, len );
1650 HeapFree( GetProcessHeap(), 0, bufferA);
1651 HeapFree( GetProcessHeap(), 0, sectionA );
1652 HeapFree( GetProcessHeap(), 0, keyA );
1653 HeapFree( GetProcessHeap(), 0, filenameA );
1655 return ret;
1660 /***********************************************************************
1661 * WritePrivateProfileStruct16 (KERNEL.406)
1663 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1664 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1666 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1669 /***********************************************************************
1670 * WritePrivateProfileStructA (KERNEL32.744)
1672 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1673 LPVOID buf, UINT bufsize, LPCSTR filename)
1675 BOOL ret = FALSE;
1676 LPBYTE binbuf;
1677 LPSTR outstring, p;
1678 DWORD sum = 0;
1680 if (!section && !key && !buf) /* flush the cache */
1681 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1683 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1684 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1685 p = outstring;
1686 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1687 *p++ = hex[*binbuf >> 4];
1688 *p++ = hex[*binbuf & 0xf];
1689 sum += *binbuf;
1691 /* checksum is sum & 0xff */
1692 *p++ = hex[(sum & 0xf0) >> 4];
1693 *p++ = hex[sum & 0xf];
1694 *p++ = '\0';
1696 EnterCriticalSection( &PROFILE_CritSect );
1698 if (PROFILE_Open( filename ))
1699 ret = PROFILE_SetString( section, key, outstring );
1701 LeaveCriticalSection( &PROFILE_CritSect );
1703 HeapFree( GetProcessHeap(), 0, outstring );
1705 return ret;
1708 /***********************************************************************
1709 * WritePrivateProfileStructW (KERNEL32.544)
1711 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1712 LPVOID buf, UINT bufsize, LPCWSTR filename)
1714 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1715 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1716 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1717 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1718 filenameA );
1719 HeapFree( GetProcessHeap(), 0, sectionA );
1720 HeapFree( GetProcessHeap(), 0, keyA );
1721 HeapFree( GetProcessHeap(), 0, filenameA );
1723 return ret;
1727 /***********************************************************************
1728 * WriteOutProfiles (KERNEL.315)
1730 void WINAPI WriteOutProfiles16(void)
1732 EnterCriticalSection( &PROFILE_CritSect );
1733 PROFILE_FlushFile();
1734 LeaveCriticalSection( &PROFILE_CritSect );
1737 /***********************************************************************
1738 * CloseProfileUserMapping (KERNEL.138)
1740 BOOL WINAPI CloseProfileUserMapping(void) {
1741 FIXME("(), stub!\n");
1742 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1743 return FALSE;