2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
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>
28 /*********************************************************************************************/
30 #define PREFS_PATH_ENVARC "ENVARC:SYS/locale.prefs"
31 #define PREFS_PATH_ENV "ENV:SYS/locale.prefs"
33 /*********************************************************************************************/
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 /*********************************************************************************************/
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
;
64 loc
= OpenLocale(NULL
);
66 ForeachNode(list
, sort
)
69 node
->ln_Name
, sort
->ln_Name
,
70 strlen(node
->ln_Name
), SC_COLLATE2
)
78 Insert(list
, node
, prev
);
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
)))
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
));
131 Close((BPTR
)iff
->iff_Stream
);
139 char *GetAROSLanguageAttribs(struct AnchorPath
*ap
, char **languageNamePtr
)
143 int read
, len
= 0, pos
, i
;
146 if ((fileHandle
= Open(ap
->ap_Info
.fib_FileName
, MODE_OLDFILE
)) != BNULL
)
148 while ((read
= Read(fileHandle
, &tmpbuff
[len
], sizeof(tmpbuff
) - len
)) > 0)
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 .. */
171 while ((len
- pos
) >= 7)
173 if (strncmp(&tmpbuff
[pos
], "$NLANG:", 7) == 0)
180 CopyMem(&tmpbuff
[pos
], tmpbuff
, (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
;
200 if (!match
&& (pos
< len
))
202 CopyMem(&tmpbuff
[pos
], tmpbuff
, (len
- pos
));
212 /*********************************************************************************************/
214 STATIC VOID
ScanDirectory(char *pattern
, struct List
*list
, LONG entrysize
)
216 struct AnchorPath ap
;
217 struct ListviewEntry
*entry
;
222 memset(&ap
, 0, sizeof(ap
));
224 if ((error
= MatchFirst(pattern
, &ap
)) == 0)
225 curdir
= CurrentDir(ap
.ap_Current
->an_Lock
);
229 if (ap
.ap_Info
.fib_DirEntryType
< 0)
231 entry
= (struct ListviewEntry
*)AllocPooled(mempool
, entrysize
);
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
)
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
, '_')))
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
);
283 /*********************************************************************************************/
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
);
296 /*********************************************************************************************/
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
);
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
;
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"));
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
;
366 FixCountryEndianess(region
);
369 D(bug("[LocalePrefs] LoadRegion: Everything okay :-)\n"));
375 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
376 } while ((error
!= IFFERR_EOF
) && (error
!= IFFERR_NOTIFF
));
377 } /* if (!StopChunk(iff, ID_PREF, ID_CTRY)) */
379 } /* if (!OpenIFF(iff, IFFF_READ)) */
380 Close((BPTR
)iff
->iff_Stream
);
381 } /* if ((iff->iff_Stream = (IPTR)Open(fullname, MODE_OLDFILE))) */
383 } /* if ((iff = AllocIFF())) */
388 /*********************************************************************************************/
390 BOOL
Prefs_ImportFH(BPTR fh
)
392 static struct LocalePrefs loadprefs
;
393 struct IFFHandle
*iff
;
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"));
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
;
433 FixLocaleEndianess(&localeprefs
);
434 FixCountryEndianess(&localeprefs
.lp_CountryData
);
437 D(bug("[LocalePrefs] LoadPrefsFH: Everything okay :-)\n"));
442 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
443 } /* if (!StopChunk(iff, ID_PREF, ID_CTRY)) */
445 } /* if (!OpenIFF(iff, IFFF_READ)) */
446 } /* if ((iff->iff_Stream = (IPTR)Open(filename, MODE_OLDFILE))) */
448 } /* if ((iff = AllocIFF())) */
450 D(bug("[LocalePrefs] LoadPrefsFH: CountryName = '%s'\n", localeprefs
.lp_CountryName
));
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
));
464 /*********************************************************************************************/
466 BOOL
Prefs_ExportFH(BPTR fh
)
468 struct LocalePrefs saveprefs
;
469 struct IFFHandle
*iff
;
472 BOOL delete_if_error
= FALSE
;
475 D(bug("[LocalePrefs] SavePrefsFH: fh: %lx\n", fh
));
477 CopyMem(&localeprefs
, &saveprefs
, sizeof(struct LocalePrefs
));
480 FixLocaleEndianess(&saveprefs
);
481 FixCountryEndianess(&saveprefs
.lp_CountryData
);
484 if ((iff
= AllocIFF()))
486 iff
->iff_Stream
= (IPTR
) fh
;
487 D(bug("[LocalePrefs] SavePrefsFH: stream opened.\n"));
490 delete_if_error
= TRUE
;
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
;
514 head
.ph_Flags
[3] = 0;
516 if (WriteChunkBytes(iff
, &head
, sizeof(head
)) == sizeof(head
))
518 D(bug("[LocalePrefs] SavePrefsFH: WriteChunkBytes(PRHD) okay.\n"));
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"));
534 } /* if (!PushChunk(iff, ID_PREF, ID_SERL, sizeof(struct LocalePrefs))) */
536 } /* if (WriteChunkBytes(iff, &head, sizeof(head)) == sizeof(head)) */
541 } /* if (!PushChunk(iff, ID_PREF, ID_PRHD, sizeof(struct PrefHeader))) */
543 } /* if (!PushChunk(iff, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN)) */
545 } /* if (!OpenIFF(iff, IFFFWRITE)) */
547 } /* if ((iff = AllocIFF())) */
550 if (!retval
&& delete_if_error
)
552 DeleteFile(filename
);
559 /*********************************************************************************************/
561 BOOL
Prefs_SaveCharset(BOOL envarc
)
563 LONG flags
= GVF_GLOBAL_ONLY
;
565 D(bug("[LocalePrefs] SaveCharset(%ld)\n", 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
);
573 DeleteVar("CHARSET", flags
);
578 /*********************************************************************************************/
580 static BOOL
Prefs_Load(STRPTR from
)
584 BPTR fh
= Open(from
, MODE_OLDFILE
);
587 retval
= Prefs_ImportFH(fh
);
594 /*********************************************************************************************/
596 BOOL
Prefs_HandleArgs(STRPTR from
, BOOL use
, BOOL save
)
602 if (!Prefs_Load(from
))
604 ShowMessage("Can't read from input file");
610 if (!Prefs_Load(PREFS_PATH_ENV
))
612 if (!Prefs_Load(PREFS_PATH_ENVARC
))
616 "Can't read from file " PREFS_PATH_ENVARC
617 ".\nUsing default values."
626 Prefs_LoadRegion(localeprefs
.lp_CountryName
, &localeprefs
.lp_CountryData
);
627 fh
= Open(PREFS_PATH_ENV
, MODE_NEWFILE
);
635 ShowMessage("Cant' open " PREFS_PATH_ENV
" for writing.");
640 fh
= Open(PREFS_PATH_ENVARC
, MODE_NEWFILE
);
648 ShowMessage("Cant' open " PREFS_PATH_ENVARC
" for writing.");
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);
666 ShowMessage("Out of memory!");
670 NewList(®ion_list
);
671 NewList(&language_list
);
672 NewList(&pref_language_list
);
674 ScanDirectory("LOCALE:Countries/~(#?.info)", ®ion_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
));
695 /*********************************************************************************************/
697 VOID
Prefs_Deinitialize(VOID
)
699 D(bug("[LocalePrefs] CleanupPrefs\n"));
707 /*********************************************************************************************/
709 BOOL
Prefs_Default(VOID
)
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
))
733 character_set
[0] = 0;