Updated italian translation
[midnight-commander.git] / src / profile.c
blob94eb1a4c27815d5631bc060ea9b6fed7be2fa578
1 /*
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <config.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include <sys/types.h>
31 #include "global.h"
32 #include "profile.h"
34 #define STRSIZE 4096
35 #define overflow (next == &CharBuffer [STRSIZE-1])
37 enum { FirstBrace, OnSecHeader, IgnoreToEOL, KeyDef, KeyDefOnKey, KeyValue };
39 typedef struct TKeys {
40 char *KeyName;
41 char *Value;
42 struct TKeys *link;
43 } TKeys;
45 typedef struct TSecHeader {
46 char *AppName;
47 TKeys *Keys;
48 struct TSecHeader *link;
49 } TSecHeader;
51 typedef struct TProfile {
52 char *FileName;
53 TSecHeader *Section;
54 struct TProfile *link;
55 } TProfile;
57 static TProfile *Base = 0;
59 static TProfile *
60 find_loaded (const char *FileName, TSecHeader ** section)
62 TProfile *p = Base;
64 while (p) {
65 if (!g_strcasecmp (FileName, p->FileName)) {
66 *section = p->Section;
67 return p;
69 p = p->link;
71 return NULL;
74 #define TRANSLATION_CHAR '\200'
76 static char *
77 str_untranslate_newline_dup (char *s)
79 int l = 0;
80 char *p = s, *q;
81 g_return_val_if_fail(s, NULL);
82 while (*p) {
83 l++;
84 l += (*p == '\n' || *p == TRANSLATION_CHAR);
85 p++;
87 q = p = g_malloc (l + 1);
88 if (!q)
89 return 0;
90 for (;;) {
91 switch (*s) {
92 case '\n':
93 *p++ = TRANSLATION_CHAR;
94 *p++ = 'n';
95 break;
96 case TRANSLATION_CHAR:
97 if (s[1] == 'n' || s[1] == TRANSLATION_CHAR)
98 *p++ = TRANSLATION_CHAR;
99 *p++ = TRANSLATION_CHAR;
100 break;
101 case '\0':
102 *p = '\0';
103 return q;
104 break;
105 default:
106 *p++ = *s;
108 s++;
110 return 0; /* not reached */
113 static char *
114 str_translate_newline_dup (char *s)
116 char *p, *q;
117 g_return_val_if_fail(s,NULL);
118 q = p = g_malloc (strlen (s) + 1);
119 if (!q)
120 return 0;
121 while (*s) {
122 if (*s == TRANSLATION_CHAR) {
123 switch (*(++s)) {
124 case 'n':
125 *p++ = '\n';
126 break;
127 case TRANSLATION_CHAR:
128 *p++ = TRANSLATION_CHAR;
129 break;
130 case '\0':
131 *p++ = TRANSLATION_CHAR;
132 *p++ = '\0';
133 return q;
134 default:
135 *p++ = TRANSLATION_CHAR;
136 *p++ = *s;
138 } else {
139 *p++ = *s;
141 s++;
143 *p = '\0';
144 return q; /* not reached */
147 static TSecHeader *load (const char *file)
149 FILE *f;
150 int state;
151 TSecHeader *SecHeader = 0;
152 char CharBuffer [STRSIZE];
153 char *next = NULL; /* Not needed */
154 int c;
156 if ((f = fopen (file, "r"))==NULL)
157 return NULL;
159 state = FirstBrace;
160 while ((c = getc (f)) != EOF){
161 if (c == '\r') /* Ignore Carriage Return */
162 continue;
164 switch (state){
166 case OnSecHeader:
167 if (c == ']' || overflow){
168 *next = '\0';
169 next = CharBuffer;
170 SecHeader->AppName = g_strdup (CharBuffer);
171 state = IgnoreToEOL;
172 } else
173 *next++ = c;
174 break;
176 case IgnoreToEOL:
177 if (c == '\n'){
178 state = KeyDef;
179 next = CharBuffer;
181 break;
183 case FirstBrace:
184 case KeyDef:
185 case KeyDefOnKey:
186 if (c == '['){
187 TSecHeader *temp;
189 temp = SecHeader;
190 SecHeader = g_new (TSecHeader, 1);
191 SecHeader->link = temp;
192 SecHeader->Keys = 0;
193 state = OnSecHeader;
194 next = CharBuffer;
195 break;
197 if (state == FirstBrace) /* On first pass, don't allow dangling keys */
198 break;
200 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
201 break;
203 if (c == '\n' || overflow) {
204 /* Abort Definition */
205 next = CharBuffer;
206 break;
209 if (c == '=' || overflow){
210 TKeys *temp;
212 temp = SecHeader->Keys;
213 *next = '\0';
214 SecHeader->Keys =g_new (TKeys, 1);
215 SecHeader->Keys->link = temp;
216 SecHeader->Keys->KeyName = g_strdup (CharBuffer);
217 state = KeyValue;
218 next = CharBuffer;
219 } else {
220 *next++ = c;
221 state = KeyDefOnKey;
223 break;
225 case KeyValue:
226 if (overflow || c == '\n'){
227 *next = '\0';
228 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
229 state = c == '\n' ? KeyDef : IgnoreToEOL;
230 next = CharBuffer;
231 #ifdef DEBUG
232 printf ("[%s] (%s)=%s\n", SecHeader->AppName,
233 SecHeader->Keys->KeyName, SecHeader->Keys->Value);
234 #endif
235 } else
236 *next++ = c;
237 break;
239 } /* switch */
241 } /* while ((c = getc (f)) != EOF) */
243 switch (state) {
244 case KeyValue:
245 *next = '\0';
246 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
247 break;
248 case OnSecHeader: { /* Broken initialization file */
249 TSecHeader *link = SecHeader->link;
250 g_free (SecHeader);
251 SecHeader = link;
252 fprintf (stderr, "Warning: Corrupted initialization file `%s'\n",
253 file);
254 break;
258 fclose (f);
259 return SecHeader;
262 static void new_key (TSecHeader *section, const char *KeyName, const char *Value)
264 TKeys *key;
266 key = g_new (TKeys, 1);
267 key->KeyName = g_strdup (KeyName);
268 key->Value = g_strdup (Value);
269 key->link = section->Keys;
270 section->Keys = key;
273 static const char *
274 GetSetProfileChar (int set, const char *AppName, const char *KeyName,
275 const char *Default, const char *FileName)
278 TProfile *Current;
279 TSecHeader *section;
280 TKeys *key;
282 Current = find_loaded (FileName, &section);
283 if (!Current) {
284 Current = g_new (TProfile, 1);
285 Current->link = Base;
286 Current->FileName = g_strdup (FileName);
287 Current->Section = load (FileName);
288 Base = Current;
289 section = Current->Section;
292 /* Start search */
293 for (; section; section = section->link){
294 if (section->AppName == 0 || g_strcasecmp (section->AppName, AppName))
295 continue;
296 for (key = section->Keys; key; key = key->link){
297 if ( g_strcasecmp (key->KeyName, KeyName))
298 continue;
299 if (set){
300 g_free (key->Value);
301 key->Value = g_strdup (Default);
303 return key->Value;
305 /* If getting the information, then don't write the information
306 to the INI file, need to run a couple of tests with windog */
307 /* No key found */
308 if (set){
309 new_key (section, KeyName, Default);
310 return 0;
314 /* Non existent section */
315 if (set && Default){
316 section = g_new (TSecHeader, 1);
317 section->AppName = g_strdup (AppName);
318 section->Keys = 0;
319 new_key (section, KeyName, Default);
320 section->link = Current->Section;
321 Current->Section = section;
323 return Default;
326 static short GetSetProfile (int set, const char * AppName, const char * KeyName,
327 const char * Default, char * ReturnedString,
328 short Size, const char * FileName)
331 const char *s;
333 s = GetSetProfileChar (set, AppName, KeyName, Default, FileName);
334 if (!set)
335 g_strlcpy (ReturnedString, s, Size);
337 return 1;
340 short GetPrivateProfileString (const char * AppName, const char * KeyName,
341 const char * Default, char * ReturnedString,
342 short Size, const char * FileName)
344 return (GetSetProfile (0, AppName, KeyName, Default, ReturnedString, Size, FileName));
347 const char *get_profile_string (const char *AppName, const char *KeyName, const char *Default,
348 const char *FileName)
350 return GetSetProfileChar (0, AppName, KeyName, Default, FileName);
353 int GetPrivateProfileInt (const char * AppName, const char * KeyName, int Default,
354 const char * File)
356 char IntBuf [BUF_TINY];
357 char buf [BUF_TINY];
359 g_snprintf (buf, sizeof (buf), "%d", Default);
361 /* Check the exact semantic with the SDK */
362 GetPrivateProfileString (AppName, KeyName, buf, IntBuf, BUF_TINY, File);
363 if (! g_strcasecmp (IntBuf, "true"))
364 return 1;
365 if (! g_strcasecmp (IntBuf, "yes"))
366 return 1;
367 return (int) atol (IntBuf);
370 int WritePrivateProfileString (const char * AppName, const char * KeyName, const char * String,
371 const char * FileName)
373 return GetSetProfile (1, AppName, KeyName, String, NULL, 0, FileName);
376 static void dump_keys (FILE * profile, TKeys * p)
378 char *t;
379 if (!p)
380 return;
381 dump_keys (profile, p->link);
382 t = str_untranslate_newline_dup (p->Value);
383 fprintf (profile, "%s=%s\n", p->KeyName, t);
384 g_free (t);
387 static void dump_sections (FILE *profile, TSecHeader *p)
389 if (!p)
390 return;
391 dump_sections (profile, p->link);
392 if (p->AppName [0]){
393 fprintf (profile, "\n[%s]\n", p->AppName);
394 dump_keys (profile, p->Keys);
398 static void dump_profile (TProfile *p)
400 FILE *profile;
402 if (!p)
403 return;
404 dump_profile (p->link);
405 /* .ado: p->FileName can be empty, it's better to jump over */
406 if (p->FileName[0] != (char) 0)
407 if ((profile = fopen (p->FileName, "w")) != NULL){
408 dump_sections (profile, p->Section);
409 fclose (profile);
414 * Must be called at the end of wine run
417 void sync_profiles (void)
419 dump_profile (Base);
422 static void free_keys (TKeys *p)
424 if (!p)
425 return;
426 free_keys (p->link);
427 g_free (p->KeyName);
428 g_free (p->Value);
429 g_free (p);
432 static void free_sections (TSecHeader *p)
434 if (!p)
435 return;
436 free_sections (p->link);
437 free_keys (p->Keys);
438 g_free (p->AppName);
439 p->link = 0;
440 p->Keys = 0;
441 g_free (p);
444 static void free_profile (TProfile *p)
446 if (!p)
447 return;
448 free_profile (p->link);
449 free_sections (p->Section);
450 g_free (p->FileName);
451 g_free (p);
454 void free_profile_name (const char *s)
456 TProfile *p;
458 if (!s)
459 return;
461 for (p = Base; p; p = p->link){
462 if (strcmp (s, p->FileName) == 0){
463 free_sections (p->Section);
464 p->Section = 0;
465 p->FileName [0] = 0;
466 return;
471 void free_profiles (void)
473 free_profile (Base);
476 void *profile_init_iterator (const char *appname, const char *file)
478 TProfile *Current;
479 TSecHeader *section;
481 Current = find_loaded (file, &section);
482 if (!Current) {
483 Current = g_new (TProfile, 1);
484 Current->link = Base;
485 Current->FileName = g_strdup (file);
486 Current->Section = load (file);
487 Base = Current;
488 section = Current->Section;
490 for (; section; section = section->link){
491 if ( g_strcasecmp (section->AppName, appname))
492 continue;
493 return section->Keys;
495 return 0;
498 void *profile_iterator_next (void *s, char **key, char **value)
500 TKeys *keys = (TKeys *) s;
502 if (keys){
503 *key = keys->KeyName;
504 *value = keys->Value;
505 keys = keys->link;
507 return keys;
510 void profile_clean_section (const char *appname, const char *file)
512 TSecHeader *section;
514 /* We assume the user has called one of the other initialization funcs */
515 if (!find_loaded (file, &section)){
516 fprintf (stderr,"Warning: profile_clean_section called before init\n");
517 return;
519 /* We only disable the section, so it will still be freed, but it */
520 /* won't be find by further walks of the structure */
522 for (; section; section = section->link){
523 if ( g_strcasecmp (section->AppName, appname))
524 continue;
525 section->AppName [0] = 0;
529 int profile_has_section (const char *section_name, const char *profile)
531 TSecHeader *section;
533 /* We assume the user has called one of the other initialization funcs */
534 if (!find_loaded (profile, &section)){
535 return 0;
537 for (; section; section = section->link){
538 if ( g_strcasecmp (section->AppName, section_name))
539 continue;
540 return 1;
542 return 0;
545 void profile_forget_profile (const char *file)
547 TProfile *p;
549 for (p = Base; p; p = p->link){
550 if ( g_strcasecmp (file, p->FileName))
551 continue;
552 p->FileName [0] = 0;