4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
13 #include <sys/types.h>
19 #include "wine/winbase16.h"
27 #include "debugtools.h"
32 DEFAULT_DEBUG_CHANNEL(profile);
34 typedef struct tagPROFILEKEY
38 struct tagPROFILEKEY *next;
41 typedef struct tagPROFILESECTION
44 struct tagPROFILEKEY *key;
45 struct tagPROFILESECTION *next;
52 PROFILESECTION *section;
60 #define N_CACHED_PROFILES 10
62 /* Cached profile files */
63 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
65 #define CurProfile (MRUProfile[0])
67 /* wine.ini config file registry root */
68 static HKEY wine_profile_key;
70 #define PROFILE_MAX_LINE_LEN 1024
72 /* Wine profile name in $HOME directory; must begin with slash */
73 static const char PROFILE_WineIniName[] = "/.winerc";
75 /* Wine profile: the profile file being used */
76 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
78 /* Check for comments in profile */
79 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
81 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
82 #define WINE_CONFIG_DIR "/.wine" /* config dir inside $HOME */
84 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
86 static CRITICAL_SECTION PROFILE_CritSect;
88 static const char hex[16] = "0123456789ABCDEF";
90 /***********************************************************************
91 * PROFILE_GetConfigDir
93 * Return the name of the configuration directory ($HOME/.wine)
95 const char *PROFILE_GetConfigDir(void)
100 const char *home = getenv( "HOME" );
103 struct passwd *pwd = getpwuid( getuid() );
106 fprintf( stderr, "wine: could not find your home directory\n" );
111 confdir = xmalloc( strlen(home) + strlen(WINE_CONFIG_DIR) + 1 );
112 strcpy( confdir, home );
113 strcat( confdir, WINE_CONFIG_DIR );
114 mkdir( confdir, 0755 ); /* create it just in case */
120 /***********************************************************************
123 * Copy the content of an entry into a buffer, removing quotes, and possibly
124 * translating environment variables.
126 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
132 if ((*value == '\'') || (*value == '\"'))
134 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
139 lstrcpynA( buffer, value, len );
140 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
144 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
146 if ((*p == '$') && (p[1] == '{'))
150 const char *p2 = strchr( p, '}' );
151 if (!p2) continue; /* ignore it */
152 lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
153 if ((env_p = getenv( env_val )) != NULL)
155 lstrcpynA( buffer, env_p, len );
156 buffer += strlen( buffer );
157 len -= strlen( buffer );
162 if (quote && (len > 1)) buffer--;
167 /***********************************************************************
170 * Save a profile tree to a file.
172 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
176 for ( ; section; section = section->next)
178 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
179 for (key = section->key; key; key = key->next)
181 fprintf( file, "%s", key->name );
182 if (key->value) fprintf( file, "=%s", key->value );
183 fprintf( file, "\r\n" );
189 /***********************************************************************
192 * Free a profile tree.
194 static void PROFILE_Free( PROFILESECTION *section )
196 PROFILESECTION *next_section;
197 PROFILEKEY *key, *next_key;
199 for ( ; section; section = next_section)
201 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
202 for (key = section->key; key; key = next_key)
204 next_key = key->next;
205 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
206 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
207 HeapFree( GetProcessHeap(), 0, key );
209 next_section = section->next;
210 HeapFree( GetProcessHeap(), 0, section );
214 static inline int PROFILE_isspace(char c)
216 if (isspace(c)) return 1;
217 if (c=='\r' || c==0x1a) return 1;
218 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
223 /***********************************************************************
226 * Load a profile tree from a file.
228 static PROFILESECTION *PROFILE_Load( FILE *file )
230 char buffer[PROFILE_MAX_LINE_LEN];
233 PROFILESECTION *section, *first_section;
234 PROFILESECTION **next_section;
235 PROFILEKEY *key, *prev_key, **next_key;
237 first_section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section) );
238 first_section->name = NULL;
239 first_section->key = NULL;
240 first_section->next = NULL;
241 next_section = &first_section->next;
242 next_key = &first_section->key;
245 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
249 while (*p && PROFILE_isspace(*p)) p++;
250 if (*p == '[') /* section start */
252 if (!(p2 = strrchr( p, ']' )))
254 WARN("Invalid section header at line %d: '%s'\n",
261 section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section) );
262 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
264 section->next = NULL;
265 *next_section = section;
266 next_section = §ion->next;
267 next_key = §ion->key;
270 TRACE("New section: '%s'\n",section->name);
277 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
279 if ((p2 = strchr( p, '=' )) != NULL)
282 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
284 while (*p2 && PROFILE_isspace(*p2)) p2++;
287 if(*p || !prev_key || *prev_key->name)
289 key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*key) );
290 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
291 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
294 next_key = &key->next;
297 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
300 return first_section;
304 /***********************************************************************
305 * PROFILE_RegistryLoad
307 * Load a profile tree from a file into a registry key.
309 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
313 char buffer[PROFILE_MAX_LINE_LEN];
317 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
321 while (*p && PROFILE_isspace(*p)) p++;
322 if (*p == '[') /* section start */
324 if (!(p2 = strrchr( p, ']' )))
326 WARN("Invalid section header at line %d: '%s'\n",
333 if (hkey) RegCloseKey( hkey );
334 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
335 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
336 TRACE("New section: '%s'\n",p);
342 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
344 if ((p2 = strchr( p, '=' )) != NULL)
347 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
349 while (*p2 && PROFILE_isspace(*p2)) p2++;
352 if (*p && hkey && !IS_ENTRY_COMMENT(p))
355 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
360 TRACE("New key: name='%s', value='%s'\n",p,p2);
363 if (hkey) RegCloseKey( hkey );
368 /***********************************************************************
369 * PROFILE_DeleteSection
371 * Delete a section from a profile tree.
373 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
377 if ((*section)->name && !strcasecmp( (*section)->name, name ))
379 PROFILESECTION *to_del = *section;
380 *section = to_del->next;
382 PROFILE_Free( to_del );
385 section = &(*section)->next;
391 /***********************************************************************
394 * Delete a key from a profile tree.
396 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
397 LPCSTR section_name, LPCSTR key_name )
401 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
403 PROFILEKEY **key = &(*section)->key;
406 if (!strcasecmp( (*key)->name, key_name ))
408 PROFILEKEY *to_del = *key;
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 );
418 section = &(*section)->next;
424 /***********************************************************************
427 * Find a key in a profile tree, optionally creating it.
429 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
430 const char *section_name,
431 const char *key_name, int create )
436 while (PROFILE_isspace(*section_name)) section_name++;
437 p = section_name + strlen(section_name) - 1;
438 while ((p > section_name) && PROFILE_isspace(*p)) p--;
439 seclen = p - section_name + 1;
441 while (PROFILE_isspace(*key_name)) key_name++;
442 p = key_name + strlen(key_name) - 1;
443 while ((p > key_name) && PROFILE_isspace(*p)) p--;
444 keylen = p - key_name + 1;
448 if ( ((*section)->name)
449 && (!(strncasecmp( (*section)->name, section_name, seclen )))
450 && (((*section)->name)[seclen] == '\0') )
452 PROFILEKEY **key = &(*section)->key;
455 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
456 && (((*key)->name)[keylen] == '\0') )
460 if (!create) return NULL;
461 *key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
462 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
463 (*key)->value = NULL;
467 section = &(*section)->next;
469 if (!create) return NULL;
470 *section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
471 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
472 (*section)->next = NULL;
473 (*section)->key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
474 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
475 (*section)->key->value = NULL;
476 (*section)->key->next = NULL;
477 return (*section)->key;
481 /***********************************************************************
484 * Flush the current profile to disk if changed.
486 static BOOL PROFILE_FlushFile(void)
488 char *p, buffer[MAX_PATHNAME_LEN];
489 const char *unix_name;
495 WARN("No current profile!\n");
499 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
500 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
502 /* Try to create it in $HOME/.wine */
503 /* FIXME: this will need a more general solution */
504 strcpy( buffer, PROFILE_GetConfigDir() );
505 p = buffer + strlen(buffer);
507 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
509 file = fopen( buffer, "w" );
515 WARN("could not save profile file %s\n", CurProfile->dos_name);
519 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
520 PROFILE_Save( file, CurProfile->section );
522 CurProfile->changed = FALSE;
523 if(!stat(unix_name,&buf))
524 CurProfile->mtime=buf.st_mtime;
529 /***********************************************************************
530 * PROFILE_ReleaseFile
532 * Flush the current profile to disk and remove it from the cache.
534 static void PROFILE_ReleaseFile(void)
537 PROFILE_Free( CurProfile->section );
538 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
539 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
540 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
541 CurProfile->changed = FALSE;
542 CurProfile->section = NULL;
543 CurProfile->dos_name = NULL;
544 CurProfile->unix_name = NULL;
545 CurProfile->filename = NULL;
546 CurProfile->mtime = 0;
550 /***********************************************************************
553 * Open a profile file, checking the cached file first.
555 static BOOL PROFILE_Open( LPCSTR filename )
557 DOS_FULL_NAME full_name;
558 char buffer[MAX_PATHNAME_LEN];
559 char *newdos_name, *p;
563 PROFILE *tempProfile;
565 /* First time around */
568 for(i=0;i<N_CACHED_PROFILES;i++)
570 MRUProfile[i]=HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILE) );
571 MRUProfile[i]->changed=FALSE;
572 MRUProfile[i]->section=NULL;
573 MRUProfile[i]->dos_name=NULL;
574 MRUProfile[i]->unix_name=NULL;
575 MRUProfile[i]->filename=NULL;
576 MRUProfile[i]->mtime=0;
579 /* Check for a match */
581 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
582 strchr( filename, ':' ))
584 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
588 GetWindowsDirectoryA( buffer, sizeof(buffer) );
589 strcat( buffer, "\\" );
590 strcat( buffer, filename );
591 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
594 for(i=0;i<N_CACHED_PROFILES;i++)
596 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
597 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
602 tempProfile=MRUProfile[i];
604 MRUProfile[j]=MRUProfile[j-1];
605 CurProfile=tempProfile;
607 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
608 TRACE("(%s): already opened (mru=%d)\n",
611 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
617 /* Flush the old current profile */
620 /* Make the oldest profile the current one only in order to get rid of it */
621 if(i==N_CACHED_PROFILES)
623 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
624 for(i=N_CACHED_PROFILES-1;i>0;i--)
625 MRUProfile[i]=MRUProfile[i-1];
626 CurProfile=tempProfile;
628 if(CurProfile->filename) PROFILE_ReleaseFile();
630 /* OK, now that CurProfile is definitely free we assign it our new file */
631 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
632 CurProfile->dos_name = newdos_name;
633 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
635 /* Try to open the profile file, first in $HOME/.wine */
637 /* FIXME: this will need a more general solution */
638 strcpy( buffer, PROFILE_GetConfigDir() );
639 p = buffer + strlen(buffer);
641 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
643 if ((file = fopen( buffer, "r" )))
645 TRACE("(%s): found it in %s\n",
647 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
652 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
653 full_name.long_name );
654 if ((file = fopen( full_name.long_name, "r" )))
655 TRACE("(%s): found it in %s\n",
656 filename, full_name.long_name );
661 CurProfile->section = PROFILE_Load( file );
663 if(!stat(CurProfile->unix_name,&buf))
664 CurProfile->mtime=buf.st_mtime;
668 /* Does not exist yet, we will create it in PROFILE_FlushFile */
669 WARN("profile file %s not found\n", newdos_name );
675 /***********************************************************************
678 * Returns all keys of a section.
679 * If return_values is TRUE, also include the corresponding values.
681 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
682 LPSTR buffer, UINT len, BOOL handle_env,
688 if (section->name && !strcasecmp( section->name, section_name ))
691 for (key = section->key; key; key = key->next)
694 if (!*key->name) continue; /* Skip empty lines */
695 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
696 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
697 len -= strlen(buffer) + 1;
698 buffer += strlen(buffer) + 1;
699 if (return_values && key->value) {
701 PROFILE_CopyEntry ( buffer,
702 key->value, len - 1, handle_env );
703 len -= strlen(buffer) + 1;
704 buffer += strlen(buffer) + 1;
709 /*If either lpszSection or lpszKey is NULL and the supplied
710 destination buffer is too small to hold all the strings,
711 the last string is truncated and followed by two null characters.
712 In this case, the return value is equal to cchReturnBuffer
720 section = section->next;
722 buffer[0] = buffer[1] = '\0';
727 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
731 PROFILESECTION *section;
733 for (section = CurProfile->section; section; section = section->next)
735 l = strlen(section->name);
740 strcpy(buf, section->name);
750 /***********************************************************************
753 * Get a profile string.
755 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
756 LPCSTR def_val, LPSTR buffer, UINT len )
758 PROFILEKEY *key = NULL;
760 if (!def_val) def_val = "";
761 if (key_name && key_name[0])
763 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
764 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
766 TRACE("('%s','%s','%s'): returning '%s'\n",
767 section, key_name, def_val, buffer );
768 return strlen( buffer );
770 if (key_name && !(key_name[0]))
771 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
773 if (section && section[0])
774 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
776 /* undocumented; both section and key_name are NULL */
777 return PROFILE_GetSectionNames(buffer, len);
781 /***********************************************************************
784 * Set a profile string.
786 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
789 if (!key_name) /* Delete a whole section */
791 TRACE("('%s')\n", section_name);
792 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
794 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
795 this is not an error on application's level.*/
797 else if (!value) /* Delete a key */
799 TRACE("('%s','%s')\n",
800 section_name, key_name );
801 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
802 section_name, key_name );
803 return TRUE; /* same error handling as above */
805 else /* Set the key value */
807 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
809 TRACE("('%s','%s','%s'): \n",
810 section_name, key_name, value );
811 if (!key) return FALSE;
814 if (!strcmp( key->value, value ))
816 TRACE(" no change needed\n" );
817 return TRUE; /* No change needed */
819 TRACE(" replacing '%s'\n", key->value );
820 HeapFree( GetProcessHeap(), 0, key->value );
822 else TRACE(" creating key\n" );
823 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
824 CurProfile->changed = TRUE;
830 /***********************************************************************
831 * PROFILE_GetWineIniString
833 * Get a config string from the wine.ini file.
835 int PROFILE_GetWineIniString( const char *section, const char *key_name,
836 const char *def, char *buffer, int len )
838 char tmp[PROFILE_MAX_LINE_LEN];
842 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
845 DWORD count = sizeof(tmp);
846 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
849 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
850 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
851 return strlen(buffer);
855 /***********************************************************************
856 * PROFILE_EnumWineIniString
858 * Get a config string from the wine.ini file.
860 BOOL PROFILE_EnumWineIniString( const char *section, int index,
861 char *name, int name_len, char *buffer, int len )
863 char tmp[PROFILE_MAX_LINE_LEN];
866 DWORD count = sizeof(tmp);
868 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
869 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
873 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
874 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
880 /***********************************************************************
881 * PROFILE_GetWineIniInt
883 * Get a config integer from the wine.ini file.
885 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
891 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
892 if (!buffer[0]) return def;
893 result = strtol( buffer, &p, 0 );
894 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
898 /******************************************************************************
900 * int PROFILE_GetWineIniBool(
901 * char const *section,
902 * char const *key_name,
905 * Reads a boolean value from the wine.ini file. This function attempts to
906 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
907 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
908 * true. Anything else results in the return of the default value.
910 * This function uses 1 to indicate true, and 0 for false. You can check
911 * for existence by setting def to something other than 0 or 1 and
912 * examining the return value.
914 int PROFILE_GetWineIniBool(
916 char const *key_name,
922 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
924 switch(key_value[0]) {
945 TRACE("(\"%s\", \"%s\", %s), "
946 "[%c], ret %s.\n", section, key_name,
947 def ? "TRUE" : "FALSE", key_value[0],
948 retval ? "TRUE" : "FALSE");
954 /***********************************************************************
955 * PROFILE_LoadWineIni
957 * Load the wine.ini file.
959 int PROFILE_LoadWineIni(void)
961 char buffer[MAX_PATHNAME_LEN];
966 /* make sure HKLM\\Software exists as non-volatile key */
967 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software", &hKeySW ))
969 ERR("Cannot create config registry key\n" );
972 RegCloseKey( hKeySW );
973 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
974 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, NULL ))
976 ERR("Cannot create config registry key\n" );
979 wine_profile_key = ConvertToGlobalHandle( wine_profile_key );
981 InitializeCriticalSection( &PROFILE_CritSect );
982 MakeCriticalSectionGlobal( &PROFILE_CritSect );
984 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
986 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
988 /* Open -config specified file */
989 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
993 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
995 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
998 if ((p = getenv( "HOME" )) != NULL)
1000 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1001 strcat( buffer, PROFILE_WineIniName );
1002 if ((f = fopen( buffer, "r" )) != NULL)
1004 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1008 else WARN("could not get $HOME value for config file.\n" );
1010 /* Try global file */
1012 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
1014 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
1017 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1018 WINE_INI_GLOBAL, PROFILE_WineIniName );
1022 PROFILE_RegistryLoad( wine_profile_key, f );
1028 /***********************************************************************
1029 * PROFILE_UsageWineIni
1031 * Explain the wine.ini file to those who don't read documentation.
1032 * Keep below one screenful in length so that error messages above are
1035 void PROFILE_UsageWineIni(void)
1037 MESSAGE("Perhaps you have not properly edited or created "
1038 "your Wine configuration file.\n");
1039 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1040 MESSAGE(" or it is determined by the -config option or from\n"
1041 " the WINE_INI environment variable.\n");
1042 if (*PROFILE_WineIniUsed)
1043 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1044 /* RTFM, so to say */
1047 /***********************************************************************
1048 * PROFILE_GetStringItem
1050 * Convenience function that turns a string 'xxx, yyy, zzz' into
1051 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1053 char* PROFILE_GetStringItem( char* start )
1057 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1061 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1063 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1065 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1068 if( lpch ) *lpch = '\0';
1072 /********************* API functions **********************************/
1074 /***********************************************************************
1075 * GetProfileInt16 (KERNEL.57)
1077 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1079 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1083 /***********************************************************************
1084 * GetProfileInt32A (KERNEL32.264)
1086 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1088 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1091 /***********************************************************************
1092 * GetProfileInt32W (KERNEL32.264)
1094 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1096 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1099 /***********************************************************************
1100 * GetProfileString16 (KERNEL.58)
1102 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1103 LPSTR buffer, UINT16 len )
1105 return GetPrivateProfileString16( section, entry, def_val,
1106 buffer, len, "win.ini" );
1109 /***********************************************************************
1110 * GetProfileString32A (KERNEL32.268)
1112 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1113 LPSTR buffer, UINT len )
1115 return GetPrivateProfileStringA( section, entry, def_val,
1116 buffer, len, "win.ini" );
1119 /***********************************************************************
1120 * GetProfileString32W (KERNEL32.269)
1122 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1123 LPCWSTR def_val, LPWSTR buffer, UINT len )
1125 return GetPrivateProfileStringW( section, entry, def_val,
1126 buffer, len, wininiW );
1129 /***********************************************************************
1130 * WriteProfileString16 (KERNEL.59)
1132 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1135 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1138 /***********************************************************************
1139 * WriteProfileString32A (KERNEL32.587)
1141 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1144 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1147 /***********************************************************************
1148 * WriteProfileString32W (KERNEL32.588)
1150 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1153 return WritePrivateProfileStringW( section, entry, string, wininiW );
1157 /***********************************************************************
1158 * GetPrivateProfileInt16 (KERNEL.127)
1160 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1161 INT16 def_val, LPCSTR filename )
1163 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1165 if (result > 65535) return 65535;
1166 if (result >= 0) return (UINT16)result;
1167 if (result < -32768) return -32768;
1168 return (UINT16)(INT16)result;
1171 /***********************************************************************
1172 * GetPrivateProfileInt32A (KERNEL32.251)
1174 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1175 INT def_val, LPCSTR filename )
1181 GetPrivateProfileStringA( section, entry, "",
1182 buffer, sizeof(buffer), filename );
1183 if (!buffer[0]) return (UINT)def_val;
1184 result = strtol( buffer, &p, 0 );
1185 if (p == buffer) return 0; /* No digits at all */
1186 return (UINT)result;
1189 /***********************************************************************
1190 * GetPrivateProfileInt32W (KERNEL32.252)
1192 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1193 INT def_val, LPCWSTR filename )
1195 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1196 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1197 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1198 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1199 HeapFree( GetProcessHeap(), 0, sectionA );
1200 HeapFree( GetProcessHeap(), 0, filenameA );
1201 HeapFree( GetProcessHeap(), 0, entryA );
1205 /***********************************************************************
1206 * GetPrivateProfileString16 (KERNEL.128)
1208 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1209 LPCSTR def_val, LPSTR buffer,
1210 UINT16 len, LPCSTR filename )
1212 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1215 /***********************************************************************
1216 * GetPrivateProfileString32A (KERNEL32.255)
1218 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1219 LPCSTR def_val, LPSTR buffer,
1220 UINT len, LPCSTR filename )
1225 filename = "win.ini";
1227 EnterCriticalSection( &PROFILE_CritSect );
1229 if (PROFILE_Open( filename )) {
1230 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1232 lstrcpynA( buffer, def_val, len );
1233 ret = strlen( buffer );
1236 LeaveCriticalSection( &PROFILE_CritSect );
1241 /***********************************************************************
1242 * GetPrivateProfileString32W (KERNEL32.256)
1244 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1245 LPCWSTR def_val, LPWSTR buffer,
1246 UINT len, LPCWSTR filename )
1248 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1249 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1250 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1251 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1252 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1253 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1254 bufferA, len, filenameA );
1255 lstrcpynAtoW( buffer, bufferA, len );
1256 HeapFree( GetProcessHeap(), 0, sectionA );
1257 HeapFree( GetProcessHeap(), 0, entryA );
1258 HeapFree( GetProcessHeap(), 0, filenameA );
1259 HeapFree( GetProcessHeap(), 0, def_valA );
1260 HeapFree( GetProcessHeap(), 0, bufferA);
1264 /***********************************************************************
1265 * GetPrivateProfileSection16 (KERNEL.418)
1267 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1268 UINT16 len, LPCSTR filename )
1270 return GetPrivateProfileSectionA( section, buffer, len, filename );
1273 /***********************************************************************
1274 * GetPrivateProfileSection32A (KERNEL32.255)
1276 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1277 DWORD len, LPCSTR filename )
1281 EnterCriticalSection( &PROFILE_CritSect );
1283 if (PROFILE_Open( filename ))
1284 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1287 LeaveCriticalSection( &PROFILE_CritSect );
1292 /***********************************************************************
1293 * GetPrivateProfileSection32W (KERNEL32.256)
1296 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1297 DWORD len, LPCWSTR filename )
1300 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1301 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1302 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1303 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1305 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1306 HeapFree( GetProcessHeap(), 0, sectionA );
1307 HeapFree( GetProcessHeap(), 0, filenameA );
1308 HeapFree( GetProcessHeap(), 0, bufferA);
1312 /***********************************************************************
1313 * GetProfileSection16 (KERNEL.419)
1315 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1317 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1320 /***********************************************************************
1321 * GetProfileSection32A (KERNEL32.268)
1323 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1325 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1328 /***********************************************************************
1329 * GetProfileSection32W (KERNEL32)
1331 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1333 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1337 /***********************************************************************
1338 * WritePrivateProfileString16 (KERNEL.129)
1340 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1341 LPCSTR string, LPCSTR filename )
1343 return WritePrivateProfileStringA(section,entry,string,filename);
1346 /***********************************************************************
1347 * WritePrivateProfileString32A (KERNEL32.582)
1349 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1350 LPCSTR string, LPCSTR filename )
1354 EnterCriticalSection( &PROFILE_CritSect );
1356 if (PROFILE_Open( filename ))
1358 if (!section && !entry && !string)
1359 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1361 ret = PROFILE_SetString( section, entry, string );
1364 LeaveCriticalSection( &PROFILE_CritSect );
1368 /***********************************************************************
1369 * WritePrivateProfileString32W (KERNEL32.583)
1371 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1372 LPCWSTR string, LPCWSTR filename )
1374 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1375 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1376 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1377 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1378 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1379 stringA, filenameA );
1380 HeapFree( GetProcessHeap(), 0, sectionA );
1381 HeapFree( GetProcessHeap(), 0, entryA );
1382 HeapFree( GetProcessHeap(), 0, stringA );
1383 HeapFree( GetProcessHeap(), 0, filenameA );
1387 /***********************************************************************
1388 * WritePrivateProfileSection16 (KERNEL.416)
1390 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1391 LPCSTR string, LPCSTR filename )
1393 return WritePrivateProfileSectionA( section, string, filename );
1396 /***********************************************************************
1397 * WritePrivateProfileSectionA (KERNEL32)
1399 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1400 LPCSTR string, LPCSTR filename )
1405 EnterCriticalSection( &PROFILE_CritSect );
1407 if (PROFILE_Open( filename )) {
1408 if (!section && !string && !filename)
1409 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1412 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1413 if((p=strchr( buf, '='))){
1415 ret = PROFILE_SetString( section, buf, p+1 );
1418 HeapFree( GetProcessHeap(), 0, buf );
1419 string += strlen(string)+1;
1425 LeaveCriticalSection( &PROFILE_CritSect );
1429 /***********************************************************************
1430 * WritePrivateProfileSection32W (KERNEL32)
1432 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1433 LPCWSTR string, LPCWSTR filename)
1436 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1437 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1438 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1439 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1440 HeapFree( GetProcessHeap(), 0, sectionA );
1441 HeapFree( GetProcessHeap(), 0, stringA );
1442 HeapFree( GetProcessHeap(), 0, filenameA );
1446 /***********************************************************************
1447 * WriteProfileSection16 (KERNEL.417)
1449 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1451 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1454 /***********************************************************************
1455 * WriteProfileSection32A (KERNEL32.747)
1457 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1460 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1463 /***********************************************************************
1464 * WriteProfileSection32W (KERNEL32.748)
1466 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1468 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1471 /***********************************************************************
1472 * GetPrivateProfileSectionNames16 (KERNEL.143)
1474 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1479 EnterCriticalSection( &PROFILE_CritSect );
1481 if (PROFILE_Open( filename ))
1482 ret = PROFILE_GetSectionNames(buffer, size);
1484 LeaveCriticalSection( &PROFILE_CritSect );
1490 /***********************************************************************
1491 * GetProfileSectionNames16 (KERNEL.142)
1493 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1496 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1500 /***********************************************************************
1501 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1503 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1507 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1511 /***********************************************************************
1512 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1514 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1518 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1519 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1521 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1522 lstrcpynAtoW( buffer, bufferA, size);
1523 HeapFree( GetProcessHeap(), 0, bufferA);
1524 HeapFree( GetProcessHeap(), 0, filenameA );
1529 /***********************************************************************
1530 * GetPrivateProfileStruct16 (KERNEL.407)
1532 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1533 LPVOID buf, UINT16 len, LPCSTR filename)
1535 return GetPrivateProfileStructA( section, key, buf, len, filename );
1538 /***********************************************************************
1539 * GetPrivateProfileStruct32A (KERNEL32.370)
1541 * Should match Win95's behaviour pretty much
1543 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1544 LPVOID buf, UINT len, LPCSTR filename)
1548 EnterCriticalSection( &PROFILE_CritSect );
1550 if (PROFILE_Open( filename )) {
1551 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1553 TRACE("value (at %p): '%s'\n", k->value, k->value);
1554 if (((strlen(k->value) - 2) / 2) == len)
1561 end = k->value + strlen(k->value); /* -> '\0' */
1562 /* check for invalid chars in ASCII coded hex string */
1563 for (p=k->value; p < end; p++)
1567 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1568 *p, filename, section, key);
1575 BOOL highnibble = TRUE;
1577 LPBYTE binbuf = (LPBYTE)buf;
1579 end -= 2; /* don't include checksum in output data */
1580 /* translate ASCII hex format into binary data */
1581 for (p=k->value; p < end; p++)
1585 (c - 'A' + 10) : (c - '0');
1592 *binbuf++ = b; /* feed binary data into output */
1593 chksum += b; /* calculate checksum */
1595 highnibble ^= 1; /* toggle */
1597 /* retrieve stored checksum value */
1599 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1601 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1602 if (b == (chksum & 0xff)) /* checksums match ? */
1608 LeaveCriticalSection( &PROFILE_CritSect );
1613 /***********************************************************************
1614 * GetPrivateProfileStruct32W (KERNEL32.543)
1616 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1617 LPVOID buffer, UINT len, LPCWSTR filename)
1619 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1620 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1621 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1622 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1624 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1626 lstrcpynAtoW( buffer, bufferA, len );
1627 HeapFree( GetProcessHeap(), 0, bufferA);
1628 HeapFree( GetProcessHeap(), 0, sectionA );
1629 HeapFree( GetProcessHeap(), 0, keyA );
1630 HeapFree( GetProcessHeap(), 0, filenameA );
1637 /***********************************************************************
1638 * WritePrivateProfileStruct16 (KERNEL.406)
1640 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1641 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1643 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1646 /***********************************************************************
1647 * WritePrivateProfileStruct32A (KERNEL32.744)
1649 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1650 LPVOID buf, UINT bufsize, LPCSTR filename)
1657 if (!section && !key && !buf) /* flush the cache */
1658 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1660 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1661 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1663 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1664 *p++ = hex[*binbuf >> 4];
1665 *p++ = hex[*binbuf & 0xf];
1668 /* checksum is sum & 0xff */
1669 *p++ = hex[(sum & 0xf0) >> 4];
1670 *p++ = hex[sum & 0xf];
1673 EnterCriticalSection( &PROFILE_CritSect );
1675 if (PROFILE_Open( filename ))
1676 ret = PROFILE_SetString( section, key, outstring );
1678 LeaveCriticalSection( &PROFILE_CritSect );
1680 HeapFree( GetProcessHeap(), 0, outstring );
1685 /***********************************************************************
1686 * WritePrivateProfileStruct32W (KERNEL32.544)
1688 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1689 LPVOID buf, UINT bufsize, LPCWSTR filename)
1691 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1692 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1693 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1694 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1696 HeapFree( GetProcessHeap(), 0, sectionA );
1697 HeapFree( GetProcessHeap(), 0, keyA );
1698 HeapFree( GetProcessHeap(), 0, filenameA );
1704 /***********************************************************************
1705 * WriteOutProfiles (KERNEL.315)
1707 void WINAPI WriteOutProfiles16(void)
1709 EnterCriticalSection( &PROFILE_CritSect );
1710 PROFILE_FlushFile();
1711 LeaveCriticalSection( &PROFILE_CritSect );
1714 /***********************************************************************
1715 * CloseProfileUserMapping (KERNEL.138)
1717 BOOL WINAPI CloseProfileUserMapping(void) {
1718 FIXME("(), stub!\n");
1719 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);