Hint added.
[AROS.git] / workbench / prefs / locale / prefs.c
blob3552199c5dc5c9907941ce3dea1abea60b452ea0
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((BPTR)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 + 2);
160 CopyMem(tmpbuff, *languageNamePtr, i + 1);
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 + 2);
188 CopyMem(tmpbuff, *languageNamePtr, i + 1);
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);
209 return NULL;
212 /*********************************************************************************************/
214 STATIC VOID ScanDirectory(char *pattern, struct List *list, LONG entrysize)
216 struct AnchorPath ap;
217 struct ListviewEntry *entry;
218 BPTR curdir = BNULL;
219 char *sp;
220 LONG error;
222 memset(&ap, 0, sizeof(ap));
224 if ((error = MatchFirst(pattern, &ap)) == 0)
225 curdir = CurrentDir(ap.ap_Current->an_Lock);
227 while((error == 0))
229 if (ap.ap_Info.fib_DirEntryType < 0)
231 entry = (struct ListviewEntry *)AllocPooled(mempool, entrysize);
232 if (entry)
234 entry->node.ln_Name = AllocVecPooled(mempool, strlen(ap.ap_Info.fib_FileName) + 1);
235 strcpy(entry->node.ln_Name, ap.ap_Info.fib_FileName);
237 if ((sp = strchr(entry->node.ln_Name, '.')) != NULL)
238 sp[0] = '\0';
240 strcpy(entry->realname, entry->node.ln_Name);
241 entry->node.ln_Name[0] = ToUpper(entry->node.ln_Name[0]);
243 if (entrysize == sizeof(struct RegionEntry))
245 D(bug("[LocalePrefs] ScanDir: Checking for FLAG chunk\n"));
246 if (!(entry->displayflag = GetAROSRegionAttribs(&ap, &entry->node.ln_Name)))
248 entry->displayflag = AllocVecPooled(mempool, strlen(entry->realname) + strlen(flagpathstr) + 12);
249 sprintf(entry->displayflag, "%sCountries/%s]", flagpathstr, entry->realname);
252 else if (entrysize == sizeof(struct LanguageEntry))
254 D(bug("[LocalePrefs] ScanDir: Checking for native Language name\n"));
255 GetAROSLanguageAttribs(&ap, &entry->node.ln_Name);
256 entry->node.ln_Name[0] = ToUpper(entry->node.ln_Name[0]);
259 sp = entry->node.ln_Name;
260 while((sp = strchr(sp, '_')))
262 sp[0] = ' ';
263 if (sp[1])
265 /* Make char after underscore uppercase only if no
266 more underscores follow */
267 if (strchr(sp, '_') == 0)
269 sp[1] = ToUpper(sp[1]);
273 SortInNode(list, &entry->node);
276 error = MatchNext(&ap);
278 if (curdir != BNULL)
279 CurrentDir(curdir);
280 MatchEnd(&ap);
283 /*********************************************************************************************/
285 #if !AROS_BIG_ENDIAN
286 STATIC VOID FixCountryEndianess(struct CountryPrefs *region)
288 region->cp_Reserved[0] = AROS_BE2LONG(region->cp_Reserved[0]);
289 region->cp_Reserved[1] = AROS_BE2LONG(region->cp_Reserved[1]);
290 region->cp_Reserved[2] = AROS_BE2LONG(region->cp_Reserved[2]);
291 region->cp_Reserved[3] = AROS_BE2LONG(region->cp_Reserved[3]);
292 region->cp_CountryCode = AROS_BE2LONG(region->cp_CountryCode);
294 #endif
296 /*********************************************************************************************/
298 #if !AROS_BIG_ENDIAN
299 STATIC VOID FixLocaleEndianess(struct LocalePrefs *localeprefs)
301 localeprefs->lp_Reserved[0] = AROS_BE2LONG(localeprefs->lp_Reserved[0]);
302 localeprefs->lp_Reserved[1] = AROS_BE2LONG(localeprefs->lp_Reserved[1]);
303 localeprefs->lp_Reserved[2] = AROS_BE2LONG(localeprefs->lp_Reserved[2]);
304 localeprefs->lp_Reserved[3] = AROS_BE2LONG(localeprefs->lp_Reserved[3]);
305 localeprefs->lp_GMTOffset = AROS_BE2LONG(localeprefs->lp_GMTOffset);
306 localeprefs->lp_Flags = AROS_BE2LONG(localeprefs->lp_Flags);
308 #endif
310 /*********************************************************************************************/
312 BOOL Prefs_LoadRegion(STRPTR name, struct CountryPrefs *region)
314 static struct CountryPrefs loadregion;
315 struct IFFHandle *iff;
316 struct ContextNode *cn;
317 LONG parse_mode = IFFPARSE_SCAN, error;
318 char fullname[100];
319 BOOL retval = FALSE;
321 strcpy(fullname, "LOCALE:Countries");
322 AddPart(fullname, name, 100);
323 strcat(fullname, ".country");
325 D(bug("[LocalePrefs] LoadRegion: Trying to open \"%s\"\n", fullname));
327 if ((iff = AllocIFF()))
329 if ((iff->iff_Stream = (IPTR)Open(fullname, MODE_OLDFILE)))
331 D(bug("[LocalePrefs] LoadRegion: stream opened.\n"));
333 InitIFFasDOS(iff);
335 if (!OpenIFF(iff, IFFF_READ))
337 D(bug("[LocalePrefs] LoadRegion: OpenIFF okay.\n"));
339 if (!StopChunk(iff, ID_PREF, ID_PRHD))
341 D(bug("[LocalePrefs] LoadRegion: StopChunk okay.\n"));
345 if ((error = ParseIFF(iff, parse_mode)) == 0)
347 parse_mode = IFFPARSE_STEP;
349 D(bug("[LocalePrefs] LoadRegion: ParseIFF okay.\n"));
351 cn = CurrentChunk(iff);
353 D(bug("[LocalePrefs] LoadRegion: Chunk ID %08x.\n", cn->cn_ID));
355 if ((cn->cn_ID == ID_CTRY) && (cn->cn_Size == sizeof(struct CountryPrefs)))
357 D(bug("[LocalePrefs] LoadRegion: Chunk ID_CTRY (size okay).\n"));
359 if (ReadChunkBytes(iff, &loadregion, sizeof(struct CountryPrefs)) == sizeof(struct CountryPrefs))
361 D(bug("[LocalePrefs] LoadRegion: Reading chunk successful.\n"));
363 *region = loadregion;
365 #if !AROS_BIG_ENDIAN
366 FixCountryEndianess(region);
367 #endif
369 D(bug("[LocalePrefs] LoadRegion: Everything okay :-)\n"));
371 retval = TRUE;
372 error = IFFERR_EOF;
375 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
376 } while ((error != IFFERR_EOF) && (error != IFFERR_NOTIFF));
377 } /* if (!StopChunk(iff, ID_PREF, ID_CTRY)) */
378 CloseIFF(iff);
379 } /* if (!OpenIFF(iff, IFFF_READ)) */
380 Close((BPTR)iff->iff_Stream);
381 } /* if ((iff->iff_Stream = (IPTR)Open(fullname, MODE_OLDFILE))) */
382 FreeIFF(iff);
383 } /* if ((iff = AllocIFF())) */
385 return retval;
388 /*********************************************************************************************/
390 BOOL Prefs_ImportFH(BPTR fh)
392 static struct LocalePrefs loadprefs;
393 struct IFFHandle *iff;
394 BOOL retval = FALSE;
396 D(bug("[LocalePrefs] LoadPrefsFH\n"));
398 if ((iff = AllocIFF()))
400 if ((iff->iff_Stream = (IPTR) fh))
402 D(bug("[LocalePrefs] LoadPrefsFH: stream is ok.\n"));
404 InitIFFasDOS(iff);
406 if (!OpenIFF(iff, IFFF_READ))
408 D(bug("[LocalePrefs] LoadPrefsFH: OpenIFF okay.\n"));
410 if (!StopChunk(iff, ID_PREF, ID_LCLE))
412 D(bug("[LocalePrefs] LoadPrefsFH: StopChunk okay.\n"));
414 if (!ParseIFF(iff, IFFPARSE_SCAN))
416 struct ContextNode *cn;
418 D(bug("[LocalePrefs] LoadPrefsFH: ParseIFF okay.\n"));
420 cn = CurrentChunk(iff);
422 if (cn->cn_Size == sizeof(struct LocalePrefs))
424 D(bug("[LocalePrefs] LoadPrefsFH: ID_LCLE chunk size okay.\n"));
426 if (ReadChunkBytes(iff, &loadprefs, sizeof(struct LocalePrefs)) == sizeof(struct LocalePrefs))
428 D(bug("[LocalePrefs] LoadPrefsFH: Reading chunk successful.\n"));
430 localeprefs = loadprefs;
432 #if !AROS_BIG_ENDIAN
433 FixLocaleEndianess(&localeprefs);
434 FixCountryEndianess(&localeprefs.lp_CountryData);
435 #endif
437 D(bug("[LocalePrefs] LoadPrefsFH: Everything okay :-)\n"));
439 retval = TRUE;
442 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
443 } /* if (!StopChunk(iff, ID_PREF, ID_CTRY)) */
444 CloseIFF(iff);
445 } /* if (!OpenIFF(iff, IFFF_READ)) */
446 } /* if ((iff->iff_Stream = (IPTR)Open(filename, MODE_OLDFILE))) */
447 FreeIFF(iff);
448 } /* if ((iff = AllocIFF())) */
450 D(bug("[LocalePrefs] LoadPrefsFH: CountryName = '%s'\n", localeprefs.lp_CountryName));
453 int i;
454 for(i = 0; i < 10 && localeprefs.lp_PreferredLanguages[i]; i++)
456 bug("[LocalePrefs] LoadPrefsFH: preferred %02d = '%s'\n", i, localeprefs.lp_PreferredLanguages[i]);
459 D(bug("[LocalePrefs] LoadPrefsFH: lp_GMTOffset = %ld\n", localeprefs.lp_GMTOffset));
460 return retval;
464 /*********************************************************************************************/
466 BOOL Prefs_ExportFH(BPTR fh)
468 struct LocalePrefs saveprefs;
469 struct IFFHandle *iff;
470 BOOL retval = FALSE;
471 #if 0 /* unused */
472 BOOL delete_if_error = FALSE;
473 #endif
475 D(bug("[LocalePrefs] SavePrefsFH: fh: %lx\n", fh));
477 CopyMem(&localeprefs, &saveprefs, sizeof(struct LocalePrefs));
479 #if !AROS_BIG_ENDIAN
480 FixLocaleEndianess(&saveprefs);
481 FixCountryEndianess(&saveprefs.lp_CountryData);
482 #endif
484 if ((iff = AllocIFF()))
486 iff->iff_Stream = (IPTR) fh;
487 D(bug("[LocalePrefs] SavePrefsFH: stream opened.\n"));
489 #if 0 /* unused */
490 delete_if_error = TRUE;
491 #endif
493 InitIFFasDOS(iff);
495 if (!OpenIFF(iff, IFFF_WRITE))
497 D(bug("[LocalePrefs] SavePrefsFH: OpenIFF okay.\n"));
499 if (!PushChunk(iff, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN))
501 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(FORM) okay.\n"));
503 if (!PushChunk(iff, ID_PREF, ID_PRHD, sizeof(struct FilePrefHeader)))
505 struct FilePrefHeader head;
507 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(PRHD) okay.\n"));
509 head.ph_Version = PHV_CURRENT;
510 head.ph_Type = 0;
511 head.ph_Flags[0] =
512 head.ph_Flags[1] =
513 head.ph_Flags[2] =
514 head.ph_Flags[3] = 0;
516 if (WriteChunkBytes(iff, &head, sizeof(head)) == sizeof(head))
518 D(bug("[LocalePrefs] SavePrefsFH: WriteChunkBytes(PRHD) okay.\n"));
520 PopChunk(iff);
522 if (!PushChunk(iff, ID_PREF, ID_LCLE, sizeof(struct LocalePrefs)))
524 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(LCLE) okay.\n"));
526 if (WriteChunkBytes(iff, &saveprefs, sizeof(saveprefs)) == sizeof(saveprefs))
528 D(bug("[LocalePrefs] SavePrefsFH: WriteChunkBytes(SERL) okay.\n"));
529 D(bug("[LocalePrefs] SavePrefsFH: Everything okay :-)\n"));
531 retval = TRUE;
533 PopChunk(iff);
534 } /* if (!PushChunk(iff, ID_PREF, ID_SERL, sizeof(struct LocalePrefs))) */
536 } /* if (WriteChunkBytes(iff, &head, sizeof(head)) == sizeof(head)) */
537 else
539 PopChunk(iff);
541 } /* if (!PushChunk(iff, ID_PREF, ID_PRHD, sizeof(struct PrefHeader))) */
542 PopChunk(iff);
543 } /* if (!PushChunk(iff, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN)) */
544 CloseIFF(iff);
545 } /* if (!OpenIFF(iff, IFFFWRITE)) */
546 FreeIFF(iff);
547 } /* if ((iff = AllocIFF())) */
549 #if 0 /* unused */
550 if (!retval && delete_if_error)
552 DeleteFile(filename);
554 #endif
556 return retval;
559 /*********************************************************************************************/
561 BOOL Prefs_SaveCharset(BOOL envarc)
563 LONG flags = GVF_GLOBAL_ONLY;
565 D(bug("[LocalePrefs] SaveCharset(%ld)\n", envarc));
567 if (envarc)
568 flags |= GVF_SAVE_VAR;
569 /* We don't check results of the following actions because they may fail if ENVARC: is read-only (CD-ROM) */
570 if (character_set[0])
571 SetVar("CHARSET", character_set, -1, flags);
572 else
573 DeleteVar("CHARSET", flags);
575 return TRUE;
578 /*********************************************************************************************/
580 static BOOL Prefs_Load(STRPTR from)
582 BOOL retval = FALSE;
584 BPTR fh = Open(from, MODE_OLDFILE);
585 if (fh)
587 retval = Prefs_ImportFH(fh);
588 Close(fh);
591 return retval;
594 /*********************************************************************************************/
596 BOOL Prefs_HandleArgs(STRPTR from, BOOL use, BOOL save)
598 BPTR fh;
600 if (from)
602 if (!Prefs_Load(from))
604 ShowMessage("Can't read from input file");
605 return FALSE;
608 else
610 if (!Prefs_Load(PREFS_PATH_ENV))
612 if (!Prefs_Load(PREFS_PATH_ENVARC))
614 ShowMessage
616 "Can't read from file " PREFS_PATH_ENVARC
617 ".\nUsing default values."
619 Prefs_Default();
624 if (use || save)
626 Prefs_LoadRegion(localeprefs.lp_CountryName, &localeprefs.lp_CountryData);
627 fh = Open(PREFS_PATH_ENV, MODE_NEWFILE);
628 if (fh)
630 Prefs_ExportFH(fh);
631 Close(fh);
633 else
635 ShowMessage("Cant' open " PREFS_PATH_ENV " for writing.");
638 if (save)
640 fh = Open(PREFS_PATH_ENVARC, MODE_NEWFILE);
641 if (fh)
643 Prefs_ExportFH(fh);
644 Close(fh);
646 else
648 ShowMessage("Cant' open " PREFS_PATH_ENVARC " for writing.");
652 return TRUE;
655 /*********************************************************************************************/
657 BOOL Prefs_Initialize(VOID)
659 D(bug("[LocalePrefs] InitPrefs\n"));
661 struct LanguageEntry *entry;
663 mempool = CreatePool(MEMF_PUBLIC | MEMF_CLEAR, 2048, 2048);
664 if (!mempool)
666 ShowMessage("Out of memory!");
667 return FALSE;
670 NewList(&region_list);
671 NewList(&language_list);
672 NewList(&pref_language_list);
674 ScanDirectory("LOCALE:Countries/~(#?.info)", &region_list, sizeof(struct RegionEntry));
675 ScanDirectory("LOCALE:Languages/#?.language", &language_list, sizeof(struct LanguageEntry));
677 /* English language is always available */
679 if ((entry = AllocPooled(mempool, sizeof(struct LanguageEntry))))
681 entry->lve.node.ln_Name = AllocVecPooled(mempool, 8);
682 strcpy( entry->lve.node.ln_Name, "English");
683 strcpy( entry->lve.realname, "english");
685 SortInNode(&language_list, &entry->lve.node);
688 character_set[0] = 0;
689 GetVar("CHARSET", character_set, sizeof(character_set), 0);
690 D(bug("[LocalePrefs] System character set: %s\n", character_set));
692 return TRUE;
695 /*********************************************************************************************/
697 VOID Prefs_Deinitialize(VOID)
699 D(bug("[LocalePrefs] CleanupPrefs\n"));
700 if (mempool)
702 DeletePool(mempool);
703 mempool = NULL;
707 /*********************************************************************************************/
709 BOOL Prefs_Default(VOID)
711 BOOL retval = FALSE;
712 WORD i;
714 localeprefs.lp_Reserved[0] = 0;
715 localeprefs.lp_Reserved[1] = 0;
716 localeprefs.lp_Reserved[2] = 0;
717 localeprefs.lp_Reserved[3] = 0;
719 strcpy(localeprefs.lp_CountryName, "united_states");
721 for(i = 0; i < 10; i++)
723 memset(localeprefs.lp_PreferredLanguages[i], 0, sizeof(localeprefs.lp_PreferredLanguages[i]));
725 localeprefs.lp_GMTOffset = 5 * 60;
726 localeprefs.lp_Flags = 0;
728 if (Prefs_LoadRegion((STRPTR) "united_states", &localeprefs.lp_CountryData))
730 retval = TRUE;
733 character_set[0] = 0;
735 return retval;