Resurrected native codesetslib from r27301
[cake.git] / workbench / libs / codesetslib / src / libinit.c
blob3cf2f435ec6e9a1a4d8b94154bdb1d11e552691f
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-2007 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 // transforms a define into a string
32 #define STR(x) STR2(x)
33 #define STR2(x) #x
35 /****************************************************************************/
37 #define MIN_STACKSIZE 65536
39 // stack cookie for shell v45+
40 static const char USED_VAR stack_size[] = "$STACK:" STR(MIN_STACKSIZE) "\n";
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 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(a0, BPTR Segment), REG(d0, struct LibraryHeader *lh), REG(a6, struct ExecBase *sb));
128 static BPTR LIBFUNC LibExpunge (REG(a6, struct LibraryHeader *base));
129 static struct LibraryHeader * LIBFUNC LibOpen (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 ULONG LibInitTab[] =
290 sizeof(struct LibraryHeader),
291 (ULONG)LibVectors,
292 (ULONG)NULL,
293 (ULONG)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 #else
310 RTF_AUTOINIT,
311 #endif
312 LIB_VERSION,
313 NT_LIBRARY,
315 (char *)UserLibName,
316 (char *)UserLibID+6, // +6 to skip '$VER: '
317 #if defined(__amigaos4__)
318 (APTR)libCreateTags // This table is for initializing the Library.
319 #else
320 (APTR)LibInitTab,
321 #endif
322 #if defined(__MORPHOS__)
323 LIB_REVISION,
325 #endif
328 #if defined(__MORPHOS__)
330 * To tell the loader that this is a new emulppc elf and not
331 * one for the ppc.library.
332 * ** IMPORTANT **
334 const USED_VAR ULONG __amigappc__ = 1;
335 const USED_VAR ULONG __abox__ = 1;
337 #endif /* __MORPHOS */
339 /****************************************************************************/
341 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
343 /* generic StackSwap() function which calls function() surrounded by
344 StackSwap() calls */
345 extern ULONG stackswap_call(struct StackSwapStruct *stack,
346 ULONG (*function)(struct LibraryHeader *),
347 struct LibraryHeader *arg);
349 #if defined(__mc68000__)
350 asm(".text \n\
351 .even \n\
352 .globl _stackswap_call \n\
353 _stackswap_call: \n\
354 moveml #0x3022,sp@- \n\
355 movel sp@(20),d3 \n\
356 movel sp@(24),a2 \n\
357 movel sp@(28),d2 \n\
358 movel _SysBase,a6 \n\
359 movel d3,a0 \n\
360 jsr a6@(-732:W) \n\
361 movel d2,sp@- \n\
362 jbsr a2@ \n\
363 movel d0,d2 \n\
364 addql #4,sp \n\
365 movel _SysBase,a6 \n\
366 movel d3,a0 \n\
367 jsr a6@(-732:W) \n\
368 movel d2,d0 \n\
369 moveml sp@+,#0x440c \n\
370 rts");
371 #elif !defined(__MORPHOS__)
372 ULONG stackswap_call(struct StackSwapStruct *stack,
373 ULONG (*function)(struct LibraryHeader *),
374 struct LibraryHeader *arg)
376 register ULONG result;
377 StackSwap(stack);
378 result = function(arg);
379 StackSwap(stack);
380 return result;
382 #endif
384 static BOOL callLibFunction(ULONG (*function)(struct LibraryHeader *), struct LibraryHeader *arg)
386 BOOL success = FALSE;
387 struct Task *tc;
388 ULONG stacksize;
390 // retrieve the task structure for the
391 // current task
392 tc = FindTask(NULL);
394 #if defined(__MORPHOS__)
395 // In MorphOS we have two stacks. One for PPC code and another for 68k code.
396 // We are only interested in the PPC stack.
397 NewGetTaskAttrsA(tc, &stacksize, sizeof(ULONG), TASKINFOTYPE_STACKSIZE, NULL);
398 #else
399 // on all other systems we query via SPUpper-SPLower calculation
400 stacksize = tc->tc_SPUpper - tc->tc_SPLower;
401 #endif
403 // Swap stacks only if current stack is insufficient
404 if(stacksize < MIN_STACKSIZE)
406 struct StackSwapStruct *stack;
408 if((stack = AllocVec(sizeof(*stack), MEMF_PUBLIC)) != NULL)
410 if((stack->stk_Lower = AllocVec(MIN_STACKSIZE, MEMF_PUBLIC)) != NULL)
412 #if defined(__MORPHOS__)
413 struct PPCStackSwapArgs swapargs;
414 #endif
416 // perform the StackSwap
417 stack->stk_Upper = (ULONG)stack->stk_Lower + MIN_STACKSIZE;
418 stack->stk_Pointer = (APTR)stack->stk_Upper;
420 // call routine but with embedding it into a [NewPPC]StackSwap()
421 #if defined(__MORPHOS__)
422 swapargs.Args[0] = (ULONG)arg;
423 success = NewPPCStackSwap(stack, function, &swapargs);
424 #else
425 success = stackswap_call(stack, function, arg);
426 #endif
428 FreeVec(stack->stk_Lower);
430 FreeVec(stack);
433 else
434 success = function(arg);
436 return success;
439 #endif // !__amigaos4__
441 /****************************************************************************/
443 #if defined(__amigaos4__)
444 static struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec)
446 struct ExecBase *sb = (struct ExecBase *)pIExec->Data.LibBase;
447 IExec = pIExec;
448 #elif defined(__MORPHOS__)
449 static struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb)
451 #else
452 static struct LibraryHeader * LIBFUNC LibInit(REG(a0, BPTR librarySegment), REG(d0, struct LibraryHeader *base), REG(a6, struct ExecBase *sb))
454 #endif
456 SysBase = (APTR)sb;
458 // make sure that this is really a 68020+ machine if optimized for 020+
459 #if _M68060 || _M68040 || _M68030 || _M68020 || __mc68020 || __mc68030 || __mc68040 || __mc68060
460 if(!(SysBase->AttnFlags & AFF_68020))
461 return(NULL);
462 #endif
464 #if defined(__amigaos4__) && defined(__NEWLIB__)
465 if((NewlibBase = OpenLibrary("newlib.library", 3)) &&
466 GETINTERFACE(INewlib, NewlibBase))
467 #endif
469 BOOL success = FALSE;
471 D(DBF_STARTUP, "LibInit()");
473 // cleanup the library header structure beginning with the
474 // library base.
475 base->libBase.lib_Node.ln_Type = NT_LIBRARY;
476 base->libBase.lib_Node.ln_Pri = 0;
477 base->libBase.lib_Node.ln_Name = (char *)UserLibName;
478 base->libBase.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
479 base->libBase.lib_Version = LIB_VERSION;
480 base->libBase.lib_Revision = LIB_REVISION;
481 base->libBase.lib_IdString = (char *)(UserLibID+6);
483 InitSemaphore(&base->libSem);
484 InitSemaphore(&base->poolSem);
486 base->sysBase = (APTR)SysBase;
487 base->pool = NULL;
488 base->flags = 0;
489 base->systemCodeset = NULL;
491 // protect access to initBase()
492 ObtainSemaphore(&base->libSem);
494 // set the CodesetsBase
495 CodesetsBase = base;
497 // If we are not running on AmigaOS4 (no stackswap required) we go and
498 // do an explicit StackSwap() in case the user wants to make sure we
499 // have enough stack for his user functions
500 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
501 success = callLibFunction(initBase, base);
502 #else
503 success = initBase(base);
504 #endif
506 // unprotect initBase()
507 ReleaseSemaphore(&base->libSem);
509 // check if everything worked out fine
510 if(success == TRUE)
512 // everything was successfully so lets
513 // set the initialized value and contiue
514 // with the class open phase
515 base->segList = librarySegment;
517 // return the library base as success
518 return base;
520 else
521 CodesetsBase = NULL;
523 #if defined(__amigaos4__) && defined(__NEWLIB__)
524 if(NewlibBase)
526 DROPINTERFACE(INewlib);
527 CloseLibrary(NewlibBase);
528 NewlibBase = NULL;
530 #endif
533 return(NULL);
536 /****************************************************************************/
538 #ifndef __amigaos4__
539 #define DeleteLibrary(LIB) \
540 FreeMem((STRPTR)(LIB)-(LIB)->lib_NegSize, (ULONG)((LIB)->lib_NegSize+(LIB)->lib_PosSize))
541 #endif
543 #if defined(__amigaos4__)
544 static BPTR LibExpunge(struct LibraryManagerInterface *Self)
546 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
547 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
548 #elif defined(__MORPHOS__)
549 static BPTR LibExpunge(void)
551 struct LibraryHeader *base = (struct LibraryHeader*)REG_A6;
552 #else
553 static BPTR LIBFUNC LibExpunge(REG(a6, struct LibraryHeader *base))
555 #endif
556 BPTR rc;
558 D(DBF_STARTUP, "LibExpunge(): %ld", base->libBase.lib_OpenCnt);
560 // in case our open counter is still > 0, we have
561 // to set the late expunge flag and return immediately
562 if(base->libBase.lib_OpenCnt > 0)
564 base->libBase.lib_Flags |= LIBF_DELEXP;
565 rc = 0;
567 else
569 // make sure to restore the SysBase
570 SysBase = (APTR)base->sysBase;
572 // remove the library base from exec's lib list in advance
573 Remove((struct Node *)base);
575 // free all our private data and stuff.
576 ObtainSemaphore(&base->libSem);
578 // make sure we have enough stack here
579 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
580 callLibFunction(freeBase, base);
581 #else
582 freeBase(base);
583 #endif
585 // unprotect
586 ReleaseSemaphore(&base->libSem);
588 #if defined(__amigaos4__) && defined(__NEWLIB__)
589 if(NewlibBase)
591 DROPINTERFACE(INewlib);
592 CloseLibrary(NewlibBase);
593 NewlibBase = NULL;
595 #endif
597 // make sure the system deletes the library as well.
598 rc = base->segList;
599 DeleteLibrary(&base->libBase);
602 return rc;
605 /****************************************************************************/
607 #if defined(__amigaos4__)
608 static struct LibraryHeader *LibOpen(struct LibraryManagerInterface *Self, ULONG version UNUSED)
610 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
611 #elif defined(__MORPHOS__)
612 static struct LibraryHeader *LibOpen(void)
614 struct LibraryHeader *base = (struct LibraryHeader*)REG_A6;
615 #else
616 static struct LibraryHeader * LIBFUNC LibOpen(REG(a6, struct LibraryHeader *base))
618 #endif
619 struct LibraryHeader *res = base;
621 D(DBF_STARTUP, "LibOpen(): %ld", base->libBase.lib_OpenCnt);
623 // LibOpen(), LibClose() and LibExpunge() are called while the system is in
624 // Forbid() state. That means that these functions should be quick and should
625 // not break this Forbid()!! Therefore the open counter should be increased
626 // as the very first instruction during LibOpen(), because a ClassOpen()
627 // which breaks a Forbid() and another task calling LibExpunge() will cause
628 // to expunge this library while it is not yet fully initialized. A crash
629 // is unavoidable then. Even the semaphore does not guarantee 100% protection
630 // against such a race condition, because waiting for the semaphore to be
631 // obtained will effectively break the Forbid()!
633 // increase the open counter ahead of anything else
634 base->libBase.lib_OpenCnt++;
636 // delete the late expunge flag
637 base->libBase.lib_Flags &= ~LIBF_DELEXP;
639 return res;
642 /****************************************************************************/
644 #if defined(__amigaos4__)
645 static BPTR LibClose(struct LibraryManagerInterface *Self)
647 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
648 #elif defined(__MORPHOS__)
649 static BPTR LibClose(void)
651 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
652 #else
653 static BPTR LIBFUNC LibClose(REG(a6, struct LibraryHeader *base))
655 #endif
656 BPTR rc = 0;
658 D(DBF_STARTUP, "LibClose(): %ld", base->libBase.lib_OpenCnt);
660 // decrease the open counter
661 base->libBase.lib_OpenCnt--;
663 // in case the opern counter is <= 0 we can
664 // make sure that we free everything
665 if(base->libBase.lib_OpenCnt <= 0)
667 // in case the late expunge flag is set we go and
668 // expunge the library base right now
669 if(base->libBase.lib_Flags & LIBF_DELEXP)
671 #if defined(__amigaos4__)
672 rc = LibExpunge(Self);
673 #elif defined(__MORPHOS__)
674 rc = LibExpunge();
675 #else
676 rc = LibExpunge(base);
677 #endif
679 return rc;
683 return rc;
686 /****************************************************************************/