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-2014 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/
21 ***************************************************************************/
26 #include <exec/resident.h>
27 #include <proto/exec.h>
31 /****************************************************************************/
34 * The system (and compiler) rely on a symbol named _start which marks
35 * the beginning of execution of an ELF file. To prevent others from
36 * executing this library, and to keep the compiler/linker happy, we
37 * define an empty _start symbol here.
39 * On the classic system (pre-AmigaOS4) this was usually done by
45 #if defined(__amigaos3__)
52 #elif defined(__AROS__)
53 __startup
int Main(void)
64 /****************************************************************************/
66 #define MIN_STACKSIZE 65536
68 #if defined(__amigaos4__)
69 // stack cookie for shell v45+
70 static const char USED_VAR stack_size
[] = "$STACK:" STR(MIN_STACKSIZE
) "\n";
73 /****************************************************************************/
75 #if defined(__amigaos4__)
76 struct Library
*SysBase
= NULL
;
77 struct ExecIFace
* IExec
= NULL
;
78 #if defined(__NEWLIB__)
79 struct Library
*NewlibBase
= NULL
;
80 struct NewlibIFace
* INewlib
= NULL
;
83 struct ExecBase
*SysBase
= NULL
;
86 struct LibraryHeader
*CodesetsBase
= NULL
;
87 #if defined(__amigaos4__)
88 struct CodesetsIFace
*ICodesets
= NULL
;
91 static const char UserLibName
[] = "codesets.library";
92 static const char UserLibID
[] = "$VER: codesets.library " LIB_REV_STRING
" [" SYSTEMSHORT
"/" CPU
"] (" LIB_DATE
") " LIB_COPYRIGHT
;
94 /****************************************************************************/
96 #define libvector LibNull \
97 LFUNC_FA_(CodesetsConvertUTF32toUTF16) \
98 LFUNC_FA_(CodesetsConvertUTF16toUTF32) \
99 LFUNC_FA_(CodesetsConvertUTF16toUTF8) \
100 LFUNC_FA_(CodesetsIsLegalUTF8) \
101 LFUNC_FA_(CodesetsIsLegalUTF8Sequence) \
102 LFUNC_FA_(CodesetsConvertUTF8toUTF16) \
103 LFUNC_FA_(CodesetsConvertUTF32toUTF8) \
104 LFUNC_FA_(CodesetsConvertUTF8toUTF32) \
105 LFUNC_FA_(CodesetsSetDefaultA) \
106 LFUNC_VA_(CodesetsSetDefault) \
107 LFUNC_FA_(CodesetsFreeA) \
108 LFUNC_VA_(CodesetsFree) \
109 LFUNC_FA_(CodesetsSupportedA) \
110 LFUNC_VA_(CodesetsSupported) \
111 LFUNC_FA_(CodesetsFindA) \
112 LFUNC_VA_(CodesetsFind) \
113 LFUNC_FA_(CodesetsFindBestA) \
114 LFUNC_VA_(CodesetsFindBest) \
115 LFUNC_FA_(CodesetsUTF8Len) \
116 LFUNC_FA_(CodesetsUTF8ToStrA) \
117 LFUNC_VA_(CodesetsUTF8ToStr) \
118 LFUNC_FA_(CodesetsUTF8CreateA) \
119 LFUNC_VA_(CodesetsUTF8Create) \
120 LFUNC_FA_(CodesetsEncodeB64A) \
121 LFUNC_VA_(CodesetsEncodeB64) \
122 LFUNC_FA_(CodesetsDecodeB64A) \
123 LFUNC_VA_(CodesetsDecodeB64) \
124 LFUNC_FA_(CodesetsStrLenA) \
125 LFUNC_VA_(CodesetsStrLen) \
126 LFUNC_FA_(CodesetsIsValidUTF8) \
127 LFUNC_FA_(CodesetsFreeVecPooledA) \
128 LFUNC_VA_(CodesetsFreeVecPooled) \
129 LFUNC_FA_(CodesetsConvertStrA) \
130 LFUNC_VA_(CodesetsConvertStr) \
131 LFUNC_FA_(CodesetsListCreateA) \
132 LFUNC_VA_(CodesetsListCreate) \
133 LFUNC_FA_(CodesetsListDeleteA) \
134 LFUNC_VA_(CodesetsListDelete) \
135 LFUNC_FA_(CodesetsListAddA) \
136 LFUNC_VA_(CodesetsListAdd) \
137 LFUNC_FA_(CodesetsListRemoveA) \
138 LFUNC_VA_(CodesetsListRemove)
141 /****************************************************************************/
143 #if defined(__amigaos4__)
145 static struct LibraryHeader
* LIBFUNC
LibInit (struct LibraryHeader
*base
, BPTR librarySegment
, struct ExecIFace
*pIExec
);
146 static BPTR LIBFUNC
LibExpunge (struct LibraryManagerInterface
*Self
);
147 static struct LibraryHeader
* LIBFUNC
LibOpen (struct LibraryManagerInterface
*Self
, ULONG version
);
148 static BPTR LIBFUNC
LibClose (struct LibraryManagerInterface
*Self
);
149 static LONG LIBFUNC
LibNull (void);
151 #elif defined(__MORPHOS__)
153 static struct LibraryHeader
* LIBFUNC
LibInit (struct LibraryHeader
*base
, BPTR librarySegment
, struct ExecBase
*sb
);
154 static BPTR LIBFUNC
LibExpunge(void);
155 static struct LibraryHeader
* LIBFUNC
LibOpen (void);
156 static BPTR LIBFUNC
LibClose (void);
157 static LONG LIBFUNC
LibNull (void);
159 #elif defined(__AROS__)
161 #include <aros/libcall.h>
163 #define Codesets_LibOpen LibOpen
164 #define Codesets_LibClose LibClose
165 #define Codesets_LibExpunge LibExpunge
167 static AROS_UFP3 (struct LibraryHeader
*, LibInit
,
168 AROS_UFPA(struct LibraryHeader
*, base
, D0
),
169 AROS_UFPA(BPTR
, librarySegment
, A0
),
170 AROS_UFPA(struct ExecBase
*, sb
, A6
)
172 static AROS_LD1 (struct LibraryHeader
*, LibOpen
,
173 AROS_LPA (UNUSED ULONG
, version
, D0
),
174 struct LibraryHeader
*, base
, 1, Codesets
176 static AROS_LD0 (BPTR
, LibClose
,
177 struct LibraryHeader
*, base
, 2, Codesets
179 static AROS_LD1(BPTR
, LibExpunge
,
180 AROS_LPA(UNUSED
struct LibraryHeader
*, __extrabase
, D0
),
181 struct LibraryHeader
*, base
, 3, Codesets
186 static struct LibraryHeader
* LIBFUNC
LibInit (REG(d0
, struct LibraryHeader
*lh
), REG(a0
, BPTR Segment
), REG(a6
, struct ExecBase
*sb
));
187 static BPTR LIBFUNC
LibExpunge (REG(a6
, struct LibraryHeader
*base
));
188 static struct LibraryHeader
* LIBFUNC
LibOpen (REG(d0
, ULONG version
), REG(a6
, struct LibraryHeader
*base
));
189 static BPTR LIBFUNC
LibClose (REG(a6
, struct LibraryHeader
*base
));
190 static LONG LIBFUNC
LibNull (void);
194 /****************************************************************************/
196 static LONG LIBFUNC
LibNull(VOID
)
201 /****************************************************************************/
203 #if defined(__amigaos4__)
204 /* ------------------- OS4 Manager Interface ------------------------ */
205 STATIC uint32
_manager_Obtain(struct LibraryManagerInterface
*Self
)
208 __asm__
__volatile__(
214 : "r" (&Self
->Data
.RefCount
)
220 STATIC uint32
_manager_Release(struct LibraryManagerInterface
*Self
)
223 __asm__
__volatile__(
229 : "r" (&Self
->Data
.RefCount
)
235 STATIC CONST CONST_APTR lib_manager_vectors
[] =
237 (CONST_APTR
)_manager_Obtain
,
238 (CONST_APTR
)_manager_Release
,
242 (CONST_APTR
)LibClose
,
243 (CONST_APTR
)LibExpunge
,
248 STATIC CONST
struct TagItem lib_managerTags
[] =
250 { MIT_Name
, (Tag
)"__library" },
251 { MIT_VectorTable
, (Tag
)lib_manager_vectors
},
256 /* ------------------- Library Interface(s) ------------------------ */
258 ULONG
LibObtain(UNUSED
struct Interface
*Self
)
263 ULONG
LibRelease(UNUSED
struct Interface
*Self
)
268 STATIC CONST CONST_APTR main_vectors
[] =
270 (CONST_APTR
)LibObtain
,
271 (CONST_APTR
)LibRelease
,
274 (CONST_APTR
)libvector
,
278 STATIC CONST
struct TagItem mainTags
[] =
280 { MIT_Name
, (Tag
)"main" },
281 { MIT_VectorTable
, (Tag
)main_vectors
},
286 STATIC CONST CONST_APTR libInterfaces
[] =
288 (CONST_APTR
)lib_managerTags
,
289 (CONST_APTR
)mainTags
,
293 // Our libraries always have to carry a 68k jump table with it, so
294 // lets define it here as extern, as we are going to link it to
296 #ifndef NO_VECTABLE68K
297 extern CONST APTR VecTable68K
[];
300 STATIC CONST
struct TagItem libCreateTags
[] =
302 { CLT_DataSize
, sizeof(struct LibraryHeader
) },
303 { CLT_InitFunc
, (Tag
)LibInit
},
304 { CLT_Interfaces
, (Tag
)libInterfaces
},
305 #ifndef NO_VECTABLE68K
306 { CLT_Vector68K
, (Tag
)VecTable68K
},
313 STATIC CONST CONST_APTR LibVectors
[] =
316 (CONST_APTR
)FUNCARRAY_32BIT_NATIVE
,
318 #if defined(__AROS__)
320 (CONST_APTR
)AROS_SLIB_ENTRY(LibOpen
, Codesets
, 1),
321 (CONST_APTR
)AROS_SLIB_ENTRY(LibClose
, Codesets
, 2),
322 (CONST_APTR
)AROS_SLIB_ENTRY(LibExpunge
, Codesets
, 3),
324 (CONST_APTR
)AROS_SLIB_ENTRY(LibOpen
, Codesets
),
325 (CONST_APTR
)AROS_SLIB_ENTRY(LibClose
, Codesets
),
326 (CONST_APTR
)AROS_SLIB_ENTRY(LibExpunge
, Codesets
),
330 (CONST_APTR
)LibClose
,
331 (CONST_APTR
)LibExpunge
,
334 (CONST_APTR
)libvector
,
338 STATIC CONST IPTR LibInitTab
[] =
340 sizeof(struct LibraryHeader
),
348 /****************************************************************************/
350 static const USED_VAR
struct Resident ROMTag
=
353 (struct Resident
*)&ROMTag
,
354 (struct Resident
*)(&ROMTag
+ 1),
355 #if defined(__amigaos4__)
356 RTF_AUTOINIT
|RTF_NATIVE
, // The Library should be set up according to the given table.
357 #elif defined(__MORPHOS__)
358 RTF_AUTOINIT
|RTF_EXTENDED
|RTF_PPC
,
359 #elif defined(__AROS__)
360 RTF_AUTOINIT
|RTF_EXTENDED
,
368 (char *)UserLibID
+6, // +6 to skip '$VER: '
369 #if defined(__amigaos4__)
370 (APTR
)libCreateTags
// This table is for initializing the Library.
374 #if defined(__MORPHOS__) || defined(__AROS__)
380 #if defined(__MORPHOS__)
382 * To tell the loader that this is a new emulppc elf and not
383 * one for the ppc.library.
386 const USED_VAR ULONG __abox__
= 1;
388 #endif /* __MORPHOS */
390 /****************************************************************************/
392 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
394 /* generic StackSwap() function which calls function() surrounded by
397 #if defined(__mc68000__) && !defined(__AROS__)
398 ULONG
stackswap_call(struct StackSwapStruct
*stack
,
399 ULONG (*function
)(struct LibraryHeader
*),
400 struct LibraryHeader
*arg
);
404 .globl _stackswap_call \n\
406 moveml #0x3022,sp@- \n\
410 movel _SysBase,a6 \n\
417 movel _SysBase,a6 \n\
421 moveml sp@+,#0x440c \n\
423 #elif defined(__MORPHOS__)
424 ULONG
stackswap_call(struct StackSwapStruct
*stack
,
425 ULONG (*function
)(struct LibraryHeader
*),
426 struct LibraryHeader
*arg
)
428 struct PPCStackSwapArgs swapargs
;
430 swapargs
.Args
[0] = (ULONG
)arg
;
432 return NewPPCStackSwap(stack
, function
, &swapargs
);
434 #elif defined(__AROS__)
435 ULONG
stackswap_call(struct StackSwapStruct
*stack
,
436 ULONG (*function
)(struct LibraryHeader
*),
437 struct LibraryHeader
*arg
)
439 struct StackSwapArgs swapargs
;
441 swapargs
.Args
[0] = (IPTR
)arg
;
443 return NewStackSwap(stack
, function
, &swapargs
);
446 #error Bogus operating system
449 static BOOL
callLibFunction(ULONG (*function
)(struct LibraryHeader
*), struct LibraryHeader
*arg
)
451 BOOL success
= FALSE
;
455 // retrieve the task structure for the
459 #if defined(__MORPHOS__)
460 // In MorphOS we have two stacks. One for PPC code and another for 68k code.
461 // We are only interested in the PPC stack.
462 NewGetTaskAttrsA(tc
, &stacksize
, sizeof(ULONG
), TASKINFOTYPE_STACKSIZE
, NULL
);
464 // on all other systems we query via SPUpper-SPLower calculation
465 stacksize
= (UBYTE
*)tc
->tc_SPUpper
- (UBYTE
*)tc
->tc_SPLower
;
468 // Swap stacks only if current stack is insufficient
469 if(stacksize
< MIN_STACKSIZE
)
471 struct StackSwapStruct
*stack
;
473 if((stack
= AllocVec(sizeof(*stack
), MEMF_PUBLIC
)) != NULL
)
475 if((stack
->stk_Lower
= AllocVec(MIN_STACKSIZE
, MEMF_PUBLIC
)) != NULL
)
477 // perform the StackSwap
478 #if defined(__AROS__)
479 // AROS uses an APTR type for stk_Upper
480 stack
->stk_Upper
= (APTR
)((IPTR
)stack
->stk_Lower
+ MIN_STACKSIZE
);
482 // all other systems use ULONG
483 stack
->stk_Upper
= (ULONG
)stack
->stk_Lower
+ MIN_STACKSIZE
;
485 stack
->stk_Pointer
= (APTR
)stack
->stk_Upper
;
487 // call routine but with embedding it into a [NewPPC]StackSwap()
488 success
= stackswap_call(stack
, function
, arg
);
490 FreeVec(stack
->stk_Lower
);
496 success
= function(arg
);
500 #else // MIN_STACKSIZE && !__amigaos4__
501 #define callLibFunction(func, arg) func(arg)
502 #endif // MIN_STACKSIZE && !__amigaos4__
504 /****************************************************************************/
506 #if defined(__amigaos4__)
507 static struct LibraryHeader
* LibInit(struct LibraryHeader
*base
, BPTR librarySegment
, struct ExecIFace
*pIExec
)
509 struct ExecBase
*sb
= (struct ExecBase
*)pIExec
->Data
.LibBase
;
511 #elif defined(__MORPHOS__)
512 static struct LibraryHeader
* LibInit(struct LibraryHeader
*base
, BPTR librarySegment
, struct ExecBase
*sb
)
514 #elif defined(__AROS__)
515 static AROS_UFH3(struct LibraryHeader
*, LibInit
,
516 AROS_UFHA(struct LibraryHeader
*, base
, D0
),
517 AROS_UFHA(BPTR
, librarySegment
, A0
),
518 AROS_UFHA(struct ExecBase
*, sb
, A6
)
523 static struct LibraryHeader
* LIBFUNC
LibInit(REG(d0
, struct LibraryHeader
*base
), REG(a0
, BPTR librarySegment
), REG(a6
, struct ExecBase
*sb
))
529 // make sure that this is really a 68020+ machine if optimized for 020+
530 #if _M68060 || _M68040 || _M68030 || _M68020 || __mc68020 || __mc68030 || __mc68040 || __mc68060
531 if(!(SysBase
->AttnFlags
& AFF_68020
))
535 #if defined(__amigaos4__) && defined(__NEWLIB__)
536 if((NewlibBase
= OpenLibrary("newlib.library", 3)) &&
537 GETINTERFACE(INewlib
, NewlibBase
))
540 BOOL success
= FALSE
;
543 // this must be called ahead of any debug output, otherwise we get stuck
546 D(DBF_STARTUP
, "LibInit()");
548 // cleanup the library header structure beginning with the
550 base
->libBase
.lib_Node
.ln_Type
= NT_LIBRARY
;
551 base
->libBase
.lib_Node
.ln_Pri
= 0;
552 base
->libBase
.lib_Node
.ln_Name
= (char *)UserLibName
;
553 base
->libBase
.lib_Flags
= LIBF_CHANGED
| LIBF_SUMUSED
;
554 base
->libBase
.lib_Version
= LIB_VERSION
;
555 base
->libBase
.lib_Revision
= LIB_REVISION
;
556 base
->libBase
.lib_IdString
= (char *)(UserLibID
+6);
558 memset(&base
->libSem
, 0, sizeof(base
->libSem
));
559 InitSemaphore(&base
->libSem
);
560 memset(&base
->poolSem
, 0, sizeof(base
->poolSem
));
561 InitSemaphore(&base
->poolSem
);
563 base
->sysBase
= (APTR
)SysBase
;
566 base
->systemCodeset
= NULL
;
568 // protect access to initBase()
569 ObtainSemaphore(&base
->libSem
);
571 // set the CodesetsBase
573 #if defined(__amigaos4__)
574 GETINTERFACE(ICodesets
, CodesetsBase
);
577 // If we are not running on AmigaOS4 (no stackswap required) we go and
578 // do an explicit StackSwap() in case the user wants to make sure we
579 // have enough stack for his user functions
580 success
= callLibFunction(initBase
, base
);
582 // unprotect initBase()
583 ReleaseSemaphore(&base
->libSem
);
585 // check if everything worked out fine
588 // everything was successfully so lets
589 // set the initialized value and contiue
590 // with the class open phase
591 base
->segList
= librarySegment
;
593 // return the library base as success
598 callLibFunction(freeBase
, base
);
600 DROPINTERFACE(ICodesets
);
603 #if defined(__amigaos4__) && defined(__NEWLIB__)
606 DROPINTERFACE(INewlib
);
607 CloseLibrary(NewlibBase
);
619 /****************************************************************************/
622 #define DeleteLibrary(LIB) \
623 FreeMem((STRPTR)(LIB)-(LIB)->lib_NegSize, (ULONG)((LIB)->lib_NegSize+(LIB)->lib_PosSize))
626 STATIC BPTR
LibDelete(struct LibraryHeader
*base
)
628 #if defined(__amigaos4__)
629 struct ExecIFace
*IExec
= (struct ExecIFace
*)(*(struct ExecBase
**)4)->MainInterface
;
633 // make sure to restore the SysBase
634 SysBase
= (APTR
)base
->sysBase
;
636 // remove the library base from exec's lib list in advance
637 Remove((struct Node
*)base
);
639 // free all our private data and stuff.
640 ObtainSemaphore(&base
->libSem
);
642 // make sure we have enough stack here
643 callLibFunction(freeBase
, base
);
646 ReleaseSemaphore(&base
->libSem
);
648 #if defined(__amigaos4__)
649 DROPINTERFACE(ICodesets
);
654 #if defined(__amigaos4__) && defined(__NEWLIB__)
657 DROPINTERFACE(INewlib
);
658 CloseLibrary(NewlibBase
);
663 // make sure the system deletes the library as well.
665 DeleteLibrary(&base
->libBase
);
670 #if defined(__amigaos4__)
671 static BPTR
LibExpunge(struct LibraryManagerInterface
*Self
)
673 struct LibraryHeader
*base
= (struct LibraryHeader
*)Self
->Data
.LibBase
;
674 #elif defined(__MORPHOS__)
675 static BPTR
LibExpunge(void)
677 struct LibraryHeader
*base
= (struct LibraryHeader
*)REG_A6
;
678 #elif defined(__AROS__)
679 static AROS_LH1(BPTR
, LibExpunge
,
680 AROS_LHA(UNUSED
struct LibraryHeader
*, __extrabase
, D0
),
681 struct LibraryHeader
*, base
, 3, Codesets
686 static BPTR LIBFUNC
LibExpunge(REG(a6
, struct LibraryHeader
*base
))
691 D(DBF_STARTUP
, "LibExpunge(): %ld", base
->libBase
.lib_OpenCnt
);
693 // in case our open counter is still > 0, we have
694 // to set the late expunge flag and return immediately
695 if(base
->libBase
.lib_OpenCnt
> 0)
697 base
->libBase
.lib_Flags
|= LIBF_DELEXP
;
702 rc
= LibDelete(base
);
711 /****************************************************************************/
713 #if defined(__amigaos4__)
714 static struct LibraryHeader
*LibOpen(struct LibraryManagerInterface
*Self
, ULONG version UNUSED
)
716 struct LibraryHeader
*base
= (struct LibraryHeader
*)Self
->Data
.LibBase
;
717 #elif defined(__MORPHOS__)
718 static struct LibraryHeader
*LibOpen(void)
720 struct LibraryHeader
*base
= (struct LibraryHeader
*)REG_A6
;
721 #elif defined(__AROS__)
722 static AROS_LH1(struct LibraryHeader
*, LibOpen
,
723 AROS_LHA(UNUSED ULONG
, version
, D0
),
724 struct LibraryHeader
*, base
, 1, Codesets
729 static struct LibraryHeader
* LIBFUNC
LibOpen(REG(d0
, UNUSED ULONG version
), REG(a6
, struct LibraryHeader
*base
))
732 struct LibraryHeader
*res
= base
;
734 D(DBF_STARTUP
, "LibOpen(): %ld", base
->libBase
.lib_OpenCnt
);
736 // LibOpen(), LibClose() and LibExpunge() are called while the system is in
737 // Forbid() state. That means that these functions should be quick and should
738 // not break this Forbid()!! Therefore the open counter should be increased
739 // as the very first instruction during LibOpen(), because a ClassOpen()
740 // which breaks a Forbid() and another task calling LibExpunge() will cause
741 // to expunge this library while it is not yet fully initialized. A crash
742 // is unavoidable then. Even the semaphore does not guarantee 100% protection
743 // against such a race condition, because waiting for the semaphore to be
744 // obtained will effectively break the Forbid()!
746 // increase the open counter ahead of anything else
747 base
->libBase
.lib_OpenCnt
++;
749 // delete the late expunge flag
750 base
->libBase
.lib_Flags
&= ~LIBF_DELEXP
;
758 /****************************************************************************/
760 #if defined(__amigaos4__)
761 static BPTR
LibClose(struct LibraryManagerInterface
*Self
)
763 struct LibraryHeader
*base
= (struct LibraryHeader
*)Self
->Data
.LibBase
;
764 #elif defined(__MORPHOS__)
765 static BPTR
LibClose(void)
767 struct LibraryHeader
*base
= (struct LibraryHeader
*)REG_A6
;
768 #elif defined(__AROS__)
769 static AROS_LH0(BPTR
, LibClose
,
770 struct LibraryHeader
*, base
, 2, Codesets
775 static BPTR LIBFUNC
LibClose(REG(a6
, struct LibraryHeader
*base
))
780 D(DBF_STARTUP
, "LibClose(): %ld", base
->libBase
.lib_OpenCnt
);
782 // decrease the open counter
783 base
->libBase
.lib_OpenCnt
--;
785 // in case the opern counter is <= 0 we can
786 // make sure that we free everything
787 if(base
->libBase
.lib_OpenCnt
<= 0)
789 // in case the late expunge flag is set we go and
790 // expunge the library base right now
791 if(base
->libBase
.lib_Flags
& LIBF_DELEXP
)
793 rc
= LibDelete(base
);
803 /****************************************************************************/