revert between 56095 -> 55830 in arch
[AROS.git] / workbench / libs / locale / opencataloga.c
blob94021f253bd3d069b1796baa4c226d66610260bf
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 #define AROS_ALMOST_COMPATIBLE
7 #include <exec/types.h>
8 #include <exec/memory.h>
9 #include <exec/lists.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
12 #include <libraries/iffparse.h>
13 #include <proto/iffparse.h>
14 #include <proto/utility.h>
15 #include <string.h>
16 #include "locale_intern.h"
18 #include <aros/debug.h>
20 #define DEBUG_OPENCATALOG(x) ;
22 struct header
24 unsigned char id[4];
25 unsigned char len[4];
28 static IPTR _OpenCatalog(const struct Locale * locale, CONST_STRPTR name, STRPTR language);
30 /*****************************************************************************
32 NAME */
33 #include <proto/locale.h>
35 AROS_LH3(struct Catalog *, OpenCatalogA,
37 /* SYNOPSIS */
38 AROS_LHA(const struct Locale *, locale, A0),
39 AROS_LHA(CONST_STRPTR, name, A1),
40 AROS_LHA(const struct TagItem *, tags, A2),
42 /* LOCATION */
43 struct LocaleBase *, LocaleBase, 25, Locale)
45 /* FUNCTION
47 INPUTS
49 RESULT
51 NOTES
53 EXAMPLE
55 BUGS
57 SEE ALSO
59 INTERNALS
61 *****************************************************************************/
63 AROS_LIBFUNC_INIT
65 struct IntLocaleBase *_localeBase = IntLB(LocaleBase);
66 struct Locale *def_locale = NULL;
67 struct IntCatalog *catalog = NULL;
68 char *language;
69 char *app_language; /* Language given with tag OC_BuiltInLanguage */
70 char *specific_language; /* Language given with tag OC_Language */
72 char buf[100];
73 LONG chars;
74 ULONG version;
75 ULONG catversion, catrevision;
76 WORD pref_language;
77 UWORD i;
79 DEBUG_OPENCATALOG(dprintf
80 ("OpenCatalogA: locale 0x%lx name <%s> Tags 0x%lx localebase 0x%lx\n",
81 locale, name, tags, LocaleBase));
83 SetIoErr(0);
85 if (!locale)
87 if (!(locale = OpenLocale(NULL)))
89 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: no locale to use? ..done\n"));
90 return NULL;
92 def_locale = (struct Locale *)locale;
93 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: default locale @ 0x%lx\n", def_locale));
96 if ((specific_language = (char *)GetTagData(OC_Language, (IPTR) 0, tags)))
98 language = specific_language;
99 pref_language = -1;
100 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: requested language '%s' @ 0x%lx\n", language, language));
102 else
104 if ((language = locale->loc_PrefLanguages[0]) == NULL)
106 if (def_locale)
107 CloseLocale(def_locale);
108 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: no language to use? ..done\n"));
109 return NULL;
111 pref_language = 0;
112 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: default language '%s' @ 0x%lx\n", language, language));
116 ** Check whether the built in language of the application matches
117 ** the language of the default locale. If it matches, then we
118 ** don't need to load anything.
121 app_language = (char *)GetTagData(OC_BuiltInLanguage,
122 (IPTR) "english", tags);
124 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: app_language '%s' @ 0x%lx\n", app_language, app_language));
126 if (app_language && (0 == strcasecmp(app_language, language)))
128 if (def_locale)
129 CloseLocale(def_locale);
130 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: failure..done\n"));
131 return NULL;
134 version = GetTagData(OC_Version, 0, tags);
136 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: version %ld\n", version));
138 if (NULL != name)
140 struct IFFHandle *iff = NULL;
143 ** The wanted catalog might be in the list of catalogs that are
144 ** already loaded. So check that list first.
147 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: CatalogLock 0x%lx\n",
148 &_localeBase->lb_CatalogLock));
150 ObtainSemaphore(&_localeBase->lb_CatalogLock);
152 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: search cached Catalog\n"));
154 ForeachNode(&_localeBase->lb_CatalogList, catalog)
156 if (catalog->ic_Name &&
157 catalog->ic_Catalog.cat_Language &&
158 (0 == strcmp(catalog->ic_Name, name)) &&
159 (0 == strcmp(catalog->ic_Catalog.cat_Language, language)))
161 DEBUG_OPENCATALOG(dprintf
162 ("OpenCatalogA: found Catalog 0x%lx\n", catalog));
163 catalog->ic_UseCount++;
164 ReleaseSemaphore(&_localeBase->lb_CatalogLock);
166 if (def_locale)
168 CloseLocale(def_locale);
171 SetIoErr(ERROR_ACTION_NOT_KNOWN);
173 DEBUG_OPENCATALOG(dprintf
174 ("OpenCatalogA: return Catalog 0x%lx\n", catalog));
175 return (struct Catalog *)catalog;
178 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: found none\n"));
180 ReleaseSemaphore(&_localeBase->lb_CatalogLock);
182 /* Clear error condition before we start. */
183 SetIoErr(0);
185 iff = AllocIFF();
187 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: iff 0x%lx\n", iff));
188 if (NULL == iff)
190 if (def_locale)
191 CloseLocale(def_locale);
192 SetIoErr(ERROR_NO_FREE_STORE);
194 return NULL;
197 DEBUG_OPENCATALOG(dprintf
198 ("OpenCatalogA: pref_language %ld language 0x%lx\n",
199 pref_language, language));
201 while ((pref_language < 10) && language)
203 if (app_language && (strcmp(language, app_language) == 0))
205 FreeIFF(iff);
206 if (def_locale)
207 CloseLocale(def_locale);
208 SetIoErr(0);
209 return NULL;
212 iff->iff_Stream = _OpenCatalog(locale, name, language);
214 if (iff->iff_Stream)
215 break;
217 pref_language++;
218 language = locale->loc_PrefLanguages[pref_language];
221 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: language 0x%lx\n",
222 language));
224 /* I no longer need the locale. So close it if we opened it */
226 if (def_locale)
228 CloseLocale(def_locale);
229 def_locale = NULL;
232 if (iff->iff_Stream == 0)
234 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: end... no stream\n"));
235 FreeIFF(iff);
236 SetIoErr(ERROR_OBJECT_NOT_FOUND);
237 return NULL;
240 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog name <%s>\n",
241 name));
242 catalog =
243 AllocVec(sizeof(struct IntCatalog) + strlen(name) + 1,
244 MEMF_CLEAR | MEMF_PUBLIC);
245 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog 0x%lx\n",
246 catalog));
247 if (NULL == catalog)
249 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: end..no catalog\n"));
250 Close((BPTR) iff->iff_Stream);
251 FreeIFF(iff);
252 SetIoErr(ERROR_NO_FREE_STORE);
253 return NULL;
256 catalog->ic_UseCount = 1;
257 catalog->ic_Catalog.cat_Language = catalog->ic_LanguageName;
258 strcpy(catalog->ic_Name, name);
259 catalog->ic_Catalog.cat_Link.ln_Name = catalog->ic_Name; /* Scout expects this */
261 InitIFFasDOS(iff);
263 if (!OpenIFF(iff, IFFF_READ))
265 while (1)
267 LONG error = ParseIFF(iff, IFFPARSE_STEP);
269 if (IFFERR_EOF == error)
271 DEBUG_OPENCATALOG(dprintf
272 ("OpenCatalogA: parsed catalog\n"));
273 /* Did everything go fine? */
275 if (!(catalog->ic_LanguageName[0]))
277 /* No ID_LANG chunk found. So setup languagename ourselves.
278 Hmm ... maybe this should be done anyway always. Because
279 if the catalog file *does* contain an ID_LANG chunk then
280 this should be the same as "language" anyway. And if it
281 is not, then maybe OpenCatalogA() should fail :-\ */
283 strcpy(catalog->ic_LanguageName, language);
286 /* Connect this catalog to the list of catalogs */
287 ObtainSemaphore(&_localeBase->lb_CatalogLock);
288 AddHead((struct List *)&_localeBase->
289 lb_CatalogList, &catalog->ic_Catalog.cat_Link);
290 ReleaseSemaphore(&_localeBase->lb_CatalogLock);
292 CloseIFF(iff);
293 Close((BPTR) iff->iff_Stream);
294 FreeIFF(iff);
296 DEBUG_OPENCATALOG(dprintf
297 ("OpenCatalogA: return catalog 0x%lx\n", catalog));
299 return &catalog->ic_Catalog;
302 if (IFFERR_EOC == error) /* end of chunk */
303 continue;
305 if (0 == error)
307 struct ContextNode *top = CurrentChunk(iff);
309 switch (top->cn_ID)
311 case ID_FORM:
312 break;
314 case ID_FVER:
316 if (top->cn_Size > 100)
317 break; /*max 100 bytes */
319 error = ReadChunkBytes(iff, buf, top->cn_Size);
320 if (error == top->cn_Size)
322 error = 0;
324 else
326 break;
329 buf[99] = 0;
331 /*Ok now we want to get the version and the revision.
332 They are separated by a blank space */
334 i = 0;
335 while (buf[i] && (buf[i] != ' '))
336 i++;
337 while (buf[i] && (buf[i] == ' '))
338 i++;
339 while (buf[i] && (buf[i] != ' '))
340 i++;
342 if (buf[i])
344 if ((chars =
345 StrToLong(&buf[i],
346 (LONG *) & catversion)) < 0)
347 break;
349 i += chars;
350 if (buf[i++])
352 if (StrToLong(&buf[i],
353 (LONG *) & catrevision) < 0)
354 break;
357 catalog->ic_Catalog.cat_Version = catversion;
358 catalog->ic_Catalog.cat_Revision = catrevision;
360 if (version && (catversion != version))
362 error = RETURN_ERROR;
365 break;
369 case ID_LANG:
370 /* The IntCatalog structure has only 30 bytes reserved for
371 the language name. So make sure the chunk is not bigger. */
373 if (top->cn_Size > 30)
374 break;
376 error =
377 ReadChunkBytes(iff, catalog->ic_LanguageName,
378 top->cn_Size);
379 if (error == top->cn_Size)
381 error = 0;
383 break;
385 case ID_CSET:
386 if (top->cn_Size != sizeof(struct CodeSet))
387 break;
388 if (top->cn_Size == ReadChunkBytes(iff,
389 &catalog->ic_CodeSet, top->cn_Size))
391 /* Who cares: codeset is not used at the moment */
393 break;
395 case ID_STRS:
396 if (!(catalog->ic_StringChunk =
397 AllocVec(top->cn_Size,
398 MEMF_PUBLIC | MEMF_CLEAR)))
400 error = ERROR_NO_FREE_STORE;
401 SetIoErr(error);
402 break;
405 error =
406 ReadChunkBytes(iff, catalog->ic_StringChunk,
407 top->cn_Size);
408 if (error == top->cn_Size)
410 error = 0;
412 else
414 break;
417 /* Count the number of strings */
420 UBYTE *buffer = catalog->ic_StringChunk;
421 LONG c = 0, strlen;
423 catalog->ic_NumStrings = 0;
425 while (c < top->cn_Size)
427 catalog->ic_NumStrings++;
429 strlen = (buffer[4] << 24) +
430 (buffer[5] << 16) +
431 (buffer[6] << 8) + (buffer[7]);
433 strlen = 8 + strlen + (strlen & 1);
434 if (strlen & 3)
435 strlen += 4 - (strlen & 3);
437 c += strlen;
438 buffer += strlen;
443 if (catalog->ic_NumStrings == 0)
444 break; /* Paranoia? */
446 if (!(catalog->ic_CatStrings =
447 AllocVec(catalog->ic_NumStrings *
448 sizeof(struct CatStr),
449 MEMF_PUBLIC | MEMF_CLEAR)))
451 error = ERROR_NO_FREE_STORE;
452 SetIoErr(error);
453 break;
456 /* Fill out catalog->ic_CatStrings array */
459 UBYTE *buffer = catalog->ic_StringChunk;
460 ULONG i, strlen, id, previd = 0;
461 BOOL inorder = TRUE;
463 for (i = 0; i < catalog->ic_NumStrings; i++)
465 id = (buffer[0] << 24) +
466 (buffer[1] << 16) +
467 (buffer[2] << 8) + (buffer[3]);
469 strlen = (buffer[4] << 24) +
470 (buffer[5] << 16) +
471 (buffer[6] << 8) + (buffer[7]);
473 catalog->ic_CatStrings[i].cs_String =
474 &buffer[8];
475 catalog->ic_CatStrings[i].cs_Id = id;
477 //kprintf("Catalog String #%d id=%d string=\"%s\"\n", i, id, catalog->ic_CatStrings[i].cs_String);
479 strlen = 8 + strlen + (strlen & 1);
480 if (strlen & 3)
481 strlen += 4 - (strlen & 3);
483 if (id < previd)
484 inorder = FALSE;
486 buffer += strlen;
487 previd = id;
490 if (inorder)
491 catalog->ic_Flags |= ICF_INORDER;
493 break;
495 } /* switch (top->cn_ID) */
497 } /* if (0 == error) */
499 if (error)
501 dispose_catalog(catalog, LocaleBase);
503 ** An error with the file occurred
505 break;
508 } /* while (1) */
510 CloseIFF(iff);
512 } /* if (!OpenIFF(iff, IFFF_READ)) */
515 Close((BPTR) iff->iff_Stream);
516 FreeIFF(iff);
517 FreeVec(catalog);
519 } /* if (NULL != name) */
521 if (def_locale)
522 CloseLocale(def_locale);
524 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog not loaded\n"));
525 return NULL;
527 AROS_LIBFUNC_EXIT
530 static STRPTR Preferred2OnDisk(struct IntLocale * locale, STRPTR language)
532 LONG i = 0;
533 while (i < 10)
535 if (locale->il_Locale.loc_PrefLanguages[i] &&
536 strcmp(locale->il_Locale.loc_PrefLanguages[i], language) == 0)
537 return locale->LanguagesOnDiskNames[i];
538 i++;
541 return NULL;
544 static IPTR _OpenFile(const struct Locale * locale, STRPTR root, CONST_STRPTR name, STRPTR language)
546 #define FILENAMESIZE 256
547 TEXT filename[FILENAMESIZE];
548 IPTR iff_Stream = (IPTR)NULL;
550 strcpy(filename, root);
551 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
552 filename));
553 AddPart(filename, language, FILENAMESIZE);
554 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
555 filename));
556 AddPart(filename, name, FILENAMESIZE);
558 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
559 filename));
560 iff_Stream = (IPTR) Open(filename, MODE_OLDFILE);
561 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: iffstream 0x%lx\n",
562 iff_Stream));
564 if (!iff_Stream && locale)
566 STRPTR altname = Preferred2OnDisk((struct IntLocale *)locale, language);
567 if (altname)
568 iff_Stream = _OpenFile(NULL, root, name, altname);
571 return iff_Stream;
573 #undef FILENAMESIZE
576 static IPTR _OpenCatalog(const struct Locale * locale, CONST_STRPTR name, STRPTR language)
578 struct Process * MyProcess = (struct Process *)FindTask(NULL);
580 IPTR iff_Stream = (IPTR)NULL;
582 if ((MyProcess->pr_HomeDir) != BNULL)
584 DEBUG_OPENCATALOG(dprintf
585 ("OpenCatalogA: HomeDir != BNULL..try progdir\n"));
586 iff_Stream = _OpenFile(locale, "PROGDIR:Catalogs", name, language);
589 if (iff_Stream)
590 return iff_Stream;
592 #ifdef __MORPHOS__
595 APTR oldwinptr = MyProcess->pr_WindowPtr;
596 MyProcess->pr_WindowPtr = (APTR) - 1;
597 iff_Stream = _OpenFile(locale, "MOSSYS:LOCALE/Catalogs", name, language);
598 MyProcess->pr_WindowPtr = oldwinptr;
601 if (iff_Stream)
602 return iff_Stream;
603 #endif
605 iff_Stream = _OpenFile(locale, "LOCALE:Catalogs", name, language);
607 if (iff_Stream)
608 return iff_Stream;
610 return (IPTR)NULL;