blob: b198dca43da10dc26751da1f2dc978e27474043e [file] [log] [blame]
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001/*
2 * Profile functions
3 *
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
7
8#include <ctype.h>
Alexandre Julliard95153362001-03-23 19:13:23 +00009#include <errno.h>
Alexandre Julliard73be8d12000-12-06 20:25:11 +000010#include <fcntl.h>
Alexandre Julliard02ed4c21996-03-02 19:34:10 +000011#include <stdlib.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000012#include <string.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +000013#include <stdio.h>
Alexandre Julliard829fe321998-07-26 14:27:39 +000014#include <sys/stat.h>
Alexandre Julliard647876e2000-01-25 01:35:01 +000015#include <sys/types.h>
16#include <pwd.h>
17#include <unistd.h>
Alexandre Julliard829fe321998-07-26 14:27:39 +000018
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000019#include "windef.h"
Marcus Meissner317af321999-02-17 13:51:06 +000020#include "winbase.h"
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000021#include "winnls.h"
Marcus Meissner9b4fcf71999-12-04 04:19:55 +000022#include "winerror.h"
Marcus Meissner317af321999-02-17 13:51:06 +000023#include "wine/winbase16.h"
Alexandre Julliard00377a72000-02-19 20:50:00 +000024#include "winreg.h"
Alexandre Julliardc6c09441997-01-12 18:32:19 +000025#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000026#include "heap.h"
Alexandre Julliard359f497e1999-07-04 16:02:24 +000027#include "debugtools.h"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000028#include "options.h"
Alexandre Julliard00377a72000-02-19 20:50:00 +000029#include "server.h"
Alexandre Julliard7e56f681996-01-31 19:02:28 +000030
Jeremy Whited3e22d92000-02-10 19:03:02 +000031DEFAULT_DEBUG_CHANNEL(profile);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000032
Alexandre Julliard7e56f681996-01-31 19:02:28 +000033typedef struct tagPROFILEKEY
34{
35 char *name;
36 char *value;
37 struct tagPROFILEKEY *next;
38} PROFILEKEY;
39
40typedef struct tagPROFILESECTION
41{
42 char *name;
43 struct tagPROFILEKEY *key;
44 struct tagPROFILESECTION *next;
45} PROFILESECTION;
46
47
48typedef struct
49{
Eric Poueched155751999-03-25 13:24:08 +000050 BOOL changed;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000051 PROFILESECTION *section;
52 char *dos_name;
Alexandre Julliardc6c09441997-01-12 18:32:19 +000053 char *unix_name;
54 char *filename;
Alexandre Julliard829fe321998-07-26 14:27:39 +000055 time_t mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000056} PROFILE;
57
58
Alexandre Julliard829fe321998-07-26 14:27:39 +000059#define N_CACHED_PROFILES 10
60
61/* Cached profile files */
62static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
63
64#define CurProfile (MRUProfile[0])
Alexandre Julliard7e56f681996-01-31 19:02:28 +000065
Alexandre Julliard00377a72000-02-19 20:50:00 +000066/* wine.ini config file registry root */
67static HKEY wine_profile_key;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000068
69#define PROFILE_MAX_LINE_LEN 1024
70
71/* Wine profile name in $HOME directory; must begin with slash */
72static const char PROFILE_WineIniName[] = "/.winerc";
73
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000074/* Wine profile: the profile file being used */
75static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
76
Alexandre Julliard7e56f681996-01-31 19:02:28 +000077/* Check for comments in profile */
78#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
79
Alexandre Julliard00377a72000-02-19 20:50:00 +000080static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000081
Alexandre Julliard227a0892000-04-08 21:06:06 +000082static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
Eric Poueched155751999-03-25 13:24:08 +000083
Andreas Mohr17b1f462000-01-30 21:15:14 +000084static const char hex[16] = "0123456789ABCDEF";
Alexandre Julliard647876e2000-01-25 01:35:01 +000085
86/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +000087 * PROFILE_CopyEntry
88 *
89 * Copy the content of an entry into a buffer, removing quotes, and possibly
90 * translating environment variables.
91 */
92static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
93 int handle_env )
94{
95 char quote = '\0';
96 const char *p;
97
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +000098 if(!buffer) return;
99
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000100 if ((*value == '\'') || (*value == '\"'))
101 {
102 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
103 }
104
105 if (!handle_env)
106 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000107 lstrcpynA( buffer, value, len );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000108 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
109 return;
110 }
111
112 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
113 {
114 if ((*p == '$') && (p[1] == '{'))
115 {
116 char env_val[1024];
117 const char *env_p;
118 const char *p2 = strchr( p, '}' );
119 if (!p2) continue; /* ignore it */
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000120 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000121 if ((env_p = getenv( env_val )) != NULL)
122 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000123 lstrcpynA( buffer, env_p, len );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000124 buffer += strlen( buffer );
125 len -= strlen( buffer );
126 }
127 p = p2 + 1;
128 }
129 }
Eric Pouechf54c95f1999-10-31 17:32:57 +0000130 if (quote && (len > 1)) buffer--;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000131 *buffer = '\0';
132}
133
134
135/***********************************************************************
136 * PROFILE_Save
137 *
138 * Save a profile tree to a file.
139 */
140static void PROFILE_Save( FILE *file, PROFILESECTION *section )
141{
142 PROFILEKEY *key;
143
144 for ( ; section; section = section->next)
145 {
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000146 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000147 for (key = section->key; key; key = key->next)
148 {
149 fprintf( file, "%s", key->name );
150 if (key->value) fprintf( file, "=%s", key->value );
Alexandre Julliard7d654eb1996-02-25 11:36:22 +0000151 fprintf( file, "\r\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000152 }
153 }
154}
155
156
157/***********************************************************************
158 * PROFILE_Free
159 *
160 * Free a profile tree.
161 */
162static void PROFILE_Free( PROFILESECTION *section )
163{
164 PROFILESECTION *next_section;
165 PROFILEKEY *key, *next_key;
166
167 for ( ; section; section = next_section)
168 {
Alexandre Julliard90476d62000-02-16 22:47:24 +0000169 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000170 for (key = section->key; key; key = next_key)
171 {
172 next_key = key->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000173 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
174 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
175 HeapFree( GetProcessHeap(), 0, key );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000176 }
177 next_section = section->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000178 HeapFree( GetProcessHeap(), 0, section );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000179 }
180}
181
Andreas Mohr17b1f462000-01-30 21:15:14 +0000182static inline int PROFILE_isspace(char c)
183{
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000184 if (isspace(c)) return 1;
185 if (c=='\r' || c==0x1a) return 1;
186 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
187 return 0;
188}
189
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000190
191/***********************************************************************
192 * PROFILE_Load
193 *
194 * Load a profile tree from a file.
195 */
196static PROFILESECTION *PROFILE_Load( FILE *file )
197{
198 char buffer[PROFILE_MAX_LINE_LEN];
199 char *p, *p2;
200 int line = 0;
201 PROFILESECTION *section, *first_section;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000202 PROFILESECTION **next_section;
203 PROFILEKEY *key, *prev_key, **next_key;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000204
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000205 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
206 if(first_section == NULL) return NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000207 first_section->name = NULL;
208 first_section->key = NULL;
209 first_section->next = NULL;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000210 next_section = &first_section->next;
211 next_key = &first_section->key;
212 prev_key = NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000213
214 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
215 {
216 line++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000217 p = buffer;
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000218 while (*p && PROFILE_isspace(*p)) p++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000219 if (*p == '[') /* section start */
220 {
221 if (!(p2 = strrchr( p, ']' )))
222 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000223 WARN("Invalid section header at line %d: '%s'\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000224 line, p );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000225 }
226 else
227 {
228 *p2 = '\0';
229 p++;
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000230 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
231 if(section == NULL) break;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000232 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000233 section->key = NULL;
234 section->next = NULL;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000235 *next_section = section;
236 next_section = &section->next;
237 next_key = &section->key;
238 prev_key = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000239
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000240 TRACE("New section: '%s'\n",section->name);
Alexandre Julliard829fe321998-07-26 14:27:39 +0000241
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000242 continue;
243 }
244 }
Alexandre Julliard829fe321998-07-26 14:27:39 +0000245
246 p2=p+strlen(p) - 1;
247 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
248
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000249 if ((p2 = strchr( p, '=' )) != NULL)
250 {
251 char *p3 = p2 - 1;
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000252 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000253 *p2++ = '\0';
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000254 while (*p2 && PROFILE_isspace(*p2)) p2++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000255 }
Alexandre Julliard642d3131998-07-12 19:29:36 +0000256
257 if(*p || !prev_key || *prev_key->name)
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000258 {
259 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
260 if(key == NULL) break;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000261 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
262 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000263 key->next = NULL;
264 *next_key = key;
265 next_key = &key->next;
266 prev_key = key;
267
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000268 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000269 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000270 }
271 return first_section;
272}
273
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000274/* convert the .winerc file to the new format */
Alexandre Julliard95153362001-03-23 19:13:23 +0000275static void convert_config( FILE *in, const char *output_name )
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000276{
277 char buffer[PROFILE_MAX_LINE_LEN];
278 char *p, *p2;
279 FILE *out;
280
281 /* create the output file, only if it doesn't exist already */
282 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
Alexandre Julliard95153362001-03-23 19:13:23 +0000283 if (fd == -1)
284 {
285 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
286 ExitProcess(1);
287 }
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000288
289 out = fdopen( fd, "w" );
290 fprintf( out, "WINE REGISTRY Version 2\n" );
291 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
292 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
293 {
294 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
295 p = buffer;
296 while (*p && PROFILE_isspace(*p)) p++;
297 if (*p == '[') /* section start */
298 {
299 if ((p2 = strrchr( p, ']' )))
300 {
301 *p2 = '\0';
302 p++;
303 fprintf( out, "[%s]\n", p );
304 }
305 continue;
306 }
307
308 if (*p == ';' || *p == '#')
309 {
310 fprintf( out, "%s\n", p );
311 continue;
312 }
313
314 p2=p+strlen(p) - 1;
315 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
316
317 if ((p2 = strchr( p, '=' )) != NULL)
318 {
319 char *p3 = p2 - 1;
320 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
321 *p2++ = '\0';
322 while (*p2 && PROFILE_isspace(*p2)) p2++;
323 }
324
325 if (!*p)
326 {
327 fprintf( out, "\n" );
328 continue;
329 }
330 fputc( '"', out );
331 while (*p)
332 {
333 if (*p == '\\') fputc( '\\', out );
334 fputc( *p, out );
335 p++;
336 }
337 fprintf( out, "\" = \"" );
Alexandre Julliard550ba5b2001-01-05 22:23:37 +0000338 if (p2)
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000339 {
Alexandre Julliard550ba5b2001-01-05 22:23:37 +0000340 while (*p2)
341 {
342 if (*p2 == '\\') fputc( '\\', out );
343 fputc( *p2, out );
344 p2++;
345 }
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000346 }
347 fprintf( out, "\"\n" );
348 }
349 fclose( out );
Alexandre Julliard00377a72000-02-19 20:50:00 +0000350}
351
352
353/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000354 * PROFILE_DeleteSection
355 *
356 * Delete a section from a profile tree.
357 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000358static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000359{
360 while (*section)
361 {
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000362 if ((*section)->name && !strcasecmp( (*section)->name, name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000363 {
364 PROFILESECTION *to_del = *section;
365 *section = to_del->next;
366 to_del->next = NULL;
367 PROFILE_Free( to_del );
368 return TRUE;
369 }
370 section = &(*section)->next;
371 }
372 return FALSE;
373}
374
375
376/***********************************************************************
377 * PROFILE_DeleteKey
378 *
379 * Delete a key from a profile tree.
380 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000381static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
Eric Poueched155751999-03-25 13:24:08 +0000382 LPCSTR section_name, LPCSTR key_name )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000383{
384 while (*section)
385 {
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000386 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000387 {
388 PROFILEKEY **key = &(*section)->key;
389 while (*key)
390 {
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000391 if (!strcasecmp( (*key)->name, key_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000392 {
393 PROFILEKEY *to_del = *key;
394 *key = to_del->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000395 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
396 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
397 HeapFree( GetProcessHeap(), 0, to_del );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000398 return TRUE;
399 }
400 key = &(*key)->next;
401 }
402 }
403 section = &(*section)->next;
404 }
405 return FALSE;
406}
407
408
409/***********************************************************************
Uwe Bonnesd88fbb72000-06-20 20:48:46 +0000410 * PROFILE_DeleteAllKeys
411 *
412 * Delete all keys from a profile tree.
413 */
414void PROFILE_DeleteAllKeys( LPCSTR section_name)
415{
416 PROFILESECTION **section= &CurProfile->section;
417 while (*section)
418 {
419 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
420 {
421 PROFILEKEY **key = &(*section)->key;
422 while (*key)
423 {
424 PROFILEKEY *to_del = *key;
425 *key = to_del->next;
426 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
427 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
428 HeapFree( GetProcessHeap(), 0, to_del );
429 CurProfile->changed =TRUE;
430 }
431 }
432 section = &(*section)->next;
433 }
434}
435
436
437/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000438 * PROFILE_Find
439 *
440 * Find a key in a profile tree, optionally creating it.
441 */
442static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
443 const char *section_name,
444 const char *key_name, int create )
445{
Andreas Mohr17b1f462000-01-30 21:15:14 +0000446 const char *p;
447 int seclen, keylen;
448
449 while (PROFILE_isspace(*section_name)) section_name++;
450 p = section_name + strlen(section_name) - 1;
451 while ((p > section_name) && PROFILE_isspace(*p)) p--;
452 seclen = p - section_name + 1;
453
454 while (PROFILE_isspace(*key_name)) key_name++;
455 p = key_name + strlen(key_name) - 1;
456 while ((p > key_name) && PROFILE_isspace(*p)) p--;
457 keylen = p - key_name + 1;
458
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000459 while (*section)
460 {
Andreas Mohr17b1f462000-01-30 21:15:14 +0000461 if ( ((*section)->name)
462 && (!(strncasecmp( (*section)->name, section_name, seclen )))
463 && (((*section)->name)[seclen] == '\0') )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000464 {
465 PROFILEKEY **key = &(*section)->key;
466 while (*key)
467 {
Andreas Mohr17b1f462000-01-30 21:15:14 +0000468 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
469 && (((*key)->name)[keylen] == '\0') )
470 return *key;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000471 key = &(*key)->next;
472 }
473 if (!create) return NULL;
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000474 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
475 if(*key == NULL) return NULL;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000476 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000477 (*key)->value = NULL;
478 (*key)->next = NULL;
479 return *key;
480 }
481 section = &(*section)->next;
482 }
483 if (!create) return NULL;
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000484 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
485 if(*section == NULL) return NULL;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000486 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000487 (*section)->next = NULL;
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000488 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
489 if((*section)->key == NULL)
490 {
491 HeapFree(GetProcessHeap(), 0, *section);
492 return NULL;
493 }
Alexandre Julliard90476d62000-02-16 22:47:24 +0000494 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000495 (*section)->key->value = NULL;
496 (*section)->key->next = NULL;
497 return (*section)->key;
498}
499
500
501/***********************************************************************
502 * PROFILE_FlushFile
503 *
504 * Flush the current profile to disk if changed.
505 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000506static BOOL PROFILE_FlushFile(void)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000507{
508 char *p, buffer[MAX_PATHNAME_LEN];
509 const char *unix_name;
510 FILE *file = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000511 struct stat buf;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000512
Alexandre Julliard829fe321998-07-26 14:27:39 +0000513 if(!CurProfile)
514 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000515 WARN("No current profile!\n");
Alexandre Julliard829fe321998-07-26 14:27:39 +0000516 return FALSE;
517 }
518
519 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
520 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000521 {
522 /* Try to create it in $HOME/.wine */
523 /* FIXME: this will need a more general solution */
Alexandre Julliardde1d5ad2000-04-06 20:36:17 +0000524 strcpy( buffer, get_config_dir() );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000525 p = buffer + strlen(buffer);
526 *p++ = '/';
527 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
Alexandre Julliarddcd247e2000-08-14 17:39:15 +0000528 _strlwr( p );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000529 file = fopen( buffer, "w" );
530 unix_name = buffer;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000531 }
532
533 if (!file)
534 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000535 WARN("could not save profile file %s\n", CurProfile->dos_name);
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000536 return FALSE;
537 }
538
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000539 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000540 PROFILE_Save( file, CurProfile->section );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000541 fclose( file );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000542 CurProfile->changed = FALSE;
543 if(!stat(unix_name,&buf))
544 CurProfile->mtime=buf.st_mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000545 return TRUE;
546}
547
548
549/***********************************************************************
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000550 * PROFILE_ReleaseFile
551 *
552 * Flush the current profile to disk and remove it from the cache.
553 */
554static void PROFILE_ReleaseFile(void)
555{
556 PROFILE_FlushFile();
557 PROFILE_Free( CurProfile->section );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000558 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
559 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
560 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000561 CurProfile->changed = FALSE;
562 CurProfile->section = NULL;
563 CurProfile->dos_name = NULL;
564 CurProfile->unix_name = NULL;
565 CurProfile->filename = NULL;
566 CurProfile->mtime = 0;
567}
568
569
570/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000571 * PROFILE_Open
572 *
573 * Open a profile file, checking the cached file first.
574 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000575static BOOL PROFILE_Open( LPCSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000576{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000577 DOS_FULL_NAME full_name;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000578 char buffer[MAX_PATHNAME_LEN];
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000579 char *newdos_name, *p;
580 FILE *file = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000581 int i,j;
582 struct stat buf;
583 PROFILE *tempProfile;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000584
Alexandre Julliard829fe321998-07-26 14:27:39 +0000585 /* First time around */
586
587 if(!CurProfile)
588 for(i=0;i<N_CACHED_PROFILES;i++)
589 {
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000590 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
591 if(MRUProfile[i] == NULL) break;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000592 MRUProfile[i]->changed=FALSE;
593 MRUProfile[i]->section=NULL;
594 MRUProfile[i]->dos_name=NULL;
595 MRUProfile[i]->unix_name=NULL;
596 MRUProfile[i]->filename=NULL;
597 MRUProfile[i]->mtime=0;
598 }
599
600 /* Check for a match */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000601
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000602 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
603 strchr( filename, ':' ))
604 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000605 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000606 }
607 else
608 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000609 GetWindowsDirectoryA( buffer, sizeof(buffer) );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000610 strcat( buffer, "\\" );
611 strcat( buffer, filename );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000612 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000613 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000614
Alexandre Julliard829fe321998-07-26 14:27:39 +0000615 for(i=0;i<N_CACHED_PROFILES;i++)
616 {
617 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
618 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
619 {
620 if(i)
621 {
622 PROFILE_FlushFile();
623 tempProfile=MRUProfile[i];
624 for(j=i;j>0;j--)
625 MRUProfile[j]=MRUProfile[j-1];
626 CurProfile=tempProfile;
627 }
628 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000629 TRACE("(%s): already opened (mru=%d)\n",
Alexandre Julliard829fe321998-07-26 14:27:39 +0000630 filename, i );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000631 else
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000632 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000633 filename, i );
634 return TRUE;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000635 }
636 }
637
Andreas Mohr87bff281999-11-21 02:03:03 +0000638 /* Flush the old current profile */
639 PROFILE_FlushFile();
Alexandre Julliard829fe321998-07-26 14:27:39 +0000640
Andreas Mohr87bff281999-11-21 02:03:03 +0000641 /* Make the oldest profile the current one only in order to get rid of it */
Alexandre Julliard829fe321998-07-26 14:27:39 +0000642 if(i==N_CACHED_PROFILES)
643 {
644 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
645 for(i=N_CACHED_PROFILES-1;i>0;i--)
646 MRUProfile[i]=MRUProfile[i-1];
647 CurProfile=tempProfile;
648 }
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000649 if(CurProfile->filename) PROFILE_ReleaseFile();
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000650
Andreas Mohr87bff281999-11-21 02:03:03 +0000651 /* OK, now that CurProfile is definitely free we assign it our new file */
Alexandre Julliard90476d62000-02-16 22:47:24 +0000652 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000653 CurProfile->dos_name = newdos_name;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000654 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000655
656 /* Try to open the profile file, first in $HOME/.wine */
657
658 /* FIXME: this will need a more general solution */
Alexandre Julliardde1d5ad2000-04-06 20:36:17 +0000659 strcpy( buffer, get_config_dir() );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000660 p = buffer + strlen(buffer);
661 *p++ = '/';
662 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
Alexandre Julliarddcd247e2000-08-14 17:39:15 +0000663 _strlwr( p );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000664 if ((file = fopen( buffer, "r" )))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000665 {
Alexandre Julliard647876e2000-01-25 01:35:01 +0000666 TRACE("(%s): found it in %s\n",
667 filename, buffer );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000668 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000669 }
670
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000671 if (!file)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000672 {
Alexandre Julliard90476d62000-02-16 22:47:24 +0000673 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000674 full_name.long_name );
675 if ((file = fopen( full_name.long_name, "r" )))
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000676 TRACE("(%s): found it in %s\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000677 filename, full_name.long_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000678 }
679
680 if (file)
681 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000682 CurProfile->section = PROFILE_Load( file );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000683 fclose( file );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000684 if(!stat(CurProfile->unix_name,&buf))
685 CurProfile->mtime=buf.st_mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000686 }
687 else
Alexandre Julliardd1ce8b21996-09-02 16:46:30 +0000688 {
689 /* Does not exist yet, we will create it in PROFILE_FlushFile */
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000690 WARN("profile file %s not found\n", newdos_name );
Alexandre Julliardd1ce8b21996-09-02 16:46:30 +0000691 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000692 return TRUE;
693}
694
695
696/***********************************************************************
697 * PROFILE_GetSection
698 *
Alexandre Julliarda845b881998-06-01 10:44:35 +0000699 * Returns all keys of a section.
Alexandre Julliard642d3131998-07-12 19:29:36 +0000700 * If return_values is TRUE, also include the corresponding values.
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000701 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000702static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
Eric Poueched155751999-03-25 13:24:08 +0000703 LPSTR buffer, UINT len, BOOL handle_env,
704 BOOL return_values )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000705{
706 PROFILEKEY *key;
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000707
708 if(!buffer) return 0;
709
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000710 while (section)
711 {
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000712 if (section->name && !strcasecmp( section->name, section_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000713 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000714 UINT oldlen = len;
Alexandre Julliard9416aba1999-01-26 17:29:49 +0000715 for (key = section->key; key; key = key->next)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000716 {
717 if (len <= 2) break;
Alexandre Julliard9416aba1999-01-26 17:29:49 +0000718 if (!*key->name) continue; /* Skip empty lines */
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000719 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
720 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
Alexandre Julliard0c126c71996-02-18 18:44:41 +0000721 len -= strlen(buffer) + 1;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000722 buffer += strlen(buffer) + 1;
Alexandre Julliarda845b881998-06-01 10:44:35 +0000723 if (return_values && key->value) {
724 buffer[-1] = '=';
725 PROFILE_CopyEntry ( buffer,
726 key->value, len - 1, handle_env );
727 len -= strlen(buffer) + 1;
728 buffer += strlen(buffer) + 1;
729 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000730 }
731 *buffer = '\0';
Marcus Meissneracfae0c1999-05-08 18:29:10 +0000732 if (len <= 1)
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000733 /*If either lpszSection or lpszKey is NULL and the supplied
734 destination buffer is too small to hold all the strings,
735 the last string is truncated and followed by two null characters.
736 In this case, the return value is equal to cchReturnBuffer
737 minus two. */
738 {
739 buffer[-1] = '\0';
740 return oldlen - 2;
741 }
Alexandre Julliard829fe321998-07-26 14:27:39 +0000742 return oldlen - len;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000743 }
744 section = section->next;
745 }
746 buffer[0] = buffer[1] = '\0';
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000747 return 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000748}
749
750
Andreas Mohradfeec91999-05-22 16:04:57 +0000751static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
752{
753 LPSTR buf = buffer;
754 WORD l, cursize = 0;
755 PROFILESECTION *section;
756
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000757 if(!buffer) return 0;
758
Andreas Mohradfeec91999-05-22 16:04:57 +0000759 for (section = CurProfile->section; section; section = section->next)
760 if (section->name) {
761 l = strlen(section->name);
762 cursize += l+1;
763 if (cursize > len+1)
764 return len-2;
765
766 strcpy(buf, section->name);
767 buf += l+1;
768 }
769
770 *buf=0;
771 buf++;
772 return buf-buffer;
773}
774
775
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000776/***********************************************************************
777 * PROFILE_GetString
778 *
779 * Get a profile string.
Andreas Mohr3ac104f2000-09-29 21:04:44 +0000780 *
781 * Tests with GetPrivateProfileString16, W95a,
782 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
783 * section key_name def_val res buffer
784 * "set1" "1" "x" 43 [data]
785 * "set1" "1 " "x" 43 [data] (!)
786 * "set1" " 1 "' "x" 43 [data] (!)
787 * "set1" "" "x" 1 "x"
788 * "set1" "" "x " 1 "x" (!)
789 * "set1" "" " x " 3 " x" (!)
790 * "set1" NULL "x" 6 "1\02\03\0\0"
791 * "set1" "" "x" 1 "x"
792 * NULL "1" "x" 0 "" (!)
793 * "" "1" "x" 1 "x"
794 * NULL NULL "" 0 ""
795 *
796 *
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000797 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000798static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
Eric Poueched155751999-03-25 13:24:08 +0000799 LPCSTR def_val, LPSTR buffer, UINT len )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000800{
801 PROFILEKEY *key = NULL;
802
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000803 if(!buffer) return 0;
804
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000805 if (!def_val) def_val = "";
Alexandre Julliard77b99181997-09-14 17:17:23 +0000806 if (key_name && key_name[0])
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000807 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000808 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000809 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
810 len, FALSE );
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000811 TRACE("('%s','%s','%s'): returning '%s'\n",
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000812 section, key_name, def_val, buffer );
813 return strlen( buffer );
814 }
Uwe Bonnesb2ccbb22000-03-04 19:03:15 +0000815 if (key_name && !(key_name[0]))
Andreas Mohr3ac104f2000-09-29 21:04:44 +0000816 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
Uwe Bonnesb2ccbb22000-03-04 19:03:15 +0000817 return 0;
Andreas Mohradfeec91999-05-22 16:04:57 +0000818 if (section && section[0])
819 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
Alexandre Julliarda845b881998-06-01 10:44:35 +0000820 FALSE, FALSE);
Andreas Mohr3ac104f2000-09-29 21:04:44 +0000821 buffer[0] = '\0';
822 return 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000823}
824
825
826/***********************************************************************
827 * PROFILE_SetString
828 *
829 * Set a profile string.
830 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000831static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
Eric Poueched155751999-03-25 13:24:08 +0000832 LPCSTR value )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000833{
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000834 if (!key_name) /* Delete a whole section */
835 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000836 TRACE("('%s')\n", section_name);
Alexandre Julliard829fe321998-07-26 14:27:39 +0000837 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
838 section_name );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000839 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
840 this is not an error on application's level.*/
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000841 }
842 else if (!value) /* Delete a key */
843 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000844 TRACE("('%s','%s')\n",
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000845 section_name, key_name );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000846 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
847 section_name, key_name );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000848 return TRUE; /* same error handling as above */
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000849 }
850 else /* Set the key value */
851 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000852 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000853 key_name, TRUE );
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000854 TRACE("('%s','%s','%s'): \n",
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000855 section_name, key_name, value );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000856 if (!key) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000857 if (key->value)
858 {
Marcus Meissnera6ae5552000-06-13 01:06:22 +0000859 /* strip the leading spaces. We can safely strip \n\r and
860 * friends too, they should not happen here anyway. */
861 while (PROFILE_isspace(*value)) value++;
862
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000863 if (!strcmp( key->value, value ))
864 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000865 TRACE(" no change needed\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000866 return TRUE; /* No change needed */
867 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000868 TRACE(" replacing '%s'\n", key->value );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000869 HeapFree( GetProcessHeap(), 0, key->value );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000870 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000871 else TRACE(" creating key\n" );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000872 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000873 CurProfile->changed = TRUE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000874 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000875 return TRUE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000876}
877
878
879/***********************************************************************
880 * PROFILE_GetWineIniString
881 *
882 * Get a config string from the wine.ini file.
883 */
884int PROFILE_GetWineIniString( const char *section, const char *key_name,
885 const char *def, char *buffer, int len )
886{
Alexandre Julliard00377a72000-02-19 20:50:00 +0000887 char tmp[PROFILE_MAX_LINE_LEN];
888 HKEY hkey;
889 DWORD err;
Eric Poueched155751999-03-25 13:24:08 +0000890
Alexandre Julliard00377a72000-02-19 20:50:00 +0000891 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000892 {
Alexandre Julliard00377a72000-02-19 20:50:00 +0000893 DWORD type;
894 DWORD count = sizeof(tmp);
895 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
896 RegCloseKey( hkey );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000897 }
Alexandre Julliard00377a72000-02-19 20:50:00 +0000898 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
899 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
900 return strlen(buffer);
901}
Eric Poueched155751999-03-25 13:24:08 +0000902
Alexandre Julliard00377a72000-02-19 20:50:00 +0000903
904/***********************************************************************
905 * PROFILE_EnumWineIniString
906 *
907 * Get a config string from the wine.ini file.
908 */
909BOOL PROFILE_EnumWineIniString( const char *section, int index,
910 char *name, int name_len, char *buffer, int len )
911{
912 char tmp[PROFILE_MAX_LINE_LEN];
913 HKEY hkey;
914 DWORD err, type;
915 DWORD count = sizeof(tmp);
916
917 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
918 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
919 RegCloseKey( hkey );
920 if (!err)
921 {
922 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
923 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
924 }
925 return !err;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000926}
927
928
929/***********************************************************************
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000930 * PROFILE_GetWineIniInt
931 *
932 * Get a config integer from the wine.ini file.
933 */
934int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
935{
936 char buffer[20];
937 char *p;
938 long result;
939
Alexandre Julliard00377a72000-02-19 20:50:00 +0000940 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
941 if (!buffer[0]) return def;
942 result = strtol( buffer, &p, 0 );
943 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000944}
945
946
947/******************************************************************************
948 *
949 * int PROFILE_GetWineIniBool(
950 * char const *section,
951 * char const *key_name,
952 * int def )
953 *
954 * Reads a boolean value from the wine.ini file. This function attempts to
955 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
956 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
957 * true. Anything else results in the return of the default value.
958 *
959 * This function uses 1 to indicate true, and 0 for false. You can check
960 * for existence by setting def to something other than 0 or 1 and
961 * examining the return value.
962 */
963int PROFILE_GetWineIniBool(
964 char const *section,
965 char const *key_name,
966 int def )
967{
968 char key_value[2];
969 int retval;
970
971 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
972
973 switch(key_value[0]) {
974 case 'n':
975 case 'N':
976 case 'f':
977 case 'F':
978 case '0':
979 retval = 0;
980 break;
981
982 case 'y':
983 case 'Y':
984 case 't':
985 case 'T':
986 case '1':
987 retval = 1;
988 break;
989
990 default:
991 retval = def;
992 }
993
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000994 TRACE("(\"%s\", \"%s\", %s), "
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000995 "[%c], ret %s.\n", section, key_name,
996 def ? "TRUE" : "FALSE", key_value[0],
997 retval ? "TRUE" : "FALSE");
998
999 return retval;
1000}
1001
1002
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001003/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001004 * PROFILE_LoadWineIni
1005 *
Chris Morgan4a3d5082001-01-10 22:57:34 +00001006 * Load the old .winerc file.
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001007 */
1008int PROFILE_LoadWineIni(void)
1009{
Alexandre Julliard95153362001-03-23 19:13:23 +00001010 OBJECT_ATTRIBUTES attr;
1011 UNICODE_STRING nameW;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001012 char buffer[MAX_PATHNAME_LEN];
1013 const char *p;
1014 FILE *f;
Eric Pouech0521a542000-02-20 13:39:42 +00001015 HKEY hKeySW;
Alexandre Julliard6c8d9172000-08-26 04:40:07 +00001016 DWORD disp;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001017
Alexandre Julliard95153362001-03-23 19:13:23 +00001018 attr.Length = sizeof(attr);
1019 attr.RootDirectory = 0;
1020 attr.ObjectName = &nameW;
1021 attr.Attributes = 0;
1022 attr.SecurityDescriptor = NULL;
1023 attr.SecurityQualityOfService = NULL;
1024
Alexandre Julliard86ff8c02000-04-13 16:10:20 +00001025 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
Alexandre Julliard95153362001-03-23 19:13:23 +00001026 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1027 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
Eric Pouech0521a542000-02-20 13:39:42 +00001028 {
1029 ERR("Cannot create config registry key\n" );
Alexandre Julliard95153362001-03-23 19:13:23 +00001030 ExitProcess( 1 );
Eric Pouech0521a542000-02-20 13:39:42 +00001031 }
Alexandre Julliard95153362001-03-23 19:13:23 +00001032 RtlFreeUnicodeString( &nameW );
1033 NtClose( hKeySW );
1034
1035 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1036 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1037 NULL, REG_OPTION_VOLATILE, &disp ))
Alexandre Julliard00377a72000-02-19 20:50:00 +00001038 {
1039 ERR("Cannot create config registry key\n" );
Alexandre Julliard95153362001-03-23 19:13:23 +00001040 ExitProcess( 1 );
Alexandre Julliard00377a72000-02-19 20:50:00 +00001041 }
Alexandre Julliard95153362001-03-23 19:13:23 +00001042 RtlFreeUnicodeString( &nameW );
Eric Poueched155751999-03-25 13:24:08 +00001043
Alexandre Julliard00377a72000-02-19 20:50:00 +00001044 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1045
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001046 if ((p = getenv( "HOME" )) != NULL)
1047 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001048 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001049 strcat( buffer, PROFILE_WineIniName );
1050 if ((f = fopen( buffer, "r" )) != NULL)
1051 {
Francois Gougetbaa9bf91999-12-27 05:24:06 +00001052 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
Alexandre Julliard00377a72000-02-19 20:50:00 +00001053 goto found;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001054 }
1055 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001056 else WARN("could not get $HOME value for config file.\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001057
Alexandre Julliard6c8d9172000-08-26 04:40:07 +00001058 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1059
Chris Morgan4a3d5082001-01-10 22:57:34 +00001060 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001061 return 0;
Alexandre Julliard00377a72000-02-19 20:50:00 +00001062
1063 found:
Alexandre Julliard6c8d9172000-08-26 04:40:07 +00001064
1065 if (disp == REG_OPENED_EXISTING_KEY)
1066 {
Chris Morgan4a3d5082001-01-10 22:57:34 +00001067 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1068 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
Alexandre Julliard6c8d9172000-08-26 04:40:07 +00001069 fclose( f );
1070 return 1;
1071 }
1072
Alexandre Julliard73be8d12000-12-06 20:25:11 +00001073 /* convert to the new format */
1074 sprintf( buffer, "%s/config", get_config_dir() );
Alexandre Julliard95153362001-03-23 19:13:23 +00001075 convert_config( f, buffer );
Alexandre Julliard00377a72000-02-19 20:50:00 +00001076 fclose( f );
Alexandre Julliard95153362001-03-23 19:13:23 +00001077
1078 MESSAGE( "The '%s' configuration file has been converted\n"
1079 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1080 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1081 "and then remove the old one and restart Wine.\n" );
1082 ExitProcess(0);
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001083}
1084
1085
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001086/***********************************************************************
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001087 * PROFILE_UsageWineIni
1088 *
1089 * Explain the wine.ini file to those who don't read documentation.
1090 * Keep below one screenful in length so that error messages above are
1091 * noticed.
1092 */
1093void PROFILE_UsageWineIni(void)
1094{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001095 MESSAGE("Perhaps you have not properly edited or created "
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001096 "your Wine configuration file.\n");
Gerard Patel151023d2001-01-22 19:27:06 +00001097 MESSAGE("This is '%s/config'\n", get_config_dir());
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001098 /* RTFM, so to say */
1099}
1100
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001101/***********************************************************************
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001102 * PROFILE_GetStringItem
1103 *
1104 * Convenience function that turns a string 'xxx, yyy, zzz' into
1105 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1106 */
1107char* PROFILE_GetStringItem( char* start )
1108{
1109 char* lpchX, *lpch;
1110
1111 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1112 {
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001113 if( *lpchX == ',' )
1114 {
1115 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1116 while( *(++lpchX) )
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001117 if( !PROFILE_isspace(*lpchX) ) return lpchX;
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001118 }
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001119 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001120 else lpch = NULL;
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001121 }
1122 if( lpch ) *lpch = '\0';
1123 return NULL;
1124}
1125
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001126/********************* API functions **********************************/
1127
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001128/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001129 * GetProfileInt16 (KERNEL.57)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001130 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001131UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001132{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001133 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001134}
1135
1136
1137/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001138 * GetProfileIntA (KERNEL32.264)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001139 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001140UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001141{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001142 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001143}
1144
1145/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001146 * GetProfileIntW (KERNEL32.264)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001147 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001148UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001149{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001150 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001151}
1152
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001153/*
1154 * undoc_feature means:
1155 * return section names string list if both section and entry are NULL.
1156 */
1157static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1158 LPCSTR def_val, LPSTR buffer,
1159 UINT16 len, LPCSTR filename,
1160 BOOL undoc_feature )
1161{
1162 int ret;
1163 LPSTR pDefVal = NULL;
1164
1165 if (!filename)
1166 filename = "win.ini";
1167
1168 /* strip any trailing ' ' of def_val. */
1169 if (def_val)
1170 {
1171 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1172
1173 while (p > def_val)
1174 {
1175 p--;
1176 if ((*p) != ' ')
1177 break;
1178 }
1179 if (*p == ' ') /* ouch, contained trailing ' ' */
1180 {
1181 int len = (int)p - (int)def_val;
1182 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1183 strncpy(pDefVal, def_val, len);
1184 pDefVal[len] = '\0';
1185 }
1186 }
1187 if (!pDefVal)
1188 pDefVal = (LPSTR)def_val;
1189
1190 EnterCriticalSection( &PROFILE_CritSect );
1191
1192 if (PROFILE_Open( filename )) {
1193 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1194 /* undocumented; both section and entry are NULL */
1195 ret = PROFILE_GetSectionNames(buffer, len);
1196 else
1197 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1198 } else {
1199 lstrcpynA( buffer, pDefVal, len );
1200 ret = strlen( buffer );
1201 }
1202
1203 LeaveCriticalSection( &PROFILE_CritSect );
1204
1205 if (pDefVal != def_val) /* allocated */
1206 HeapFree(GetProcessHeap(), 0, pDefVal);
1207
1208 return ret;
1209}
1210
1211/***********************************************************************
1212 * GetPrivateProfileString16 (KERNEL.128)
1213 */
1214INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1215 LPCSTR def_val, LPSTR buffer,
1216 UINT16 len, LPCSTR filename )
1217{
1218 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1219 buffer, len, filename, FALSE );
1220}
1221
1222/***********************************************************************
1223 * GetPrivateProfileStringA (KERNEL32.255)
1224 */
1225INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1226 LPCSTR def_val, LPSTR buffer,
1227 UINT len, LPCSTR filename )
1228{
1229 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1230 buffer, len, filename, TRUE );
1231}
1232
1233/***********************************************************************
1234 * GetPrivateProfileStringW (KERNEL32.256)
1235 */
1236INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1237 LPCWSTR def_val, LPWSTR buffer,
1238 UINT len, LPCWSTR filename )
1239{
1240 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1241 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1242 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1243 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1244 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1245 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1246 bufferA, len, filenameA );
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001247 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1248 buffer[len-1] = 0;
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001249 HeapFree( GetProcessHeap(), 0, sectionA );
1250 HeapFree( GetProcessHeap(), 0, entryA );
1251 HeapFree( GetProcessHeap(), 0, filenameA );
1252 HeapFree( GetProcessHeap(), 0, def_valA );
1253 HeapFree( GetProcessHeap(), 0, bufferA);
1254 return ret;
1255}
1256
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001257/***********************************************************************
1258 * GetProfileString16 (KERNEL.58)
1259 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001260INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001261 LPSTR buffer, UINT16 len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001262{
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001263 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1264 buffer, len, "win.ini", FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001265}
1266
1267/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001268 * GetProfileStringA (KERNEL32.268)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001269 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001270INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
Eric Poueched155751999-03-25 13:24:08 +00001271 LPSTR buffer, UINT len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001272{
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001273 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1274 buffer, len, "win.ini", TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001275}
1276
1277/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001278 * GetProfileStringW (KERNEL32.269)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001279 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001280INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001281 LPCWSTR def_val, LPWSTR buffer, UINT len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001282{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001283 return GetPrivateProfileStringW( section, entry, def_val,
Eric Poueched155751999-03-25 13:24:08 +00001284 buffer, len, wininiW );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001285}
1286
Alexandre Julliard77b99181997-09-14 17:17:23 +00001287/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001288 * WriteProfileString16 (KERNEL.59)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001289 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001290BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1291 LPCSTR string )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001292{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001293 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1294}
1295
1296/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001297 * WriteProfileStringA (KERNEL32.587)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001298 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001299BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001300 LPCSTR string )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001301{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001302 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001303}
1304
1305/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001306 * WriteProfileStringW (KERNEL32.588)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001307 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001308BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001309 LPCWSTR string )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001310{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001311 return WritePrivateProfileStringW( section, entry, string, wininiW );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001312}
1313
1314
1315/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001316 * GetPrivateProfileInt16 (KERNEL.127)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001317 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001318UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1319 INT16 def_val, LPCSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001320{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001321 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001322
1323 if (result > 65535) return 65535;
1324 if (result >= 0) return (UINT16)result;
1325 if (result < -32768) return -32768;
1326 return (UINT16)(INT16)result;
1327}
1328
1329/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001330 * GetPrivateProfileIntA (KERNEL32.251)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001331 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001332UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001333 INT def_val, LPCSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001334{
1335 char buffer[20];
1336 char *p;
1337 long result;
1338
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001339 PROFILE_GetPrivateProfileString( section, entry, "",
1340 buffer, sizeof(buffer), filename, FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001341 if (!buffer[0]) return (UINT)def_val;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001342 result = strtol( buffer, &p, 0 );
1343 if (p == buffer) return 0; /* No digits at all */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001344 return (UINT)result;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001345}
1346
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001347/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001348 * GetPrivateProfileIntW (KERNEL32.252)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001349 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001350UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001351 INT def_val, LPCWSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001352{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001353 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1354 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1355 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001356 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001357 HeapFree( GetProcessHeap(), 0, sectionA );
1358 HeapFree( GetProcessHeap(), 0, filenameA );
1359 HeapFree( GetProcessHeap(), 0, entryA );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001360 return res;
1361}
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001362
1363/***********************************************************************
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001364 * GetPrivateProfileSection16 (KERNEL.418)
1365 */
1366INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1367 UINT16 len, LPCSTR filename )
1368{
1369 return GetPrivateProfileSectionA( section, buffer, len, filename );
1370}
1371
1372/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001373 * GetPrivateProfileSectionA (KERNEL32.255)
Alexandre Julliard77b99181997-09-14 17:17:23 +00001374 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001375INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
Eric Poueched155751999-03-25 13:24:08 +00001376 DWORD len, LPCSTR filename )
Alexandre Julliard77b99181997-09-14 17:17:23 +00001377{
Eric Poueched155751999-03-25 13:24:08 +00001378 int ret = 0;
1379
1380 EnterCriticalSection( &PROFILE_CritSect );
1381
Alexandre Julliard77b99181997-09-14 17:17:23 +00001382 if (PROFILE_Open( filename ))
Eric Poueched155751999-03-25 13:24:08 +00001383 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1384 FALSE, TRUE);
1385
1386 LeaveCriticalSection( &PROFILE_CritSect );
Alexandre Julliarda845b881998-06-01 10:44:35 +00001387
Marcus Meissner264360f1999-05-08 10:02:05 +00001388 return ret;
Alexandre Julliard77b99181997-09-14 17:17:23 +00001389}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001390
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001391/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001392 * GetPrivateProfileSectionW (KERNEL32.256)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001393 */
1394
Alexandre Julliarda3960291999-02-26 11:11:13 +00001395INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
Eric Poueched155751999-03-25 13:24:08 +00001396 DWORD len, LPCWSTR filename )
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001397
1398{
1399 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1400 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1401 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001402 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001403 filenameA );
Marcus Meissner264360f1999-05-08 10:02:05 +00001404 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001405 HeapFree( GetProcessHeap(), 0, sectionA );
1406 HeapFree( GetProcessHeap(), 0, filenameA );
1407 HeapFree( GetProcessHeap(), 0, bufferA);
1408 return ret;
1409}
1410
1411/***********************************************************************
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001412 * GetProfileSection16 (KERNEL.419)
1413 */
1414INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1415{
1416 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1417}
1418
1419/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001420 * GetProfileSectionA (KERNEL32.268)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001421 */
1422INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1423{
1424 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1425}
1426
1427/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001428 * GetProfileSectionW (KERNEL32)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001429 */
1430INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1431{
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001432 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1433}
1434
1435
1436/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001437 * WritePrivateProfileString16 (KERNEL.129)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001438 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001439BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1440 LPCSTR string, LPCSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001441{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001442 return WritePrivateProfileStringA(section,entry,string,filename);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001443}
1444
1445/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001446 * WritePrivateProfileStringA (KERNEL32.582)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001447 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001448BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001449 LPCSTR string, LPCSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001450{
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001451 BOOL ret = FALSE;
Eric Poueched155751999-03-25 13:24:08 +00001452
1453 EnterCriticalSection( &PROFILE_CritSect );
1454
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001455 if (PROFILE_Open( filename ))
1456 {
1457 if (!section && !entry && !string)
1458 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1459 else
1460 ret = PROFILE_SetString( section, entry, string );
Eric Poueched155751999-03-25 13:24:08 +00001461 }
1462
1463 LeaveCriticalSection( &PROFILE_CritSect );
Eric Poueched155751999-03-25 13:24:08 +00001464 return ret;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001465}
1466
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001467/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001468 * WritePrivateProfileStringW (KERNEL32.583)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001469 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001470BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001471 LPCWSTR string, LPCWSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001472{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001473 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1474 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1475 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1476 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001477 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
Eric Poueched155751999-03-25 13:24:08 +00001478 stringA, filenameA );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001479 HeapFree( GetProcessHeap(), 0, sectionA );
1480 HeapFree( GetProcessHeap(), 0, entryA );
1481 HeapFree( GetProcessHeap(), 0, stringA );
1482 HeapFree( GetProcessHeap(), 0, filenameA );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001483 return res;
1484}
1485
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001486/***********************************************************************
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001487 * WritePrivateProfileSection16 (KERNEL.416)
1488 */
1489BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1490 LPCSTR string, LPCSTR filename )
1491{
1492 return WritePrivateProfileSectionA( section, string, filename );
1493}
1494
1495/***********************************************************************
Rein Klazes7458be02000-01-05 01:42:51 +00001496 * WritePrivateProfileSectionA (KERNEL32)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001497 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001498BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
Eric Poueched155751999-03-25 13:24:08 +00001499 LPCSTR string, LPCSTR filename )
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001500{
Rein Klazes7458be02000-01-05 01:42:51 +00001501 BOOL ret = FALSE;
1502 LPSTR p ;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001503
Rein Klazes7458be02000-01-05 01:42:51 +00001504 EnterCriticalSection( &PROFILE_CritSect );
1505
1506 if (PROFILE_Open( filename )) {
Marcus Meissner25e74032000-11-26 22:36:19 +00001507 if (!section && !string)
Rein Klazes7458be02000-01-05 01:42:51 +00001508 PROFILE_ReleaseFile(); /* always return FALSE in this case */
Uwe Bonnesd88fbb72000-06-20 20:48:46 +00001509 else if (!string) /* delete the named section*/
1510 ret = PROFILE_SetString(section,NULL,NULL);
Rein Klazes7458be02000-01-05 01:42:51 +00001511 else {
Uwe Bonnesd88fbb72000-06-20 20:48:46 +00001512 PROFILE_DeleteAllKeys(section);
1513 ret = TRUE;
1514 while(*string) {
1515 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
Rein Klazes7458be02000-01-05 01:42:51 +00001516 if((p=strchr( buf, '='))){
1517 *p='\0';
1518 ret = PROFILE_SetString( section, buf, p+1 );
1519
1520 }
1521 HeapFree( GetProcessHeap(), 0, buf );
1522 string += strlen(string)+1;
1523 }
1524
1525 }
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001526 }
Rein Klazes7458be02000-01-05 01:42:51 +00001527
1528 LeaveCriticalSection( &PROFILE_CritSect );
1529 return ret;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001530}
1531
Alexandre Julliarda845b881998-06-01 10:44:35 +00001532/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001533 * WritePrivateProfileSectionW (KERNEL32)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001534 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001535BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
Eric Poueched155751999-03-25 13:24:08 +00001536 LPCWSTR string, LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001537
1538{
1539 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1540 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1541 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001542 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001543 HeapFree( GetProcessHeap(), 0, sectionA );
1544 HeapFree( GetProcessHeap(), 0, stringA );
1545 HeapFree( GetProcessHeap(), 0, filenameA );
1546 return res;
1547}
1548
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001549/***********************************************************************
1550 * WriteProfileSection16 (KERNEL.417)
1551 */
1552BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1553{
1554 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1555}
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001556
1557/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001558 * WriteProfileSectionA (KERNEL32.747)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001559 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001560BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001561
1562{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001563 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001564}
1565
1566/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001567 * WriteProfileSectionW (KERNEL32.748)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001568 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001569BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001570{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001571 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001572}
1573
1574/***********************************************************************
Alexandre Julliarda845b881998-06-01 10:44:35 +00001575 * GetPrivateProfileSectionNames16 (KERNEL.143)
1576 */
1577WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1578 LPCSTR filename )
1579{
Andreas Mohradfeec91999-05-22 16:04:57 +00001580 WORD ret = 0;
Eric Poueched155751999-03-25 13:24:08 +00001581
1582 EnterCriticalSection( &PROFILE_CritSect );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001583
Andreas Mohradfeec91999-05-22 16:04:57 +00001584 if (PROFILE_Open( filename ))
1585 ret = PROFILE_GetSectionNames(buffer, size);
Eric Poueched155751999-03-25 13:24:08 +00001586
1587 LeaveCriticalSection( &PROFILE_CritSect );
1588
1589 return ret;
Alexandre Julliarda845b881998-06-01 10:44:35 +00001590}
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001591
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001592
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001593/***********************************************************************
1594 * GetProfileSectionNames16 (KERNEL.142)
1595 */
1596WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1597
1598{
Eric Poueched155751999-03-25 13:24:08 +00001599 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001600}
1601
1602
1603/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001604 * GetPrivateProfileSectionNamesA (KERNEL32.365)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001605 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001606DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
Eric Poueched155751999-03-25 13:24:08 +00001607 LPCSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001608
1609{
1610 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1611}
1612
1613
1614/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001615 * GetPrivateProfileSectionNamesW (KERNEL32.366)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001616 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001617DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
Eric Poueched155751999-03-25 13:24:08 +00001618 LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001619
1620{
1621 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1622 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1623
Alexandre Julliarda3960291999-02-26 11:11:13 +00001624 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001625 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1626 buffer[size-1] = 0;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001627 HeapFree( GetProcessHeap(), 0, bufferA);
1628 HeapFree( GetProcessHeap(), 0, filenameA );
1629
1630 return ret;
1631}
1632
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001633/***********************************************************************
1634 * GetPrivateProfileStruct16 (KERNEL.407)
1635 */
1636BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1637 LPVOID buf, UINT16 len, LPCSTR filename)
1638{
1639 return GetPrivateProfileStructA( section, key, buf, len, filename );
1640}
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001641
1642/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001643 * GetPrivateProfileStructA (KERNEL32.370)
Andreas Mohr17b1f462000-01-30 21:15:14 +00001644 *
1645 * Should match Win95's behaviour pretty much
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001646 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001647BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
Eric Poueched155751999-03-25 13:24:08 +00001648 LPVOID buf, UINT len, LPCSTR filename)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001649{
Eric Poueched155751999-03-25 13:24:08 +00001650 BOOL ret = FALSE;
1651
1652 EnterCriticalSection( &PROFILE_CritSect );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001653
1654 if (PROFILE_Open( filename )) {
Eric Poueched155751999-03-25 13:24:08 +00001655 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1656 if (k) {
Andreas Mohr17b1f462000-01-30 21:15:14 +00001657 TRACE("value (at %p): '%s'\n", k->value, k->value);
1658 if (((strlen(k->value) - 2) / 2) == len)
1659 {
1660 LPSTR end, p;
1661 BOOL valid = TRUE;
1662 CHAR c;
1663 DWORD chksum = 0;
1664
1665 end = k->value + strlen(k->value); /* -> '\0' */
1666 /* check for invalid chars in ASCII coded hex string */
1667 for (p=k->value; p < end; p++)
1668 {
1669 if (!isxdigit(*p))
1670 {
1671 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1672 *p, filename, section, key);
1673 valid = FALSE;
1674 break;
1675 }
1676 }
1677 if (valid)
1678 {
1679 BOOL highnibble = TRUE;
1680 BYTE b = 0, val;
1681 LPBYTE binbuf = (LPBYTE)buf;
1682
1683 end -= 2; /* don't include checksum in output data */
1684 /* translate ASCII hex format into binary data */
1685 for (p=k->value; p < end; p++)
1686 {
1687 c = toupper(*p);
1688 val = (c > '9') ?
1689 (c - 'A' + 10) : (c - '0');
1690
1691 if (highnibble)
1692 b = val << 4;
1693 else
1694 {
1695 b += val;
1696 *binbuf++ = b; /* feed binary data into output */
1697 chksum += b; /* calculate checksum */
1698 }
1699 highnibble ^= 1; /* toggle */
1700 }
1701 /* retrieve stored checksum value */
1702 c = toupper(*p++);
1703 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1704 c = toupper(*p);
1705 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1706 if (b == (chksum & 0xff)) /* checksums match ? */
1707 ret = TRUE;
1708 }
1709 }
Eric Poueched155751999-03-25 13:24:08 +00001710 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001711 }
Eric Poueched155751999-03-25 13:24:08 +00001712 LeaveCriticalSection( &PROFILE_CritSect );
1713
Andreas Mohr17b1f462000-01-30 21:15:14 +00001714 return ret;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001715}
1716
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001717/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001718 * GetPrivateProfileStructW (KERNEL32.543)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001719 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001720BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
Eric Poueched155751999-03-25 13:24:08 +00001721 LPVOID buffer, UINT len, LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001722{
1723 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1724 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1725 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1726 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1727
Alexandre Julliarda3960291999-02-26 11:11:13 +00001728 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
Eric Poueched155751999-03-25 13:24:08 +00001729 len, filenameA );
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001730 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1731 ((LPWSTR)buffer)[len-1] = 0;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001732 HeapFree( GetProcessHeap(), 0, bufferA);
1733 HeapFree( GetProcessHeap(), 0, sectionA );
1734 HeapFree( GetProcessHeap(), 0, keyA );
1735 HeapFree( GetProcessHeap(), 0, filenameA );
1736
1737 return ret;
1738}
1739
1740
1741
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001742/***********************************************************************
1743 * WritePrivateProfileStruct16 (KERNEL.406)
1744 */
1745BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1746 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1747{
1748 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1749}
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001750
1751/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001752 * WritePrivateProfileStructA (KERNEL32.744)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001753 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001754BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001755 LPVOID buf, UINT bufsize, LPCSTR filename)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001756{
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001757 BOOL ret = FALSE;
Andreas Mohr17b1f462000-01-30 21:15:14 +00001758 LPBYTE binbuf;
1759 LPSTR outstring, p;
1760 DWORD sum = 0;
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001761
1762 if (!section && !key && !buf) /* flush the cache */
1763 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
Eric Poueched155751999-03-25 13:24:08 +00001764
Andreas Mohr17b1f462000-01-30 21:15:14 +00001765 /* allocate string buffer for hex chars + checksum hex char + '\0' */
Alexandre Julliard90476d62000-02-16 22:47:24 +00001766 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
Andreas Mohr17b1f462000-01-30 21:15:14 +00001767 p = outstring;
1768 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1769 *p++ = hex[*binbuf >> 4];
1770 *p++ = hex[*binbuf & 0xf];
1771 sum += *binbuf;
1772 }
1773 /* checksum is sum & 0xff */
1774 *p++ = hex[(sum & 0xf0) >> 4];
1775 *p++ = hex[sum & 0xf];
1776 *p++ = '\0';
1777
Eric Poueched155751999-03-25 13:24:08 +00001778 EnterCriticalSection( &PROFILE_CritSect );
1779
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001780 if (PROFILE_Open( filename ))
Andreas Mohr17b1f462000-01-30 21:15:14 +00001781 ret = PROFILE_SetString( section, key, outstring );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001782
Eric Poueched155751999-03-25 13:24:08 +00001783 LeaveCriticalSection( &PROFILE_CritSect );
1784
Alexandre Julliard90476d62000-02-16 22:47:24 +00001785 HeapFree( GetProcessHeap(), 0, outstring );
Andreas Mohr17b1f462000-01-30 21:15:14 +00001786
Eric Poueched155751999-03-25 13:24:08 +00001787 return ret;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001788}
1789
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001790/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001791 * WritePrivateProfileStructW (KERNEL32.544)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001792 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001793BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
Eric Poueched155751999-03-25 13:24:08 +00001794 LPVOID buf, UINT bufsize, LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001795{
1796 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1797 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1798 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001799 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
Eric Poueched155751999-03-25 13:24:08 +00001800 filenameA );
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001801 HeapFree( GetProcessHeap(), 0, sectionA );
1802 HeapFree( GetProcessHeap(), 0, keyA );
1803 HeapFree( GetProcessHeap(), 0, filenameA );
1804
1805 return ret;
1806}
1807
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001808
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001809/***********************************************************************
1810 * WriteOutProfiles (KERNEL.315)
1811 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001812void WINAPI WriteOutProfiles16(void)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001813{
Eric Poueched155751999-03-25 13:24:08 +00001814 EnterCriticalSection( &PROFILE_CritSect );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001815 PROFILE_FlushFile();
Eric Poueched155751999-03-25 13:24:08 +00001816 LeaveCriticalSection( &PROFILE_CritSect );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001817}
Marcus Meissner9b4fcf71999-12-04 04:19:55 +00001818
1819/***********************************************************************
1820 * CloseProfileUserMapping (KERNEL.138)
1821 */
1822BOOL WINAPI CloseProfileUserMapping(void) {
1823 FIXME("(), stub!\n");
1824 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1825 return FALSE;
1826}