- Tabs to spaces.
[AROS.git] / workbench / libs / locale / opencataloga.c
blob3ef6b91c9e626474158dccbd6c2eab264a8c0499
1 /*
2 Copyright © 1995-2011, 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 /*****************************************************************************
30 NAME */
31 #include <proto/locale.h>
33 AROS_LH3(struct Catalog *, OpenCatalogA,
35 /* SYNOPSIS */
36 AROS_LHA(const struct Locale *, locale, A0),
37 AROS_LHA(CONST_STRPTR, name, A1),
38 AROS_LHA(const struct TagItem *, tags, A2),
40 /* LOCATION */
41 struct LocaleBase *, LocaleBase, 25, Locale)
43 /* FUNCTION
45 INPUTS
47 RESULT
49 NOTES
51 EXAMPLE
53 BUGS
55 SEE ALSO
57 INTERNALS
59 *****************************************************************************/
61 AROS_LIBFUNC_INIT
63 struct Locale *def_locale = NULL;
64 struct IntCatalog *catalog = NULL;
65 char *language;
66 char *app_language; /* Language given with tag OC_BuiltInLanguage */
67 char *specific_language; /* Language given with tag OC_Language */
68 struct Process *MyProcess;
69 #define FILENAMESIZE 256
71 char filename[FILENAMESIZE];
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 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: no locale\n"));
88 locale = def_locale = OpenLocale(NULL);
89 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: def_locale 0x%lx\n",
90 def_locale));
93 if (!locale)
95 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: nolocale..done\n"));
96 return NULL;
99 MyProcess = (struct Process *)FindTask(NULL);
101 specific_language = (char *)GetTagData(OC_Language, (IPTR) 0, tags);
103 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: specific lang 0x%lx\n",
104 specific_language));
105 if (specific_language)
107 language = specific_language;
108 pref_language = -1;
109 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: language 0x%lx\n",
110 language));
112 else
114 language = locale->loc_PrefLanguages[0];
115 pref_language = 0;
116 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: language 0x%lx\n",
117 language));
120 if (language == NULL)
122 if (def_locale)
123 CloseLocale(def_locale);
124 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: nolanguage..done\n"));
125 return NULL;
129 ** Check whether the built in language of the application matches
130 ** the language of the default locale. If it matches, then I
131 ** don't need to load anything.
134 app_language = "english";
135 app_language = (char *)GetTagData(OC_BuiltInLanguage,
136 (IPTR) app_language, tags);
138 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: app_language 0x%lx\n",
139 app_language));
141 if (NULL != app_language && 0 == strcasecmp(app_language, language))
143 if (def_locale)
144 CloseLocale(def_locale);
145 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: failure..done\n"));
146 return NULL;
149 version = GetTagData(OC_Version, 0, tags);
151 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: version %ld\n", version));
153 if (NULL != name)
155 struct IFFHandle *iff = NULL;
158 ** The wanted catalog might be in the list of catalogs that are
159 ** already loaded. So check that list first.
162 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: CatalogLock 0x%lx\n",
163 &IntLB(LocaleBase)->lb_CatalogLock));
165 ObtainSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
167 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: search cached Catalog\n"));
169 ForeachNode(&IntLB(LocaleBase)->lb_CatalogList, catalog)
171 if (catalog->ic_Name &&
172 0 == strcmp(catalog->ic_Name, name) &&
173 catalog->ic_Catalog.cat_Language &&
174 0 == strcmp(catalog->ic_Catalog.cat_Language, language))
176 DEBUG_OPENCATALOG(dprintf
177 ("OpenCatalogA: found Catalog 0x%lx\n", catalog));
178 catalog->ic_UseCount++;
179 ReleaseSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
181 if (def_locale)
183 CloseLocale(def_locale);
186 SetIoErr(ERROR_ACTION_NOT_KNOWN);
188 DEBUG_OPENCATALOG(dprintf
189 ("OpenCatalogA: return Catalog 0x%lx\n", catalog));
190 return (struct Catalog *)catalog;
193 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: found none\n"));
195 ReleaseSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
197 /* Clear error condition before we start. */
198 SetIoErr(0);
200 iff = AllocIFF();
202 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: iff 0x%lx\n", iff));
203 if (NULL == iff)
205 if (def_locale)
206 CloseLocale(def_locale);
207 SetIoErr(ERROR_NO_FREE_STORE);
209 return NULL;
212 DEBUG_OPENCATALOG(dprintf
213 ("OpenCatalogA: pref_language %ld language 0x%lx\n",
214 pref_language, language));
216 while ((pref_language < 10) && language)
218 if (app_language && (strcmp(language, app_language) == 0))
220 FreeIFF(iff);
221 if (def_locale)
222 CloseLocale(def_locale);
223 SetIoErr(0);
224 return NULL;
227 if ((MyProcess->pr_HomeDir) != BNULL)
229 DEBUG_OPENCATALOG(dprintf
230 ("OpenCatalogA: HomeDir != BNULL..try progdir\n"));
231 strcpy(filename, "PROGDIR:Catalogs");
232 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
233 filename));
234 AddPart(filename, language, FILENAMESIZE);
235 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
236 filename));
237 AddPart(filename, name, FILENAMESIZE);
239 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
240 filename));
241 iff->iff_Stream = (IPTR) Open(filename, MODE_OLDFILE);
242 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: iffstream 0x%lx\n",
243 iff->iff_Stream));
245 if (iff->iff_Stream)
246 break;
248 #ifdef __MORPHOS__
249 strcpy(filename, "MOSSYS:LOCALE/Catalogs");
251 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
252 filename));
253 AddPart(filename, language, FILENAMESIZE);
254 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
255 filename));
256 AddPart(filename, name, FILENAMESIZE);
258 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: try filename <%s>\n",
259 filename));
262 APTR oldwinptr = MyProcess->pr_WindowPtr;
263 MyProcess->pr_WindowPtr = (APTR) - 1;
264 iff->iff_Stream = (IPTR) Open(filename, MODE_OLDFILE);
265 MyProcess->pr_WindowPtr = oldwinptr;
268 if (iff->iff_Stream)
269 break;
270 #endif
271 strcpy(filename, "LOCALE:Catalogs");
273 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
274 filename));
275 AddPart(filename, language, FILENAMESIZE);
276 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: filename <%s>\n",
277 filename));
278 AddPart(filename, name, FILENAMESIZE);
280 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: try filename <%s>\n",
281 filename));
283 iff->iff_Stream = (IPTR) Open(filename, MODE_OLDFILE);
284 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: iffstream 0x%lx\n",
285 iff->iff_Stream));
287 if (iff->iff_Stream)
288 break;
290 pref_language++;
291 language = locale->loc_PrefLanguages[pref_language];
294 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: language 0x%lx\n",
295 language));
297 /* I no longer need the locale. So close it if we opened it */
299 if (def_locale)
301 CloseLocale(def_locale);
302 def_locale = NULL;
305 #undef FILENAMESIZE
307 if (iff->iff_Stream == 0)
309 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: end... no stream\n"));
310 FreeIFF(iff);
311 SetIoErr(ERROR_OBJECT_NOT_FOUND);
312 return NULL;
315 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog name <%s>\n",
316 name));
317 catalog =
318 AllocVec(sizeof(struct IntCatalog) + strlen(name) + 1,
319 MEMF_CLEAR | MEMF_PUBLIC);
320 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog 0x%lx\n",
321 catalog));
322 if (NULL == catalog)
324 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: end..no catalog\n"));
325 Close((BPTR) iff->iff_Stream);
326 FreeIFF(iff);
327 SetIoErr(ERROR_NO_FREE_STORE);
328 return NULL;
331 catalog->ic_UseCount = 1;
332 catalog->ic_Catalog.cat_Language = catalog->ic_LanguageName;
333 strcpy(catalog->ic_Name, name);
334 catalog->ic_Catalog.cat_Link.ln_Name = catalog->ic_Name; /* Scout expects this */
336 InitIFFasDOS(iff);
338 if (!OpenIFF(iff, IFFF_READ))
340 while (1)
342 LONG error = ParseIFF(iff, IFFPARSE_STEP);
344 if (IFFERR_EOF == error)
346 DEBUG_OPENCATALOG(dprintf
347 ("OpenCatalogA: parsed catalog\n"));
348 /* Did everything go fine? */
350 if (!(catalog->ic_LanguageName[0]))
352 /* No ID_LANG chunk found. So setup languagename ourselves.
353 Hmm ... maybe this should be done anyway always. Because
354 if the catalog file *does* contain an ID_LANG chunk then
355 this should be the same as "language" anyway. And if it
356 is not, then maybe OpenCatalogA() should fail :-\ */
358 strcpy(catalog->ic_LanguageName, language);
361 /* Connect this catalog to the list of catalogs */
362 ObtainSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
363 AddHead((struct List *)&IntLB(LocaleBase)->
364 lb_CatalogList, &catalog->ic_Catalog.cat_Link);
365 ReleaseSemaphore(&IntLB(LocaleBase)->lb_CatalogLock);
367 CloseIFF(iff);
368 Close((BPTR) iff->iff_Stream);
369 FreeIFF(iff);
371 DEBUG_OPENCATALOG(dprintf
372 ("OpenCatalogA: return catalog 0x%lx\n", catalog));
374 return &catalog->ic_Catalog;
377 if (IFFERR_EOC == error) /* end of chunk */
378 continue;
380 if (0 == error)
382 struct ContextNode *top = CurrentChunk(iff);
384 switch (top->cn_ID)
386 case ID_FORM:
387 break;
389 case ID_FVER:
391 if (top->cn_Size > 100)
392 break; /*max 100 bytes */
394 error = ReadChunkBytes(iff, buf, top->cn_Size);
395 if (error == top->cn_Size)
397 error = 0;
399 else
401 break;
404 buf[99] = 0;
406 /*Ok now we want to get the version and the revision.
407 They are separated by a blank space */
409 i = 0;
410 while (buf[i] && (buf[i] != ' '))
411 i++;
412 while (buf[i] && (buf[i] == ' '))
413 i++;
414 while (buf[i] && (buf[i] != ' '))
415 i++;
417 if (buf[i])
419 if ((chars =
420 StrToLong(&buf[i],
421 (LONG *) & catversion)) < 0)
422 break;
424 i += chars;
425 if (buf[i++])
427 if (StrToLong(&buf[i],
428 (LONG *) & catrevision) < 0)
429 break;
432 catalog->ic_Catalog.cat_Version = catversion;
433 catalog->ic_Catalog.cat_Revision = catrevision;
435 if (version && (catversion != version))
437 error = RETURN_ERROR;
440 break;
444 case ID_LANG:
445 /* The IntCatalog structure has only 30 bytes reserved for
446 the language name. So make sure the chunk is not bigger. */
448 if (top->cn_Size > 30)
449 break;
451 error =
452 ReadChunkBytes(iff, catalog->ic_LanguageName,
453 top->cn_Size);
454 if (error == top->cn_Size)
456 error = 0;
458 break;
460 case ID_CSET:
461 if (top->cn_Size != sizeof(struct CodeSet))
462 break;
463 if (top->cn_Size == ReadChunkBytes(iff,
464 &catalog->ic_CodeSet, top->cn_Size))
466 /* Who cares: codeset is not used at the moment */
468 break;
470 case ID_STRS:
471 if (!(catalog->ic_StringChunk =
472 AllocVec(top->cn_Size,
473 MEMF_PUBLIC | MEMF_CLEAR)))
475 error = ERROR_NO_FREE_STORE;
476 SetIoErr(error);
477 break;
480 error =
481 ReadChunkBytes(iff, catalog->ic_StringChunk,
482 top->cn_Size);
483 if (error == top->cn_Size)
485 error = 0;
487 else
489 break;
492 /* Count the number of strings */
495 UBYTE *buffer = catalog->ic_StringChunk;
496 LONG c = 0, strlen;
498 catalog->ic_NumStrings = 0;
500 while (c < top->cn_Size)
502 catalog->ic_NumStrings++;
504 strlen = (buffer[4] << 24) +
505 (buffer[5] << 16) +
506 (buffer[6] << 8) + (buffer[7]);
508 strlen = 8 + strlen + (strlen & 1);
509 if (strlen & 3)
510 strlen += 4 - (strlen & 3);
512 c += strlen;
513 buffer += strlen;
518 if (catalog->ic_NumStrings == 0)
519 break; /* Paranoia? */
521 if (!(catalog->ic_CatStrings =
522 AllocVec(catalog->ic_NumStrings *
523 sizeof(struct CatStr),
524 MEMF_PUBLIC | MEMF_CLEAR)))
526 error = ERROR_NO_FREE_STORE;
527 SetIoErr(error);
528 break;
531 /* Fill out catalog->ic_CatStrings array */
534 UBYTE *buffer = catalog->ic_StringChunk;
535 ULONG i, strlen, id, previd = 0;
536 BOOL inorder = TRUE;
538 for (i = 0; i < catalog->ic_NumStrings; i++)
540 id = (buffer[0] << 24) +
541 (buffer[1] << 16) +
542 (buffer[2] << 8) + (buffer[3]);
544 strlen = (buffer[4] << 24) +
545 (buffer[5] << 16) +
546 (buffer[6] << 8) + (buffer[7]);
548 catalog->ic_CatStrings[i].cs_String =
549 &buffer[8];
550 catalog->ic_CatStrings[i].cs_Id = id;
552 //kprintf("Catalog String #%d id=%d string=\"%s\"\n", i, id, catalog->ic_CatStrings[i].cs_String);
554 strlen = 8 + strlen + (strlen & 1);
555 if (strlen & 3)
556 strlen += 4 - (strlen & 3);
558 if (id < previd)
559 inorder = FALSE;
561 buffer += strlen;
562 previd = id;
565 if (inorder)
566 catalog->ic_Flags |= ICF_INORDER;
568 break;
570 } /* switch (top->cn_ID) */
572 } /* if (0 == error) */
574 if (error)
576 dispose_catalog(catalog, LocaleBase);
578 ** An error with the file occurred
580 break;
583 } /* while (1) */
585 CloseIFF(iff);
587 } /* if (!OpenIFF(iff, IFFF_READ)) */
590 Close((BPTR) iff->iff_Stream);
591 FreeIFF(iff);
592 FreeVec(catalog);
594 } /* if (NULL != name) */
596 if (def_locale)
597 CloseLocale(def_locale);
599 DEBUG_OPENCATALOG(dprintf("OpenCatalogA: catalog not loaded\n"));
600 return NULL;
602 AROS_LIBFUNC_EXIT