define __KERNEL_STRICT_NAMES to avoid inclusion of kernel types on systems that carry...
[cake.git] / workbench / libs / openurl / library / libinit.c
blob78ae6ea477df00f9c7c562341659204824d555fb
1 /***************************************************************************
3 openurl.library - universal URL display and browser launcher library
4 Copyright (C) 1998-2005 by Troels Walsted Hansen, et al.
5 Copyright (C) 2005-2009 by openurl.library Open Source Team
7 This library is free software; it has been placed in the public domain
8 and you can freely redistribute it and/or modify it. Please note, however,
9 that some components may be under the LGPL or GPL license.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 openurl.library project: http://sourceforge.net/projects/openurllib/
17 $Id$
19 ***************************************************************************/
21 #include "lib.h"
22 #include "version.h"
24 #include <exec/resident.h>
25 #include <proto/exec.h>
27 #include "macros.h"
28 #include "debug.h"
30 /****************************************************************************/
32 #if !defined(__MORPHOS__)
33 #ifndef __AROS__
34 #define MIN_STACKSIZE 65536
35 #endif
37 // stack cookie for shell v45+
38 static const char USED_VAR stack_size[] = "$STACK:" STR(MIN_STACKSIZE) "\n";
39 #endif
41 /****************************************************************************/
43 #if defined(__amigaos4__)
44 struct Library *SysBase = NULL;
45 struct ExecIFace* IExec = NULL;
46 #if defined(__NEWLIB__)
47 struct Library *NewlibBase = NULL;
48 struct NewlibIFace* INewlib = NULL;
49 #endif
50 #else
51 struct ExecBase *SysBase = NULL;
52 #endif
54 struct LibraryHeader *OpenURLBase = NULL;
56 static const char UserLibName[] = "openurl.library";
57 static const char UserLibID[] = "$VER: openurl.library " LIB_REV_STRING " [" SYSTEMSHORT "/" CPU "] (" LIB_DATE ") " LIB_COPYRIGHT;
59 /****************************************************************************/
61 #define libvector LFUNC_FAS(URL_OpenA) \
62 LFUNC_VA_(URL_Open) \
63 LFUNC_FA_(URL_OldGetPrefs) \
64 LFUNC_FA_(URL_OldFreePrefs) \
65 LFUNC_FA_(URL_OldSetPrefs) \
66 LFUNC_FA_(URL_OldGetDefaultPrefs) \
67 LFUNC_FA_(URL_OldLaunchPrefsApp) \
68 LFUNC_FA_(dispatch) \
69 LFUNC_FA_(URL_GetPrefsA) \
70 LFUNC_VA_(URL_GetPrefs) \
71 LFUNC_FA_(URL_FreePrefsA) \
72 LFUNC_VA_(URL_FreePrefs) \
73 LFUNC_FA_(URL_SetPrefsA) \
74 LFUNC_VA_(URL_SetPrefs) \
75 LFUNC_FA_(URL_LaunchPrefsAppA) \
76 LFUNC_VA_(URL_LaunchPrefsApp) \
77 LFUNC_FA_(URL_GetAttr)
79 /****************************************************************************/
81 #if defined(__amigaos4__)
83 static struct LibraryHeader * LIBFUNC LibInit (struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec);
84 static BPTR LIBFUNC LibExpunge (struct LibraryManagerInterface *Self);
85 static struct LibraryHeader * LIBFUNC LibOpen (struct LibraryManagerInterface *Self, ULONG version);
86 static BPTR LIBFUNC LibClose (struct LibraryManagerInterface *Self);
87 //static LONG LIBFUNC LibNull (void);
89 #elif defined(__MORPHOS__)
91 static struct LibraryHeader * LIBFUNC LibInit (struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb);
92 static BPTR LIBFUNC LibExpunge(void);
93 static struct LibraryHeader * LIBFUNC LibOpen (void);
94 static BPTR LIBFUNC LibClose (void);
95 static LONG LIBFUNC LibNull (void);
97 #else
99 static struct LibraryHeader * LIBFUNC LibInit (REG(d0, struct LibraryHeader *lh), REG(a0, BPTR Segment), REG(a6, struct ExecBase *sb));
100 static BPTR LIBFUNC LibExpunge (REG(a6, struct LibraryHeader *base));
101 static struct LibraryHeader * LIBFUNC LibOpen (REG(d0, ULONG version), REG(a6, struct LibraryHeader *base));
102 static BPTR LIBFUNC LibClose (REG(a6, struct LibraryHeader *base));
103 static LONG LIBFUNC LibNull (void);
105 #endif
107 /****************************************************************************/
110 * The system (and compiler) rely on a symbol named _start which marks
111 * the beginning of execution of an ELF file. To prevent others from
112 * executing this library, and to keep the compiler/linker happy, we
113 * define an empty _start symbol here.
115 * On the classic system (pre-AmigaOS4) this was usually done by
116 * moveq #0,d0
117 * rts
121 #if defined(__amigaos4__)
122 int _start(void)
123 #else
124 int Main(void)
125 #endif
127 return RETURN_FAIL;
130 #if !defined(__amigaos4__)
131 static LONG LIBFUNC LibNull(VOID)
133 return(0);
135 #endif
137 /****************************************************************************/
139 #if defined(__amigaos4__)
140 /* ------------------- OS4 Manager Interface ------------------------ */
141 STATIC uint32 _manager_Obtain(struct LibraryManagerInterface *Self)
143 uint32 res;
144 __asm__ __volatile__(
145 "1: lwarx %0,0,%1\n"
146 "addic %0,%0,1\n"
147 "stwcx. %0,0,%1\n"
148 "bne- 1b"
149 : "=&r" (res)
150 : "r" (&Self->Data.RefCount)
151 : "cc", "memory");
153 return res;
156 STATIC uint32 _manager_Release(struct LibraryManagerInterface *Self)
158 uint32 res;
159 __asm__ __volatile__(
160 "1: lwarx %0,0,%1\n"
161 "addic %0,%0,-1\n"
162 "stwcx. %0,0,%1\n"
163 "bne- 1b"
164 : "=&r" (res)
165 : "r" (&Self->Data.RefCount)
166 : "cc", "memory");
168 return res;
171 STATIC CONST CONST_APTR lib_manager_vectors[] =
173 (CONST_APTR)_manager_Obtain,
174 (CONST_APTR)_manager_Release,
175 (CONST_APTR)NULL,
176 (CONST_APTR)NULL,
177 (CONST_APTR)LibOpen,
178 (CONST_APTR)LibClose,
179 (CONST_APTR)LibExpunge,
180 (CONST_APTR)NULL,
181 (CONST_APTR)-1
184 STATIC CONST struct TagItem lib_managerTags[] =
186 { MIT_Name, (Tag)"__library" },
187 { MIT_VectorTable, (Tag)lib_manager_vectors },
188 { MIT_Version, 1 },
189 { TAG_DONE, 0 }
192 /* ------------------- Library Interface(s) ------------------------ */
194 ULONG LibObtain(UNUSED struct Interface *Self)
196 return 0;
199 ULONG LibRelease(UNUSED struct Interface *Self)
201 return 0;
204 STATIC CONST CONST_APTR main_vectors[] =
206 (CONST_APTR)LibObtain,
207 (CONST_APTR)LibRelease,
208 (CONST_APTR)NULL,
209 (CONST_APTR)NULL,
210 (CONST_APTR)libvector,
211 (CONST_APTR)-1
214 STATIC CONST struct TagItem mainTags[] =
216 { MIT_Name, (Tag)"main" },
217 { MIT_VectorTable, (Tag)main_vectors },
218 { MIT_Version, 1 },
219 { TAG_DONE, 0 }
222 STATIC CONST CONST_APTR libInterfaces[] =
224 (CONST_APTR)lib_managerTags,
225 (CONST_APTR)mainTags,
226 (CONST_APTR)NULL
229 // Our libraries always have to carry a 68k jump table with it, so
230 // lets define it here as extern, as we are going to link it to
231 // our binary here.
232 #ifndef NO_VECTABLE68K
233 extern CONST APTR VecTable68K[];
234 #endif
236 STATIC CONST struct TagItem libCreateTags[] =
238 { CLT_DataSize, sizeof(struct LibraryHeader) },
239 { CLT_InitFunc, (Tag)LibInit },
240 { CLT_Interfaces, (Tag)libInterfaces },
241 #ifndef NO_VECTABLE68K
242 { CLT_Vector68K, (Tag)VecTable68K },
243 #endif
244 { TAG_DONE, 0 }
247 #else
249 STATIC CONST CONST_APTR LibVectors[] =
251 #ifdef __MORPHOS__
252 (CONST_APTR)FUNCARRAY_32BIT_NATIVE,
253 #endif
254 (CONST_APTR)LibOpen,
255 (CONST_APTR)LibClose,
256 (CONST_APTR)LibExpunge,
257 (CONST_APTR)LibNull,
258 (CONST_APTR)libvector,
259 (CONST_APTR)-1
262 STATIC CONST IPTR LibInitTab[] =
264 sizeof(struct LibraryHeader),
265 (IPTR)LibVectors,
266 (IPTR)NULL,
267 (IPTR)LibInit
270 #endif
272 /****************************************************************************/
274 static const USED_VAR struct Resident ROMTag =
276 RTC_MATCHWORD,
277 (struct Resident *)&ROMTag,
278 (struct Resident *)(&ROMTag + 1),
279 #if defined(__amigaos4__)
280 RTF_AUTOINIT|RTF_NATIVE, // The Library should be set up according to the given table.
281 #elif defined(__MORPHOS__)
282 RTF_AUTOINIT|RTF_EXTENDED|RTF_PPC,
283 #elif defined(__AROS__)
284 RTF_AUTOINIT|RTF_EXTENDED,
285 #else
286 RTF_AUTOINIT,
287 #endif
288 LIB_VERSION,
289 NT_LIBRARY,
291 (char *)UserLibName,
292 (char *)UserLibID+6, // +6 to skip '$VER: '
293 #if defined(__amigaos4__)
294 (APTR)libCreateTags // This table is for initializing the Library.
295 #else
296 (APTR)LibInitTab,
297 #endif
298 #if defined(__MORPHOS__) || defined(__AROS__)
299 LIB_REVISION,
301 #endif
304 #if defined(__MORPHOS__)
306 * To tell the loader that this is a new emulppc elf and not
307 * one for the ppc.library.
308 * ** IMPORTANT **
310 const USED_VAR ULONG __abox__ = 1;
312 #endif /* __MORPHOS */
314 /****************************************************************************/
316 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
318 /* generic StackSwap() function which calls function() surrounded by
319 StackSwap() calls */
321 #if defined(__mc68000__)
322 ULONG stackswap_call(struct StackSwapStruct *stack,
323 ULONG (*function)(struct LibraryHeader *),
324 struct LibraryHeader *arg);
326 asm(".text \n\
327 .even \n\
328 .globl _stackswap_call \n\
329 _stackswap_call: \n\
330 moveml #0x3022,sp@- \n\
331 movel sp@(20),d3 \n\
332 movel sp@(24),a2 \n\
333 movel sp@(28),d2 \n\
334 movel _SysBase,a6 \n\
335 movel d3,a0 \n\
336 jsr a6@(-732:W) \n\
337 movel d2,sp@- \n\
338 jbsr a2@ \n\
339 movel d0,d2 \n\
340 addql #4,sp \n\
341 movel _SysBase,a6 \n\
342 movel d3,a0 \n\
343 jsr a6@(-732:W) \n\
344 movel d2,d0 \n\
345 moveml sp@+,#0x440c \n\
346 rts");
347 #elif defined(__MORPHOS__)
348 ULONG stackswap_call(struct StackSwapStruct *stack,
349 ULONG (*function)(struct LibraryHeader *),
350 struct LibraryHeader *arg)
352 struct PPCStackSwapArgs swapargs;
354 swapargs.Args[0] = (ULONG)arg;
356 return NewPPCStackSwap(stack, function, &swapargs);
358 #else
359 /* FIXME: This does not work because it can't work. 'arg' variable is also on stack.
360 On AmigaOS v4 it ocassionally works because function's parameters are placed
361 in registers on PPC */
362 ULONG REGARGS stackswap_call(struct StackSwapStruct *stack,
363 ULONG (*function)(struct LibraryHeader *),
364 struct LibraryHeader *arg)
366 register ULONG result;
368 StackSwap(stack);
369 result = function(arg);
370 StackSwap(stack);
372 return result;
374 #endif
376 static BOOL callLibFunction(ULONG (*function)(struct LibraryHeader *), struct LibraryHeader *arg)
378 BOOL success = FALSE;
379 struct Task *tc;
380 ULONG stacksize;
382 // retrieve the task structure for the
383 // current task
384 tc = FindTask(NULL);
386 #if defined(__MORPHOS__)
387 // In MorphOS we have two stacks. One for PPC code and another for 68k code.
388 // We are only interested in the PPC stack.
389 NewGetTaskAttrsA(tc, &stacksize, sizeof(ULONG), TASKINFOTYPE_STACKSIZE, NULL);
390 #else
391 // on all other systems we query via SPUpper-SPLower calculation
392 stacksize = (ULONG)tc->tc_SPUpper - (ULONG)tc->tc_SPLower;
393 #endif
395 // Swap stacks only if current stack is insufficient
396 if(stacksize < MIN_STACKSIZE)
398 struct StackSwapStruct *stack;
400 if((stack = AllocVec(sizeof(*stack), MEMF_PUBLIC)) != NULL)
402 if((stack->stk_Lower = AllocVec(MIN_STACKSIZE, MEMF_PUBLIC)) != NULL)
404 // perform the StackSwap
405 stack->stk_Upper = (ULONG)stack->stk_Lower + MIN_STACKSIZE;
406 stack->stk_Pointer = (APTR)stack->stk_Upper;
408 // call routine but with embedding it into a [NewPPC]StackSwap()
409 success = stackswap_call(stack, function, arg);
411 FreeVec(stack->stk_Lower);
413 FreeVec(stack);
416 else
417 success = function(arg);
419 return success;
422 #endif // !__amigaos4__
424 /****************************************************************************/
426 #if defined(__amigaos4__)
427 static struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec)
429 struct ExecBase *sb = (struct ExecBase *)pIExec->Data.LibBase;
430 IExec = pIExec;
431 #elif defined(__MORPHOS__)
432 static struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb)
434 #else
435 static struct LibraryHeader * LIBFUNC LibInit(REG(d0, struct LibraryHeader *base), REG(a0, BPTR librarySegment), REG(a6, struct ExecBase *sb))
437 #endif
439 SysBase = (APTR)sb;
441 // make sure that this is really a 68020+ machine if optimized for 020+
442 #if _M68060 || _M68040 || _M68030 || _M68020 || __mc68020 || __mc68030 || __mc68040 || __mc68060
443 if(isFlagClear(SysBase->AttnFlags, AFF_68020))
444 return(NULL);
445 #endif
447 #if defined(__amigaos4__) && defined(__NEWLIB__)
448 if((NewlibBase = OpenLibrary("newlib.library", 3)) &&
449 GETINTERFACE(INewlib, NewlibBase))
450 #endif
452 BOOL success = FALSE;
454 D(DBF_STARTUP, "LibInit()");
456 // cleanup the library header structure beginning with the
457 // library base.
458 base->libBase.lib_Node.ln_Type = NT_LIBRARY;
459 base->libBase.lib_Node.ln_Pri = 0;
460 base->libBase.lib_Node.ln_Name = (char *)UserLibName;
461 base->libBase.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
462 base->libBase.lib_Version = LIB_VERSION;
463 base->libBase.lib_Revision = LIB_REVISION;
464 base->libBase.lib_IdString = (char *)(UserLibID+6);
466 InitSemaphore(&base->libSem);
467 InitSemaphore(&base->poolSem);
468 InitSemaphore(&base->prefsSem);
470 base->sysBase = (APTR)SysBase;
471 base->pool = NULL;
472 base->prefs = NULL;
473 base->flags = 0;
474 base->rexx_use = 0;
476 // protect access to initBase()
477 ObtainSemaphore(&base->libSem);
479 // set the OpenURLBase
480 OpenURLBase = base;
482 // If we are not running on AmigaOS4 (no stackswap required) we go and
483 // do an explicit StackSwap() in case the user wants to make sure we
484 // have enough stack for his user functions
485 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
486 success = callLibFunction(initBase, base);
487 #else
488 success = initBase(base);
489 #endif
491 // unprotect initBase()
492 ReleaseSemaphore(&base->libSem);
494 // check if everything worked out fine
495 if(success == TRUE)
497 // everything was successfully so lets
498 // set the initialized value and contiue
499 // with the class open phase
500 base->segList = librarySegment;
502 // return the library base as success
503 return base;
505 else
506 OpenURLBase = NULL;
508 #if defined(__amigaos4__) && defined(__NEWLIB__)
509 if(NewlibBase)
511 DROPINTERFACE(INewlib);
512 CloseLibrary(NewlibBase);
513 NewlibBase = NULL;
515 #endif
518 return NULL;
521 /****************************************************************************/
523 #ifndef __amigaos4__
524 #define DeleteLibrary(LIB) \
525 FreeMem((STRPTR)(LIB)-(LIB)->lib_NegSize, (ULONG)((LIB)->lib_NegSize+(LIB)->lib_PosSize))
526 #endif
528 #if defined(__amigaos4__)
529 static BPTR LibExpunge(struct LibraryManagerInterface *Self)
531 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
532 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
533 #elif defined(__MORPHOS__)
534 static BPTR LibExpunge(void)
536 struct LibraryHeader *base = (struct LibraryHeader*)REG_A6;
537 #else
538 static BPTR LIBFUNC LibExpunge(REG(a6, struct LibraryHeader *base))
540 #endif
541 BPTR rc;
543 D(DBF_STARTUP, "LibExpunge(): %ld", base->libBase.lib_OpenCnt);
545 // in case our open counter is still > 0, we have
546 // to set the late expunge flag and return immediately
547 if(base->libBase.lib_OpenCnt > 0)
549 SET_FLAG(base->libBase.lib_Flags, LIBF_DELEXP);
550 rc = 0;
552 else
554 // make sure to restore the SysBase
555 SysBase = (APTR)base->sysBase;
557 // remove the library base from exec's lib list in advance
558 Remove((struct Node *)base);
560 // free all our private data and stuff.
561 ObtainSemaphore(&base->libSem);
563 // make sure we have enough stack here
564 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
565 callLibFunction(freeBase, base);
566 #else
567 freeBase(base);
568 #endif
570 // unprotect
571 ReleaseSemaphore(&base->libSem);
573 #if defined(__amigaos4__) && defined(__NEWLIB__)
574 if(NewlibBase)
576 DROPINTERFACE(INewlib);
577 CloseLibrary(NewlibBase);
578 NewlibBase = NULL;
580 #endif
582 // make sure the system deletes the library as well.
583 rc = base->segList;
584 DeleteLibrary(&base->libBase);
587 return rc;
590 /****************************************************************************/
592 #if defined(__amigaos4__)
593 static struct LibraryHeader *LibOpen(struct LibraryManagerInterface *Self, ULONG version UNUSED)
595 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
596 #elif defined(__MORPHOS__)
597 static struct LibraryHeader *LibOpen(void)
599 struct LibraryHeader *base = (struct LibraryHeader*)REG_A6;
600 #else
601 static struct LibraryHeader * LIBFUNC LibOpen(REG(d0, UNUSED ULONG version), REG(a6, struct LibraryHeader *base))
603 #endif
604 struct LibraryHeader *res = base;
606 D(DBF_STARTUP, "LibOpen(): %ld", base->libBase.lib_OpenCnt);
608 // LibOpen(), LibClose() and LibExpunge() are called while the system is in
609 // Forbid() state. That means that these functions should be quick and should
610 // not break this Forbid()!! Therefore the open counter should be increased
611 // as the very first instruction during LibOpen(), because a ClassOpen()
612 // which breaks a Forbid() and another task calling LibExpunge() will cause
613 // to expunge this library while it is not yet fully initialized. A crash
614 // is unavoidable then. Even the semaphore does not guarantee 100% protection
615 // against such a race condition, because waiting for the semaphore to be
616 // obtained will effectively break the Forbid()!
618 // increase the open counter ahead of anything else
619 base->libBase.lib_OpenCnt++;
621 // delete the late expunge flag
622 CLEAR_FLAG(base->libBase.lib_Flags, LIBF_DELEXP);
624 return res;
627 /****************************************************************************/
629 #if defined(__amigaos4__)
630 static BPTR LibClose(struct LibraryManagerInterface *Self)
632 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
633 #elif defined(__MORPHOS__)
634 static BPTR LibClose(void)
636 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
637 #else
638 static BPTR LIBFUNC LibClose(REG(a6, struct LibraryHeader *base))
640 #endif
641 BPTR rc = 0;
643 D(DBF_STARTUP, "LibClose(): %ld", base->libBase.lib_OpenCnt);
645 // decrease the open counter
646 base->libBase.lib_OpenCnt--;
648 // in case the opern counter is <= 0 we can
649 // make sure that we free everything
650 if(base->libBase.lib_OpenCnt <= 0)
652 // in case the late expunge flag is set we go and
653 // expunge the library base right now
654 if(isFlagSet(base->libBase.lib_Flags, LIBF_DELEXP))
656 #if defined(__amigaos4__)
657 rc = LibExpunge(Self);
658 #elif defined(__MORPHOS__)
659 rc = LibExpunge();
660 #else
661 rc = LibExpunge(base);
662 #endif
666 return rc;
669 /****************************************************************************/