4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
13 #include <sys/types.h>
19 #include "wine/winbase16.h"
20 #include "wine/winestring.h"
26 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(profile
);
32 typedef struct tagPROFILEKEY
36 struct tagPROFILEKEY
*next
;
39 typedef struct tagPROFILESECTION
42 struct tagPROFILEKEY
*key
;
43 struct tagPROFILESECTION
*next
;
50 PROFILESECTION
*section
;
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 /***********************************************************************
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
,
99 if ((*value
== '\'') || (*value
== '\"'))
101 if (value
[1] && (value
[strlen(value
)-1] == *value
)) quote
= *value
++;
106 lstrcpynA( buffer
, value
, len
);
107 if (quote
&& (len
>= strlen(value
))) buffer
[strlen(buffer
)-1] = '\0';
111 for (p
= value
; (*p
&& (len
> 1)); *buffer
++ = *p
++, len
-- )
113 if ((*p
== '$') && (p
[1] == '{'))
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
);
129 if (quote
&& (len
> 1)) buffer
--;
134 /***********************************************************************
137 * Save a profile tree to a file.
139 static void PROFILE_Save( FILE *file
, PROFILESECTION
*section
)
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 /***********************************************************************
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) */
190 /***********************************************************************
193 * Load a profile tree from a file.
195 static PROFILESECTION
*PROFILE_Load( FILE *file
)
197 char buffer
[PROFILE_MAX_LINE_LEN
];
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
;
213 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
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",
229 section
= HeapAlloc( GetProcessHeap(), 0, sizeof(*section
) );
230 if(section
== NULL
) break;
231 section
->name
= HEAP_strdupA( GetProcessHeap(), 0, p
);
233 section
->next
= NULL
;
234 *next_section
= section
;
235 next_section
= §ion
->next
;
236 next_key
= §ion
->key
;
239 TRACE("New section: '%s'\n",section
->name
);
246 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
248 if ((p2
= strchr( p
, '=' )) != NULL
)
251 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\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
;
264 next_key
= &key
->next
;
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
)
283 char buffer
[PROFILE_MAX_LINE_LEN
];
287 while (fgets( buffer
, PROFILE_MAX_LINE_LEN
, file
))
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",
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
);
312 while ((p2
> p
) && ((*p2
== '\n') || PROFILE_isspace(*p2
))) *p2
--='\0';
314 if ((p2
= strchr( p
, '=' )) != NULL
)
317 while ((p3
> p
) && PROFILE_isspace(*p3
)) *p3
-- = '\0';
319 while (*p2
&& PROFILE_isspace(*p2
)) p2
++;
322 if (*p
&& hkey
&& !IS_ENTRY_COMMENT(p
))
325 if ((err
= RegSetValueExA( hkey
, p
, 0, REG_SZ
, p2
, strlen(p2
)+1 )))
330 TRACE("New key: name='%s', value='%s'\n",p
,p2
);
333 if (hkey
) RegCloseKey( hkey
);
338 /***********************************************************************
339 * PROFILE_DeleteSection
341 * Delete a section from a profile tree.
343 static BOOL
PROFILE_DeleteSection( PROFILESECTION
**section
, LPCSTR name
)
347 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, name
))
349 PROFILESECTION
*to_del
= *section
;
350 *section
= to_del
->next
;
352 PROFILE_Free( to_del
);
355 section
= &(*section
)->next
;
361 /***********************************************************************
364 * Delete a key from a profile tree.
366 static BOOL
PROFILE_DeleteKey( PROFILESECTION
**section
,
367 LPCSTR section_name
, LPCSTR key_name
)
371 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
373 PROFILEKEY
**key
= &(*section
)->key
;
376 if (!strcasecmp( (*key
)->name
, key_name
))
378 PROFILEKEY
*to_del
= *key
;
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
);
388 section
= &(*section
)->next
;
394 /***********************************************************************
395 * PROFILE_DeleteAllKeys
397 * Delete all keys from a profile tree.
399 void PROFILE_DeleteAllKeys( LPCSTR section_name
)
401 PROFILESECTION
**section
= &CurProfile
->section
;
404 if ((*section
)->name
&& !strcasecmp( (*section
)->name
, section_name
))
406 PROFILEKEY
**key
= &(*section
)->key
;
409 PROFILEKEY
*to_del
= *key
;
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 /***********************************************************************
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
)
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;
446 if ( ((*section
)->name
)
447 && (!(strncasecmp( (*section
)->name
, section_name
, seclen
)))
448 && (((*section
)->name
)[seclen
] == '\0') )
450 PROFILEKEY
**key
= &(*section
)->key
;
453 if ( (!(strncasecmp( (*key
)->name
, key_name
, keylen
)))
454 && (((*key
)->name
)[keylen
] == '\0') )
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
;
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
);
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 /***********************************************************************
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
;
500 WARN("No current profile!\n");
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
);
512 strcpy( p
, strrchr( CurProfile
->dos_name
, '\\' ) + 1 );
514 file
= fopen( buffer
, "w" );
520 WARN("could not save profile file %s\n", CurProfile
->dos_name
);
524 TRACE("Saving '%s' into '%s'\n", CurProfile
->dos_name
, unix_name
);
525 PROFILE_Save( file
, CurProfile
->section
);
527 CurProfile
->changed
= FALSE
;
528 if(!stat(unix_name
,&buf
))
529 CurProfile
->mtime
=buf
.st_mtime
;
534 /***********************************************************************
535 * PROFILE_ReleaseFile
537 * Flush the current profile to disk and remove it from the cache.
539 static void PROFILE_ReleaseFile(void)
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 /***********************************************************************
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
;
568 PROFILE
*tempProfile
;
570 /* First time around */
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
;
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
)))
608 tempProfile
=MRUProfile
[i
];
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",
617 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
623 /* Flush the old current profile */
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
);
647 strcpy( p
, strrchr( newdos_name
, '\\' ) + 1 );
649 if ((file
= fopen( buffer
, "r" )))
651 TRACE("(%s): found it in %s\n",
653 CurProfile
->unix_name
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
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
);
667 CurProfile
->section
= PROFILE_Load( file
);
669 if(!stat(CurProfile
->unix_name
,&buf
))
670 CurProfile
->mtime
=buf
.st_mtime
;
674 /* Does not exist yet, we will create it in PROFILE_FlushFile */
675 WARN("profile file %s not found\n", newdos_name
);
681 /***********************************************************************
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
,
694 if (section
->name
&& !strcasecmp( section
->name
, section_name
))
697 for (key
= section
->key
; key
; key
= key
->next
)
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
) {
707 PROFILE_CopyEntry ( buffer
,
708 key
->value
, len
- 1, handle_env
);
709 len
-= strlen(buffer
) + 1;
710 buffer
+= strlen(buffer
) + 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
726 section
= section
->next
;
728 buffer
[0] = buffer
[1] = '\0';
733 static INT
PROFILE_GetSectionNames( LPSTR buffer
, UINT len
)
737 PROFILESECTION
*section
;
739 for (section
= CurProfile
->section
; section
; section
= section
->next
)
741 l
= strlen(section
->name
);
746 strcpy(buf
, section
->name
);
756 /***********************************************************************
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
,
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*/
779 if (section
&& section
[0])
780 return PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
782 /* undocumented; both section and key_name are NULL */
783 return PROFILE_GetSectionNames(buffer
, len
);
787 /***********************************************************************
790 * Set a profile string.
792 static BOOL
PROFILE_SetString( LPCSTR section_name
, LPCSTR key_name
,
795 if (!key_name
) /* Delete a whole section */
797 TRACE("('%s')\n", section_name
);
798 CurProfile
->changed
|= PROFILE_DeleteSection( &CurProfile
->section
,
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
,
815 TRACE("('%s','%s','%s'): \n",
816 section_name
, key_name
, value
);
817 if (!key
) return FALSE
;
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
;
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
];
852 if (!(err
= RegOpenKeyA( wine_profile_key
, section
, &hkey
)))
855 DWORD count
= sizeof(tmp
);
856 err
= RegQueryValueExA( hkey
, key_name
, 0, &type
, tmp
, &count
);
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
];
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
);
883 PROFILE_CopyEntry( buffer
, tmp
, len
, TRUE
);
884 TRACE( "('%s',%d): returning '%s'='%s'\n", section
, index
, name
, buffer
);
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
)
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,
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(
926 char const *key_name
,
932 PROFILE_GetWineIniString(section
, key_name
, "~", key_value
, 2);
934 switch(key_value
[0]) {
955 TRACE("(\"%s\", \"%s\", %s), "
956 "[%c], ret %s.\n", section
, key_name
,
957 def
? "TRUE" : "FALSE", key_value
[0],
958 retval
? "TRUE" : "FALSE");
964 /***********************************************************************
965 * PROFILE_LoadWineIni
967 * Load the wine.ini file.
969 int PROFILE_LoadWineIni(void)
971 char buffer
[MAX_PATHNAME_LEN
];
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" );
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" );
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
);
1000 if ( (p
= getenv( "WINE_INI" )) && (f
= fopen( p
, "r" )) )
1002 lstrcpynA(PROFILE_WineIniUsed
,p
,MAX_PATHNAME_LEN
);
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
);
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
);
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
);
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
);
1041 PROFILE_RegistryLoad( wine_profile_key
, f
);
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
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
)
1076 for (lpchX
= start
, lpch
= NULL
; *lpchX
!= '\0'; lpchX
++ )
1080 if( lpch
) *lpch
= '\0'; else *lpchX
= '\0';
1082 if( !PROFILE_isspace(*lpchX
) ) return lpchX
;
1084 else if( PROFILE_isspace( *lpchX
) && !lpch
) lpch
= lpchX
;
1087 if( lpch
) *lpch
= '\0';
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
,
1154 return WritePrivateProfileString16( section
, entry
, string
, "win.ini" );
1157 /***********************************************************************
1158 * WriteProfileStringA (KERNEL32.587)
1160 BOOL WINAPI
WriteProfileStringA( LPCSTR section
, LPCSTR entry
,
1163 return WritePrivateProfileStringA( section
, entry
, string
, "win.ini" );
1166 /***********************************************************************
1167 * WriteProfileStringW (KERNEL32.588)
1169 BOOL WINAPI
WriteProfileStringW( LPCWSTR section
, LPCWSTR entry
,
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
)
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
);
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
)
1244 filename
= "win.ini";
1246 EnterCriticalSection( &PROFILE_CritSect
);
1248 if (PROFILE_Open( filename
)) {
1249 ret
= PROFILE_GetString( section
, entry
, def_val
, buffer
, len
);
1251 lstrcpynA( buffer
, def_val
, len
);
1252 ret
= strlen( buffer
);
1255 LeaveCriticalSection( &PROFILE_CritSect
);
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
);
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
)
1300 EnterCriticalSection( &PROFILE_CritSect
);
1302 if (PROFILE_Open( filename
))
1303 ret
= PROFILE_GetSection(CurProfile
->section
, section
, buffer
, len
,
1306 LeaveCriticalSection( &PROFILE_CritSect
);
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
,
1324 MultiByteToWideChar(CP_ACP
,0,bufferA
,ret
,buffer
,len
);
1325 HeapFree( GetProcessHeap(), 0, sectionA
);
1326 HeapFree( GetProcessHeap(), 0, filenameA
);
1327 HeapFree( GetProcessHeap(), 0, bufferA
);
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
)
1373 EnterCriticalSection( &PROFILE_CritSect
);
1375 if (PROFILE_Open( filename
))
1377 if (!section
&& !entry
&& !string
)
1378 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1380 ret
= PROFILE_SetString( section
, entry
, string
);
1383 LeaveCriticalSection( &PROFILE_CritSect
);
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
);
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
)
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
);
1432 PROFILE_DeleteAllKeys(section
);
1435 LPSTR buf
=HEAP_strdupA( GetProcessHeap(), 0, string
);
1436 if((p
=strchr( buf
, '='))){
1438 ret
= PROFILE_SetString( section
, buf
, p
+1 );
1441 HeapFree( GetProcessHeap(), 0, buf
);
1442 string
+= strlen(string
)+1;
1448 LeaveCriticalSection( &PROFILE_CritSect
);
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
);
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
,
1502 EnterCriticalSection( &PROFILE_CritSect
);
1504 if (PROFILE_Open( filename
))
1505 ret
= PROFILE_GetSectionNames(buffer
, size
);
1507 LeaveCriticalSection( &PROFILE_CritSect
);
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
,
1530 return (GetPrivateProfileSectionNames16 (buffer
,size
,filename
));
1534 /***********************************************************************
1535 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1537 DWORD WINAPI
GetPrivateProfileSectionNamesW( LPWSTR buffer
, DWORD size
,
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
);
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
)
1571 EnterCriticalSection( &PROFILE_CritSect
);
1573 if (PROFILE_Open( filename
)) {
1574 PROFILEKEY
*k
= PROFILE_Find ( &CurProfile
->section
, section
, key
, FALSE
);
1576 TRACE("value (at %p): '%s'\n", k
->value
, k
->value
);
1577 if (((strlen(k
->value
) - 2) / 2) == len
)
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
++)
1590 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1591 *p
, filename
, section
, key
);
1598 BOOL highnibble
= TRUE
;
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
++)
1608 (c
- 'A' + 10) : (c
- '0');
1615 *binbuf
++ = b
; /* feed binary data into output */
1616 chksum
+= b
; /* calculate checksum */
1618 highnibble
^= 1; /* toggle */
1620 /* retrieve stored checksum value */
1622 b
= ( (c
> '9') ? (c
- 'A' + 10) : (c
- '0') ) << 4;
1624 b
+= (c
> '9') ? (c
- 'A' + 10) : (c
- '0');
1625 if (b
== (chksum
& 0xff)) /* checksums match ? */
1631 LeaveCriticalSection( &PROFILE_CritSect
);
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
,
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
);
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
)
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);
1686 for (binbuf
= (LPBYTE
)buf
; binbuf
< (LPBYTE
)buf
+bufsize
; binbuf
++) {
1687 *p
++ = hex
[*binbuf
>> 4];
1688 *p
++ = hex
[*binbuf
& 0xf];
1691 /* checksum is sum & 0xff */
1692 *p
++ = hex
[(sum
& 0xf0) >> 4];
1693 *p
++ = hex
[sum
& 0xf];
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
);
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
,
1719 HeapFree( GetProcessHeap(), 0, sectionA
);
1720 HeapFree( GetProcessHeap(), 0, keyA
);
1721 HeapFree( GetProcessHeap(), 0, filenameA
);
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
);