2 * Initialization-File Functions.
4 * From the Wine project
6 Copyright (C) 1993, 1994 Miguel de Icaza.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include <sys/types.h>
31 #define overflow (next == &CharBuffer [STRSIZE-1])
33 enum { FirstBrace
, OnSecHeader
, IgnoreToEOL
, KeyDef
, KeyDefOnKey
, KeyValue
};
35 typedef struct TKeys
{
41 typedef struct TSecHeader
{
44 struct TSecHeader
*link
;
47 typedef struct TProfile
{
50 struct TProfile
*link
;
53 static TProfile
*Base
= 0;
56 find_loaded (char *FileName
, TSecHeader
** section
)
61 if (!g_strcasecmp (FileName
, p
->FileName
)) {
62 *section
= p
->Section
;
70 #define TRANSLATION_CHAR '\200'
73 str_untranslate_newline_dup (char *s
)
77 g_return_val_if_fail(s
, NULL
);
80 l
+= (*p
== '\n' || *p
== TRANSLATION_CHAR
);
83 q
= p
= g_malloc (l
+ 1);
89 *p
++ = TRANSLATION_CHAR
;
92 case TRANSLATION_CHAR
:
93 if (s
[1] == 'n' || s
[1] == TRANSLATION_CHAR
)
94 *p
++ = TRANSLATION_CHAR
;
95 *p
++ = TRANSLATION_CHAR
;
106 return 0; /* not reached */
110 str_translate_newline_dup (char *s
)
113 g_return_val_if_fail(s
,NULL
);
114 q
= p
= g_malloc (strlen (s
) + 1);
118 if (*s
== TRANSLATION_CHAR
) {
123 case TRANSLATION_CHAR
:
124 *p
++ = TRANSLATION_CHAR
;
127 *p
++ = TRANSLATION_CHAR
;
131 *p
++ = TRANSLATION_CHAR
;
140 return q
; /* not reached */
143 static TSecHeader
*load (char *file
)
147 TSecHeader
*SecHeader
= 0;
148 char CharBuffer
[STRSIZE
];
149 char *next
= ""; /* Not needed */
152 if ((f
= fopen (file
, "r"))==NULL
)
156 while ((c
= getc (f
)) != EOF
){
157 if (c
== '\r') /* Ignore Carriage Return */
163 if (c
== ']' || overflow
){
166 SecHeader
->AppName
= g_strdup (CharBuffer
);
186 SecHeader
= g_new (TSecHeader
, 1);
187 SecHeader
->link
= temp
;
193 if (state
== FirstBrace
) /* On first pass, don't allow dangling keys */
196 if ((c
== ' ' && state
!= KeyDefOnKey
) || c
== '\t')
199 if (c
== '\n' || overflow
) /* Abort Definition */
202 if (c
== '=' || overflow
){
205 temp
= SecHeader
->Keys
;
207 SecHeader
->Keys
=g_new (TKeys
, 1);
208 SecHeader
->Keys
->link
= temp
;
209 SecHeader
->Keys
->KeyName
= g_strdup (CharBuffer
);
219 if (overflow
|| c
== '\n'){
221 SecHeader
->Keys
->Value
= str_translate_newline_dup (CharBuffer
);
222 state
= c
== '\n' ? KeyDef
: IgnoreToEOL
;
225 printf ("[%s] (%s)=%s\n", SecHeader
->AppName
,
226 SecHeader
->Keys
->KeyName
, SecHeader
->Keys
->Value
);
234 } /* while ((c = getc (f)) != EOF) */
235 if (c
== EOF
&& state
== KeyValue
){
237 SecHeader
->Keys
->Value
= str_translate_newline_dup (CharBuffer
);
243 static void new_key (TSecHeader
*section
, char *KeyName
, char *Value
)
247 key
= g_new (TKeys
, 1);
248 key
->KeyName
= g_strdup (KeyName
);
249 key
->Value
= g_strdup (Value
);
250 key
->link
= section
->Keys
;
255 GetSetProfileChar (int set
, const char *AppName
, char *KeyName
,
256 char *Default
, char *FileName
)
263 Current
= find_loaded (FileName
, §ion
);
265 Current
= g_new (TProfile
, 1);
266 Current
->link
= Base
;
267 Current
->FileName
= g_strdup (FileName
);
268 Current
->Section
= load (FileName
);
270 section
= Current
->Section
;
274 for (; section
; section
= section
->link
){
275 if (section
->AppName
== 0 || g_strcasecmp (section
->AppName
, AppName
))
277 for (key
= section
->Keys
; key
; key
= key
->link
){
278 if ( g_strcasecmp (key
->KeyName
, KeyName
))
282 key
->Value
= g_strdup (Default
);
286 /* If getting the information, then don't write the information
287 to the INI file, need to run a couple of tests with windog */
290 new_key (section
, KeyName
, Default
);
295 /* Non existent section */
297 section
= g_new (TSecHeader
, 1);
298 section
->AppName
= g_strdup (AppName
);
300 new_key (section
, KeyName
, Default
);
301 section
->link
= Current
->Section
;
302 Current
->Section
= section
;
307 static short GetSetProfile (int set
, const char * AppName
, char * KeyName
,
308 char * Default
, char * ReturnedString
,
309 short Size
, char * FileName
)
314 s
= GetSetProfileChar (set
, AppName
, KeyName
, Default
, FileName
);
316 ReturnedString
[Size
-1] = 0;
317 strncpy (ReturnedString
, s
, Size
-1);
322 short GetPrivateProfileString (const char * AppName
, char * KeyName
,
323 char * Default
, char * ReturnedString
,
324 short Size
, char * FileName
)
326 return (GetSetProfile (0, AppName
, KeyName
, Default
, ReturnedString
, Size
, FileName
));
329 char *get_profile_string (const char *AppName
, char *KeyName
, char *Default
,
332 return GetSetProfileChar (0, AppName
, KeyName
, Default
, FileName
);
335 int GetPrivateProfileInt (const char * AppName
, char * KeyName
, int Default
,
338 static char IntBuf
[BUF_TINY
];
339 static char buf
[BUF_TINY
];
341 g_snprintf (buf
, sizeof (buf
), "%d", Default
);
343 /* Check the exact semantic with the SDK */
344 GetPrivateProfileString (AppName
, KeyName
, buf
, IntBuf
, BUF_TINY
, File
);
345 if (! g_strcasecmp (IntBuf
, "true"))
347 if (! g_strcasecmp (IntBuf
, "yes"))
349 return (int) atol (IntBuf
);
352 int WritePrivateProfileString (const char * AppName
, char * KeyName
, char * String
,
355 return GetSetProfile (1, AppName
, KeyName
, String
, "", 0, FileName
);
358 static void dump_keys (FILE * profile
, TKeys
* p
)
363 dump_keys (profile
, p
->link
);
364 t
= str_untranslate_newline_dup (p
->Value
);
365 fprintf (profile
, "%s=%s\n", p
->KeyName
, t
);
369 static void dump_sections (FILE *profile
, TSecHeader
*p
)
373 dump_sections (profile
, p
->link
);
375 fprintf (profile
, "\n[%s]\n", p
->AppName
);
376 dump_keys (profile
, p
->Keys
);
380 static void dump_profile (TProfile
*p
)
386 dump_profile (p
->link
);
387 /* .ado: p->FileName can be empty, it's better to jump over */
388 if (p
->FileName
[0] != (char) 0)
389 if ((profile
= fopen (p
->FileName
, "w")) != NULL
){
390 dump_sections (profile
, p
->Section
);
396 * Must be called at the end of wine run
399 void sync_profiles (void)
404 static void free_keys (TKeys
*p
)
414 static void free_sections (TSecHeader
*p
)
418 free_sections (p
->link
);
426 static void free_profile (TProfile
*p
)
430 free_profile (p
->link
);
431 free_sections (p
->Section
);
432 g_free (p
->FileName
);
436 void free_profile_name (char *s
)
443 for (p
= Base
; p
; p
= p
->link
){
444 if (strcmp (s
, p
->FileName
) == 0){
445 free_sections (p
->Section
);
453 void free_profiles (void)
458 void *profile_init_iterator (char *appname
, char *file
)
463 Current
= find_loaded (file
, §ion
);
465 Current
= g_new (TProfile
, 1);
466 Current
->link
= Base
;
467 Current
->FileName
= g_strdup (file
);
468 Current
->Section
= load (file
);
470 section
= Current
->Section
;
472 for (; section
; section
= section
->link
){
473 if ( g_strcasecmp (section
->AppName
, appname
))
475 return section
->Keys
;
480 void *profile_iterator_next (void *s
, char **key
, char **value
)
482 TKeys
*keys
= (TKeys
*) s
;
485 *key
= keys
->KeyName
;
486 *value
= keys
->Value
;
492 void profile_clean_section (char *appname
, char *file
)
496 /* We assume the user has called one of the other initialization funcs */
497 if (!find_loaded (file
, §ion
)){
498 fprintf (stderr
,"Warning: profile_clean_section called before init\n");
501 /* We only disable the section, so it will still be freed, but it */
502 /* won't be find by further walks of the structure */
504 for (; section
; section
= section
->link
){
505 if ( g_strcasecmp (section
->AppName
, appname
))
507 section
->AppName
[0] = 0;
511 int profile_has_section (char *section_name
, char *profile
)
515 /* We assume the user has called one of the other initialization funcs */
516 if (!find_loaded (profile
, §ion
)){
519 for (; section
; section
= section
->link
){
520 if ( g_strcasecmp (section
->AppName
, section_name
))
527 void profile_forget_profile (char *file
)
531 for (p
= Base
; p
; p
= p
->link
){
532 if ( g_strcasecmp (file
, p
->FileName
))