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-2010 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/
19 ***************************************************************************/
24 #include <exec/resident.h>
25 #include <proto/exec.h>
30 /****************************************************************************/
33 * The system (and compiler) rely on a symbol named _start which marks
34 * the beginning of execution of an ELF file. To prevent others from
35 * executing this library, and to keep the compiler/linker happy, we
36 * define an empty _start symbol here.
38 * On the classic system (pre-AmigaOS4) this was usually done by
44 #if defined(__amigaos3__)
51 #elif defined(__AROS__)
52 __startup
int Main(void)
63 /****************************************************************************/
65 #if defined(__amigaos4__)
66 // stack cookie for shell v45+
67 static const char USED_VAR stack_size
[] = "$STACK:" STR(MIN_STACKSIZE
) "\n";
70 /****************************************************************************/
72 #if defined(__amigaos4__)
73 struct Library
*SysBase
= NULL
;
74 struct ExecIFace
* IExec
= NULL
;
75 #if defined(__NEWLIB__)
76 struct Library
*NewlibBase
= NULL
;
77 struct NewlibIFace
* INewlib
= NULL
;
80 struct ExecBase
*SysBase
= NULL
;
83 struct LibraryHeader
*OpenURLBase
= NULL
;
84 #if defined(__amigaos4__)
85 struct OpenURLIFace
*IOpenURL
= NULL
;
88 static const char UserLibName
[] = "openurl.library";
89 static const char UserLibID
[] = "$VER: openurl.library " LIB_REV_STRING
" [" SYSTEMSHORT
"/" CPU
"] (" LIB_DATE
") " LIB_COPYRIGHT
;
91 /****************************************************************************/
93 #define libvector LFUNC_FAS(URL_OpenA) \
95 LFUNC_FA_(URL_OldGetPrefs) \
96 LFUNC_FA_(URL_OldFreePrefs) \
97 LFUNC_FA_(URL_OldSetPrefs) \
98 LFUNC_FA_(URL_OldGetDefaultPrefs) \
99 LFUNC_FA_(URL_OldLaunchPrefsApp) \
100 LFUNC_FA_(dispatch) \
101 LFUNC_FA_(URL_GetPrefsA) \
102 LFUNC_VA_(URL_GetPrefs) \
103 LFUNC_FA_(URL_FreePrefsA) \
104 LFUNC_VA_(URL_FreePrefs) \
105 LFUNC_FA_(URL_SetPrefsA) \
106 LFUNC_VA_(URL_SetPrefs) \
107 LFUNC_FA_(URL_LaunchPrefsAppA) \
108 LFUNC_VA_(URL_LaunchPrefsApp) \
109 LFUNC_FA_(URL_GetAttr)
111 /****************************************************************************/
113 #if defined(__amigaos4__)
115 static struct LibraryHeader
* LIBFUNC
LibInit (struct LibraryHeader
*base
, BPTR librarySegment
, struct ExecIFace
*pIExec
);
116 static BPTR LIBFUNC
LibExpunge (struct LibraryManagerInterface
*Self
);
117 static struct LibraryHeader
* LIBFUNC
LibOpen (struct LibraryManagerInterface
*Self
, ULONG version
);
118 static BPTR LIBFUNC
LibClose (struct LibraryManagerInterface
*Self
);
119 //static LONG LIBFUNC LibNull (void);
121 #elif defined(__MORPHOS__)
123 static struct LibraryHeader
* LIBFUNC
LibInit (struct LibraryHeader
*base
, BPTR librarySegment
, struct ExecBase
*sb
);
124 static BPTR LIBFUNC
LibExpunge(void);
125 static struct LibraryHeader
* LIBFUNC
LibOpen (void);
126 static BPTR LIBFUNC
LibClose (void);
127 static LONG LIBFUNC
LibNull (void);
129 #elif defined(__AROS__)
131 #include <aros/libcall.h>
133 #define Openurl_LibOpen LibOpen
134 #define Openurl_LibClose LibClose
135 #define Openurl_LibExpunge LibExpunge
137 static AROS_UFP3 (struct LibraryHeader
*, LibInit
,
138 AROS_UFPA(struct LibraryHeader
*, base
, D0
),
139 AROS_UFPA(BPTR
, librarySegment
, A0
),
140 AROS_UFPA(struct ExecBase
*, sb
, A6
)
142 static AROS_LD1 (struct LibraryHeader
*, LibOpen
,
143 AROS_LPA (UNUSED ULONG
, version
, D0
),
144 struct LibraryHeader
*, base
, 1, Openurl
146 static AROS_LD0 (BPTR
, LibClose
,
147 struct LibraryHeader
*, base
, 2, Openurl
149 static AROS_LD1(BPTR
, LibExpunge
,
150 AROS_LPA(UNUSED
struct LibraryHeader
*, __extrabase
, D0
),
151 struct LibraryHeader
*, base
, 3, Openurl
156 static struct LibraryHeader
* LIBFUNC
LibInit (REG(d0
, struct LibraryHeader
*lh
), REG(a0
, BPTR Segment
), REG(a6
, struct ExecBase
*sb
));
157 static BPTR LIBFUNC
LibExpunge (REG(a6
, struct LibraryHeader
*base
));
158 static struct LibraryHeader
* LIBFUNC
LibOpen (REG(d0
, ULONG version
), REG(a6
, struct LibraryHeader
*base
));
159 static BPTR LIBFUNC
LibClose (REG(a6
, struct LibraryHeader
*base
));
160 static LONG LIBFUNC
LibNull (void);
164 /****************************************************************************/
166 #if !defined(__amigaos4__)
167 static LONG LIBFUNC
LibNull(VOID
)
173 /****************************************************************************/
175 #if defined(__amigaos4__)
176 /* ------------------- OS4 Manager Interface ------------------------ */
177 STATIC uint32
_manager_Obtain(struct LibraryManagerInterface
*Self
)
180 __asm__
__volatile__(
186 : "r" (&Self
->Data
.RefCount
)
192 STATIC uint32
_manager_Release(struct LibraryManagerInterface
*Self
)
195 __asm__
__volatile__(
201 : "r" (&Self
->Data
.RefCount
)
207 STATIC CONST CONST_APTR lib_manager_vectors
[] =
209 (CONST_APTR
)_manager_Obtain
,
210 (CONST_APTR
)_manager_Release
,
214 (CONST_APTR
)LibClose
,
215 (CONST_APTR
)LibExpunge
,
220 STATIC CONST
struct TagItem lib_managerTags
[] =
222 { MIT_Name
, (Tag
)"__library" },
223 { MIT_VectorTable
, (Tag
)lib_manager_vectors
},
228 /* ------------------- Library Interface(s) ------------------------ */
230 ULONG
LibObtain(UNUSED
struct Interface
*Self
)
235 ULONG
LibRelease(UNUSED
struct Interface
*Self
)
240 STATIC CONST CONST_APTR main_vectors
[] =
242 (CONST_APTR
)LibObtain
,
243 (CONST_APTR
)LibRelease
,
246 (CONST_APTR
)libvector
,
250 STATIC CONST
struct TagItem mainTags
[] =
252 { MIT_Name
, (Tag
)"main" },
253 { MIT_VectorTable
, (Tag
)main_vectors
},
258 STATIC CONST CONST_APTR libInterfaces
[] =
260 (CONST_APTR
)lib_managerTags
,
261 (CONST_APTR
)mainTags
,
265 // Our libraries always have to carry a 68k jump table with it, so
266 // lets define it here as extern, as we are going to link it to
268 #ifndef NO_VECTABLE68K
269 extern CONST APTR VecTable68K
[];
272 STATIC CONST
struct TagItem libCreateTags
[] =
274 { CLT_DataSize
, sizeof(struct LibraryHeader
) },
275 { CLT_InitFunc
, (Tag
)LibInit
},
276 { CLT_Interfaces
, (Tag
)libInterfaces
},
277 #ifndef NO_VECTABLE68K
278 { CLT_Vector68K
, (Tag
)VecTable68K
},
285 STATIC CONST CONST_APTR LibVectors
[] =
288 (CONST_APTR
)FUNCARRAY_32BIT_NATIVE
,
290 #if defined(__AROS__)
292 (CONST_APTR
)AROS_SLIB_ENTRY(LibOpen
, Openurl
, 1),
293 (CONST_APTR
)AROS_SLIB_ENTRY(LibClose
, Openurl
, 2),
294 (CONST_APTR
)AROS_SLIB_ENTRY(LibExpunge
, Openurl
, 3),
296 (CONST_APTR
)AROS_SLIB_ENTRY(LibOpen
, Openurl
),
297 (CONST_APTR
)AROS_SLIB_ENTRY(LibClose
, Openurl
),
298 (CONST_APTR
)AROS_SLIB_ENTRY(LibExpunge
, Openurl
),
302 (CONST_APTR
)LibClose
,
303 (CONST_APTR
)LibExpunge
,
306 (CONST_APTR
)libvector
,
310 STATIC CONST IPTR LibInitTab
[] =
312 sizeof(struct LibraryHeader
),
320 /****************************************************************************/
322 static const USED_VAR
struct Resident ROMTag
=
325 (struct Resident
*)&ROMTag
,
326 (struct Resident
*)(&ROMTag
+ 1),
327 #if defined(__amigaos4__)
328 RTF_AUTOINIT
|RTF_NATIVE
, // The Library should be set up according to the given table.
329 #elif defined(__MORPHOS__)
330 RTF_AUTOINIT
|RTF_EXTENDED
|RTF_PPC
,
331 #elif defined(__AROS__)
332 RTF_AUTOINIT
|RTF_EXTENDED
,
340 (char *)UserLibID
+6, // +6 to skip '$VER: '
341 #if defined(__amigaos4__)
342 (APTR
)libCreateTags
// This table is for initializing the Library.
346 #if defined(__MORPHOS__) || defined(__AROS__)
352 #if defined(__MORPHOS__)
354 * To tell the loader that this is a new emulppc elf and not
355 * one for the ppc.library.
358 const USED_VAR ULONG __abox__
= 1;
360 #endif /* __MORPHOS */
362 /****************************************************************************/
364 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
366 /* generic StackSwap() function which calls function() surrounded by
369 #if defined(__mc68000__)
370 ULONG
stackswap_call(struct StackSwapStruct
*stack
,
371 ULONG (*function
)(struct LibraryHeader
*),
372 struct LibraryHeader
*arg
);
376 .globl _stackswap_call \n\
378 moveml #0x3022,sp@- \n\
382 movel _SysBase,a6 \n\
389 movel _SysBase,a6 \n\
393 moveml sp@+,#0x440c \n\
395 #elif defined(__MORPHOS__)
396 ULONG
stackswap_call(struct StackSwapStruct
*stack
,
397 ULONG (*function
)(struct LibraryHeader
*),
398 struct LibraryHeader
*arg
)
400 struct PPCStackSwapArgs swapargs
;
402 swapargs
.Args
[0] = (ULONG
)arg
;
404 return NewPPCStackSwap(stack
, function
, &swapargs
);
406 #elif defined(__AROS__)
407 ULONG
stackswap_call(struct StackSwapStruct
*stack
,
408 ULONG (*function
)(struct LibraryHeader
*),
409 struct LibraryHeader
*arg
)
411 struct StackSwapArgs swapargs
;
413 swapargs
.Args
[0] = (IPTR
)arg
;
415 return NewStackSwap(stack
, function
, &swapargs
);
418 #error Bogus operating system
421 static BOOL
callLibFunction(ULONG (*function
)(struct LibraryHeader
*), struct LibraryHeader
*arg
)
423 BOOL success
= FALSE
;
427 // retrieve the task structure for the
431 #if defined(__MORPHOS__)
432 // In MorphOS we have two stacks. One for PPC code and another for 68k code.
433 // We are only interested in the PPC stack.
434 NewGetTaskAttrsA(tc
, &stacksize
, sizeof(ULONG
), TASKINFOTYPE_STACKSIZE
, NULL
);
436 // on all other systems we query via SPUpper-SPLower calculation
437 stacksize
= (UBYTE
*)tc
->tc_SPUpper
- (UBYTE
*)tc
->tc_SPLower
;
440 // Swap stacks only if current stack is insufficient
441 if(stacksize
< MIN_STACKSIZE
)
443 struct StackSwapStruct
*stack
;
445 if((stack
= AllocVec(sizeof(*stack
), MEMF_PUBLIC
)) != NULL
)
447 if((stack
->stk_Lower
= AllocVec(MIN_STACKSIZE
, MEMF_PUBLIC
)) != NULL
)
449 // perform the StackSwap
450 #if defined(__AROS__)
451 // AROS uses an APTR type for stk_Upper
452 stack
->stk_Upper
= (APTR
)((IPTR
)stack
->stk_Lower
+ MIN_STACKSIZE
);
454 // all other systems use ULONG
455 stack
->stk_Upper
= (ULONG
)stack
->stk_Lower
+ MIN_STACKSIZE
;
457 stack
->stk_Pointer
= (APTR
)stack
->stk_Upper
;
459 // call routine but with embedding it into a [NewPPC]StackSwap()
460 success
= stackswap_call(stack
, function
, arg
);
462 FreeVec(stack
->stk_Lower
);
468 success
= function(arg
);
472 #else // MIN_STACKSIZE && !__amigaos4__
473 #define callLibFunction(func, arg) func(arg)
474 #endif // MIN_STACKSIZE && !__amigaos4__
476 /****************************************************************************/
478 #if defined(__amigaos4__)
479 static struct LibraryHeader
* LibInit(struct LibraryHeader
*base
, BPTR librarySegment
, struct ExecIFace
*pIExec
)
481 struct ExecBase
*sb
= (struct ExecBase
*)pIExec
->Data
.LibBase
;
483 #elif defined(__MORPHOS__)
484 static struct LibraryHeader
* LibInit(struct LibraryHeader
*base
, BPTR librarySegment
, struct ExecBase
*sb
)
486 #elif defined(__AROS__)
487 static AROS_UFH3(struct LibraryHeader
*, LibInit
,
488 AROS_UFHA(struct LibraryHeader
*, base
, D0
),
489 AROS_UFHA(BPTR
, librarySegment
, A0
),
490 AROS_UFHA(struct ExecBase
*, sb
, A6
)
495 static struct LibraryHeader
* LIBFUNC
LibInit(REG(d0
, struct LibraryHeader
*base
), REG(a0
, BPTR librarySegment
), REG(a6
, struct ExecBase
*sb
))
501 // make sure that this is really a 68020+ machine if optimized for 020+
502 #if _M68060 || _M68040 || _M68030 || _M68020 || __mc68020 || __mc68030 || __mc68040 || __mc68060
503 if(isFlagClear(SysBase
->AttnFlags
, AFF_68020
))
507 #if defined(__amigaos4__) && defined(__NEWLIB__)
508 if((NewlibBase
= OpenLibrary("newlib.library", 3)) &&
509 GETINTERFACE(INewlib
, NewlibBase
))
512 BOOL success
= FALSE
;
514 D(DBF_STARTUP
, "LibInit()");
516 // cleanup the library header structure beginning with the
518 base
->libBase
.lib_Node
.ln_Type
= NT_LIBRARY
;
519 base
->libBase
.lib_Node
.ln_Pri
= 0;
520 base
->libBase
.lib_Node
.ln_Name
= (char *)UserLibName
;
521 base
->libBase
.lib_Flags
= LIBF_CHANGED
| LIBF_SUMUSED
;
522 base
->libBase
.lib_Version
= LIB_VERSION
;
523 base
->libBase
.lib_Revision
= LIB_REVISION
;
524 base
->libBase
.lib_IdString
= (char *)(UserLibID
+6);
526 memset(&base
->libSem
, 0, sizeof(base
->libSem
));
527 InitSemaphore(&base
->libSem
);
528 memset(&base
->poolSem
, 0, sizeof(base
->poolSem
));
529 InitSemaphore(&base
->poolSem
);
530 memset(&base
->prefsSem
, 0, sizeof(base
->prefsSem
));
531 InitSemaphore(&base
->prefsSem
);
533 base
->sysBase
= (APTR
)SysBase
;
539 // protect access to initBase()
540 ObtainSemaphore(&base
->libSem
);
542 // set the OpenURLBase
544 #if defined(__amigaos4__)
545 GETINTERFACE(IOpenURL
, OpenURLBase
);
548 // If we are not running on AmigaOS4 (no stackswap required) we go and
549 // do an explicit StackSwap() in case the user wants to make sure we
550 // have enough stack for his user functions
551 success
= callLibFunction(initBase
, base
);
553 // unprotect initBase()
554 ReleaseSemaphore(&base
->libSem
);
556 // check if everything worked out fine
559 // everything was successfully so lets
560 // set the initialized value and contiue
561 // with the class open phase
562 base
->segList
= librarySegment
;
564 // return the library base as success
569 callLibFunction(freeBase
, base
);
571 DROPINTERFACE(IOpenURL
);
574 #if defined(__amigaos4__) && defined(__NEWLIB__)
577 DROPINTERFACE(INewlib
);
578 CloseLibrary(NewlibBase
);
590 /****************************************************************************/
593 #define DeleteLibrary(LIB) \
594 FreeMem((STRPTR)(LIB)-(LIB)->lib_NegSize, (ULONG)((LIB)->lib_NegSize+(LIB)->lib_PosSize))
597 STATIC BPTR
LibDelete(struct LibraryHeader
*base
)
599 #if defined(__amigaos4__)
600 struct ExecIFace
*IExec
= (struct ExecIFace
*)(*(struct ExecBase
**)4)->MainInterface
;
604 // make sure to restore the SysBase
605 SysBase
= (APTR
)base
->sysBase
;
607 // remove the library base from exec's lib list in advance
608 Remove((struct Node
*)base
);
610 // free all our private data and stuff.
611 ObtainSemaphore(&base
->libSem
);
613 // make sure we have enough stack here
614 callLibFunction(freeBase
, base
);
617 ReleaseSemaphore(&base
->libSem
);
619 #if defined(__amigaos4__)
620 DROPINTERFACE(IOpenURL
);
625 #if defined(__amigaos4__) && defined(__NEWLIB__)
628 DROPINTERFACE(INewlib
);
629 CloseLibrary(NewlibBase
);
634 // make sure the system deletes the library as well.
636 DeleteLibrary(&base
->libBase
);
641 #if defined(__amigaos4__)
642 static BPTR
LibExpunge(struct LibraryManagerInterface
*Self
)
644 struct LibraryHeader
*base
= (struct LibraryHeader
*)Self
->Data
.LibBase
;
645 #elif defined(__MORPHOS__)
646 static BPTR
LibExpunge(void)
648 struct LibraryHeader
*base
= (struct LibraryHeader
*)REG_A6
;
649 #elif defined(__AROS__)
650 static AROS_LH1(BPTR
, LibExpunge
,
651 AROS_LHA(UNUSED
struct LibraryHeader
*, __extrabase
, D0
),
652 struct LibraryHeader
*, base
, 3, Openurl
657 static BPTR LIBFUNC
LibExpunge(REG(a6
, struct LibraryHeader
*base
))
662 D(DBF_STARTUP
, "LibExpunge(): %ld", base
->libBase
.lib_OpenCnt
);
664 // in case our open counter is still > 0, we have
665 // to set the late expunge flag and return immediately
666 if(base
->libBase
.lib_OpenCnt
> 0)
668 SET_FLAG(base
->libBase
.lib_Flags
, LIBF_DELEXP
);
673 rc
= LibDelete(base
);
682 /****************************************************************************/
684 #if defined(__amigaos4__)
685 static struct LibraryHeader
*LibOpen(struct LibraryManagerInterface
*Self
, ULONG version UNUSED
)
687 struct LibraryHeader
*base
= (struct LibraryHeader
*)Self
->Data
.LibBase
;
688 #elif defined(__MORPHOS__)
689 static struct LibraryHeader
*LibOpen(void)
691 struct LibraryHeader
*base
= (struct LibraryHeader
*)REG_A6
;
692 #elif defined(__AROS__)
693 static AROS_LH1(struct LibraryHeader
*, LibOpen
,
694 AROS_LHA(UNUSED ULONG
, version
, D0
),
695 struct LibraryHeader
*, base
, 1, Openurl
700 static struct LibraryHeader
* LIBFUNC
LibOpen(REG(d0
, UNUSED ULONG version
), REG(a6
, struct LibraryHeader
*base
))
703 struct LibraryHeader
*res
= base
;
705 D(DBF_STARTUP
, "LibOpen(): %ld", base
->libBase
.lib_OpenCnt
);
707 // LibOpen(), LibClose() and LibExpunge() are called while the system is in
708 // Forbid() state. That means that these functions should be quick and should
709 // not break this Forbid()!! Therefore the open counter should be increased
710 // as the very first instruction during LibOpen(), because a ClassOpen()
711 // which breaks a Forbid() and another task calling LibExpunge() will cause
712 // to expunge this library while it is not yet fully initialized. A crash
713 // is unavoidable then. Even the semaphore does not guarantee 100% protection
714 // against such a race condition, because waiting for the semaphore to be
715 // obtained will effectively break the Forbid()!
717 // increase the open counter ahead of anything else
718 base
->libBase
.lib_OpenCnt
++;
720 // delete the late expunge flag
721 CLEAR_FLAG(base
->libBase
.lib_Flags
, LIBF_DELEXP
);
729 /****************************************************************************/
731 #if defined(__amigaos4__)
732 static BPTR
LibClose(struct LibraryManagerInterface
*Self
)
734 struct LibraryHeader
*base
= (struct LibraryHeader
*)Self
->Data
.LibBase
;
735 #elif defined(__MORPHOS__)
736 static BPTR
LibClose(void)
738 struct LibraryHeader
*base
= (struct LibraryHeader
*)REG_A6
;
739 #elif defined(__AROS__)
740 static AROS_LH0(BPTR
, LibClose
,
741 struct LibraryHeader
*, base
, 2, Openurl
746 static BPTR LIBFUNC
LibClose(REG(a6
, struct LibraryHeader
*base
))
751 D(DBF_STARTUP
, "LibClose(): %ld", base
->libBase
.lib_OpenCnt
);
753 // decrease the open counter
754 base
->libBase
.lib_OpenCnt
--;
756 // in case the opern counter is <= 0 we can
757 // make sure that we free everything
758 if(base
->libBase
.lib_OpenCnt
<= 0)
760 // in case the late expunge flag is set we go and
761 // expunge the library base right now
762 if(isFlagSet(base
->libBase
.lib_Flags
, LIBF_DELEXP
))
764 rc
= LibDelete(base
);
774 /****************************************************************************/