Release 960516
[wine.git] / files / profile.c
blob9932328539f42df5dfb563b5c6f8e726e993d6b3
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <ctype.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
13 #include "dos_fs.h"
14 #include "windows.h"
15 #include "xmalloc.h"
16 #include "stddebug.h"
17 #include "debug.h"
19 typedef struct tagPROFILEKEY
21 char *name;
22 char *value;
23 struct tagPROFILEKEY *next;
24 } PROFILEKEY;
26 typedef struct tagPROFILESECTION
28 char *name;
29 struct tagPROFILEKEY *key;
30 struct tagPROFILESECTION *next;
31 } PROFILESECTION;
34 typedef struct
36 int changed;
37 PROFILESECTION *section;
38 char *dos_name;
39 } PROFILE;
42 /* Cached profile file */
43 static PROFILE CurProfile = { FALSE, NULL, NULL };
45 /* wine.ini profile content */
46 static PROFILESECTION *WineProfile;
48 #define PROFILE_MAX_LINE_LEN 1024
50 /* Wine profile name in $HOME directory; must begin with slash */
51 static const char PROFILE_WineIniName[] = "/.winerc";
53 /* Check for comments in profile */
54 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
57 /***********************************************************************
58 * PROFILE_CopyEntry
60 * Copy the content of an entry into a buffer, removing quotes, and possibly
61 * translating environment variables.
63 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
64 int handle_env )
66 char quote = '\0';
67 const char *p;
69 if ((*value == '\'') || (*value == '\"'))
71 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
74 if (!handle_env)
76 lstrcpyn( buffer, value, len );
77 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
78 return;
81 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
83 if ((*p == '$') && (p[1] == '{'))
85 char env_val[1024];
86 const char *env_p;
87 const char *p2 = strchr( p, '}' );
88 if (!p2) continue; /* ignore it */
89 lstrcpyn( env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ) );
90 if ((env_p = getenv( env_val )) != NULL)
92 lstrcpyn( buffer, env_p, len );
93 buffer += strlen( buffer );
94 len -= strlen( buffer );
96 p = p2 + 1;
99 *buffer = '\0';
103 /***********************************************************************
104 * PROFILE_Save
106 * Save a profile tree to a file.
108 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
110 PROFILEKEY *key;
112 for ( ; section; section = section->next)
114 if (section->name) fprintf( file, "[%s]\r\n", section->name );
115 for (key = section->key; key; key = key->next)
117 fprintf( file, "%s", key->name );
118 if (key->value) fprintf( file, "=%s", key->value );
119 fprintf( file, "\r\n" );
125 /***********************************************************************
126 * PROFILE_Free
128 * Free a profile tree.
130 static void PROFILE_Free( PROFILESECTION *section )
132 PROFILESECTION *next_section;
133 PROFILEKEY *key, *next_key;
135 for ( ; section; section = next_section)
137 if (section->name) free( section->name );
138 for (key = section->key; key; key = next_key)
140 next_key = key->next;
141 if (key->name) free( key->name );
142 if (key->value) free( key->value );
143 free( key );
145 next_section = section->next;
146 free( section );
151 /***********************************************************************
152 * PROFILE_Load
154 * Load a profile tree from a file.
156 static PROFILESECTION *PROFILE_Load( FILE *file )
158 char buffer[PROFILE_MAX_LINE_LEN];
159 char *p, *p2;
160 int line = 0;
161 PROFILESECTION *section, *first_section;
162 PROFILESECTION **prev_section;
163 PROFILEKEY *key, **prev_key;
165 first_section = (PROFILESECTION *)xmalloc( sizeof(*section) );
166 first_section->name = NULL;
167 first_section->key = NULL;
168 first_section->next = NULL;
169 prev_section = &first_section->next;
170 prev_key = &first_section->key;
172 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
174 line++;
175 p = buffer + strlen(buffer) - 1;
176 while ((p > buffer) && ((*p == '\n') || isspace(*p))) *p-- = '\0';
177 p = buffer;
178 while (*p && isspace(*p)) p++;
179 if (*p == '[') /* section start */
181 if (!(p2 = strrchr( p, ']' )))
183 fprintf( stderr, "PROFILE_Load: Invalid section header at line %d: '%s'\n",
184 line, p );
186 else
188 *p2 = '\0';
189 p++;
190 section = (PROFILESECTION *)xmalloc( sizeof(*section));
191 section->name = xstrdup( p );
192 section->key = NULL;
193 section->next = NULL;
194 *prev_section = section;
195 prev_section = &section->next;
196 prev_key = &section->key;
197 continue;
200 if ((p2 = strchr( p, '=' )) != NULL)
202 char *p3 = p2 - 1;
203 while ((p3 > p) && isspace(*p3)) *p3-- = '\0';
204 *p2++ = '\0';
205 while (*p2 && isspace(*p2)) p2++;
207 key = (PROFILEKEY *)xmalloc( sizeof(*key) );
208 key->name = xstrdup( p );
209 key->value = p2 ? xstrdup( p2 ) : NULL;
210 key->next = NULL;
211 *prev_key = key;
212 prev_key = &key->next;
214 if (debugging_profile)
216 fprintf( stddeb, "PROFILE_Load:\n" );
217 PROFILE_Save( stddeb, first_section );
218 fprintf( stddeb, "PROFILE_Load finished.\n" );
220 return first_section;
224 /***********************************************************************
225 * PROFILE_DeleteSection
227 * Delete a section from a profile tree.
229 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, const char *name )
231 while (*section)
233 if ((*section)->name && !lstrcmpi( (*section)->name, name ))
235 PROFILESECTION *to_del = *section;
236 *section = to_del->next;
237 to_del->next = NULL;
238 PROFILE_Free( to_del );
239 return TRUE;
241 section = &(*section)->next;
243 return FALSE;
247 /***********************************************************************
248 * PROFILE_DeleteKey
250 * Delete a key from a profile tree.
252 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
253 const char *section_name, const char *key_name )
255 while (*section)
257 if ((*section)->name && !lstrcmpi( (*section)->name, section_name ))
259 PROFILEKEY **key = &(*section)->key;
260 while (*key)
262 if (!lstrcmpi( (*key)->name, key_name ))
264 PROFILEKEY *to_del = *key;
265 *key = to_del->next;
266 if (to_del->name) free( to_del->name );
267 if (to_del->value) free( to_del->value );
268 free( to_del );
269 return TRUE;
271 key = &(*key)->next;
274 section = &(*section)->next;
276 return FALSE;
280 /***********************************************************************
281 * PROFILE_Find
283 * Find a key in a profile tree, optionally creating it.
285 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
286 const char *section_name,
287 const char *key_name, int create )
289 while (*section)
291 if ((*section)->name && !lstrcmpi( (*section)->name, section_name ))
293 PROFILEKEY **key = &(*section)->key;
294 while (*key)
296 if (!lstrcmpi( (*key)->name, key_name )) return *key;
297 key = &(*key)->next;
299 if (!create) return NULL;
300 *key = (PROFILEKEY *)xmalloc( sizeof(PROFILEKEY) );
301 (*key)->name = xstrdup( key_name );
302 (*key)->value = NULL;
303 (*key)->next = NULL;
304 return *key;
306 section = &(*section)->next;
308 if (!create) return NULL;
309 *section = (PROFILESECTION *)xmalloc( sizeof(PROFILESECTION) );
310 (*section)->name = xstrdup(section_name);
311 (*section)->next = NULL;
312 (*section)->key = (PROFILEKEY *)xmalloc( sizeof(PROFILEKEY) );
313 (*section)->key->name = xstrdup( key_name );
314 (*section)->key->value = NULL;
315 (*section)->key->next = NULL;
316 return (*section)->key;
320 /***********************************************************************
321 * PROFILE_FlushFile
323 * Flush the current profile to disk if changed.
325 static BOOL PROFILE_FlushFile(void)
327 char *p, buffer[MAX_PATHNAME_LEN];
328 const char *unix_name;
329 FILE *file = NULL;
331 if (!CurProfile.changed || !CurProfile.dos_name) return TRUE;
332 if (!(unix_name = DOSFS_GetUnixFileName( CurProfile.dos_name, FALSE )) ||
333 !(file = fopen( unix_name, "w" )))
335 /* Try to create it in $HOME/.wine */
336 /* FIXME: this will need a more general solution */
337 if ((p = getenv( "HOME" )) != NULL)
339 strcpy( buffer, p );
340 strcat( buffer, "/.wine/" );
341 p = buffer + strlen(buffer);
342 strcpy( p, strrchr( CurProfile.dos_name, '\\' ) + 1 );
343 AnsiLower( p );
344 file = fopen( buffer, "w" );
345 unix_name = buffer;
349 if (!file)
351 fprintf( stderr, "Warning: could not save profile file %s\n",
352 CurProfile.dos_name );
353 return FALSE;
356 dprintf_profile( stddeb, "Saving '%s' into '%s'\n",
357 CurProfile.dos_name, unix_name );
358 PROFILE_Save( file, CurProfile.section );
359 fclose( file );
360 CurProfile.changed = FALSE;
361 return TRUE;
365 /***********************************************************************
366 * PROFILE_Open
368 * Open a profile file, checking the cached file first.
370 static BOOL PROFILE_Open( const char *filename )
372 char buffer[MAX_PATHNAME_LEN];
373 const char *dos_name, *unix_name;
374 char *newdos_name, *p;
375 FILE *file = NULL;
377 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
378 strchr( filename, ':' ))
380 if (!(dos_name = DOSFS_GetDosTrueName( filename, FALSE))) return FALSE;
382 else
384 GetWindowsDirectory( buffer, sizeof(buffer) );
385 strcat( buffer, "\\" );
386 strcat( buffer, filename );
387 if (!(dos_name = DOSFS_GetDosTrueName( buffer, FALSE ))) return FALSE;
389 if (CurProfile.dos_name && !strcmp( dos_name, CurProfile.dos_name ))
391 dprintf_profile( stddeb, "PROFILE_Open(%s): already opened\n",
392 filename );
393 return TRUE;
396 /* Flush the previous profile */
398 newdos_name = xstrdup( dos_name );
399 PROFILE_FlushFile();
400 PROFILE_Free( CurProfile.section );
401 if (CurProfile.dos_name) free( CurProfile.dos_name );
402 CurProfile.section = NULL;
403 CurProfile.dos_name = newdos_name;
405 /* Try to open the profile file, first in $HOME/.wine */
407 /* FIXME: this will need a more general solution */
408 if ((p = getenv( "HOME" )) != NULL)
410 strcpy( buffer, p );
411 strcat( buffer, "/.wine/" );
412 p = buffer + strlen(buffer);
413 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
414 AnsiLower( p );
415 if ((file = fopen( buffer, "r" )))
416 dprintf_profile( stddeb, "Found it in %s\n", buffer );
419 if (!file && ((unix_name = DOSFS_GetUnixFileName( dos_name, TRUE ))))
421 if ((file = fopen( unix_name, "r" )))
422 dprintf_profile( stddeb, "Found it in %s\n", unix_name );
425 if (file)
427 CurProfile.section = PROFILE_Load( file );
428 fclose( file );
430 else
431 fprintf( stderr, "Warning: profile file %s not found\n", newdos_name );
432 dprintf_profile( stddeb, "PROFILE_Open(%s): successful\n", filename );
433 return TRUE;
437 /***********************************************************************
438 * PROFILE_GetSection
440 * Enumerate all the keys of a section.
442 static INT PROFILE_GetSection( PROFILESECTION *section,
443 const char *section_name,
444 char *buffer, INT len, int handle_env )
446 PROFILEKEY *key;
447 while (section)
449 if (section->name && !lstrcmpi( section->name, section_name ))
451 INT oldlen = len;
452 for (key = section->key; key; key = key->next)
454 if (len <= 2) break;
455 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
456 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
457 len -= strlen(buffer) + 1;
458 buffer += strlen(buffer) + 1;
460 *buffer = '\0';
461 return oldlen - len + 1;
463 section = section->next;
465 buffer[0] = buffer[1] = '\0';
466 return 2;
470 /***********************************************************************
471 * PROFILE_GetString
473 * Get a profile string.
475 static INT PROFILE_GetString( const char *section, const char *key_name,
476 const char *def_val, char *buffer, INT len )
478 PROFILEKEY *key = NULL;
480 if (!def_val) def_val = "";
481 if (key_name)
483 key = PROFILE_Find( &CurProfile.section, section, key_name, FALSE );
484 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
485 len, FALSE );
486 dprintf_profile( stddeb, "PROFILE_GetString('%s','%s','%s'): returning '%s'\n",
487 section, key_name, def_val, buffer );
488 return strlen( buffer );
490 return PROFILE_GetSection(CurProfile.section, section, buffer, len, FALSE);
494 /***********************************************************************
495 * PROFILE_SetString
497 * Set a profile string.
499 static BOOL PROFILE_SetString( const char *section_name, const char *key_name,
500 const char *value )
502 BOOL ret;
504 if (!key_name) /* Delete a whole section */
506 dprintf_profile(stddeb, "PROFILE_DeleteSection('%s')\n", section_name);
507 ret = PROFILE_DeleteSection( &CurProfile.section, section_name );
508 CurProfile.changed |= ret;
509 return ret;
511 else if (!value) /* Delete a key */
513 dprintf_profile( stddeb, "PROFILE_DeleteKey('%s','%s')\n",
514 section_name, key_name );
515 ret = PROFILE_DeleteKey( &CurProfile.section, section_name, key_name );
516 CurProfile.changed |= ret;
517 return ret;
519 else /* Set the key value */
521 PROFILEKEY *key = PROFILE_Find( &CurProfile.section, section_name,
522 key_name, TRUE );
523 dprintf_profile( stddeb, "PROFILE_SetString('%s','%s','%s'): ",
524 section_name, key_name, value );
525 if (key->value)
527 if (!strcmp( key->value, value ))
529 dprintf_profile( stddeb, "no change needed\n" );
530 return TRUE; /* No change needed */
532 dprintf_profile( stddeb, "replacing '%s'\n", key->value );
533 free( key->value );
535 else dprintf_profile( stddeb, "creating key\n" );
536 key->value = xstrdup( value );
537 CurProfile.changed = TRUE;
538 return TRUE;
543 /***********************************************************************
544 * PROFILE_GetWineIniString
546 * Get a config string from the wine.ini file.
548 int PROFILE_GetWineIniString( const char *section, const char *key_name,
549 const char *def, char *buffer, int len )
551 if (key_name)
553 PROFILEKEY *key = PROFILE_Find(&WineProfile, section, key_name, FALSE);
554 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
555 len, TRUE );
556 dprintf_profile( stddeb, "PROFILE_GetWineIniString('%s','%s','%s'): returning '%s'\n",
557 section, key_name, def, buffer );
558 return strlen( buffer );
560 return PROFILE_GetSection( WineProfile, section, buffer, len, TRUE );
564 /***********************************************************************
565 * PROFILE_LoadWineIni
567 * Load the wine.ini file.
569 int PROFILE_LoadWineIni(void)
571 char buffer[MAX_PATHNAME_LEN];
572 const char *p;
573 FILE *f;
575 if ((p = getenv( "HOME" )) != NULL)
577 lstrcpyn( buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName) );
578 strcat( buffer, PROFILE_WineIniName );
579 if ((f = fopen( buffer, "r" )) != NULL)
581 WineProfile = PROFILE_Load( f );
582 fclose( f );
583 return 1;
586 else fprintf( stderr, "Warning: could not get $HOME value for config file.\n" );
588 /* Try global file */
590 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
592 WineProfile = PROFILE_Load( f );
593 fclose( f );
594 return 1;
596 fprintf( stderr, "Can't open configuration file %s or $HOME%s\n",
597 WINE_INI_GLOBAL, PROFILE_WineIniName );
598 return 0;
602 /***********************************************************************
603 * GetProfileInt (KERNEL.57)
605 UINT GetProfileInt( LPCSTR section, LPCSTR entry, INT def_val )
607 return GetPrivateProfileInt( section, entry, def_val, "win.ini" );
611 /***********************************************************************
612 * GetProfileString (KERNEL.58)
614 INT GetProfileString( LPCSTR section, LPCSTR entry, LPCSTR def_val,
615 LPSTR buffer, INT len )
617 return GetPrivateProfileString( section, entry, def_val,
618 buffer, len, "win.ini" );
622 /***********************************************************************
623 * WriteProfileString (KERNEL.59)
625 BOOL WriteProfileString( LPCSTR section, LPCSTR entry, LPCSTR string )
627 return WritePrivateProfileString( section, entry, string, "win.ini" );
631 /***********************************************************************
632 * GetPrivateProfileInt (KERNEL.127)
634 UINT GetPrivateProfileInt( LPCSTR section, LPCSTR entry, INT def_val,
635 LPCSTR filename )
637 char buffer[20];
638 char *p;
639 long result;
641 GetPrivateProfileString( section, entry, "",
642 buffer, sizeof(buffer), filename );
643 if (!buffer[0]) return (UINT)def_val;
644 result = strtol( buffer, &p, 0 );
645 if (p == buffer) return 0; /* No digits at all */
646 #ifdef WINELIB32
647 return (UINT)result;
648 #else
649 if (result > 65535) return 65535;
650 if (result >= 0) return (UINT)result;
651 if (result < -32768) return -32768;
652 return (UINT)(INT)result;
653 #endif
657 /***********************************************************************
658 * GetPrivateProfileString (KERNEL.128)
660 INT GetPrivateProfileString( LPCSTR section, LPCSTR entry, LPCSTR def_val,
661 LPSTR buffer, INT len, LPCSTR filename )
663 if (PROFILE_Open( filename ))
664 return PROFILE_GetString( section, entry, def_val, buffer, len );
665 lstrcpyn( buffer, def_val, len );
666 return strlen( buffer );
670 /***********************************************************************
671 * WritePrivateProfileString (KERNEL.129)
673 BOOL WritePrivateProfileString( LPCSTR section, LPCSTR entry, LPCSTR string,
674 LPCSTR filename )
676 if (!PROFILE_Open( filename )) return FALSE;
677 if (!section) return PROFILE_FlushFile();
678 return PROFILE_SetString( section, entry, string );
682 /***********************************************************************
683 * WriteOutProfiles (KERNEL.315)
685 void WriteOutProfiles(void)
687 PROFILE_FlushFile();