[comp.sys.amiga] A shared library

jmsynge@sqm.dec.com.UUCP (05/29/87)

	Here is the source for a shared library which is written
in C with a little bit of assembly glue.  It is very heavily commented,
so it should be easy for others to produce shared libraries by simply
editing this version.  The library, task.library, contains versions of
CreateTask and DeleteTask.

	I developed this library after having examined every example
that Amiga produced and reading and re-reading the RKM.  I have copyrighted
this code because it is not simply a paraphrase of previous works, nor
a simple rearrangement.  It contains substantial addtions which significantly
improve the library.  I'm not a lawyer, so I don't know all the regulations
about copyrights, but I hope I've stated the case correctly.

	This code may be redistributed for non-commercial purposes.  If you
wish to sell this library for a profit, contact me.  My purpose is to spread
the knowledge of how shared libraries work and how to build them.

	Have fun gang!

James Synge

USENET:  {decvax, ucbvax, allegra}!decwrl!sqm.dec.com!jmsynge
ARPAnet: jmsynge%sqm.DEC@decwrl.DEC.COM
USmail:  12 Newcastle Dr, #12, Nashua, NH, 03060

#include <disclaimer.h>
"Ken Olsen can speak for Digital, not me!"

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	LibHead.asm
#	Library.c
#	ExtLibrary.h
#	Task_Routines.c
#	FunctionList.c
#	Interface.asm
#	Protect.i
#	2Tasks.c
#	task_lib.asm
#	Makefile
# This archive created: Wed May 27 23:46:09 1987
echo shar: extracting LibHead.asm
cat << \SHAR_EOF > LibHead.asm
;; LibHead.asm
;;		Copyright 1986, James M Synge
;;
;; This file contains the data structures and an
;; initialization routine.
;;
	far	code	; Absolute addresses please.
	far	data	; Me too!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; To protect against the library accidentally being invoked
;; as a program, we return an error value.  This code must
;; be the first thing in the library.

	cseg		; Code segment
	moveq.l	#20,d0	; AmigaDOS Fatal Error
	rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Declaration Section:
;;
;; Imported Global Variables and Constants:

	dseg			; Data segment

	public	_LibraryName	; char * LibraryName
	public	_LibraryId	; char * LibraryId

	public	LibVersion	; Current version number.
				; Will be checked by
				; OpenLibrary() against the
				; requested version number.

	public	_LibInitBlock	; Defined in Library.c

	public	_SysBase	; Library Base Pointer for
				; exec.library

;; Exported Global Variables:

	global	_LibraryBase,4	; Address of this library.

	global	_LibSegList,4	; Address of first entry in
				; this library's seg list.
;; Imported Functions:

	cseg

	public	_LibraryInit	; This is the routine which
				; handles most of the
				; details of preparing the
				; library, except for regs.
;; Exported Functions:

	public	__LibInitCode	; Referenced by LibInitBlock
				; in Library.c

	public	_regA6		; Returns register A6.

;; Constants:
;; (These should be set in the Amiga supplied include files
;;  but these aren't available for Manx 3.2a)

RTC_MATCHWORD	EQU	$4afc	; An illegal instruction
RTF_AUTOINIT	EQU	(1 << 7)
NT_LIBRARY	EQU	9	; As defined in exec/nodes.i

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Resident (RomTag) Structure
;; This structure must be in the first hunk (AmigaDOS Hunk)
;; of the library.  Defined in "exec/resident.h"

RomTag:
	DC.W	RTC_MATCHWORD	; This value is an illegal
				; instruction.  It is used
				; to mark the beginning of a
				; rom tag.  The next
				; longword confirms it.

	DC.L	RomTag		; The RomTag points to
				; itself as confirmation
				; that this is a RomTag.

	DC.L	EndMarker	; The address of a location
				; after this structure, but
				; still in the same hunk.
				; The simplest solution is
				; to place the label right
				; after this structure.

	DC.B	RTF_AUTOINIT	; Auto-initialize flag, see
				; Library.c for description

	DC.B	LibVersion	; Library version, will be
				; checked against the value
				; requested in the
				; OpenLibrary() call.

	DC.B	NT_LIBRARY	; This is the Resident
				; struct of a library.

	DC.B	0		; Execution priority.
				; Not used in libraries.

	DC.L	_LibraryName	; Pointer to library name.

	DC.L	_LibraryId	; Pointer to full library id

	DC.L	_LibInitBlock	; Pointer to initialization
				; descriptor block or code.
				; See Library.c
;;	End of the RomTag

EndMarker	; Simplest place for this marker

; See Interface.asm for a complete explanation of:
AztecBugList:	reg	a4/a6

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; LibInitCode, is called from within MakeLibrary(), after
;; all the memory has been allocated, the jump table has
;; been constructed, and the InitStruct() call has been
;; made.  It is identified as the initialization code by
;; LibInitBlock in Library.c.  LibraryInit() returns the
;; value (in D0 as per the calling standard) which is then
;; returned to MakeLibrary().  If it is zero, the library
;; wouldn't be added to the exec's library list and thus
;; cann't be opened.

__LibInitCode:
	move.l	a6,_SysBase	; Store away these three
				; registers which tell us
	move.l	d0,_LibraryBase	; we are and where the rest
	move.l	a0,_LibSegList	; of the world can be found.

	; Forgive me, Oh Lord, for I have sinned...
	movem.l	AztecBugList,-(sp)

	; Now call the C routine LibraryInit() with the
	; address of our Library struct as its only argument.

	move.l	d0,-(sp)	; Push LibraryBase
	jsr	_LibraryInit	; Call
	addq.l	#4,sp		; Pop LibraryBase

	; Restore the registers
	movem.l	(sp)+,AztecBugList

	rts			; Now return to our caller.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; This trite little routine is included so that those
;; library specific routines which wish to access the struct
;; Library may do so by calling regA6() in order to get the
;; value of the Library Base Pointer.
;; Example Code Fragment:
;;
;;		struct Library *lib, *regA6();
;;		lib = regA6();
;;		return(lib -> lib_IdString);
;;
;; An alternate (and perhaps safer method) is to use the
;; _LibraryBase global variable which is setup by the
;; __LibInitCode routine.

	public _regA6
_regA6:	move.l	a6,d0
	rts

	ds.w	0	; Align to a word boundary
        END
SHAR_EOF
if test 4746 -ne "`wc -c LibHead.asm`"
then
echo shar: error transmitting LibHead.asm '(should have been 4746 characters)'
fi
echo shar: extracting Library.c
cat << \SHAR_EOF > Library.c
/* Library.c
 *	Routines required in all shared libraries.
 *	Copyright 1986 by James M Synge.
 */

#include "exec/types.h"
#include "exec/libraries.h"
#include "ExtLibrary.h"
#include "libraries/dos.h"

/* Declare the name of the library	*/

char LibraryName[] = "task.library";
char LibraryId[] =
	"task.library V1.0 (25 May 1987)\015\012";

#define LIB_VERSION	1
#define LIB_REVISION	2

/*
 * This short assembler section is included here so that
 * there is just one small place where these numbers need to
 * be replaced, instead of in two different files (i.e. here
 * and LibHead.asm).
 */

#asm
	PUBLIC	LibVersion
	PUBLIC	LibRevision
LibVersion	EQU	1	; Shared with libhead via
LibRevision	EQU	2	; the PUBLIC statement
#endasm

/*
 * If the rt_Flags field of the RomTag (struct Resident) has
 * the AUTOINIT bit set, then the rt_Init field must point
 * to a block such the following LibInitBlock.  This block
 * contains four of the five parameters which OpenLibrary()
 * will pass to MakeLibrary.  (The fifth parameter is the
 * SegList.)  If the AUTOINIT bit is not set, then the
 * rt_Init field must point to a routine which will perform
 * the equivalent initialization.
 *
 * When the library is being auto-initialized, a block of
 * memory is allocated by MakeLibrary().  Its size is
 * determined by the length of FunctionList (in Functions.c)
 * and an entry, lib_sizeof_ExtLibrary, in the structure
 * pointed to by rt_Init.  That entry is the size in bytes
 * of the struct ExtLibrary to be allocated automatically,
 * before calling the routine whose address is in
 * lib_InitCode.  So, this value must be known before
 * linking.
 *
 * This can be done by expressing the LibInitBlock structure
 * in C so that the compiler can determine the size for us.
 * This is a drastic improvement over figuring it out by
 * hand!
 */

extern long *FunctionList[];
void _LibInitCode();

struct {

	long lib_sizeof_ExtLibrary; /* Bytes to allocate  */
	APTR lib_FunctionList;	    /* Ptr to func list   */
	long lib_InitStruct;	    /* see initializers.i */
	APTR lib_InitCode;	    /* Ptr to asm routine */

} LibInitBlock = {

	sizeof( struct ExtLibrary ),
	(APTR) FunctionList,
	0L,			    /* No struct init	  */
	(APTR) _LibInitCode

};

/* The assembly routine _LibInitCode calls LibraryInit() to
 * complete the initialization of the library.
 */
struct ExtLibrary *
LibraryInit( LibBasePtr )

struct ExtLibrary *LibBasePtr;
{
	/* These initializations are done here because it is
	 * difficult to build an initializer structure with
	 * Aztec Assembler 3.2.  The argument, the library
	 * pointer, is pushed onto the stack by the
	 * assembler routine _LibInitCode.
	 */

	LibBasePtr -> el_Node.ln_Type	= NT_LIBRARY;
	LibBasePtr -> el_Node.ln_Name	= LibraryName;
	LibBasePtr -> el_Version	= LIB_VERSION;
	LibBasePtr -> el_Revision	= LIB_REVISION;
	LibBasePtr -> el_IdString	= (APTR) LibraryId;

	/* Now set up the initial values for my libraries'
	 * variables.
	 */

	/* NONE IN THIS EXAMPLE!!! */

	return LibBasePtr;	/* This is the value which
				 * will be returned to
				 * MakeLibrary()
				 */
}

/*
 * The required routines Open, Close and Expunge are called
 * not by other C routines, but rather by Exec.  This means
 * that their arguments are in registers instead of on the
 * stack.
 *
 * There are three straight forward options at this point:
 *
 *   1)	Use the variable LibraryBase (see LibHead.asm) which
 *	should contain the same value as that in A6.
 *
 *   2)	Immediately call the routine regA6() in LibHead.asm
 *	which will return the value in A6 (Should be the
 *	Library Base Pointer).  This requires that we can be
 *	certain that A6 hasn't been wiped out already by the
 *	compiler generated setup code.
 *
 *   3)	Place an intermediate assembly routine between exec
 *	and each C routine which moves the arguments,
 *	including the Library Base Pointer, from the
 *	registers to the stack.
 *
 * The last method seems the best, so we'll use it.
 */

struct ExtLibrary *
Library_Open( LibBasePtr, Version )

struct ExtLibrary *LibBasePtr;	/* Was in A6 */
long Version;			/* Was in D0 */
{
	Forbid();

	/* Note that another open has occured. */
	LibBasePtr->el_OpenCnt ++;

	/* Since we know that there is at least one user of
	 * this library, we'll ignore any previous call to
	 * Library_Expunge.
	 */
	 
	LibBasePtr->el_Flags &= ~LIBF_DELEXP;

	Permit();

	return LibBasePtr;
}

/* When the memory allocator in exec.library is looking for
 * more memory, it will try to get rid of the memory used by
 * libraries, devices and fonts.  To do this with a library,
 * it calls Library_Expunge, the third of the required
 * routines.  If Library_Expunge returns zero, then the
 * memory allocator looks elsewhere.  If it returns non-zero
 * then the value must be a pointer to an AmigaDOS SegList.
 * This will be placed on the free list by the memory
 * allocator.  It is the responsibility of the library to
 * free the jump table and Library structure.
 */

extern BPTR LibSegList;  /* Allocated in LibHead.asm */

BPTR
Library_Expunge( LibBasePtr )

struct ExtLibrary * LibBasePtr;	/* Was in A6 */
{
	unsigned long size, JumpTableBase;

	/* The memory allocator runs inside a Forbid() /
	 * Permit() pair.  To protect against being called
	 * by somebody else (i.e. Library_Close).
	 */

	Forbid ();

	if (LibBasePtr->el_OpenCnt > 0) {
		/* Still open, so note the expunge for
		 * later use in Library_Close.
		 */
		LibBasePtr->el_Flags |= LIBF_DELEXP;
		Permit ();
		return 0;
	}

	/* Remove the library from the exec library list
	 * so that nobody tries to allocate the library.
	 */

	Remove( LibBasePtr );

	/* Now free up the jump table and library structure.
	 * We add the sizes of the two (lib_NegSize is the
	 * size of the jump table, and lib_PosSize is the
	 * size of struct ExtLibrary), then free the block
	 * starting at the base of the jump table.
	 */

	size = (long)(LibBasePtr->el_NegSize)
	     + (long)(LibBasePtr->el_PosSize);

	if ( size ) {
		JumpTableBase = (long) LibBasePtr -
			(long) (LibBasePtr->el_NegSize);

		FreeMem( JumpTableBase, size );
	}

	Permit();

	return LibSegList;
}

/* When the exec routine CloseLibrary() is called, it calls
 * the required Close() routine of the identified library.
 * That routine is implemented here by Library_Close.  It
 * decrements the open count.  If it is zero, and if the
 * delayed expunge flags is set, then Library_Expunge() is
 * called.  Just as in the case of the Expunge routine, if
 * a non-zero value is returned, it must be a BPTR to an
 * AmigaDOS SegList.
 */

BPTR
Library_Close( LibBasePtr )

struct ExtLibrary * LibBasePtr;	/* Was in A6 */
{
	Forbid();	/* Have to be cautious when there's
			 * not much documentation. */
	LibBasePtr->el_OpenCnt -- ;	/* Decrement */
	Permit();
	
	if (LibBasePtr->el_OpenCnt == 0)
	    if ((LibBasePtr->el_Flags & LIBF_DELEXP) != 0)
		return Library_Expunge();

	return 0;	/* No expunge. */
}

/* Now for the big routine!
 */
long Library_Reserved()
{
	return(0L);
}
SHAR_EOF
if test 7036 -ne "`wc -c Library.c`"
then
echo shar: error transmitting Library.c '(should have been 7036 characters)'
fi
echo shar: extracting ExtLibrary.h
cat << \SHAR_EOF > ExtLibrary.h
/* library.h	James M Synge	16-Apr-1987	*/

/* This struct definition is designed to enable easy
 * extention of the Library structure with a particular
 * library's variables.
 */

#ifndef EXEC_TYPES_H
#include "exec/types.h"
#endif
#ifndef EXEC_NODES_H
#include "exec/nodes.h"
#endif
#ifndef EXEC_LIBRARIES_H
#include "exec/libraries.h"
#endif

struct ExtLibrary {
	/* First the standard Library */
	struct Library el_Lib;

	/* And now any library specific variables */

	/* Example: These show the form of the names
	 * such variables might have. */

/*	long el_var1;		*/
/*	long el_var2;		*/
/*	long el_var3;		*/
};

/* These accessor #define's are simple conveniences. */

#define el_Node		el_Lib.lib_Node
#define el_Flags	el_Lib.lib_Flags
#define el_pad		el_Lib.lib_pad
#define el_NegSize	el_Lib.lib_NegSize
#define el_PosSize	el_Lib.lib_PosSize
#define el_Version	el_Lib.lib_Version
#define el_Revision	el_Lib.lib_Revision
#define el_IdString	el_Lib.lib_IdString
#define el_Sum		el_Lib.lib_Sum
#define el_OpenCnt	el_Lib.lib_OpenCnt
SHAR_EOF
if test 1038 -ne "`wc -c ExtLibrary.h`"
then
echo shar: error transmitting ExtLibrary.h '(should have been 1038 characters)'
fi
echo shar: extracting Task_Routines.c
cat << \SHAR_EOF > Task_Routines.c
/* Task_Routines.c	Copyright 1987 by James M Synge   */

/* This file contains CreateTask() and DeleteTask(),
 * versions of the routines of the same names in the ROM
 * Kernel Manual.
 */

#include "exec/types.h"
#include "exec/ports.h"
#include "exec/tasks.h"
#include "exec/memory.h"

struct Task *
CreateTask(Task_Name, Priority, Startup_Routine, Stack_Size)

char *Task_Name;
int Priority;
void (* Startup_Routine) ();
int Stack_Size;
{
    /* A pointer to the child task's task structure. */
    register struct Task *Child;
    register APTR Child_Stack;   /* A pointer to it's stack */
    register APTR AllocMem();

    /* First allocate a stack for the task. */

    Child_Stack = AllocMem(Stack_Size, MEMF_CLEAR);

    if (Child_Stack == 0) {

/*	Couldn't allocate a stack! And we cann't print an
 *	error message because this routine could be called
 *	by a task or a process which doesn't have a window.
 */
	return(NULL);
    };

    /* Now allocate a Task structure. */

    Child = (struct Task *)
    	AllocMem(sizeof(struct Task),
		 MEMF_CLEAR | MEMF_PUBLIC);

    if (Child == NULL) {
	FreeMem(Child_Stack, Stack_Size);
	return(NULL);
    };

    /* Now initialize the task structure as per the RKM. */

    Child->tc_SPLower = Child_Stack;

    Child->tc_SPReg   =
    Child->tc_SPUpper = (APTR)( (ULONG)Child_Stack +
    				(ULONG)Stack_Size);

    Child->tc_Node.ln_Type = NT_TASK;
    Child->tc_Node.ln_Pri = Priority;
    Child->tc_Node.ln_Name = Task_Name;

    AddTask(Child, Startup_Routine, 0L);

    return(Child);
}

/* DeleteTask is written in a style which will allow it to
 * be called by any task, including the task being deleted.
 * Note that it can not delete an AmigaDOS Process.
 */

void DeleteTask(Child)
    register struct Task *Child;
{
    register ULONG Stack_Size;

    if (Child == NULL) return;

    /* Free up the stack and the Task structure.  This is
     * done inside a Forbid() / Permit() so that no other
     * task can do the same.
     */

    Forbid();

    if (Child->tc_Node.ln_Type != NT_TASK) {
	/* OOPS! It ain't a Task! */
	Permit();
    	return;
    }

    Stack_Size = (ULONG)(Child->tc_SPUpper) -
    		 (ULONG)(Child->tc_SPLower);

    FreeMem(Child->tc_SPLower, Stack_Size);
    FreeMem(Child, sizeof(struct Task));

    /* Now remove the task.  This will not return if it is
     * removing the current task.
     */

    RemTask( Child );

    /* If we removed another task, then we continue on:
     * so call Permit() and return.
     */

    Permit();

    return;
}
SHAR_EOF
if test 2545 -ne "`wc -c Task_Routines.c`"
then
echo shar: error transmitting Task_Routines.c '(should have been 2545 characters)'
fi
echo shar: extracting FunctionList.c
cat << \SHAR_EOF > FunctionList.c
/* FunctionList.c	James M Synge	16-Apr-1987	*/

/* This file contains the function table whose address is
 * passed to MakeLibrary.  This table is used to create the
 * jump table which will immediately proceed the library
 * structure in memory.  Notice that the first three entries
 * are the assembly language interludes in the file
 * LibHead.ASM.
 */

/* Required routines:					*/

long _Library_Open();	/* Called by OpenLibrary().	*/
long _Library_Close();	/* Called by CloseLibrary().	*/
long _Library_Expunge();/* Called by memory allocator.	*/
long  Library_Reserved();	/* Must return 0L.	*/

/* Public, library specific routines:			*/

long _CreateTask();
long _DeleteTask();

long (* FunctionList[])() = {

	_Library_Open,
	_Library_Close,
	_Library_Expunge,
	 Library_Reserved,

	_CreateTask,
	_DeleteTask,

	-1L	/* Marks the end of the list. */
};
SHAR_EOF
if test 861 -ne "`wc -c FunctionList.c`"
then
echo shar: error transmitting FunctionList.c '(should have been 861 characters)'
fi
echo shar: extracting Interface.asm
cat << \SHAR_EOF > Interface.asm
;; Interface.ASM
;;		Copyright 1986, James M Synge
;;
;; This file contains the assembly language interfaces which
;; allow the C routines to be called from any language which
;; can push arguments on to the stack.

	far	code
	far	data

;; Imported Functions:

	public	_Library_Open
	public	_Library_Close
	public	_Library_Expunge

	public	_CreateTask
	public	_DeleteTask

;; Exported Functions:

	public	__Library_Open
	public	__Library_Close
	public	__Library_Expunge

	public	__CreateTask
	public	__DeleteTask

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Due to the fact that the Aztec C68K compiler does not use
;; the same register allocation as the rest of the system,
;; it tromps on some of the registers which it is supposed
;; to preserve.  It is designed to be the top level, making
;; calls to the rest of the system and NOT being called by
;; the OS.
;;
;; Using version 3.4a of the compiler, I find it necessary
;; to save A6.  Version 3.2a also stepped on D2 and D3.  I
;; have not yet seen any use of register A4, even though I'm
;; using the +R option on the CC command line.  Nonetheless,
;; I'll be cautious, and save A4.
;;
;; So?  So I've written an interlude for each of the
;; routines which the OS will be calling.  These interludes
;; know where the arguments are in the registers, and push
;; them onto the stack where they are useful.
;;
;; And after these interludes are the library specific
;; interlude routines.  These are designed to have their
;; arguments on the stack, as if called by a C routine.

AztecBugList:	reg	a4/a6
AztecBugSize:	equ	2	; 2 registers

; AztecBugList_3_2a:	reg	d2/d3/a4/a6

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; These are the interlude routines for Library_Open,
;; Library_Close and Library_Expunge.  They enable these C
;; routines to receive the arguments which are in registers.

__Library_Open:
	movem.l	AztecBugList,-(sp)
	move.l	d0,-(sp)		; Push the version
	move.l	a6,-(sp)		; and the lib base
	jsr	_Library_Open
	addq.l	#8,sp			; Pop them
	movem.l	(sp)+,AztecBugList
	rts

__Library_Close:
	movem.l	AztecBugList,-(sp)
	move.l	a6,-(sp)		; Push lib base
	jsr	_Library_Close
	addq.l	#4,sp			; Pop it
	movem.l	(sp)+,AztecBugList
	rts

__Library_Expunge:
	movem.l	AztecBugList,-(sp)
	move.l	a6,-(sp)		; Push lib base
	jsr	_Library_Expunge
	addq.l	#4,sp			; Pop it
	movem.l	(sp)+,AztecBugList
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Library specific interface routines.  These first push
;; certain registers to the stack to protect them, then push
;; the arguments from earlier on the stack.  The only reason
;; this is done is so that we can protect two of the
;; registers.  Otherwise the need for these silly routines
;; would totally disappear.
;;
;; In order to make it easy for those not familiar with
;; 68000 assembly language to add their own routines to a
;; library, and the corresponding interface routines, I've
;; written a macro which can be invoked to generate all the
;; code to protect the registers and move the arguments.
;; The macro, protect, is defined in the file Protect.i, but
;; I don't recommend reading it until after you get a good
;; feeling for the way macro's and assembly work.
;;
;; It is very easy to use protect.  The syntax should be:
;;
;;	label	PROTECT.L	address,n
;;
;; where label is the name of the routine you are creating,
;; for example __CreateTask below; address is the name of a
;; C routine (with the underscore prepended), just like
;; _CreateTask below; and finally n is the number of
;; longword arguments the routine takes.  No support is
;; supplied for variable numbers of arguments.  Nor support
;; for arguments which are not longwords.

	include protect.i

; CreateTask(Task_Name, Startup_Routine, Cleanup_Routine,
;	     Priority, Stack_Size)

__CreateTask	protect.l	_CreateTask,5

; DeleteTask( Child )

__DeleteTask:	protect.l	_DeleteTask,1

; Now that was pretty painless, wasn't it.  Macros are great

	ds.w	0
        END
SHAR_EOF
if test 4032 -ne "`wc -c Interface.asm`"
then
echo shar: error transmitting Interface.asm '(should have been 4032 characters)'
fi
echo shar: extracting Protect.i
cat << \SHAR_EOF > Protect.i
;; Protect.i	Copyright 1987 by James M Synge
;;
;; An assembly macro for protecting registers.
;; Not for the weak of heart.

	macro	protect

	if	NARG <> 2
	fail		; Must specify the number of args!
	mexit
	endc

	iflt	\2
	fail		; Negative number of args!
	mexit
	endc

; Until a bug fix arrives for the assembler so that the \0
; macro works, we must assume the argument size is 4 bytes.

\@elementsize	set 4
\@bytes		set \@elementsize * \2
\@offset	set \@bytes + (AztecBugSize * 4)

	movem.l	AztecBugList,-(sp)	; Save some regs

	; Push the argument(s).  We'll use D0 as our scratch
	; register since it is free for that use according
	; to the register convention.
	
	ifne	\2	; If there are any arguments

	moveq	#\2,d0	; Number of arguments to move
\@loop	move.l	\@offset(sp),-(sp)	; Push an arg
	dbeq	d0,\@loop		; Loop again?
	
	endc

	jsr	\1	; Call the C routine

	ifne	\2		; Pop any arguments
	ifge	8 - \@bytes	; Can we use addq.l?
	addq.l	#\@bytes,sp	; Yup!
	else
	lea	\@bytes(sp),sp	; Otherwise use lea
	endc
	endc

	movem.l	(sp)+,AztecBugList	; Restore regs
	rts		; And return

	endm	; End of the protect macro
SHAR_EOF
if test 1120 -ne "`wc -c Protect.i`"
then
echo shar: error transmitting Protect.i '(should have been 1120 characters)'
fi
echo shar: extracting 2Tasks.c
cat << \SHAR_EOF > 2Tasks.c
/* 2Tasks.C	James M Synge,	May 18, 1987		  */

/* Include files */
#include "exec/types.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/tasks.h"
#include "exec/libraries.h"
#include "exec/ports.h"

/* Other declarations	*/

struct Library  *TaskBase, /* Library Base Pointer. */
		*OpenLibrary();

struct MsgPort	*CreatePort(), *FindPort();
struct Message	*WaitPort(), *GetMsg();

#define TASK_LIBRARY	"task.library"
#define	TASK_VERSION	1L

#define CHILD_PORT	"2Tasks.Child.Port"
#define CHILD_TASK	"2Tasks.Child.Name"

main()
{
	struct Message message, *msg;
	struct MsgPort *ParentPort, *ChildPort;
	struct Task *ChildTask, *CreateTask();
	void ChildMain();
	int seconds;	

	/* First things first: Open the task library: */

	printf("Openning %s\n", TASK_LIBRARY);
	TaskBase = OpenLibrary(TASK_LIBRARY, TASK_VERSION);
	if (TaskBase == 0L) {
		printf("Unable to open %s\n", TASK_LIBRARY);
		exit(10);
	}

	/* Create a nameless MsgPort where we can receive
	 * the reply to a message.
	 */
	if ((ParentPort = CreatePort( 0L, 0L )) == 0L) {
		printf("Unable to create a MsgPort!\n");
		CloseLibrary( TaskBase );
		exit(10);
	}

	/* Now create the child task. */

	printf("Creating the child task.\n");
	ChildTask = CreateTask(
		CHILD_TASK,	/* Name of the task.	*/
		1L,		/* Higher priority.	*/
		ChildMain,	/* Its main routine.	*/
		4096L);		/* Stack Size.		*/

	if (ChildTask == 0L) {
		printf("Unable to create child task!\n");
		DeletePort( ParentPort );
		CloseLibrary( TaskBase );
		exit(10);
	}

	/* Find the child's message port. */

	for(seconds = 0; seconds < 60; seconds++) {
		printf("Find the child's MsgPort\n");
		if (ChildPort = FindPort( CHILD_PORT ))
			break;
		Delay(50);	/* Wait a second! */
	}

	if (ChildPort == 0L) {
		printf("Unable to find child MsgPort!\n");
		DeleteTask( ChildTask );
		DeletePort( ParentPort );
		CloseLibrary( TaskBase );
		exit(10);
	}

	/* Send the child a message. */

	message.mn_Node.ln_Type	= NT_MESSAGE;
	message.mn_ReplyPort	= ParentPort;
	message.mn_Length	= 0;

	printf("Sending the message.\n");
	PutMsg( ChildPort, &message );

	/* Wait for the child to respond. */

	WaitPort( ParentPort );

	/* Get the message. */

	msg = GetMsg( ParentPort );
	printf("Got the reply.  All done.\n");
	
	/* And now delete the MsgPort we used. */

	DeletePort( ParentPort );
	
	/* Finally, close the library. */
	
	CloseLibrary( TaskBase );

	exit(0);
}

/* Notice that the child doesn't open any libraries,
 * including exec.library and Task.Library whose
 * routines it uses. It does this because it will
 * operate solely during the life of the parent, when we
 * know the libraries will be open.  This is not kosher in
 * general, but Commodore has produced examples doing this,
 * and I know there aren't any problems in this case.
 *
 * It's also particularly difficult to close a library
 * after using DeleteTask() on yourself!
 */
void ChildMain()
{
	struct Message *msg;
	struct MsgPort *ChildPort;

	/* To allow this to be a small code/small data model
	 * task, we must make sure register A4 contains the
	 * correct value.  We do so by calling the Aztec C
	 * routine geta4() which computes the value.
	 */
	geta4();

	/* Create a MsgPort where we can receive a message
	 * from the parent task.
	 */
	if ((ChildPort = CreatePort( CHILD_PORT, 0L )) == 0)
		DeleteTask( FindTask( 0L ));
		
	/* Now wait for the message. */
 
	WaitPort( ChildPort );

	/* Fetch it from the port... */

	msg = GetMsg( ChildPort );

	/* ... and reply to it.  Do so inside a Forbid() /
	 * Permit() pair so there'll be time to delete the
	 * message port.  Note that the Permit() call is
	 * not included because it will never be called;
	 * instead, DeleteTask() is called so that we
	 * delete the current task: ourselves!
	 */
	Forbid();

	ReplyMsg( msg );

	DeletePort( ChildPort );

	/* Now take the leap of death. */

	DeleteTask( FindTask( 0L ));

	/* That's all she wrote! */
}
SHAR_EOF
if test 3939 -ne "`wc -c 2Tasks.c`"
then
echo shar: error transmitting 2Tasks.c '(should have been 3939 characters)'
fi
echo shar: extracting task_lib.asm
cat << \SHAR_EOF > task_lib.asm
; task_lib.asm	James M Synge	25-May-1987
;
; Note that these glue routines do not save register A6.
; This is because they are designed for use with Aztec C
; which does not seem to expect A6 to remain unchanged
; during a subroutine call.

	dseg

; TaskBase = OpenLibrary("Task.Library",0);
	public	_TaskBase

	cseg

	public	_CreateTask
_CreateTask
	move.l	_TaskBase,a6
	jmp	_LVOCreateTask(a6)

	public	_DeleteTask
_DeleteTask
	move.l	_TaskBase,a6
	jmp	_LVODeleteTask(a6)

_LVODeleteTask	equ	-36
_LVOCreateTask	equ	-30

	end
SHAR_EOF
if test 526 -ne "`wc -c task_lib.asm`"
then
echo shar: error transmitting task_lib.asm '(should have been 526 characters)'
fi
echo shar: extracting Makefile
cat << \SHAR_EOF > Makefile
# makefile	James M Synge	26-May-1987
#
# Used to build the shared library (task.library) and the
# interface library (task.lib).  Note that the shared
# library is like a complete program in that it is linked,
# while the interface library is just an object file which
# can be included on some other programs linkage line.
#
# Example: ln prog.o -ltask -lc
#
# This example places task.lib earlier in the link than
# c.lib.  Therefore, any routine in task.lib of the same
# name as a routine in c.lib will be loaded instead of the
# routine in c.lib.  This is useful because it allows us to
# replace any routine in c.lib.
#
# Note that these FLAGS macros are only used for making the
# shared library, not the test program nor the interface
# library.

CFLAGS = +BCDLP
AFLAGS = -CD

LIBOBJ = LibHead.o Library.o Task_Routines.o \
	 FunctionList.o Interface.o

ALL =	LibHead.asm Library.c ExtLibrary.h Task_Routines.c FunctionList.c \
	Interface.asm Protect.i 2tasks.c task_lib.asm Makefile

all:	task.library task.lib 2Tasks

task.library : $(LIBOBJ)
	ln -o task.library $(LIBOBJ) -lcl32
#	You may wish to add a command like this:
#	copy task.library LIBS:

LibHead.o : LibHead.asm

Interface.o : Interface.asm Protect.i

Library.o : ExtLibrary.h

task.lib : task_lib.asm
	as $(AFLAGS) -o task.lib task_lib.asm
#	You may wish to add a command which moves the file
#	to the directory where you keep c.lib, etc.

2Tasks	: 2Tasks.o task.lib
	ln 2Tasks.o -ltask -lc

2Tasks.o : 2Tasks.c
	cc 2Tasks.c

ram:sharfile : $(ALL)
	shar > ram:sharfile -vc $(ALL)
SHAR_EOF
if test 1553 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 1553 characters)'
fi
#	End of shell archive
exit 0

jmsynge@sqm.dec.com (James M Synge, DTN 381-1545) (05/30/87)

[ For all I do, dis bugs for me ]

	My line eater comment really expresses the current state of the
library I posted.  I made a mistake in the assembly code in the file
Protect.i, and failed to catch it before I sent it out.  Thats what I get
for hacking till late and not carefully checking all the versions.  That
last minute change killed the program.

	So, I'm following my signature with a shar file with that one file.

James Synge

USENET:  {decvax, ucbvax, allegra}!decwrl!sqm.dec.com!jmsynge
ARPAnet: jmsynge%sqm.DEC@decwrl.DEC.COM

#include <pithy_comment.h>
So many ratholes, so little time!

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	Protect.i
# This archive created: Fri May 29 20:42:26 1987
cat << \SHAR_EOF > Protect.i
;; Protect.i	Copyright 1987 by James M Synge
;;
;; An assembly macro for protecting registers.
;; Not for the weak of heart.

	macro	protect

	if	NARG <> 2
	fail		; Must specify the number of args!
	mexit
	endc

	iflt	\2
	fail		; Negative number of args!
	mexit
	endc

; Until a bug fix arrives for the assembler so that the \0
; macro works, we must assume the argument size is 4 bytes.

\@elementsize	set 4
\@bytes		set \@elementsize * \2
\@offset	set \@bytes + (AztecBugSize * 4)

	movem.l	AztecBugList,-(sp)	; Save some regs

	; Push the argument(s).  We'll use D0 as our scratch
	; register.  It is free for that use according to
	; the register convention.  It is used as the result
	; register.
	
	ifne	\2	; If there are any arguments

	moveq	#\2,d0	; Number of arguments to move
\@loop	move.l	\@offset(sp),-(sp)	; Push an arg
	subq.l	#1,d0		; Last argument?
	bne	\@loop		; If so, loop again?

	endc

	jsr	\1	; Call the C routine

	ifne	\2		; Pop any arguments
	ifge	8 - \@bytes	; Can we use addq.l?
	addq.l	#\@bytes,sp	; Yup!
	else
	lea	\@bytes(sp),sp	; Otherwise use lea
	endc
	endc

	movem.l	(sp)+,AztecBugList	; Restore regs
	rts		; And return

	endm	; End of the protect macro
SHAR_EOF
if test 1189 -ne "`wc -c Protect.i`"
then
echo shar: error transmitting Protect.i '(should have been 1189 characters)'
fi
#	End of shell archive
exit 0

page@ulowell.UUCP (06/08/87)

Uh oh ..

Now that we can write our own C libraries, how do we handle name conflicts?
If I have (say) an "iff.library" that has an IFF read routine called
"iffread" and you have a library for your application called "myapp.library"
that also has a routine called "iffread", which one gets used, mine or yours,
assuming you call OpenLibrary() on both libraries?

This is not as trivial as it sounds.  I think the reason everybody doesn't
have shared C libraries is because C-A didn't document how do to them
well, and I think THAT is because they didn't know how to handle conflicts
in the name space.

A better example is something like push(), that could occur in two
libraries and do totally different things .. one that operates on
a stack, the other that plays with window arrangement.

This Open-Ended-ness of the Amiga operating system can be a can of worms.
Witness potential problems with SetFunction (SetVector?  Can never remember)
or hot-key programs that all look for META-CTRL-ESC to do their thing.
I'm not saying I want to get rid of the functionality - I just wish there
were a way to arbitrate it.  JimM has a package called "Commodities Exchange"
that attempts to rectify the hot-keys problems; alas, it is not part of
Exec now, and won't be universally accepted until it *is* part of it.

Anyway, how do we avoid colliding function names in run-time libraries?
I mean besides appending a "unique" string to the function name...

..Bob
-- 
Bob Page, U of Lowell CS Dept.   page@ulowell.{uucp,edu,csnet} 

daveh@cbmvax.cbm.UUCP (Dave Haynie) (06/09/87)

in article <1358@ulowell.cs.ulowell.edu>, page@ulowell.cs.ulowell.edu (Bob Page) says:
> 
> Uh oh ..
> 
> Now that we can write our own C libraries, how do we handle name conflicts?
> If I have (say) an "iff.library" that has an IFF read routine called
> "iffread" and you have a library for your application called "myapp.library"
> that also has a routine called "iffread", which one gets used, mine or yours,
> assuming you call OpenLibrary() on both libraries?

I'd expect that name conflicts in this care are resolved the same way
that name conflicts are resolved in any compilation -- first come, first
serve, at link time.  So when you link in iff.lib before myapp.lib, the
"iffread()" function you get is in iff.lib, just as when you link lc.lib in
before amiga.lib, you get Lattice's printf(), not the Amiga library 
"printf()".  It's the interface code that turns symbolic names into offsets
from a library base, not the library itself.  I claim all the symbolic 
names will be resolved at compile time.

> ..Bob
-- 
Dave Haynie     Commodore-Amiga    Usenet: {ihnp4|caip|rutgers}!cbmvax!daveh
"The A2000 Guy"                    BIX   : hazy
	"These are the days of miracle and wonder" -P. Simon

daveh@cbmvax.cbm.UUCP (Dave Haynie) (06/09/87)

in article <1987@cbmvax.cbmvax.cbm.UUCP>, daveh@cbmvax.cbm.UUCP (Dave Haynie) says:

> I claim all the symbolic names will be resolved at compile time.

Uh, duh.  LINK time is what I mean, not COMPILE time.  It's been a very
rough day.....

-- 
Dave Haynie     Commodore-Amiga    Usenet: {ihnp4|caip|rutgers}!cbmvax!daveh
"The A2000 Guy"                    BIX   : hazy
	"These are the days of miracle and wonder" -P. Simon

higgin@cbmvax.cbm.UUCP (Paul Higginbottom SALES) (06/09/87)

In article <1358@ulowell.cs.ulowell.edu> page@ulowell.cs.ulowell.edu (Bob Page) writes:
$Now that we can write our own C libraries, how do we handle name conflicts?
$If I have (say) an "iff.library" that has an IFF read routine called
$"iffread" and you have a library for your application called "myapp.library"
$that also has a routine called "iffread", which one gets used, mine or yours,
$assuming you call OpenLibrary() on both libraries?

In order to call library functions as if they were part of your program,
there is generally a "stub" routine which sets up registers etc., and
then does a jump to a location offset from the library base pointer.

These stubs are contained in the object code library which you link to.
Therefore, there are stubs for all the intuition, dos, exec, etc. calls.

So in order to have an easily usable library, you also need a linkable
object stub library.  Generally, a linker will resolve a reference with
the first instance of that name it comes across, and give a warning
on any others (as duplicate symbols, but should not STOP linking - at
least this is how Manx works).

The name conflict even occurs without user-created libraries.  Have
you ever wanted to call a routine "Write" for example, but realized that's
a bad idea because it conflicts with the DOS routine.  Not to say it can't
be done, it's just not wise.

$Bob Page, U of Lowell CS Dept.   page@ulowell.{uucp,edu,csnet} 

	Paul Higginbottom, Commodore.

carolyn@cbmvax.UUCP (06/11/87)

In article <1358@ulowell.cs.ulowell.edu> page@ulowell.cs.ulowell.edu (Bob Page) writes:
>[]
>Now that we can write our own C libraries, how do we handle name conflicts?
>If I have (say) an "iff.library" that has an IFF read routine called
>"iffread" and you have a library for your application called "myapp.library"
>that also has a routine called "iffread", which one gets used, mine or yours,
>assuming you call OpenLibrary() on both libraries?
>[]
>Anyway, how do we avoid colliding function names in run-time libraries?
>I mean besides appending a "unique" string to the function name...

   Assuming you have also written an Amiga.lib type linker library to
interface with your library functions and allow you to call them by
name in a C program, the linker will resolve it with the first match
it comes across.  So you decide which of two conflicting-name functions
you get by simply specifying the proper .lib order in your link.

   I consider this a feature since it allows me, for example, to use
Amiga.lib's AmigaDOS stdio printf() and getchar() rather than Lattice's
stdio, giving me Greenhill's compatibility.  I believe others (Matt Dillon?)
have written their own stdio .lib's which they link with first so that
all stdio functions used are theirs.  

   Of course, if you need to use both same-name functions, you'll have to
write yourself a small assembler stub with a different name which will
specifically call the second one for you.  But don't blame the OS.
Executable programs are not calling functions by name.  By that time,
the code is just the first thing the linker found that matched that
function name.  This might be a function name in your own code.  If
not, then it's the code from the first .lib containing that label.
In either case, any labels hanging around after that are just for
debugging purposes.  

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

jmsynge@sqm.dec.com.UUCP (06/11/87)

Summary: The linker doesn't solve the name conflict problem

Dave Haynie writes that he expects the function name conflicts in libraries to
be resolved at link time.  Dave may have missed the point which Bob Page was
trying to express:  imagine that you have bought two libraries, both of which
provide very different functionality.  But they both provide a routine named
push().  And you need to be able to use both versions of push().  Now we have
a name conflict which is not resolvable when writing in C (Modula-2 might offer
an acceptable solution).

An additional problem is one of conflicts in library names themselves.  Two
companies might happen to identically name their libraries.  Imagine two
libraries named "Music.library".  They could provide complementary capabilities,
but be incompatible due to the fact that only one can exist on the system.

I would suggest that Commodore perform the same registration service with
library names as they've done with Zorro id's and IFF hunk names.  This would
not handle the problem of libraries which contain identically named functions,
but it would be an improvement.

In a way the link problem isn't too bad because ultimately one is transferring
control via a jump table at some offset from the library structure, not through
a dynamic linking mechanism such as Matt Dillon proposed.  If that type of
system were introduced, a whole new set of problems would crop up.

James Synge

USENET:  {decvax, ucbvax, allegra}!decwrl!sqm.dec.com!jmsynge
ARPAnet: jmsynge%sqm.DEC@decwrl.DEC.COM

#include <disclaimer.h>
"Ken Olsen can speak for Digital, not me!"

peter@sugar.UUCP (Peter DaSilva) (06/13/87)

I believe the original message (lo these long days ago) was about load-time
linking (late binding) the actual names, rather than doing so at compile
or "link" time (early binding). I'm not sure what the advantage is, but
I don't think that early binding type solutions are relevant.

charles@hpcvcd.HP (Charles Brown) (06/14/87)

>>If I have (say) an "iff.library" that has an IFF read routine called
>>"iffread" and you have a library for your application called "myapp.library"
>>that also has a routine called "iffread", which one gets used ...

>...	 the linker will resolve it with the first match
>it comes across.  So you decide which of two conflicting-name functions
>you get by simply specifying the proper .lib order in your link.

This sounds like an excellent start.  However, there are still some
irksome limitations.

Consider the case where my.library and your.library both have
definitions for foo and bar.  If I want to use foo from my.library
and bar from your.library I have a problem.  This problem is similar
to executing commands from a shell or CLI.  The PATH defines the
order in which directorys are searched.  But I can still specify a
full path name if I want to override that choice.  If this is applied
to librarys, it gives the programmer the power to protect his program
from changes in the users run time environment.

Notice that the same concept can be applied to compile-time-linking
as well as run-time-linking.  In the case of compile time linking, it
is mostly a convenience for the programmer.  Of course, if I want to
link BOTH versions of foo, the problem is worse.  If properly thought
out, I am sure even this pathological case could be handled with full
path name linking.

	Charles Brown		hplabs!hp-pcd!charles
	"Just a thought"

page@ulowell.cs.ulowell.edu (Bob Page) (06/15/87)

>...	 the linker will resolve it with the first match
>it comes across.  So you decide which of two conflicting-name functions
>you get by simply specifying the proper .lib order in your link.

I guess I wasn't clear enough.  Some scenarios:

I buy two packages, ZIP and ZAP, from two different vendors.  Each has a
C run-time library called z.library that I have to install in order to
have the program work.  In this case, I can't use both libraries, since
they are the same name.  It is possible I could use FileZap and change
the "z" to a "y" and hope that I got all the references.  This also
assumes I have FileZap and some "advanced" level of intelligence about
what makes these things work.  I'd say your average Joe does not, and
does not want to be bothered by such matters.

Maybe both have the convention that ZLibBase is the name of the base
pointer each wants.

Maybe both have a push() and pop() function, one for playing with windows
and another for queue management, and I want to use both push()es and
both pop()s.  Can't do it, since the linker will find the first one
only.

Suppose things aren't so bad, but I have a push() and a pop() in each
of two libraries and only need push() in the first library and pop()
in the second.  This is probably the most "normal" case of name space
collisions.  In this case, I cannot direct the linker to get push in
lib A and pop in lib B; it will grab both from lib A or lib B
depending on my command line and/or library layout.

Note that some operating systems have linkers that allow you do specify
individual modules from specific libraries; this would solve the
problem but would also force you to keep a knowledge of what modules
were contained in what libraries - a good case for using a MAKE utility.

Anyway, maybe CATS sees the picture a little more clearly now.  Just
like SetFunction(), having versatile libraries can also be a headache
if not managed correctly.  Although James Synge's request that Commodore
come up with either a naming convention for libraries/functions or try
to somehow arbitrate them is a good one, I don't think either will work
in practice, since anybody can now write C-based run-time libraries
in a matter of hours and post them everywhere; naming rules be damned.

I also understand that I have gone a little overboard at times with the
scenarios; but I wanted to point out that the dangers are real and
probably need some official CBM word other than "let the linker do it"
since, as I pointed out, the linker can't usually do it.

..Bob
-- 
Bob Page, U of Lowell CS Dept.   page@ulowell.{uucp,edu,csnet} 

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner CATS) (06/19/87)

In article <1377@ulowell.cs.ulowell.edu> page@ulowell.cs.ulowell.edu (Bob Page) writes:
>[]  (re: needing ability to specify which lib to get function from)
>
>I also understand that I have gone a little overboard at times with the
>scenarios; but I wanted to point out that the dangers are real and
>probably need some official CBM word other than "let the linker do it"
>since, as I pointed out, the linker can't usually do it.

   Sounds like a nice linker enhancement, but I suggest that you contact
Lattice or Manx and request it.  Both currently distribute their own
linkers with their compilers, not Alink.  I believe our Alink is written
in BCPL by Metacomco and is Copyright Metacomco.  It would probably have
to be enhanced by Metacomco (at our cost) and the people who wrote it
there may have left with Tim King when he formed his own company.
In addition, enhancing our linker is certainly not a priority item
in comparison with the other things we are all trying to do here.
On the other hand, compilers and linkers are Manx and Lattice's bread
and butter.  I think they might be glad to implement your enhancement.

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

peter@sugar.UUCP (Peter DaSilva) (06/19/87)

main()
{
	xpackage:push(something);
	ypackage:push(something, else);
}

The : might be some other character. @, $, and ` aren't used right now.

Peter da Silva (with his l key busted).

jonesjg@dg_rtp.UUCP (Greg Jones) (06/23/87)

In article <2028@cbmvax.cbmvax.cbm.UUCP> carolyn@cbmvax.UUCP (Carolyn Scheppner CATS) writes:
>In article <1377@ulowell.cs.ulowell.edu> page@ulowell.cs.ulowell.edu (Bob Page) writes:
>>[]  (re: needing ability to specify which lib to get function from)
>   Sounds like a nice linker enhancement, but I suggest that you contact
>Lattice or Manx and request it.  Both currently distribute their own
>linkers with their compilers, not Alink.  

Check out oml in the lattice 3.10 manual.  This is an object module librarian
which allows the listing, extraction, and addition of object modules from
a given library.  I haven't used this utility but if it is anything like the
library file editors at work (functionally looks the same) why not extract
the object in question, rename it and replace it in the library.  It's a
little brut force for most, but in a pinch when you need both objects from
different libraries that have the same name it should work.  Can't say much
for compatablity with the anyone elses libraries though. Just wanted everyone
to know the 'half linker' does exist, at least for us lattice users.

						Greg Jones.

-- 

				Greg Jones
				Data General, RTP, NC
				...!seismo!mcnc!rti!dg_rtp!jones