2 * Initialization-File Functions.
4 * From the Wine project
6 Copyright (C) 1993, 1994, 1998, 1999, 2000, 2002, 2003, 2004, 2005,
7 2007 Free Software Foundation, Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 #include <sys/types.h>
31 #include <mhl/string.h>
37 #define overflow (next == &CharBuffer [STRSIZE-1])
39 enum { FirstBrace
, OnSecHeader
, IgnoreToEOL
, KeyDef
, KeyDefOnKey
, KeyValue
};
41 typedef struct TKeys
{
47 typedef struct TSecHeader
{
50 struct TSecHeader
*link
;
53 typedef struct TProfile
{
56 struct TProfile
*link
;
59 static TProfile
*Base
= 0;
62 find_loaded (const char *FileName
, TSecHeader
** section
)
67 if (!g_strcasecmp (FileName
, p
->FileName
)) {
68 *section
= p
->Section
;
76 #define TRANSLATION_CHAR '\200'
79 str_untranslate_newline_dup (char *s
)
83 g_return_val_if_fail(s
, NULL
);
86 l
+= (*p
== '\n' || *p
== TRANSLATION_CHAR
);
89 q
= p
= g_malloc (l
+ 1);
95 *p
++ = TRANSLATION_CHAR
;
98 case TRANSLATION_CHAR
:
99 if (s
[1] == 'n' || s
[1] == TRANSLATION_CHAR
)
100 *p
++ = TRANSLATION_CHAR
;
101 *p
++ = TRANSLATION_CHAR
;
112 return 0; /* not reached */
116 str_translate_newline_dup (char *s
)
119 g_return_val_if_fail(s
,NULL
);
120 q
= p
= g_malloc (strlen (s
) + 1);
124 if (*s
== TRANSLATION_CHAR
) {
129 case TRANSLATION_CHAR
:
130 *p
++ = TRANSLATION_CHAR
;
133 *p
++ = TRANSLATION_CHAR
;
137 *p
++ = TRANSLATION_CHAR
;
146 return q
; /* not reached */
149 static TSecHeader
*load (const char *file
)
153 TSecHeader
*SecHeader
= 0;
154 char CharBuffer
[STRSIZE
];
155 char *next
= NULL
; /* Not needed */
158 if ((f
= fopen (file
, "r"))==NULL
)
162 while ((c
= getc (f
)) != EOF
){
163 if (c
== '\r') /* Ignore Carriage Return */
169 if (c
== ']' || overflow
){
172 SecHeader
->AppName
= mhl_str_dup (CharBuffer
);
192 SecHeader
= g_new (TSecHeader
, 1);
193 SecHeader
->link
= temp
;
199 if (state
== FirstBrace
) /* On first pass, don't allow dangling keys */
202 if ((c
== ' ' && state
!= KeyDefOnKey
) || c
== '\t')
205 if (c
== '\n' || overflow
) {
206 /* Abort Definition */
211 if (c
== '=' || overflow
){
214 temp
= SecHeader
->Keys
;
216 SecHeader
->Keys
=g_new (TKeys
, 1);
217 SecHeader
->Keys
->link
= temp
;
218 SecHeader
->Keys
->KeyName
= mhl_str_dup (CharBuffer
);
228 if (overflow
|| c
== '\n'){
230 SecHeader
->Keys
->Value
= str_translate_newline_dup (CharBuffer
);
231 state
= c
== '\n' ? KeyDef
: IgnoreToEOL
;
234 printf ("[%s] (%s)=%s\n", SecHeader
->AppName
,
235 SecHeader
->Keys
->KeyName
, SecHeader
->Keys
->Value
);
243 } /* while ((c = getc (f)) != EOF) */
248 SecHeader
->Keys
->Value
= str_translate_newline_dup (CharBuffer
);
250 case OnSecHeader
: { /* Broken initialization file */
251 TSecHeader
*link
= SecHeader
->link
;
254 fprintf (stderr
, "Warning: Corrupted initialization file `%s'\n",
264 static void new_key (TSecHeader
*section
, const char *KeyName
, const char *Value
)
268 key
= g_new (TKeys
, 1);
269 key
->KeyName
= mhl_str_dup (KeyName
);
270 key
->Value
= mhl_str_dup (Value
);
271 key
->link
= section
->Keys
;
276 GetSetProfileChar (int set
, const char *AppName
, const char *KeyName
,
277 const char *Default
, const char *FileName
)
284 Current
= find_loaded (FileName
, §ion
);
286 Current
= g_new (TProfile
, 1);
287 Current
->link
= Base
;
288 Current
->FileName
= mhl_str_dup (FileName
);
289 Current
->Section
= load (FileName
);
291 section
= Current
->Section
;
295 for (; section
; section
= section
->link
){
296 if (section
->AppName
== 0 || g_strcasecmp (section
->AppName
, AppName
))
298 for (key
= section
->Keys
; key
; key
= key
->link
){
299 if ( g_strcasecmp (key
->KeyName
, KeyName
))
303 key
->Value
= mhl_str_dup (Default
);
307 /* If getting the information, then don't write the information
308 to the INI file, need to run a couple of tests with windog */
311 new_key (section
, KeyName
, Default
);
316 /* Non existent section */
318 section
= g_new (TSecHeader
, 1);
319 section
->AppName
= mhl_str_dup (AppName
);
321 new_key (section
, KeyName
, Default
);
322 section
->link
= Current
->Section
;
323 Current
->Section
= section
;
328 static short GetSetProfile (int set
, const char * AppName
, const char * KeyName
,
329 const char * Default
, char * ReturnedString
,
330 short Size
, const char * FileName
)
335 s
= GetSetProfileChar (set
, AppName
, KeyName
, Default
, FileName
);
337 g_strlcpy (ReturnedString
, s
, Size
);
342 short GetPrivateProfileString (const char * AppName
, const char * KeyName
,
343 const char * Default
, char * ReturnedString
,
344 short Size
, const char * FileName
)
346 return (GetSetProfile (0, AppName
, KeyName
, Default
, ReturnedString
, Size
, FileName
));
349 const char *get_profile_string (const char *AppName
, const char *KeyName
, const char *Default
,
350 const char *FileName
)
352 return GetSetProfileChar (0, AppName
, KeyName
, Default
, FileName
);
355 int GetPrivateProfileInt (const char * AppName
, const char * KeyName
, int Default
,
358 char IntBuf
[BUF_TINY
];
361 g_snprintf (buf
, sizeof (buf
), "%d", Default
);
363 /* Check the exact semantic with the SDK */
364 GetPrivateProfileString (AppName
, KeyName
, buf
, IntBuf
, BUF_TINY
, File
);
365 if (! g_strcasecmp (IntBuf
, "true"))
367 if (! g_strcasecmp (IntBuf
, "yes"))
369 return (int) atol (IntBuf
);
372 int WritePrivateProfileString (const char * AppName
, const char * KeyName
, const char * String
,
373 const char * FileName
)
375 return GetSetProfile (1, AppName
, KeyName
, String
, NULL
, 0, FileName
);
378 static void dump_keys (FILE * profile
, TKeys
* p
)
383 dump_keys (profile
, p
->link
);
384 t
= str_untranslate_newline_dup (p
->Value
);
385 fprintf (profile
, "%s=%s\n", p
->KeyName
, t
);
389 static void dump_sections (FILE *profile
, TSecHeader
*p
)
393 dump_sections (profile
, p
->link
);
395 fprintf (profile
, "\n[%s]\n", p
->AppName
);
396 dump_keys (profile
, p
->Keys
);
400 static void dump_profile (TProfile
*p
)
406 dump_profile (p
->link
);
407 /* .ado: p->FileName can be empty, it's better to jump over */
408 if (p
->FileName
[0] != (char) 0)
409 if ((profile
= fopen (p
->FileName
, "w")) != NULL
){
410 dump_sections (profile
, p
->Section
);
416 * Must be called at the end of wine run
419 void sync_profiles (void)
424 static void free_keys (TKeys
*p
)
434 static void free_sections (TSecHeader
*p
)
438 free_sections (p
->link
);
446 static void free_profile (TProfile
*p
)
450 free_profile (p
->link
);
451 free_sections (p
->Section
);
452 g_free (p
->FileName
);
456 void free_profile_name (const char *s
)
463 for (p
= Base
; p
; p
= p
->link
){
464 if (strcmp (s
, p
->FileName
) == 0){
465 free_sections (p
->Section
);
473 void free_profiles (void)
478 void *profile_init_iterator (const char *appname
, const char *file
)
483 Current
= find_loaded (file
, §ion
);
485 Current
= g_new (TProfile
, 1);
486 Current
->link
= Base
;
487 Current
->FileName
= mhl_str_dup (file
);
488 Current
->Section
= load (file
);
490 section
= Current
->Section
;
492 for (; section
; section
= section
->link
){
493 if ( g_strcasecmp (section
->AppName
, appname
))
495 return section
->Keys
;
500 void *profile_iterator_next (void *s
, char **key
, char **value
)
502 TKeys
*keys
= (TKeys
*) s
;
505 *key
= keys
->KeyName
;
506 *value
= keys
->Value
;
512 void profile_clean_section (const char *appname
, const char *file
)
516 /* We assume the user has called one of the other initialization funcs */
517 if (!find_loaded (file
, §ion
)){
518 fprintf (stderr
,"Warning: profile_clean_section called before init\n");
521 /* We only disable the section, so it will still be freed, but it */
522 /* won't be find by further walks of the structure */
524 for (; section
; section
= section
->link
){
525 if ( g_strcasecmp (section
->AppName
, appname
))
527 section
->AppName
[0] = 0;
531 int profile_has_section (const char *section_name
, const char *profile
)
535 /* We assume the user has called one of the other initialization funcs */
536 if (!find_loaded (profile
, §ion
)){
539 for (; section
; section
= section
->link
){
540 if ( g_strcasecmp (section
->AppName
, section_name
))
547 void profile_forget_profile (const char *file
)
551 for (p
= Base
; p
; p
= p
->link
){
552 if ( g_strcasecmp (file
, p
->FileName
))