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);
162 D(bug("[LocalePrefs] GetAROSLanguageAttribs: NativeName (A) '%s'\n", *languageNamePtr
));
163 return *languageNamePtr
;
165 /* we shouldnt really ever reach here .. */
172 while ((len
- pos
) >= 7)
174 if (strncmp(&tmpbuff
[pos
], "$NLANG:", 7) == 0)
181 CopyMem(&tmpbuff
[pos
], tmpbuff
, (len
- pos
));
183 for (i
= 0; i
< len
; i
++)
185 if (tmpbuff
[i
] == '\0')
187 FreeVecPooled(mempool
, *languageNamePtr
);
188 *languageNamePtr
= AllocVecPooled(mempool
, i
+ 2);
189 CopyMem(tmpbuff
, *languageNamePtr
, i
+ 1);
191 D(bug("[LocalePrefs] GetAROSLanguageAttribs: NativeName (B) '%s'\n", *languageNamePtr
));
192 return *languageNamePtr
;
202 if (!match
&& (pos
< len
))
204 CopyMem(&tmpbuff
[pos
], tmpbuff
, (len
- pos
));
214 /*********************************************************************************************/
216 STATIC VOID
ScanDirectory(char *pattern
, struct List
*list
, LONG entrysize
)
218 struct AnchorPath ap
;
219 struct ListviewEntry
*entry
;
224 memset(&ap
, 0, sizeof(ap
));
226 if ((error
= MatchFirst(pattern
, &ap
)) == 0)
227 curdir
= CurrentDir(ap
.ap_Current
->an_Lock
);
231 if (ap
.ap_Info
.fib_DirEntryType
< 0)
233 entry
= (struct ListviewEntry
*)AllocPooled(mempool
, entrysize
);
236 entry
->node
.ln_Name
= AllocVecPooled(mempool
, strlen(ap
.ap_Info
.fib_FileName
) + 1);
237 strcpy(entry
->node
.ln_Name
, ap
.ap_Info
.fib_FileName
);
239 if ((sp
= strchr(entry
->node
.ln_Name
, '.')) != NULL
)
242 strcpy(entry
->realname
, entry
->node
.ln_Name
);
243 entry
->node
.ln_Name
[0] = ToUpper(entry
->node
.ln_Name
[0]);
245 if (entrysize
== sizeof(struct RegionEntry
))
247 D(bug("[LocalePrefs] ScanDir: Checking for FLAG chunk\n"));
248 if (!(entry
->displayflag
= GetAROSRegionAttribs(&ap
, &entry
->node
.ln_Name
)))
250 entry
->displayflag
= AllocVecPooled(mempool
, strlen(entry
->realname
) + strlen(flagpathstr
) + 12);
251 sprintf(entry
->displayflag
, "%sCountries/%s]", flagpathstr
, entry
->realname
);
254 else if (entrysize
== sizeof(struct LanguageEntry
))
256 D(bug("[LocalePrefs] ScanDir: Checking for native Language name\n"));
257 GetAROSLanguageAttribs(&ap
, &entry
->node
.ln_Name
);
258 entry
->node
.ln_Name
[0] = ToUpper(entry
->node
.ln_Name
[0]);
261 sp
= entry
->node
.ln_Name
;
262 while((sp
= strchr(sp
, '_')))
267 /* Make char after underscore uppercase only if no
268 more underscores follow */
269 if (strchr(sp
, '_') == 0)
271 sp
[1] = ToUpper(sp
[1]);
275 SortInNode(list
, &entry
->node
);
278 error
= MatchNext(&ap
);
285 /*********************************************************************************************/
288 STATIC VOID
FixCountryEndianess(struct CountryPrefs
*region
)
290 region
->cp_Reserved
[0] = AROS_BE2LONG(region
->cp_Reserved
[0]);
291 region
->cp_Reserved
[1] = AROS_BE2LONG(region
->cp_Reserved
[1]);
292 region
->cp_Reserved
[2] = AROS_BE2LONG(region
->cp_Reserved
[2]);
293 region
->cp_Reserved
[3] = AROS_BE2LONG(region
->cp_Reserved
[3]);
294 region
->cp_CountryCode
= AROS_BE2LONG(region
->cp_CountryCode
);
298 /*********************************************************************************************/
301 STATIC VOID
FixLocaleEndianess(struct LocalePrefs
*localeprefs
)
303 localeprefs
->lp_Reserved
[0] = AROS_BE2LONG(localeprefs
->lp_Reserved
[0]);
304 localeprefs
->lp_Reserved
[1] = AROS_BE2LONG(localeprefs
->lp_Reserved
[1]);
305 localeprefs
->lp_Reserved
[2] = AROS_BE2LONG(localeprefs
->lp_Reserved
[2]);
306 localeprefs
->lp_Reserved
[3] = AROS_BE2LONG(localeprefs
->lp_Reserved
[3]);
307 localeprefs
->lp_GMTOffset
= AROS_BE2LONG(localeprefs
->lp_GMTOffset
);
308 localeprefs
->lp_Flags
= AROS_BE2LONG(localeprefs
->lp_Flags
);
312 /*********************************************************************************************/
314 BOOL
Prefs_LoadRegion(STRPTR name
, struct CountryPrefs
*region
)
316 static struct CountryPrefs loadregion
;
317 struct IFFHandle
*iff
;
318 struct ContextNode
*cn
;
319 LONG parse_mode
= IFFPARSE_SCAN
, error
;
323 strcpy(fullname
, "LOCALE:Countries");
324 AddPart(fullname
, name
, 100);
325 strcat(fullname
, ".country");
327 D(bug("[LocalePrefs] LoadRegion: Trying to open \"%s\"\n", fullname
));
329 if ((iff
= AllocIFF()))
331 if ((iff
->iff_Stream
= (IPTR
)Open(fullname
, MODE_OLDFILE
)))
333 D(bug("[LocalePrefs] LoadRegion: stream opened.\n"));
337 if (!OpenIFF(iff
, IFFF_READ
))
339 D(bug("[LocalePrefs] LoadRegion: OpenIFF okay.\n"));
341 if (!StopChunk(iff
, ID_PREF
, ID_PRHD
))
343 D(bug("[LocalePrefs] LoadRegion: StopChunk okay.\n"));
347 if ((error
= ParseIFF(iff
, parse_mode
)) == 0)
349 parse_mode
= IFFPARSE_STEP
;
351 D(bug("[LocalePrefs] LoadRegion: ParseIFF okay.\n"));
353 cn
= CurrentChunk(iff
);
355 D(bug("[LocalePrefs] LoadRegion: Chunk ID %08x.\n", cn
->cn_ID
));
357 if ((cn
->cn_ID
== ID_CTRY
) && (cn
->cn_Size
== sizeof(struct CountryPrefs
)))
359 D(bug("[LocalePrefs] LoadRegion: Chunk ID_CTRY (size okay).\n"));
361 if (ReadChunkBytes(iff
, &loadregion
, sizeof(struct CountryPrefs
)) == sizeof(struct CountryPrefs
))
363 D(bug("[LocalePrefs] LoadRegion: Reading chunk successful.\n"));
365 *region
= loadregion
;
368 FixCountryEndianess(region
);
371 D(bug("[LocalePrefs] LoadRegion: Everything okay :-)\n"));
377 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
378 } while ((error
!= IFFERR_EOF
) && (error
!= IFFERR_NOTIFF
));
379 } /* if (!StopChunk(iff, ID_PREF, ID_CTRY)) */
381 } /* if (!OpenIFF(iff, IFFF_READ)) */
382 Close((BPTR
)iff
->iff_Stream
);
383 } /* if ((iff->iff_Stream = (IPTR)Open(fullname, MODE_OLDFILE))) */
385 } /* if ((iff = AllocIFF())) */
390 /*********************************************************************************************/
392 BOOL
Prefs_ImportFH(BPTR fh
)
394 static struct LocalePrefs loadprefs
;
395 struct IFFHandle
*iff
;
398 D(bug("[LocalePrefs] LoadPrefsFH\n"));
400 if ((iff
= AllocIFF()))
402 if ((iff
->iff_Stream
= (IPTR
) fh
))
404 D(bug("[LocalePrefs] LoadPrefsFH: stream is ok.\n"));
408 if (!OpenIFF(iff
, IFFF_READ
))
410 D(bug("[LocalePrefs] LoadPrefsFH: OpenIFF okay.\n"));
412 if (!StopChunk(iff
, ID_PREF
, ID_LCLE
))
414 D(bug("[LocalePrefs] LoadPrefsFH: StopChunk okay.\n"));
416 if (!ParseIFF(iff
, IFFPARSE_SCAN
))
418 struct ContextNode
*cn
;
420 D(bug("[LocalePrefs] LoadPrefsFH: ParseIFF okay.\n"));
422 cn
= CurrentChunk(iff
);
424 if (cn
->cn_Size
== sizeof(struct LocalePrefs
))
426 D(bug("[LocalePrefs] LoadPrefsFH: ID_LCLE chunk size okay.\n"));
428 if (ReadChunkBytes(iff
, &loadprefs
, sizeof(struct LocalePrefs
)) == sizeof(struct LocalePrefs
))
430 D(bug("[LocalePrefs] LoadPrefsFH: Reading chunk successful.\n"));
432 localeprefs
= loadprefs
;
435 FixLocaleEndianess(&localeprefs
);
436 FixCountryEndianess(&localeprefs
.lp_CountryData
);
439 D(bug("[LocalePrefs] LoadPrefsFH: Everything okay :-)\n"));
444 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
445 } /* if (!StopChunk(iff, ID_PREF, ID_CTRY)) */
447 } /* if (!OpenIFF(iff, IFFF_READ)) */
448 } /* if ((iff->iff_Stream = (IPTR)Open(filename, MODE_OLDFILE))) */
450 } /* if ((iff = AllocIFF())) */
452 D(bug("[LocalePrefs] LoadPrefsFH: CountryName = '%s'\n", localeprefs
.lp_CountryName
));
456 for(i
= 0; i
< 10 && localeprefs
.lp_PreferredLanguages
[i
]; i
++)
458 bug("[LocalePrefs] LoadPrefsFH: preferred %02d = '%s'\n", i
, localeprefs
.lp_PreferredLanguages
[i
]);
461 D(bug("[LocalePrefs] LoadPrefsFH: lp_GMTOffset = %ld\n", localeprefs
.lp_GMTOffset
));
466 /*********************************************************************************************/
468 BOOL
Prefs_ExportFH(BPTR fh
)
470 struct LocalePrefs saveprefs
;
471 struct IFFHandle
*iff
;
474 BOOL delete_if_error
= FALSE
;
477 D(bug("[LocalePrefs] SavePrefsFH: fh: %lx\n", fh
));
479 CopyMem(&localeprefs
, &saveprefs
, sizeof(struct LocalePrefs
));
482 FixLocaleEndianess(&saveprefs
);
483 FixCountryEndianess(&saveprefs
.lp_CountryData
);
486 if ((iff
= AllocIFF()))
488 iff
->iff_Stream
= (IPTR
) fh
;
489 D(bug("[LocalePrefs] SavePrefsFH: stream opened.\n"));
492 delete_if_error
= TRUE
;
497 if (!OpenIFF(iff
, IFFF_WRITE
))
499 D(bug("[LocalePrefs] SavePrefsFH: OpenIFF okay.\n"));
501 if (!PushChunk(iff
, ID_PREF
, ID_FORM
, IFFSIZE_UNKNOWN
))
503 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(FORM) okay.\n"));
505 if (!PushChunk(iff
, ID_PREF
, ID_PRHD
, sizeof(struct FilePrefHeader
)))
507 struct FilePrefHeader head
;
509 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(PRHD) okay.\n"));
511 head
.ph_Version
= PHV_CURRENT
;
516 head
.ph_Flags
[3] = 0;
518 if (WriteChunkBytes(iff
, &head
, sizeof(head
)) == sizeof(head
))
520 D(bug("[LocalePrefs] SavePrefsFH: WriteChunkBytes(PRHD) okay.\n"));
524 if (!PushChunk(iff
, ID_PREF
, ID_LCLE
, sizeof(struct LocalePrefs
)))
526 D(bug("[LocalePrefs] SavePrefsFH: PushChunk(LCLE) okay.\n"));
528 if (WriteChunkBytes(iff
, &saveprefs
, sizeof(saveprefs
)) == sizeof(saveprefs
))
530 D(bug("[LocalePrefs] SavePrefsFH: WriteChunkBytes(SERL) okay.\n"));
531 D(bug("[LocalePrefs] SavePrefsFH: Everything okay :-)\n"));
536 } /* if (!PushChunk(iff, ID_PREF, ID_SERL, sizeof(struct LocalePrefs))) */
538 } /* if (WriteChunkBytes(iff, &head, sizeof(head)) == sizeof(head)) */
543 } /* if (!PushChunk(iff, ID_PREF, ID_PRHD, sizeof(struct PrefHeader))) */
545 } /* if (!PushChunk(iff, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN)) */
547 } /* if (!OpenIFF(iff, IFFFWRITE)) */
549 } /* if ((iff = AllocIFF())) */
552 if (!retval
&& delete_if_error
)
554 DeleteFile(filename
);
561 /*********************************************************************************************/
563 BOOL
Prefs_SaveCharset(BOOL envarc
)
565 LONG flags
= GVF_GLOBAL_ONLY
;
567 D(bug("[LocalePrefs] SaveCharset(%ld)\n", envarc
));
570 flags
|= GVF_SAVE_VAR
;
571 /* We don't check results of the following actions because they may fail if ENVARC: is read-only (CD-ROM) */
572 if (character_set
[0])
573 SetVar("CHARSET", character_set
, -1, flags
);
575 DeleteVar("CHARSET", flags
);
580 /*********************************************************************************************/
582 static BOOL
Prefs_Load(STRPTR from
)
586 BPTR fh
= Open(from
, MODE_OLDFILE
);
589 retval
= Prefs_ImportFH(fh
);
596 /*********************************************************************************************/
598 BOOL
Prefs_HandleArgs(STRPTR from
, BOOL use
, BOOL save
)
604 if (!Prefs_Load(from
))
606 ShowMessage("Can't read from input file");
612 if (!Prefs_Load(PREFS_PATH_ENV
))
614 if (!Prefs_Load(PREFS_PATH_ENVARC
))
618 "Can't read from file " PREFS_PATH_ENVARC
619 ".\nUsing default values."
628 Prefs_LoadRegion(localeprefs
.lp_CountryName
, &localeprefs
.lp_CountryData
);
629 fh
= Open(PREFS_PATH_ENV
, MODE_NEWFILE
);
637 ShowMessage("Cant' open " PREFS_PATH_ENV
" for writing.");
642 fh
= Open(PREFS_PATH_ENVARC
, MODE_NEWFILE
);
650 ShowMessage("Cant' open " PREFS_PATH_ENVARC
" for writing.");
657 /*********************************************************************************************/
659 BOOL
Prefs_Initialize(VOID
)
661 D(bug("[LocalePrefs] InitPrefs\n"));
663 struct LanguageEntry
*entry
;
665 mempool
= CreatePool(MEMF_PUBLIC
| MEMF_CLEAR
, 2048, 2048);
668 ShowMessage("Out of memory!");
672 NewList(®ion_list
);
673 NewList(&language_list
);
674 NewList(&pref_language_list
);
676 ScanDirectory("LOCALE:Countries/~(#?.info)", ®ion_list
, sizeof(struct RegionEntry
));
677 ScanDirectory("LOCALE:Languages/#?.language", &language_list
, sizeof(struct LanguageEntry
));
679 /* English language is always available */
681 if ((entry
= AllocPooled(mempool
, sizeof(struct LanguageEntry
))))
683 entry
->lve
.node
.ln_Name
= AllocVecPooled(mempool
, 8);
684 strcpy( entry
->lve
.node
.ln_Name
, "English");
685 strcpy( entry
->lve
.realname
, "english");
687 SortInNode(&language_list
, &entry
->lve
.node
);
690 character_set
[0] = 0;
691 GetVar("CHARSET", character_set
, sizeof(character_set
), 0);
692 D(bug("[LocalePrefs] System character set: %s\n", character_set
));
697 /*********************************************************************************************/
699 VOID
Prefs_Deinitialize(VOID
)
701 D(bug("[LocalePrefs] CleanupPrefs\n"));
709 /*********************************************************************************************/
711 BOOL
Prefs_Default(VOID
)
716 localeprefs
.lp_Reserved
[0] = 0;
717 localeprefs
.lp_Reserved
[1] = 0;
718 localeprefs
.lp_Reserved
[2] = 0;
719 localeprefs
.lp_Reserved
[3] = 0;
721 strcpy(localeprefs
.lp_CountryName
, "united_states");
723 for(i
= 0; i
< 10; i
++)
725 memset(localeprefs
.lp_PreferredLanguages
[i
], 0, sizeof(localeprefs
.lp_PreferredLanguages
[i
]));
727 localeprefs
.lp_GMTOffset
= 5 * 60;
728 localeprefs
.lp_Flags
= 0;
730 if (Prefs_LoadRegion((STRPTR
) "united_states", &localeprefs
.lp_CountryData
))
735 character_set
[0] = 0;