Minor API files update.
[wine/gsoc_dplay.git] / files / profile.c
blobbdbd121de2193fd15fc7f08a4ac6dcb0ed49f1cb
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 "winnls.h"
22 #include "winreg.h"
23 #include "file.h"
24 #include "heap.h"
25 #include "debugtools.h"
26 #include "options.h"
27 #include "server.h"
29 DEFAULT_DEBUG_CHANNEL(profile);
31 typedef struct tagPROFILEKEY
33 char *name;
34 char *value;
35 struct tagPROFILEKEY *next;
36 } PROFILEKEY;
38 typedef struct tagPROFILESECTION
40 char *name;
41 struct tagPROFILEKEY *key;
42 struct tagPROFILESECTION *next;
43 } PROFILESECTION;
46 typedef struct
48 BOOL changed;
49 PROFILESECTION *section;
50 char *dos_name;
51 char *unix_name;
52 char *filename;
53 time_t mtime;
54 } PROFILE;
57 #define N_CACHED_PROFILES 10
59 /* Cached profile files */
60 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
62 #define CurProfile (MRUProfile[0])
64 /* wine.ini config file registry root */
65 static HKEY wine_profile_key;
67 #define PROFILE_MAX_LINE_LEN 1024
69 /* Wine profile name in $HOME directory; must begin with slash */
70 static const char PROFILE_WineIniName[] = "/.winerc";
72 /* Wine profile: the profile file being used */
73 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
75 /* Check for comments in profile */
76 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
78 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
80 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
82 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
84 static const char hex[16] = "0123456789ABCDEF";
86 /***********************************************************************
87 * PROFILE_CopyEntry
89 * Copy the content of an entry into a buffer, removing quotes, and possibly
90 * translating environment variables.
92 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
93 int handle_env )
95 char quote = '\0';
96 const char *p;
98 if ((*value == '\'') || (*value == '\"'))
100 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
103 if (!handle_env)
105 lstrcpynA( buffer, value, len );
106 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
107 return;
110 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
112 if ((*p == '$') && (p[1] == '{'))
114 char env_val[1024];
115 const char *env_p;
116 const char *p2 = strchr( p, '}' );
117 if (!p2) continue; /* ignore it */
118 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
119 if ((env_p = getenv( env_val )) != NULL)
121 lstrcpynA( buffer, env_p, len );
122 buffer += strlen( buffer );
123 len -= strlen( buffer );
125 p = p2 + 1;
128 if (quote && (len > 1)) buffer--;
129 *buffer = '\0';
133 /***********************************************************************
134 * PROFILE_Save
136 * Save a profile tree to a file.
138 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
140 PROFILEKEY *key;
142 for ( ; section; section = section->next)
144 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
145 for (key = section->key; key; key = key->next)
147 fprintf( file, "%s", key->name );
148 if (key->value) fprintf( file, "=%s", key->value );
149 fprintf( file, "\r\n" );
155 /***********************************************************************
156 * PROFILE_Free
158 * Free a profile tree.
160 static void PROFILE_Free( PROFILESECTION *section )
162 PROFILESECTION *next_section;
163 PROFILEKEY *key, *next_key;
165 for ( ; section; section = next_section)
167 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
168 for (key = section->key; key; key = next_key)
170 next_key = key->next;
171 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
172 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
173 HeapFree( GetProcessHeap(), 0, key );
175 next_section = section->next;
176 HeapFree( GetProcessHeap(), 0, section );
180 static inline int PROFILE_isspace(char c)
182 if (isspace(c)) return 1;
183 if (c=='\r' || c==0x1a) return 1;
184 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
185 return 0;
189 /***********************************************************************
190 * PROFILE_Load
192 * Load a profile tree from a file.
194 static PROFILESECTION *PROFILE_Load( FILE *file )
196 char buffer[PROFILE_MAX_LINE_LEN];
197 char *p, *p2;
198 int line = 0;
199 PROFILESECTION *section, *first_section;
200 PROFILESECTION **next_section;
201 PROFILEKEY *key, *prev_key, **next_key;
203 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
204 if(first_section == NULL) return NULL;
205 first_section->name = NULL;
206 first_section->key = NULL;
207 first_section->next = NULL;
208 next_section = &first_section->next;
209 next_key = &first_section->key;
210 prev_key = NULL;
212 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
214 line++;
215 p = buffer;
216 while (*p && PROFILE_isspace(*p)) p++;
217 if (*p == '[') /* section start */
219 if (!(p2 = strrchr( p, ']' )))
221 WARN("Invalid section header at line %d: '%s'\n",
222 line, p );
224 else
226 *p2 = '\0';
227 p++;
228 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
229 if(section == NULL) break;
230 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
231 section->key = NULL;
232 section->next = NULL;
233 *next_section = section;
234 next_section = &section->next;
235 next_key = &section->key;
236 prev_key = NULL;
238 TRACE("New section: '%s'\n",section->name);
240 continue;
244 p2=p+strlen(p) - 1;
245 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
247 if ((p2 = strchr( p, '=' )) != NULL)
249 char *p3 = p2 - 1;
250 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
251 *p2++ = '\0';
252 while (*p2 && PROFILE_isspace(*p2)) p2++;
255 if(*p || !prev_key || *prev_key->name)
257 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
258 if(key == NULL) break;
259 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
260 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
261 key->next = NULL;
262 *next_key = key;
263 next_key = &key->next;
264 prev_key = key;
266 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
269 return first_section;
273 /***********************************************************************
274 * PROFILE_RegistryLoad
276 * Load a profile tree from a file into a registry key.
278 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
280 HKEY hkey = 0;
281 DWORD err = 0;
282 char buffer[PROFILE_MAX_LINE_LEN];
283 char *p, *p2;
284 int line = 0;
286 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
288 line++;
289 p = buffer;
290 while (*p && PROFILE_isspace(*p)) p++;
291 if (*p == '[') /* section start */
293 if (!(p2 = strrchr( p, ']' )))
295 WARN("Invalid section header at line %d: '%s'\n",
296 line, p );
298 else
300 *p2 = '\0';
301 p++;
302 if (hkey) RegCloseKey( hkey );
303 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
304 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
305 TRACE("New section: '%s'\n",p);
306 continue;
310 p2=p+strlen(p) - 1;
311 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
313 if ((p2 = strchr( p, '=' )) != NULL)
315 char *p3 = p2 - 1;
316 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
317 *p2++ = '\0';
318 while (*p2 && PROFILE_isspace(*p2)) p2++;
321 if (*p && hkey && !IS_ENTRY_COMMENT(p))
323 if (!p2) p2 = "";
324 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
326 RegCloseKey( hkey );
327 return err;
329 TRACE("New key: name='%s', value='%s'\n",p,p2);
332 if (hkey) RegCloseKey( hkey );
333 return 0;
337 /***********************************************************************
338 * PROFILE_DeleteSection
340 * Delete a section from a profile tree.
342 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
344 while (*section)
346 if ((*section)->name && !strcasecmp( (*section)->name, name ))
348 PROFILESECTION *to_del = *section;
349 *section = to_del->next;
350 to_del->next = NULL;
351 PROFILE_Free( to_del );
352 return TRUE;
354 section = &(*section)->next;
356 return FALSE;
360 /***********************************************************************
361 * PROFILE_DeleteKey
363 * Delete a key from a profile tree.
365 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
366 LPCSTR section_name, LPCSTR key_name )
368 while (*section)
370 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
372 PROFILEKEY **key = &(*section)->key;
373 while (*key)
375 if (!strcasecmp( (*key)->name, key_name ))
377 PROFILEKEY *to_del = *key;
378 *key = to_del->next;
379 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
380 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
381 HeapFree( GetProcessHeap(), 0, to_del );
382 return TRUE;
384 key = &(*key)->next;
387 section = &(*section)->next;
389 return FALSE;
393 /***********************************************************************
394 * PROFILE_DeleteAllKeys
396 * Delete all keys from a profile tree.
398 void PROFILE_DeleteAllKeys( LPCSTR section_name)
400 PROFILESECTION **section= &CurProfile->section;
401 while (*section)
403 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
405 PROFILEKEY **key = &(*section)->key;
406 while (*key)
408 PROFILEKEY *to_del = *key;
409 *key = to_del->next;
410 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
411 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
412 HeapFree( GetProcessHeap(), 0, to_del );
413 CurProfile->changed =TRUE;
416 section = &(*section)->next;
421 /***********************************************************************
422 * PROFILE_Find
424 * Find a key in a profile tree, optionally creating it.
426 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
427 const char *section_name,
428 const char *key_name, int create )
430 const char *p;
431 int seclen, keylen;
433 while (PROFILE_isspace(*section_name)) section_name++;
434 p = section_name + strlen(section_name) - 1;
435 while ((p > section_name) && PROFILE_isspace(*p)) p--;
436 seclen = p - section_name + 1;
438 while (PROFILE_isspace(*key_name)) key_name++;
439 p = key_name + strlen(key_name) - 1;
440 while ((p > key_name) && PROFILE_isspace(*p)) p--;
441 keylen = p - key_name + 1;
443 while (*section)
445 if ( ((*section)->name)
446 && (!(strncasecmp( (*section)->name, section_name, seclen )))
447 && (((*section)->name)[seclen] == '\0') )
449 PROFILEKEY **key = &(*section)->key;
450 while (*key)
452 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
453 && (((*key)->name)[keylen] == '\0') )
454 return *key;
455 key = &(*key)->next;
457 if (!create) return NULL;
458 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
459 if(*key == NULL) return NULL;
460 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
461 (*key)->value = NULL;
462 (*key)->next = NULL;
463 return *key;
465 section = &(*section)->next;
467 if (!create) return NULL;
468 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
469 if(*section == NULL) return NULL;
470 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
471 (*section)->next = NULL;
472 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
473 if((*section)->key == NULL)
475 HeapFree(GetProcessHeap(), 0, *section);
476 return NULL;
478 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
479 (*section)->key->value = NULL;
480 (*section)->key->next = NULL;
481 return (*section)->key;
485 /***********************************************************************
486 * PROFILE_FlushFile
488 * Flush the current profile to disk if changed.
490 static BOOL PROFILE_FlushFile(void)
492 char *p, buffer[MAX_PATHNAME_LEN];
493 const char *unix_name;
494 FILE *file = NULL;
495 struct stat buf;
497 if(!CurProfile)
499 WARN("No current profile!\n");
500 return FALSE;
503 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
504 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
506 /* Try to create it in $HOME/.wine */
507 /* FIXME: this will need a more general solution */
508 strcpy( buffer, get_config_dir() );
509 p = buffer + strlen(buffer);
510 *p++ = '/';
511 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
512 _strlwr( p );
513 file = fopen( buffer, "w" );
514 unix_name = buffer;
517 if (!file)
519 WARN("could not save profile file %s\n", CurProfile->dos_name);
520 return FALSE;
523 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
524 PROFILE_Save( file, CurProfile->section );
525 fclose( file );
526 CurProfile->changed = FALSE;
527 if(!stat(unix_name,&buf))
528 CurProfile->mtime=buf.st_mtime;
529 return TRUE;
533 /***********************************************************************
534 * PROFILE_ReleaseFile
536 * Flush the current profile to disk and remove it from the cache.
538 static void PROFILE_ReleaseFile(void)
540 PROFILE_FlushFile();
541 PROFILE_Free( CurProfile->section );
542 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
543 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
544 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
545 CurProfile->changed = FALSE;
546 CurProfile->section = NULL;
547 CurProfile->dos_name = NULL;
548 CurProfile->unix_name = NULL;
549 CurProfile->filename = NULL;
550 CurProfile->mtime = 0;
554 /***********************************************************************
555 * PROFILE_Open
557 * Open a profile file, checking the cached file first.
559 static BOOL PROFILE_Open( LPCSTR filename )
561 DOS_FULL_NAME full_name;
562 char buffer[MAX_PATHNAME_LEN];
563 char *newdos_name, *p;
564 FILE *file = NULL;
565 int i,j;
566 struct stat buf;
567 PROFILE *tempProfile;
569 /* First time around */
571 if(!CurProfile)
572 for(i=0;i<N_CACHED_PROFILES;i++)
574 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
575 if(MRUProfile[i] == NULL) break;
576 MRUProfile[i]->changed=FALSE;
577 MRUProfile[i]->section=NULL;
578 MRUProfile[i]->dos_name=NULL;
579 MRUProfile[i]->unix_name=NULL;
580 MRUProfile[i]->filename=NULL;
581 MRUProfile[i]->mtime=0;
584 /* Check for a match */
586 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
587 strchr( filename, ':' ))
589 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
591 else
593 GetWindowsDirectoryA( buffer, sizeof(buffer) );
594 strcat( buffer, "\\" );
595 strcat( buffer, filename );
596 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
599 for(i=0;i<N_CACHED_PROFILES;i++)
601 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
602 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
604 if(i)
606 PROFILE_FlushFile();
607 tempProfile=MRUProfile[i];
608 for(j=i;j>0;j--)
609 MRUProfile[j]=MRUProfile[j-1];
610 CurProfile=tempProfile;
612 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
613 TRACE("(%s): already opened (mru=%d)\n",
614 filename, i );
615 else
616 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
617 filename, i );
618 return TRUE;
622 /* Flush the old current profile */
623 PROFILE_FlushFile();
625 /* Make the oldest profile the current one only in order to get rid of it */
626 if(i==N_CACHED_PROFILES)
628 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
629 for(i=N_CACHED_PROFILES-1;i>0;i--)
630 MRUProfile[i]=MRUProfile[i-1];
631 CurProfile=tempProfile;
633 if(CurProfile->filename) PROFILE_ReleaseFile();
635 /* OK, now that CurProfile is definitely free we assign it our new file */
636 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
637 CurProfile->dos_name = newdos_name;
638 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
640 /* Try to open the profile file, first in $HOME/.wine */
642 /* FIXME: this will need a more general solution */
643 strcpy( buffer, get_config_dir() );
644 p = buffer + strlen(buffer);
645 *p++ = '/';
646 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
647 _strlwr( p );
648 if ((file = fopen( buffer, "r" )))
650 TRACE("(%s): found it in %s\n",
651 filename, buffer );
652 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
655 if (!file)
657 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
658 full_name.long_name );
659 if ((file = fopen( full_name.long_name, "r" )))
660 TRACE("(%s): found it in %s\n",
661 filename, full_name.long_name );
664 if (file)
666 CurProfile->section = PROFILE_Load( file );
667 fclose( file );
668 if(!stat(CurProfile->unix_name,&buf))
669 CurProfile->mtime=buf.st_mtime;
671 else
673 /* Does not exist yet, we will create it in PROFILE_FlushFile */
674 WARN("profile file %s not found\n", newdos_name );
676 return TRUE;
680 /***********************************************************************
681 * PROFILE_GetSection
683 * Returns all keys of a section.
684 * If return_values is TRUE, also include the corresponding values.
686 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
687 LPSTR buffer, UINT len, BOOL handle_env,
688 BOOL return_values )
690 PROFILEKEY *key;
691 while (section)
693 if (section->name && !strcasecmp( section->name, section_name ))
695 UINT oldlen = len;
696 for (key = section->key; key; key = key->next)
698 if (len <= 2) break;
699 if (!*key->name) continue; /* Skip empty lines */
700 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
701 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
702 len -= strlen(buffer) + 1;
703 buffer += strlen(buffer) + 1;
704 if (return_values && key->value) {
705 buffer[-1] = '=';
706 PROFILE_CopyEntry ( buffer,
707 key->value, len - 1, handle_env );
708 len -= strlen(buffer) + 1;
709 buffer += strlen(buffer) + 1;
712 *buffer = '\0';
713 if (len <= 1)
714 /*If either lpszSection or lpszKey is NULL and the supplied
715 destination buffer is too small to hold all the strings,
716 the last string is truncated and followed by two null characters.
717 In this case, the return value is equal to cchReturnBuffer
718 minus two. */
720 buffer[-1] = '\0';
721 return oldlen - 2;
723 return oldlen - len;
725 section = section->next;
727 buffer[0] = buffer[1] = '\0';
728 return 0;
732 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
734 LPSTR buf = buffer;
735 WORD l, cursize = 0;
736 PROFILESECTION *section;
738 for (section = CurProfile->section; section; section = section->next)
739 if (section->name) {
740 l = strlen(section->name);
741 cursize += l+1;
742 if (cursize > len+1)
743 return len-2;
745 strcpy(buf, section->name);
746 buf += l+1;
749 *buf=0;
750 buf++;
751 return buf-buffer;
755 /***********************************************************************
756 * PROFILE_GetString
758 * Get a profile string.
760 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
761 LPCSTR def_val, LPSTR buffer, UINT len )
763 PROFILEKEY *key = NULL;
765 if (!def_val) def_val = "";
766 if (key_name && key_name[0])
768 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
769 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
770 len, FALSE );
771 TRACE("('%s','%s','%s'): returning '%s'\n",
772 section, key_name, def_val, buffer );
773 return strlen( buffer );
775 if (key_name && !(key_name[0]))
776 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
777 return 0;
778 if (section && section[0])
779 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
780 FALSE, FALSE);
781 /* undocumented; both section and key_name are NULL */
782 return PROFILE_GetSectionNames(buffer, len);
786 /***********************************************************************
787 * PROFILE_SetString
789 * Set a profile string.
791 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
792 LPCSTR value )
794 if (!key_name) /* Delete a whole section */
796 TRACE("('%s')\n", section_name);
797 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
798 section_name );
799 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
800 this is not an error on application's level.*/
802 else if (!value) /* Delete a key */
804 TRACE("('%s','%s')\n",
805 section_name, key_name );
806 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
807 section_name, key_name );
808 return TRUE; /* same error handling as above */
810 else /* Set the key value */
812 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
813 key_name, TRUE );
814 TRACE("('%s','%s','%s'): \n",
815 section_name, key_name, value );
816 if (!key) return FALSE;
817 if (key->value)
819 /* strip the leading spaces. We can safely strip \n\r and
820 * friends too, they should not happen here anyway. */
821 while (PROFILE_isspace(*value)) value++;
823 if (!strcmp( key->value, value ))
825 TRACE(" no change needed\n" );
826 return TRUE; /* No change needed */
828 TRACE(" replacing '%s'\n", key->value );
829 HeapFree( GetProcessHeap(), 0, key->value );
831 else TRACE(" creating key\n" );
832 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
833 CurProfile->changed = TRUE;
835 return TRUE;
839 /***********************************************************************
840 * PROFILE_GetWineIniString
842 * Get a config string from the wine.ini file.
844 int PROFILE_GetWineIniString( const char *section, const char *key_name,
845 const char *def, char *buffer, int len )
847 char tmp[PROFILE_MAX_LINE_LEN];
848 HKEY hkey;
849 DWORD err;
851 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
853 DWORD type;
854 DWORD count = sizeof(tmp);
855 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
856 RegCloseKey( hkey );
858 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
859 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
860 return strlen(buffer);
864 /***********************************************************************
865 * PROFILE_EnumWineIniString
867 * Get a config string from the wine.ini file.
869 BOOL PROFILE_EnumWineIniString( const char *section, int index,
870 char *name, int name_len, char *buffer, int len )
872 char tmp[PROFILE_MAX_LINE_LEN];
873 HKEY hkey;
874 DWORD err, type;
875 DWORD count = sizeof(tmp);
877 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
878 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
879 RegCloseKey( hkey );
880 if (!err)
882 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
883 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
885 return !err;
889 /***********************************************************************
890 * PROFILE_GetWineIniInt
892 * Get a config integer from the wine.ini file.
894 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
896 char buffer[20];
897 char *p;
898 long result;
900 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
901 if (!buffer[0]) return def;
902 result = strtol( buffer, &p, 0 );
903 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
907 /******************************************************************************
909 * int PROFILE_GetWineIniBool(
910 * char const *section,
911 * char const *key_name,
912 * int def )
914 * Reads a boolean value from the wine.ini file. This function attempts to
915 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
916 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
917 * true. Anything else results in the return of the default value.
919 * This function uses 1 to indicate true, and 0 for false. You can check
920 * for existence by setting def to something other than 0 or 1 and
921 * examining the return value.
923 int PROFILE_GetWineIniBool(
924 char const *section,
925 char const *key_name,
926 int def )
928 char key_value[2];
929 int retval;
931 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
933 switch(key_value[0]) {
934 case 'n':
935 case 'N':
936 case 'f':
937 case 'F':
938 case '0':
939 retval = 0;
940 break;
942 case 'y':
943 case 'Y':
944 case 't':
945 case 'T':
946 case '1':
947 retval = 1;
948 break;
950 default:
951 retval = def;
954 TRACE("(\"%s\", \"%s\", %s), "
955 "[%c], ret %s.\n", section, key_name,
956 def ? "TRUE" : "FALSE", key_value[0],
957 retval ? "TRUE" : "FALSE");
959 return retval;
963 /***********************************************************************
964 * PROFILE_LoadWineIni
966 * Load the wine.ini file.
968 int PROFILE_LoadWineIni(void)
970 char buffer[MAX_PATHNAME_LEN];
971 const char *p;
972 FILE *f;
973 HKEY hKeySW;
974 DWORD disp;
976 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
977 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
979 ERR("Cannot create config registry key\n" );
980 return 0;
982 RegCloseKey( hKeySW );
983 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
984 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, &disp ))
986 ERR("Cannot create config registry key\n" );
987 return 0;
990 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
992 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
994 /* Open -config specified file */
995 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
996 goto found;
999 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
1001 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
1002 goto found;
1004 if ((p = getenv( "HOME" )) != NULL)
1006 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1007 strcat( buffer, PROFILE_WineIniName );
1008 if ((f = fopen( buffer, "r" )) != NULL)
1010 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1011 goto found;
1014 else WARN("could not get $HOME value for config file.\n" );
1016 /* Try global file */
1018 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
1020 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
1021 goto found;
1024 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1026 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1027 WINE_INI_GLOBAL, PROFILE_WineIniName );
1028 return 0;
1030 found:
1032 if (disp == REG_OPENED_EXISTING_KEY)
1034 MESSAGE( "Warning: configuration loaded by the server from %s/config,\n"
1035 " file %s was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1036 fclose( f );
1037 return 1;
1040 PROFILE_RegistryLoad( wine_profile_key, f );
1041 fclose( f );
1042 return 1;
1046 /***********************************************************************
1047 * PROFILE_UsageWineIni
1049 * Explain the wine.ini file to those who don't read documentation.
1050 * Keep below one screenful in length so that error messages above are
1051 * noticed.
1053 void PROFILE_UsageWineIni(void)
1055 MESSAGE("Perhaps you have not properly edited or created "
1056 "your Wine configuration file.\n");
1057 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1058 MESSAGE(" or it is determined by the -config option or from\n"
1059 " the WINE_INI environment variable.\n");
1060 if (*PROFILE_WineIniUsed)
1061 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1062 /* RTFM, so to say */
1065 /***********************************************************************
1066 * PROFILE_GetStringItem
1068 * Convenience function that turns a string 'xxx, yyy, zzz' into
1069 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1071 char* PROFILE_GetStringItem( char* start )
1073 char* lpchX, *lpch;
1075 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1077 if( *lpchX == ',' )
1079 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1080 while( *(++lpchX) )
1081 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1083 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1084 else lpch = NULL;
1086 if( lpch ) *lpch = '\0';
1087 return NULL;
1090 /********************* API functions **********************************/
1092 /***********************************************************************
1093 * GetProfileInt16 (KERNEL.57)
1095 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1097 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1101 /***********************************************************************
1102 * GetProfileIntA (KERNEL32.264)
1104 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1106 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1109 /***********************************************************************
1110 * GetProfileIntW (KERNEL32.264)
1112 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1114 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1117 /***********************************************************************
1118 * GetProfileString16 (KERNEL.58)
1120 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1121 LPSTR buffer, UINT16 len )
1123 return GetPrivateProfileString16( section, entry, def_val,
1124 buffer, len, "win.ini" );
1127 /***********************************************************************
1128 * GetProfileStringA (KERNEL32.268)
1130 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1131 LPSTR buffer, UINT len )
1133 return GetPrivateProfileStringA( section, entry, def_val,
1134 buffer, len, "win.ini" );
1137 /***********************************************************************
1138 * GetProfileStringW (KERNEL32.269)
1140 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1141 LPCWSTR def_val, LPWSTR buffer, UINT len )
1143 return GetPrivateProfileStringW( section, entry, def_val,
1144 buffer, len, wininiW );
1147 /***********************************************************************
1148 * WriteProfileString16 (KERNEL.59)
1150 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1151 LPCSTR string )
1153 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1156 /***********************************************************************
1157 * WriteProfileStringA (KERNEL32.587)
1159 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1160 LPCSTR string )
1162 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1165 /***********************************************************************
1166 * WriteProfileStringW (KERNEL32.588)
1168 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1169 LPCWSTR string )
1171 return WritePrivateProfileStringW( section, entry, string, wininiW );
1175 /***********************************************************************
1176 * GetPrivateProfileInt16 (KERNEL.127)
1178 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1179 INT16 def_val, LPCSTR filename )
1181 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1183 if (result > 65535) return 65535;
1184 if (result >= 0) return (UINT16)result;
1185 if (result < -32768) return -32768;
1186 return (UINT16)(INT16)result;
1189 /***********************************************************************
1190 * GetPrivateProfileIntA (KERNEL32.251)
1192 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1193 INT def_val, LPCSTR filename )
1195 char buffer[20];
1196 char *p;
1197 long result;
1199 GetPrivateProfileStringA( section, entry, "",
1200 buffer, sizeof(buffer), filename );
1201 if (!buffer[0]) return (UINT)def_val;
1202 result = strtol( buffer, &p, 0 );
1203 if (p == buffer) return 0; /* No digits at all */
1204 return (UINT)result;
1207 /***********************************************************************
1208 * GetPrivateProfileIntW (KERNEL32.252)
1210 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1211 INT def_val, LPCWSTR filename )
1213 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1214 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1215 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1216 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1217 HeapFree( GetProcessHeap(), 0, sectionA );
1218 HeapFree( GetProcessHeap(), 0, filenameA );
1219 HeapFree( GetProcessHeap(), 0, entryA );
1220 return res;
1223 /***********************************************************************
1224 * GetPrivateProfileString16 (KERNEL.128)
1226 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1227 LPCSTR def_val, LPSTR buffer,
1228 UINT16 len, LPCSTR filename )
1230 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1233 /***********************************************************************
1234 * GetPrivateProfileStringA (KERNEL32.255)
1236 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1237 LPCSTR def_val, LPSTR buffer,
1238 UINT len, LPCSTR filename )
1240 int ret;
1242 if (!filename)
1243 filename = "win.ini";
1245 EnterCriticalSection( &PROFILE_CritSect );
1247 if (PROFILE_Open( filename )) {
1248 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1249 } else {
1250 lstrcpynA( buffer, def_val, len );
1251 ret = strlen( buffer );
1254 LeaveCriticalSection( &PROFILE_CritSect );
1256 return ret;
1259 /***********************************************************************
1260 * GetPrivateProfileStringW (KERNEL32.256)
1262 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1263 LPCWSTR def_val, LPWSTR buffer,
1264 UINT len, LPCWSTR filename )
1266 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1267 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1268 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1269 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1270 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1271 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1272 bufferA, len, filenameA );
1273 lstrcpynAtoW( buffer, bufferA, len );
1274 HeapFree( GetProcessHeap(), 0, sectionA );
1275 HeapFree( GetProcessHeap(), 0, entryA );
1276 HeapFree( GetProcessHeap(), 0, filenameA );
1277 HeapFree( GetProcessHeap(), 0, def_valA );
1278 HeapFree( GetProcessHeap(), 0, bufferA);
1279 return ret;
1282 /***********************************************************************
1283 * GetPrivateProfileSection16 (KERNEL.418)
1285 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1286 UINT16 len, LPCSTR filename )
1288 return GetPrivateProfileSectionA( section, buffer, len, filename );
1291 /***********************************************************************
1292 * GetPrivateProfileSectionA (KERNEL32.255)
1294 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1295 DWORD len, LPCSTR filename )
1297 int ret = 0;
1299 EnterCriticalSection( &PROFILE_CritSect );
1301 if (PROFILE_Open( filename ))
1302 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1303 FALSE, TRUE);
1305 LeaveCriticalSection( &PROFILE_CritSect );
1307 return ret;
1310 /***********************************************************************
1311 * GetPrivateProfileSectionW (KERNEL32.256)
1314 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1315 DWORD len, LPCWSTR filename )
1318 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1319 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1320 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1321 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1322 filenameA );
1323 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1324 HeapFree( GetProcessHeap(), 0, sectionA );
1325 HeapFree( GetProcessHeap(), 0, filenameA );
1326 HeapFree( GetProcessHeap(), 0, bufferA);
1327 return ret;
1330 /***********************************************************************
1331 * GetProfileSection16 (KERNEL.419)
1333 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1335 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1338 /***********************************************************************
1339 * GetProfileSectionA (KERNEL32.268)
1341 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1343 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1346 /***********************************************************************
1347 * GetProfileSectionW (KERNEL32)
1349 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1351 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1355 /***********************************************************************
1356 * WritePrivateProfileString16 (KERNEL.129)
1358 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1359 LPCSTR string, LPCSTR filename )
1361 return WritePrivateProfileStringA(section,entry,string,filename);
1364 /***********************************************************************
1365 * WritePrivateProfileStringA (KERNEL32.582)
1367 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1368 LPCSTR string, LPCSTR filename )
1370 BOOL ret = FALSE;
1372 EnterCriticalSection( &PROFILE_CritSect );
1374 if (PROFILE_Open( filename ))
1376 if (!section && !entry && !string)
1377 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1378 else
1379 ret = PROFILE_SetString( section, entry, string );
1382 LeaveCriticalSection( &PROFILE_CritSect );
1383 return ret;
1386 /***********************************************************************
1387 * WritePrivateProfileStringW (KERNEL32.583)
1389 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1390 LPCWSTR string, LPCWSTR filename )
1392 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1393 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1394 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1395 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1396 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1397 stringA, filenameA );
1398 HeapFree( GetProcessHeap(), 0, sectionA );
1399 HeapFree( GetProcessHeap(), 0, entryA );
1400 HeapFree( GetProcessHeap(), 0, stringA );
1401 HeapFree( GetProcessHeap(), 0, filenameA );
1402 return res;
1405 /***********************************************************************
1406 * WritePrivateProfileSection16 (KERNEL.416)
1408 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1409 LPCSTR string, LPCSTR filename )
1411 return WritePrivateProfileSectionA( section, string, filename );
1414 /***********************************************************************
1415 * WritePrivateProfileSectionA (KERNEL32)
1417 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1418 LPCSTR string, LPCSTR filename )
1420 BOOL ret = FALSE;
1421 LPSTR p ;
1423 EnterCriticalSection( &PROFILE_CritSect );
1425 if (PROFILE_Open( filename )) {
1426 if (!section && !string && !filename)
1427 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1428 else if (!string) /* delete the named section*/
1429 ret = PROFILE_SetString(section,NULL,NULL);
1430 else {
1431 PROFILE_DeleteAllKeys(section);
1432 ret = TRUE;
1433 while(*string) {
1434 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1435 if((p=strchr( buf, '='))){
1436 *p='\0';
1437 ret = PROFILE_SetString( section, buf, p+1 );
1440 HeapFree( GetProcessHeap(), 0, buf );
1441 string += strlen(string)+1;
1447 LeaveCriticalSection( &PROFILE_CritSect );
1448 return ret;
1451 /***********************************************************************
1452 * WritePrivateProfileSectionW (KERNEL32)
1454 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1455 LPCWSTR string, LPCWSTR filename)
1458 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1459 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1460 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1461 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1462 HeapFree( GetProcessHeap(), 0, sectionA );
1463 HeapFree( GetProcessHeap(), 0, stringA );
1464 HeapFree( GetProcessHeap(), 0, filenameA );
1465 return res;
1468 /***********************************************************************
1469 * WriteProfileSection16 (KERNEL.417)
1471 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1473 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1476 /***********************************************************************
1477 * WriteProfileSectionA (KERNEL32.747)
1479 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1482 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1485 /***********************************************************************
1486 * WriteProfileSectionW (KERNEL32.748)
1488 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1490 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1493 /***********************************************************************
1494 * GetPrivateProfileSectionNames16 (KERNEL.143)
1496 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1497 LPCSTR filename )
1499 WORD ret = 0;
1501 EnterCriticalSection( &PROFILE_CritSect );
1503 if (PROFILE_Open( filename ))
1504 ret = PROFILE_GetSectionNames(buffer, size);
1506 LeaveCriticalSection( &PROFILE_CritSect );
1508 return ret;
1512 /***********************************************************************
1513 * GetProfileSectionNames16 (KERNEL.142)
1515 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1518 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1522 /***********************************************************************
1523 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1525 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1526 LPCSTR filename)
1529 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1533 /***********************************************************************
1534 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1536 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1537 LPCWSTR filename)
1540 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1541 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1543 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1544 lstrcpynAtoW( buffer, bufferA, size);
1545 HeapFree( GetProcessHeap(), 0, bufferA);
1546 HeapFree( GetProcessHeap(), 0, filenameA );
1548 return ret;
1551 /***********************************************************************
1552 * GetPrivateProfileStruct16 (KERNEL.407)
1554 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1555 LPVOID buf, UINT16 len, LPCSTR filename)
1557 return GetPrivateProfileStructA( section, key, buf, len, filename );
1560 /***********************************************************************
1561 * GetPrivateProfileStructA (KERNEL32.370)
1563 * Should match Win95's behaviour pretty much
1565 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1566 LPVOID buf, UINT len, LPCSTR filename)
1568 BOOL ret = FALSE;
1570 EnterCriticalSection( &PROFILE_CritSect );
1572 if (PROFILE_Open( filename )) {
1573 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1574 if (k) {
1575 TRACE("value (at %p): '%s'\n", k->value, k->value);
1576 if (((strlen(k->value) - 2) / 2) == len)
1578 LPSTR end, p;
1579 BOOL valid = TRUE;
1580 CHAR c;
1581 DWORD chksum = 0;
1583 end = k->value + strlen(k->value); /* -> '\0' */
1584 /* check for invalid chars in ASCII coded hex string */
1585 for (p=k->value; p < end; p++)
1587 if (!isxdigit(*p))
1589 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1590 *p, filename, section, key);
1591 valid = FALSE;
1592 break;
1595 if (valid)
1597 BOOL highnibble = TRUE;
1598 BYTE b = 0, val;
1599 LPBYTE binbuf = (LPBYTE)buf;
1601 end -= 2; /* don't include checksum in output data */
1602 /* translate ASCII hex format into binary data */
1603 for (p=k->value; p < end; p++)
1605 c = toupper(*p);
1606 val = (c > '9') ?
1607 (c - 'A' + 10) : (c - '0');
1609 if (highnibble)
1610 b = val << 4;
1611 else
1613 b += val;
1614 *binbuf++ = b; /* feed binary data into output */
1615 chksum += b; /* calculate checksum */
1617 highnibble ^= 1; /* toggle */
1619 /* retrieve stored checksum value */
1620 c = toupper(*p++);
1621 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1622 c = toupper(*p);
1623 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1624 if (b == (chksum & 0xff)) /* checksums match ? */
1625 ret = TRUE;
1630 LeaveCriticalSection( &PROFILE_CritSect );
1632 return ret;
1635 /***********************************************************************
1636 * GetPrivateProfileStructW (KERNEL32.543)
1638 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1639 LPVOID buffer, UINT len, LPCWSTR filename)
1641 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1642 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1643 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1644 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1646 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1647 len, filenameA );
1648 lstrcpynAtoW( buffer, bufferA, len );
1649 HeapFree( GetProcessHeap(), 0, bufferA);
1650 HeapFree( GetProcessHeap(), 0, sectionA );
1651 HeapFree( GetProcessHeap(), 0, keyA );
1652 HeapFree( GetProcessHeap(), 0, filenameA );
1654 return ret;
1659 /***********************************************************************
1660 * WritePrivateProfileStruct16 (KERNEL.406)
1662 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1663 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1665 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1668 /***********************************************************************
1669 * WritePrivateProfileStructA (KERNEL32.744)
1671 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1672 LPVOID buf, UINT bufsize, LPCSTR filename)
1674 BOOL ret = FALSE;
1675 LPBYTE binbuf;
1676 LPSTR outstring, p;
1677 DWORD sum = 0;
1679 if (!section && !key && !buf) /* flush the cache */
1680 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1682 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1683 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1684 p = outstring;
1685 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1686 *p++ = hex[*binbuf >> 4];
1687 *p++ = hex[*binbuf & 0xf];
1688 sum += *binbuf;
1690 /* checksum is sum & 0xff */
1691 *p++ = hex[(sum & 0xf0) >> 4];
1692 *p++ = hex[sum & 0xf];
1693 *p++ = '\0';
1695 EnterCriticalSection( &PROFILE_CritSect );
1697 if (PROFILE_Open( filename ))
1698 ret = PROFILE_SetString( section, key, outstring );
1700 LeaveCriticalSection( &PROFILE_CritSect );
1702 HeapFree( GetProcessHeap(), 0, outstring );
1704 return ret;
1707 /***********************************************************************
1708 * WritePrivateProfileStructW (KERNEL32.544)
1710 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1711 LPVOID buf, UINT bufsize, LPCWSTR filename)
1713 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1714 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1715 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1716 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1717 filenameA );
1718 HeapFree( GetProcessHeap(), 0, sectionA );
1719 HeapFree( GetProcessHeap(), 0, keyA );
1720 HeapFree( GetProcessHeap(), 0, filenameA );
1722 return ret;
1726 /***********************************************************************
1727 * WriteOutProfiles (KERNEL.315)
1729 void WINAPI WriteOutProfiles16(void)
1731 EnterCriticalSection( &PROFILE_CritSect );
1732 PROFILE_FlushFile();
1733 LeaveCriticalSection( &PROFILE_CritSect );
1736 /***********************************************************************
1737 * CloseProfileUserMapping (KERNEL.138)
1739 BOOL WINAPI CloseProfileUserMapping(void) {
1740 FIXME("(), stub!\n");
1741 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1742 return FALSE;