replaced calls to g_strdup() by mhl_str_dup()
[midnight-commander.git] / src / profile.c
blob05d774c23a62aa0904b3c4cb2be0019407236b8b
1 /*
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.
24 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
31 #include <mhl/string.h>
33 #include "global.h"
34 #include "profile.h"
36 #define STRSIZE 4096
37 #define overflow (next == &CharBuffer [STRSIZE-1])
39 enum { FirstBrace, OnSecHeader, IgnoreToEOL, KeyDef, KeyDefOnKey, KeyValue };
41 typedef struct TKeys {
42 char *KeyName;
43 char *Value;
44 struct TKeys *link;
45 } TKeys;
47 typedef struct TSecHeader {
48 char *AppName;
49 TKeys *Keys;
50 struct TSecHeader *link;
51 } TSecHeader;
53 typedef struct TProfile {
54 char *FileName;
55 TSecHeader *Section;
56 struct TProfile *link;
57 } TProfile;
59 static TProfile *Base = 0;
61 static TProfile *
62 find_loaded (const char *FileName, TSecHeader ** section)
64 TProfile *p = Base;
66 while (p) {
67 if (!g_strcasecmp (FileName, p->FileName)) {
68 *section = p->Section;
69 return p;
71 p = p->link;
73 return NULL;
76 #define TRANSLATION_CHAR '\200'
78 static char *
79 str_untranslate_newline_dup (char *s)
81 int l = 0;
82 char *p = s, *q;
83 g_return_val_if_fail(s, NULL);
84 while (*p) {
85 l++;
86 l += (*p == '\n' || *p == TRANSLATION_CHAR);
87 p++;
89 q = p = g_malloc (l + 1);
90 if (!q)
91 return 0;
92 for (;;) {
93 switch (*s) {
94 case '\n':
95 *p++ = TRANSLATION_CHAR;
96 *p++ = 'n';
97 break;
98 case TRANSLATION_CHAR:
99 if (s[1] == 'n' || s[1] == TRANSLATION_CHAR)
100 *p++ = TRANSLATION_CHAR;
101 *p++ = TRANSLATION_CHAR;
102 break;
103 case '\0':
104 *p = '\0';
105 return q;
106 break;
107 default:
108 *p++ = *s;
110 s++;
112 return 0; /* not reached */
115 static char *
116 str_translate_newline_dup (char *s)
118 char *p, *q;
119 g_return_val_if_fail(s,NULL);
120 q = p = g_malloc (strlen (s) + 1);
121 if (!q)
122 return 0;
123 while (*s) {
124 if (*s == TRANSLATION_CHAR) {
125 switch (*(++s)) {
126 case 'n':
127 *p++ = '\n';
128 break;
129 case TRANSLATION_CHAR:
130 *p++ = TRANSLATION_CHAR;
131 break;
132 case '\0':
133 *p++ = TRANSLATION_CHAR;
134 *p++ = '\0';
135 return q;
136 default:
137 *p++ = TRANSLATION_CHAR;
138 *p++ = *s;
140 } else {
141 *p++ = *s;
143 s++;
145 *p = '\0';
146 return q; /* not reached */
149 static TSecHeader *load (const char *file)
151 FILE *f;
152 int state;
153 TSecHeader *SecHeader = 0;
154 char CharBuffer [STRSIZE];
155 char *next = NULL; /* Not needed */
156 int c;
158 if ((f = fopen (file, "r"))==NULL)
159 return NULL;
161 state = FirstBrace;
162 while ((c = getc (f)) != EOF){
163 if (c == '\r') /* Ignore Carriage Return */
164 continue;
166 switch (state){
168 case OnSecHeader:
169 if (c == ']' || overflow){
170 *next = '\0';
171 next = CharBuffer;
172 SecHeader->AppName = mhl_str_dup (CharBuffer);
173 state = IgnoreToEOL;
174 } else
175 *next++ = c;
176 break;
178 case IgnoreToEOL:
179 if (c == '\n'){
180 state = KeyDef;
181 next = CharBuffer;
183 break;
185 case FirstBrace:
186 case KeyDef:
187 case KeyDefOnKey:
188 if (c == '['){
189 TSecHeader *temp;
191 temp = SecHeader;
192 SecHeader = g_new (TSecHeader, 1);
193 SecHeader->link = temp;
194 SecHeader->Keys = 0;
195 state = OnSecHeader;
196 next = CharBuffer;
197 break;
199 if (state == FirstBrace) /* On first pass, don't allow dangling keys */
200 break;
202 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
203 break;
205 if (c == '\n' || overflow) {
206 /* Abort Definition */
207 next = CharBuffer;
208 break;
211 if (c == '=' || overflow){
212 TKeys *temp;
214 temp = SecHeader->Keys;
215 *next = '\0';
216 SecHeader->Keys =g_new (TKeys, 1);
217 SecHeader->Keys->link = temp;
218 SecHeader->Keys->KeyName = mhl_str_dup (CharBuffer);
219 state = KeyValue;
220 next = CharBuffer;
221 } else {
222 *next++ = c;
223 state = KeyDefOnKey;
225 break;
227 case KeyValue:
228 if (overflow || c == '\n'){
229 *next = '\0';
230 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
231 state = c == '\n' ? KeyDef : IgnoreToEOL;
232 next = CharBuffer;
233 #ifdef DEBUG
234 printf ("[%s] (%s)=%s\n", SecHeader->AppName,
235 SecHeader->Keys->KeyName, SecHeader->Keys->Value);
236 #endif
237 } else
238 *next++ = c;
239 break;
241 } /* switch */
243 } /* while ((c = getc (f)) != EOF) */
245 switch (state) {
246 case KeyValue:
247 *next = '\0';
248 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
249 break;
250 case OnSecHeader: { /* Broken initialization file */
251 TSecHeader *link = SecHeader->link;
252 g_free (SecHeader);
253 SecHeader = link;
254 fprintf (stderr, "Warning: Corrupted initialization file `%s'\n",
255 file);
256 break;
260 fclose (f);
261 return SecHeader;
264 static void new_key (TSecHeader *section, const char *KeyName, const char *Value)
266 TKeys *key;
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;
272 section->Keys = key;
275 static const char *
276 GetSetProfileChar (int set, const char *AppName, const char *KeyName,
277 const char *Default, const char *FileName)
280 TProfile *Current;
281 TSecHeader *section;
282 TKeys *key;
284 Current = find_loaded (FileName, &section);
285 if (!Current) {
286 Current = g_new (TProfile, 1);
287 Current->link = Base;
288 Current->FileName = mhl_str_dup (FileName);
289 Current->Section = load (FileName);
290 Base = Current;
291 section = Current->Section;
294 /* Start search */
295 for (; section; section = section->link){
296 if (section->AppName == 0 || g_strcasecmp (section->AppName, AppName))
297 continue;
298 for (key = section->Keys; key; key = key->link){
299 if ( g_strcasecmp (key->KeyName, KeyName))
300 continue;
301 if (set){
302 g_free (key->Value);
303 key->Value = mhl_str_dup (Default);
305 return key->Value;
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 */
309 /* No key found */
310 if (set){
311 new_key (section, KeyName, Default);
312 return 0;
316 /* Non existent section */
317 if (set && Default){
318 section = g_new (TSecHeader, 1);
319 section->AppName = mhl_str_dup (AppName);
320 section->Keys = 0;
321 new_key (section, KeyName, Default);
322 section->link = Current->Section;
323 Current->Section = section;
325 return Default;
328 static short GetSetProfile (int set, const char * AppName, const char * KeyName,
329 const char * Default, char * ReturnedString,
330 short Size, const char * FileName)
333 const char *s;
335 s = GetSetProfileChar (set, AppName, KeyName, Default, FileName);
336 if (!set)
337 g_strlcpy (ReturnedString, s, Size);
339 return 1;
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,
356 const char * File)
358 char IntBuf [BUF_TINY];
359 char buf [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"))
366 return 1;
367 if (! g_strcasecmp (IntBuf, "yes"))
368 return 1;
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)
380 char *t;
381 if (!p)
382 return;
383 dump_keys (profile, p->link);
384 t = str_untranslate_newline_dup (p->Value);
385 fprintf (profile, "%s=%s\n", p->KeyName, t);
386 g_free (t);
389 static void dump_sections (FILE *profile, TSecHeader *p)
391 if (!p)
392 return;
393 dump_sections (profile, p->link);
394 if (p->AppName [0]){
395 fprintf (profile, "\n[%s]\n", p->AppName);
396 dump_keys (profile, p->Keys);
400 static void dump_profile (TProfile *p)
402 FILE *profile;
404 if (!p)
405 return;
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);
411 fclose (profile);
416 * Must be called at the end of wine run
419 void sync_profiles (void)
421 dump_profile (Base);
424 static void free_keys (TKeys *p)
426 if (!p)
427 return;
428 free_keys (p->link);
429 g_free (p->KeyName);
430 g_free (p->Value);
431 g_free (p);
434 static void free_sections (TSecHeader *p)
436 if (!p)
437 return;
438 free_sections (p->link);
439 free_keys (p->Keys);
440 g_free (p->AppName);
441 p->link = 0;
442 p->Keys = 0;
443 g_free (p);
446 static void free_profile (TProfile *p)
448 if (!p)
449 return;
450 free_profile (p->link);
451 free_sections (p->Section);
452 g_free (p->FileName);
453 g_free (p);
456 void free_profile_name (const char *s)
458 TProfile *p;
460 if (!s)
461 return;
463 for (p = Base; p; p = p->link){
464 if (strcmp (s, p->FileName) == 0){
465 free_sections (p->Section);
466 p->Section = 0;
467 p->FileName [0] = 0;
468 return;
473 void free_profiles (void)
475 free_profile (Base);
478 void *profile_init_iterator (const char *appname, const char *file)
480 TProfile *Current;
481 TSecHeader *section;
483 Current = find_loaded (file, &section);
484 if (!Current) {
485 Current = g_new (TProfile, 1);
486 Current->link = Base;
487 Current->FileName = mhl_str_dup (file);
488 Current->Section = load (file);
489 Base = Current;
490 section = Current->Section;
492 for (; section; section = section->link){
493 if ( g_strcasecmp (section->AppName, appname))
494 continue;
495 return section->Keys;
497 return 0;
500 void *profile_iterator_next (void *s, char **key, char **value)
502 TKeys *keys = (TKeys *) s;
504 if (keys){
505 *key = keys->KeyName;
506 *value = keys->Value;
507 keys = keys->link;
509 return keys;
512 void profile_clean_section (const char *appname, const char *file)
514 TSecHeader *section;
516 /* We assume the user has called one of the other initialization funcs */
517 if (!find_loaded (file, &section)){
518 fprintf (stderr,"Warning: profile_clean_section called before init\n");
519 return;
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))
526 continue;
527 section->AppName [0] = 0;
531 int profile_has_section (const char *section_name, const char *profile)
533 TSecHeader *section;
535 /* We assume the user has called one of the other initialization funcs */
536 if (!find_loaded (profile, &section)){
537 return 0;
539 for (; section; section = section->link){
540 if ( g_strcasecmp (section->AppName, section_name))
541 continue;
542 return 1;
544 return 0;
547 void profile_forget_profile (const char *file)
549 TProfile *p;
551 for (p = Base; p; p = p->link){
552 if ( g_strcasecmp (file, p->FileName))
553 continue;
554 p->FileName [0] = 0;