Updated PCI IDs to latest snapshot.
[tangerine.git] / workbench / libs / codesetslib / src / libinit.c
blob81dae5d91f9a879d1ccbe7ab53c4ad4b85299f83
1 /***************************************************************************
3 codesets.library - Amiga shared library for handling different codesets
4 Copyright (C) 2001-2005 by Alfonso [alfie] Ranieri <alforan@tin.it>.
5 Copyright (C) 2005-2009 by codesets.library Open Source Team
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 codesets.library project: http://sourceforge.net/projects/codesetslib/
19 $Id$
21 ***************************************************************************/
23 #include "lib.h"
24 #include "version.h"
26 #include <exec/resident.h>
27 #include <proto/exec.h>
29 #include "debug.h"
31 /****************************************************************************/
33 #if !defined(__MORPHOS__)
34 #ifndef __AROS__
35 #define MIN_STACKSIZE 65536
36 #endif
38 // stack cookie for shell v45+
39 static const char USED_VAR stack_size[] = "$STACK:" STR(MIN_STACKSIZE) "\n";
40 #endif
42 /****************************************************************************/
44 #if defined(__amigaos4__)
45 struct Library *SysBase = NULL;
46 struct ExecIFace* IExec = NULL;
47 #if defined(__NEWLIB__)
48 struct Library *NewlibBase = NULL;
49 struct NewlibIFace* INewlib = NULL;
50 #endif
51 #else
52 struct ExecBase *SysBase = NULL;
53 #endif
55 struct LibraryHeader *CodesetsBase = NULL;
57 static const char UserLibName[] = "codesets.library";
58 static const char UserLibID[] = "$VER: codesets.library " LIB_REV_STRING " [" SYSTEMSHORT "/" CPU "] (" LIB_DATE ") " LIB_COPYRIGHT;
60 /****************************************************************************/
62 #define libvector LibNull \
63 LFUNC_FA_(CodesetsConvertUTF32toUTF16) \
64 LFUNC_FA_(CodesetsConvertUTF16toUTF32) \
65 LFUNC_FA_(CodesetsConvertUTF16toUTF8) \
66 LFUNC_FA_(CodesetsIsLegalUTF8) \
67 LFUNC_FA_(CodesetsIsLegalUTF8Sequence) \
68 LFUNC_FA_(CodesetsConvertUTF8toUTF16) \
69 LFUNC_FA_(CodesetsConvertUTF32toUTF8) \
70 LFUNC_FA_(CodesetsConvertUTF8toUTF32) \
71 LFUNC_FA_(CodesetsSetDefaultA) \
72 LFUNC_VA_(CodesetsSetDefault) \
73 LFUNC_FA_(CodesetsFreeA) \
74 LFUNC_VA_(CodesetsFree) \
75 LFUNC_FA_(CodesetsSupportedA) \
76 LFUNC_VA_(CodesetsSupported) \
77 LFUNC_FA_(CodesetsFindA) \
78 LFUNC_VA_(CodesetsFind) \
79 LFUNC_FA_(CodesetsFindBestA) \
80 LFUNC_VA_(CodesetsFindBest) \
81 LFUNC_FA_(CodesetsUTF8Len) \
82 LFUNC_FA_(CodesetsUTF8ToStrA) \
83 LFUNC_VA_(CodesetsUTF8ToStr) \
84 LFUNC_FA_(CodesetsUTF8CreateA) \
85 LFUNC_VA_(CodesetsUTF8Create) \
86 LFUNC_FA_(CodesetsEncodeB64A) \
87 LFUNC_VA_(CodesetsEncodeB64) \
88 LFUNC_FA_(CodesetsDecodeB64A) \
89 LFUNC_VA_(CodesetsDecodeB64) \
90 LFUNC_FA_(CodesetsStrLenA) \
91 LFUNC_VA_(CodesetsStrLen) \
92 LFUNC_FA_(CodesetsIsValidUTF8) \
93 LFUNC_FA_(CodesetsFreeVecPooledA) \
94 LFUNC_VA_(CodesetsFreeVecPooled) \
95 LFUNC_FA_(CodesetsConvertStrA) \
96 LFUNC_VA_(CodesetsConvertStr) \
97 LFUNC_FA_(CodesetsListCreateA) \
98 LFUNC_VA_(CodesetsListCreate) \
99 LFUNC_FA_(CodesetsListDeleteA) \
100 LFUNC_VA_(CodesetsListDelete) \
101 LFUNC_FA_(CodesetsListAddA) \
102 LFUNC_VA_(CodesetsListAdd) \
103 LFUNC_FA_(CodesetsListRemoveA) \
104 LFUNC_VA_(CodesetsListRemove)
107 /****************************************************************************/
109 #if defined(__amigaos4__)
111 static struct LibraryHeader * LIBFUNC LibInit (struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec);
112 static BPTR LIBFUNC LibExpunge (struct LibraryManagerInterface *Self);
113 static struct LibraryHeader * LIBFUNC LibOpen (struct LibraryManagerInterface *Self, ULONG version);
114 static BPTR LIBFUNC LibClose (struct LibraryManagerInterface *Self);
115 static LONG LIBFUNC LibNull (void);
117 #elif defined(__MORPHOS__)
119 static struct LibraryHeader * LIBFUNC LibInit (struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb);
120 static BPTR LIBFUNC LibExpunge(void);
121 static struct LibraryHeader * LIBFUNC LibOpen (void);
122 static BPTR LIBFUNC LibClose (void);
123 static LONG LIBFUNC LibNull (void);
125 #else
127 static struct LibraryHeader * LIBFUNC LibInit (REG(d0, struct LibraryHeader *lh), REG(a0, BPTR Segment), REG(a6, struct ExecBase *sb));
128 static BPTR LIBFUNC LibExpunge (REG(a6, struct LibraryHeader *base));
129 static struct LibraryHeader * LIBFUNC LibOpen (REG(d0, ULONG version), REG(a6, struct LibraryHeader *base));
130 static BPTR LIBFUNC LibClose (REG(a6, struct LibraryHeader *base));
131 static LONG LIBFUNC LibNull (void);
133 #endif
135 /****************************************************************************/
138 * The system (and compiler) rely on a symbol named _start which marks
139 * the beginning of execution of an ELF file. To prevent others from
140 * executing this library, and to keep the compiler/linker happy, we
141 * define an empty _start symbol here.
143 * On the classic system (pre-AmigaOS4) this was usually done by
144 * moveq #0,d0
145 * rts
149 #if defined(__amigaos4__)
150 int _start(void)
151 #else
152 int Main(void)
153 #endif
155 return RETURN_FAIL;
158 static LONG LIBFUNC LibNull(VOID)
160 return(0);
163 /****************************************************************************/
165 #if defined(__amigaos4__)
166 /* ------------------- OS4 Manager Interface ------------------------ */
167 STATIC uint32 _manager_Obtain(struct LibraryManagerInterface *Self)
169 uint32 res;
170 __asm__ __volatile__(
171 "1: lwarx %0,0,%1\n"
172 "addic %0,%0,1\n"
173 "stwcx. %0,0,%1\n"
174 "bne- 1b"
175 : "=&r" (res)
176 : "r" (&Self->Data.RefCount)
177 : "cc", "memory");
179 return res;
182 STATIC uint32 _manager_Release(struct LibraryManagerInterface *Self)
184 uint32 res;
185 __asm__ __volatile__(
186 "1: lwarx %0,0,%1\n"
187 "addic %0,%0,-1\n"
188 "stwcx. %0,0,%1\n"
189 "bne- 1b"
190 : "=&r" (res)
191 : "r" (&Self->Data.RefCount)
192 : "cc", "memory");
194 return res;
197 STATIC CONST CONST_APTR lib_manager_vectors[] =
199 (CONST_APTR)_manager_Obtain,
200 (CONST_APTR)_manager_Release,
201 (CONST_APTR)NULL,
202 (CONST_APTR)NULL,
203 (CONST_APTR)LibOpen,
204 (CONST_APTR)LibClose,
205 (CONST_APTR)LibExpunge,
206 (CONST_APTR)NULL,
207 (CONST_APTR)-1
210 STATIC CONST struct TagItem lib_managerTags[] =
212 { MIT_Name, (Tag)"__library" },
213 { MIT_VectorTable, (Tag)lib_manager_vectors },
214 { MIT_Version, 1 },
215 { TAG_DONE, 0 }
218 /* ------------------- Library Interface(s) ------------------------ */
220 ULONG LibObtain(UNUSED struct Interface *Self)
222 return 0;
225 ULONG LibRelease(UNUSED struct Interface *Self)
227 return 0;
230 STATIC CONST CONST_APTR main_vectors[] =
232 (CONST_APTR)LibObtain,
233 (CONST_APTR)LibRelease,
234 (CONST_APTR)NULL,
235 (CONST_APTR)NULL,
236 (CONST_APTR)libvector,
237 (CONST_APTR)-1
240 STATIC CONST struct TagItem mainTags[] =
242 { MIT_Name, (Tag)"main" },
243 { MIT_VectorTable, (Tag)main_vectors },
244 { MIT_Version, 1 },
245 { TAG_DONE, 0 }
248 STATIC CONST CONST_APTR libInterfaces[] =
250 (CONST_APTR)lib_managerTags,
251 (CONST_APTR)mainTags,
252 (CONST_APTR)NULL
255 // Our libraries always have to carry a 68k jump table with it, so
256 // lets define it here as extern, as we are going to link it to
257 // our binary here.
258 #ifndef NO_VECTABLE68K
259 extern CONST APTR VecTable68K[];
260 #endif
262 STATIC CONST struct TagItem libCreateTags[] =
264 { CLT_DataSize, sizeof(struct LibraryHeader) },
265 { CLT_InitFunc, (Tag)LibInit },
266 { CLT_Interfaces, (Tag)libInterfaces },
267 #ifndef NO_VECTABLE68K
268 { CLT_Vector68K, (Tag)VecTable68K },
269 #endif
270 { TAG_DONE, 0 }
273 #else
275 STATIC CONST CONST_APTR LibVectors[] =
277 #ifdef __MORPHOS__
278 (CONST_APTR)FUNCARRAY_32BIT_NATIVE,
279 #endif
280 (CONST_APTR)LibOpen,
281 (CONST_APTR)LibClose,
282 (CONST_APTR)LibExpunge,
283 (CONST_APTR)LibNull,
284 (CONST_APTR)libvector,
285 (CONST_APTR)-1
288 STATIC CONST IPTR LibInitTab[] =
290 sizeof(struct LibraryHeader),
291 (IPTR)LibVectors,
292 (IPTR)NULL,
293 (IPTR)LibInit
296 #endif
298 /****************************************************************************/
300 static const USED_VAR struct Resident ROMTag =
302 RTC_MATCHWORD,
303 (struct Resident *)&ROMTag,
304 (struct Resident *)(&ROMTag + 1),
305 #if defined(__amigaos4__)
306 RTF_AUTOINIT|RTF_NATIVE, // The Library should be set up according to the given table.
307 #elif defined(__MORPHOS__)
308 RTF_AUTOINIT|RTF_PPC,
309 #elif defined(__AROS__)
310 RTF_AUTOINIT|RTF_EXTENDED,
311 #else
312 RTF_AUTOINIT,
313 #endif
314 LIB_VERSION,
315 NT_LIBRARY,
317 (char *)UserLibName,
318 (char *)UserLibID+6, // +6 to skip '$VER: '
319 #if defined(__amigaos4__)
320 (APTR)libCreateTags // This table is for initializing the Library.
321 #else
322 (APTR)LibInitTab,
323 #endif
324 #if defined(__MORPHOS__) || defined(__AROS__)
325 LIB_REVISION,
327 #endif
330 #if defined(__MORPHOS__)
332 * To tell the loader that this is a new emulppc elf and not
333 * one for the ppc.library.
334 * ** IMPORTANT **
336 const USED_VAR ULONG __abox__ = 1;
338 #endif /* __MORPHOS */
340 /****************************************************************************/
342 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
344 /* generic StackSwap() function which calls function() surrounded by
345 StackSwap() calls */
346 /*extern REGARGS ULONG stackswap_call(struct StackSwapStruct *stack,
347 ULONG (*function)(struct LibraryHeader *),
348 struct LibraryHeader *arg);*/
350 #if defined(__mc68000__)
351 asm(".text \n\
352 .even \n\
353 .globl _stackswap_call \n\
354 _stackswap_call: \n\
355 moveml #0x3022,sp@- \n\
356 movel sp@(20),d3 \n\
357 movel sp@(24),a2 \n\
358 movel sp@(28),d2 \n\
359 movel _SysBase,a6 \n\
360 movel d3,a0 \n\
361 jsr a6@(-732:W) \n\
362 movel d2,sp@- \n\
363 jbsr a2@ \n\
364 movel d0,d2 \n\
365 addql #4,sp \n\
366 movel _SysBase,a6 \n\
367 movel d3,a0 \n\
368 jsr a6@(-732:W) \n\
369 movel d2,d0 \n\
370 moveml sp@+,#0x440c \n\
371 rts");
372 #elif defined(__MORPHOS__)
373 ULONG stackswap_call(struct StackSwapStruct *stack,
374 ULONG (*function)(struct LibraryHeader *),
375 struct LibraryHeader *arg)
377 struct PPCStackSwapArgs swapargs;
379 swapargs.Args[0] = (ULONG)arg;
380 return NewPPCStackSwap(stack, function, &swapargs);
382 #else
383 /* FIXME: This does not work because it can't work. 'arg' variable is also on stack.
384 On AmigaOS v4 it ocassionally works because function's parameters are placed
385 in registers on PPC */
386 ULONG REGARGS stackswap_call(struct StackSwapStruct *stack,
387 ULONG (*function)(struct LibraryHeader *),
388 struct LibraryHeader *arg)
390 register ULONG result;
391 StackSwap(stack);
392 result = function(arg);
393 StackSwap(stack);
394 return result;
396 #endif
398 static BOOL callLibFunction(ULONG (*function)(struct LibraryHeader *), struct LibraryHeader *arg)
400 BOOL success = FALSE;
401 struct Task *tc;
402 ULONG stacksize;
404 // retrieve the task structure for the
405 // current task
406 tc = FindTask(NULL);
408 #if defined(__MORPHOS__)
409 // In MorphOS we have two stacks. One for PPC code and another for 68k code.
410 // We are only interested in the PPC stack.
411 NewGetTaskAttrsA(tc, &stacksize, sizeof(ULONG), TASKINFOTYPE_STACKSIZE, NULL);
412 #else
413 // on all other systems we query via SPUpper-SPLower calculation
414 stacksize = (ULONG)tc->tc_SPUpper - (ULONG)tc->tc_SPLower;
415 #endif
417 // Swap stacks only if current stack is insufficient
418 if(stacksize < MIN_STACKSIZE)
420 struct StackSwapStruct *stack;
422 if((stack = AllocVec(sizeof(*stack), MEMF_PUBLIC)) != NULL)
424 if((stack->stk_Lower = AllocVec(MIN_STACKSIZE, MEMF_PUBLIC)) != NULL)
426 // perform the StackSwap
427 stack->stk_Upper = (ULONG)stack->stk_Lower + MIN_STACKSIZE;
428 stack->stk_Pointer = (APTR)stack->stk_Upper;
430 // call routine but with embedding it into a [NewPPC]StackSwap()
431 success = stackswap_call(stack, function, arg);
433 FreeVec(stack->stk_Lower);
435 FreeVec(stack);
438 else
439 success = function(arg);
441 return success;
444 #endif // !__amigaos4__
446 /****************************************************************************/
448 #if defined(__amigaos4__)
449 static struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec)
451 struct ExecBase *sb = (struct ExecBase *)pIExec->Data.LibBase;
452 IExec = pIExec;
453 #elif defined(__MORPHOS__)
454 static struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb)
456 #else
457 static struct LibraryHeader * LIBFUNC LibInit(REG(d0, struct LibraryHeader *base), REG(a0, BPTR librarySegment), REG(a6, struct ExecBase *sb))
459 #endif
461 SysBase = (APTR)sb;
463 // make sure that this is really a 68020+ machine if optimized for 020+
464 #if _M68060 || _M68040 || _M68030 || _M68020 || __mc68020 || __mc68030 || __mc68040 || __mc68060
465 if(!(SysBase->AttnFlags & AFF_68020))
466 return(NULL);
467 #endif
469 #if defined(__amigaos4__) && defined(__NEWLIB__)
470 if((NewlibBase = OpenLibrary("newlib.library", 3)) &&
471 GETINTERFACE(INewlib, NewlibBase))
472 #endif
474 BOOL success = FALSE;
476 D(DBF_STARTUP, "LibInit()");
478 // cleanup the library header structure beginning with the
479 // library base.
480 base->libBase.lib_Node.ln_Type = NT_LIBRARY;
481 base->libBase.lib_Node.ln_Pri = 0;
482 base->libBase.lib_Node.ln_Name = (char *)UserLibName;
483 base->libBase.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
484 base->libBase.lib_Version = LIB_VERSION;
485 base->libBase.lib_Revision = LIB_REVISION;
486 base->libBase.lib_IdString = (char *)(UserLibID+6);
488 InitSemaphore(&base->libSem);
489 InitSemaphore(&base->poolSem);
491 base->sysBase = (APTR)SysBase;
492 base->pool = NULL;
493 base->flags = 0;
494 base->systemCodeset = NULL;
496 // protect access to initBase()
497 ObtainSemaphore(&base->libSem);
499 // set the CodesetsBase
500 CodesetsBase = base;
502 // If we are not running on AmigaOS4 (no stackswap required) we go and
503 // do an explicit StackSwap() in case the user wants to make sure we
504 // have enough stack for his user functions
505 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
506 success = callLibFunction(initBase, base);
507 #else
508 success = initBase(base);
509 #endif
511 // unprotect initBase()
512 ReleaseSemaphore(&base->libSem);
514 // check if everything worked out fine
515 if(success == TRUE)
517 // everything was successfully so lets
518 // set the initialized value and contiue
519 // with the class open phase
520 base->segList = librarySegment;
522 // return the library base as success
523 return base;
525 else
526 CodesetsBase = NULL;
528 #if defined(__amigaos4__) && defined(__NEWLIB__)
529 if(NewlibBase)
531 DROPINTERFACE(INewlib);
532 CloseLibrary(NewlibBase);
533 NewlibBase = NULL;
535 #endif
538 return(NULL);
541 /****************************************************************************/
543 #ifndef __amigaos4__
544 #define DeleteLibrary(LIB) \
545 FreeMem((STRPTR)(LIB)-(LIB)->lib_NegSize, (ULONG)((LIB)->lib_NegSize+(LIB)->lib_PosSize))
546 #endif
548 #if defined(__amigaos4__)
549 static BPTR LibExpunge(struct LibraryManagerInterface *Self)
551 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
552 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
553 #elif defined(__MORPHOS__)
554 static BPTR LibExpunge(void)
556 struct LibraryHeader *base = (struct LibraryHeader*)REG_A6;
557 #else
558 static BPTR LIBFUNC LibExpunge(REG(a6, struct LibraryHeader *base))
560 #endif
561 BPTR rc;
563 D(DBF_STARTUP, "LibExpunge(): %ld", base->libBase.lib_OpenCnt);
565 // in case our open counter is still > 0, we have
566 // to set the late expunge flag and return immediately
567 if(base->libBase.lib_OpenCnt > 0)
569 base->libBase.lib_Flags |= LIBF_DELEXP;
570 rc = 0;
572 else
574 // make sure to restore the SysBase
575 SysBase = (APTR)base->sysBase;
577 // remove the library base from exec's lib list in advance
578 Remove((struct Node *)base);
580 // free all our private data and stuff.
581 ObtainSemaphore(&base->libSem);
583 // make sure we have enough stack here
584 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
585 callLibFunction(freeBase, base);
586 #else
587 freeBase(base);
588 #endif
590 // unprotect
591 ReleaseSemaphore(&base->libSem);
593 #if defined(__amigaos4__) && defined(__NEWLIB__)
594 if(NewlibBase)
596 DROPINTERFACE(INewlib);
597 CloseLibrary(NewlibBase);
598 NewlibBase = NULL;
600 #endif
602 // make sure the system deletes the library as well.
603 rc = base->segList;
604 DeleteLibrary(&base->libBase);
607 return rc;
610 /****************************************************************************/
612 #if defined(__amigaos4__)
613 static struct LibraryHeader *LibOpen(struct LibraryManagerInterface *Self, ULONG version UNUSED)
615 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
616 #elif defined(__MORPHOS__)
617 static struct LibraryHeader *LibOpen(void)
619 struct LibraryHeader *base = (struct LibraryHeader*)REG_A6;
620 #else
621 static struct LibraryHeader * LIBFUNC LibOpen(REG(d0, UNUSED ULONG version), REG(a6, struct LibraryHeader *base))
623 #endif
624 struct LibraryHeader *res = base;
626 D(DBF_STARTUP, "LibOpen(): %ld", base->libBase.lib_OpenCnt);
628 // LibOpen(), LibClose() and LibExpunge() are called while the system is in
629 // Forbid() state. That means that these functions should be quick and should
630 // not break this Forbid()!! Therefore the open counter should be increased
631 // as the very first instruction during LibOpen(), because a ClassOpen()
632 // which breaks a Forbid() and another task calling LibExpunge() will cause
633 // to expunge this library while it is not yet fully initialized. A crash
634 // is unavoidable then. Even the semaphore does not guarantee 100% protection
635 // against such a race condition, because waiting for the semaphore to be
636 // obtained will effectively break the Forbid()!
638 // increase the open counter ahead of anything else
639 base->libBase.lib_OpenCnt++;
641 // delete the late expunge flag
642 base->libBase.lib_Flags &= ~LIBF_DELEXP;
644 return res;
647 /****************************************************************************/
649 #if defined(__amigaos4__)
650 static BPTR LibClose(struct LibraryManagerInterface *Self)
652 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
653 #elif defined(__MORPHOS__)
654 static BPTR LibClose(void)
656 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
657 #else
658 static BPTR LIBFUNC LibClose(REG(a6, struct LibraryHeader *base))
660 #endif
661 BPTR rc = 0;
663 D(DBF_STARTUP, "LibClose(): %ld", base->libBase.lib_OpenCnt);
665 // decrease the open counter
666 base->libBase.lib_OpenCnt--;
668 // in case the opern counter is <= 0 we can
669 // make sure that we free everything
670 if(base->libBase.lib_OpenCnt <= 0)
672 // in case the late expunge flag is set we go and
673 // expunge the library base right now
674 if(base->libBase.lib_Flags & LIBF_DELEXP)
676 #if defined(__amigaos4__)
677 rc = LibExpunge(Self);
678 #elif defined(__MORPHOS__)
679 rc = LibExpunge();
680 #else
681 rc = LibExpunge(base);
682 #endif
684 return rc;
688 return rc;
691 /****************************************************************************/