fix parsing language native names. use AllocVecPooled for the flag name.
[AROS.git] / workbench / prefs / locale / prefs.c
blobebfe6f081e4ce0aa8c58ce62869c56f7ab1b941d
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /*********************************************************************************************/
8 #include <aros/debug.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
12 #include <proto/locale.h>
13 #include <proto/utility.h>
14 #include <proto/alib.h>
15 #include <proto/iffparse.h>
17 #include <aros/macros.h>
19 #include <prefs/prefhdr.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
25 #include "prefs.h"
26 #include "misc.h"
28 /*********************************************************************************************/
30 #define PREFS_PATH_ENVARC "ENVARC:SYS/locale.prefs"
31 #define PREFS_PATH_ENV "ENV:SYS/locale.prefs"
33 /*********************************************************************************************/
35 struct FilePrefHeader
37 UBYTE ph_Version;
38 UBYTE ph_Type;
39 UBYTE ph_Flags[4];
42 /*********************************************************************************************/
44 struct LocalePrefs localeprefs;
45 char character_set[CHARACTER_SET_LEN];
46 char restore_charset[CHARACTER_SET_LEN];
47 struct List region_list;
48 struct List language_list;
49 struct List pref_language_list;
51 /*********************************************************************************************/
53 static APTR mempool;
55 const char *flagpathstr = "\033I[5:Locale:Flags/";
57 /*********************************************************************************************/
59 STATIC VOID SortInNode(struct List *list, struct Node *node)
61 struct Node *sort, *prev = NULL;
62 struct Locale *loc;
64 loc = OpenLocale(NULL);
66 ForeachNode(list, sort)
68 if (StrnCmp(loc,
69 node->ln_Name, sort->ln_Name,
70 strlen(node->ln_Name), SC_COLLATE2)
71 < 0)
73 break;
75 prev = sort;
78 Insert(list, node, prev);
79 CloseLocale(loc);
82 /*********************************************************************************************/
84 char *GetAROSRegionAttribs(struct AnchorPath *ap, char **regionNamePtr)
86 char *lockFlag = NULL;
87 struct IFFHandle *iff;
88 struct ContextNode *cn;
89 LONG parse_mode = IFFPARSE_SCAN, error;
91 if ((iff = AllocIFF()))
93 if ((iff->iff_Stream = (IPTR)Open(ap->ap_Info.fib_FileName, MODE_OLDFILE)))
95 InitIFFasDOS(iff);
97 if (!OpenIFF(iff, IFFF_READ))
99 if (!StopChunk(iff, ID_PREF, ID_PRHD))
103 if ((error = ParseIFF(iff, parse_mode)) == 0)
105 parse_mode = IFFPARSE_STEP;
107 cn = CurrentChunk(iff);
108 D(bug("[LocalePrefs] GetAROSRegionAttribs: Chunk ID %08x. %d bytes\n", cn->cn_ID, cn->cn_Size));
110 if (cn->cn_ID == MAKE_ID('N','N','A','M'))
112 FreeVecPooled(mempool, *regionNamePtr);
113 *regionNamePtr = AllocVecPooled(mempool, cn->cn_Size);
114 ReadChunkBytes(iff, *regionNamePtr, cn->cn_Size);
115 D(bug("[LocalePrefs] GetAROSRegionAttribs: NativeNames '%s'\n", *regionNamePtr));
118 if (cn->cn_ID == MAKE_ID('F','L','A','G'))
120 lockFlag = AllocVecPooled(mempool, cn->cn_Size + 18 + 1);
121 sprintf(lockFlag, flagpathstr);
122 ReadChunkBytes(iff, lockFlag + 18, cn->cn_Size);
123 lockFlag[cn->cn_Size + 17] = ']';
124 D(bug("[LocalePrefs] GetAROSRegionAttribs: Flag '%s'\n", lockFlag));
127 } while ((error != IFFERR_EOF) && (error != IFFERR_NOTIFF));
129 CloseIFF(iff);
131 Close(iff->iff_Stream);
133 FreeIFF(iff);
136 return lockFlag;
139 char *GetAROSLanguageAttribs(struct AnchorPath *ap, char **languageNamePtr)
141 BPTR fileHandle;
142 char tmpbuff[32];
143 int read, len = 0, pos, i;
144 BOOL match = FALSE;
146 if ((fileHandle = Open(ap->ap_Info.fib_FileName, MODE_OLDFILE)) != BNULL)
148 while ((read = Read(fileHandle, &tmpbuff[len], sizeof(tmpbuff) - len)) > 0)
150 len = len + read;
152 if (match)
154 for (i = 0; i < len; i++)
156 if (tmpbuff[i] == '\0')
158 FreeVecPooled(mempool, *languageNamePtr);
159 *languageNamePtr = AllocVecPooled(mempool, i + 1);
160 CopyMem(tmpbuff, *languageNamePtr, i);
161 D(bug("[LocalePrefs] GetAROSLanguageAttribs: NativeName (A) '%s'\n", *languageNamePtr));
162 return *languageNamePtr;
164 /* we shouldnt really ever reach here .. */
167 else
169 pos = 0;
171 while ((len - pos) >= 7)
173 if (strncmp(&tmpbuff[pos], "$NLANG:", 7) == 0)
175 match = TRUE;
176 pos += 7;
178 if ((len - pos) > 0)
180 CopyMem(&tmpbuff[pos], tmpbuff, (len - pos));
181 len = len - pos;
182 for (i = 0; i < len; i++)
184 if (tmpbuff[i] == '\0')
186 FreeVecPooled(mempool, *languageNamePtr);
187 *languageNamePtr = AllocVecPooled(mempool, i + 1);
188 CopyMem(tmpbuff, *languageNamePtr, i);
189 D(bug("[LocalePrefs] GetAROSLanguageAttribs: NativeName (B) '%s'\n", *languageNamePtr));
190 return *languageNamePtr;
194 else
195 len = 0;
197 else
198 pos++;
200 if (!match && (pos < len))
202 CopyMem(&tmpbuff[pos], tmpbuff, (len - pos));
203 len = len - pos;
207 Close(fileHandle);
211 /*********************************************************************************************/
213 STATIC VOID ScanDirectory(char *pattern, struct List *list, LONG entrysize)
215 struct AnchorPath ap;
216 struct ListviewEntry *entry;
217 BPTR curdir = BNULL;
218 char *sp;
219 LONG error;
221 memset(&ap, 0, sizeof(ap));
223 if ((error = MatchFirst(pattern, &ap)) == 0)
224 curdir = CurrentDir(ap.ap_Current->an_Lock);
226 while((error == 0))
228 if (ap.ap_Info.fib_DirEntryType < 0)
230 entry = (struct ListviewEntry *)AllocPooled(mempool, entrysize);
231 if (entry)
233 entry->node.ln_Name = AllocVecPooled(mempool, strlen(ap.ap_Info.fib_FileName));
234 strcpy(entry->node.ln_Name, ap.ap_Info.fib_FileName);
236 entry->node.ln_Name[0] = ToUpper(entry->node.ln_Name[0]);
237 if ((sp = strchr(entry->node.ln_Name, '.')) != NULL)
238 sp[0] = '\0';
240 strcpy(entry->realname, entry->node.ln_Name);
242 if (entrysize == sizeof(struct RegionEntry))
244 D(bug("[LocalePrefs] ScanDir: Checking for FLAG chunk\n"));
245 if (!(entry->displayflag = GetAROSRegionAttribs(&ap, &entry->node.ln_Name)))
247 entry->displayflag = AllocVecPooled(mempool, strlen(entry->realname) + strlen(flagpathstr) + 12);
248 sprintf(entry->displayflag, "%sCountries/%s]", flagpathstr, entry->realname);
251 else if (entrysize == sizeof(struct LanguageEntry))
253 D(bug("[LocalePrefs] ScanDir: Checking for native Language name\n"));
254 GetAROSLanguageAttribs(&ap, &entry->node.ln_Name);
257 sp = entry->node.ln_Name;
258 while((sp = strchr(sp, '_')))
260 sp[0] = ' ';
261 if (sp[1])
263 /* Make char after underscore uppercase only if no
264 more underscores follow */
265 if (strchr(sp, '_') == 0)
267 sp[1] = ToUpper(sp[1]);
271 SortInNode(list, &entry->node);
274 error = MatchNext(&ap);
276 if (curdir != BNULL)
277 CurrentDir(curdir);
278 MatchEnd(&ap);
281 /*********************************************************************************************/
283 #if !AROS_BIG_ENDIAN
284 STATIC VOID FixCountryEndianess(struct CountryPrefs *region)
286 region->cp_Reserved[0] = AROS_BE2LONG(region->cp_Reserved[0]);
287 region->cp_Reserved[1] = AROS_BE2LONG(region->cp_Reserved[1]);
288 region->cp_Reserved[2] = AROS_BE2LONG(region->cp_Reserved[2]);
289 region->cp_Reserved[3] = AROS_BE2LONG(region->cp_Reserved[3]);
290 region->cp_CountryCode = AROS_BE2LONG(region->cp_CountryCode);
292 #endif
294 /*********************************************************************************************/
296 #if !AROS_BIG_ENDIAN
297 STATIC VOID FixLocaleEndianess(struct LocalePrefs *localeprefs)
299 localeprefs->lp_Reserved[0] = AROS_BE2LONG(localeprefs->lp_Reserved[0]);
300 localeprefs->lp_Reserved[1] = AROS_BE2LONG(localeprefs->lp_Reserved[1]);
301 localeprefs->lp_Reserved[2] = AROS_BE2LONG(localeprefs->lp_Reserved[2]);
302 localeprefs->lp_Reserved[3] = AROS_BE2LONG(localeprefs->lp_Reserved[3]);
303 localeprefs->lp_GMTOffset = AROS_BE2LONG(localeprefs->lp_GMTOffset);
304 localeprefs->lp_Flags = AROS_BE2LONG(localeprefs->lp_Flags);
306 #endif
308 /*********************************************************************************************/
310 BOOL Prefs_LoadRegion(STRPTR name, struct CountryPrefs *region)
312 static struct CountryPrefs loadregion;
313 struct IFFHandle *iff;
314 struct ContextNode *cn;
315 LONG parse_mode = IFFPARSE_SCAN, error;
316 char fullname[100];
317 BOOL retval = FALSE;
319 strcpy(fullname, "LOCALE:Countries");
320 AddPart(fullname, name, 100);
321 strcat(fullname, ".country");
323 D(bug("[LocalePrefs] LoadRegion: Trying to open \"%s\"\n", fullname));
325 if ((iff = AllocIFF()))
327 if ((iff->iff_Stream = (IPTR)Open(fullname, MODE_OLDFILE)))
329 D(bug("[LocalePrefs] LoadRegion: stream opened.\n"));
331 InitIFFasDOS(iff);
333 if (!OpenIFF(iff, IFFF_READ))
335 D(bug("[LocalePrefs] LoadRegion: OpenIFF okay.\n"));
337 if (!StopChunk(iff, ID_PREF, ID_PRHD))
339 D(bug("[LocalePrefs] LoadRegion: StopChunk okay.\n"));
343 if ((error = ParseIFF(iff, parse_mode)) == 0)
345 parse_mode = IFFPARSE_STEP;
347 D(bug("[LocalePrefs] LoadRegion: ParseIFF okay.\n"));
349 cn = CurrentChunk(iff);
351 D(bug("[LocalePrefs] LoadRegion: Chunk ID %08x.\n", cn->cn_ID));
353 if ((cn->cn_ID == ID_CTRY) && (cn->cn_Size == sizeof(struct CountryPrefs)))
355 D(bug("[LocalePrefs] LoadRegion: Chunk ID_CTRY (size okay).\n"));
357 if (ReadChunkBytes(iff, &loadregion, sizeof(struct CountryPrefs)) == sizeof(struct CountryPrefs))
359 D(bug("[LocalePrefs] LoadRegion: Reading chunk successful.\n"));
361 *region = loadregion;
363 #if !AROS_BIG_ENDIAN
364 FixCountryEndianess(region);
365 #endif
367 D(bug("[LocalePrefs] LoadRegion: Everything okay :-)\n"));
369 retval = TRUE;
370 error = IFFERR_EOF;
373 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
374 } while ((error != IFFERR_EOF) && (error != IFFERR_NOTIFF));
375 } /* if (!StopChunk(iff, ID_PREF, ID_CTRY)) */
376 CloseIFF(iff);
377 } /* if (!OpenIFF(iff, IFFF_READ)) */
378 Close((BPTR)iff->iff_Stream);
379 } /* if ((iff->iff_Stream = (IPTR)Open(fullname, MODE_OLDFILE))) */
380 FreeIFF(iff);
381 } /* if ((iff = AllocIFF())) */
383 return retval;
386 /*********************************************************************************************/
388 BOOL Prefs_ImportFH(BPTR fh)
390 static struct LocalePrefs loadprefs;
391 struct IFFHandle *iff;
392 BOOL retval = FALSE;
394 D(bug("[LocalePrefs] LoadPrefsFH\n"));
396 if ((iff = AllocIFF()))
398 if ((iff->iff_Stream = (IPTR) fh))
400 D(bug("[LocalePrefs] LoadPrefsFH: stream is ok.\n"));
402 InitIFFasDOS(iff);
404 if (!OpenIFF(iff, IFFF_READ))
406 D(bug("[LocalePrefs] LoadPrefsFH: OpenIFF okay.\n"));
408 if (!StopChunk(iff, ID_PREF, ID_LCLE))
410 D(bug("[LocalePrefs] LoadPrefsFH: StopChunk okay.\n"));
412 if (!ParseIFF(iff, IFFPARSE_SCAN))
414 struct ContextNode *cn;
416 D(bug("[LocalePrefs] LoadPrefsFH: ParseIFF okay.\n"));
418 cn = CurrentChunk(iff);
420 if (cn->cn_Size == sizeof(struct LocalePrefs))
422 D(bug("[LocalePrefs] LoadPrefsFH: ID_LCLE chunk size okay.\n"));
424 if (ReadChunkBytes(iff, &loadprefs, sizeof(struct LocalePrefs)) == sizeof(struct LocalePrefs))
426 D(bug("[LocalePrefs] LoadPrefsFH: Reading chunk successful.\n"));
428 localeprefs = loadprefs;
430 #if !AROS_BIG_ENDIAN
431 FixLocaleEndianess(&localeprefs);
432 FixCountryEndianess(&localeprefs.lp_CountryData);
433 #endif
435 D(bug("[LocalePrefs] LoadPrefsFH: Everything okay :-)\n"));
437 retval = TRUE;
440 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
441 } /* if (!StopChunk(iff, ID_PREF, ID_CTRY)) */
442 CloseIFF(iff);
443 } /* if (!OpenIFF(iff, IFFF_READ)) */
444 } /* if ((iff->iff_Stream = (IPTR)Open(filename, MODE_OLDFILE))) */
445 FreeIFF(iff);
446 } /* if ((iff = AllocIFF())) */
448 D(bug("[LocalePrefs] CountryName: %s\n",localeprefs.lp_CountryName));
451 int i;
452 for(i = 0; i < 10 && localeprefs.lp_PreferredLanguages[i]; i++)
454 bug("[LocalePrefs] preferred %ld: %s\n",i,localeprefs.lp_PreferredLanguages[i]);
457 D(bug("[LocalePrefs] lp_GMTOffset: %ld\n",localeprefs.lp_GMTOffset));
458 return retval;
462 /*********************************************************************************************/
464 BOOL Prefs_ExportFH(BPTR fh)
466 struct LocalePrefs saveprefs;
467 struct IFFHandle *iff;
468 BOOL retval = FALSE;
469 #if 0 /* unused */
470 BOOL delete_if_error = FALSE;
471 #endif
473 D(bug("[LocalePrefs] SavePrefsFH: fh: %lx\n", fh));
475 saveprefs = localeprefs;
477 #if !AROS_BIG_ENDIAN
478 FixLocaleEndianess(&saveprefs);
479 FixCountryEndianess(&saveprefs.lp_CountryData);
480 #endif
482 if ((iff = AllocIFF()))
484 iff->iff_Stream = (IPTR) fh;
485 D(bug("[LocalePrefs] SavePrefsFH: stream opened.\n"));
487 #if 0 /* unused */
488 delete_if_error = TRUE;
489 #endif
491 InitIFFasDOS(iff);
493 if (!OpenIFF(iff, IFFF_WRITE))
495 D(bug("[LocalePrefs] SavePrefsFH: OpenIFF okay.\n"));
497 if (!PushChunk(iff, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN))
499 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(FORM) okay.\n"));
501 if (!PushChunk(iff, ID_PREF, ID_PRHD, sizeof(struct FilePrefHeader)))
503 struct FilePrefHeader head;
505 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(PRHD) okay.\n"));
507 head.ph_Version = PHV_CURRENT;
508 head.ph_Type = 0;
509 head.ph_Flags[0] =
510 head.ph_Flags[1] =
511 head.ph_Flags[2] =
512 head.ph_Flags[3] = 0;
514 if (WriteChunkBytes(iff, &head, sizeof(head)) == sizeof(head))
516 D(bug("[LocalePrefs] SavePrefsFH: WriteChunkBytes(PRHD) okay.\n"));
518 PopChunk(iff);
520 if (!PushChunk(iff, ID_PREF, ID_LCLE, sizeof(struct LocalePrefs)))
522 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(LCLE) okay.\n"));
524 if (WriteChunkBytes(iff, &saveprefs, sizeof(saveprefs)) == sizeof(saveprefs))
526 D(bug("[LocalePrefs] SavePrefsFH: WriteChunkBytes(SERL) okay.\n"));
527 D(bug("[LocalePrefs] SavePrefsFH: Everything okay :-)\n"));
529 retval = TRUE;
531 PopChunk(iff);
532 } /* if (!PushChunk(iff, ID_PREF, ID_SERL, sizeof(struct LocalePrefs))) */
534 } /* if (WriteChunkBytes(iff, &head, sizeof(head)) == sizeof(head)) */
535 else
537 PopChunk(iff);
539 } /* if (!PushChunk(iff, ID_PREF, ID_PRHD, sizeof(struct PrefHeader))) */
540 PopChunk(iff);
541 } /* if (!PushChunk(iff, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN)) */
542 CloseIFF(iff);
543 } /* if (!OpenIFF(iff, IFFFWRITE)) */
544 FreeIFF(iff);
545 } /* if ((iff = AllocIFF())) */
547 #if 0 /* unused */
548 if (!retval && delete_if_error)
550 DeleteFile(filename);
552 #endif
554 return retval;
557 /*********************************************************************************************/
559 BOOL Prefs_SaveCharset(BOOL envarc)
561 LONG flags = GVF_GLOBAL_ONLY;
563 D(bug("[LocalePrefs] SaveCharset(%ld)\n", envarc));
565 if (envarc)
566 flags |= GVF_SAVE_VAR;
567 /* We don't check results of the following actions because they may fail if ENVARC: is read-only (CD-ROM) */
568 if (character_set[0])
569 SetVar("CHARSET", character_set, -1, flags);
570 else
571 DeleteVar("CHARSET", flags);
573 return TRUE;
576 /*********************************************************************************************/
578 static BOOL Prefs_Load(STRPTR from)
580 BOOL retval = FALSE;
582 BPTR fh = Open(from, MODE_OLDFILE);
583 if (fh)
585 retval = Prefs_ImportFH(fh);
586 Close(fh);
589 return retval;
592 /*********************************************************************************************/
594 BOOL Prefs_HandleArgs(STRPTR from, BOOL use, BOOL save)
596 BPTR fh;
598 if (from)
600 if (!Prefs_Load(from))
602 ShowMessage("Can't read from input file");
603 return FALSE;
606 else
608 if (!Prefs_Load(PREFS_PATH_ENV))
610 if (!Prefs_Load(PREFS_PATH_ENVARC))
612 ShowMessage
614 "Can't read from file " PREFS_PATH_ENVARC
615 ".\nUsing default values."
617 Prefs_Default();
622 if (use || save)
624 Prefs_LoadRegion(localeprefs.lp_CountryName, &localeprefs.lp_CountryData);
625 fh = Open(PREFS_PATH_ENV, MODE_NEWFILE);
626 if (fh)
628 Prefs_ExportFH(fh);
629 Close(fh);
631 else
633 ShowMessage("Cant' open " PREFS_PATH_ENV " for writing.");
636 if (save)
638 fh = Open(PREFS_PATH_ENVARC, MODE_NEWFILE);
639 if (fh)
641 Prefs_ExportFH(fh);
642 Close(fh);
644 else
646 ShowMessage("Cant' open " PREFS_PATH_ENVARC " for writing.");
650 return TRUE;
653 /*********************************************************************************************/
655 BOOL Prefs_Initialize(VOID)
657 D(bug("[LocalePrefs] InitPrefs\n"));
659 struct LanguageEntry *entry;
661 mempool = CreatePool(MEMF_PUBLIC | MEMF_CLEAR, 2048, 2048);
662 if (!mempool)
664 ShowMessage("Out of memory!");
665 return FALSE;
668 NewList(&region_list);
669 NewList(&language_list);
670 NewList(&pref_language_list);
672 ScanDirectory("LOCALE:Countries/~(#?.info)", &region_list, sizeof(struct RegionEntry));
673 ScanDirectory("LOCALE:Languages/#?.language", &language_list, sizeof(struct LanguageEntry));
675 /* English language is always available */
677 if ((entry = AllocPooled(mempool, sizeof(struct LanguageEntry))))
679 entry->lve.node.ln_Name = AllocVecPooled(mempool, 8);
680 strcpy( entry->lve.node.ln_Name, "English");
681 strcpy( entry->lve.realname, "English");
683 SortInNode(&language_list, &entry->lve.node);
686 character_set[0] = 0;
687 GetVar("CHARSET", character_set, sizeof(character_set), 0);
688 D(bug("[LocalePrefs] System character set: %s\n", character_set));
690 return TRUE;
693 /*********************************************************************************************/
695 VOID Prefs_Deinitialize(VOID)
697 D(bug("[LocalePrefs] CleanupPrefs\n"));
698 if (mempool)
700 DeletePool(mempool);
701 mempool = NULL;
705 /*********************************************************************************************/
707 BOOL Prefs_Default(VOID)
709 BOOL retval = FALSE;
710 WORD i;
712 localeprefs.lp_Reserved[0] = 0;
713 localeprefs.lp_Reserved[1] = 0;
714 localeprefs.lp_Reserved[2] = 0;
715 localeprefs.lp_Reserved[3] = 0;
717 strcpy(localeprefs.lp_CountryName, "united_states");
719 for(i = 0; i < 10; i++)
721 memset(localeprefs.lp_PreferredLanguages[i], 0, sizeof(localeprefs.lp_PreferredLanguages[i]));
723 localeprefs.lp_GMTOffset = 5 * 60;
724 localeprefs.lp_Flags = 0;
726 if (Prefs_LoadRegion((STRPTR) "united_states", &localeprefs.lp_CountryData))
728 retval = TRUE;
731 character_set[0] = 0;
733 return retval;