[comp.sys.amiga] Updated EXAMPLE LIBRARY source

dillon@CORY.BERKELEY.EDU (Matt Dillon) (10/17/87)

	Here is a revised working sample library for Aztec C.  It fixes a
bug and now uses MakeLibrary() instead of a hardwired library.

				-Matt


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Makefile
#	README
#	hlib.asm
#	test.c
#	testlib.c
# This archive created: Sat Oct 17 11:38:41 1987
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Makefile'" '(623 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'

#   You must modify SYMBOLS to some temporary directory if you do not
#   already have a complete precompiled symbol table (*/*.h .. only
#   sub-directory includes, not top level includes).  Remember to
#   use +L when generating the precompiled symbol table.

SYMBOLS= vd0:include/symbols.m

all: lib test

lib:
    cc +BCDL +p +I$(SYMBOLS) testlib.c -o ram:testlib.o
    ln +Q ram:testlib.o -lcl32
    copy ram:testlib libs:testlib.library
    delete ram:testlib ram:testlib.o

test:
    cc +L +I$(SYMBOLS) test.c -o ram:test.o
    as hlib.asm -o ram:hlib.o
    ln +Q ram:test.o ram:hlib.o -lc32
    delete ram:test.o

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'README'" '(2522 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \!Funky!Stuff! > 'README'


	Working Library Skeleton for AZTEC C.

	By Matthew Dillon

	Placed in Public Domain


	This is an example library for Aztec C.  It will not work with
Lattice C due to extensive Manxisms.   This library does not use the
auto-init method and thus provides a contrast with the RKM example.  Note
especially the compile time options required (in the Makefile).  Here are
the reasons:

	+B	No reference to startup code.

	+CD	Large code and data model.  Alternately you can setup A4
		on every entry point and use the small code and data model.

	+L	32 bit integers.  My preference.. not required when
		designing your own libraries, of course.  Required for 
		this particular example, however.

	+p	compatibility option... Aztec automagically saves D2 and D3
		on function calls.  Otherwise we would have to do it by hand
		on every entry point.  This also sets +L automatically.


LINK LIBRARY:

	The routines in this example expect arguments on the stack.   You
	will note the link library is incredibly simple ... the assembly
	to make a library call is only two instructions.  Note that since the
	arguments are expected on the stack, the link library routines cannot
	save anything on the stack.  A0-A1 D0-D1 are scratch however and I
	simply use A0.

	Thus this library is optimized for C->C calls.	You want your library
	to follow the AMIGA STANDARD, which is that only A0-A1 D0-D1 may be
	trashed.  The only register Aztec C calls will not automatically
	save is A6 and this must be done WITHIN your actual library routines
	(see testlib.c).

FILES:

	Makefile

		For making the library itself.	I make reference to a
		precompiled symbol table which is all the AMIGA includes
		(none of the Aztec includes) */*.h . That is, all the
		include files in sub-directories but none of the
		top-level include files.  You will have to either generate
		such a symbol table yourself or simply figure out which
		#include's you need to make.  If generating the symbol
		table yourself, remember to use the +L option.

	hlib.asm

		Example 'link' library... what you need to link with your
		C programs to be able to call library functions after openning
		the library and sticking the library base into the proper
		global variable.

	testlib.c

		The source to the library itself.

	test.c

		The source to the test program.  Must be linked with
		hlib.o	.  Without arguments, the library is openned, the
		routines executed, then closed.  With arguments,  the
		program does an expunge (via allocating too much memory).

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'hlib.asm'" '(216 characters)'
if test -f 'hlib.asm'
then
	echo shar: "will not over-write existing file 'hlib.asm'"
else
cat << \!Funky!Stuff! > 'hlib.asm'


	    ;	TestBase

	    FAR code
	    FAR data

	    public  _TestBase
	    public  _Sub
	    public  _Add

_Sub:	    move.l  _TestBase,A0
	    jmp     -36(A0)

_Add:	    move.l  _TestBase,A0
	    jmp     -30(A0)



!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'test.c'" '(668 characters)'
if test -f 'test.c'
then
	echo shar: "will not over-write existing file 'test.c'"
else
cat << \!Funky!Stuff! > 'test.c'

/*
 *  Test the library
 */

long TestBase;

extern long OpenLibrary();
extern void *AllocMem();
extern long Add(), Sub();

main(ac,av)
char *av[];
{
    if (ac != 1) {
	register long i = 256000;
	register char *ptr;
	puts("Expunging by allocating too much memory");
	while (ptr = AllocMem(i,0)) {
	    FreeMem(ptr,i);
	    i <<= 1;
	}
	puts("ok");
	exit(1);
    }

    TestBase = OpenLibrary("testlib.library",0);
    if (TestBase) {
	printf("Open OK %08xl\n", TestBase);
	printf("ADD 1 -> %ld (should be 2)\n", Add(1L));
	printf("SUB 33-> %ld (should be 32)\n", Sub(33L));
	CloseLibrary(TestBase);
	puts("Close OK");
    } else {
	puts("Unable to Open");
    }
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'testlib.c'" '(5596 characters)'
if test -f 'testlib.c'
then
	echo shar: "will not over-write existing file 'testlib.c'"
else
cat << \!Funky!Stuff! > 'testlib.c'

/*
 *  TESTLIB.C
 *
 *  Example fully working library for Aztec C ... with comments (which is
 *  a miracle in itself).   By Matthew Dillon.	PUBLIC DOMAIN.
 *
 *  Aztec Compile with +BCDL
 *	    +B	No startup reference
 *	    +C	Large code
 *	    +D	Large data
 *	    +L	32 bit Integers
 *
 *  Since Original release, the following has been fixed:
 *	-slight bug in LibClose() .. did not expunge library if DELEXP set
 *	 on final close.  (thanks to Rico Mariani for finding the bug)
 *	-Now uses MakeLibrary call rather than a hardwired Library structure.
 */

#asm
	;   RLIB.ASM
	;
	;   Run-time library tag

	    FAR     code
	    FAR     data

	    public  _CInit
	    public  _LibOpen
	    public  _LibClose
	    public  _LibExpunge

Start:	    clr.l   D0
	    rts

InitDesc:   dc.w    $4AFC	;RTC_MATCHWORD
	    dc.l    InitDesc	;Pointer to beginning
	    dc.l    EndCode	;Note sure it matters
	    dc.b    0		;flags (NO RTF_AUTOINIT)
	    dc.b    0		;version
	    dc.b    9		;NT_LIBRARY
	    dc.b    0		;priority (doesn't matter)
	    dc.l    _Libname	;Name of library
	    dc.l    _Libid	;ID string (note CR-LF at end)
	    dc.l    Init	;Pointer to init routine

_Libname:   dc.b    "testlib.library",0
_Libid:     dc.b    "testlib.library 1.0 (02 Oct 1987)",13,10,0
EndCode:

Init:	    move.l  A6,-(sp)	;Must save A6
	    move.l  A0,-(sp)	;Segment list
	    jsr     _CInit
	    addq.l  #4,sp
	    move.l  (sp)+,A6
	    rts

cifc	    macro
	    move.l  D0,-(sp)	;Make a C call and save A6 to boot
	    move.l  A6,-(sp)
	    jsr     \1
	    move.l  (sp)+,A6
	    addq.l  #4,sp
	    rts
	    endm

_ALibOpen:	cifc	_LibOpen
_ALibClose:	cifc	_LibClose
_ALibExpunge:	cifc	_LibExpunge

#endasm

extern char Libname[1];
extern char Libid[1];

extern long ALibExpunge(), ALibClose(), ALibOpen();
extern long Lib_Add(), Lib_Sub();

typedef struct Library LIB;

LIB  *Lib;			/*  Library Base pointer    */
long Seglist;			/*  Save the DOS seglist    */

extern LIB *MakeLibrary();
extern void *AllocMem();

/*
 *    The Initialization routine is given only a seglist pointer.  Since
 *    we are NOT AUTOINIT we must construct and add the library ourselves
 *    and return either NULL or the library pointer.  Exec has Forbid()
 *    for us during the call.
 *
 *    If you have an extended library structure you must specify the size
 *    of the extended structure in MakeLibrary().
 */

LIB *
CInit(segment)
{
    extern long SysBase;
    static long (*Vectors[])() = {
	ALibOpen,ALibClose,ALibExpunge,NULL,
	Lib_Add, Lib_Sub, (long (*)())-1
    };

    SysBase = *(long *)4;
    Lib = MakeLibrary(Vectors,NULL,NULL,sizeof(LIB),NULL);
    Lib->lib_Node.ln_Type = NT_LIBRARY;
    Lib->lib_Node.ln_Name = Libname;
    Lib->lib_Flags = LIBF_CHANGED|LIBF_SUMUSED;
    Lib->lib_Version  = 0;
    Lib->lib_Revision = 0;
    Lib->lib_IdString = (APTR)Libid;
    Seglist = segment;
    AddLibrary(Lib);
    return(Lib);
}

/*
 *    Open is given the library pointer and the version request.  Either
 *    return the library pointer or NULL.  Remove the DELAYED-EXPUNGE flag.
 *    Exec has Forbid() for us during the call.
 */

LIB *
LibOpen(lib,version)
LIB *lib;
{
    ++lib->lib_OpenCnt;
    lib->lib_Flags &= ~LIBF_DELEXP;
    return(lib);
}

/*
 *    Close is given the library pointer and the version request.  Be sure
 *    not to decrement the open count if already zero.	If the open count
 *    is or becomes zero AND there is a LIBF_DELEXP, we expunge the library
 *    and return the seglist.  Otherwise we return NULL.
 *
 *    Note that this routine never sets LIBF_DELEXP on its own.
 *
 *    Exec has Forbid() for us during the call.
 */

LibClose(lib)
LIB *lib;
{
    if (lib->lib_OpenCnt && --lib->lib_OpenCnt)
	return(NULL);
    if (lib->lib_Flags & LIBF_DELEXP)
	return(LibExpunge(lib));
    return(NULL);
}

/*
 *    We expunge the library and return the Seglist ONLY if the open count
 *    is zero.	If the open count is not zero we set the DELAYED-EXPUNGE
 *    flag and return NULL.
 *
 *    Exec has Forbid() for us during the call.  NOTE ALSO that Expunge
 *    might be called from the memory allocator and thus we CANNOT DO A
 *    Wait() or otherwise take a long time to complete (straight from RKM).
 *
 *    Apparently RemLibrary(lib) calls our expunge routine and would
 *    therefore freeze if we called it ourselves.  As far as I can tell
 *    from RKM, LibExpunge(lib) must remove the library itself as shown
 *    below.
 */

LibExpunge(lib)
LIB *lib;
{
    if (lib->lib_OpenCnt) {
	lib->lib_Flags |= LIBF_DELEXP;
	return(NULL);
    }
    Remove(lib);
    FreeMem((char *)lib-lib->lib_NegSize, lib->lib_NegSize+lib->lib_PosSize);
    return(Seglist);
}

/*
 *  The Library routines themselves.  Note that we must also save A6 if
 *  any library routine makes a library call to another library.  These
 *  examples do not and thus you can remove the #asm statements in them if
 *  you wish... just DON'T FORGET!
 *
 *  The reason A6 must be saved is that Aztec library interface routines
 *  (e.g. FindTask(), OpenWindow(), etc....) trash A6 on purpose to make
 *  the interface routine faster.
 *
 *  D2 and D3 are automatically saved/restored via the +p compile option
 *  A0,A1,D0,D1 are always scratch.  In an assembly interface, these might
 *  also contain arguments... but they are still scratch.
 */

Lib_Add(n)
{
#asm
    move.l A6,-(sp)
#endasm

    ++n; /* do stuff here */

#asm
    move.l (sp)+,A6
#endasm
    return(n);
}

Lib_Sub(n)
{
#asm
    move.l A6,-(sp)
#endasm

    --n; /* do stuff here */

#asm
    move.l (sp)+,A6
#endasm
    return(n);
}


!Funky!Stuff!
fi  # end of overwriting check
exit 0
#	End of shell archive